diff --git a/.env.example.complete b/.env.example.complete index 0853bd1fe..e8520a24c 100644 --- a/.env.example.complete +++ b/.env.example.complete @@ -273,6 +273,7 @@ OIDC_USER_TO_GROUPS=false OIDC_GROUPS_CLAIM=groups OIDC_REMOVE_FROM_GROUPS=false OIDC_EXTERNAL_ID_CLAIM=sub +OIDC_END_SESSION_ENDPOINT=false # Disable default third-party services such as Gravatar and Draw.IO # Service-specific options will override this option diff --git a/.github/translators.txt b/.github/translators.txt index 6bb9de259..a27717f94 100644 --- a/.github/translators.txt +++ b/.github/translators.txt @@ -177,7 +177,7 @@ Alexander Predl (Harveyhase68) :: German Rem (Rem9000) :: Dutch Michał Stelmach (stelmach-web) :: Polish arniom :: French -REMOVED_USER :: French; Dutch; Turkish; +REMOVED_USER :: French; Dutch; Portuguese, Brazilian; Portuguese; Turkish; 林祖年 (contagion) :: Chinese Traditional Siamak Guodarzi (siamakgoudarzi88) :: Persian Lis Maestrelo (lismtrl) :: Portuguese, Brazilian @@ -371,3 +371,18 @@ LameeQS :: Latvian Sorin T. (trimbitassorin) :: Romanian poesty :: Chinese Simplified balmag :: Hungarian +Antti-Jussi Nygård (ajnyga) :: Finnish +Eduard Ereza Martínez (Ereza) :: Catalan +Jabir Lang (amar.almrad) :: Arabic +Jaroslav Koblizek (foretix) :: Czech; French +Wiktor Adamczyk (adamczyk.wiktor) :: Polish +Abdulmajeed Alshuaibi (4Majeed) :: Arabic +NotSmartZakk :: Czech +HyoungMin Lee (ddokkaebi) :: Korean +Dasferco :: Chinese Simplified +Marcus Teräs (mteras) :: Finnish +Serkan Yardim (serkanzz) :: Turkish +Y (cnsr) :: Ukrainian +ZY ZV (vy0b0x) :: Chinese Simplified +diegobenitez :: Spanish +Marc Hagen (MarcHagen) :: Dutch diff --git a/.gitignore b/.gitignore index ede4fe296..a8d2e6af7 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,5 @@ webpack-stats.json .phpunit.result.cache .DS_Store phpstan.neon -esbuild-meta.json \ No newline at end of file +esbuild-meta.json +.phpactor.json diff --git a/app/Access/Controllers/ForgotPasswordController.php b/app/Access/Controllers/ForgotPasswordController.php index bc59e9d2f..86fbe8fa3 100644 --- a/app/Access/Controllers/ForgotPasswordController.php +++ b/app/Access/Controllers/ForgotPasswordController.php @@ -9,11 +9,6 @@ use Illuminate\Support\Facades\Password; class ForgotPasswordController extends Controller { - /** - * Create a new controller instance. - * - * @return void - */ public function __construct() { $this->middleware('guest'); @@ -30,10 +25,6 @@ class ForgotPasswordController extends Controller /** * Send a reset link to the given user. - * - * @param \Illuminate\Http\Request $request - * - * @return \Illuminate\Http\RedirectResponse */ public function sendResetLinkEmail(Request $request) { @@ -56,13 +47,13 @@ class ForgotPasswordController extends Controller $message = trans('auth.reset_password_sent', ['email' => $request->get('email')]); $this->showSuccessNotification($message); - return back()->with('status', trans($response)); + return redirect('/password/email')->with('status', trans($response)); } // If an error was returned by the password broker, we will get this message // translated so we can notify a user of the problem. We'll redirect back // to where the users came from so they can attempt this process again. - return back()->withErrors( + return redirect('/password/email')->withErrors( ['email' => trans($response)] ); } diff --git a/app/Access/Controllers/LoginController.php b/app/Access/Controllers/LoginController.php index 3b4f9b347..ce872ba88 100644 --- a/app/Access/Controllers/LoginController.php +++ b/app/Access/Controllers/LoginController.php @@ -3,34 +3,26 @@ namespace BookStack\Access\Controllers; use BookStack\Access\LoginService; -use BookStack\Access\SocialAuthService; +use BookStack\Access\SocialDriverManager; use BookStack\Exceptions\LoginAttemptEmailNeededException; use BookStack\Exceptions\LoginAttemptException; use BookStack\Facades\Activity; use BookStack\Http\Controller; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Auth; use Illuminate\Validation\ValidationException; class LoginController extends Controller { use ThrottlesLogins; - protected SocialAuthService $socialAuthService; - protected LoginService $loginService; - - /** - * Create a new controller instance. - */ - public function __construct(SocialAuthService $socialAuthService, LoginService $loginService) - { + public function __construct( + protected SocialDriverManager $socialDriverManager, + protected LoginService $loginService, + ) { $this->middleware('guest', ['only' => ['getLogin', 'login']]); $this->middleware('guard:standard,ldap', ['only' => ['login']]); $this->middleware('guard:standard,ldap,oidc', ['only' => ['logout']]); - - $this->socialAuthService = $socialAuthService; - $this->loginService = $loginService; } /** @@ -38,7 +30,7 @@ class LoginController extends Controller */ public function getLogin(Request $request) { - $socialDrivers = $this->socialAuthService->getActiveDrivers(); + $socialDrivers = $this->socialDriverManager->getActive(); $authMethod = config('auth.method'); $preventInitiation = $request->get('prevent_auto_init') === 'true'; @@ -52,7 +44,7 @@ class LoginController extends Controller // Store the previous location for redirect after login $this->updateIntendedFromPrevious(); - if (!$preventInitiation && $this->shouldAutoInitiate()) { + if (!$preventInitiation && $this->loginService->shouldAutoInitiate()) { return view('auth.login-initiate', [ 'authMethod' => $authMethod, ]); @@ -101,15 +93,9 @@ class LoginController extends Controller /** * Logout user and perform subsequent redirect. */ - public function logout(Request $request) + public function logout() { - Auth::guard()->logout(); - $request->session()->invalidate(); - $request->session()->regenerateToken(); - - $redirectUri = $this->shouldAutoInitiate() ? '/login?prevent_auto_init=true' : '/'; - - return redirect($redirectUri); + return redirect($this->loginService->logout()); } /** @@ -200,7 +186,7 @@ class LoginController extends Controller { // Store the previous location for redirect after login $previous = url()->previous(''); - $isPreviousFromInstance = (strpos($previous, url('/')) === 0); + $isPreviousFromInstance = str_starts_with($previous, url('/')); if (!$previous || !setting('app-public') || !$isPreviousFromInstance) { return; } @@ -211,23 +197,11 @@ class LoginController extends Controller ]; foreach ($ignorePrefixList as $ignorePrefix) { - if (strpos($previous, url($ignorePrefix)) === 0) { + if (str_starts_with($previous, url($ignorePrefix))) { return; } } redirect()->setIntendedUrl($previous); } - - /** - * Check if login auto-initiate should be valid based upon authentication config. - */ - protected function shouldAutoInitiate(): bool - { - $socialDrivers = $this->socialAuthService->getActiveDrivers(); - $authMethod = config('auth.method'); - $autoRedirect = config('auth.auto_initiate'); - - return $autoRedirect && count($socialDrivers) === 0 && in_array($authMethod, ['oidc', 'saml2']); - } } diff --git a/app/Access/Controllers/OidcController.php b/app/Access/Controllers/OidcController.php index e8c944934..055d4c140 100644 --- a/app/Access/Controllers/OidcController.php +++ b/app/Access/Controllers/OidcController.php @@ -11,9 +11,6 @@ class OidcController extends Controller { protected OidcService $oidcService; - /** - * OpenIdController constructor. - */ public function __construct(OidcService $oidcService) { $this->oidcService = $oidcService; @@ -63,4 +60,12 @@ class OidcController extends Controller return redirect()->intended(); } + + /** + * Log the user out then start the OIDC RP-initiated logout process. + */ + public function logout() + { + return redirect($this->oidcService->logout()); + } } diff --git a/app/Access/Controllers/RegisterController.php b/app/Access/Controllers/RegisterController.php index 3c653a073..13b97f03c 100644 --- a/app/Access/Controllers/RegisterController.php +++ b/app/Access/Controllers/RegisterController.php @@ -4,7 +4,7 @@ namespace BookStack\Access\Controllers; use BookStack\Access\LoginService; use BookStack\Access\RegistrationService; -use BookStack\Access\SocialAuthService; +use BookStack\Access\SocialDriverManager; use BookStack\Exceptions\StoppedAuthenticationException; use BookStack\Exceptions\UserRegistrationException; use BookStack\Http\Controller; @@ -15,7 +15,7 @@ use Illuminate\Validation\Rules\Password; class RegisterController extends Controller { - protected SocialAuthService $socialAuthService; + protected SocialDriverManager $socialDriverManager; protected RegistrationService $registrationService; protected LoginService $loginService; @@ -23,14 +23,14 @@ class RegisterController extends Controller * Create a new controller instance. */ public function __construct( - SocialAuthService $socialAuthService, + SocialDriverManager $socialDriverManager, RegistrationService $registrationService, LoginService $loginService ) { $this->middleware('guest'); $this->middleware('guard:standard'); - $this->socialAuthService = $socialAuthService; + $this->socialDriverManager = $socialDriverManager; $this->registrationService = $registrationService; $this->loginService = $loginService; } @@ -43,7 +43,7 @@ class RegisterController extends Controller public function getRegister() { $this->registrationService->ensureRegistrationAllowed(); - $socialDrivers = $this->socialAuthService->getActiveDrivers(); + $socialDrivers = $this->socialDriverManager->getActive(); return view('auth.register', [ 'socialDrivers' => $socialDrivers, diff --git a/app/Access/Controllers/ResetPasswordController.php b/app/Access/Controllers/ResetPasswordController.php index eae4e5e25..a8a45dddf 100644 --- a/app/Access/Controllers/ResetPasswordController.php +++ b/app/Access/Controllers/ResetPasswordController.php @@ -66,7 +66,7 @@ class ResetPasswordController extends Controller // redirect them back to where they came from with their error message. return $response === Password::PASSWORD_RESET ? $this->sendResetResponse() - : $this->sendResetFailedResponse($request, $response); + : $this->sendResetFailedResponse($request, $response, $request->get('token')); } /** @@ -83,7 +83,7 @@ class ResetPasswordController extends Controller /** * Get the response for a failed password reset. */ - protected function sendResetFailedResponse(Request $request, string $response): RedirectResponse + protected function sendResetFailedResponse(Request $request, string $response, string $token): RedirectResponse { // We show invalid users as invalid tokens as to not leak what // users may exist in the system. @@ -91,7 +91,7 @@ class ResetPasswordController extends Controller $response = Password::INVALID_TOKEN; } - return redirect()->back() + return redirect("/password/reset/{$token}") ->withInput($request->only('email')) ->withErrors(['email' => trans($response)]); } diff --git a/app/Access/Controllers/Saml2Controller.php b/app/Access/Controllers/Saml2Controller.php index 2f1698446..6f802370e 100644 --- a/app/Access/Controllers/Saml2Controller.php +++ b/app/Access/Controllers/Saml2Controller.php @@ -9,14 +9,9 @@ use Illuminate\Support\Str; class Saml2Controller extends Controller { - protected Saml2Service $samlService; - - /** - * Saml2Controller constructor. - */ - public function __construct(Saml2Service $samlService) - { - $this->samlService = $samlService; + public function __construct( + protected Saml2Service $samlService + ) { $this->middleware('guard:saml2'); } @@ -36,7 +31,12 @@ class Saml2Controller extends Controller */ public function logout() { - $logoutDetails = $this->samlService->logout(auth()->user()); + $user = user(); + if ($user->isGuest()) { + return redirect('/login'); + } + + $logoutDetails = $this->samlService->logout($user); if ($logoutDetails['id']) { session()->flash('saml2_logout_request_id', $logoutDetails['id']); @@ -64,7 +64,7 @@ class Saml2Controller extends Controller public function sls() { $requestId = session()->pull('saml2_logout_request_id', null); - $redirect = $this->samlService->processSlsResponse($requestId) ?? '/'; + $redirect = $this->samlService->processSlsResponse($requestId); return redirect($redirect); } diff --git a/app/Access/Controllers/SocialController.php b/app/Access/Controllers/SocialController.php index ff6d5c2dd..07f57062d 100644 --- a/app/Access/Controllers/SocialController.php +++ b/app/Access/Controllers/SocialController.php @@ -79,7 +79,7 @@ class SocialController extends Controller try { return $this->socialAuthService->handleLoginCallback($socialDriver, $socialUser); } catch (SocialSignInAccountNotUsed $exception) { - if ($this->socialAuthService->driverAutoRegisterEnabled($socialDriver)) { + if ($this->socialAuthService->drivers()->isAutoRegisterEnabled($socialDriver)) { return $this->socialRegisterCallback($socialDriver, $socialUser); } @@ -91,7 +91,7 @@ class SocialController extends Controller return $this->socialRegisterCallback($socialDriver, $socialUser); } - return redirect()->back(); + return redirect('/'); } /** @@ -114,7 +114,7 @@ class SocialController extends Controller { $socialUser = $this->socialAuthService->handleRegistrationCallback($socialDriver, $socialUser); $socialAccount = $this->socialAuthService->newSocialAccount($socialDriver, $socialUser); - $emailVerified = $this->socialAuthService->driverAutoConfirmEmailEnabled($socialDriver); + $emailVerified = $this->socialAuthService->drivers()->isAutoConfirmEmailEnabled($socialDriver); // Create an array of the user data to create a new user instance $userData = [ diff --git a/app/Access/LoginService.php b/app/Access/LoginService.php index 27480ba21..cc48e0f9b 100644 --- a/app/Access/LoginService.php +++ b/app/Access/LoginService.php @@ -16,13 +16,11 @@ class LoginService { protected const LAST_LOGIN_ATTEMPTED_SESSION_KEY = 'auth-login-last-attempted'; - protected $mfaSession; - protected $emailConfirmationService; - - public function __construct(MfaSession $mfaSession, EmailConfirmationService $emailConfirmationService) - { - $this->mfaSession = $mfaSession; - $this->emailConfirmationService = $emailConfirmationService; + public function __construct( + protected MfaSession $mfaSession, + protected EmailConfirmationService $emailConfirmationService, + protected SocialDriverManager $socialDriverManager, + ) { } /** @@ -163,4 +161,33 @@ class LoginService return $result; } + + /** + * Logs the current user out of the application. + * Returns an app post-redirect path. + */ + public function logout(): string + { + auth()->logout(); + session()->invalidate(); + session()->regenerateToken(); + + return $this->shouldAutoInitiate() ? '/login?prevent_auto_init=true' : '/'; + } + + /** + * Check if login auto-initiate should be active based upon authentication config. + */ + public function shouldAutoInitiate(): bool + { + $autoRedirect = config('auth.auto_initiate'); + if (!$autoRedirect) { + return false; + } + + $socialDrivers = $this->socialDriverManager->getActive(); + $authMethod = config('auth.method'); + + return count($socialDrivers) === 0 && in_array($authMethod, ['oidc', 'saml2']); + } } diff --git a/app/Access/Oidc/OidcProviderSettings.php b/app/Access/Oidc/OidcProviderSettings.php index fa3f579b1..bea6a523e 100644 --- a/app/Access/Oidc/OidcProviderSettings.php +++ b/app/Access/Oidc/OidcProviderSettings.php @@ -21,6 +21,7 @@ class OidcProviderSettings public ?string $redirectUri; public ?string $authorizationEndpoint; public ?string $tokenEndpoint; + public ?string $endSessionEndpoint; /** * @var string[]|array[] @@ -132,6 +133,10 @@ class OidcProviderSettings $discoveredSettings['keys'] = $this->filterKeys($keys); } + if (!empty($result['end_session_endpoint'])) { + $discoveredSettings['endSessionEndpoint'] = $result['end_session_endpoint']; + } + return $discoveredSettings; } diff --git a/app/Access/Oidc/OidcService.php b/app/Access/Oidc/OidcService.php index 8778cbd98..f1e5b25af 100644 --- a/app/Access/Oidc/OidcService.php +++ b/app/Access/Oidc/OidcService.php @@ -84,6 +84,7 @@ class OidcService 'redirectUri' => url('/oidc/callback'), 'authorizationEndpoint' => $config['authorization_endpoint'], 'tokenEndpoint' => $config['token_endpoint'], + 'endSessionEndpoint' => is_string($config['end_session_endpoint']) ? $config['end_session_endpoint'] : null, ]); // Use keys if configured @@ -100,6 +101,14 @@ class OidcService } } + // Prevent use of RP-initiated logout if specifically disabled + // Or force use of a URL if specifically set. + if ($config['end_session_endpoint'] === false) { + $settings->endSessionEndpoint = null; + } else if (is_string($config['end_session_endpoint'])) { + $settings->endSessionEndpoint = $config['end_session_endpoint']; + } + $settings->validate(); return $settings; @@ -217,6 +226,8 @@ class OidcService $settings->keys, ); + session()->put("oidc_id_token", $idTokenText); + $returnClaims = Theme::dispatch(ThemeEvents::OIDC_ID_TOKEN_PRE_VALIDATE, $idToken->getAllClaims(), [ 'access_token' => $accessToken->getToken(), 'expires_in' => $accessToken->getExpires(), @@ -284,4 +295,30 @@ class OidcService { return $this->config()['user_to_groups'] !== false; } + + /** + * Start the RP-initiated logout flow if active, otherwise start a standard logout flow. + * Returns a post-app-logout redirect URL. + * Reference: https://openid.net/specs/openid-connect-rpinitiated-1_0.html + * @throws OidcException + */ + public function logout(): string + { + $oidcToken = session()->pull("oidc_id_token"); + $defaultLogoutUrl = url($this->loginService->logout()); + $oidcSettings = $this->getProviderSettings(); + + if (!$oidcSettings->endSessionEndpoint) { + return $defaultLogoutUrl; + } + + $endpointParams = [ + 'id_token_hint' => $oidcToken, + 'post_logout_redirect_uri' => $defaultLogoutUrl, + ]; + + $joiner = str_contains($oidcSettings->endSessionEndpoint, '?') ? '&' : '?'; + + return $oidcSettings->endSessionEndpoint . $joiner . http_build_query($endpointParams); + } } diff --git a/app/Access/Saml2Service.php b/app/Access/Saml2Service.php index c033bd6a1..664b77aba 100644 --- a/app/Access/Saml2Service.php +++ b/app/Access/Saml2Service.php @@ -21,19 +21,13 @@ use OneLogin\Saml2\ValidationError; class Saml2Service { protected array $config; - protected RegistrationService $registrationService; - protected LoginService $loginService; - protected GroupSyncService $groupSyncService; public function __construct( - RegistrationService $registrationService, - LoginService $loginService, - GroupSyncService $groupSyncService + protected RegistrationService $registrationService, + protected LoginService $loginService, + protected GroupSyncService $groupSyncService ) { $this->config = config('saml2'); - $this->registrationService = $registrationService; - $this->loginService = $loginService; - $this->groupSyncService = $groupSyncService; } /** @@ -54,20 +48,23 @@ class Saml2Service /** * Initiate a logout flow. + * Returns the SAML2 request ID, and the URL to redirect the user to. * * @throws Error + * @returns array{url: string, id: ?string} */ public function logout(User $user): array { $toolKit = $this->getToolkit(); - $returnRoute = url('/'); + $sessionIndex = session()->get('saml2_session_index'); + $returnUrl = url($this->loginService->logout()); try { $url = $toolKit->logout( - $returnRoute, + $returnUrl, [], $user->email, - session()->get('saml2_session_index'), + $sessionIndex, true, Constants::NAMEID_EMAIL_ADDRESS ); @@ -77,8 +74,7 @@ class Saml2Service throw $error; } - $this->actionLogout(); - $url = '/'; + $url = $returnUrl; $id = null; } @@ -128,7 +124,7 @@ class Saml2Service * * @throws Error */ - public function processSlsResponse(?string $requestId): ?string + public function processSlsResponse(?string $requestId): string { $toolkit = $this->getToolkit(); @@ -137,7 +133,7 @@ class Saml2Service // value so that the exact encoding format is matched when checking the signature. // This is primarily due to ADFS encoding query params with lowercase percent encoding while // PHP (And most other sensible providers) standardise on uppercase. - $redirect = $toolkit->processSLO(true, $requestId, true, null, true); + $samlRedirect = $toolkit->processSLO(true, $requestId, true, null, true); $errors = $toolkit->getErrors(); if (!empty($errors)) { @@ -146,18 +142,9 @@ class Saml2Service ); } - $this->actionLogout(); + $defaultBookStackRedirect = $this->loginService->logout(); - return $redirect; - } - - /** - * Do the required actions to log a user out. - */ - protected function actionLogout() - { - auth()->logout(); - session()->invalidate(); + return $samlRedirect ?? $defaultBookStackRedirect; } /** @@ -357,6 +344,10 @@ class Saml2Service $userDetails = $this->getUserDetails($samlID, $samlAttributes); $isLoggedIn = auth()->check(); + if ($this->shouldSyncGroups()) { + $userDetails['groups'] = $this->getUserGroups($samlAttributes); + } + if ($this->config['dump_user_details']) { throw new JsonDebugException([ 'id_from_idp' => $samlID, @@ -379,13 +370,8 @@ class Saml2Service $userDetails['external_id'] ); - if ($user === null) { - throw new SamlException(trans('errors.saml_user_not_registered', ['name' => $userDetails['external_id']]), '/login'); - } - if ($this->shouldSyncGroups()) { - $groups = $this->getUserGroups($samlAttributes); - $this->groupSyncService->syncUserWithFoundGroups($user, $groups, $this->config['remove_from_groups']); + $this->groupSyncService->syncUserWithFoundGroups($user, $userDetails['groups'], $this->config['remove_from_groups']); } $this->loginService->login($user, 'saml2'); diff --git a/app/Access/SocialAuthService.php b/app/Access/SocialAuthService.php index f0e0413f0..c3c20587d 100644 --- a/app/Access/SocialAuthService.php +++ b/app/Access/SocialAuthService.php @@ -2,69 +2,24 @@ namespace BookStack\Access; -use BookStack\Auth\Access\handler; use BookStack\Exceptions\SocialDriverNotConfigured; use BookStack\Exceptions\SocialSignInAccountNotUsed; use BookStack\Exceptions\UserRegistrationException; use BookStack\Users\Models\User; -use Illuminate\Support\Facades\Event; use Illuminate\Support\Str; use Laravel\Socialite\Contracts\Factory as Socialite; use Laravel\Socialite\Contracts\Provider; use Laravel\Socialite\Contracts\User as SocialUser; use Laravel\Socialite\Two\GoogleProvider; -use SocialiteProviders\Manager\SocialiteWasCalled; use Symfony\Component\HttpFoundation\RedirectResponse; class SocialAuthService { - /** - * The core socialite library used. - * - * @var Socialite - */ - protected $socialite; - - /** - * @var LoginService - */ - protected $loginService; - - /** - * The default built-in social drivers we support. - * - * @var string[] - */ - protected $validSocialDrivers = [ - 'google', - 'github', - 'facebook', - 'slack', - 'twitter', - 'azure', - 'okta', - 'gitlab', - 'twitch', - 'discord', - ]; - - /** - * Callbacks to run when configuring a social driver - * for an initial redirect action. - * Array is keyed by social driver name. - * Callbacks are passed an instance of the driver. - * - * @var array - */ - protected $configureForRedirectCallbacks = []; - - /** - * SocialAuthService constructor. - */ - public function __construct(Socialite $socialite, LoginService $loginService) - { - $this->socialite = $socialite; - $this->loginService = $loginService; + public function __construct( + protected Socialite $socialite, + protected LoginService $loginService, + protected SocialDriverManager $driverManager, + ) { } /** @@ -74,9 +29,10 @@ class SocialAuthService */ public function startLogIn(string $socialDriver): RedirectResponse { - $driver = $this->validateDriver($socialDriver); + $socialDriver = trim(strtolower($socialDriver)); + $this->driverManager->ensureDriverActive($socialDriver); - return $this->getDriverForRedirect($driver)->redirect(); + return $this->getDriverForRedirect($socialDriver)->redirect(); } /** @@ -86,9 +42,10 @@ class SocialAuthService */ public function startRegister(string $socialDriver): RedirectResponse { - $driver = $this->validateDriver($socialDriver); + $socialDriver = trim(strtolower($socialDriver)); + $this->driverManager->ensureDriverActive($socialDriver); - return $this->getDriverForRedirect($driver)->redirect(); + return $this->getDriverForRedirect($socialDriver)->redirect(); } /** @@ -119,9 +76,10 @@ class SocialAuthService */ public function getSocialUser(string $socialDriver): SocialUser { - $driver = $this->validateDriver($socialDriver); + $socialDriver = trim(strtolower($socialDriver)); + $this->driverManager->ensureDriverActive($socialDriver); - return $this->socialite->driver($driver)->user(); + return $this->socialite->driver($socialDriver)->user(); } /** @@ -131,6 +89,7 @@ class SocialAuthService */ public function handleLoginCallback(string $socialDriver, SocialUser $socialUser) { + $socialDriver = trim(strtolower($socialDriver)); $socialId = $socialUser->getId(); // Get any attached social accounts or users @@ -181,76 +140,11 @@ class SocialAuthService } /** - * Ensure the social driver is correct and supported. - * - * @throws SocialDriverNotConfigured + * Get the social driver manager used by this service. */ - protected function validateDriver(string $socialDriver): string + public function drivers(): SocialDriverManager { - $driver = trim(strtolower($socialDriver)); - - if (!in_array($driver, $this->validSocialDrivers)) { - abort(404, trans('errors.social_driver_not_found')); - } - - if (!$this->checkDriverConfigured($driver)) { - throw new SocialDriverNotConfigured(trans('errors.social_driver_not_configured', ['socialAccount' => Str::title($socialDriver)])); - } - - return $driver; - } - - /** - * Check a social driver has been configured correctly. - */ - protected function checkDriverConfigured(string $driver): bool - { - $lowerName = strtolower($driver); - $configPrefix = 'services.' . $lowerName . '.'; - $config = [config($configPrefix . 'client_id'), config($configPrefix . 'client_secret'), config('services.callback_url')]; - - return !in_array(false, $config) && !in_array(null, $config); - } - - /** - * Gets the names of the active social drivers. - * @returns array - */ - public function getActiveDrivers(): array - { - $activeDrivers = []; - - foreach ($this->validSocialDrivers as $driverKey) { - if ($this->checkDriverConfigured($driverKey)) { - $activeDrivers[$driverKey] = $this->getDriverName($driverKey); - } - } - - return $activeDrivers; - } - - /** - * Get the presentational name for a driver. - */ - public function getDriverName(string $driver): string - { - return config('services.' . strtolower($driver) . '.name'); - } - - /** - * Check if the current config for the given driver allows auto-registration. - */ - public function driverAutoRegisterEnabled(string $driver): bool - { - return config('services.' . strtolower($driver) . '.auto_register') === true; - } - - /** - * Check if the current config for the given driver allow email address auto-confirmation. - */ - public function driverAutoConfirmEmailEnabled(string $driver): bool - { - return config('services.' . strtolower($driver) . '.auto_confirm') === true; + return $this->driverManager; } /** @@ -284,33 +178,8 @@ class SocialAuthService $driver->with(['prompt' => 'select_account']); } - if (isset($this->configureForRedirectCallbacks[$driverName])) { - $this->configureForRedirectCallbacks[$driverName]($driver); - } + $this->driverManager->getConfigureForRedirectCallback($driverName)($driver); return $driver; } - - /** - * Add a custom socialite driver to be used. - * Driver name should be lower_snake_case. - * Config array should mirror the structure of a service - * within the `Config/services.php` file. - * Handler should be a Class@method handler to the SocialiteWasCalled event. - */ - public function addSocialDriver( - string $driverName, - array $config, - string $socialiteHandler, - callable $configureForRedirect = null - ) { - $this->validSocialDrivers[] = $driverName; - config()->set('services.' . $driverName, $config); - config()->set('services.' . $driverName . '.redirect', url('/login/service/' . $driverName . '/callback')); - config()->set('services.' . $driverName . '.name', $config['name'] ?? $driverName); - Event::listen(SocialiteWasCalled::class, $socialiteHandler); - if (!is_null($configureForRedirect)) { - $this->configureForRedirectCallbacks[$driverName] = $configureForRedirect; - } - } } diff --git a/app/Access/SocialDriverManager.php b/app/Access/SocialDriverManager.php new file mode 100644 index 000000000..536b2e63d --- /dev/null +++ b/app/Access/SocialDriverManager.php @@ -0,0 +1,147 @@ + + */ + protected array $configureForRedirectCallbacks = []; + + /** + * Check if the current config for the given driver allows auto-registration. + */ + public function isAutoRegisterEnabled(string $driver): bool + { + return $this->getDriverConfigProperty($driver, 'auto_register') === true; + } + + /** + * Check if the current config for the given driver allow email address auto-confirmation. + */ + public function isAutoConfirmEmailEnabled(string $driver): bool + { + return $this->getDriverConfigProperty($driver, 'auto_confirm') === true; + } + + /** + * Gets the names of the active social drivers, keyed by driver id. + * @returns array + */ + public function getActive(): array + { + $activeDrivers = []; + + foreach ($this->validDrivers as $driverKey) { + if ($this->checkDriverConfigured($driverKey)) { + $activeDrivers[$driverKey] = $this->getName($driverKey); + } + } + + return $activeDrivers; + } + + /** + * Get the configure-for-redirect callback for the given driver. + * This is a callable that allows modification of the driver at redirect time. + * Commonly used to perform custom dynamic configuration where required. + * The callback is passed a \Laravel\Socialite\Contracts\Provider instance. + */ + public function getConfigureForRedirectCallback(string $driver): callable + { + return $this->configureForRedirectCallbacks[$driver] ?? (fn() => true); + } + + /** + * Add a custom socialite driver to be used. + * Driver name should be lower_snake_case. + * Config array should mirror the structure of a service + * within the `Config/services.php` file. + * Handler should be a Class@method handler to the SocialiteWasCalled event. + */ + public function addSocialDriver( + string $driverName, + array $config, + string $socialiteHandler, + callable $configureForRedirect = null + ) { + $this->validDrivers[] = $driverName; + config()->set('services.' . $driverName, $config); + config()->set('services.' . $driverName . '.redirect', url('/login/service/' . $driverName . '/callback')); + config()->set('services.' . $driverName . '.name', $config['name'] ?? $driverName); + Event::listen(SocialiteWasCalled::class, $socialiteHandler); + if (!is_null($configureForRedirect)) { + $this->configureForRedirectCallbacks[$driverName] = $configureForRedirect; + } + } + + /** + * Get the presentational name for a driver. + */ + protected function getName(string $driver): string + { + return $this->getDriverConfigProperty($driver, 'name') ?? ''; + } + + protected function getDriverConfigProperty(string $driver, string $property): mixed + { + return config("services.{$driver}.{$property}"); + } + + /** + * Ensure the social driver is correct and supported. + * + * @throws SocialDriverNotConfigured + */ + public function ensureDriverActive(string $driverName): void + { + if (!in_array($driverName, $this->validDrivers)) { + abort(404, trans('errors.social_driver_not_found')); + } + + if (!$this->checkDriverConfigured($driverName)) { + throw new SocialDriverNotConfigured(trans('errors.social_driver_not_configured', ['socialAccount' => Str::title($driverName)])); + } + } + + /** + * Check a social driver has been configured correctly. + */ + protected function checkDriverConfigured(string $driver): bool + { + $lowerName = strtolower($driver); + $configPrefix = 'services.' . $lowerName . '.'; + $config = [config($configPrefix . 'client_id'), config($configPrefix . 'client_secret'), config('services.callback_url')]; + + return !in_array(false, $config) && !in_array(null, $config); + } +} diff --git a/app/Activity/Controllers/FavouriteController.php b/app/Activity/Controllers/FavouriteController.php index d2534ddfe..b3aff1cef 100644 --- a/app/Activity/Controllers/FavouriteController.php +++ b/app/Activity/Controllers/FavouriteController.php @@ -2,9 +2,6 @@ namespace BookStack\Activity\Controllers; -use BookStack\Activity\Models\Favouritable; -use BookStack\App\Model; -use BookStack\Entities\Models\Entity; use BookStack\Entities\Queries\TopFavourites; use BookStack\Entities\Tools\MixedEntityRequestHelper; use BookStack\Http\Controller; @@ -52,7 +49,7 @@ class FavouriteController extends Controller 'name' => $entity->name, ])); - return redirect()->back(); + return redirect($entity->getUrl()); } /** @@ -70,6 +67,6 @@ class FavouriteController extends Controller 'name' => $entity->name, ])); - return redirect()->back(); + return redirect($entity->getUrl()); } } diff --git a/app/Activity/Controllers/WatchController.php b/app/Activity/Controllers/WatchController.php index c0b1c5872..5df75da39 100644 --- a/app/Activity/Controllers/WatchController.php +++ b/app/Activity/Controllers/WatchController.php @@ -24,6 +24,6 @@ class WatchController extends Controller $this->showSuccessNotification(trans('activities.watch_update_level_notification')); - return redirect()->back(); + return redirect($watchable->getUrl()); } } diff --git a/app/Activity/Models/Activity.php b/app/Activity/Models/Activity.php index 9e4cb7858..5fad9f1d3 100644 --- a/app/Activity/Models/Activity.php +++ b/app/Activity/Models/Activity.php @@ -9,6 +9,7 @@ use BookStack\Users\Models\User; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\MorphTo; +use Illuminate\Support\Carbon; use Illuminate\Support\Str; /** diff --git a/app/Activity/Notifications/MessageParts/EntityLinkMessageLine.php b/app/Activity/Notifications/MessageParts/EntityLinkMessageLine.php new file mode 100644 index 000000000..599833cce --- /dev/null +++ b/app/Activity/Notifications/MessageParts/EntityLinkMessageLine.php @@ -0,0 +1,29 @@ +entity->getUrl()) . '">' . e($this->entity->getShortName($this->nameLength)) . ''; + } + + public function __toString(): string + { + return "{$this->entity->getShortName($this->nameLength)} ({$this->entity->getUrl()})"; + } +} diff --git a/app/Activity/Notifications/MessageParts/EntityPathMessageLine.php b/app/Activity/Notifications/MessageParts/EntityPathMessageLine.php new file mode 100644 index 000000000..4b0f6e6cf --- /dev/null +++ b/app/Activity/Notifications/MessageParts/EntityPathMessageLine.php @@ -0,0 +1,35 @@ +entityLinks = array_map(fn (Entity $entity) => new EntityLinkMessageLine($entity, 24), $this->entities); + } + + public function toHtml(): string + { + $entityHtmls = array_map(fn (EntityLinkMessageLine $line) => $line->toHtml(), $this->entityLinks); + return implode(' > ', $entityHtmls); + } + + public function __toString(): string + { + return implode(' > ', $this->entityLinks); + } +} diff --git a/app/Activity/Notifications/Messages/BaseActivityNotification.php b/app/Activity/Notifications/Messages/BaseActivityNotification.php index 322df5d94..ca86eb81b 100644 --- a/app/Activity/Notifications/Messages/BaseActivityNotification.php +++ b/app/Activity/Notifications/Messages/BaseActivityNotification.php @@ -3,8 +3,12 @@ namespace BookStack\Activity\Notifications\Messages; use BookStack\Activity\Models\Loggable; +use BookStack\Activity\Notifications\MessageParts\EntityPathMessageLine; use BookStack\Activity\Notifications\MessageParts\LinkedMailMessageLine; use BookStack\App\MailNotification; +use BookStack\Entities\Models\Entity; +use BookStack\Entities\Models\Page; +use BookStack\Permissions\PermissionApplicator; use BookStack\Translation\LocaleDefinition; use BookStack\Users\Models\User; use Illuminate\Bus\Queueable; @@ -44,4 +48,20 @@ abstract class BaseActivityNotification extends MailNotification $locale->trans('notifications.footer_reason_link'), ); } + + /** + * Build a line which provides the book > chapter path to a page. + * Takes into account visibility of these parent items. + * Returns null if no path items can be used. + */ + protected function buildPagePathLine(Page $page, User $notifiable): ?EntityPathMessageLine + { + $permissions = new PermissionApplicator($notifiable); + + $path = array_filter([$page->book, $page->chapter], function (?Entity $entity) use ($permissions) { + return !is_null($entity) && $permissions->checkOwnableUserAccess($entity, 'view'); + }); + + return empty($path) ? null : new EntityPathMessageLine($path); + } } diff --git a/app/Activity/Notifications/Messages/CommentCreationNotification.php b/app/Activity/Notifications/Messages/CommentCreationNotification.php index 094ab30b7..30d0ffa2b 100644 --- a/app/Activity/Notifications/Messages/CommentCreationNotification.php +++ b/app/Activity/Notifications/Messages/CommentCreationNotification.php @@ -3,6 +3,7 @@ namespace BookStack\Activity\Notifications\Messages; use BookStack\Activity\Models\Comment; +use BookStack\Activity\Notifications\MessageParts\EntityLinkMessageLine; use BookStack\Activity\Notifications\MessageParts\ListMessageLine; use BookStack\Entities\Models\Page; use BookStack\Users\Models\User; @@ -19,14 +20,17 @@ class CommentCreationNotification extends BaseActivityNotification $locale = $notifiable->getLocale(); + $listLines = array_filter([ + $locale->trans('notifications.detail_page_name') => new EntityLinkMessageLine($page), + $locale->trans('notifications.detail_page_path') => $this->buildPagePathLine($page, $notifiable), + $locale->trans('notifications.detail_commenter') => $this->user->name, + $locale->trans('notifications.detail_comment') => strip_tags($comment->html), + ]); + return $this->newMailMessage($locale) ->subject($locale->trans('notifications.new_comment_subject', ['pageName' => $page->getShortName()])) ->line($locale->trans('notifications.new_comment_intro', ['appName' => setting('app-name')])) - ->line(new ListMessageLine([ - $locale->trans('notifications.detail_page_name') => $page->name, - $locale->trans('notifications.detail_commenter') => $this->user->name, - $locale->trans('notifications.detail_comment') => strip_tags($comment->html), - ])) + ->line(new ListMessageLine($listLines)) ->action($locale->trans('notifications.action_view_comment'), $page->getUrl('#comment' . $comment->local_id)) ->line($this->buildReasonFooterLine($locale)); } diff --git a/app/Activity/Notifications/Messages/PageCreationNotification.php b/app/Activity/Notifications/Messages/PageCreationNotification.php index da028aa8c..0b98ad30c 100644 --- a/app/Activity/Notifications/Messages/PageCreationNotification.php +++ b/app/Activity/Notifications/Messages/PageCreationNotification.php @@ -2,6 +2,7 @@ namespace BookStack\Activity\Notifications\Messages; +use BookStack\Activity\Notifications\MessageParts\EntityLinkMessageLine; use BookStack\Activity\Notifications\MessageParts\ListMessageLine; use BookStack\Entities\Models\Page; use BookStack\Users\Models\User; @@ -16,13 +17,16 @@ class PageCreationNotification extends BaseActivityNotification $locale = $notifiable->getLocale(); + $listLines = array_filter([ + $locale->trans('notifications.detail_page_name') => new EntityLinkMessageLine($page), + $locale->trans('notifications.detail_page_path') => $this->buildPagePathLine($page, $notifiable), + $locale->trans('notifications.detail_created_by') => $this->user->name, + ]); + return $this->newMailMessage($locale) ->subject($locale->trans('notifications.new_page_subject', ['pageName' => $page->getShortName()])) - ->line($locale->trans('notifications.new_page_intro', ['appName' => setting('app-name')], $locale)) - ->line(new ListMessageLine([ - $locale->trans('notifications.detail_page_name') => $page->name, - $locale->trans('notifications.detail_created_by') => $this->user->name, - ])) + ->line($locale->trans('notifications.new_page_intro', ['appName' => setting('app-name')])) + ->line(new ListMessageLine($listLines)) ->action($locale->trans('notifications.action_view_page'), $page->getUrl()) ->line($this->buildReasonFooterLine($locale)); } diff --git a/app/Activity/Notifications/Messages/PageUpdateNotification.php b/app/Activity/Notifications/Messages/PageUpdateNotification.php index 1c8155d29..80ee378cc 100644 --- a/app/Activity/Notifications/Messages/PageUpdateNotification.php +++ b/app/Activity/Notifications/Messages/PageUpdateNotification.php @@ -2,6 +2,7 @@ namespace BookStack\Activity\Notifications\Messages; +use BookStack\Activity\Notifications\MessageParts\EntityLinkMessageLine; use BookStack\Activity\Notifications\MessageParts\ListMessageLine; use BookStack\Entities\Models\Page; use BookStack\Users\Models\User; @@ -16,13 +17,16 @@ class PageUpdateNotification extends BaseActivityNotification $locale = $notifiable->getLocale(); + $listLines = array_filter([ + $locale->trans('notifications.detail_page_name') => new EntityLinkMessageLine($page), + $locale->trans('notifications.detail_page_path') => $this->buildPagePathLine($page, $notifiable), + $locale->trans('notifications.detail_updated_by') => $this->user->name, + ]); + return $this->newMailMessage($locale) ->subject($locale->trans('notifications.updated_page_subject', ['pageName' => $page->getShortName()])) ->line($locale->trans('notifications.updated_page_intro', ['appName' => setting('app-name')])) - ->line(new ListMessageLine([ - $locale->trans('notifications.detail_page_name') => $page->name, - $locale->trans('notifications.detail_updated_by') => $this->user->name, - ])) + ->line(new ListMessageLine($listLines)) ->line($locale->trans('notifications.updated_page_debounce')) ->action($locale->trans('notifications.action_view_page'), $page->getUrl()) ->line($this->buildReasonFooterLine($locale)); diff --git a/app/App/Providers/AppServiceProvider.php b/app/App/Providers/AppServiceProvider.php index 0275a5489..0f4dc55dd 100644 --- a/app/App/Providers/AppServiceProvider.php +++ b/app/App/Providers/AppServiceProvider.php @@ -2,7 +2,7 @@ namespace BookStack\App\Providers; -use BookStack\Access\SocialAuthService; +use BookStack\Access\SocialDriverManager; use BookStack\Activity\Tools\ActivityLogger; use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Bookshelf; @@ -36,7 +36,7 @@ class AppServiceProvider extends ServiceProvider public $singletons = [ 'activity' => ActivityLogger::class, SettingService::class => SettingService::class, - SocialAuthService::class => SocialAuthService::class, + SocialDriverManager::class => SocialDriverManager::class, CspService::class => CspService::class, HttpRequestService::class => HttpRequestService::class, ]; diff --git a/app/App/Providers/RouteServiceProvider.php b/app/App/Providers/RouteServiceProvider.php index 913dfa435..abd556244 100644 --- a/app/App/Providers/RouteServiceProvider.php +++ b/app/App/Providers/RouteServiceProvider.php @@ -2,9 +2,12 @@ namespace BookStack\App\Providers; +use BookStack\Facades\Theme; +use BookStack\Theming\ThemeEvents; use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider; use Illuminate\Http\Request; +use Illuminate\Routing\Router; use Illuminate\Support\Facades\RateLimiter; use Illuminate\Support\Facades\Route; @@ -46,8 +49,15 @@ class RouteServiceProvider extends ServiceProvider Route::group([ 'middleware' => 'web', 'namespace' => $this->namespace, - ], function ($router) { + ], function (Router $router) { require base_path('routes/web.php'); + Theme::dispatch(ThemeEvents::ROUTES_REGISTER_WEB, $router); + }); + + Route::group([ + 'middleware' => ['web', 'auth'], + ], function (Router $router) { + Theme::dispatch(ThemeEvents::ROUTES_REGISTER_WEB_AUTH, $router); }); } diff --git a/app/App/Providers/ThemeServiceProvider.php b/app/App/Providers/ThemeServiceProvider.php index 4c657d912..c15b43a6b 100644 --- a/app/App/Providers/ThemeServiceProvider.php +++ b/app/App/Providers/ThemeServiceProvider.php @@ -4,6 +4,7 @@ namespace BookStack\App\Providers; use BookStack\Theming\ThemeEvents; use BookStack\Theming\ThemeService; +use Illuminate\Support\Facades\Route; use Illuminate\Support\ServiceProvider; class ThemeServiceProvider extends ServiceProvider diff --git a/app/Config/oidc.php b/app/Config/oidc.php index b28b8a41a..7f8f40d41 100644 --- a/app/Config/oidc.php +++ b/app/Config/oidc.php @@ -36,6 +36,12 @@ return [ 'authorization_endpoint' => env('OIDC_AUTH_ENDPOINT', null), 'token_endpoint' => env('OIDC_TOKEN_ENDPOINT', null), + // OIDC RP-Initiated Logout endpoint URL. + // A false value force-disables RP-Initiated Logout. + // A true value gets the URL from discovery, if active. + // A string value is used as the URL. + 'end_session_endpoint' => env('OIDC_END_SESSION_ENDPOINT', false), + // Add extra scopes, upon those required, to the OIDC authentication request // Multiple values can be provided comma seperated. 'additional_scopes' => env('OIDC_ADDITIONAL_SCOPES', null), @@ -45,6 +51,6 @@ return [ 'user_to_groups' => env('OIDC_USER_TO_GROUPS', false), // Attribute, within a OIDC ID token, to find group names within 'groups_claim' => env('OIDC_GROUPS_CLAIM', 'groups'), - // When syncing groups, remove any groups that no longer match. Otherwise sync only adds new groups. + // When syncing groups, remove any groups that no longer match. Otherwise, sync only adds new groups. 'remove_from_groups' => env('OIDC_REMOVE_FROM_GROUPS', false), ]; diff --git a/app/Console/Commands/RegenerateReferencesCommand.php b/app/Console/Commands/RegenerateReferencesCommand.php index ea8ff8e00..563da100a 100644 --- a/app/Console/Commands/RegenerateReferencesCommand.php +++ b/app/Console/Commands/RegenerateReferencesCommand.php @@ -34,7 +34,7 @@ class RegenerateReferencesCommand extends Command DB::setDefaultConnection($this->option('database')); } - $references->updateForAllPages(); + $references->updateForAll(); DB::setDefaultConnection($connection); diff --git a/app/Console/Commands/UpdateUrlCommand.php b/app/Console/Commands/UpdateUrlCommand.php index 27f84cc89..0c95b0a3c 100644 --- a/app/Console/Commands/UpdateUrlCommand.php +++ b/app/Console/Commands/UpdateUrlCommand.php @@ -46,6 +46,9 @@ class UpdateUrlCommand extends Command $columnsToUpdateByTable = [ 'attachments' => ['path'], 'pages' => ['html', 'text', 'markdown'], + 'chapters' => ['description_html'], + 'books' => ['description_html'], + 'bookshelves' => ['description_html'], 'images' => ['url'], 'settings' => ['value'], 'comments' => ['html', 'text'], diff --git a/app/Entities/Controllers/BookApiController.php b/app/Entities/Controllers/BookApiController.php index cb67184a0..aa21aea47 100644 --- a/app/Entities/Controllers/BookApiController.php +++ b/app/Entities/Controllers/BookApiController.php @@ -14,11 +14,9 @@ use Illuminate\Validation\ValidationException; class BookApiController extends ApiController { - protected BookRepo $bookRepo; - - public function __construct(BookRepo $bookRepo) - { - $this->bookRepo = $bookRepo; + public function __construct( + protected BookRepo $bookRepo + ) { } /** @@ -47,7 +45,7 @@ class BookApiController extends ApiController $book = $this->bookRepo->create($requestData); - return response()->json($book); + return response()->json($this->forJsonDisplay($book)); } /** @@ -58,7 +56,9 @@ class BookApiController extends ApiController */ public function read(string $id) { - $book = Book::visible()->with(['tags', 'cover', 'createdBy', 'updatedBy', 'ownedBy'])->findOrFail($id); + $book = Book::visible()->findOrFail($id); + $book = $this->forJsonDisplay($book); + $book->load(['createdBy', 'updatedBy', 'ownedBy']); $contents = (new BookContents($book))->getTree(true, false)->all(); $contentsApiData = (new ApiEntityListFormatter($contents)) @@ -89,7 +89,7 @@ class BookApiController extends ApiController $requestData = $this->validate($request, $this->rules()['update']); $book = $this->bookRepo->update($book, $requestData); - return response()->json($book); + return response()->json($this->forJsonDisplay($book)); } /** @@ -108,20 +108,36 @@ class BookApiController extends ApiController return response('', 204); } + protected function forJsonDisplay(Book $book): Book + { + $book = clone $book; + $book->unsetRelations()->refresh(); + + $book->load(['tags', 'cover']); + $book->makeVisible('description_html') + ->setAttribute('description_html', $book->descriptionHtml()); + + return $book; + } + protected function rules(): array { return [ 'create' => [ - 'name' => ['required', 'string', 'max:255'], - 'description' => ['string', 'max:1000'], - 'tags' => ['array'], - 'image' => array_merge(['nullable'], $this->getImageValidationRules()), + 'name' => ['required', 'string', 'max:255'], + 'description' => ['string', 'max:1900'], + 'description_html' => ['string', 'max:2000'], + 'tags' => ['array'], + 'image' => array_merge(['nullable'], $this->getImageValidationRules()), + 'default_template_id' => ['nullable', 'integer'], ], 'update' => [ - 'name' => ['string', 'min:1', 'max:255'], - 'description' => ['string', 'max:1000'], - 'tags' => ['array'], - 'image' => array_merge(['nullable'], $this->getImageValidationRules()), + 'name' => ['string', 'min:1', 'max:255'], + 'description' => ['string', 'max:1900'], + 'description_html' => ['string', 'max:2000'], + 'tags' => ['array'], + 'image' => array_merge(['nullable'], $this->getImageValidationRules()), + 'default_template_id' => ['nullable', 'integer'], ], ]; } diff --git a/app/Entities/Controllers/BookController.php b/app/Entities/Controllers/BookController.php index 55d28c684..412feca2f 100644 --- a/app/Entities/Controllers/BookController.php +++ b/app/Entities/Controllers/BookController.php @@ -24,15 +24,11 @@ use Throwable; class BookController extends Controller { - protected BookRepo $bookRepo; - protected ShelfContext $shelfContext; - protected ReferenceFetcher $referenceFetcher; - - public function __construct(ShelfContext $entityContextManager, BookRepo $bookRepo, ReferenceFetcher $referenceFetcher) - { - $this->bookRepo = $bookRepo; - $this->shelfContext = $entityContextManager; - $this->referenceFetcher = $referenceFetcher; + public function __construct( + protected ShelfContext $shelfContext, + protected BookRepo $bookRepo, + protected ReferenceFetcher $referenceFetcher + ) { } /** @@ -96,10 +92,11 @@ class BookController extends Controller { $this->checkPermission('book-create-all'); $validated = $this->validate($request, [ - 'name' => ['required', 'string', 'max:255'], - 'description' => ['string', 'max:1000'], - 'image' => array_merge(['nullable'], $this->getImageValidationRules()), - 'tags' => ['array'], + 'name' => ['required', 'string', 'max:255'], + 'description_html' => ['string', 'max:2000'], + 'image' => array_merge(['nullable'], $this->getImageValidationRules()), + 'tags' => ['array'], + 'default_template_id' => ['nullable', 'integer'], ]); $bookshelf = null; @@ -141,7 +138,7 @@ class BookController extends Controller 'bookParentShelves' => $bookParentShelves, 'watchOptions' => new UserEntityWatchOptions(user(), $book), 'activity' => $activities->entityActivity($book, 20, 1), - 'referenceCount' => $this->referenceFetcher->getPageReferenceCountToEntity($book), + 'referenceCount' => $this->referenceFetcher->getReferenceCountToEntity($book), ]); } @@ -170,10 +167,11 @@ class BookController extends Controller $this->checkOwnablePermission('book-update', $book); $validated = $this->validate($request, [ - 'name' => ['required', 'string', 'max:255'], - 'description' => ['string', 'max:1000'], - 'image' => array_merge(['nullable'], $this->getImageValidationRules()), - 'tags' => ['array'], + 'name' => ['required', 'string', 'max:255'], + 'description_html' => ['string', 'max:2000'], + 'image' => array_merge(['nullable'], $this->getImageValidationRules()), + 'tags' => ['array'], + 'default_template_id' => ['nullable', 'integer'], ]); if ($request->has('image_reset')) { diff --git a/app/Entities/Controllers/BookshelfApiController.php b/app/Entities/Controllers/BookshelfApiController.php index 9bdb8256d..a12dc90ac 100644 --- a/app/Entities/Controllers/BookshelfApiController.php +++ b/app/Entities/Controllers/BookshelfApiController.php @@ -12,11 +12,9 @@ use Illuminate\Validation\ValidationException; class BookshelfApiController extends ApiController { - protected BookshelfRepo $bookshelfRepo; - - public function __construct(BookshelfRepo $bookshelfRepo) - { - $this->bookshelfRepo = $bookshelfRepo; + public function __construct( + protected BookshelfRepo $bookshelfRepo + ) { } /** @@ -48,7 +46,7 @@ class BookshelfApiController extends ApiController $bookIds = $request->get('books', []); $shelf = $this->bookshelfRepo->create($requestData, $bookIds); - return response()->json($shelf); + return response()->json($this->forJsonDisplay($shelf)); } /** @@ -56,12 +54,14 @@ class BookshelfApiController extends ApiController */ public function read(string $id) { - $shelf = Bookshelf::visible()->with([ - 'tags', 'cover', 'createdBy', 'updatedBy', 'ownedBy', + $shelf = Bookshelf::visible()->findOrFail($id); + $shelf = $this->forJsonDisplay($shelf); + $shelf->load([ + 'createdBy', 'updatedBy', 'ownedBy', 'books' => function (BelongsToMany $query) { $query->scopes('visible')->get(['id', 'name', 'slug']); }, - ])->findOrFail($id); + ]); return response()->json($shelf); } @@ -86,7 +86,7 @@ class BookshelfApiController extends ApiController $shelf = $this->bookshelfRepo->update($shelf, $requestData, $bookIds); - return response()->json($shelf); + return response()->json($this->forJsonDisplay($shelf)); } /** @@ -105,22 +105,36 @@ class BookshelfApiController extends ApiController return response('', 204); } + protected function forJsonDisplay(Bookshelf $shelf): Bookshelf + { + $shelf = clone $shelf; + $shelf->unsetRelations()->refresh(); + + $shelf->load(['tags', 'cover']); + $shelf->makeVisible('description_html') + ->setAttribute('description_html', $shelf->descriptionHtml()); + + return $shelf; + } + protected function rules(): array { return [ 'create' => [ - 'name' => ['required', 'string', 'max:255'], - 'description' => ['string', 'max:1000'], - 'books' => ['array'], - 'tags' => ['array'], - 'image' => array_merge(['nullable'], $this->getImageValidationRules()), + 'name' => ['required', 'string', 'max:255'], + 'description' => ['string', 'max:1900'], + 'description_html' => ['string', 'max:2000'], + 'books' => ['array'], + 'tags' => ['array'], + 'image' => array_merge(['nullable'], $this->getImageValidationRules()), ], 'update' => [ - 'name' => ['string', 'min:1', 'max:255'], - 'description' => ['string', 'max:1000'], - 'books' => ['array'], - 'tags' => ['array'], - 'image' => array_merge(['nullable'], $this->getImageValidationRules()), + 'name' => ['string', 'min:1', 'max:255'], + 'description' => ['string', 'max:1900'], + 'description_html' => ['string', 'max:2000'], + 'books' => ['array'], + 'tags' => ['array'], + 'image' => array_merge(['nullable'], $this->getImageValidationRules()), ], ]; } diff --git a/app/Entities/Controllers/BookshelfController.php b/app/Entities/Controllers/BookshelfController.php index fcfd37538..2f5461cdb 100644 --- a/app/Entities/Controllers/BookshelfController.php +++ b/app/Entities/Controllers/BookshelfController.php @@ -18,15 +18,11 @@ use Illuminate\Validation\ValidationException; class BookshelfController extends Controller { - protected BookshelfRepo $shelfRepo; - protected ShelfContext $shelfContext; - protected ReferenceFetcher $referenceFetcher; - - public function __construct(BookshelfRepo $shelfRepo, ShelfContext $shelfContext, ReferenceFetcher $referenceFetcher) - { - $this->shelfRepo = $shelfRepo; - $this->shelfContext = $shelfContext; - $this->referenceFetcher = $referenceFetcher; + public function __construct( + protected BookshelfRepo $shelfRepo, + protected ShelfContext $shelfContext, + protected ReferenceFetcher $referenceFetcher + ) { } /** @@ -81,10 +77,10 @@ class BookshelfController extends Controller { $this->checkPermission('bookshelf-create-all'); $validated = $this->validate($request, [ - 'name' => ['required', 'string', 'max:255'], - 'description' => ['string', 'max:1000'], - 'image' => array_merge(['nullable'], $this->getImageValidationRules()), - 'tags' => ['array'], + 'name' => ['required', 'string', 'max:255'], + 'description_html' => ['string', 'max:2000'], + 'image' => array_merge(['nullable'], $this->getImageValidationRules()), + 'tags' => ['array'], ]); $bookIds = explode(',', $request->get('books', '')); @@ -129,7 +125,7 @@ class BookshelfController extends Controller 'view' => $view, 'activity' => $activities->entityActivity($shelf, 20, 1), 'listOptions' => $listOptions, - 'referenceCount' => $this->referenceFetcher->getPageReferenceCountToEntity($shelf), + 'referenceCount' => $this->referenceFetcher->getReferenceCountToEntity($shelf), ]); } @@ -164,10 +160,10 @@ class BookshelfController extends Controller $shelf = $this->shelfRepo->getBySlug($slug); $this->checkOwnablePermission('bookshelf-update', $shelf); $validated = $this->validate($request, [ - 'name' => ['required', 'string', 'max:255'], - 'description' => ['string', 'max:1000'], - 'image' => array_merge(['nullable'], $this->getImageValidationRules()), - 'tags' => ['array'], + 'name' => ['required', 'string', 'max:255'], + 'description_html' => ['string', 'max:2000'], + 'image' => array_merge(['nullable'], $this->getImageValidationRules()), + 'tags' => ['array'], ]); if ($request->has('image_reset')) { diff --git a/app/Entities/Controllers/ChapterApiController.php b/app/Entities/Controllers/ChapterApiController.php index 7f01e445a..c21323262 100644 --- a/app/Entities/Controllers/ChapterApiController.php +++ b/app/Entities/Controllers/ChapterApiController.php @@ -15,18 +15,20 @@ class ChapterApiController extends ApiController { protected $rules = [ 'create' => [ - 'book_id' => ['required', 'integer'], - 'name' => ['required', 'string', 'max:255'], - 'description' => ['string', 'max:1000'], - 'tags' => ['array'], - 'priority' => ['integer'], + 'book_id' => ['required', 'integer'], + 'name' => ['required', 'string', 'max:255'], + 'description' => ['string', 'max:1900'], + 'description_html' => ['string', 'max:2000'], + 'tags' => ['array'], + 'priority' => ['integer'], ], 'update' => [ - 'book_id' => ['integer'], - 'name' => ['string', 'min:1', 'max:255'], - 'description' => ['string', 'max:1000'], - 'tags' => ['array'], - 'priority' => ['integer'], + 'book_id' => ['integer'], + 'name' => ['string', 'min:1', 'max:255'], + 'description' => ['string', 'max:1900'], + 'description_html' => ['string', 'max:2000'], + 'tags' => ['array'], + 'priority' => ['integer'], ], ]; @@ -61,7 +63,7 @@ class ChapterApiController extends ApiController $chapter = $this->chapterRepo->create($requestData, $book); - return response()->json($chapter->load(['tags'])); + return response()->json($this->forJsonDisplay($chapter)); } /** @@ -69,9 +71,15 @@ class ChapterApiController extends ApiController */ public function read(string $id) { - $chapter = Chapter::visible()->with(['tags', 'createdBy', 'updatedBy', 'ownedBy', 'pages' => function (HasMany $query) { - $query->scopes('visible')->get(['id', 'name', 'slug']); - }])->findOrFail($id); + $chapter = Chapter::visible()->findOrFail($id); + $chapter = $this->forJsonDisplay($chapter); + + $chapter->load([ + 'createdBy', 'updatedBy', 'ownedBy', + 'pages' => function (HasMany $query) { + $query->scopes('visible')->get(['id', 'name', 'slug']); + } + ]); return response()->json($chapter); } @@ -93,7 +101,7 @@ class ChapterApiController extends ApiController try { $this->chapterRepo->move($chapter, "book:{$requestData['book_id']}"); } catch (Exception $exception) { - if ($exception instanceof PermissionsException) { + if ($exception instanceof PermissionsException) { $this->showPermissionError(); } @@ -103,7 +111,7 @@ class ChapterApiController extends ApiController $updatedChapter = $this->chapterRepo->update($chapter, $requestData); - return response()->json($updatedChapter->load(['tags'])); + return response()->json($this->forJsonDisplay($updatedChapter)); } /** @@ -119,4 +127,16 @@ class ChapterApiController extends ApiController return response('', 204); } + + protected function forJsonDisplay(Chapter $chapter): Chapter + { + $chapter = clone $chapter; + $chapter->unsetRelations()->refresh(); + + $chapter->load(['tags']); + $chapter->makeVisible('description_html') + ->setAttribute('description_html', $chapter->descriptionHtml()); + + return $chapter; + } } diff --git a/app/Entities/Controllers/ChapterController.php b/app/Entities/Controllers/ChapterController.php index ee1df0581..28ad35fa4 100644 --- a/app/Entities/Controllers/ChapterController.php +++ b/app/Entities/Controllers/ChapterController.php @@ -12,6 +12,7 @@ use BookStack\Entities\Tools\HierarchyTransformer; use BookStack\Entities\Tools\NextPreviousContentLocator; use BookStack\Exceptions\MoveOperationException; use BookStack\Exceptions\NotFoundException; +use BookStack\Exceptions\NotifyException; use BookStack\Exceptions\PermissionsException; use BookStack\Http\Controller; use BookStack\References\ReferenceFetcher; @@ -21,13 +22,10 @@ use Throwable; class ChapterController extends Controller { - protected ChapterRepo $chapterRepo; - protected ReferenceFetcher $referenceFetcher; - - public function __construct(ChapterRepo $chapterRepo, ReferenceFetcher $referenceFetcher) - { - $this->chapterRepo = $chapterRepo; - $this->referenceFetcher = $referenceFetcher; + public function __construct( + protected ChapterRepo $chapterRepo, + protected ReferenceFetcher $referenceFetcher + ) { } /** @@ -50,14 +48,16 @@ class ChapterController extends Controller */ public function store(Request $request, string $bookSlug) { - $this->validate($request, [ - 'name' => ['required', 'string', 'max:255'], + $validated = $this->validate($request, [ + 'name' => ['required', 'string', 'max:255'], + 'description_html' => ['string', 'max:2000'], + 'tags' => ['array'], ]); $book = Book::visible()->where('slug', '=', $bookSlug)->firstOrFail(); $this->checkOwnablePermission('chapter-create', $book); - $chapter = $this->chapterRepo->create($request->all(), $book); + $chapter = $this->chapterRepo->create($validated, $book); return redirect($chapter->getUrl()); } @@ -86,7 +86,7 @@ class ChapterController extends Controller 'pages' => $pages, 'next' => $nextPreviousLocator->getNext(), 'previous' => $nextPreviousLocator->getPrevious(), - 'referenceCount' => $this->referenceFetcher->getPageReferenceCountToEntity($chapter), + 'referenceCount' => $this->referenceFetcher->getReferenceCountToEntity($chapter), ]); } @@ -110,10 +110,16 @@ class ChapterController extends Controller */ public function update(Request $request, string $bookSlug, string $chapterSlug) { + $validated = $this->validate($request, [ + 'name' => ['required', 'string', 'max:255'], + 'description_html' => ['string', 'max:2000'], + 'tags' => ['array'], + ]); + $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $this->checkOwnablePermission('chapter-update', $chapter); - $this->chapterRepo->update($chapter, $request->all()); + $this->chapterRepo->update($chapter, $validated); return redirect($chapter->getUrl()); } @@ -170,7 +176,7 @@ class ChapterController extends Controller /** * Perform the move action for a chapter. * - * @throws NotFoundException + * @throws NotFoundException|NotifyException */ public function move(Request $request, string $bookSlug, string $chapterSlug) { @@ -184,13 +190,13 @@ class ChapterController extends Controller } try { - $newBook = $this->chapterRepo->move($chapter, $entitySelection); + $this->chapterRepo->move($chapter, $entitySelection); } catch (PermissionsException $exception) { $this->showPermissionError(); } catch (MoveOperationException $exception) { $this->showErrorNotification(trans('errors.selected_book_not_found')); - return redirect()->back(); + return redirect($chapter->getUrl('/move')); } return redirect($chapter->getUrl()); @@ -231,7 +237,7 @@ class ChapterController extends Controller if (is_null($newParentBook)) { $this->showErrorNotification(trans('errors.selected_book_not_found')); - return redirect()->back(); + return redirect($chapter->getUrl('/copy')); } $this->checkOwnablePermission('chapter-create', $newParentBook); diff --git a/app/Entities/Controllers/PageController.php b/app/Entities/Controllers/PageController.php index 624931065..adafcdc7b 100644 --- a/app/Entities/Controllers/PageController.php +++ b/app/Entities/Controllers/PageController.php @@ -5,6 +5,7 @@ namespace BookStack\Entities\Controllers; use BookStack\Activity\Models\View; use BookStack\Activity\Tools\CommentTree; use BookStack\Activity\Tools\UserEntityWatchOptions; +use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Page; use BookStack\Entities\Repos\PageRepo; use BookStack\Entities\Tools\BookContents; @@ -71,7 +72,6 @@ class PageController extends Controller $page = $this->pageRepo->getNewDraftPage($parent); $this->pageRepo->publishDraft($page, [ 'name' => $request->get('name'), - 'html' => '', ]); return redirect($page->getUrl('/edit')); @@ -155,7 +155,7 @@ class PageController extends Controller 'watchOptions' => new UserEntityWatchOptions(user(), $page), 'next' => $nextPreviousLocator->getNext(), 'previous' => $nextPreviousLocator->getPrevious(), - 'referenceCount' => $this->referenceFetcher->getPageReferenceCountToEntity($page), + 'referenceCount' => $this->referenceFetcher->getReferenceCountToEntity($page), ]); } @@ -259,11 +259,13 @@ class PageController extends Controller $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); $this->checkOwnablePermission('page-delete', $page); $this->setPageTitle(trans('entities.pages_delete_named', ['pageName' => $page->getShortName()])); + $usedAsTemplate = Book::query()->where('default_template_id', '=', $page->id)->count() > 0; return view('pages.delete', [ 'book' => $page->book, 'page' => $page, 'current' => $page, + 'usedAsTemplate' => $usedAsTemplate, ]); } @@ -277,11 +279,13 @@ class PageController extends Controller $page = $this->pageRepo->getById($pageId); $this->checkOwnablePermission('page-update', $page); $this->setPageTitle(trans('entities.pages_delete_draft_named', ['pageName' => $page->getShortName()])); + $usedAsTemplate = Book::query()->where('default_template_id', '=', $page->id)->count() > 0; return view('pages.delete', [ 'book' => $page->book, 'page' => $page, 'current' => $page, + 'usedAsTemplate' => $usedAsTemplate, ]); } @@ -391,7 +395,7 @@ class PageController extends Controller } catch (Exception $exception) { $this->showErrorNotification(trans('errors.selected_book_chapter_not_found')); - return redirect()->back(); + return redirect($page->getUrl('/move')); } return redirect($page->getUrl()); @@ -431,7 +435,7 @@ class PageController extends Controller if (is_null($newParent)) { $this->showErrorNotification(trans('errors.selected_book_chapter_not_found')); - return redirect()->back(); + return redirect($page->getUrl('/copy')); } $this->checkOwnablePermission('page-create', $newParent); diff --git a/app/Entities/Models/Book.php b/app/Entities/Models/Book.php index f54a0bf2d..14cb790c5 100644 --- a/app/Entities/Models/Book.php +++ b/app/Entities/Models/Book.php @@ -15,20 +15,23 @@ use Illuminate\Support\Collection; * * @property string $description * @property int $image_id + * @property ?int $default_template_id * @property Image|null $cover * @property \Illuminate\Database\Eloquent\Collection $chapters * @property \Illuminate\Database\Eloquent\Collection $pages * @property \Illuminate\Database\Eloquent\Collection $directPages * @property \Illuminate\Database\Eloquent\Collection $shelves + * @property ?Page $defaultTemplate */ class Book extends Entity implements HasCoverImage { use HasFactory; + use HasHtmlDescription; - public $searchFactor = 1.2; + public float $searchFactor = 1.2; - protected $fillable = ['name', 'description']; - protected $hidden = ['pivot', 'image_id', 'deleted_at']; + protected $fillable = ['name']; + protected $hidden = ['pivot', 'image_id', 'deleted_at', 'description_html']; /** * Get the url for this book. @@ -71,6 +74,14 @@ class Book extends Entity implements HasCoverImage return 'cover_book'; } + /** + * Get the Page that is used as default template for newly created pages within this Book. + */ + public function defaultTemplate(): BelongsTo + { + return $this->belongsTo(Page::class, 'default_template_id'); + } + /** * Get all pages within this book. */ diff --git a/app/Entities/Models/BookChild.php b/app/Entities/Models/BookChild.php index ed08f16e6..18735e56b 100644 --- a/app/Entities/Models/BookChild.php +++ b/app/Entities/Models/BookChild.php @@ -65,7 +65,7 @@ abstract class BookChild extends Entity $this->refresh(); if ($oldUrl !== $this->getUrl()) { - app()->make(ReferenceUpdater::class)->updateEntityPageReferences($this, $oldUrl); + app()->make(ReferenceUpdater::class)->updateEntityReferences($this, $oldUrl); } // Update all child pages if a chapter diff --git a/app/Entities/Models/Bookshelf.php b/app/Entities/Models/Bookshelf.php index 4b44025a4..9ffa0ea9c 100644 --- a/app/Entities/Models/Bookshelf.php +++ b/app/Entities/Models/Bookshelf.php @@ -11,14 +11,15 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany; class Bookshelf extends Entity implements HasCoverImage { use HasFactory; + use HasHtmlDescription; protected $table = 'bookshelves'; - public $searchFactor = 1.2; + public float $searchFactor = 1.2; protected $fillable = ['name', 'description', 'image_id']; - protected $hidden = ['image_id', 'deleted_at']; + protected $hidden = ['image_id', 'deleted_at', 'description_html']; /** * Get the books in this shelf. diff --git a/app/Entities/Models/Chapter.php b/app/Entities/Models/Chapter.php index 98889ce3f..f30d77b5c 100644 --- a/app/Entities/Models/Chapter.php +++ b/app/Entities/Models/Chapter.php @@ -15,11 +15,12 @@ use Illuminate\Support\Collection; class Chapter extends BookChild { use HasFactory; + use HasHtmlDescription; - public $searchFactor = 1.2; + public float $searchFactor = 1.2; protected $fillable = ['name', 'description', 'priority']; - protected $hidden = ['pivot', 'deleted_at']; + protected $hidden = ['pivot', 'deleted_at', 'description_html']; /** * Get the pages that this chapter contains. diff --git a/app/Entities/Models/Entity.php b/app/Entities/Models/Entity.php index 332510672..f07d372c3 100644 --- a/app/Entities/Models/Entity.php +++ b/app/Entities/Models/Entity.php @@ -57,12 +57,17 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable /** * @var string - Name of property where the main text content is found */ - public $textField = 'description'; + public string $textField = 'description'; + + /** + * @var string - Name of the property where the main HTML content is found + */ + public string $htmlField = 'description_html'; /** * @var float - Multiplier for search indexing. */ - public $searchFactor = 1.0; + public float $searchFactor = 1.0; /** * Get the entities that are visible to the current user. diff --git a/app/Entities/Models/HasHtmlDescription.php b/app/Entities/Models/HasHtmlDescription.php new file mode 100644 index 000000000..c9f08616d --- /dev/null +++ b/app/Entities/Models/HasHtmlDescription.php @@ -0,0 +1,21 @@ +description_html ?: '

' . nl2br(e($this->description)) . '

'; + return HtmlContentFilter::removeScriptsFromHtmlString($html); + } +} diff --git a/app/Entities/Models/Page.php b/app/Entities/Models/Page.php index 7e2c12c20..17d6f9a01 100644 --- a/app/Entities/Models/Page.php +++ b/app/Entities/Models/Page.php @@ -37,7 +37,8 @@ class Page extends BookChild protected $fillable = ['name', 'priority']; - public $textField = 'text'; + public string $textField = 'text'; + public string $htmlField = 'html'; protected $hidden = ['html', 'markdown', 'text', 'pivot', 'deleted_at']; diff --git a/app/Entities/Repos/BaseRepo.php b/app/Entities/Repos/BaseRepo.php index 2894a04e3..27bf00161 100644 --- a/app/Entities/Repos/BaseRepo.php +++ b/app/Entities/Repos/BaseRepo.php @@ -5,22 +5,22 @@ namespace BookStack\Entities\Repos; use BookStack\Activity\TagRepo; use BookStack\Entities\Models\Entity; use BookStack\Entities\Models\HasCoverImage; +use BookStack\Entities\Models\HasHtmlDescription; use BookStack\Exceptions\ImageUploadException; +use BookStack\References\ReferenceStore; use BookStack\References\ReferenceUpdater; use BookStack\Uploads\ImageRepo; +use BookStack\Util\HtmlDescriptionFilter; use Illuminate\Http\UploadedFile; class BaseRepo { - protected TagRepo $tagRepo; - protected ImageRepo $imageRepo; - protected ReferenceUpdater $referenceUpdater; - - public function __construct(TagRepo $tagRepo, ImageRepo $imageRepo, ReferenceUpdater $referenceUpdater) - { - $this->tagRepo = $tagRepo; - $this->imageRepo = $imageRepo; - $this->referenceUpdater = $referenceUpdater; + public function __construct( + protected TagRepo $tagRepo, + protected ImageRepo $imageRepo, + protected ReferenceUpdater $referenceUpdater, + protected ReferenceStore $referenceStore, + ) { } /** @@ -29,6 +29,7 @@ class BaseRepo public function create(Entity $entity, array $input) { $entity->fill($input); + $this->updateDescription($entity, $input); $entity->forceFill([ 'created_by' => user()->id, 'updated_by' => user()->id, @@ -44,6 +45,7 @@ class BaseRepo $entity->refresh(); $entity->rebuildPermissions(); $entity->indexForSearch(); + $this->referenceStore->updateForEntity($entity); } /** @@ -54,6 +56,7 @@ class BaseRepo $oldUrl = $entity->getUrl(); $entity->fill($input); + $this->updateDescription($entity, $input); $entity->updated_by = user()->id; if ($entity->isDirty('name') || empty($entity->slug)) { @@ -69,9 +72,10 @@ class BaseRepo $entity->rebuildPermissions(); $entity->indexForSearch(); + $this->referenceStore->updateForEntity($entity); if ($oldUrl !== $entity->getUrl()) { - $this->referenceUpdater->updateEntityPageReferences($entity, $oldUrl); + $this->referenceUpdater->updateEntityReferences($entity, $oldUrl); } } @@ -99,4 +103,21 @@ class BaseRepo $entity->save(); } } + + protected function updateDescription(Entity $entity, array $input): void + { + if (!in_array(HasHtmlDescription::class, class_uses($entity))) { + return; + } + + /** @var HasHtmlDescription $entity */ + if (isset($input['description_html'])) { + $entity->description_html = HtmlDescriptionFilter::filterFromString($input['description_html']); + $entity->description = html_entity_decode(strip_tags($input['description_html'])); + } else if (isset($input['description'])) { + $entity->description = $input['description']; + $entity->description_html = ''; + $entity->description_html = $entity->descriptionHtml(); + } + } } diff --git a/app/Entities/Repos/BookRepo.php b/app/Entities/Repos/BookRepo.php index 737caa70b..03e1118b1 100644 --- a/app/Entities/Repos/BookRepo.php +++ b/app/Entities/Repos/BookRepo.php @@ -5,6 +5,7 @@ namespace BookStack\Entities\Repos; use BookStack\Activity\ActivityType; use BookStack\Activity\TagRepo; use BookStack\Entities\Models\Book; +use BookStack\Entities\Models\Page; use BookStack\Entities\Tools\TrashCan; use BookStack\Exceptions\ImageUploadException; use BookStack\Exceptions\NotFoundException; @@ -17,18 +18,11 @@ use Illuminate\Support\Collection; class BookRepo { - protected $baseRepo; - protected $tagRepo; - protected $imageRepo; - - /** - * BookRepo constructor. - */ - public function __construct(BaseRepo $baseRepo, TagRepo $tagRepo, ImageRepo $imageRepo) - { - $this->baseRepo = $baseRepo; - $this->tagRepo = $tagRepo; - $this->imageRepo = $imageRepo; + public function __construct( + protected BaseRepo $baseRepo, + protected TagRepo $tagRepo, + protected ImageRepo $imageRepo + ) { } /** @@ -92,6 +86,7 @@ class BookRepo $book = new Book(); $this->baseRepo->create($book, $input); $this->baseRepo->updateCoverImage($book, $input['image'] ?? null); + $this->updateBookDefaultTemplate($book, intval($input['default_template_id'] ?? null)); Activity::add(ActivityType::BOOK_CREATE, $book); return $book; @@ -104,6 +99,10 @@ class BookRepo { $this->baseRepo->update($book, $input); + if (array_key_exists('default_template_id', $input)) { + $this->updateBookDefaultTemplate($book, intval($input['default_template_id'])); + } + if (array_key_exists('image', $input)) { $this->baseRepo->updateCoverImage($book, $input['image'], $input['image'] === null); } @@ -113,6 +112,33 @@ class BookRepo return $book; } + /** + * Update the default page template used for this book. + * Checks that, if changing, the provided value is a valid template and the user + * has visibility of the provided page template id. + */ + protected function updateBookDefaultTemplate(Book $book, int $templateId): void + { + $changing = $templateId !== intval($book->default_template_id); + if (!$changing) { + return; + } + + if ($templateId === 0) { + $book->default_template_id = null; + $book->save(); + return; + } + + $templateExists = Page::query()->visible() + ->where('template', '=', true) + ->where('id', '=', $templateId) + ->exists(); + + $book->default_template_id = $templateExists ? $templateId : null; + $book->save(); + } + /** * Update the given book's cover image, or clear it. * diff --git a/app/Entities/Repos/PageRepo.php b/app/Entities/Repos/PageRepo.php index dbd4a47d2..7b14ea7d2 100644 --- a/app/Entities/Repos/PageRepo.php +++ b/app/Entities/Repos/PageRepo.php @@ -136,6 +136,14 @@ class PageRepo $page->book_id = $parent->id; } + $defaultTemplate = $page->book->defaultTemplate; + if ($defaultTemplate && userCan('view', $defaultTemplate)) { + $page->forceFill([ + 'html' => $defaultTemplate->html, + 'markdown' => $defaultTemplate->markdown, + ]); + } + $page->save(); $page->refresh()->rebuildPermissions(); @@ -154,7 +162,6 @@ class PageRepo $this->baseRepo->update($draft, $input); $this->revisionRepo->storeNewForPage($draft, trans('entities.pages_initial_revision')); - $this->referenceStore->updateForPage($draft); $draft->refresh(); Activity::add(ActivityType::PAGE_CREATE, $draft); @@ -174,7 +181,6 @@ class PageRepo $this->updateTemplateStatusAndContentFromInput($page, $input); $this->baseRepo->update($page, $input); - $this->referenceStore->updateForPage($page); // Update with new details $page->revision_count++; @@ -293,13 +299,13 @@ class PageRepo $page->refreshSlug(); $page->save(); $page->indexForSearch(); - $this->referenceStore->updateForPage($page); + $this->referenceStore->updateForEntity($page); $summary = trans('entities.pages_revision_restored_from', ['id' => strval($revisionId), 'summary' => $revision->summary]); $this->revisionRepo->storeNewForPage($page, $summary); if ($oldUrl !== $page->getUrl()) { - $this->referenceUpdater->updateEntityPageReferences($page, $oldUrl); + $this->referenceUpdater->updateEntityReferences($page, $oldUrl); } Activity::add(ActivityType::PAGE_RESTORE, $page); diff --git a/app/Entities/Tools/ExportFormatter.php b/app/Entities/Tools/ExportFormatter.php index 9a8c687b0..beddfe8e6 100644 --- a/app/Entities/Tools/ExportFormatter.php +++ b/app/Entities/Tools/ExportFormatter.php @@ -8,9 +8,8 @@ use BookStack\Entities\Models\Page; use BookStack\Entities\Tools\Markdown\HtmlToMarkdown; use BookStack\Uploads\ImageService; use BookStack\Util\CspService; -use DOMDocument; +use BookStack\Util\HtmlDocument; use DOMElement; -use DOMXPath; use Exception; use Throwable; @@ -151,45 +150,36 @@ class ExportFormatter protected function htmlToPdf(string $html): string { $html = $this->containHtml($html); - $html = $this->replaceIframesWithLinks($html); - $html = $this->openDetailElements($html); + $doc = new HtmlDocument(); + $doc->loadCompleteHtml($html); - return $this->pdfGenerator->fromHtml($html); + $this->replaceIframesWithLinks($doc); + $this->openDetailElements($doc); + $cleanedHtml = $doc->getHtml(); + + return $this->pdfGenerator->fromHtml($cleanedHtml); } /** * Within the given HTML content, Open any detail blocks. */ - protected function openDetailElements(string $html): string + protected function openDetailElements(HtmlDocument $doc): void { - libxml_use_internal_errors(true); - - $doc = new DOMDocument(); - $doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8')); - $xPath = new DOMXPath($doc); - - $details = $xPath->query('//details'); + $details = $doc->queryXPath('//details'); /** @var DOMElement $detail */ foreach ($details as $detail) { $detail->setAttribute('open', 'open'); } - - return $doc->saveHTML(); } /** - * Within the given HTML content, replace any iframe elements + * Within the given HTML document, replace any iframe elements * with anchor links within paragraph blocks. */ - protected function replaceIframesWithLinks(string $html): string + protected function replaceIframesWithLinks(HtmlDocument $doc): void { - libxml_use_internal_errors(true); + $iframes = $doc->queryXPath('//iframe'); - $doc = new DOMDocument(); - $doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8')); - $xPath = new DOMXPath($doc); - - $iframes = $xPath->query('//iframe'); /** @var DOMElement $iframe */ foreach ($iframes as $iframe) { $link = $iframe->getAttribute('src'); @@ -203,8 +193,6 @@ class ExportFormatter $paragraph->appendChild($anchor); $iframe->parentNode->replaceChild($paragraph, $iframe); } - - return $doc->saveHTML(); } /** diff --git a/app/Entities/Tools/MixedEntityListLoader.php b/app/Entities/Tools/MixedEntityListLoader.php new file mode 100644 index 000000000..50079e3bf --- /dev/null +++ b/app/Entities/Tools/MixedEntityListLoader.php @@ -0,0 +1,103 @@ + ['id', 'name', 'slug', 'book_id', 'chapter_id', 'text', 'draft'], + 'chapter' => ['id', 'name', 'slug', 'book_id', 'description'], + 'book' => ['id', 'name', 'slug', 'description'], + 'bookshelf' => ['id', 'name', 'slug', 'description'], + ]; + + public function __construct( + protected EntityProvider $entityProvider + ) { + } + + /** + * Efficiently load in entities for listing onto the given list + * where entities are set as a relation via the given name. + * This will look for a model id and type via 'name_id' and 'name_type'. + * @param Model[] $relations + */ + public function loadIntoRelations(array $relations, string $relationName): void + { + $idsByType = []; + foreach ($relations as $relation) { + $type = $relation->getAttribute($relationName . '_type'); + $id = $relation->getAttribute($relationName . '_id'); + + if (!isset($idsByType[$type])) { + $idsByType[$type] = []; + } + + $idsByType[$type][] = $id; + } + + $modelMap = $this->idsByTypeToModelMap($idsByType); + + foreach ($relations as $relation) { + $type = $relation->getAttribute($relationName . '_type'); + $id = $relation->getAttribute($relationName . '_id'); + $related = $modelMap[$type][strval($id)] ?? null; + if ($related) { + $relation->setRelation($relationName, $related); + } + } + } + + /** + * @param array $idsByType + * @return array> + */ + protected function idsByTypeToModelMap(array $idsByType): array + { + $modelMap = []; + + foreach ($idsByType as $type => $ids) { + if (!isset($this->listAttributes[$type])) { + continue; + } + + $instance = $this->entityProvider->get($type); + $models = $instance->newQuery() + ->select($this->listAttributes[$type]) + ->scopes('visible') + ->whereIn('id', $ids) + ->with($this->getRelationsToEagerLoad($type)) + ->get(); + + if (count($models) > 0) { + $modelMap[$type] = []; + } + + foreach ($models as $model) { + $modelMap[$type][strval($model->id)] = $model; + } + } + + return $modelMap; + } + + protected function getRelationsToEagerLoad(string $type): array + { + $toLoad = []; + $loadVisible = fn (Relation $query) => $query->scopes('visible'); + + if ($type === 'chapter' || $type === 'page') { + $toLoad['book'] = $loadVisible; + } + + if ($type === 'page') { + $toLoad['chapter'] = $loadVisible; + } + + return $toLoad; + } +} diff --git a/app/Entities/Tools/PageContent.php b/app/Entities/Tools/PageContent.php index 1bde7b6ce..6a89ff626 100644 --- a/app/Entities/Tools/PageContent.php +++ b/app/Entities/Tools/PageContent.php @@ -11,12 +11,12 @@ use BookStack\Uploads\ImageRepo; use BookStack\Uploads\ImageService; use BookStack\Users\Models\User; use BookStack\Util\HtmlContentFilter; +use BookStack\Util\HtmlDocument; use BookStack\Util\WebSafeMimeSniffer; -use DOMDocument; +use Closure; use DOMElement; use DOMNode; use DOMNodeList; -use DOMXPath; use Illuminate\Support\Str; class PageContent @@ -58,27 +58,18 @@ class PageContent return $htmlText; } - $doc = $this->loadDocumentFromHtml($htmlText); - $container = $doc->documentElement; - $body = $container->childNodes->item(0); - $childNodes = $body->childNodes; - $xPath = new DOMXPath($doc); + $doc = new HtmlDocument($htmlText); // Get all img elements with image data blobs - $imageNodes = $xPath->query('//img[contains(@src, \'data:image\')]'); + $imageNodes = $doc->queryXPath('//img[contains(@src, \'data:image\')]'); + /** @var DOMElement $imageNode */ foreach ($imageNodes as $imageNode) { $imageSrc = $imageNode->getAttribute('src'); $newUrl = $this->base64ImageUriToUploadedImageUrl($imageSrc, $updater); $imageNode->setAttribute('src', $newUrl); } - // Generate inner html as a string - $html = ''; - foreach ($childNodes as $childNode) { - $html .= $doc->saveHTML($childNode); - } - - return $html; + return $doc->getBodyInnerHtml(); } /** @@ -186,27 +177,18 @@ class PageContent return $htmlText; } - $doc = $this->loadDocumentFromHtml($htmlText); - $container = $doc->documentElement; - $body = $container->childNodes->item(0); - $childNodes = $body->childNodes; - $xPath = new DOMXPath($doc); + $doc = new HtmlDocument($htmlText); // Map to hold used ID references $idMap = []; // Map to hold changing ID references $changeMap = []; - $this->updateIdsRecursively($body, 0, $idMap, $changeMap); - $this->updateLinks($xPath, $changeMap); + $this->updateIdsRecursively($doc->getBody(), 0, $idMap, $changeMap); + $this->updateLinks($doc, $changeMap); - // Generate inner html as a string - $html = ''; - foreach ($childNodes as $childNode) { - $html .= $doc->saveHTML($childNode); - } - - // Perform required string-level tweaks + // Generate inner html as a string & perform required string-level tweaks + $html = $doc->getBodyInnerHtml(); $html = str_replace(' ', ' ', $html); return $html; @@ -239,13 +221,13 @@ class PageContent * Update the all links in the given xpath to apply requires changes within the * given $changeMap array. */ - protected function updateLinks(DOMXPath $xpath, array $changeMap): void + protected function updateLinks(HtmlDocument $doc, array $changeMap): void { if (empty($changeMap)) { return; } - $links = $xpath->query('//body//*//*[@href]'); + $links = $doc->queryXPath('//body//*//*[@href]'); /** @var DOMElement $domElem */ foreach ($links as $domElem) { $href = ltrim($domElem->getAttribute('href'), '#'); @@ -309,21 +291,65 @@ class PageContent */ public function render(bool $blankIncludes = false): string { - $content = $this->page->html ?? ''; + $html = $this->page->html ?? ''; + + if (empty($html)) { + return $html; + } + + $doc = new HtmlDocument($html); + $contentProvider = $this->getContentProviderClosure($blankIncludes); + $parser = new PageIncludeParser($doc, $contentProvider); + + $nodesAdded = 1; + for ($includeDepth = 0; $includeDepth < 3 && $nodesAdded !== 0; $includeDepth++) { + $nodesAdded = $parser->parse(); + } + + if ($includeDepth > 1) { + $idMap = []; + $changeMap = []; + $this->updateIdsRecursively($doc->getBody(), 0, $idMap, $changeMap); + } if (!config('app.allow_content_scripts')) { - $content = HtmlContentFilter::removeScripts($content); + HtmlContentFilter::removeScriptsFromDocument($doc); } - if ($blankIncludes) { - $content = $this->blankPageIncludes($content); - } else { - for ($includeDepth = 0; $includeDepth < 3; $includeDepth++) { - $content = $this->parsePageIncludes($content); + return $doc->getBodyInnerHtml(); + } + + /** + * Get the closure used to fetch content for page includes. + */ + protected function getContentProviderClosure(bool $blankIncludes): Closure + { + $contextPage = $this->page; + + return function (PageIncludeTag $tag) use ($blankIncludes, $contextPage): PageIncludeContent { + if ($blankIncludes) { + return PageIncludeContent::fromHtmlAndTag('', $tag); } - } - return $content; + $matchedPage = Page::visible()->find($tag->getPageId()); + $content = PageIncludeContent::fromHtmlAndTag($matchedPage->html ?? '', $tag); + + if (Theme::hasListeners(ThemeEvents::PAGE_INCLUDE_PARSE)) { + $themeReplacement = Theme::dispatch( + ThemeEvents::PAGE_INCLUDE_PARSE, + $tag->tagContent, + $content->toHtml(), + clone $contextPage, + $matchedPage ? (clone $matchedPage) : null, + ); + + if ($themeReplacement !== null) { + $content = PageIncludeContent::fromInlineHtml(strval($themeReplacement)); + } + } + + return $content; + }; } /** @@ -335,11 +361,10 @@ class PageContent return []; } - $doc = $this->loadDocumentFromHtml($htmlContent); - $xPath = new DOMXPath($doc); - $headers = $xPath->query('//h1|//h2|//h3|//h4|//h5|//h6'); + $doc = new HtmlDocument($htmlContent); + $headers = $doc->queryXPath('//h1|//h2|//h3|//h4|//h5|//h6'); - return $headers ? $this->headerNodesToLevelList($headers) : []; + return $headers->count() === 0 ? [] : $this->headerNodesToLevelList($headers); } /** @@ -372,102 +397,4 @@ class PageContent return $tree->toArray(); } - - /** - * Remove any page include tags within the given HTML. - */ - protected function blankPageIncludes(string $html): string - { - return preg_replace("/{{@\s?([0-9].*?)}}/", '', $html); - } - - /** - * Parse any include tags "{{@#section}}" to be part of the page. - */ - protected function parsePageIncludes(string $html): string - { - $matches = []; - preg_match_all("/{{@\s?([0-9].*?)}}/", $html, $matches); - - foreach ($matches[1] as $index => $includeId) { - $fullMatch = $matches[0][$index]; - $splitInclude = explode('#', $includeId, 2); - - // Get page id from reference - $pageId = intval($splitInclude[0]); - if (is_nan($pageId)) { - continue; - } - - // Find page to use, and default replacement to empty string for non-matches. - /** @var ?Page $matchedPage */ - $matchedPage = Page::visible()->find($pageId); - $replacement = ''; - - if ($matchedPage && count($splitInclude) === 1) { - // If we only have page id, just insert all page html and continue. - $replacement = $matchedPage->html; - } elseif ($matchedPage && count($splitInclude) > 1) { - // Otherwise, if our include tag defines a section, load that specific content - $innerContent = $this->fetchSectionOfPage($matchedPage, $splitInclude[1]); - $replacement = trim($innerContent); - } - - $themeReplacement = Theme::dispatch( - ThemeEvents::PAGE_INCLUDE_PARSE, - $includeId, - $replacement, - clone $this->page, - $matchedPage ? (clone $matchedPage) : null, - ); - - // Perform the content replacement - $html = str_replace($fullMatch, $themeReplacement ?? $replacement, $html); - } - - return $html; - } - - /** - * Fetch the content from a specific section of the given page. - */ - protected function fetchSectionOfPage(Page $page, string $sectionId): string - { - $topLevelTags = ['table', 'ul', 'ol', 'pre']; - $doc = $this->loadDocumentFromHtml($page->html); - - // Search included content for the id given and blank out if not exists. - $matchingElem = $doc->getElementById($sectionId); - if ($matchingElem === null) { - return ''; - } - - // Otherwise replace the content with the found content - // Checks if the top-level wrapper should be included by matching on tag types - $innerContent = ''; - $isTopLevel = in_array(strtolower($matchingElem->nodeName), $topLevelTags); - if ($isTopLevel) { - $innerContent .= $doc->saveHTML($matchingElem); - } else { - foreach ($matchingElem->childNodes as $childNode) { - $innerContent .= $doc->saveHTML($childNode); - } - } - libxml_clear_errors(); - - return $innerContent; - } - - /** - * Create and load a DOMDocument from the given html content. - */ - protected function loadDocumentFromHtml(string $html): DOMDocument - { - libxml_use_internal_errors(true); - $doc = new DOMDocument(); - $html = '' . $html . ''; - $doc->loadHTML($html); - - return $doc; - } } diff --git a/app/Entities/Tools/PageIncludeContent.php b/app/Entities/Tools/PageIncludeContent.php new file mode 100644 index 000000000..7c4f943c8 --- /dev/null +++ b/app/Entities/Tools/PageIncludeContent.php @@ -0,0 +1,85 @@ +getSectionId(); + if (!$sectionId) { + $contents = [...$doc->getBodyChildren()]; + return new self($contents, false); + } + + $section = $doc->getElementById($sectionId); + if (!$section) { + return new self([], true); + } + + $isTopLevel = in_array(strtolower($section->nodeName), static::$topLevelTags); + $contents = $isTopLevel ? [$section] : [...$section->childNodes]; + return new self($contents, !$isTopLevel); + } + + public static function fromInlineHtml(string $html): self + { + if (empty($html)) { + return new self([], true); + } + + $doc = new HtmlDocument($html); + + return new self([...$doc->getBodyChildren()], true); + } + + public function isInline(): bool + { + return $this->isInline; + } + + public function isEmpty(): bool + { + return empty($this->contents); + } + + /** + * @return DOMNode[] + */ + public function toDomNodes(): array + { + return $this->contents; + } + + public function toHtml(): string + { + $html = ''; + + foreach ($this->contents as $content) { + $html .= $content->ownerDocument->saveHTML($content); + } + + return $html; + } +} diff --git a/app/Entities/Tools/PageIncludeParser.php b/app/Entities/Tools/PageIncludeParser.php new file mode 100644 index 000000000..dad7c29e6 --- /dev/null +++ b/app/Entities/Tools/PageIncludeParser.php @@ -0,0 +1,220 @@ +locateAndIsolateIncludeTags(); + + foreach ($tags as $tag) { + /** @var PageIncludeContent $content */ + $content = $this->pageContentForId->call($this, $tag); + + if (!$content->isInline()) { + $parentP = $this->getParentParagraph($tag->domNode); + $isWithinParentP = $parentP === $tag->domNode->parentNode; + if ($parentP && $isWithinParentP) { + $this->splitNodeAtChildNode($tag->domNode->parentNode, $tag->domNode); + } else if ($parentP) { + $this->moveTagNodeToBesideParent($tag, $parentP); + } + } + + $replacementNodes = $content->toDomNodes(); + $nodesAdded += count($replacementNodes); + $this->replaceNodeWithNodes($tag->domNode, $replacementNodes); + } + + $this->cleanup(); + + return $nodesAdded; + } + + /** + * Locate include tags within the given document, isolating them to their + * own nodes in the DOM for future targeted manipulation. + * @return PageIncludeTag[] + */ + protected function locateAndIsolateIncludeTags(): array + { + $includeHosts = $this->doc->queryXPath("//*[text()[contains(., '{{@')]]"); + $includeTags = []; + + /** @var DOMNode $node */ + foreach ($includeHosts as $node) { + /** @var DOMNode $childNode */ + foreach ($node->childNodes as $childNode) { + if ($childNode->nodeName === '#text') { + array_push($includeTags, ...$this->splitTextNodesAtTags($childNode)); + } + } + } + + return $includeTags; + } + + /** + * Takes a text DOMNode and splits its text content at include tags + * into multiple text nodes within the original parent. + * Returns found PageIncludeTag references. + * @return PageIncludeTag[] + */ + protected function splitTextNodesAtTags(DOMNode $textNode): array + { + $includeTags = []; + $text = $textNode->textContent; + preg_match_all(static::$includeTagRegex, $text, $matches, PREG_OFFSET_CAPTURE); + + $currentOffset = 0; + foreach ($matches[0] as $index => $fullTagMatch) { + $tagOuterContent = $fullTagMatch[0]; + $tagInnerContent = $matches[1][$index][0]; + $tagStartOffset = $fullTagMatch[1]; + + if ($currentOffset < $tagStartOffset) { + $previousText = substr($text, $currentOffset, $tagStartOffset - $currentOffset); + $textNode->parentNode->insertBefore(new DOMText($previousText), $textNode); + } + + $node = $textNode->parentNode->insertBefore(new DOMText($tagOuterContent), $textNode); + $includeTags[] = new PageIncludeTag($tagInnerContent, $node); + $currentOffset = $tagStartOffset + strlen($tagOuterContent); + } + + if ($currentOffset > 0) { + $textNode->textContent = substr($text, $currentOffset); + } + + return $includeTags; + } + + /** + * Replace the given node with all those in $replacements + * @param DOMNode[] $replacements + */ + protected function replaceNodeWithNodes(DOMNode $toReplace, array $replacements): void + { + /** @var DOMDocument $targetDoc */ + $targetDoc = $toReplace->ownerDocument; + + foreach ($replacements as $replacement) { + if ($replacement->ownerDocument !== $targetDoc) { + $replacement = $targetDoc->importNode($replacement, true); + } + + $toReplace->parentNode->insertBefore($replacement, $toReplace); + } + + $toReplace->parentNode->removeChild($toReplace); + } + + /** + * Move a tag node to become a sibling of the given parent. + * Will attempt to guess a position based upon the tag content within the parent. + */ + protected function moveTagNodeToBesideParent(PageIncludeTag $tag, DOMNode $parent): void + { + $parentText = $parent->textContent; + $tagPos = strpos($parentText, $tag->tagContent); + $before = $tagPos < (strlen($parentText) / 2); + $this->toCleanup[] = $tag->domNode->parentNode; + + if ($before) { + $parent->parentNode->insertBefore($tag->domNode, $parent); + } else { + $parent->parentNode->insertBefore($tag->domNode, $parent->nextSibling); + } + } + + /** + * Splits the given $parentNode at the location of the $domNode within it. + * Attempts replicate the original $parentNode, moving some of their parent + * children in where needed, before adding the $domNode between. + */ + protected function splitNodeAtChildNode(DOMElement $parentNode, DOMNode $domNode): void + { + $children = [...$parentNode->childNodes]; + $splitPos = array_search($domNode, $children, true); + if ($splitPos === false) { + $splitPos = count($children) - 1; + } + + $parentClone = $parentNode->cloneNode(); + $parentNode->parentNode->insertBefore($parentClone, $parentNode); + $parentClone->removeAttribute('id'); + + for ($i = 0; $i < $splitPos; $i++) { + /** @var DOMNode $child */ + $child = $children[$i]; + $parentClone->appendChild($child); + } + + $parentNode->parentNode->insertBefore($domNode, $parentNode); + + $this->toCleanup[] = $parentNode; + $this->toCleanup[] = $parentClone; + } + + /** + * Get the parent paragraph of the given node, if existing. + */ + protected function getParentParagraph(DOMNode $parent): ?DOMNode + { + do { + if (strtolower($parent->nodeName) === 'p') { + return $parent; + } + + $parent = $parent->parentNode; + } while ($parent !== null); + + return null; + } + + /** + * Cleanup after a parse operation. + * Removes stranded elements we may have left during the parse. + */ + protected function cleanup(): void + { + foreach ($this->toCleanup as $element) { + $element->normalize(); + while ($element->parentNode && !$element->hasChildNodes()) { + $parent = $element->parentNode; + $parent->removeChild($element); + $element = $parent; + } + } + } +} diff --git a/app/Entities/Tools/PageIncludeTag.php b/app/Entities/Tools/PageIncludeTag.php new file mode 100644 index 000000000..05a532fb2 --- /dev/null +++ b/app/Entities/Tools/PageIncludeTag.php @@ -0,0 +1,30 @@ +tagContent, 2)[0])); + } + + /** + * Get the section ID that this tag references (if any) + */ + public function getSectionId(): string + { + return trim(explode('#', $this->tagContent, 2)[1] ?? ''); + } +} diff --git a/app/Entities/Tools/TrashCan.php b/app/Entities/Tools/TrashCan.php index 08276230c..b25103985 100644 --- a/app/Entities/Tools/TrashCan.php +++ b/app/Entities/Tools/TrashCan.php @@ -202,6 +202,10 @@ class TrashCan $attachmentService->deleteFile($attachment); } + // Remove book template usages + Book::query()->where('default_template_id', '=', $page->id) + ->update(['default_template_id' => null]); + $page->forceDelete(); return 1; diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 6a4420056..61e126327 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -9,6 +9,7 @@ use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Illuminate\Http\Exceptions\PostTooLargeException; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Illuminate\Http\Response; use Illuminate\Validation\ValidationException; use Symfony\Component\ErrorHandler\Error\FatalError; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; @@ -42,7 +43,7 @@ class Handler extends ExceptionHandler * If it returns a response, that will be provided back to the request * upon an out of memory event. * - * @var ?callable + * @var ?callable(): ?Response */ protected $onOutOfMemory = null; diff --git a/app/Http/Controller.php b/app/Http/Controller.php index 6e81dfd65..8facf5dab 100644 --- a/app/Http/Controller.php +++ b/app/Http/Controller.php @@ -9,6 +9,8 @@ use BookStack\Facades\Activity; use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Foundation\Validation\ValidatesRequests; use Illuminate\Http\JsonResponse; +use Illuminate\Http\RedirectResponse; +use Illuminate\Http\Request; use Illuminate\Routing\Controller as BaseController; abstract class Controller extends BaseController @@ -165,4 +167,20 @@ abstract class Controller extends BaseController { return ['image_extension', 'mimes:jpeg,png,gif,webp', 'max:' . (config('app.upload_limit') * 1000)]; } + + /** + * Redirect to the URL provided in the request as a '_return' parameter. + * Will check that the parameter leads to a URL under the root path of the system. + */ + protected function redirectToRequest(Request $request): RedirectResponse + { + $basePath = url('/'); + $returnUrl = $request->input('_return') ?? $basePath; + + if (!str_starts_with($returnUrl, $basePath)) { + return redirect($basePath); + } + + return redirect($returnUrl); + } } diff --git a/app/Permissions/EntityPermissionEvaluator.php b/app/Permissions/EntityPermissionEvaluator.php index 06f0126ad..98ec03306 100644 --- a/app/Permissions/EntityPermissionEvaluator.php +++ b/app/Permissions/EntityPermissionEvaluator.php @@ -9,11 +9,9 @@ use Illuminate\Database\Eloquent\Builder; class EntityPermissionEvaluator { - protected string $action; - - public function __construct(string $action) - { - $this->action = $action; + public function __construct( + protected string $action + ) { } public function evaluateEntityForUser(Entity $entity, array $userRoleIds): ?bool @@ -82,23 +80,25 @@ class EntityPermissionEvaluator */ protected function getPermissionsMapByTypeId(array $typeIdChain, array $filterRoleIds): array { - $query = EntityPermission::query()->where(function (Builder $query) use ($typeIdChain) { - foreach ($typeIdChain as $typeId) { - $query->orWhere(function (Builder $query) use ($typeId) { - [$type, $id] = explode(':', $typeId); - $query->where('entity_type', '=', $type) - ->where('entity_id', '=', $id); - }); + $idsByType = []; + foreach ($typeIdChain as $typeId) { + [$type, $id] = explode(':', $typeId); + if (!isset($idsByType[$type])) { + $idsByType[$type] = []; } - }); - if (!empty($filterRoleIds)) { - $query->where(function (Builder $query) use ($filterRoleIds) { - $query->whereIn('role_id', [...$filterRoleIds, 0]); - }); + $idsByType[$type][] = $id; } - $relevantPermissions = $query->get(['entity_id', 'entity_type', 'role_id', $this->action])->all(); + $relevantPermissions = []; + + foreach ($idsByType as $type => $ids) { + $idsChunked = array_chunk($ids, 10000); + foreach ($idsChunked as $idChunk) { + $permissions = $this->getPermissionsForEntityIdsOfType($type, $idChunk, $filterRoleIds); + array_push($relevantPermissions, ...$permissions); + } + } $map = []; foreach ($relevantPermissions as $permission) { @@ -113,6 +113,26 @@ class EntityPermissionEvaluator return $map; } + /** + * @param string[] $ids + * @param int[] $filterRoleIds + * @return EntityPermission[] + */ + protected function getPermissionsForEntityIdsOfType(string $type, array $ids, array $filterRoleIds): array + { + $query = EntityPermission::query() + ->where('entity_type', '=', $type) + ->whereIn('entity_id', $ids); + + if (!empty($filterRoleIds)) { + $query->where(function (Builder $query) use ($filterRoleIds) { + $query->whereIn('role_id', [...$filterRoleIds, 0]); + }); + } + + return $query->get(['entity_id', 'entity_type', 'role_id', $this->action])->all(); + } + /** * @return string[] */ diff --git a/app/Permissions/JointPermissionBuilder.php b/app/Permissions/JointPermissionBuilder.php index 945909631..8c961fb13 100644 --- a/app/Permissions/JointPermissionBuilder.php +++ b/app/Permissions/JointPermissionBuilder.php @@ -83,13 +83,13 @@ class JointPermissionBuilder $role->load('permissions'); // Chunk through all books - $this->bookFetchQuery()->chunk(20, function ($books) use ($roles) { + $this->bookFetchQuery()->chunk(10, function ($books) use ($roles) { $this->buildJointPermissionsForBooks($books, $roles); }); // Chunk through all bookshelves Bookshelf::query()->select(['id', 'owned_by']) - ->chunk(50, function ($shelves) use ($roles) { + ->chunk(100, function ($shelves) use ($roles) { $this->createManyJointPermissions($shelves->all(), $roles); }); } diff --git a/app/Permissions/PermissionApplicator.php b/app/Permissions/PermissionApplicator.php index 7b62ac0a7..ce4a543fd 100644 --- a/app/Permissions/PermissionApplicator.php +++ b/app/Permissions/PermissionApplicator.php @@ -25,7 +25,7 @@ class PermissionApplicator /** * Checks if an entity has a restriction set upon it. * - * @param HasCreatorAndUpdater|HasOwner $ownable + * @param Model&(HasCreatorAndUpdater|HasOwner) $ownable */ public function checkOwnableUserAccess(Model $ownable, string $permission): bool { @@ -160,10 +160,9 @@ class PermissionApplicator $joinQuery = function ($query) use ($entityProvider) { $first = true; - /** @var Builder $query */ foreach ($entityProvider->all() as $entity) { + /** @var Builder $query */ $entityQuery = function ($query) use ($entity) { - /** @var Builder $query */ $query->select(['id', 'deleted_at']) ->selectRaw("'{$entity->getMorphClass()}' as type") ->from($entity->getTable()) diff --git a/app/References/CrossLinkParser.php b/app/References/CrossLinkParser.php index 88ca5d6a7..b9c3ad205 100644 --- a/app/References/CrossLinkParser.php +++ b/app/References/CrossLinkParser.php @@ -9,8 +9,7 @@ use BookStack\References\ModelResolvers\ChapterLinkModelResolver; use BookStack\References\ModelResolvers\CrossLinkModelResolver; use BookStack\References\ModelResolvers\PageLinkModelResolver; use BookStack\References\ModelResolvers\PagePermalinkModelResolver; -use DOMDocument; -use DOMXPath; +use BookStack\Util\HtmlDocument; class CrossLinkParser { @@ -54,13 +53,8 @@ class CrossLinkParser { $links = []; - $html = '' . $html . ''; - libxml_use_internal_errors(true); - $doc = new DOMDocument(); - $doc->loadHTML($html); - - $xPath = new DOMXPath($doc); - $anchors = $xPath->query('//a[@href]'); + $doc = new HtmlDocument($html); + $anchors = $doc->queryXPath('//a[@href]'); /** @var \DOMElement $anchor */ foreach ($anchors as $anchor) { diff --git a/app/References/ReferenceController.php b/app/References/ReferenceController.php index d6978dd5b..991f47225 100644 --- a/app/References/ReferenceController.php +++ b/app/References/ReferenceController.php @@ -10,11 +10,9 @@ use BookStack\Http\Controller; class ReferenceController extends Controller { - protected ReferenceFetcher $referenceFetcher; - - public function __construct(ReferenceFetcher $referenceFetcher) - { - $this->referenceFetcher = $referenceFetcher; + public function __construct( + protected ReferenceFetcher $referenceFetcher + ) { } /** @@ -23,7 +21,7 @@ class ReferenceController extends Controller public function page(string $bookSlug, string $pageSlug) { $page = Page::getBySlugs($bookSlug, $pageSlug); - $references = $this->referenceFetcher->getPageReferencesToEntity($page); + $references = $this->referenceFetcher->getReferencesToEntity($page); return view('pages.references', [ 'page' => $page, @@ -37,7 +35,7 @@ class ReferenceController extends Controller public function chapter(string $bookSlug, string $chapterSlug) { $chapter = Chapter::getBySlugs($bookSlug, $chapterSlug); - $references = $this->referenceFetcher->getPageReferencesToEntity($chapter); + $references = $this->referenceFetcher->getReferencesToEntity($chapter); return view('chapters.references', [ 'chapter' => $chapter, @@ -51,7 +49,7 @@ class ReferenceController extends Controller public function book(string $slug) { $book = Book::getBySlug($slug); - $references = $this->referenceFetcher->getPageReferencesToEntity($book); + $references = $this->referenceFetcher->getReferencesToEntity($book); return view('books.references', [ 'book' => $book, @@ -65,7 +63,7 @@ class ReferenceController extends Controller public function shelf(string $slug) { $shelf = Bookshelf::getBySlug($slug); - $references = $this->referenceFetcher->getPageReferencesToEntity($shelf); + $references = $this->referenceFetcher->getReferencesToEntity($shelf); return view('shelves.references', [ 'shelf' => $shelf, diff --git a/app/References/ReferenceFetcher.php b/app/References/ReferenceFetcher.php index c4a7d31b6..0d9883a3e 100644 --- a/app/References/ReferenceFetcher.php +++ b/app/References/ReferenceFetcher.php @@ -3,65 +3,51 @@ namespace BookStack\References; use BookStack\Entities\Models\Entity; -use BookStack\Entities\Models\Page; +use BookStack\Entities\Tools\MixedEntityListLoader; use BookStack\Permissions\PermissionApplicator; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; -use Illuminate\Database\Eloquent\Relations\Relation; class ReferenceFetcher { - protected PermissionApplicator $permissions; - - public function __construct(PermissionApplicator $permissions) - { - $this->permissions = $permissions; + public function __construct( + protected PermissionApplicator $permissions, + protected MixedEntityListLoader $mixedEntityListLoader, + ) { } /** - * Query and return the page references pointing to the given entity. + * Query and return the references pointing to the given entity. * Loads the commonly required relations while taking permissions into account. */ - public function getPageReferencesToEntity(Entity $entity): Collection + public function getReferencesToEntity(Entity $entity): Collection { - $baseQuery = $this->queryPageReferencesToEntity($entity) - ->with([ - 'from' => fn (Relation $query) => $query->select(Page::$listAttributes), - 'from.book' => fn (Relation $query) => $query->scopes('visible'), - 'from.chapter' => fn (Relation $query) => $query->scopes('visible'), - ]); - - $references = $this->permissions->restrictEntityRelationQuery( - $baseQuery, - 'references', - 'from_id', - 'from_type' - )->get(); + $references = $this->queryReferencesToEntity($entity)->get(); + $this->mixedEntityListLoader->loadIntoRelations($references->all(), 'from'); return $references; } /** - * Returns the count of page references pointing to the given entity. + * Returns the count of references pointing to the given entity. * Takes permissions into account. */ - public function getPageReferenceCountToEntity(Entity $entity): int + public function getReferenceCountToEntity(Entity $entity): int { - $count = $this->permissions->restrictEntityRelationQuery( - $this->queryPageReferencesToEntity($entity), + return $this->queryReferencesToEntity($entity)->count(); + } + + protected function queryReferencesToEntity(Entity $entity): Builder + { + $baseQuery = Reference::query() + ->where('to_type', '=', $entity->getMorphClass()) + ->where('to_id', '=', $entity->id); + + return $this->permissions->restrictEntityRelationQuery( + $baseQuery, 'references', 'from_id', 'from_type' - )->count(); - - return $count; - } - - protected function queryPageReferencesToEntity(Entity $entity): Builder - { - return Reference::query() - ->where('to_type', '=', $entity->getMorphClass()) - ->where('to_id', '=', $entity->id) - ->where('from_type', '=', (new Page())->getMorphClass()); + ); } } diff --git a/app/References/ReferenceStore.php b/app/References/ReferenceStore.php index 4c6db35c5..78595084b 100644 --- a/app/References/ReferenceStore.php +++ b/app/References/ReferenceStore.php @@ -2,60 +2,62 @@ namespace BookStack\References; -use BookStack\Entities\Models\Page; +use BookStack\Entities\EntityProvider; +use BookStack\Entities\Models\Entity; use Illuminate\Database\Eloquent\Collection; class ReferenceStore { - /** - * Update the outgoing references for the given page. - */ - public function updateForPage(Page $page): void - { - $this->updateForPages([$page]); + public function __construct( + protected EntityProvider $entityProvider + ) { } /** - * Update the outgoing references for all pages in the system. + * Update the outgoing references for the given entity. */ - public function updateForAllPages(): void + public function updateForEntity(Entity $entity): void { - Reference::query() - ->where('from_type', '=', (new Page())->getMorphClass()) - ->delete(); - - Page::query()->select(['id', 'html'])->chunk(100, function (Collection $pages) { - $this->updateForPages($pages->all()); - }); + $this->updateForEntities([$entity]); } /** - * Update the outgoing references for the pages in the given array. + * Update the outgoing references for all entities in the system. + */ + public function updateForAll(): void + { + Reference::query()->delete(); + + foreach ($this->entityProvider->all() as $entity) { + $entity->newQuery()->select(['id', $entity->htmlField])->chunk(100, function (Collection $entities) { + $this->updateForEntities($entities->all()); + }); + } + } + + /** + * Update the outgoing references for the entities in the given array. * - * @param Page[] $pages + * @param Entity[] $entities */ - protected function updateForPages(array $pages): void + protected function updateForEntities(array $entities): void { - if (count($pages) === 0) { + if (count($entities) === 0) { return; } $parser = CrossLinkParser::createWithEntityResolvers(); $references = []; - $pageIds = array_map(fn (Page $page) => $page->id, $pages); - Reference::query() - ->where('from_type', '=', $pages[0]->getMorphClass()) - ->whereIn('from_id', $pageIds) - ->delete(); + $this->dropReferencesFromEntities($entities); - foreach ($pages as $page) { - $models = $parser->extractLinkedModels($page->html); + foreach ($entities as $entity) { + $models = $parser->extractLinkedModels($entity->getAttribute($entity->htmlField)); foreach ($models as $model) { $references[] = [ - 'from_id' => $page->id, - 'from_type' => $page->getMorphClass(), + 'from_id' => $entity->id, + 'from_type' => $entity->getMorphClass(), 'to_id' => $model->id, 'to_type' => $model->getMorphClass(), ]; @@ -66,4 +68,29 @@ class ReferenceStore Reference::query()->insert($referenceDataChunk); } } + + /** + * Delete all the existing references originating from the given entities. + * @param Entity[] $entities + */ + protected function dropReferencesFromEntities(array $entities): void + { + $IdsByType = []; + + foreach ($entities as $entity) { + $type = $entity->getMorphClass(); + if (!isset($IdsByType[$type])) { + $IdsByType[$type] = []; + } + + $IdsByType[$type][] = $entity->id; + } + + foreach ($IdsByType as $type => $entityIds) { + Reference::query() + ->where('from_type', '=', $type) + ->whereIn('from_id', $entityIds) + ->delete(); + } + } } diff --git a/app/References/ReferenceUpdater.php b/app/References/ReferenceUpdater.php index 2f7b70a87..db355f211 100644 --- a/app/References/ReferenceUpdater.php +++ b/app/References/ReferenceUpdater.php @@ -4,32 +4,28 @@ namespace BookStack\References; use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Entity; +use BookStack\Entities\Models\HasHtmlDescription; use BookStack\Entities\Models\Page; use BookStack\Entities\Repos\RevisionRepo; -use DOMDocument; -use DOMXPath; +use BookStack\Util\HtmlDocument; class ReferenceUpdater { - protected ReferenceFetcher $referenceFetcher; - protected RevisionRepo $revisionRepo; - - public function __construct(ReferenceFetcher $referenceFetcher, RevisionRepo $revisionRepo) - { - $this->referenceFetcher = $referenceFetcher; - $this->revisionRepo = $revisionRepo; + public function __construct( + protected ReferenceFetcher $referenceFetcher, + protected RevisionRepo $revisionRepo, + ) { } - public function updateEntityPageReferences(Entity $entity, string $oldLink) + public function updateEntityReferences(Entity $entity, string $oldLink): void { $references = $this->getReferencesToUpdate($entity); $newLink = $entity->getUrl(); - /** @var Reference $reference */ foreach ($references as $reference) { - /** @var Page $page */ - $page = $reference->from; - $this->updateReferencesWithinPage($page, $oldLink, $newLink); + /** @var Entity $entity */ + $entity = $reference->from; + $this->updateReferencesWithinEntity($entity, $oldLink, $newLink); } } @@ -39,14 +35,15 @@ class ReferenceUpdater protected function getReferencesToUpdate(Entity $entity): array { /** @var Reference[] $references */ - $references = $this->referenceFetcher->getPageReferencesToEntity($entity)->values()->all(); + $references = $this->referenceFetcher->getReferencesToEntity($entity)->values()->all(); if ($entity instanceof Book) { $pages = $entity->pages()->get(['id']); $chapters = $entity->chapters()->get(['id']); $children = $pages->concat($chapters); foreach ($children as $bookChild) { - $childRefs = $this->referenceFetcher->getPageReferencesToEntity($bookChild)->values()->all(); + /** @var Reference[] $childRefs */ + $childRefs = $this->referenceFetcher->getReferencesToEntity($bookChild)->values()->all(); array_push($references, ...$childRefs); } } @@ -60,7 +57,28 @@ class ReferenceUpdater return array_values($deduped); } - protected function updateReferencesWithinPage(Page $page, string $oldLink, string $newLink) + protected function updateReferencesWithinEntity(Entity $entity, string $oldLink, string $newLink): void + { + if ($entity instanceof Page) { + $this->updateReferencesWithinPage($entity, $oldLink, $newLink); + return; + } + + if (in_array(HasHtmlDescription::class, class_uses($entity))) { + $this->updateReferencesWithinDescription($entity, $oldLink, $newLink); + } + } + + protected function updateReferencesWithinDescription(Entity $entity, string $oldLink, string $newLink): void + { + /** @var HasHtmlDescription&Entity $entity */ + $entity = (clone $entity)->refresh(); + $html = $this->updateLinksInHtml($entity->description_html ?: '', $oldLink, $newLink); + $entity->description_html = $html; + $entity->save(); + } + + protected function updateReferencesWithinPage(Page $page, string $oldLink, string $newLink): void { $page = (clone $page)->refresh(); $html = $this->updateLinksInHtml($page->html, $oldLink, $newLink); @@ -96,13 +114,8 @@ class ReferenceUpdater return $html; } - $html = '' . $html . ''; - libxml_use_internal_errors(true); - $doc = new DOMDocument(); - $doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8')); - - $xPath = new DOMXPath($doc); - $anchors = $xPath->query('//a[@href]'); + $doc = new HtmlDocument($html); + $anchors = $doc->queryXPath('//a[@href]'); /** @var \DOMElement $anchor */ foreach ($anchors as $anchor) { @@ -111,12 +124,6 @@ class ReferenceUpdater $anchor->setAttribute('href', $updated); } - $html = ''; - $topElems = $doc->documentElement->childNodes->item(0)->childNodes; - foreach ($topElems as $child) { - $html .= $doc->saveHTML($child); - } - - return $html; + return $doc->getBodyInnerHtml(); } } diff --git a/app/Search/SearchController.php b/app/Search/SearchController.php index 09a67f2b5..6cf12a579 100644 --- a/app/Search/SearchController.php +++ b/app/Search/SearchController.php @@ -2,6 +2,7 @@ namespace BookStack\Search; +use BookStack\Entities\Models\Page; use BookStack\Entities\Queries\Popular; use BookStack\Entities\Tools\SiblingFetcher; use BookStack\Http\Controller; @@ -82,6 +83,32 @@ class SearchController extends Controller return view('search.parts.entity-selector-list', ['entities' => $entities, 'permission' => $permission]); } + /** + * Search for a list of templates to choose from. + */ + public function templatesForSelector(Request $request) + { + $searchTerm = $request->get('term', false); + + if ($searchTerm !== false) { + $searchOptions = SearchOptions::fromString($searchTerm); + $searchOptions->setFilter('is_template'); + $entities = $this->searchRunner->searchEntities($searchOptions, 'page', 1, 20)['results']; + } else { + $entities = Page::visible() + ->where('template', '=', true) + ->where('draft', '=', false) + ->orderBy('updated_at', 'desc') + ->take(20) + ->get(Page::$listAttributes); + } + + return view('search.parts.entity-selector-list', [ + 'entities' => $entities, + 'permission' => 'view' + ]); + } + /** * Search for a list of entities and return a partial HTML response of matching entities * to be used as a result preview suggestion list for global system searches. diff --git a/app/Search/SearchIndex.php b/app/Search/SearchIndex.php index e882e987b..d9fc4e7aa 100644 --- a/app/Search/SearchIndex.php +++ b/app/Search/SearchIndex.php @@ -6,7 +6,7 @@ use BookStack\Activity\Models\Tag; use BookStack\Entities\EntityProvider; use BookStack\Entities\Models\Entity; use BookStack\Entities\Models\Page; -use DOMDocument; +use BookStack\Util\HtmlDocument; use DOMNode; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Collection; @@ -138,16 +138,11 @@ class SearchIndex 'h6' => 1.5, ]; - $html = '' . $html . ''; $html = str_ireplace(['
', '
', '
'], "\n", $html); + $doc = new HtmlDocument($html); - libxml_use_internal_errors(true); - $doc = new DOMDocument(); - $doc->loadHTML($html); - - $topElems = $doc->documentElement->childNodes->item(0)->childNodes; /** @var DOMNode $child */ - foreach ($topElems as $child) { + foreach ($doc->getBodyChildren() as $child) { $nodeName = $child->nodeName; $termCounts = $this->textToTermCountMap(trim($child->textContent)); foreach ($termCounts as $term => $count) { @@ -168,7 +163,6 @@ class SearchIndex */ protected function generateTermScoreMapFromTags(array $tags): array { - $scoreMap = []; $names = []; $values = []; diff --git a/app/Search/SearchOptions.php b/app/Search/SearchOptions.php index d38fc8d57..fffa03db0 100644 --- a/app/Search/SearchOptions.php +++ b/app/Search/SearchOptions.php @@ -170,6 +170,14 @@ class SearchOptions return $parsed; } + /** + * Set the value of a specific filter in the search options. + */ + public function setFilter(string $filterName, string $filterValue = ''): void + { + $this->filters[$filterName] = $filterValue; + } + /** * Encode this instance to a search string. */ diff --git a/app/Search/SearchRunner.php b/app/Search/SearchRunner.php index fc36cb816..aac9d1000 100644 --- a/app/Search/SearchRunner.php +++ b/app/Search/SearchRunner.php @@ -58,7 +58,7 @@ class SearchRunner $entityTypesToSearch = $entityTypes; if ($entityType !== 'all') { - $entityTypesToSearch = $entityType; + $entityTypesToSearch = [$entityType]; } elseif (isset($searchOpts->filters['type'])) { $entityTypesToSearch = explode('|', $searchOpts->filters['type']); } @@ -469,6 +469,13 @@ class SearchRunner }); } + protected function filterIsTemplate(EloquentBuilder $query, Entity $model, $input) + { + if ($model instanceof Page) { + $query->where('template', '=', true); + } + } + protected function filterSortBy(EloquentBuilder $query, Entity $model, $input) { $functionName = Str::camel('sort_by_' . $input); diff --git a/app/Settings/MaintenanceController.php b/app/Settings/MaintenanceController.php index 60e5fee28..62eeecf39 100644 --- a/app/Settings/MaintenanceController.php +++ b/app/Settings/MaintenanceController.php @@ -87,7 +87,7 @@ class MaintenanceController extends Controller $this->logActivity(ActivityType::MAINTENANCE_ACTION_RUN, 'regenerate-references'); try { - $referenceStore->updateForAllPages(); + $referenceStore->updateForAll(); $this->showSuccessNotification(trans('settings.maint_regen_references_success')); } catch (\Exception $exception) { $this->showErrorNotification($exception->getMessage()); diff --git a/app/Theming/CustomHtmlHeadContentProvider.php b/app/Theming/CustomHtmlHeadContentProvider.php index 041e5d025..95d9ff5ad 100644 --- a/app/Theming/CustomHtmlHeadContentProvider.php +++ b/app/Theming/CustomHtmlHeadContentProvider.php @@ -50,7 +50,7 @@ class CustomHtmlHeadContentProvider $hash = md5($content); return $this->cache->remember('custom-head-export:' . $hash, 86400, function () use ($content) { - return HtmlContentFilter::removeScripts($content); + return HtmlContentFilter::removeScriptsFromHtmlString($content); }); } diff --git a/app/Theming/ThemeEvents.php b/app/Theming/ThemeEvents.php index 4b56b2f56..ff9e86e16 100644 --- a/app/Theming/ThemeEvents.php +++ b/app/Theming/ThemeEvents.php @@ -2,8 +2,6 @@ namespace BookStack\Theming; -use BookStack\Entities\Models\Page; - /** * The ThemeEvents used within BookStack. * @@ -93,11 +91,30 @@ class ThemeEvents * * @param string $tagReference * @param string $replacementHTML - * @param Page $currentPage - * @param ?Page $referencedPage + * @param \BookStack\Entities\Models\Page $currentPage + * @param ?\BookStack\Entities\Models\Page $referencedPage */ const PAGE_INCLUDE_PARSE = 'page_include_parse'; + /** + * Routes register web event. + * Called when standard web (browser/non-api) app routes are registered. + * Provides an app router, so you can register your own web routes. + * + * @param \Illuminate\Routing\Router $router + */ + const ROUTES_REGISTER_WEB = 'routes_register_web'; + + /** + * Routes register web auth event. + * Called when auth-required web (browser/non-api) app routes can be registered. + * These are routes that typically require login to access (unless the instance is made public). + * Provides an app router, so you can register your own web routes. + * + * @param \Illuminate\Routing\Router $router + */ + const ROUTES_REGISTER_WEB_AUTH = 'routes_register_web_auth'; + /** * Web before middleware action. * Runs before the request is handled but after all other middleware apart from those diff --git a/app/Theming/ThemeService.php b/app/Theming/ThemeService.php index 31a7d3c64..94e471217 100644 --- a/app/Theming/ThemeService.php +++ b/app/Theming/ThemeService.php @@ -2,7 +2,7 @@ namespace BookStack\Theming; -use BookStack\Access\SocialAuthService; +use BookStack\Access\SocialDriverManager; use BookStack\Exceptions\ThemeException; use Illuminate\Console\Application; use Illuminate\Console\Application as Artisan; @@ -48,6 +48,14 @@ class ThemeService return null; } + /** + * Check if there are listeners registered for the given event name. + */ + public function hasListeners(string $event): bool + { + return count($this->listeners[$event] ?? []) > 0; + } + /** * Register a new custom artisan command to be available. */ @@ -74,11 +82,11 @@ class ThemeService } /** - * @see SocialAuthService::addSocialDriver + * @see SocialDriverManager::addSocialDriver */ public function addSocialDriver(string $driverName, array $config, string $socialiteHandler, callable $configureForRedirect = null): void { - $socialAuthService = app()->make(SocialAuthService::class); - $socialAuthService->addSocialDriver($driverName, $config, $socialiteHandler, $configureForRedirect); + $driverManager = app()->make(SocialDriverManager::class); + $driverManager->addSocialDriver($driverName, $config, $socialiteHandler, $configureForRedirect); } } diff --git a/app/Users/Controllers/RoleController.php b/app/Users/Controllers/RoleController.php index 0052d829d..a874ce4d6 100644 --- a/app/Users/Controllers/RoleController.php +++ b/app/Users/Controllers/RoleController.php @@ -154,7 +154,7 @@ class RoleController extends Controller } catch (PermissionsException $e) { $this->showErrorNotification($e->getMessage()); - return redirect()->back(); + return redirect("/settings/roles/delete/{$id}"); } return redirect('/settings/roles'); diff --git a/app/Users/Controllers/UserAccountController.php b/app/Users/Controllers/UserAccountController.php index 55776a7f6..708a91e9d 100644 --- a/app/Users/Controllers/UserAccountController.php +++ b/app/Users/Controllers/UserAccountController.php @@ -2,7 +2,7 @@ namespace BookStack\Users\Controllers; -use BookStack\Access\SocialAuthService; +use BookStack\Access\SocialDriverManager; use BookStack\Http\Controller; use BookStack\Permissions\PermissionApplicator; use BookStack\Settings\UserNotificationPreferences; @@ -161,7 +161,7 @@ class UserAccountController extends Controller /** * Show the view for the "Access & Security" account options. */ - public function showAuth(SocialAuthService $socialAuthService) + public function showAuth(SocialDriverManager $socialDriverManager) { $mfaMethods = user()->mfaValues()->get()->groupBy('method'); @@ -171,7 +171,7 @@ class UserAccountController extends Controller 'category' => 'auth', 'mfaMethods' => $mfaMethods, 'authMethod' => config('auth.method'), - 'activeSocialDrivers' => $socialAuthService->getActiveDrivers(), + 'activeSocialDrivers' => $socialDriverManager->getActive(), ]); } diff --git a/app/Users/Controllers/UserApiController.php b/app/Users/Controllers/UserApiController.php index 880165e1b..1ccfecd73 100644 --- a/app/Users/Controllers/UserApiController.php +++ b/app/Users/Controllers/UserApiController.php @@ -90,7 +90,7 @@ class UserApiController extends ApiController public function create(Request $request) { $data = $this->validate($request, $this->rules()['create']); - $sendInvite = ($data['send_invite'] ?? false) === true; + $sendInvite = boolval($data['send_invite'] ?? false) === true; $user = null; DB::transaction(function () use ($data, $sendInvite, &$user) { diff --git a/app/Users/Controllers/UserController.php b/app/Users/Controllers/UserController.php index 507c7cf06..185d6101c 100644 --- a/app/Users/Controllers/UserController.php +++ b/app/Users/Controllers/UserController.php @@ -2,7 +2,7 @@ namespace BookStack\Users\Controllers; -use BookStack\Access\SocialAuthService; +use BookStack\Access\SocialDriverManager; use BookStack\Exceptions\ImageUploadException; use BookStack\Exceptions\UserUpdateException; use BookStack\Http\Controller; @@ -101,7 +101,7 @@ class UserController extends Controller /** * Show the form for editing the specified user. */ - public function edit(int $id, SocialAuthService $socialAuthService) + public function edit(int $id, SocialDriverManager $socialDriverManager) { $this->checkPermission('users-manage'); @@ -109,7 +109,7 @@ class UserController extends Controller $user->load(['apiTokens', 'mfaValues']); $authMethod = ($user->system_name) ? 'system' : config('auth.method'); - $activeSocialDrivers = $socialAuthService->getActiveDrivers(); + $activeSocialDrivers = $socialDriverManager->getActive(); $mfaMethods = $user->mfaValues->groupBy('method'); $this->setPageTitle(trans('settings.user_profile')); $roles = Role::query()->orderBy('display_name', 'asc')->get(); diff --git a/app/Users/Controllers/UserPreferencesController.php b/app/Users/Controllers/UserPreferencesController.php index 3600dc55f..0bed2d22a 100644 --- a/app/Users/Controllers/UserPreferencesController.php +++ b/app/Users/Controllers/UserPreferencesController.php @@ -3,9 +3,6 @@ namespace BookStack\Users\Controllers; use BookStack\Http\Controller; -use BookStack\Permissions\PermissionApplicator; -use BookStack\Settings\UserNotificationPreferences; -use BookStack\Settings\UserShortcutMap; use BookStack\Users\UserRepo; use Illuminate\Http\Request; @@ -23,7 +20,7 @@ class UserPreferencesController extends Controller { $valueViewTypes = ['books', 'bookshelves', 'bookshelf']; if (!in_array($type, $valueViewTypes)) { - return redirect()->back(500); + return $this->redirectToRequest($request); } $view = $request->get('view'); @@ -34,7 +31,7 @@ class UserPreferencesController extends Controller $key = $type . '_view_type'; setting()->putForCurrentUser($key, $view); - return redirect()->back(302, [], "/"); + return $this->redirectToRequest($request); } /** @@ -44,7 +41,7 @@ class UserPreferencesController extends Controller { $validSortTypes = ['books', 'bookshelves', 'shelf_books', 'users', 'roles', 'webhooks', 'tags', 'page_revisions']; if (!in_array($type, $validSortTypes)) { - return redirect()->back(500); + return $this->redirectToRequest($request); } $sort = substr($request->get('sort') ?: 'name', 0, 50); @@ -55,18 +52,18 @@ class UserPreferencesController extends Controller setting()->putForCurrentUser($sortKey, $sort); setting()->putForCurrentUser($orderKey, $order); - return redirect()->back(302, [], "/"); + return $this->redirectToRequest($request); } /** * Toggle dark mode for the current user. */ - public function toggleDarkMode() + public function toggleDarkMode(Request $request) { $enabled = setting()->getForCurrentUser('dark-mode-enabled'); setting()->putForCurrentUser('dark-mode-enabled', $enabled ? 'false' : 'true'); - return redirect()->back(); + return $this->redirectToRequest($request); } /** diff --git a/app/Util/HtmlContentFilter.php b/app/Util/HtmlContentFilter.php index e51f512bd..758591729 100644 --- a/app/Util/HtmlContentFilter.php +++ b/app/Util/HtmlContentFilter.php @@ -3,70 +3,65 @@ namespace BookStack\Util; use DOMAttr; -use DOMDocument; use DOMElement; use DOMNodeList; -use DOMXPath; class HtmlContentFilter { /** - * Remove all the script elements from the given HTML. + * Remove all the script elements from the given HTML document. */ - public static function removeScripts(string $html): string + public static function removeScriptsFromDocument(HtmlDocument $doc) { - if (empty($html)) { - return $html; - } - - $html = '' . $html . ''; - libxml_use_internal_errors(true); - $doc = new DOMDocument(); - $doc->loadHTML($html); - $xPath = new DOMXPath($doc); - // Remove standard script tags - $scriptElems = $xPath->query('//script'); + $scriptElems = $doc->queryXPath('//script'); static::removeNodes($scriptElems); // Remove clickable links to JavaScript URI - $badLinks = $xPath->query('//*[' . static::xpathContains('@href', 'javascript:') . ']'); + $badLinks = $doc->queryXPath('//*[' . static::xpathContains('@href', 'javascript:') . ']'); static::removeNodes($badLinks); // Remove forms with calls to JavaScript URI - $badForms = $xPath->query('//*[' . static::xpathContains('@action', 'javascript:') . '] | //*[' . static::xpathContains('@formaction', 'javascript:') . ']'); + $badForms = $doc->queryXPath('//*[' . static::xpathContains('@action', 'javascript:') . '] | //*[' . static::xpathContains('@formaction', 'javascript:') . ']'); static::removeNodes($badForms); // Remove meta tag to prevent external redirects - $metaTags = $xPath->query('//meta[' . static::xpathContains('@content', 'url') . ']'); + $metaTags = $doc->queryXPath('//meta[' . static::xpathContains('@content', 'url') . ']'); static::removeNodes($metaTags); // Remove data or JavaScript iFrames - $badIframes = $xPath->query('//*[' . static::xpathContains('@src', 'data:') . '] | //*[' . static::xpathContains('@src', 'javascript:') . '] | //*[@srcdoc]'); + $badIframes = $doc->queryXPath('//*[' . static::xpathContains('@src', 'data:') . '] | //*[' . static::xpathContains('@src', 'javascript:') . '] | //*[@srcdoc]'); static::removeNodes($badIframes); // Remove attributes, within svg children, hiding JavaScript or data uris. // A bunch of svg element and attribute combinations expose xss possibilities. // For example, SVG animate tag can exploit javascript in values. - $badValuesAttrs = $xPath->query('//svg//@*[' . static::xpathContains('.', 'data:') . '] | //svg//@*[' . static::xpathContains('.', 'javascript:') . ']'); + $badValuesAttrs = $doc->queryXPath('//svg//@*[' . static::xpathContains('.', 'data:') . '] | //svg//@*[' . static::xpathContains('.', 'javascript:') . ']'); static::removeAttributes($badValuesAttrs); // Remove elements with a xlink:href attribute // Used in SVG but deprecated anyway, so we'll be a bit more heavy-handed here. - $xlinkHrefAttributes = $xPath->query('//@*[contains(name(), \'xlink:href\')]'); + $xlinkHrefAttributes = $doc->queryXPath('//@*[contains(name(), \'xlink:href\')]'); static::removeAttributes($xlinkHrefAttributes); // Remove 'on*' attributes - $onAttributes = $xPath->query('//@*[starts-with(name(), \'on\')]'); + $onAttributes = $doc->queryXPath('//@*[starts-with(name(), \'on\')]'); static::removeAttributes($onAttributes); + } - $html = ''; - $topElems = $doc->documentElement->childNodes->item(0)->childNodes; - foreach ($topElems as $child) { - $html .= $doc->saveHTML($child); + /** + * Remove scripts from the given HTML string. + */ + public static function removeScriptsFromHtmlString(string $html): string + { + if (empty($html)) { + return $html; } - return $html; + $doc = new HtmlDocument($html); + static::removeScriptsFromDocument($doc); + + return $doc->getBodyInnerHtml(); } /** diff --git a/app/Util/HtmlDescriptionFilter.php b/app/Util/HtmlDescriptionFilter.php new file mode 100644 index 000000000..7287586d1 --- /dev/null +++ b/app/Util/HtmlDescriptionFilter.php @@ -0,0 +1,79 @@ + + */ + protected static array $allowedAttrsByElements = [ + 'p' => [], + 'a' => ['href', 'title'], + 'ol' => [], + 'ul' => [], + 'li' => [], + 'strong' => [], + 'em' => [], + 'br' => [], + ]; + + public static function filterFromString(string $html): string + { + if (empty(trim($html))) { + return ''; + } + + $doc = new HtmlDocument($html); + + $topLevel = [...$doc->getBodyChildren()]; + foreach ($topLevel as $child) { + /** @var DOMNode $child */ + if ($child instanceof DOMElement) { + static::filterElement($child); + } else { + $child->parentNode->removeChild($child); + } + } + + return $doc->getBodyInnerHtml(); + } + + protected static function filterElement(DOMElement $element): void + { + $elType = strtolower($element->tagName); + $allowedAttrs = static::$allowedAttrsByElements[$elType] ?? null; + if (is_null($allowedAttrs)) { + $element->remove(); + return; + } + + /** @var DOMNamedNodeMap $attrs */ + $attrs = $element->attributes; + for ($i = $attrs->length - 1; $i >= 0; $i--) { + /** @var DOMAttr $attr */ + $attr = $attrs->item($i); + $name = strtolower($attr->name); + if (!in_array($name, $allowedAttrs)) { + $element->removeAttribute($attr->name); + } + } + + foreach ($element->childNodes as $child) { + if ($child instanceof DOMElement) { + static::filterElement($child); + } + } + } +} diff --git a/app/Util/HtmlDocument.php b/app/Util/HtmlDocument.php new file mode 100644 index 000000000..b8c53d439 --- /dev/null +++ b/app/Util/HtmlDocument.php @@ -0,0 +1,152 @@ +document = new DOMDocument(); + $this->loadOptions = $loadOptions; + + if ($partialHtml) { + $this->loadPartialHtml($partialHtml); + } + } + + /** + * Load some HTML content that's part of a document (e.g. body content) + * into the current document. + */ + public function loadPartialHtml(string $html): void + { + $html = '' . $html . ''; + $this->document->loadHTML($html, $this->loadOptions); + $this->xpath = null; + } + + /** + * Load a complete page of HTML content into the document. + */ + public function loadCompleteHtml(string $html): void + { + $html = '' . $html; + $this->document->loadHTML($html, $this->loadOptions); + $this->xpath = null; + } + + /** + * Start an XPath query on the current document. + */ + public function queryXPath(string $expression): DOMNodeList + { + if (is_null($this->xpath)) { + $this->xpath = new DOMXPath($this->document); + } + + $result = $this->xpath->query($expression); + if ($result === false) { + throw new \InvalidArgumentException("XPath query for expression [$expression] failed to execute"); + } + + return $result; + } + + /** + * Create a new DOMElement instance within the document. + */ + public function createElement(string $localName, string $value = ''): DOMElement + { + $element = $this->document->createElement($localName, $value); + + if ($element === false) { + throw new \InvalidArgumentException("Failed to create element of name [$localName] and value [$value]"); + } + + return $element; + } + + /** + * Get an element within the document of the given ID. + */ + public function getElementById(string $elementId): ?DOMElement + { + return $this->document->getElementById($elementId); + } + + /** + * Get the DOMNode that represents the HTML body. + */ + public function getBody(): DOMNode + { + return $this->document->getElementsByTagName('body')[0]; + } + + /** + * Get the nodes that are a direct child of the body. + * This is usually all the content nodes if loaded partially. + */ + public function getBodyChildren(): DOMNodeList + { + return $this->getBody()->childNodes; + } + + /** + * Get the inner HTML content of the body. + * This is usually all the content if loaded partially. + */ + public function getBodyInnerHtml(): string + { + $html = ''; + foreach ($this->getBodyChildren() as $child) { + $html .= $this->document->saveHTML($child); + } + + return $html; + } + + /** + * Get the HTML content of the whole document. + */ + public function getHtml(): string + { + return $this->document->saveHTML($this->document->documentElement); + } + + /** + * Get the inner HTML for the given node. + */ + public function getNodeInnerHtml(DOMNode $node): string + { + $html = ''; + + foreach ($node->childNodes as $childNode) { + $html .= $this->document->saveHTML($childNode); + } + + return $html; + } + + /** + * Get the outer HTML for the given node. + */ + public function getNodeOuterHtml(DOMNode $node): string + { + return $this->document->saveHTML($node); + } +} diff --git a/app/Util/HtmlNonceApplicator.php b/app/Util/HtmlNonceApplicator.php index 07298577c..3a798e848 100644 --- a/app/Util/HtmlNonceApplicator.php +++ b/app/Util/HtmlNonceApplicator.php @@ -2,14 +2,12 @@ namespace BookStack\Util; -use DOMDocument; use DOMElement; use DOMNodeList; -use DOMXPath; class HtmlNonceApplicator { - protected static $placeholder = '[CSP_NONCE_VALUE]'; + protected static string $placeholder = '[CSP_NONCE_VALUE]'; /** * Prepare the given HTML content with nonce attributes including a placeholder @@ -21,28 +19,20 @@ class HtmlNonceApplicator return $html; } - $html = '' . $html . ''; - libxml_use_internal_errors(true); - $doc = new DOMDocument(); - $doc->loadHTML($html, LIBXML_SCHEMA_CREATE); - $xPath = new DOMXPath($doc); + // LIBXML_SCHEMA_CREATE was found to be required here otherwise + // the PHP DOMDocument handling will attempt to format/close + // HTML tags within scripts and therefore change JS content. + $doc = new HtmlDocument($html, LIBXML_SCHEMA_CREATE); // Apply to scripts - $scriptElems = $xPath->query('//script'); + $scriptElems = $doc->queryXPath('//script'); static::addNonceAttributes($scriptElems, static::$placeholder); // Apply to styles - $styleElems = $xPath->query('//style'); + $styleElems = $doc->queryXPath('//style'); static::addNonceAttributes($styleElems, static::$placeholder); - $returnHtml = ''; - $topElems = $doc->documentElement->childNodes->item(0)->childNodes; - foreach ($topElems as $child) { - $content = $doc->saveHTML($child); - $returnHtml .= $content; - } - - return $returnHtml; + return $doc->getBodyInnerHtml(); } /** diff --git a/composer.json b/composer.json index 037f8984e..85bb3cbae 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "guzzlehttp/guzzle": "^7.4", "intervention/image": "^2.7", "laravel/framework": "^9.0", - "laravel/socialite": "^5.8", + "laravel/socialite": "^5.10", "laravel/tinker": "^2.6", "league/commonmark": "^2.3", "league/flysystem-aws-s3-v3": "^3.0", @@ -38,18 +38,18 @@ "socialiteproviders/microsoft-azure": "^5.1", "socialiteproviders/okta": "^4.2", "socialiteproviders/twitch": "^5.3", - "ssddanbrown/htmldiff": "^1.0.2" + "ssddanbrown/htmldiff": "^1.0.2", + "ssddanbrown/symfony-mailer": "6.0.x-dev" }, "require-dev": { "fakerphp/faker": "^1.21", "itsgoingd/clockwork": "^5.1", "mockery/mockery": "^1.5", "nunomaduro/collision": "^6.4", - "nunomaduro/larastan": "^2.4", + "larastan/larastan": "^2.7", "phpunit/phpunit": "^9.5", "squizlabs/php_codesniffer": "^3.7", - "ssddanbrown/asserthtml": "^2.0", - "ssddanbrown/symfony-mailer": "6.0.x-dev" + "ssddanbrown/asserthtml": "^2.0" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index bd158cf48..56d33e78e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "db3cca7a93d7d097c9f517b6fe00ee7b", + "content-hash": "7c64775f79832d552a2ef40e11f79c40", "packages": [ { "name": "aws/aws-crt-php", - "version": "v1.2.2", + "version": "v1.2.4", "source": { "type": "git", "url": "https://github.com/awslabs/aws-crt-php.git", - "reference": "2f1dc7b7eda080498be96a4a6d683a41583030e9" + "reference": "eb0c6e4e142224a10b08f49ebf87f32611d162b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/2f1dc7b7eda080498be96a4a6d683a41583030e9", - "reference": "2f1dc7b7eda080498be96a4a6d683a41583030e9", + "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/eb0c6e4e142224a10b08f49ebf87f32611d162b2", + "reference": "eb0c6e4e142224a10b08f49ebf87f32611d162b2", "shasum": "" }, "require": { @@ -56,26 +56,26 @@ ], "support": { "issues": "https://github.com/awslabs/aws-crt-php/issues", - "source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.2" + "source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.4" }, - "time": "2023-07-20T16:49:55+00:00" + "time": "2023-11-08T00:42:13+00:00" }, { "name": "aws/aws-sdk-php", - "version": "3.283.8", + "version": "3.294.5", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "0f73ec85852312a6e971cfe2eebfd7c8091cca34" + "reference": "2e34d45e970c77775e4c298e08732d64b647c41c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/0f73ec85852312a6e971cfe2eebfd7c8091cca34", - "reference": "0f73ec85852312a6e971cfe2eebfd7c8091cca34", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/2e34d45e970c77775e4c298e08732d64b647c41c", + "reference": "2e34d45e970c77775e4c298e08732d64b647c41c", "shasum": "" }, "require": { - "aws/aws-crt-php": "^1.0.4", + "aws/aws-crt-php": "^1.2.3", "ext-json": "*", "ext-pcre": "*", "ext-simplexml": "*", @@ -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.283.8" + "source": "https://github.com/aws/aws-sdk-php/tree/3.294.5" }, - "time": "2023-10-19T19:26:52+00:00" + "time": "2023-12-21T19:10:21+00:00" }, { "name": "bacon/bacon-qr-code", @@ -419,6 +419,75 @@ ], "time": "2023-01-15T23:15:59+00:00" }, + { + "name": "carbonphp/carbon-doctrine-types", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/CarbonPHP/carbon-doctrine-types.git", + "reference": "99f76ffa36cce3b70a4a6abce41dba15ca2e84cb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/99f76ffa36cce3b70a4a6abce41dba15ca2e84cb", + "reference": "99f76ffa36cce3b70a4a6abce41dba15ca2e84cb", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "conflict": { + "doctrine/dbal": "<3.7.0 || >=4.0.0" + }, + "require-dev": { + "doctrine/dbal": "^3.7.0", + "nesbot/carbon": "^2.71.0 || ^3.0.0", + "phpunit/phpunit": "^10.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Carbon\\Doctrine\\": "src/Carbon/Doctrine/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "KyleKatarn", + "email": "kylekatarnls@gmail.com" + } + ], + "description": "Types to use Carbon in Doctrine", + "keywords": [ + "carbon", + "date", + "datetime", + "doctrine", + "time" + ], + "support": { + "issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues", + "source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/2.1.0" + }, + "funding": [ + { + "url": "https://github.com/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", + "type": "tidelift" + } + ], + "time": "2023-12-11T17:09:12+00:00" + }, { "name": "dasprid/enum", "version": "1.0.5", @@ -639,16 +708,16 @@ }, { "name": "doctrine/dbal", - "version": "3.7.1", + "version": "3.7.2", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "5b7bd66c9ff58c04c5474ab85edce442f8081cb2" + "reference": "0ac3c270590e54910715e9a1a044cc368df282b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/5b7bd66c9ff58c04c5474ab85edce442f8081cb2", - "reference": "5b7bd66c9ff58c04c5474ab85edce442f8081cb2", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/0ac3c270590e54910715e9a1a044cc368df282b2", + "reference": "0ac3c270590e54910715e9a1a044cc368df282b2", "shasum": "" }, "require": { @@ -664,7 +733,7 @@ "doctrine/coding-standard": "12.0.0", "fig/log-test": "^1", "jetbrains/phpstorm-stubs": "2023.1", - "phpstan/phpstan": "1.10.35", + "phpstan/phpstan": "1.10.42", "phpstan/phpstan-strict-rules": "^1.5", "phpunit/phpunit": "9.6.13", "psalm/plugin-phpunit": "0.18.4", @@ -732,7 +801,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.7.1" + "source": "https://github.com/doctrine/dbal/tree/3.7.2" }, "funding": [ { @@ -748,7 +817,7 @@ "type": "tidelift" } ], - "time": "2023-10-06T05:06:20+00:00" + "time": "2023-11-19T08:06:58+00:00" }, { "name": "doctrine/deprecations", @@ -1060,16 +1129,16 @@ }, { "name": "dompdf/dompdf", - "version": "v2.0.3", + "version": "v2.0.4", "source": { "type": "git", "url": "https://github.com/dompdf/dompdf.git", - "reference": "e8d2d5e37e8b0b30f0732a011295ab80680d7e85" + "reference": "093f2d9739cec57428e39ddadedfd4f3ae862c0f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/dompdf/zipball/e8d2d5e37e8b0b30f0732a011295ab80680d7e85", - "reference": "e8d2d5e37e8b0b30f0732a011295ab80680d7e85", + "url": "https://api.github.com/repos/dompdf/dompdf/zipball/093f2d9739cec57428e39ddadedfd4f3ae862c0f", + "reference": "093f2d9739cec57428e39ddadedfd4f3ae862c0f", "shasum": "" }, "require": { @@ -1116,9 +1185,9 @@ "homepage": "https://github.com/dompdf/dompdf", "support": { "issues": "https://github.com/dompdf/dompdf/issues", - "source": "https://github.com/dompdf/dompdf/tree/v2.0.3" + "source": "https://github.com/dompdf/dompdf/tree/v2.0.4" }, - "time": "2023-02-07T12:51:48+00:00" + "time": "2023-12-12T20:19:39+00:00" }, { "name": "dragonmantank/cron-expression", @@ -1321,24 +1390,24 @@ }, { "name": "graham-campbell/result-type", - "version": "v1.1.1", + "version": "v1.1.2", "source": { "type": "git", "url": "https://github.com/GrahamCampbell/Result-Type.git", - "reference": "672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831" + "reference": "fbd48bce38f73f8a4ec8583362e732e4095e5862" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831", - "reference": "672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/fbd48bce38f73f8a4ec8583362e732e4095e5862", + "reference": "fbd48bce38f73f8a4ec8583362e732e4095e5862", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.1" + "phpoption/phpoption": "^1.9.2" }, "require-dev": { - "phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12" + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" }, "type": "library", "autoload": { @@ -1367,7 +1436,7 @@ ], "support": { "issues": "https://github.com/GrahamCampbell/Result-Type/issues", - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.1" + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.2" }, "funding": [ { @@ -1379,20 +1448,20 @@ "type": "tidelift" } ], - "time": "2023-02-25T20:23:15+00:00" + "time": "2023-11-12T22:16:48+00:00" }, { "name": "guzzlehttp/guzzle", - "version": "7.8.0", + "version": "7.8.1", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "1110f66a6530a40fe7aea0378fe608ee2b2248f9" + "reference": "41042bc7ab002487b876a0683fc8dce04ddce104" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/1110f66a6530a40fe7aea0378fe608ee2b2248f9", - "reference": "1110f66a6530a40fe7aea0378fe608ee2b2248f9", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104", + "reference": "41042bc7ab002487b876a0683fc8dce04ddce104", "shasum": "" }, "require": { @@ -1407,11 +1476,11 @@ "psr/http-client-implementation": "1.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", + "bamarni/composer-bin-plugin": "^1.8.2", "ext-curl": "*", "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", "php-http/message-factory": "^1.1", - "phpunit/phpunit": "^8.5.29 || ^9.5.23", + "phpunit/phpunit": "^8.5.36 || ^9.6.15", "psr/log": "^1.1 || ^2.0 || ^3.0" }, "suggest": { @@ -1489,7 +1558,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.8.0" + "source": "https://github.com/guzzle/guzzle/tree/7.8.1" }, "funding": [ { @@ -1505,28 +1574,28 @@ "type": "tidelift" } ], - "time": "2023-08-27T10:20:53+00:00" + "time": "2023-12-03T20:35:24+00:00" }, { "name": "guzzlehttp/promises", - "version": "2.0.1", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "111166291a0f8130081195ac4556a5587d7f1b5d" + "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/111166291a0f8130081195ac4556a5587d7f1b5d", - "reference": "111166291a0f8130081195ac4556a5587d7f1b5d", + "url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223", + "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", - "phpunit/phpunit": "^8.5.29 || ^9.5.23" + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.36 || ^9.6.15" }, "type": "library", "extra": { @@ -1572,7 +1641,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.0.1" + "source": "https://github.com/guzzle/promises/tree/2.0.2" }, "funding": [ { @@ -1588,20 +1657,20 @@ "type": "tidelift" } ], - "time": "2023-08-03T15:11:55+00:00" + "time": "2023-12-03T20:19:20+00:00" }, { "name": "guzzlehttp/psr7", - "version": "2.6.1", + "version": "2.6.2", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727" + "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/be45764272e8873c72dbe3d2edcfdfcc3bc9f727", - "reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221", + "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221", "shasum": "" }, "require": { @@ -1615,9 +1684,9 @@ "psr/http-message-implementation": "1.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", + "bamarni/composer-bin-plugin": "^1.8.2", "http-interop/http-factory-tests": "^0.9", - "phpunit/phpunit": "^8.5.29 || ^9.5.23" + "phpunit/phpunit": "^8.5.36 || ^9.6.15" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" @@ -1688,7 +1757,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.6.1" + "source": "https://github.com/guzzle/psr7/tree/2.6.2" }, "funding": [ { @@ -1704,32 +1773,38 @@ "type": "tidelift" } ], - "time": "2023-08-27T10:13:57+00:00" + "time": "2023-12-03T20:05:35+00:00" }, { "name": "guzzlehttp/uri-template", - "version": "v1.0.2", + "version": "v1.0.3", "source": { "type": "git", "url": "https://github.com/guzzle/uri-template.git", - "reference": "61bf437fc2197f587f6857d3ff903a24f1731b5d" + "reference": "ecea8feef63bd4fef1f037ecb288386999ecc11c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/uri-template/zipball/61bf437fc2197f587f6857d3ff903a24f1731b5d", - "reference": "61bf437fc2197f587f6857d3ff903a24f1731b5d", + "url": "https://api.github.com/repos/guzzle/uri-template/zipball/ecea8feef63bd4fef1f037ecb288386999ecc11c", + "reference": "ecea8feef63bd4fef1f037ecb288386999ecc11c", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0", - "symfony/polyfill-php80": "^1.17" + "symfony/polyfill-php80": "^1.24" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", - "phpunit/phpunit": "^8.5.19 || ^9.5.8", + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.36 || ^9.6.15", "uri-template/tests": "1.0.0" }, "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, "autoload": { "psr-4": { "GuzzleHttp\\UriTemplate\\": "src" @@ -1768,7 +1843,7 @@ ], "support": { "issues": "https://github.com/guzzle/uri-template/issues", - "source": "https://github.com/guzzle/uri-template/tree/v1.0.2" + "source": "https://github.com/guzzle/uri-template/tree/v1.0.3" }, "funding": [ { @@ -1784,7 +1859,7 @@ "type": "tidelift" } ], - "time": "2023-08-27T10:19:19+00:00" + "time": "2023-12-03T19:50:20+00:00" }, { "name": "intervention/image", @@ -2144,16 +2219,16 @@ }, { "name": "laravel/serializable-closure", - "version": "v1.3.1", + "version": "v1.3.3", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "e5a3057a5591e1cfe8183034b0203921abe2c902" + "reference": "3dbf8a8e914634c48d389c1234552666b3d43754" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/e5a3057a5591e1cfe8183034b0203921abe2c902", - "reference": "e5a3057a5591e1cfe8183034b0203921abe2c902", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/3dbf8a8e914634c48d389c1234552666b3d43754", + "reference": "3dbf8a8e914634c48d389c1234552666b3d43754", "shasum": "" }, "require": { @@ -2200,36 +2275,36 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2023-07-14T13:56:28+00:00" + "time": "2023-11-08T14:08:06+00:00" }, { "name": "laravel/socialite", - "version": "v5.9.1", + "version": "v5.11.0", "source": { "type": "git", "url": "https://github.com/laravel/socialite.git", - "reference": "49ecc4c907ed88c1254bae991c6b2948945645c2" + "reference": "4f6a8af6f3f7c18da03d19842dd0514315501c10" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/socialite/zipball/49ecc4c907ed88c1254bae991c6b2948945645c2", - "reference": "49ecc4c907ed88c1254bae991c6b2948945645c2", + "url": "https://api.github.com/repos/laravel/socialite/zipball/4f6a8af6f3f7c18da03d19842dd0514315501c10", + "reference": "4f6a8af6f3f7c18da03d19842dd0514315501c10", "shasum": "" }, "require": { "ext-json": "*", "guzzlehttp/guzzle": "^6.0|^7.0", - "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0", - "illuminate/http": "^6.0|^7.0|^8.0|^9.0|^10.0", - "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0", + "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", + "illuminate/http": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", + "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", "league/oauth1-client": "^1.10.1", "php": "^7.2|^8.0" }, "require-dev": { "mockery/mockery": "^1.0", - "orchestra/testbench": "^4.0|^5.0|^6.0|^7.0|^8.0", + "orchestra/testbench": "^4.0|^5.0|^6.0|^7.0|^8.0|^9.0", "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^8.0|^9.3" + "phpunit/phpunit": "^8.0|^9.3|^10.4" }, "type": "library", "extra": { @@ -2270,7 +2345,7 @@ "issues": "https://github.com/laravel/socialite/issues", "source": "https://github.com/laravel/socialite" }, - "time": "2023-09-07T16:13:53+00:00" + "time": "2023-12-02T18:22:36+00:00" }, { "name": "laravel/tinker", @@ -2531,16 +2606,16 @@ }, { "name": "league/flysystem", - "version": "3.17.0", + "version": "3.23.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "bd4c9b26849d82364119c68429541f1631fba94b" + "reference": "d4ad81e2b67396e33dc9d7e54ec74ccf73151dcc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/bd4c9b26849d82364119c68429541f1631fba94b", - "reference": "bd4c9b26849d82364119c68429541f1631fba94b", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/d4ad81e2b67396e33dc9d7e54ec74ccf73151dcc", + "reference": "d4ad81e2b67396e33dc9d7e54ec74ccf73151dcc", "shasum": "" }, "require": { @@ -2568,8 +2643,8 @@ "friendsofphp/php-cs-fixer": "^3.5", "google/cloud-storage": "^1.23", "microsoft/azure-storage-blob": "^1.1", - "phpseclib/phpseclib": "^3.0.14", - "phpstan/phpstan": "^0.12.26", + "phpseclib/phpseclib": "^3.0.34", + "phpstan/phpstan": "^1.10", "phpunit/phpunit": "^9.5.11|^10.0", "sabre/dav": "^4.3.1" }, @@ -2605,7 +2680,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/3.17.0" + "source": "https://github.com/thephpleague/flysystem/tree/3.23.0" }, "funding": [ { @@ -2617,20 +2692,20 @@ "type": "github" } ], - "time": "2023-10-05T20:15:05+00:00" + "time": "2023-12-04T10:16:17+00:00" }, { "name": "league/flysystem-aws-s3-v3", - "version": "3.16.0", + "version": "3.22.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git", - "reference": "ded9ba346bb01cb9cc4cc7f2743c2c0e14d18e1c" + "reference": "9808919ee5d819730d9582d4e1673e8d195c38d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/ded9ba346bb01cb9cc4cc7f2743c2c0e14d18e1c", - "reference": "ded9ba346bb01cb9cc4cc7f2743c2c0e14d18e1c", + "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/9808919ee5d819730d9582d4e1673e8d195c38d8", + "reference": "9808919ee5d819730d9582d4e1673e8d195c38d8", "shasum": "" }, "require": { @@ -2671,7 +2746,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem-aws-s3-v3/issues", - "source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.16.0" + "source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.22.0" }, "funding": [ { @@ -2683,20 +2758,20 @@ "type": "github" } ], - "time": "2023-08-30T10:14:57+00:00" + "time": "2023-11-18T14:03:37+00:00" }, { "name": "league/flysystem-local", - "version": "3.16.0", + "version": "3.23.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-local.git", - "reference": "ec7383f25642e6fd4bb0c9554fc2311245391781" + "reference": "5cf046ba5f059460e86a997c504dd781a39a109b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/ec7383f25642e6fd4bb0c9554fc2311245391781", - "reference": "ec7383f25642e6fd4bb0c9554fc2311245391781", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/5cf046ba5f059460e86a997c504dd781a39a109b", + "reference": "5cf046ba5f059460e86a997c504dd781a39a109b", "shasum": "" }, "require": { @@ -2731,7 +2806,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem-local/issues", - "source": "https://github.com/thephpleague/flysystem-local/tree/3.16.0" + "source": "https://github.com/thephpleague/flysystem-local/tree/3.23.0" }, "funding": [ { @@ -2743,7 +2818,7 @@ "type": "github" } ], - "time": "2023-08-30T10:23:59+00:00" + "time": "2023-12-04T10:14:46+00:00" }, { "name": "league/html-to-markdown", @@ -3105,16 +3180,16 @@ }, { "name": "monolog/monolog", - "version": "2.9.1", + "version": "2.9.2", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1" + "reference": "437cb3628f4cf6042cc10ae97fc2b8472e48ca1f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f259e2b15fb95494c83f52d3caad003bbf5ffaa1", - "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/437cb3628f4cf6042cc10ae97fc2b8472e48ca1f", + "reference": "437cb3628f4cf6042cc10ae97fc2b8472e48ca1f", "shasum": "" }, "require": { @@ -3191,7 +3266,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/2.9.1" + "source": "https://github.com/Seldaek/monolog/tree/2.9.2" }, "funding": [ { @@ -3203,7 +3278,7 @@ "type": "tidelift" } ], - "time": "2023-02-06T13:44:46+00:00" + "time": "2023-10-27T15:25:26+00:00" }, { "name": "mtdowling/jmespath.php", @@ -3273,19 +3348,20 @@ }, { "name": "nesbot/carbon", - "version": "2.71.0", + "version": "2.72.1", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "98276233188583f2ff845a0f992a235472d9466a" + "reference": "2b3b3db0a2d0556a177392ff1a3bf5608fa09f78" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/98276233188583f2ff845a0f992a235472d9466a", - "reference": "98276233188583f2ff845a0f992a235472d9466a", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/2b3b3db0a2d0556a177392ff1a3bf5608fa09f78", + "reference": "2b3b3db0a2d0556a177392ff1a3bf5608fa09f78", "shasum": "" }, "require": { + "carbonphp/carbon-doctrine-types": "*", "ext-json": "*", "php": "^7.1.8 || ^8.0", "psr/clock": "^1.0", @@ -3297,8 +3373,8 @@ "psr/clock-implementation": "1.0" }, "require-dev": { - "doctrine/dbal": "^2.0 || ^3.1.4", - "doctrine/orm": "^2.7", + "doctrine/dbal": "^2.0 || ^3.1.4 || ^4.0", + "doctrine/orm": "^2.7 || ^3.0", "friendsofphp/php-cs-fixer": "^3.0", "kylekatarnls/multi-tester": "^2.0", "ondrejmirtes/better-reflection": "*", @@ -3375,7 +3451,7 @@ "type": "tidelift" } ], - "time": "2023-09-25T11:31:05+00:00" + "time": "2023-12-08T23:47:49+00:00" }, { "name": "nette/schema", @@ -3441,16 +3517,16 @@ }, { "name": "nette/utils", - "version": "v4.0.2", + "version": "v4.0.3", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "cead6637226456b35e1175cc53797dd585d85545" + "reference": "a9d127dd6a203ce6d255b2e2db49759f7506e015" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/cead6637226456b35e1175cc53797dd585d85545", - "reference": "cead6637226456b35e1175cc53797dd585d85545", + "url": "https://api.github.com/repos/nette/utils/zipball/a9d127dd6a203ce6d255b2e2db49759f7506e015", + "reference": "a9d127dd6a203ce6d255b2e2db49759f7506e015", "shasum": "" }, "require": { @@ -3521,22 +3597,22 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.0.2" + "source": "https://github.com/nette/utils/tree/v4.0.3" }, - "time": "2023-09-19T11:58:07+00:00" + "time": "2023-10-29T21:02:13+00:00" }, { "name": "nikic/php-parser", - "version": "v4.17.1", + "version": "v4.18.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" + "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", "shasum": "" }, "require": { @@ -3577,9 +3653,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" }, - "time": "2023-08-13T19:53:39+00:00" + "time": "2023-12-10T21:03:43+00:00" }, { "name": "nunomaduro/termwind", @@ -3886,16 +3962,16 @@ }, { "name": "phenx/php-svg-lib", - "version": "0.5.0", + "version": "0.5.1", "source": { "type": "git", "url": "https://github.com/dompdf/php-svg-lib.git", - "reference": "76876c6cf3080bcb6f249d7d59705108166a6685" + "reference": "8a8a1ebcf6aea861ef30197999f096f7bd4b4456" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/76876c6cf3080bcb6f249d7d59705108166a6685", - "reference": "76876c6cf3080bcb6f249d7d59705108166a6685", + "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/8a8a1ebcf6aea861ef30197999f096f7bd4b4456", + "reference": "8a8a1ebcf6aea861ef30197999f096f7bd4b4456", "shasum": "" }, "require": { @@ -3926,22 +4002,22 @@ "homepage": "https://github.com/PhenX/php-svg-lib", "support": { "issues": "https://github.com/dompdf/php-svg-lib/issues", - "source": "https://github.com/dompdf/php-svg-lib/tree/0.5.0" + "source": "https://github.com/dompdf/php-svg-lib/tree/0.5.1" }, - "time": "2022-09-06T12:16:56+00:00" + "time": "2023-12-11T20:56:08+00:00" }, { "name": "phpoption/phpoption", - "version": "1.9.1", + "version": "1.9.2", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e" + "reference": "80735db690fe4fc5c76dfa7f9b770634285fa820" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/dd3a383e599f49777d8b628dadbb90cae435b87e", - "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/80735db690fe4fc5c76dfa7f9b770634285fa820", + "reference": "80735db690fe4fc5c76dfa7f9b770634285fa820", "shasum": "" }, "require": { @@ -3949,7 +4025,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12" + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" }, "type": "library", "extra": { @@ -3991,7 +4067,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.1" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.2" }, "funding": [ { @@ -4003,20 +4079,20 @@ "type": "tidelift" } ], - "time": "2023-02-25T19:38:58+00:00" + "time": "2023-11-12T21:59:55+00:00" }, { "name": "phpseclib/phpseclib", - "version": "3.0.23", + "version": "3.0.34", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "866cc78fbd82462ffd880e3f65692afe928bed50" + "reference": "56c79f16a6ae17e42089c06a2144467acc35348a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/866cc78fbd82462ffd880e3f65692afe928bed50", - "reference": "866cc78fbd82462ffd880e3f65692afe928bed50", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/56c79f16a6ae17e42089c06a2144467acc35348a", + "reference": "56c79f16a6ae17e42089c06a2144467acc35348a", "shasum": "" }, "require": { @@ -4097,7 +4173,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.23" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.34" }, "funding": [ { @@ -4113,7 +4189,7 @@ "type": "tidelift" } ], - "time": "2023-09-18T17:22:01+00:00" + "time": "2023-11-27T11:13:31+00:00" }, { "name": "pragmarx/google2fa", @@ -4905,16 +4981,16 @@ }, { "name": "ramsey/uuid", - "version": "4.7.4", + "version": "4.7.5", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "60a4c63ab724854332900504274f6150ff26d286" + "reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/60a4c63ab724854332900504274f6150ff26d286", - "reference": "60a4c63ab724854332900504274f6150ff26d286", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e", + "reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e", "shasum": "" }, "require": { @@ -4981,7 +5057,7 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.7.4" + "source": "https://github.com/ramsey/uuid/tree/4.7.5" }, "funding": [ { @@ -4993,7 +5069,7 @@ "type": "tidelift" } ], - "time": "2023-04-15T23:01:58+00:00" + "time": "2023-11-08T05:53:05+00:00" }, { "name": "robrichards/xmlseclibs", @@ -5308,22 +5384,22 @@ }, { "name": "socialiteproviders/okta", - "version": "4.3.0", + "version": "4.4.0", "source": { "type": "git", "url": "https://github.com/SocialiteProviders/Okta.git", - "reference": "e5fb62035bfa0ccdbc8facf4cf205428fc502edb" + "reference": "5e47cd7b4c19da94ecafbd91fa430e4151c09806" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/SocialiteProviders/Okta/zipball/e5fb62035bfa0ccdbc8facf4cf205428fc502edb", - "reference": "e5fb62035bfa0ccdbc8facf4cf205428fc502edb", + "url": "https://api.github.com/repos/SocialiteProviders/Okta/zipball/5e47cd7b4c19da94ecafbd91fa430e4151c09806", + "reference": "5e47cd7b4c19da94ecafbd91fa430e4151c09806", "shasum": "" }, "require": { "ext-json": "*", - "php": "^7.4 || ^8.0", - "socialiteproviders/manager": "~4.0" + "php": "^8.0", + "socialiteproviders/manager": "^4.4" }, "type": "library", "autoload": { @@ -5354,7 +5430,7 @@ "issues": "https://github.com/socialiteproviders/providers/issues", "source": "https://github.com/socialiteproviders/providers" }, - "time": "2022-09-06T03:39:26+00:00" + "time": "2023-12-12T01:59:17+00:00" }, { "name": "socialiteproviders/twitch", @@ -7695,23 +7771,23 @@ }, { "name": "tijsverkoyen/css-to-inline-styles", - "version": "2.2.6", + "version": "v2.2.7", "source": { "type": "git", "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", - "reference": "c42125b83a4fa63b187fdf29f9c93cb7733da30c" + "reference": "83ee6f38df0a63106a9e4536e3060458b74ccedb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/c42125b83a4fa63b187fdf29f9c93cb7733da30c", - "reference": "c42125b83a4fa63b187fdf29f9c93cb7733da30c", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/83ee6f38df0a63106a9e4536e3060458b74ccedb", + "reference": "83ee6f38df0a63106a9e4536e3060458b74ccedb", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "php": "^5.5 || ^7.0 || ^8.0", - "symfony/css-selector": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0" + "symfony/css-selector": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0" }, "require-dev": { "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^7.5 || ^8.5.21 || ^9.5.10" @@ -7742,37 +7818,37 @@ "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", "support": { "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", - "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/2.2.6" + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.2.7" }, - "time": "2023-01-03T09:29:04+00:00" + "time": "2023-12-08T13:03:43+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v5.5.0", + "version": "v5.6.0", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7" + "reference": "2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7", - "reference": "1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4", + "reference": "2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4", "shasum": "" }, "require": { "ext-pcre": "*", - "graham-campbell/result-type": "^1.0.2", - "php": "^7.1.3 || ^8.0", - "phpoption/phpoption": "^1.8", - "symfony/polyfill-ctype": "^1.23", - "symfony/polyfill-mbstring": "^1.23.1", - "symfony/polyfill-php80": "^1.23.1" + "graham-campbell/result-type": "^1.1.2", + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.2", + "symfony/polyfill-ctype": "^1.24", + "symfony/polyfill-mbstring": "^1.24", + "symfony/polyfill-php80": "^1.24" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.4.1", + "bamarni/composer-bin-plugin": "^1.8.2", "ext-filter": "*", - "phpunit/phpunit": "^7.5.20 || ^8.5.30 || ^9.5.25" + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" }, "suggest": { "ext-filter": "Required to use the boolean validator." @@ -7784,7 +7860,7 @@ "forward-command": true }, "branch-alias": { - "dev-master": "5.5-dev" + "dev-master": "5.6-dev" } }, "autoload": { @@ -7816,7 +7892,7 @@ ], "support": { "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.5.0" + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.0" }, "funding": [ { @@ -7828,7 +7904,7 @@ "type": "tidelift" } ], - "time": "2022-10-16T01:01:54+00:00" + "time": "2023-11-12T22:43:29+00:00" }, { "name": "voku/portable-ascii", @@ -8104,16 +8180,16 @@ }, { "name": "filp/whoops", - "version": "2.15.3", + "version": "2.15.4", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "c83e88a30524f9360b11f585f71e6b17313b7187" + "reference": "a139776fa3f5985a50b509f2a02ff0f709d2a546" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/c83e88a30524f9360b11f585f71e6b17313b7187", - "reference": "c83e88a30524f9360b11f585f71e6b17313b7187", + "url": "https://api.github.com/repos/filp/whoops/zipball/a139776fa3f5985a50b509f2a02ff0f709d2a546", + "reference": "a139776fa3f5985a50b509f2a02ff0f709d2a546", "shasum": "" }, "require": { @@ -8163,7 +8239,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.15.3" + "source": "https://github.com/filp/whoops/tree/2.15.4" }, "funding": [ { @@ -8171,7 +8247,7 @@ "type": "github" } ], - "time": "2023-07-13T12:00:00+00:00" + "time": "2023-11-03T12:00:00+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -8293,17 +8369,118 @@ "time": "2022-12-13T00:04:12+00:00" }, { - "name": "mockery/mockery", - "version": "1.6.6", + "name": "larastan/larastan", + "version": "v2.7.0", "source": { "type": "git", - "url": "https://github.com/mockery/mockery.git", - "reference": "b8e0bb7d8c604046539c1115994632c74dcb361e" + "url": "https://github.com/larastan/larastan.git", + "reference": "a2610d46b9999cf558d9900ccb641962d1442f55" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/b8e0bb7d8c604046539c1115994632c74dcb361e", - "reference": "b8e0bb7d8c604046539c1115994632c74dcb361e", + "url": "https://api.github.com/repos/larastan/larastan/zipball/a2610d46b9999cf558d9900ccb641962d1442f55", + "reference": "a2610d46b9999cf558d9900ccb641962d1442f55", + "shasum": "" + }, + "require": { + "ext-json": "*", + "illuminate/console": "^9.52.16 || ^10.28.0", + "illuminate/container": "^9.52.16 || ^10.28.0", + "illuminate/contracts": "^9.52.16 || ^10.28.0", + "illuminate/database": "^9.52.16 || ^10.28.0", + "illuminate/http": "^9.52.16 || ^10.28.0", + "illuminate/pipeline": "^9.52.16 || ^10.28.0", + "illuminate/support": "^9.52.16 || ^10.28.0", + "php": "^8.0.2", + "phpmyadmin/sql-parser": "^5.8.2", + "phpstan/phpstan": "^1.10.41" + }, + "require-dev": { + "nikic/php-parser": "^4.17.1", + "orchestra/canvas": "^7.11.1 || ^8.11.0", + "orchestra/testbench": "^7.33.0 || ^8.13.0", + "phpunit/phpunit": "^9.6.13" + }, + "suggest": { + "orchestra/testbench": "Using Larastan for analysing a package needs Testbench" + }, + "type": "phpstan-extension", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + }, + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "autoload": { + "psr-4": { + "Larastan\\Larastan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Can Vural", + "email": "can9119@gmail.com" + }, + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Larastan - Discover bugs in your code without running it. A phpstan/phpstan wrapper for Laravel", + "keywords": [ + "PHPStan", + "code analyse", + "code analysis", + "larastan", + "laravel", + "package", + "php", + "static analysis" + ], + "support": { + "issues": "https://github.com/larastan/larastan/issues", + "source": "https://github.com/larastan/larastan/tree/v2.7.0" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/canvural", + "type": "github" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://www.patreon.com/nunomaduro", + "type": "patreon" + } + ], + "time": "2023-12-04T19:21:38+00:00" + }, + { + "name": "mockery/mockery", + "version": "1.6.7", + "source": { + "type": "git", + "url": "https://github.com/mockery/mockery.git", + "reference": "0cc058854b3195ba21dc6b1f7b1f60f4ef3a9c06" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mockery/mockery/zipball/0cc058854b3195ba21dc6b1f7b1f60f4ef3a9c06", + "reference": "0cc058854b3195ba21dc6b1f7b1f60f4ef3a9c06", "shasum": "" }, "require": { @@ -8316,9 +8493,7 @@ }, "require-dev": { "phpunit/phpunit": "^8.5 || ^9.6.10", - "psalm/plugin-phpunit": "^0.18.4", - "symplify/easy-coding-standard": "^11.5.0", - "vimeo/psalm": "^4.30" + "symplify/easy-coding-standard": "^12.0.8" }, "type": "library", "autoload": { @@ -8375,7 +8550,7 @@ "security": "https://github.com/mockery/mockery/security/advisories", "source": "https://github.com/mockery/mockery" }, - "time": "2023-08-09T00:03:52+00:00" + "time": "2023-12-10T02:24:34+00:00" }, { "name": "myclabs/deep-copy", @@ -8524,102 +8699,6 @@ ], "time": "2023-01-03T12:54:54+00:00" }, - { - "name": "nunomaduro/larastan", - "version": "v2.6.4", - "source": { - "type": "git", - "url": "https://github.com/nunomaduro/larastan.git", - "reference": "6c5e8820f3db6397546f3ce48520af9d312aed27" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/larastan/zipball/6c5e8820f3db6397546f3ce48520af9d312aed27", - "reference": "6c5e8820f3db6397546f3ce48520af9d312aed27", - "shasum": "" - }, - "require": { - "ext-json": "*", - "illuminate/console": "^9.47.0 || ^10.0.0", - "illuminate/container": "^9.47.0 || ^10.0.0", - "illuminate/contracts": "^9.47.0 || ^10.0.0", - "illuminate/database": "^9.47.0 || ^10.0.0", - "illuminate/http": "^9.47.0 || ^10.0.0", - "illuminate/pipeline": "^9.47.0 || ^10.0.0", - "illuminate/support": "^9.47.0 || ^10.0.0", - "php": "^8.0.2", - "phpmyadmin/sql-parser": "^5.6.0", - "phpstan/phpstan": "~1.10.6" - }, - "require-dev": { - "nikic/php-parser": "^4.15.2", - "orchestra/testbench": "^7.19.0 || ^8.0.0", - "phpunit/phpunit": "^9.5.27" - }, - "suggest": { - "orchestra/testbench": "Using Larastan for analysing a package needs Testbench" - }, - "type": "phpstan-extension", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - }, - "phpstan": { - "includes": [ - "extension.neon" - ] - } - }, - "autoload": { - "psr-4": { - "NunoMaduro\\Larastan\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nuno Maduro", - "email": "enunomaduro@gmail.com" - } - ], - "description": "Larastan - Discover bugs in your code without running it. A phpstan/phpstan wrapper for Laravel", - "keywords": [ - "PHPStan", - "code analyse", - "code analysis", - "larastan", - "laravel", - "package", - "php", - "static analysis" - ], - "support": { - "issues": "https://github.com/nunomaduro/larastan/issues", - "source": "https://github.com/nunomaduro/larastan/tree/v2.6.4" - }, - "funding": [ - { - "url": "https://www.paypal.com/paypalme/enunomaduro", - "type": "custom" - }, - { - "url": "https://github.com/canvural", - "type": "github" - }, - { - "url": "https://github.com/nunomaduro", - "type": "github" - }, - { - "url": "https://www.patreon.com/nunomaduro", - "type": "patreon" - } - ], - "time": "2023-07-29T12:13:13+00:00" - }, { "name": "phar-io/manifest", "version": "2.0.3", @@ -8820,16 +8899,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.39", + "version": "1.10.50", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "d9dedb0413f678b4d03cbc2279a48f91592c97c4" + "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/d9dedb0413f678b4d03cbc2279a48f91592c97c4", - "reference": "d9dedb0413f678b4d03cbc2279a48f91592c97c4", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/06a98513ac72c03e8366b5a0cb00750b487032e4", + "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4", "shasum": "" }, "require": { @@ -8878,27 +8957,27 @@ "type": "tidelift" } ], - "time": "2023-10-17T15:46:26+00:00" + "time": "2023-12-13T10:59:42+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.29", + "version": "9.2.30", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" + "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", - "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089", + "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.15", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -8948,7 +9027,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30" }, "funding": [ { @@ -8956,7 +9035,7 @@ "type": "github" } ], - "time": "2023-09-19T04:57:46+00:00" + "time": "2023-12-22T06:47:57+00:00" }, { "name": "phpunit/php-file-iterator", @@ -9201,16 +9280,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.13", + "version": "9.6.15", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be" + "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be", - "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/05017b80304e0eb3f31d90194a563fd53a6021f1", + "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1", "shasum": "" }, "require": { @@ -9284,7 +9363,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.15" }, "funding": [ { @@ -9300,7 +9379,7 @@ "type": "tidelift" } ], - "time": "2023-09-19T05:39:22+00:00" + "time": "2023-12-01T16:55:19+00:00" }, { "name": "sebastian/cli-parser", @@ -9545,20 +9624,20 @@ }, { "name": "sebastian/complexity", - "version": "2.0.2", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", "shasum": "" }, "require": { - "nikic/php-parser": "^4.7", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -9590,7 +9669,7 @@ "homepage": "https://github.com/sebastianbergmann/complexity", "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" }, "funding": [ { @@ -9598,7 +9677,7 @@ "type": "github" } ], - "time": "2020-10-26T15:52:27+00:00" + "time": "2023-12-22T06:19:30+00:00" }, { "name": "sebastian/diff", @@ -9872,20 +9951,20 @@ }, { "name": "sebastian/lines-of-code", - "version": "1.0.3", + "version": "1.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", "shasum": "" }, "require": { - "nikic/php-parser": "^4.6", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -9917,7 +9996,7 @@ "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" }, "funding": [ { @@ -9925,7 +10004,7 @@ "type": "github" } ], - "time": "2020-11-28T06:42:11+00:00" + "time": "2023-12-22T06:20:34+00:00" }, { "name": "sebastian/object-enumerator", @@ -10268,16 +10347,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.7.2", + "version": "3.8.0", "source": { "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879" + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "5805f7a4e4958dbb5e944ef1e6edae0a303765e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879", - "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5805f7a4e4958dbb5e944ef1e6edae0a303765e7", + "reference": "5805f7a4e4958dbb5e944ef1e6edae0a303765e7", "shasum": "" }, "require": { @@ -10287,7 +10366,7 @@ "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" }, "bin": [ "bin/phpcs", @@ -10306,22 +10385,45 @@ "authors": [ { "name": "Greg Sherwood", - "role": "lead" + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" } ], "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", "keywords": [ "phpcs", "standards", "static analysis" ], "support": { - "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", - "source": "https://github.com/squizlabs/PHP_CodeSniffer", - "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" }, - "time": "2023-02-22T23:07:41+00:00" + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + } + ], + "time": "2023-12-08T12:32:31+00:00" }, { "name": "ssddanbrown/asserthtml", @@ -10454,16 +10556,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.2.1", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96", + "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96", "shasum": "" }, "require": { @@ -10492,7 +10594,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + "source": "https://github.com/theseer/tokenizer/tree/1.2.2" }, "funding": [ { @@ -10500,7 +10602,7 @@ "type": "github" } ], - "time": "2021-07-28T10:34:58+00:00" + "time": "2023-11-20T00:12:19+00:00" } ], "aliases": [], diff --git a/database/factories/Entities/Models/BookFactory.php b/database/factories/Entities/Models/BookFactory.php index 3bf157786..9cb8e971c 100644 --- a/database/factories/Entities/Models/BookFactory.php +++ b/database/factories/Entities/Models/BookFactory.php @@ -21,10 +21,12 @@ class BookFactory extends Factory */ public function definition() { + $description = $this->faker->paragraph(); return [ 'name' => $this->faker->sentence(), 'slug' => Str::random(10), - 'description' => $this->faker->paragraph(), + 'description' => $description, + 'description_html' => '

' . e($description) . '

' ]; } } diff --git a/database/factories/Entities/Models/BookshelfFactory.php b/database/factories/Entities/Models/BookshelfFactory.php index 66dd1c111..edbefc3e7 100644 --- a/database/factories/Entities/Models/BookshelfFactory.php +++ b/database/factories/Entities/Models/BookshelfFactory.php @@ -21,10 +21,12 @@ class BookshelfFactory extends Factory */ public function definition() { + $description = $this->faker->paragraph(); return [ 'name' => $this->faker->sentence, 'slug' => Str::random(10), - 'description' => $this->faker->paragraph, + 'description' => $description, + 'description_html' => '

' . e($description) . '

' ]; } } diff --git a/database/factories/Entities/Models/ChapterFactory.php b/database/factories/Entities/Models/ChapterFactory.php index 36379866e..1fc49933e 100644 --- a/database/factories/Entities/Models/ChapterFactory.php +++ b/database/factories/Entities/Models/ChapterFactory.php @@ -21,10 +21,12 @@ class ChapterFactory extends Factory */ public function definition() { + $description = $this->faker->paragraph(); return [ 'name' => $this->faker->sentence(), 'slug' => Str::random(10), - 'description' => $this->faker->paragraph(), + 'description' => $description, + 'description_html' => '

' . e($description) . '

' ]; } } diff --git a/database/migrations/2023_12_02_104541_add_default_template_to_books.php b/database/migrations/2023_12_02_104541_add_default_template_to_books.php new file mode 100644 index 000000000..c23bebc2e --- /dev/null +++ b/database/migrations/2023_12_02_104541_add_default_template_to_books.php @@ -0,0 +1,32 @@ +integer('default_template_id')->nullable()->default(null); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('books', function (Blueprint $table) { + $table->dropColumn('default_template_id'); + }); + } +} diff --git a/database/migrations/2023_12_17_140913_add_description_html_to_entities.php b/database/migrations/2023_12_17_140913_add_description_html_to_entities.php new file mode 100644 index 000000000..68c52e81b --- /dev/null +++ b/database/migrations/2023_12_17_140913_add_description_html_to_entities.php @@ -0,0 +1,36 @@ + $table->text('description_html'); + + Schema::table('books', $addColumn); + Schema::table('chapters', $addColumn); + Schema::table('bookshelves', $addColumn); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + $removeColumn = fn(Blueprint $table) => $table->removeColumn('description_html'); + + Schema::table('books', $removeColumn); + Schema::table('chapters', $removeColumn); + Schema::table('bookshelves', $removeColumn); + } +}; diff --git a/database/seeders/DummyContentSeeder.php b/database/seeders/DummyContentSeeder.php index 47e8d1d7c..a4383be50 100644 --- a/database/seeders/DummyContentSeeder.php +++ b/database/seeders/DummyContentSeeder.php @@ -3,6 +3,7 @@ namespace Database\Seeders; use BookStack\Api\ApiToken; +use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Bookshelf; use BookStack\Entities\Models\Chapter; use BookStack\Entities\Models\Page; @@ -38,7 +39,7 @@ class DummyContentSeeder extends Seeder $byData = ['created_by' => $editorUser->id, 'updated_by' => $editorUser->id, 'owned_by' => $editorUser->id]; - \BookStack\Entities\Models\Book::factory()->count(5)->create($byData) + Book::factory()->count(5)->create($byData) ->each(function ($book) use ($byData) { $chapters = Chapter::factory()->count(3)->create($byData) ->each(function ($chapter) use ($book, $byData) { @@ -50,7 +51,7 @@ class DummyContentSeeder extends Seeder $book->pages()->saveMany($pages); }); - $largeBook = \BookStack\Entities\Models\Book::factory()->create(array_merge($byData, ['name' => 'Large book' . Str::random(10)])); + $largeBook = Book::factory()->create(array_merge($byData, ['name' => 'Large book' . Str::random(10)])); $pages = Page::factory()->count(200)->make($byData); $chapters = Chapter::factory()->count(50)->make($byData); $largeBook->pages()->saveMany($pages); diff --git a/database/seeders/LargeContentSeeder.php b/database/seeders/LargeContentSeeder.php index bb9b087d2..ac551dd93 100644 --- a/database/seeders/LargeContentSeeder.php +++ b/database/seeders/LargeContentSeeder.php @@ -28,12 +28,18 @@ class LargeContentSeeder extends Seeder /** @var Book $largeBook */ $largeBook = Book::factory()->create(['name' => 'Large book' . Str::random(10), 'created_by' => $editorUser->id, 'updated_by' => $editorUser->id]); - $pages = Page::factory()->count(200)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]); $chapters = Chapter::factory()->count(50)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]); - - $largeBook->pages()->saveMany($pages); $largeBook->chapters()->saveMany($chapters); - $all = array_merge([$largeBook], array_values($pages->all()), array_values($chapters->all())); + + $allPages = []; + + foreach ($chapters as $chapter) { + $pages = Page::factory()->count(100)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id, 'chapter_id' => $chapter->id]); + $largeBook->pages()->saveMany($pages); + array_push($allPages, ...$pages->all()); + } + + $all = array_merge([$largeBook], $allPages, array_values($chapters->all())); app()->make(JointPermissionBuilder::class)->rebuildForEntity($largeBook); app()->make(SearchIndex::class)->indexEntities($all); diff --git a/dev/api/requests/books-create.json b/dev/api/requests/books-create.json index 4a6626619..71dbdcc65 100644 --- a/dev/api/requests/books-create.json +++ b/dev/api/requests/books-create.json @@ -1,4 +1,9 @@ { "name": "My own book", - "description": "This is my own little book" + "description_html": "

This is my own little book created via the API

", + "default_template_id": 2427, + "tags": [ + {"name": "Category", "value": "Top Content"}, + {"name": "Rating", "value": "Highest"} + ] } \ No newline at end of file diff --git a/dev/api/requests/books-update.json b/dev/api/requests/books-update.json index fc67d5fcc..30ce7e95a 100644 --- a/dev/api/requests/books-update.json +++ b/dev/api/requests/books-update.json @@ -1,4 +1,8 @@ { "name": "My updated book", - "description": "This is my book with updated details" + "description_html": "

This is my book with updated details

", + "default_template_id": 2427, + "tags": [ + {"name": "Subject", "value": "Updates"} + ] } \ No newline at end of file diff --git a/dev/api/requests/chapters-create.json b/dev/api/requests/chapters-create.json index a7a0e072c..e9d903387 100644 --- a/dev/api/requests/chapters-create.json +++ b/dev/api/requests/chapters-create.json @@ -1,7 +1,7 @@ { "book_id": 1, "name": "My fantastic new chapter", - "description": "This is a great new chapter that I've created via the API", + "description_html": "

This is a great new chapter that I've created via the API

", "priority": 15, "tags": [ {"name": "Category", "value": "Top Content"}, diff --git a/dev/api/requests/chapters-update.json b/dev/api/requests/chapters-update.json index 18c40301b..be675772b 100644 --- a/dev/api/requests/chapters-update.json +++ b/dev/api/requests/chapters-update.json @@ -1,7 +1,7 @@ { "book_id": 1, "name": "My fantastic updated chapter", - "description": "This is an updated chapter that I've altered via the API", + "description_html": "

This is an updated chapter that I've altered via the API

", "priority": 16, "tags": [ {"name": "Category", "value": "Kinda Good Content"}, diff --git a/dev/api/requests/shelves-create.json b/dev/api/requests/shelves-create.json index 39b88af7e..8f35340f6 100644 --- a/dev/api/requests/shelves-create.json +++ b/dev/api/requests/shelves-create.json @@ -1,5 +1,8 @@ { "name": "My shelf", - "description": "This is my shelf with some books", - "books": [5,1,3] + "description_html": "

This is my shelf with some books

", + "books": [5,1,3], + "tags": [ + {"name": "Category", "value": "Learning"} + ] } \ No newline at end of file diff --git a/dev/api/requests/shelves-update.json b/dev/api/requests/shelves-update.json index df5f5735d..081c8f4c1 100644 --- a/dev/api/requests/shelves-update.json +++ b/dev/api/requests/shelves-update.json @@ -1,5 +1,5 @@ { "name": "My updated shelf", - "description": "This is my update shelf with some books", + "description_html": "

This is my updated shelf with some books

", "books": [5,1,3] } \ No newline at end of file diff --git a/dev/api/responses/books-create.json b/dev/api/responses/books-create.json index 12a3e9e9f..8895fb854 100644 --- a/dev/api/responses/books-create.json +++ b/dev/api/responses/books-create.json @@ -1,11 +1,26 @@ { - "id": 15, - "name": "My new book", - "slug": "my-new-book", - "description": "This is a book created via the API", + "id": 226, + "name": "My own book", + "slug": "my-own-book", + "description": "This is my own little book created via the API", + "created_at": "2023-12-22T14:22:28.000000Z", + "updated_at": "2023-12-22T14:22:28.000000Z", "created_by": 1, "updated_by": 1, "owned_by": 1, - "updated_at": "2020-01-12T14:05:11.000000Z", - "created_at": "2020-01-12T14:05:11.000000Z" + "default_template_id": 2427, + "description_html": "

This is my<\/strong> own little book created via the API<\/p>", + "tags": [ + { + "name": "Category", + "value": "Top Content", + "order": 0 + }, + { + "name": "Rating", + "value": "Highest", + "order": 0 + } + ], + "cover": null } \ No newline at end of file diff --git a/dev/api/responses/books-read.json b/dev/api/responses/books-read.json index 3744445d0..afeebade6 100644 --- a/dev/api/responses/books-read.json +++ b/dev/api/responses/books-read.json @@ -3,6 +3,7 @@ "name": "My own book", "slug": "my-own-book", "description": "This is my own little book", + "description_html": "

This is my own little book

", "created_at": "2020-01-12T14:09:59.000000Z", "updated_at": "2020-01-12T14:11:51.000000Z", "created_by": { @@ -20,6 +21,7 @@ "name": "Admin", "slug": "admin" }, + "default_template_id": null, "contents": [ { "id": 50, diff --git a/dev/api/responses/books-update.json b/dev/api/responses/books-update.json index 7d3d6735e..dafa2feb0 100644 --- a/dev/api/responses/books-update.json +++ b/dev/api/responses/books-update.json @@ -1,11 +1,21 @@ { - "id": 16, - "name": "My own book", - "slug": "my-own-book", - "description": "This is my own little book - updated", - "created_at": "2020-01-12T14:09:59.000000Z", - "updated_at": "2020-01-12T14:16:10.000000Z", + "id": 226, + "name": "My updated book", + "slug": "my-updated-book", + "description": "This is my book with updated details", + "created_at": "2023-12-22T14:22:28.000000Z", + "updated_at": "2023-12-22T14:24:07.000000Z", "created_by": 1, "updated_by": 1, - "owned_by": 1 + "owned_by": 1, + "default_template_id": 2427, + "description_html": "

This is my book with updated<\/em> details<\/p>", + "tags": [ + { + "name": "Subject", + "value": "Updates", + "order": 0 + } + ], + "cover": null } \ No newline at end of file diff --git a/dev/api/responses/chapters-create.json b/dev/api/responses/chapters-create.json index cf47b123d..183186b0b 100644 --- a/dev/api/responses/chapters-create.json +++ b/dev/api/responses/chapters-create.json @@ -1,15 +1,16 @@ { - "id": 74, + "id": 668, "book_id": 1, "slug": "my-fantastic-new-chapter", "name": "My fantastic new chapter", "description": "This is a great new chapter that I've created via the API", "priority": 15, + "created_at": "2023-12-22T14:26:28.000000Z", + "updated_at": "2023-12-22T14:26:28.000000Z", "created_by": 1, "updated_by": 1, "owned_by": 1, - "updated_at": "2020-05-22T22:59:55.000000Z", - "created_at": "2020-05-22T22:59:55.000000Z", + "description_html": "

This is a great new chapter<\/strong> that I've created via the API<\/p>", "tags": [ { "name": "Category", @@ -19,7 +20,7 @@ { "name": "Rating", "value": "Highest", - "order": 1 + "order": 0 } ] } \ No newline at end of file diff --git a/dev/api/responses/chapters-read.json b/dev/api/responses/chapters-read.json index 5f4de85f1..192ffce7c 100644 --- a/dev/api/responses/chapters-read.json +++ b/dev/api/responses/chapters-read.json @@ -4,6 +4,7 @@ "slug": "content-creation", "name": "Content Creation", "description": "How to create documentation on whatever subject you need to write about.", + "description_html": "

How to create documentation on whatever subject you need to write about.

", "priority": 3, "created_at": "2019-05-05T21:49:56.000000Z", "updated_at": "2019-09-28T11:24:23.000000Z", diff --git a/dev/api/responses/chapters-update.json b/dev/api/responses/chapters-update.json index a4940af2d..5ac3c64c1 100644 --- a/dev/api/responses/chapters-update.json +++ b/dev/api/responses/chapters-update.json @@ -1,16 +1,16 @@ { - "id": 75, + "id": 668, "book_id": 1, "slug": "my-fantastic-updated-chapter", "name": "My fantastic updated chapter", "description": "This is an updated chapter that I've altered via the API", "priority": 16, - "created_at": "2020-05-22T23:03:35.000000Z", - "updated_at": "2020-05-22T23:07:20.000000Z", + "created_at": "2023-12-22T14:26:28.000000Z", + "updated_at": "2023-12-22T14:27:59.000000Z", "created_by": 1, "updated_by": 1, "owned_by": 1, - "book_slug": "bookstack-demo-site", + "description_html": "

This is an updated chapter<\/strong> that I've altered via the API<\/p>", "tags": [ { "name": "Category", @@ -20,7 +20,7 @@ { "name": "Rating", "value": "Medium", - "order": 1 + "order": 0 } ] } \ No newline at end of file diff --git a/dev/api/responses/shelves-create.json b/dev/api/responses/shelves-create.json index 84caf8bdc..235557834 100644 --- a/dev/api/responses/shelves-create.json +++ b/dev/api/responses/shelves-create.json @@ -1,11 +1,20 @@ { - "id": 14, + "id": 20, "name": "My shelf", "slug": "my-shelf", "description": "This is my shelf with some books", "created_by": 1, "updated_by": 1, + "created_at": "2023-12-22T14:33:52.000000Z", + "updated_at": "2023-12-22T14:33:52.000000Z", "owned_by": 1, - "created_at": "2020-04-10T13:24:09.000000Z", - "updated_at": "2020-04-10T13:24:09.000000Z" + "description_html": "

This is my shelf<\/strong> with some books<\/p>", + "tags": [ + { + "name": "Category", + "value": "Learning", + "order": 0 + } + ], + "cover": null } \ No newline at end of file diff --git a/dev/api/responses/shelves-read.json b/dev/api/responses/shelves-read.json index 802045bd8..eca06a46b 100644 --- a/dev/api/responses/shelves-read.json +++ b/dev/api/responses/shelves-read.json @@ -3,6 +3,7 @@ "name": "My shelf", "slug": "my-shelf", "description": "This is my shelf with some books", + "description_html": "

This is my shelf with some books

", "created_by": { "id": 1, "name": "Admin", diff --git a/dev/api/responses/shelves-update.json b/dev/api/responses/shelves-update.json index e199d8d68..3b3f0538e 100644 --- a/dev/api/responses/shelves-update.json +++ b/dev/api/responses/shelves-update.json @@ -1,11 +1,20 @@ { - "id": 14, + "id": 20, "name": "My updated shelf", "slug": "my-updated-shelf", - "description": "This is my update shelf with some books", + "description": "This is my updated shelf with some books", "created_by": 1, "updated_by": 1, + "created_at": "2023-12-22T14:33:52.000000Z", + "updated_at": "2023-12-22T14:35:00.000000Z", "owned_by": 1, - "created_at": "2020-04-10T13:24:09.000000Z", - "updated_at": "2020-04-10T13:48:22.000000Z" + "description_html": "

This is my updated shelf<\/em> with some books<\/p>", + "tags": [ + { + "name": "Category", + "value": "Learning", + "order": 0 + } + ], + "cover": null } \ No newline at end of file diff --git a/dev/build/esbuild.js b/dev/build/esbuild.js index c1e246955..c47727c2c 100644 --- a/dev/build/esbuild.js +++ b/dev/build/esbuild.js @@ -25,11 +25,11 @@ esbuild.build({ entryPoints, outdir, sourcemap: true, - target: 'es2020', + target: 'es2021', mainFields: ['module', 'main'], format: 'esm', minify: isProd, - logLevel: "info", + logLevel: 'info', }).then(result => { fs.writeFileSync('esbuild-meta.json', JSON.stringify(result.metafile)); -}).catch(() => process.exit(1)); \ No newline at end of file +}).catch(() => process.exit(1)); diff --git a/lang/ar/activities.php b/lang/ar/activities.php index f4065b1f1..51f814d3d 100644 --- a/lang/ar/activities.php +++ b/lang/ar/activities.php @@ -15,7 +15,7 @@ return [ 'page_restore' => 'تمت استعادة الصفحة', 'page_restore_notification' => 'تمت استعادة الصفحة بنجاح', 'page_move' => 'تم نقل الصفحة', - 'page_move_notification' => 'Page successfully moved', + 'page_move_notification' => 'تم نقل الصفحة بنجاح', // Chapters 'chapter_create' => 'تم إنشاء فصل', @@ -25,7 +25,7 @@ return [ 'chapter_delete' => 'تم حذف الفصل', 'chapter_delete_notification' => 'تم حذف الفصل بنجاح', 'chapter_move' => 'تم نقل الفصل', - 'chapter_move_notification' => 'Chapter successfully moved', + 'chapter_move_notification' => 'تم نقل الفصل بنجاح', // Books 'book_create' => 'تم إنشاء كتاب', @@ -50,31 +50,31 @@ return [ 'bookshelf_delete_notification' => 'تم حذف الرف بنجاح', // Revisions - 'revision_restore' => 'restored revision', - 'revision_delete' => 'deleted revision', - 'revision_delete_notification' => 'Revision successfully deleted', + 'revision_restore' => 'استعادة مراجعة', + 'revision_delete' => 'مراجعة محذوفة', + 'revision_delete_notification' => 'تم حذف المراجعة بنجاح', // Favourites 'favourite_add_notification' => 'تم إضافة ":name" إلى المفضلة لديك', 'favourite_remove_notification' => 'تم إزالة ":name" من المفضلة لديك', // Watching - 'watch_update_level_notification' => 'Watch preferences successfully updated', + 'watch_update_level_notification' => 'تم تحديث الإعدادات المشاهدة بنجاح', // Auth - 'auth_login' => 'logged in', - 'auth_register' => 'registered as new user', - 'auth_password_reset_request' => 'requested user password reset', - 'auth_password_reset_update' => 'reset user password', - 'mfa_setup_method' => 'configured MFA method', + 'auth_login' => 'تم تسجيل الدخول', + 'auth_register' => 'سجل كمستخدم جديد', + 'auth_password_reset_request' => 'طلب رابط جديد لإعادة تعيين كلمة المرور', + 'auth_password_reset_update' => 'إعادة تعيين كلمة مرور المستخدم', + 'mfa_setup_method' => 'طريقة MFA المكونة', 'mfa_setup_method_notification' => 'تم تكوين طريقة متعددة العوامل بنجاح', - 'mfa_remove_method' => 'removed MFA method', + 'mfa_remove_method' => 'إزالة طريقة MFA', 'mfa_remove_method_notification' => 'تمت إزالة طريقة متعددة العوامل بنجاح', // Settings - 'settings_update' => 'updated settings', - 'settings_update_notification' => 'Settings successfully updated', - 'maintenance_action_run' => 'ran maintenance action', + 'settings_update' => 'تحديث الإعدادات', + 'settings_update_notification' => 'تم تحديث الإعدادات', + 'maintenance_action_run' => 'إجراء الصيانة', // Webhooks 'webhook_create' => 'تم إنشاء webhook', @@ -85,39 +85,39 @@ return [ 'webhook_delete_notification' => 'تم حذف Webhook بنجاح', // Users - 'user_create' => 'created user', - 'user_create_notification' => 'User successfully created', - 'user_update' => 'updated user', + 'user_create' => 'إنشاء مستخدم', + 'user_create_notification' => 'تم انشاء الحساب', + 'user_update' => 'المستخدم المحدث', 'user_update_notification' => 'تم تحديث المستخدم بنجاح', - 'user_delete' => 'deleted user', + 'user_delete' => 'المستخدم المحذوف', 'user_delete_notification' => 'تم إزالة المستخدم بنجاح', // API Tokens - 'api_token_create' => 'created api token', - 'api_token_create_notification' => 'API token successfully created', - 'api_token_update' => 'updated api token', - 'api_token_update_notification' => 'API token successfully updated', - 'api_token_delete' => 'deleted api token', - 'api_token_delete_notification' => 'API token successfully deleted', + 'api_token_create' => 'تم إنشاء رمز api', + 'api_token_create_notification' => 'تم إنشاء رمز الـ API بنجاح', + 'api_token_update' => 'تم تحديث رمز api', + 'api_token_update_notification' => 'تم تحديث رمز الـ API بنجاح', + 'api_token_delete' => 'رمز api المحذوف', + 'api_token_delete_notification' => 'تم حذف رمز الـ API بنجاح', // Roles - 'role_create' => 'created role', - 'role_create_notification' => 'Role successfully created', - 'role_update' => 'updated role', - 'role_update_notification' => 'Role successfully updated', - 'role_delete' => 'deleted role', - 'role_delete_notification' => 'Role successfully deleted', + 'role_create' => 'إنشاء صَلاحِيَة', + 'role_create_notification' => 'تم إنشاء الدور بنجاح', + 'role_update' => 'حدّث الدور', + 'role_update_notification' => 'تم تحديث الدور بنجاح', + 'role_delete' => 'حذف الدور', + 'role_delete_notification' => 'تم حذف الدور بنجاح', // Recycle Bin - 'recycle_bin_empty' => 'emptied recycle bin', - 'recycle_bin_restore' => 'restored from recycle bin', - 'recycle_bin_destroy' => 'removed from recycle bin', + 'recycle_bin_empty' => 'سلة إعادة التدوير المفرغة', + 'recycle_bin_restore' => 'استعادة من سلة المحذوفات', + 'recycle_bin_destroy' => 'إزالة من سلة المحذوفات', // Comments 'commented_on' => 'تم التعليق', - 'comment_create' => 'added comment', - 'comment_update' => 'updated comment', - 'comment_delete' => 'deleted comment', + 'comment_create' => 'تعليق مضاف', + 'comment_update' => 'تعليق محدث', + 'comment_delete' => 'تعليق محذوف', // Other 'permissions_update' => 'تحديث الأذونات', diff --git a/lang/ar/auth.php b/lang/ar/auth.php index 55c9aae41..7d64babc4 100644 --- a/lang/ar/auth.php +++ b/lang/ar/auth.php @@ -39,8 +39,8 @@ return [ 'register_success' => 'شكراً لإنشاء حسابكم! تم تسجيلكم ودخولكم للحساب الخاص بكم.', // Login auto-initiation - 'auto_init_starting' => 'Attempting Login', - 'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.', + 'auto_init_starting' => 'محاولة تسجيل الدخول', + 'auto_init_starting_desc' => 'نحن نتصل بنظام المصادقة الخاص بك لبدء عملية تسجيل الدخول. إذا لم يحدث أي تقدم بعد 5 ثوان يمكنك محاولة النقر على الرابط أدناه.', 'auto_init_start_link' => 'المتابعة مع المصادقة', // Password Reset @@ -59,10 +59,10 @@ return [ 'email_confirm_text' => 'الرجاء تأكيد بريدكم الإلكتروني بالضغط على الزر أدناه:', 'email_confirm_action' => 'تأكيد البريد الإلكتروني', 'email_confirm_send_error' => 'تأكيد البريد الإلكتروني مطلوب ولكن النظام لم يستطع إرسال الرسالة. تواصل مع مشرف النظام للتأكد من إعدادات البريد.', - 'email_confirm_success' => 'Your email has been confirmed! You should now be able to login using this email address.', + 'email_confirm_success' => 'تم تأكيد بريدك الإلكتروني! يمكنك الآن تسجيل الدخول باستخدام عنوان البريد الإلكتروني هذا.', 'email_confirm_resent' => 'تمت إعادة إرسال رسالة التأكيد. الرجاء مراجعة صندوق الوارد', - 'email_confirm_thanks' => 'Thanks for confirming!', - 'email_confirm_thanks_desc' => 'Please wait a moment while your confirmation is handled. If you are not redirected after 3 seconds press the "Continue" link below to proceed.', + 'email_confirm_thanks' => 'شكرا للتأكيد!', + 'email_confirm_thanks_desc' => 'الرجاء الانتظار لحظة بينما يتم التعامل مع التأكيد الخاص بك. إذا لم يتم إعادة توجيهك بعد 3 ثوان اضغط على الرابط "المتابعة" أدناه للمتابعة.', 'email_not_confirmed' => 'لم يتم تأكيد البريد الإلكتروني', 'email_not_confirmed_text' => 'لم يتم بعد تأكيد عنوان البريد الإلكتروني.', @@ -78,14 +78,14 @@ return [ 'user_invite_page_welcome' => 'مرحبا بكم في :appName!', 'user_invite_page_text' => 'لإكمال حسابك والحصول على حق الوصول تحتاج إلى تعيين كلمة مرور سيتم استخدامها لتسجيل الدخول إلى :appName في الزيارات المستقبلية.', 'user_invite_page_confirm_button' => 'تأكيد كلمة المرور', - 'user_invite_success_login' => 'Password set, you should now be able to login using your set password to access :appName!', + 'user_invite_success_login' => 'تم تأكيد كلمة المرور. يمكنك الآن تسجيل الدخول باستخدام كلمة المرور المحددة للوصول إلى :appName!', // Multi-factor Authentication - 'mfa_setup' => 'Setup Multi-Factor Authentication', - 'mfa_setup_desc' => 'Setup multi-factor authentication as an extra layer of security for your user account.', - 'mfa_setup_configured' => 'Already configured', - 'mfa_setup_reconfigure' => 'Reconfigure', - 'mfa_setup_remove_confirmation' => 'Are you sure you want to remove this multi-factor authentication method?', + 'mfa_setup' => 'إعداد المصادقة متعددة العوامل', + 'mfa_setup_desc' => 'إعداد المصادقة متعددة العوامل كطبقة إضافية من الأمان لحساب المستخدم الخاص بك.', + 'mfa_setup_configured' => 'تم إعداده مسبقاً', + 'mfa_setup_reconfigure' => 'إعادة التكوين', + 'mfa_setup_remove_confirmation' => 'هل أنت متأكد من أنك تريد إزالة طريقة المصادقة متعددة العناصر هذه؟', 'mfa_setup_action' => 'إعداد (تنصيب)', 'mfa_backup_codes_usage_limit_warning' => 'You have less than 5 backup codes remaining, Please generate and store a new set before you run out of codes to prevent being locked out of your account.', 'mfa_option_totp_title' => 'تطبيق الجوال', diff --git a/lang/ar/common.php b/lang/ar/common.php index 75bdfdec2..5a391cd6d 100644 --- a/lang/ar/common.php +++ b/lang/ar/common.php @@ -6,7 +6,7 @@ return [ // Buttons 'cancel' => 'إلغاء', - 'close' => 'Close', + 'close' => 'إغلاق', 'confirm' => 'تأكيد', 'back' => 'رجوع', 'save' => 'حفظ', @@ -26,7 +26,7 @@ return [ 'actions' => 'إجراءات', 'view' => 'عرض', 'view_all' => 'عرض الكل', - 'new' => 'New', + 'new' => 'جديد', 'create' => 'إنشاء', 'update' => 'تحديث', 'edit' => 'تعديل', @@ -41,18 +41,18 @@ return [ 'reset' => 'إعادة تعيين', 'remove' => 'إزالة', 'add' => 'إضافة', - 'configure' => 'Configure', - 'manage' => 'Manage', + 'configure' => 'ضبط', + 'manage' => 'إدارة', 'fullscreen' => 'شاشة كاملة', - 'favourite' => 'Favourite', - 'unfavourite' => 'Unfavourite', - 'next' => 'Next', - 'previous' => 'Previous', - 'filter_active' => 'Active Filter:', - 'filter_clear' => 'Clear Filter', - 'download' => 'Download', - 'open_in_tab' => 'Open in Tab', - 'open' => 'Open', + 'favourite' => 'أضف إلى المفضلة', + 'unfavourite' => 'إزالة من المفضلة', + 'next' => 'التالي', + 'previous' => 'السابق', + 'filter_active' => 'الفلاتر المفعلة:', + 'filter_clear' => 'مسح الفلاتر', + 'download' => 'تنزيل', + 'open_in_tab' => 'فتح في علامة تبويب', + 'open' => 'فتح', // Sort Options 'sort_options' => 'خيارات الفرز', @@ -69,7 +69,7 @@ return [ 'no_activity' => 'لا يوجد نشاط لعرضه', 'no_items' => 'لا توجد عناصر متوفرة', 'back_to_top' => 'العودة إلى الأعلى', - 'skip_to_main_content' => 'Skip to main content', + 'skip_to_main_content' => 'تخطى إلى المحتوى الرئيسي', 'toggle_details' => 'عرض / إخفاء التفاصيل', 'toggle_thumbnails' => 'عرض / إخفاء الصور المصغرة', 'details' => 'التفاصيل', @@ -77,21 +77,21 @@ return [ 'list_view' => 'عرض منسدل', 'default' => 'افتراضي', 'breadcrumb' => 'شريط التنقل', - 'status' => 'Status', - 'status_active' => 'Active', - 'status_inactive' => 'Inactive', - 'never' => 'Never', - 'none' => 'None', + 'status' => 'الحالة', + 'status_active' => 'نشط', + 'status_inactive' => 'غير نشط', + 'never' => 'مطلقاً', + 'none' => 'لا شَيْء', // Header - 'homepage' => 'Homepage', + 'homepage' => 'الصفحة الرئيسية', 'header_menu_expand' => 'عرض القائمة', 'profile_menu' => 'قائمة ملف التعريف', 'view_profile' => 'عرض الملف الشخصي', 'edit_profile' => 'تعديل الملف الشخصي', 'dark_mode' => 'الوضع المظلم', 'light_mode' => 'الوضع المضيء', - 'global_search' => 'Global Search', + 'global_search' => 'البحث العام', // Layout tabs 'tab_info' => 'معلومات', diff --git a/lang/ar/entities.php b/lang/ar/entities.php index 1c9c15bd9..30ad78454 100644 --- a/lang/ar/entities.php +++ b/lang/ar/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'مُحدث :timeLength', 'meta_updated_name' => 'مُحدث :timeLength بواسطة :user', 'meta_owned_name' => 'Owned by :user', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'اختيار الكيان', 'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item', 'images' => 'صور', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'تعديل كتاب :bookName', 'books_form_book_name' => 'اسم الكتاب', 'books_save' => 'حفظ الكتاب', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'أذونات الكتاب', 'books_permissions_updated' => 'تم تحديث أذونات الكتاب', 'books_empty_contents' => 'لم يتم إنشاء أي صفحات أو فصول لهذا الكتاب.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'حذف المسودة', 'pages_delete_success' => 'تم حذف الصفحة', 'pages_delete_draft_success' => 'تم حذف المسودة', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'تأكيد حذف الصفحة؟', 'pages_delete_draft_confirm' => 'تأكيد حذف المسودة؟', 'pages_editing_named' => ':pageName قيد التعديل', @@ -405,7 +409,7 @@ return [ // References 'references' => 'References', 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/ar/errors.php b/lang/ar/errors.php index ffd7b2e11..70bcf2137 100644 --- a/lang/ar/errors.php +++ b/lang/ar/errors.php @@ -19,14 +19,13 @@ return [ 'ldap_extension_not_installed' => 'لم يتم تثبيت إضافة LDAP PHP', 'ldap_cannot_connect' => 'لا يمكن الاتصال بخادم ldap, فشل الاتصال المبدئي', 'saml_already_logged_in' => 'تم تسجيل الدخول بالفعل', - 'saml_user_not_registered' => 'المستخدم :name غير مسجل ويتم تعطيل التسجيل التلقائي', 'saml_no_email_address' => 'تعذر العثور على عنوان بريد إلكتروني، لهذا المستخدم، في البيانات المقدمة من نظام المصادقة الخارجي', 'saml_invalid_response_id' => 'لم يتم التعرف على الطلب من نظام التوثيق الخارجي من خلال عملية تبدأ بهذا التطبيق. العودة بعد تسجيل الدخول يمكن أن يسبب هذه المشكلة.', 'saml_fail_authed' => 'تسجيل الدخول باستخدام :system فشل، النظام لم يوفر التفويض الناجح', - 'oidc_already_logged_in' => 'Already logged in', - 'oidc_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', - 'oidc_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', - 'oidc_fail_authed' => 'Login using :system failed, system did not provide successful authorization', + 'oidc_already_logged_in' => 'تم تسجيل الدخول مسبقاً', + 'oidc_user_not_registered' => 'المستخدم :name غير مسجل و لايمكن التسجيل بشكل اتوماتيكي', + 'oidc_no_email_address' => 'تعذر العثور على عنوان بريد إلكتروني، لهذا المستخدم، في البيانات المقدمة من نظام المصادقة الخارجي', + 'oidc_fail_authed' => 'تسجيل الدخول باستخدام :system فشل، النظام لم يوفر التفويض الناجح', 'social_no_action_defined' => 'لم يتم تعريف أي إجراء', 'social_login_bad_response' => "حصل خطأ خلال تسجيل الدخول باستخدام :socialAccount \n:error", 'social_account_in_use' => 'حساب :socialAccount قيد الاستخدام حالياً, الرجاء محاولة الدخول باستخدام خيار :socialAccount.', @@ -44,30 +43,30 @@ return [ 'cannot_get_image_from_url' => 'لا يمكن الحصول على الصورة من :url', 'cannot_create_thumbs' => 'لا يمكن للخادم إنشاء صور مصغرة. الرجاء التأكد من تثبيت إضافة GD PHP.', 'server_upload_limit' => 'الخادم لا يسمح برفع ملفات بهذا الحجم. الرجاء محاولة الرفع بحجم أصغر.', - 'server_post_limit' => 'The server cannot receive the provided amount of data. Try again with less data or a smaller file.', + 'server_post_limit' => 'لا يمكن للخادم تلقي كمية البيانات المتاحة. حاول مرة أخرى باستخدام بيانات أقل أو ملف أصغر.', 'uploaded' => 'الخادم لا يسمح برفع ملفات بهذا الحجم. الرجاء محاولة الرفع بحجم أصغر.', // Drawing & Images 'image_upload_error' => 'حدث خطأ خلال رفع الصورة', 'image_upload_type_error' => 'صيغة الصورة المرفوعة غير صالحة', - 'image_upload_replace_type' => 'Image file replacements must be of the same type', - 'image_upload_memory_limit' => 'Failed to handle image upload and/or create thumbnails due to system resource limits.', - 'image_thumbnail_memory_limit' => 'Failed to create image size variations due to system resource limits.', - 'image_gallery_thumbnail_memory_limit' => 'Failed to create gallery thumbnails due to system resource limits.', - 'drawing_data_not_found' => 'Drawing data could not be loaded. The drawing file might no longer exist or you may not have permission to access it.', + 'image_upload_replace_type' => 'يجب أن يكون استبدال ملف الصورة من نفس النوع', + 'image_upload_memory_limit' => 'فشل في التعامل مع تحميل الصورة و/أو إنشاء الصور المصغرة بسبب حدود موارد النظام.', + 'image_thumbnail_memory_limit' => 'فشل في إنشاء تغيرات حجم الصورة بسبب حدود موارد النظام.', + 'image_gallery_thumbnail_memory_limit' => 'فشل في إنشاء الصور المصغرة للمعرض بسبب حدود موارد النظام.', + 'drawing_data_not_found' => 'تعذر تحميل بيانات الرسم. قد لا يكون ملف الرسم موجودا أو قد لا يكون لديك إذن للوصول إليه.', // Attachments 'attachment_not_found' => 'لم يتم العثور على المرفق', - 'attachment_upload_error' => 'An error occurred uploading the attachment file', + 'attachment_upload_error' => 'حدث خطأ أثناء تحميل الملف المرفق', // Pages 'page_draft_autosave_fail' => 'فشل حفظ المسودة. الرجاء التأكد من وجود اتصال بالإنترنت قبل حفظ الصفحة', - 'page_draft_delete_fail' => 'Failed to delete page draft and fetch current page saved content', + 'page_draft_delete_fail' => 'فشل في حذف مسودة الصفحة وجلب محتوى الصفحة الحالية المحفوظة', 'page_custom_home_deletion' => 'لا يمكن حذف الصفحة إذا كانت محددة كصفحة رئيسية', // Entities 'entity_not_found' => 'الكيان غير موجود', - 'bookshelf_not_found' => 'Shelf not found', + 'bookshelf_not_found' => 'رف الكتب غير موجود', 'book_not_found' => 'لم يتم العثور على الكتاب', 'page_not_found' => 'لم يتم العثور على الصفحة', 'chapter_not_found' => 'لم يتم العثور على الفصل', @@ -96,9 +95,9 @@ return [ '404_page_not_found' => 'لم يتم العثور على الصفحة', 'sorry_page_not_found' => 'عفواً, لا يمكن العثور على الصفحة التي تبحث عنها.', 'sorry_page_not_found_permission_warning' => 'إذا كنت تتوقع أن تكون هذه الصفحة موجودة، قد لا يكون لديك تصريح بمشاهدتها.', - 'image_not_found' => 'Image Not Found', - 'image_not_found_subtitle' => 'Sorry, The image file you were looking for could not be found.', - 'image_not_found_details' => 'If you expected this image to exist it might have been deleted.', + 'image_not_found' => 'لم يتم العثور على الصورة', + 'image_not_found_subtitle' => 'عذراً، لم يتم العثور على ملف الصورة الذي كنت تبحث عنه.', + 'image_not_found_details' => 'إذا كنت تتوقع وجود هذه الصورة ربما تم حذفها.', 'return_home' => 'العودة للصفحة الرئيسية', 'error_occurred' => 'حدث خطأ', 'app_down' => ':appName لا يعمل حالياً', @@ -116,5 +115,5 @@ return [ 'maintenance_test_email_failure' => 'حدث خطأ عند إرسال بريد إلكتروني تجريبي:', // HTTP errors - 'http_ssr_url_no_match' => 'The URL does not match the configured allowed SSR hosts', + 'http_ssr_url_no_match' => 'الرابط لا يتطابق مع الاعدادات المسموح بها لاستضافة SSR', ]; diff --git a/lang/ar/notifications.php b/lang/ar/notifications.php index 5539ae9a9..1afd23f1d 100644 --- a/lang/ar/notifications.php +++ b/lang/ar/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/ar/settings.php b/lang/ar/settings.php index 309c9a06c..ca0f2fdb3 100644 --- a/lang/ar/settings.php +++ b/lang/ar/settings.php @@ -9,8 +9,8 @@ return [ // Common Messages 'settings' => 'الإعدادات', 'settings_save' => 'حفظ الإعدادات', - 'system_version' => 'System Version', - 'categories' => 'Categories', + 'system_version' => 'إصدار النظام', + 'categories' => 'التصنيفات', // App Settings 'app_customization' => 'تخصيص', @@ -26,23 +26,23 @@ return [ 'app_secure_images' => 'تفعيل حماية أكبر لرفع الصور؟', 'app_secure_images_toggle' => 'لمزيد من الحماية', 'app_secure_images_desc' => 'لتحسين أداء النظام, ستكون جميع الصور متاحة للعامة. هذا الخيار يضيف سلسلة من الحروف والأرقام العشوائية صعبة التخمين إلى رابط الصورة. الرجاء التأكد من تعطيل فهرسة المسارات لمنع الوصول السهل.', - 'app_default_editor' => 'Default Page Editor', - 'app_default_editor_desc' => 'Select which editor will be used by default when editing new pages. This can be overridden at a page level where permissions allow.', + 'app_default_editor' => 'محرر الصفحة الافتراضي', + 'app_default_editor_desc' => 'حدد أي محرر سيتم استخدامه بشكل افتراضي عند تحرير صفحات جديدة. يمكن تجاوز هذا على مستوى الصفحة حيث تسمح الأذونات.', 'app_custom_html' => 'Custom HTML head content', 'app_custom_html_desc' => 'سيتم إدراج أي محتوى مضاف هنا في الجزء السفلي من قسم من كل صفحة. هذا أمر مفيد لتجاوز الأنماط أو إضافة رمز التحليل.', 'app_custom_html_disabled_notice' => 'تم تعطيل محتوى HTML الرئيسي المخصص في صفحة الإعدادات هذه لضمان عكس أي تغييرات متتالية.', 'app_logo' => 'شعار التطبيق', - '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_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_logo_desc' => 'يستخدم هذا في شريط رأس التطبيق، ضمن مجالات أخرى. يجب أن تكون هذه الصورة 86 بكسل في الطول. سيتم تقليص الصور الكبيرة.', + 'app_icon' => 'أيقونة التطبيق', + 'app_icon_desc' => 'يستخدم هذا الرمز لعلامات تبويب المتصفح والرموز المختصرة. يجب أن تكون هذه صورة PNG مربعة 256px.', 'app_homepage' => 'الصفحة الرئيسية للتطبيق', 'app_homepage_desc' => 'الرجاء اختيار صفحة لتصبح الصفحة الرئيسية بدل من الافتراضية. سيتم تجاهل جميع الأذونات الخاصة بالصفحة المختارة.', 'app_homepage_select' => 'اختر صفحة', - 'app_footer_links' => 'Footer Links', - 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', - 'app_footer_links_label' => 'Link Label', - 'app_footer_links_url' => 'Link URL', - 'app_footer_links_add' => 'Add Footer Link', + 'app_footer_links' => 'روابط تذييل الصفحة', + 'app_footer_links_desc' => 'إضافة روابط لعرضها داخل تذييل الموقع. سيتم عرضها في أسفل معظم الصفحات، بما في ذلك تلك التي لا تتطلب تسجيل الدخول. يمكنك استخدام تسمية "trans::لاستخدام الترجمات المحددة في النظام. على سبيل المثال: باستخدام "trans::common.privacy_policy" سيوفر النص المترجم "Privacy Policy" و "trans::common.terms_of_service" سيوفر النص المترجم "شروط الخدمة".', + 'app_footer_links_label' => 'تسمية الرابط', + 'app_footer_links_url' => 'عنوان الرابط', + 'app_footer_links_add' => 'إضافة رابط تذييل الصفحة', 'app_disable_comments' => 'تعطيل التعليقات', 'app_disable_comments_toggle' => 'تعطيل التعليقات', 'app_disable_comments_desc' => 'تعطيل التعليقات على جميع الصفحات داخل التطبيق. التعليقات الموجودة من الأصل لن تكون ظاهرة.', @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/ar/validation.php b/lang/ar/validation.php index 94112789d..a9793c548 100644 --- a/lang/ar/validation.php +++ b/lang/ar/validation.php @@ -15,7 +15,7 @@ return [ 'alpha_dash' => 'يجب أن يقتصر :attribute على حروف أو أرقام أو شرطات فقط.', 'alpha_num' => 'يجب أن يقتصر :attribute على الحروف والأرقام فقط.', 'array' => 'يجب أن تكون السمة مصفوفة.', - 'backup_codes' => 'The provided code is not valid or has already been used.', + 'backup_codes' => 'الرمز المقدم غير صالح أو تم استخدامه بالفعل.', 'before' => 'يجب أن يكون التاريخ :attribute قبل :date.', 'between' => [ 'numeric' => 'يجب أن يكون :attribute بين :min و :max.', @@ -32,7 +32,7 @@ return [ 'digits_between' => 'يجب أن يكون :attribute بعدد خانات بين :min و :max.', 'email' => 'يجب أن يكون :attribute عنوان بريد إلكتروني صالح.', 'ends_with' => 'يجب أن تنتهي السمة بأحد القيم التالية', - 'file' => 'The :attribute must be provided as a valid file.', + 'file' => 'يجب توفير :attribute كملف صالح.', 'filled' => 'حقل :attribute مطلوب.', 'gt' => [ 'numeric' => 'يجب أن تكون السمة أكبر من: القيمة.', @@ -100,7 +100,7 @@ return [ ], 'string' => 'يجب أن تكون السمة: سلسلة.', 'timezone' => 'يجب أن تكون :attribute منطقة صالحة.', - 'totp' => 'The provided code is not valid or has expired.', + 'totp' => 'الرمز المقدم غير صالح أو انتهت صلاحيته.', 'unique' => 'تم حجز :attribute من قبل.', 'url' => 'صيغة :attribute غير صالحة.', 'uploaded' => 'تعذر تحميل الملف. قد لا يقبل الخادم ملفات بهذا الحجم.', diff --git a/lang/bg/entities.php b/lang/bg/entities.php index e4ed83ef9..fb57bf1bc 100644 --- a/lang/bg/entities.php +++ b/lang/bg/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Актуализирано :timeLength', 'meta_updated_name' => 'Актуализирано преди :timeLength от :user', 'meta_owned_name' => 'Притежавано от :user', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Избор на обект', 'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item', 'images' => 'Изображения', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Редактирай книга :bookName', 'books_form_book_name' => 'Име на книга', 'books_save' => 'Запази книга', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Настройки за достъп до книгата', 'books_permissions_updated' => 'Настройките за достъп до книгата бяха обновени', 'books_empty_contents' => 'Няма създадени страници или глави към тази книга.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Изтрий чернова', 'pages_delete_success' => 'Страницата е изтрита', 'pages_delete_draft_success' => 'Черновата на страницата бе изтрита', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Сигурни ли сте, че искате да изтриете тази страница?', 'pages_delete_draft_confirm' => 'Сигурни ли сте, че искате да изтриете тази чернова?', 'pages_editing_named' => 'Редактиране на страница :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'References', 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/bg/errors.php b/lang/bg/errors.php index 91c7b6f60..fbc042a05 100644 --- a/lang/bg/errors.php +++ b/lang/bg/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'LDAP PHP не беше инсталирана', 'ldap_cannot_connect' => 'Не може да се свържете с Ldap сървъра, първоначалната връзка се разпадна', 'saml_already_logged_in' => 'Вече сте влезли', - 'saml_user_not_registered' => 'Потребителят :name не е регистриран и автоматичната регистрация не е достъпна', 'saml_no_email_address' => 'Не успяхме да намерим емейл адрес, за този потребител, от информацията предоставена от външната система', 'saml_invalid_response_id' => 'Заявката от външната система не е разпознат от процеса започнат от това приложение. Връщането назад след влизане може да породи този проблем.', 'saml_fail_authed' => 'Влизането чрез :system не беше успешно, системата не успя да удостовери потребителя', diff --git a/lang/bg/notifications.php b/lang/bg/notifications.php index 5539ae9a9..1afd23f1d 100644 --- a/lang/bg/notifications.php +++ b/lang/bg/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/bg/settings.php b/lang/bg/settings.php index df500db44..f4654135b 100644 --- a/lang/bg/settings.php +++ b/lang/bg/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/bs/entities.php b/lang/bs/entities.php index 5955b47e7..a8a49fe1c 100644 --- a/lang/bs/entities.php +++ b/lang/bs/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Ažurirana :timeLength', 'meta_updated_name' => 'Ažurirana :timeLength od :user', 'meta_owned_name' => 'Vlasnik je :user', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Odaberi entitet', 'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item', 'images' => 'Slike', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Uredi knjigu :bookName', 'books_form_book_name' => 'Naziv knjige', 'books_save' => 'Spremi knjigu', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Dozvole knjige', 'books_permissions_updated' => 'Dozvole knjige su ažurirane', 'books_empty_contents' => 'Za ovu knjigu nisu napravljene ni stranice ni poglavlja.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Delete Draft Page', 'pages_delete_success' => 'Page deleted', 'pages_delete_draft_success' => 'Draft page deleted', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Are you sure you want to delete this page?', 'pages_delete_draft_confirm' => 'Are you sure you want to delete this draft page?', 'pages_editing_named' => 'Editing Page :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'References', 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/bs/errors.php b/lang/bs/errors.php index 8af5a6c78..4f3d61066 100644 --- a/lang/bs/errors.php +++ b/lang/bs/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'LDAP PHP ekstenzija nije instalirana', 'ldap_cannot_connect' => 'Nije se moguće povezati sa ldap serverom, incijalna konekcija nije uspjela', 'saml_already_logged_in' => 'Već prijavljeni', - 'saml_user_not_registered' => 'Korisnik :user nije registrovan i automatska registracija je onemogućena', 'saml_no_email_address' => 'E-mail adresa za ovog korisnika nije nađena u podacima dobijenim od eksternog autentifikacijskog sistema', 'saml_invalid_response_id' => 'Proces, koji je pokrenula ova aplikacija, nije prepoznao zahtjev od eksternog sistema za autentifikaciju. Navigacija nazad nakon prijave može uzrokovati ovaj problem.', 'saml_fail_authed' => 'Prijava koristeći :system nije uspjela, sistem nije obezbijedio uspješnu autorizaciju', diff --git a/lang/bs/notifications.php b/lang/bs/notifications.php index 5539ae9a9..1afd23f1d 100644 --- a/lang/bs/notifications.php +++ b/lang/bs/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/bs/settings.php b/lang/bs/settings.php index c5ca662c3..03e9bf462 100644 --- a/lang/bs/settings.php +++ b/lang/bs/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/ca/activities.php b/lang/ca/activities.php index 03174ff85..fb9071174 100644 --- a/lang/ca/activities.php +++ b/lang/ca/activities.php @@ -11,11 +11,11 @@ return [ 'page_update' => 'ha actualitzat la pàgina', 'page_update_notification' => 'Pàgina actualitzada correctament', 'page_delete' => 'ha suprimit una pàgina', - 'page_delete_notification' => 'Imatge esborrada correctament', + 'page_delete_notification' => 'Pàgina suprimida correctament', 'page_restore' => 'ha restaurat la pàgina', 'page_restore_notification' => 'Pàgina restaurada correctament', 'page_move' => 'ha mogut la pàgina', - 'page_move_notification' => 'Page successfully moved', + 'page_move_notification' => 'Pàgina moguda correctament', // Chapters 'chapter_create' => 'ha creat el capítol', @@ -23,101 +23,101 @@ return [ 'chapter_update' => 'ha actualitzat el capítol', 'chapter_update_notification' => 'Capítol actualitzat correctament', 'chapter_delete' => 'ha suprimit un capítol', - 'chapter_delete_notification' => 'Capítol esborrat correctament', + 'chapter_delete_notification' => 'Capítol suprimit correctament', 'chapter_move' => 'ha mogut el capítol', - 'chapter_move_notification' => 'Chapter successfully moved', + 'chapter_move_notification' => 'Capítol mogut correctament', // Books 'book_create' => 'ha creat el llibre', 'book_create_notification' => 'Llibre creat correctament', - 'book_create_from_chapter' => 'converted chapter to book', - 'book_create_from_chapter_notification' => 'Chapter successfully converted to a book', + 'book_create_from_chapter' => 'ha convertit un capítol en el llibre', + 'book_create_from_chapter_notification' => 'Capítol convertit en llibre correctament', 'book_update' => 'ha actualitzat el llibre', - 'book_update_notification' => 'Book successfully updated', + 'book_update_notification' => 'Llibre actualitzat correctament', 'book_delete' => 'ha suprimit un llibre', - 'book_delete_notification' => 'Book successfully deleted', + 'book_delete_notification' => 'Llibre suprimit correctament', 'book_sort' => 'ha ordenat el llibre', - 'book_sort_notification' => 'Book successfully re-sorted', + 'book_sort_notification' => 'Llibre reordenat correctament', // Bookshelves - 'bookshelf_create' => 'created shelf', - 'bookshelf_create_notification' => 'Shelf successfully created', - 'bookshelf_create_from_book' => 'converted book to shelf', - 'bookshelf_create_from_book_notification' => 'Book successfully converted to a shelf', - 'bookshelf_update' => 'updated shelf', - 'bookshelf_update_notification' => 'Shelf successfully updated', - 'bookshelf_delete' => 'deleted shelf', - 'bookshelf_delete_notification' => 'Shelf successfully deleted', + 'bookshelf_create' => 'ha creat el prestatge', + 'bookshelf_create_notification' => 'Prestatge creat correctament', + 'bookshelf_create_from_book' => 'ha convertit un llibre en el prestatge', + 'bookshelf_create_from_book_notification' => 'Llibre convertit en prestatge correctament', + 'bookshelf_update' => 'ha actualitzat el prestatge', + 'bookshelf_update_notification' => 'Prestatge actualitzat correctament', + 'bookshelf_delete' => 'ha suprimit un prestatge', + 'bookshelf_delete_notification' => 'Prestatge suprimit correctament', // Revisions - 'revision_restore' => 'restored revision', - 'revision_delete' => 'deleted revision', - 'revision_delete_notification' => 'Revision successfully deleted', + 'revision_restore' => 'ha restaurat la revisió', + 'revision_delete' => 'ha suprimit una revisió', + 'revision_delete_notification' => 'Revisió suprimida correctament', // Favourites - 'favourite_add_notification' => '":name" has been added to your favourites', - 'favourite_remove_notification' => '":name" has been removed from your favourites', + 'favourite_add_notification' => 'S’ha afegit «:name» als vostres preferits', + 'favourite_remove_notification' => 'S’ha suprimit «:name» dels vostres preferits', // Watching - 'watch_update_level_notification' => 'Watch preferences successfully updated', + 'watch_update_level_notification' => 'Preferències de seguiment actualitzades correctament', // Auth - 'auth_login' => 'logged in', - 'auth_register' => 'registered as new user', - 'auth_password_reset_request' => 'requested user password reset', - 'auth_password_reset_update' => 'reset user password', - 'mfa_setup_method' => 'configured MFA method', - 'mfa_setup_method_notification' => 'Multi-factor method successfully configured', - 'mfa_remove_method' => 'removed MFA method', - 'mfa_remove_method_notification' => 'Multi-factor method successfully removed', + 'auth_login' => 'ha iniciat la sessió', + 'auth_register' => 's’ha registrat com a usuari nou', + 'auth_password_reset_request' => 'ha sol·licitat un restabliment de la contrasenya', + 'auth_password_reset_update' => 'ha restablert la contrasenya de l’usuari', + 'mfa_setup_method' => 'ha configurat un mètode d’autenticació de múltiple factor', + 'mfa_setup_method_notification' => 'Mètode d’autenticació de múltiple factor configurat correctament', + 'mfa_remove_method' => 'ha suprimit un mètode d’autenticació de múltiple factor', + 'mfa_remove_method_notification' => 'Mètode d’autenticació de múltiple factor suprimit correctament', // Settings - 'settings_update' => 'updated settings', - 'settings_update_notification' => 'Settings successfully updated', - 'maintenance_action_run' => 'ran maintenance action', + 'settings_update' => 'ha actualitzat la configuració', + 'settings_update_notification' => 'Configuració actualitzada correctament', + 'maintenance_action_run' => 'ha executat una acció de manteniment', // Webhooks - 'webhook_create' => 'created webhook', - 'webhook_create_notification' => 'Webhook successfully created', - 'webhook_update' => 'updated webhook', - 'webhook_update_notification' => 'Webhook successfully updated', - 'webhook_delete' => 'deleted webhook', - 'webhook_delete_notification' => 'Webhook successfully deleted', + 'webhook_create' => 'ha creat un webhook', + 'webhook_create_notification' => 'Webhook creat correctament', + 'webhook_update' => 'ha actualitzat un webhook', + 'webhook_update_notification' => 'Webhook actualitzat correctament', + 'webhook_delete' => 'ha suprimit un webhook', + 'webhook_delete_notification' => 'Webhook suprimit correctament', // Users - 'user_create' => 'created user', - 'user_create_notification' => 'User successfully created', - 'user_update' => 'updated user', - 'user_update_notification' => 'User successfully updated', - 'user_delete' => 'deleted user', - 'user_delete_notification' => 'User successfully removed', + 'user_create' => 'ha creat l’usuari', + 'user_create_notification' => 'Usuari creat correctament', + 'user_update' => 'ha actualitzat l’usuari', + 'user_update_notification' => 'Usuari actualitzat correctament', + 'user_delete' => 'ha suprimit un usuari', + 'user_delete_notification' => 'Usuari suprimit correctament', // API Tokens - 'api_token_create' => 'created api token', - 'api_token_create_notification' => 'API token successfully created', - 'api_token_update' => 'updated api token', - 'api_token_update_notification' => 'API token successfully updated', - 'api_token_delete' => 'deleted api token', - 'api_token_delete_notification' => 'API token successfully deleted', + 'api_token_create' => 'ha creat un testimoni d’API', + 'api_token_create_notification' => 'Testimoni d’API creat correctament', + 'api_token_update' => 'ha actualitzat un testimoni d’API', + 'api_token_update_notification' => 'Testimoni d’API actualitzat correctament', + 'api_token_delete' => 'ha suprimit un testumoni d’API', + 'api_token_delete_notification' => 'Testimoni d’API suprimit correctament', // Roles - 'role_create' => 'created role', - 'role_create_notification' => 'Role successfully created', - 'role_update' => 'updated role', - 'role_update_notification' => 'Role successfully updated', - 'role_delete' => 'deleted role', - 'role_delete_notification' => 'Role successfully deleted', + 'role_create' => 'ha creat el rol', + 'role_create_notification' => 'Rol creat correctament', + 'role_update' => 'ha actualitzat el rol', + 'role_update_notification' => 'Rol actualitzat correctament', + 'role_delete' => 'ha suprimit un rol', + 'role_delete_notification' => 'Rol suprimit correctament', // Recycle Bin - 'recycle_bin_empty' => 'emptied recycle bin', - 'recycle_bin_restore' => 'restored from recycle bin', - 'recycle_bin_destroy' => 'removed from recycle bin', + 'recycle_bin_empty' => 'ha buidat la paperera de reciclatge', + 'recycle_bin_restore' => 'ha restaurat de la paperera de reciclatge', + 'recycle_bin_destroy' => 'ha suprimit de la paperera de reciclatge', // Comments 'commented_on' => 'ha comentat a', - 'comment_create' => 'added comment', - 'comment_update' => 'updated comment', - 'comment_delete' => 'deleted comment', + 'comment_create' => 'ha afegit el comentari', + 'comment_update' => 'ha actualitzat el comentari', + 'comment_delete' => 'ha suprimit un comentari', // Other 'permissions_update' => 'ha actualitzat els permisos', diff --git a/lang/ca/auth.php b/lang/ca/auth.php index a156ecee3..714c095b6 100644 --- a/lang/ca/auth.php +++ b/lang/ca/auth.php @@ -7,29 +7,29 @@ return [ 'failed' => 'Les credencials no coincideixen amb les que hi ha emmagatzemades.', - 'throttle' => 'Massa intents d\'inici de sessió. Torna-ho a provar d\'aquí a :seconds segons.', + 'throttle' => 'Massa intents d’inici de sessió. Torneu-ho a provar d’aquí a :seconds segons.', // Login & Register - 'sign_up' => 'Registra-m\'hi', + 'sign_up' => 'Registra-m’hi', 'log_in' => 'Inicia la sessió', 'log_in_with' => 'Inicia la sessió amb :socialDriver', - 'sign_up_with' => 'Registra-m\'hi amb :socialDriver', + 'sign_up_with' => 'Registra-m’hi amb :socialDriver', 'logout' => 'Tanca la sessió', 'name' => 'Nom', - 'username' => 'Nom d\'usuari', + 'username' => 'Nom d’usuari', 'email' => 'Adreça electrònica', 'password' => 'Contrasenya', 'password_confirm' => 'Confirmeu la contrasenya', - 'password_hint' => 'Must be at least 8 characters', + 'password_hint' => 'Cal que tingui un mínim de 8 caràcters', 'forgot_password' => 'Heu oblidat la contrasenya?', - 'remember_me' => 'Recorda\'m', + 'remember_me' => 'Recorda’m', 'ldap_email_hint' => 'Introduïu una adreça electrònica per a aquest compte.', 'create_account' => 'Crea el compte', 'already_have_account' => 'Ja teniu un compte?', 'dont_have_account' => 'No teniu cap compte?', - 'social_login' => 'Inici de sessió amb xarxes social', - 'social_registration' => 'Registre social', + 'social_login' => 'Inici de sessió amb xarxes socials', + 'social_registration' => 'Registre amb xarxes socials', 'social_registration_text' => 'Registreu-vos i inicieu la sessió fent servir un altre servei.', 'register_thanks' => 'Gràcies per registrar-vos!', @@ -39,79 +39,79 @@ return [ 'register_success' => 'Gràcies per registrar-vos! Ja us hi heu registrat i heu iniciat la sessió.', // Login auto-initiation - 'auto_init_starting' => 'Attempting Login', - 'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.', - 'auto_init_start_link' => 'Proceed with authentication', + 'auto_init_starting' => 'S’està provant d’iniciar la sessió', + 'auto_init_starting_desc' => 'Estem contactant amb el vostre sistema d’autenticació per a començar el procés d’inici de sessió. Si no hi ha cap progrés d’aquí a 5 segons, proveu de fer clic a l’enllaç de sota.', + 'auto_init_start_link' => 'Continua amb l’autenticació', // Password Reset 'reset_password' => 'Restableix la contrasenya', 'reset_password_send_instructions' => 'Introduïu la vostra adreça electrònica a continuació i us enviarem un correu electrònic amb un enllaç per a restablir la contrasenya.', - 'reset_password_send_button' => 'Envia l\'enllaç de restabliment', - 'reset_password_sent' => 'S\'enviarà un enllaç per a restablir la contrasenya a :email, si es troba aquesta adreça al sistema.', - 'reset_password_success' => 'La vostra contrasenya s\'ha restablert correctament.', + 'reset_password_send_button' => 'Envia l’enllaç de restabliment', + 'reset_password_sent' => 'S’enviarà un enllaç per a restablir la contrasenya a :email, si es troba aquesta adreça al sistema.', + 'reset_password_success' => 'La contrasenya s’ha restablert correctament.', 'email_reset_subject' => 'Restabliu la contrasenya a :appName', - 'email_reset_text' => 'Rebeu aquest correu electrònic perquè heu rebut una petició de restabliment de contrasenya per al vostre compte.', - 'email_reset_not_requested' => 'Si no heu demanat restablir la contrasenya, no cal que prengueu cap acció.', + 'email_reset_text' => 'Rebeu aquest correu electrònic perquè s’ha fet una petició de restabliment de contrasenya per al vostre compte.', + 'email_reset_not_requested' => 'Si no heu demanat restablir la contrasenya, no cal que emprengueu cap acció.', // Email Confirmation 'email_confirm_subject' => 'Confirmeu la vostra adreça electrònica a :appName', 'email_confirm_greeting' => 'Gràcies per unir-vos a :appName!', 'email_confirm_text' => 'Confirmeu la vostra adreça electrònica fent clic al botó a continuació:', 'email_confirm_action' => 'Confirma el correu', - 'email_confirm_send_error' => 'Cal confirmar l\'adreça electrònica, però el sistema no ha pogut enviar el correu electrònic. Poseu-vos en contacte amb l\'administrador perquè s\'asseguri que el correu electrònic està ben configurat.', - 'email_confirm_success' => 'Your email has been confirmed! You should now be able to login using this email address.', - 'email_confirm_resent' => 'S\'ha tornat a enviar el correu electrònic de confirmació. Reviseu la vostra safata d\'entrada.', - 'email_confirm_thanks' => 'Thanks for confirming!', - 'email_confirm_thanks_desc' => 'Please wait a moment while your confirmation is handled. If you are not redirected after 3 seconds press the "Continue" link below to proceed.', + 'email_confirm_send_error' => 'Cal confirmar l’adreça electrònica, però el sistema no ha pogut enviar el correu electrònic. Poseu-vos en contacte amb l’administrador perquè s’asseguri que el correu electrònic està ben configurat.', + 'email_confirm_success' => 'Heu confirmat el vostre correu electrònic! Ara hauríeu de poder iniciar la sessió fent servir aquesta adreça electrònica.', + 'email_confirm_resent' => 'S’ha tornat a enviar el correu electrònic de confirmació. Reviseu la vostra safata d’entrada.', + 'email_confirm_thanks' => 'Gràcies per la confirmació!', + 'email_confirm_thanks_desc' => 'Espereu uns instants mentre gestionem la confirmació. Si no se us redirigeix d’aquí a 3 segons, premeu l’enllaç «Continua» de sota per a continuar.', 'email_not_confirmed' => 'Adreça electrònica no confirmada', 'email_not_confirmed_text' => 'La vostra adreça electrònica encara no està confirmada.', - 'email_not_confirmed_click_link' => 'Feu clic a l\'enllaç del correu electrònic que us vam enviar poc després que us registréssiu.', - 'email_not_confirmed_resend' => 'Si no podeu trobar el correu, podeu tornar a enviar el correu electrònic de confirmació enviant el formulari a continuació.', + 'email_not_confirmed_click_link' => 'Feu clic a l’enllaç del correu electrònic que us vam enviar poc després que us registréssiu.', + 'email_not_confirmed_resend' => 'Si no el trobeu, podeu tornar a enviar el correu electrònic de confirmació enviant el formulari a continuació.', 'email_not_confirmed_resend_button' => 'Torna a enviar el correu de confirmació', // User Invite 'user_invite_email_subject' => 'Us han convidat a unir-vos a :appName!', - 'user_invite_email_greeting' => 'Us hem creat un compte en el vostre nom a :appName.', + 'user_invite_email_greeting' => 'S’ha creat un compte en el vostre nom a :appName.', 'user_invite_email_text' => 'Feu clic al botó a continuació per a definir una contrasenya per al compte i obtenir-hi accés:', 'user_invite_email_action' => 'Defineix una contrasenya per al compte', 'user_invite_page_welcome' => 'Us donem la benvinguda a :appName!', 'user_invite_page_text' => 'Per a enllestir el vostre compte i obtenir-hi accés, cal que definiu una contrasenya, que es farà servir per a iniciar la sessió a :appName en futures visites.', 'user_invite_page_confirm_button' => 'Confirma la contrasenya', - 'user_invite_success_login' => 'Password set, you should now be able to login using your set password to access :appName!', + 'user_invite_success_login' => 'S’ha definit la contrasenya. Ara hauríeu de poder iniciar la sessió fent servir la contrasenya que heu definit per a accedir a :appName!', // Multi-factor Authentication - 'mfa_setup' => 'Setup Multi-Factor Authentication', - 'mfa_setup_desc' => 'Setup multi-factor authentication as an extra layer of security for your user account.', - 'mfa_setup_configured' => 'Already configured', - 'mfa_setup_reconfigure' => 'Reconfigure', - 'mfa_setup_remove_confirmation' => 'Are you sure you want to remove this multi-factor authentication method?', - 'mfa_setup_action' => 'Setup', - 'mfa_backup_codes_usage_limit_warning' => 'You have less than 5 backup codes remaining, Please generate and store a new set before you run out of codes to prevent being locked out of your account.', - 'mfa_option_totp_title' => 'Mobile App', - 'mfa_option_totp_desc' => 'To use multi-factor authentication you\'ll need a mobile application that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator.', - 'mfa_option_backup_codes_title' => 'Backup Codes', - 'mfa_option_backup_codes_desc' => 'Securely store a set of one-time-use backup codes which you can enter to verify your identity.', - 'mfa_gen_confirm_and_enable' => 'Confirm and Enable', - 'mfa_gen_backup_codes_title' => 'Backup Codes Setup', - 'mfa_gen_backup_codes_desc' => 'Store the below list of codes in a safe place. When accessing the system you\'ll be able to use one of the codes as a second authentication mechanism.', - 'mfa_gen_backup_codes_download' => 'Download Codes', - 'mfa_gen_backup_codes_usage_warning' => 'Each code can only be used once', - 'mfa_gen_totp_title' => 'Mobile App Setup', - 'mfa_gen_totp_desc' => 'To use multi-factor authentication you\'ll need a mobile application that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator.', - 'mfa_gen_totp_scan' => 'Scan the QR code below using your preferred authentication app to get started.', - 'mfa_gen_totp_verify_setup' => 'Verify Setup', - 'mfa_gen_totp_verify_setup_desc' => 'Verify that all is working by entering a code, generated within your authentication app, in the input box below:', - 'mfa_gen_totp_provide_code_here' => 'Provide your app generated code here', - 'mfa_verify_access' => 'Verify Access', - 'mfa_verify_access_desc' => 'Your user account requires you to confirm your identity via an additional level of verification before you\'re granted access. Verify using one of your configured methods to continue.', - 'mfa_verify_no_methods' => 'No Methods Configured', - 'mfa_verify_no_methods_desc' => 'No multi-factor authentication methods could be found for your account. You\'ll need to set up at least one method before you gain access.', - 'mfa_verify_use_totp' => 'Verify using a mobile app', - 'mfa_verify_use_backup_codes' => 'Verify using a backup code', - 'mfa_verify_backup_code' => 'Backup Code', - 'mfa_verify_backup_code_desc' => 'Enter one of your remaining backup codes below:', - 'mfa_verify_backup_code_enter_here' => 'Enter backup code here', - 'mfa_verify_totp_desc' => 'Enter the code, generated using your mobile app, below:', - 'mfa_setup_login_notification' => 'Multi-factor method configured, Please now login again using the configured method.', + 'mfa_setup' => 'Configura l’autenticació de múltiple factor', + 'mfa_setup_desc' => 'Configureu l’autenticació de múltiple factor com a capa extra de seguretat en el vostre compte d’usuari.', + 'mfa_setup_configured' => 'Ja està configurada', + 'mfa_setup_reconfigure' => 'Torna-la a configurar', + 'mfa_setup_remove_confirmation' => 'Segur que voleu suprimir aquest mètode d’autenticació de múltiple factor?', + 'mfa_setup_action' => 'Configura', + 'mfa_backup_codes_usage_limit_warning' => 'Teniu menys de 5 codis de seguretat restants. Genereu-ne i emmagatzemeu-ne un nou conjunt abans que se us acabin perquè no perdeu l’accés al vostre compte.', + 'mfa_option_totp_title' => 'Aplicació mòbil', + 'mfa_option_totp_desc' => 'Per a fer servir l’autenticació de múltiple factor us caldrà una aplicació mòbil que suporti TOTP, com ara Google Authenticador, Authy o Microsoft Authenticator.', + 'mfa_option_backup_codes_title' => 'Codis de seguretat', + 'mfa_option_backup_codes_desc' => 'Deseu de manera segura codis de seguretat d’un sol ús que podeu introduir per a verificar la vostra identitat.', + 'mfa_gen_confirm_and_enable' => 'Confirma i activa', + 'mfa_gen_backup_codes_title' => 'Configuració de codis de seguretat', + 'mfa_gen_backup_codes_desc' => 'Deseu la següent llista de codis en un lloc segur. Quan accediu al sistema, podeu fer servir un dels codis com a segon mètode d’autenticació.', + 'mfa_gen_backup_codes_download' => 'Baixa els codis', + 'mfa_gen_backup_codes_usage_warning' => 'Cada codi es pot fer servir només una vegada', + 'mfa_gen_totp_title' => 'Configuració de l’aplicació mòbil', + 'mfa_gen_totp_desc' => 'Per a fer servir l’autenticació de múltiple factor us caldrà una aplicació mòbil que suporti TOTP, com ara Google Authenticador, Authy o Microsoft Authenticator.', + 'mfa_gen_totp_scan' => 'Per a començar, escanegeu el codi QR següent fent servir la vostre aplicació d’autenticació preferida.', + 'mfa_gen_totp_verify_setup' => 'Verifica la configuració', + 'mfa_gen_totp_verify_setup_desc' => 'Verifiqueu que tot funciona introduint un codi, generat amb l’aplicació d’autenticació, a la capsa de text següent:', + 'mfa_gen_totp_provide_code_here' => 'Proporcioneu aquí el codi generat per l’aplicació', + 'mfa_verify_access' => 'Verifica l’accés', + 'mfa_verify_access_desc' => 'El vostre compte d’usuari requereix que confirmeu la vostra identitat amb un nivell addicional de verificació abans que pugueu obtenir-hi accés. Verifiqueu-la fent servir un dels vostres mètodes configurats per a continuar.', + 'mfa_verify_no_methods' => 'No hi ha cap mètode configurat', + 'mfa_verify_no_methods_desc' => 'No s’ha trobat cap mètode d’autenticació de múltiple factor al vostre compte. Cal que configureu almenys un mètode abans d’obtenir-hi accés.', + 'mfa_verify_use_totp' => 'Verifica fent servir una aplicació mòbil', + 'mfa_verify_use_backup_codes' => 'Verifica fent servir un codi de seguretat', + 'mfa_verify_backup_code' => 'Codi de seguretat', + 'mfa_verify_backup_code_desc' => 'Introduïu un dels vostres codis de seguretat restants a continuació:', + 'mfa_verify_backup_code_enter_here' => 'Introduïu aquí el codi de seguretat', + 'mfa_verify_totp_desc' => 'Introduïu el codi generat amb la vostra aplicació mòbil a continuació:', + 'mfa_setup_login_notification' => 'S’ha configurat el mètode d’autenticació de múltiple factor. Torneu a iniciar la sessió fent servir el mètode que heu configurat.', ]; diff --git a/lang/ca/common.php b/lang/ca/common.php index 4b8f2eddc..1798c82b7 100644 --- a/lang/ca/common.php +++ b/lang/ca/common.php @@ -6,8 +6,8 @@ return [ // Buttons 'cancel' => 'Cancel·la', - 'close' => 'Close', - 'confirm' => 'D\'acord', + 'close' => 'Tanca', + 'confirm' => 'D’acord', 'back' => 'Enrere', 'save' => 'Desa', 'continue' => 'Continua', @@ -26,7 +26,7 @@ return [ 'actions' => 'Accions', 'view' => 'Visualitza', 'view_all' => 'Visualitza-ho tot', - 'new' => 'New', + 'new' => 'Nou', 'create' => 'Crea', 'update' => 'Actualitza', 'edit' => 'Edita', @@ -41,35 +41,35 @@ return [ 'reset' => 'Reinicialitza', 'remove' => 'Elimina', 'add' => 'Afegeix', - 'configure' => 'Configure', - 'manage' => 'Manage', + 'configure' => 'Configura', + 'manage' => 'Gestiona', 'fullscreen' => 'Pantalla completa', - 'favourite' => 'Favourite', - 'unfavourite' => 'Unfavourite', - 'next' => 'Next', - 'previous' => 'Previous', - 'filter_active' => 'Active Filter:', - 'filter_clear' => 'Clear Filter', - 'download' => 'Download', - 'open_in_tab' => 'Open in Tab', - 'open' => 'Open', + 'favourite' => 'Afegeix a preferits', + 'unfavourite' => 'Suprimeix de preferits', + 'next' => 'Següent', + 'previous' => 'Anterior', + 'filter_active' => 'Filtre actiu:', + 'filter_clear' => 'Esborra el filtre', + 'download' => 'Baixa', + 'open_in_tab' => 'Obre en una pestanya', + 'open' => 'Obre', // Sort Options - 'sort_options' => 'Opcions d\'ordenació', - 'sort_direction_toggle' => 'Commuta la direcció de l\'ordenació', + 'sort_options' => 'Opcions d’ordenació', + 'sort_direction_toggle' => 'Commuta la direcció de l’ordenació', 'sort_ascending' => 'Ordre ascendent', 'sort_descending' => 'Ordre descendent', 'sort_name' => 'Nom', 'sort_default' => 'Per defecte', 'sort_created_at' => 'Data de creació', - 'sort_updated_at' => 'Data d\'actualització', + 'sort_updated_at' => 'Data d’actualització', // Misc - 'deleted_user' => 'Usuari eliminat', + 'deleted_user' => 'Usuari suprimit', 'no_activity' => 'No hi ha activitat', 'no_items' => 'No hi ha cap element', 'back_to_top' => 'Torna a dalt', - 'skip_to_main_content' => 'Skip to main content', + 'skip_to_main_content' => 'Vés al contingut', 'toggle_details' => 'Commuta els detalls', 'toggle_thumbnails' => 'Commuta les miniatures', 'details' => 'Detalls', @@ -77,30 +77,30 @@ return [ 'list_view' => 'Visualització en llista', 'default' => 'Per defecte', 'breadcrumb' => 'Ruta de navegació', - 'status' => 'Status', - 'status_active' => 'Active', - 'status_inactive' => 'Inactive', - 'never' => 'Never', - 'none' => 'None', + 'status' => 'Estat', + 'status_active' => 'Actiu', + 'status_inactive' => 'Inactiu', + 'never' => 'Mai', + 'none' => 'Cap', // Header - 'homepage' => 'Homepage', - 'header_menu_expand' => 'Expand Header Menu', + 'homepage' => 'Pàgina principal', + 'header_menu_expand' => 'Expandeix el menú de la capçalera', 'profile_menu' => 'Menú del perfil', 'view_profile' => 'Mostra el perfil', 'edit_profile' => 'Edita el perfil', 'dark_mode' => 'Mode fosc', 'light_mode' => 'Mode clar', - 'global_search' => 'Global Search', + 'global_search' => 'Cerca global', // Layout tabs 'tab_info' => 'Informació', - 'tab_info_label' => 'Tab: Show Secondary Information', + 'tab_info_label' => 'Pestanya: Mostra la informació secundària', 'tab_content' => 'Contingut', - 'tab_content_label' => 'Tab: Show Primary Content', + 'tab_content_label' => 'Pestanya: Mostra el contingut principal', // Email Content - 'email_action_help' => 'Si teniu problemes per fer clic al botó ":actionText", copieu i enganxeu l\'URL següent al vostre navegador web:', + 'email_action_help' => 'Si teniu problemes per a fer clic al botó «:actionText», copieu i enganxeu l’URL següent al vostre navegador web:', 'email_rights' => 'Tots els drets reservats', // Footer Link Options diff --git a/lang/ca/components.php b/lang/ca/components.php index e002886d7..9c3485021 100644 --- a/lang/ca/components.php +++ b/lang/ca/components.php @@ -6,36 +6,36 @@ return [ // Image Manager 'image_select' => 'Selecciona una imatge', - 'image_list' => 'Image List', - 'image_details' => 'Image Details', - 'image_upload' => 'Upload Image', - 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.', - 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.', + 'image_list' => 'Llista d’imatges', + 'image_details' => 'Detalls de la imatge', + 'image_upload' => 'Puja una imatge', + 'image_intro' => 'Aquí podeu seleccionar i gestionar imatges que s’hagin pujat anteriorment al sistema.', + 'image_intro_upload' => 'Pugeu una imatge nova arrossegant un fitxer d’imatge a aquesta finestra o fent servir el botó de «Puja una imatge».', 'image_all' => 'Totes', 'image_all_title' => 'Mostra totes les imatges', 'image_book_title' => 'Mostra les imatges pujades a aquest llibre', 'image_page_title' => 'Mostra les imatges pujades a aquesta pàgina', - 'image_search_hint' => 'Cerca per nom d\'imatge', + 'image_search_hint' => 'Cerca per nom d’imatge', 'image_uploaded' => 'Pujada :uploadedDate', - 'image_uploaded_by' => 'Uploaded by :userName', - 'image_uploaded_to' => 'Uploaded to :pageLink', - 'image_updated' => 'Updated :updateDate', - 'image_load_more' => 'Carrega\'n més', + 'image_uploaded_by' => 'Pujada per :userName', + 'image_uploaded_to' => 'Pujada a :pageLink', + 'image_updated' => 'Actualitzada :updateDate', + 'image_load_more' => 'Carrega’n més', 'image_image_name' => 'Nom de la imatge', - 'image_delete_used' => 'Aquesta imatge s\'utilitza a les pàgines següents.', + 'image_delete_used' => 'Aquesta imatge s’utilitza a les pàgines següents.', 'image_delete_confirm_text' => 'Segur que voleu suprimir aquesta imatge?', 'image_select_image' => 'Selecciona una imatge', 'image_dropzone' => 'Arrossegueu imatges o feu clic aquí per a pujar-les', - 'image_dropzone_drop' => 'Drop images here to upload', + 'image_dropzone_drop' => 'Arrossegueu imatges aquí per a pujar-les', 'images_deleted' => 'Imatges suprimides', 'image_preview' => 'Previsualització de la imatge', 'image_upload_success' => 'Imatge pujada correctament', 'image_update_success' => 'Detalls de la imatge actualitzats correctament', 'image_delete_success' => 'Imatge suprimida correctament', - 'image_replace' => 'Replace Image', - 'image_replace_success' => 'Image file successfully updated', - 'image_rebuild_thumbs' => 'Regenerate Size Variations', - 'image_rebuild_thumbs_success' => 'Image size variations successfully rebuilt!', + 'image_replace' => 'Substitueix la imatge', + 'image_replace_success' => 'Fitxer de la imatge actualitzat correctament', + 'image_rebuild_thumbs' => 'Regenera les variacions de mida', + 'image_rebuild_thumbs_success' => 'Variacions de mida de la imatge regenerades correctament!', // Code Editor 'code_editor' => 'Edita el codi', diff --git a/lang/ca/editor.php b/lang/ca/editor.php index 670c1c5e1..eaef6402f 100644 --- a/lang/ca/editor.php +++ b/lang/ca/editor.php @@ -8,167 +8,167 @@ return [ // General editor terms 'general' => 'General', - 'advanced' => 'Advanced', - 'none' => 'None', - 'cancel' => 'Cancel', - 'save' => 'Save', - 'close' => 'Close', - 'undo' => 'Undo', - 'redo' => 'Redo', - 'left' => 'Left', - 'center' => 'Center', - 'right' => 'Right', - 'top' => 'Top', - 'middle' => 'Middle', - 'bottom' => 'Bottom', - 'width' => 'Width', - 'height' => 'Height', - 'More' => 'More', - 'select' => 'Select...', + 'advanced' => 'Avançat', + 'none' => 'Cap', + 'cancel' => 'Cancel·la', + 'save' => 'Desa', + 'close' => 'Tanca', + 'undo' => 'Desfés', + 'redo' => 'Refés', + 'left' => 'Esquerra', + 'center' => 'Centre', + 'right' => 'Dreta', + 'top' => 'Superior', + 'middle' => 'Centre', + 'bottom' => 'Inferior', + 'width' => 'Amplada', + 'height' => 'Alçada', + 'More' => 'Més', + 'select' => 'Selecciona...', // Toolbar 'formats' => 'Formats', - 'header_large' => 'Large Header', - 'header_medium' => 'Medium Header', - 'header_small' => 'Small Header', - 'header_tiny' => 'Tiny Header', - 'paragraph' => 'Paragraph', - 'blockquote' => 'Blockquote', - 'inline_code' => 'Inline code', - 'callouts' => 'Callouts', - 'callout_information' => 'Information', - 'callout_success' => 'Success', - 'callout_warning' => 'Warning', - 'callout_danger' => 'Danger', - 'bold' => 'Bold', - 'italic' => 'Italic', - 'underline' => 'Underline', - 'strikethrough' => 'Strikethrough', - 'superscript' => 'Superscript', - 'subscript' => 'Subscript', - 'text_color' => 'Text color', - 'custom_color' => 'Custom color', - 'remove_color' => 'Remove color', - 'background_color' => 'Background color', - 'align_left' => 'Align left', - 'align_center' => 'Align center', - 'align_right' => 'Align right', - 'align_justify' => 'Justify', - 'list_bullet' => 'Bullet list', - 'list_numbered' => 'Numbered list', - 'list_task' => 'Task list', - 'indent_increase' => 'Increase indent', - 'indent_decrease' => 'Decrease indent', - 'table' => 'Table', - 'insert_image' => 'Insert image', - 'insert_image_title' => 'Insert/Edit Image', - 'insert_link' => 'Insert/edit link', - 'insert_link_title' => 'Insert/Edit Link', - 'insert_horizontal_line' => 'Insert horizontal line', - 'insert_code_block' => 'Insert code block', - 'edit_code_block' => 'Edit code block', - 'insert_drawing' => 'Insert/edit drawing', - 'drawing_manager' => 'Drawing manager', - 'insert_media' => 'Insert/edit media', - 'insert_media_title' => 'Insert/Edit Media', - 'clear_formatting' => 'Clear formatting', - 'source_code' => 'Source code', - 'source_code_title' => 'Source Code', - 'fullscreen' => 'Fullscreen', - 'image_options' => 'Image options', + 'header_large' => 'Capçalera grossa', + 'header_medium' => 'Capçalera mitjana', + 'header_small' => 'Capçalera petita', + 'header_tiny' => 'Capçalera minúscula', + 'paragraph' => 'Paràgraf', + 'blockquote' => 'Citació', + 'inline_code' => 'Codi en línia', + 'callouts' => 'Llegendes', + 'callout_information' => 'Informació', + 'callout_success' => 'Èxit', + 'callout_warning' => 'Advertència', + 'callout_danger' => 'Perill', + 'bold' => 'Negreta', + 'italic' => 'Cursiva', + 'underline' => 'Subratllat', + 'strikethrough' => 'Ratllat', + 'superscript' => 'Superíndex', + 'subscript' => 'Subíndex', + 'text_color' => 'Color del text', + 'custom_color' => 'Color personalitzat', + 'remove_color' => 'Suprimeix el color', + 'background_color' => 'Color de fons', + 'align_left' => 'Alinea a l’esquerra', + 'align_center' => 'Alinea al centre', + 'align_right' => 'Alinea a la dreta', + 'align_justify' => 'Justifica', + 'list_bullet' => 'Llista amb pics', + 'list_numbered' => 'Llista numerada', + 'list_task' => 'Llista de tasques', + 'indent_increase' => 'Augmenta el sagnat', + 'indent_decrease' => 'Redueix el sagnat', + 'table' => 'Taula', + 'insert_image' => 'Insereix una imatge', + 'insert_image_title' => 'Insereix/edita una imatge', + 'insert_link' => 'Insereix/edita un enllaç', + 'insert_link_title' => 'Insereix/edita un enllaç', + 'insert_horizontal_line' => 'Insereix una línia horitzontal', + 'insert_code_block' => 'Insereix un bloc de codi', + 'edit_code_block' => 'Edita un bloc de codi', + 'insert_drawing' => 'Insereix/edita un dibuix', + 'drawing_manager' => 'Gestor de dibuixos', + 'insert_media' => 'Insereix/edita un mitjà', + 'insert_media_title' => 'Insereix/edita un mitjà', + 'clear_formatting' => 'Neteja el format', + 'source_code' => 'Codi font', + 'source_code_title' => 'Codi font', + 'fullscreen' => 'Pantalla completa', + 'image_options' => 'Opcions d’imatge', // Tables - 'table_properties' => 'Table properties', - 'table_properties_title' => 'Table Properties', - 'delete_table' => 'Delete table', - 'insert_row_before' => 'Insert row before', - 'insert_row_after' => 'Insert row after', - 'delete_row' => 'Delete row', - 'insert_column_before' => 'Insert column before', - 'insert_column_after' => 'Insert column after', - 'delete_column' => 'Delete column', - 'table_cell' => 'Cell', - 'table_row' => 'Row', - 'table_column' => 'Column', - 'cell_properties' => 'Cell properties', - 'cell_properties_title' => 'Cell Properties', - 'cell_type' => 'Cell type', - 'cell_type_cell' => 'Cell', - 'cell_scope' => 'Scope', - 'cell_type_header' => 'Header cell', - 'merge_cells' => 'Merge cells', - 'split_cell' => 'Split cell', - 'table_row_group' => 'Row Group', - 'table_column_group' => 'Column Group', - 'horizontal_align' => 'Horizontal align', - 'vertical_align' => 'Vertical align', - 'border_width' => 'Border width', - 'border_style' => 'Border style', - 'border_color' => 'Border color', - 'row_properties' => 'Row properties', - 'row_properties_title' => 'Row Properties', - 'cut_row' => 'Cut row', - 'copy_row' => 'Copy row', - 'paste_row_before' => 'Paste row before', - 'paste_row_after' => 'Paste row after', - 'row_type' => 'Row type', - 'row_type_header' => 'Header', - 'row_type_body' => 'Body', - 'row_type_footer' => 'Footer', - 'alignment' => 'Alignment', - 'cut_column' => 'Cut column', - 'copy_column' => 'Copy column', - 'paste_column_before' => 'Paste column before', - 'paste_column_after' => 'Paste column after', - 'cell_padding' => 'Cell padding', - 'cell_spacing' => 'Cell spacing', - 'caption' => 'Caption', - 'show_caption' => 'Show caption', - 'constrain' => 'Constrain proportions', - 'cell_border_solid' => 'Solid', - 'cell_border_dotted' => 'Dotted', - 'cell_border_dashed' => 'Dashed', - 'cell_border_double' => 'Double', - 'cell_border_groove' => 'Groove', - 'cell_border_ridge' => 'Ridge', - 'cell_border_inset' => 'Inset', - 'cell_border_outset' => 'Outset', - 'cell_border_none' => 'None', - 'cell_border_hidden' => 'Hidden', + 'table_properties' => 'Propietats de la taula', + 'table_properties_title' => 'Propietats de la taula', + 'delete_table' => 'Suprimeix la taula', + 'insert_row_before' => 'Insereix una fila abans', + 'insert_row_after' => 'Insereix una fila després', + 'delete_row' => 'Suprimeix la fila', + 'insert_column_before' => 'Insereix una columna abans', + 'insert_column_after' => 'Insereix una columna després', + 'delete_column' => 'Suprimeix la columna', + 'table_cell' => 'Cel·la', + 'table_row' => 'Fila', + 'table_column' => 'Columna', + 'cell_properties' => 'Propietats de la cel·la', + 'cell_properties_title' => 'Propietats de la cel·la', + 'cell_type' => 'Tipus de cel·la', + 'cell_type_cell' => 'Cel·la', + 'cell_scope' => 'Àmbit', + 'cell_type_header' => 'Cel·la de capçalera', + 'merge_cells' => 'Fusiona les cel·les', + 'split_cell' => 'Divideix les cel·les', + 'table_row_group' => 'Grup de files', + 'table_column_group' => 'Grup de columnes', + 'horizontal_align' => 'Alineació horitzontal', + 'vertical_align' => 'Alineació vertical', + 'border_width' => 'Amplada de la vora', + 'border_style' => 'Estil de la vora', + 'border_color' => 'Color de la vora', + 'row_properties' => 'Propietats de la fila', + 'row_properties_title' => 'Propietats de la fila', + 'cut_row' => 'Retalla la fila', + 'copy_row' => 'Copia la fila', + 'paste_row_before' => 'Enganxa la fila abans', + 'paste_row_after' => 'Enganxa la fila després', + 'row_type' => 'Tipus de fila', + 'row_type_header' => 'Capçalera', + 'row_type_body' => 'Cos', + 'row_type_footer' => 'Peu de pàgina', + 'alignment' => 'Alineació', + 'cut_column' => 'Retalla la columna', + 'copy_column' => 'Copia la columna', + 'paste_column_before' => 'Enganxa la columna abans', + 'paste_column_after' => 'Enganxa la columna després', + 'cell_padding' => 'Separació de la cel·la', + 'cell_spacing' => 'Espaiat de la cel·la', + 'caption' => 'Títol', + 'show_caption' => 'Mostra el títol', + 'constrain' => 'Mantén les proporcions', + 'cell_border_solid' => 'Sòlida', + 'cell_border_dotted' => 'Puntejada', + 'cell_border_dashed' => 'Discontínua', + 'cell_border_double' => 'Doble', + 'cell_border_groove' => 'Bisellada', + 'cell_border_ridge' => 'Emmarcada', + 'cell_border_inset' => 'Enfonsada', + 'cell_border_outset' => 'Ressaltada', + 'cell_border_none' => 'Cap', + 'cell_border_hidden' => 'Oculta', // Images, links, details/summary & embed - 'source' => 'Source', - 'alt_desc' => 'Alternative description', - 'embed' => 'Embed', - 'paste_embed' => 'Paste your embed code below:', + 'source' => 'Origen', + 'alt_desc' => 'Descripció alternativa', + 'embed' => 'Incrustació', + 'paste_embed' => 'Enganxeu el codi d’incrustació a continuació:', 'url' => 'URL', - 'text_to_display' => 'Text to display', - 'title' => 'Title', - 'open_link' => 'Open link', - 'open_link_in' => 'Open link in...', - 'open_link_current' => 'Current window', - 'open_link_new' => 'New window', - 'remove_link' => 'Remove link', - 'insert_collapsible' => 'Insert collapsible block', - 'collapsible_unwrap' => 'Unwrap', - 'edit_label' => 'Edit label', - 'toggle_open_closed' => 'Toggle open/closed', - 'collapsible_edit' => 'Edit collapsible block', - 'toggle_label' => 'Toggle label', + 'text_to_display' => 'Text a mostrar', + 'title' => 'Títol', + 'open_link' => 'Obre l’enllaç', + 'open_link_in' => 'Obre l’enllaç a...', + 'open_link_current' => 'Finestra actual', + 'open_link_new' => 'Finestra nova', + 'remove_link' => 'Suprimeix l’enllaç', + 'insert_collapsible' => 'Insereix un bloc contraïble', + 'collapsible_unwrap' => 'Deixa de contraure', + 'edit_label' => 'Edita l’etiqueta', + 'toggle_open_closed' => 'Obre/tanca', + 'collapsible_edit' => 'Edita el bloc contraïble', + 'toggle_label' => 'Commuta l’etiqueta', // About view - 'about' => 'About the editor', - 'about_title' => 'About the WYSIWYG Editor', - 'editor_license' => 'Editor License & Copyright', - 'editor_tiny_license' => 'This editor is built using :tinyLink which is provided under the MIT license.', - 'editor_tiny_license_link' => 'The copyright and license details of TinyMCE can be found here.', - 'save_continue' => 'Save Page & Continue', - 'callouts_cycle' => '(Keep pressing to toggle through types)', - 'link_selector' => 'Link to content', - 'shortcuts' => 'Shortcuts', - 'shortcut' => 'Shortcut', - 'shortcuts_intro' => 'The following shortcuts are available in the editor:', + 'about' => 'Quant a l’editor', + 'about_title' => 'Quant a l’editor WYSIWYG', + 'editor_license' => 'Llicència i copyright de l’editor', + 'editor_tiny_license' => 'Aquest editor s’ha construït amb :tinyLink, que es proporciona sota la llicència MIT.', + 'editor_tiny_license_link' => 'Podeu trobar els detalls de la llicència i el copyright del TinyMCE aquí.', + 'save_continue' => 'Desa la pàgina i continua', + 'callouts_cycle' => '(Continueu prement per a commutar els diferents tipus)', + 'link_selector' => 'Enllaç al contingut', + 'shortcuts' => 'Dreceres', + 'shortcut' => 'Drecera', + 'shortcuts_intro' => 'Hi ha les següents dreceres disponibles a l’editor:', 'windows_linux' => '(Windows/Linux)', 'mac' => '(Mac)', - 'description' => 'Description', + 'description' => 'Descripció', ]; diff --git a/lang/ca/entities.php b/lang/ca/entities.php index a53a7a3bd..9bffe493c 100644 --- a/lang/ca/entities.php +++ b/lang/ca/entities.php @@ -15,7 +15,7 @@ return [ 'recently_update' => 'Actualitzat fa poc', 'recently_viewed' => 'Vist fa poc', 'recent_activity' => 'Activitat recent', - 'create_now' => 'Crea\'n ara', + 'create_now' => 'Crea’n ara', 'revisions' => 'Revisions', 'meta_revision' => 'Revisió núm. :revisionCount', 'meta_created' => 'Creat :timeLength', @@ -23,38 +23,38 @@ return [ 'meta_updated' => 'Actualitzat :timeLength', 'meta_updated_name' => 'Actualitzat :timeLength per :user', 'meta_owned_name' => 'Propietat de :user', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Selecciona una entitat', - 'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item', + 'entity_select_lack_permission' => 'No teniu els permisos necessaris per a seleccionar aquest element', 'images' => 'Imatges', 'my_recent_drafts' => 'Els vostres esborranys recents', 'my_recently_viewed' => 'Les vostres visualitzacions recents', - 'my_most_viewed_favourites' => 'My Most Viewed Favourites', - 'my_favourites' => 'My Favourites', + 'my_most_viewed_favourites' => 'Els vostres preferits més vistos', + 'my_favourites' => 'Els vostres preferits', 'no_pages_viewed' => 'No heu vist cap pàgina', - 'no_pages_recently_created' => 'No s\'ha creat cap pàgina fa poc', - 'no_pages_recently_updated' => 'No s\'ha actualitzat cap pàgina fa poc', + 'no_pages_recently_created' => 'No s’ha creat cap pàgina fa poc', + 'no_pages_recently_updated' => 'No s’ha actualitzat cap pàgina fa poc', 'export' => 'Exporta', 'export_html' => 'Fitxer web independent', 'export_pdf' => 'Fitxer PDF', 'export_text' => 'Fitxer de text sense format', - 'export_md' => 'Markdown File', + 'export_md' => 'Fitxer Markdown', // Permissions and restrictions 'permissions' => 'Permisos', - 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', - 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', - 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', + 'permissions_desc' => 'Definiu aquí permisos que tindran preferència sobre les permisos per defecte proporcionats pels rols d’usuari.', + 'permissions_book_cascade' => 'Els permisos definits en llibres s’hereten automàticament en pàgines i capítols inferiors, llevat que tinguin permisos propis definits.', + 'permissions_chapter_cascade' => 'Els permisos definits en capítols s’hereten automàticament en pàgines inferiors, llevat que tinguin permisos propis definits.', 'permissions_save' => 'Desa els permisos', 'permissions_owner' => 'Propietari', - 'permissions_role_everyone_else' => 'Everyone Else', - 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', - 'permissions_role_override' => 'Override permissions for role', - 'permissions_inherit_defaults' => 'Inherit defaults', + 'permissions_role_everyone_else' => 'Tota la resta', + 'permissions_role_everyone_else_desc' => 'Definiu permisos per a tots els rols no definits específicament.', + 'permissions_role_override' => 'Força els permisos per al rol', + 'permissions_inherit_defaults' => 'Hereta els permisos per defecte', // Search 'search_results' => 'Resultats de la cerca', - 'search_total_results_found' => 'S\'ha trobat :count resultat en total|S\'han trobat :count resultats en total', + 'search_total_results_found' => 'S’ha trobat :count resultat|S’han trobat :count resultats en total', 'search_clear' => 'Esborra la cerca', 'search_no_pages' => 'La cerca no coincideix amb cap pàgina', 'search_for_term' => 'Cerca :term', @@ -63,14 +63,14 @@ return [ 'search_terms' => 'Termes de la cerca', 'search_content_type' => 'Tipus de contingut', 'search_exact_matches' => 'Coincidències exactes', - 'search_tags' => 'Cerca d\'etiquetes', + 'search_tags' => 'Cerca d’etiquetes', 'search_options' => 'Opcions', 'search_viewed_by_me' => 'Visualitzat per mi', 'search_not_viewed_by_me' => 'No visualitzat per mi', 'search_permissions_set' => 'Amb permisos definits', 'search_created_by_me' => 'Creat per mi', 'search_updated_by_me' => 'Actualitzat per mi', - 'search_owned_by_me' => 'Owned by me', + 'search_owned_by_me' => 'En sóc propietari', 'search_date_options' => 'Opcions de dates', 'search_updated_before' => 'Actualitzat abans de', 'search_updated_after' => 'Actualitzat després de', @@ -93,24 +93,24 @@ return [ 'shelves_save' => 'Desa el prestatge', 'shelves_books' => 'Llibres en aquest prestatge', 'shelves_add_books' => 'Afegeix llibres a aquest prestatge', - 'shelves_drag_books' => 'Drag books below to add them to this shelf', + 'shelves_drag_books' => 'Arrossegueu llibres a sota per a afegir-los a aquest prestatge', 'shelves_empty_contents' => 'Aquest prestatge no té cap llibre assignat', 'shelves_edit_and_assign' => 'Editeu el prestatge per a assignar-hi llibres', - 'shelves_edit_named' => 'Edit Shelf :name', - 'shelves_edit' => 'Edit Shelf', - 'shelves_delete' => 'Delete Shelf', - 'shelves_delete_named' => 'Delete Shelf :name', - 'shelves_delete_explain' => "This will delete the shelf with the name ':name'. Contained books will not be deleted.", - 'shelves_delete_confirmation' => 'Are you sure you want to delete this shelf?', - 'shelves_permissions' => 'Shelf Permissions', - 'shelves_permissions_updated' => 'Shelf Permissions Updated', - 'shelves_permissions_active' => 'Shelf Permissions Active', - 'shelves_permissions_cascade_warning' => 'Permissions on shelves do not automatically cascade to contained books. This is because a book can exist on multiple shelves. Permissions can however be copied down to child books using the option found below.', - 'shelves_permissions_create' => 'Shelf create permissions are only used for copying permissions to child books using the action below. They do not control the ability to create books.', + 'shelves_edit_named' => 'Edita el prestatge :name', + 'shelves_edit' => 'Edita el prestatge', + 'shelves_delete' => 'Suprimeix el prestatge', + 'shelves_delete_named' => 'Suprimeix el prestatge :name', + 'shelves_delete_explain' => "Se suprimirà el prestatge amb el nom «:name». Els llibres que contingui no se suprimiran.", + 'shelves_delete_confirmation' => 'Segur que voleu suprimir aquest prestatge?', + 'shelves_permissions' => 'Permisos del prestatge', + 'shelves_permissions_updated' => 'S’han actualitzat els permisos del prestatge', + 'shelves_permissions_active' => 'Permisos del prestatge actius', + 'shelves_permissions_cascade_warning' => 'Els permisos dels prestatges no s’hereten automàticament en els llibres que contenen. És així perquè un llibre pot estar en múltiples prestatges. Es poden copiar, però, els permisos als llibres continguts fent servir l’opció a continuació.', + 'shelves_permissions_create' => 'Els permisos de crear prestatges només es fan servir per a copiar permisos a llibres continguts fent servir l’acció següent. No controlen la capacitat de crear llibres.', 'shelves_copy_permissions_to_books' => 'Copia els permisos als llibres', 'shelves_copy_permissions' => 'Copia els permisos', - 'shelves_copy_permissions_explain' => 'This will apply the current permission settings of this shelf to all books contained within. Before activating, ensure any changes to the permissions of this shelf have been saved.', - 'shelves_copy_permission_success' => 'Shelf permissions copied to :count books', + 'shelves_copy_permissions_explain' => 'S’aplicarà la configuració de permisos actual a tots els llibres continguts. Abans d’activar-la, assegureu-vos que hàgiu desat qualsevol canvi en els permisos d’aquest prestatge.', + 'shelves_copy_permission_success' => 'S’han copiat els permisos del prestatge a :count llibres', // Books 'book' => 'Llibre', @@ -126,44 +126,47 @@ return [ 'books_create' => 'Crea un llibre nou', 'books_delete' => 'Suprimeix el llibre', 'books_delete_named' => 'Suprimeix el llibre :bookName', - 'books_delete_explain' => 'Se suprimirà el llibre amb el nom \':bookName\'. Se\'n suprimiran les pàgines i els capítols.', + 'books_delete_explain' => 'Se suprimirà el llibre amb el nom «:bookName». Se’n suprimiran totes les pàgines i tots els capítols.', 'books_delete_confirmation' => 'Segur que voleu suprimir aquest llibre?', 'books_edit' => 'Edita el llibre', 'books_edit_named' => 'Edita el llibre :bookName', 'books_form_book_name' => 'Nom del llibre', 'books_save' => 'Desa el llibre', + 'books_default_template' => 'Plantilla de pàgina per defecte', + 'books_default_template_explain' => 'Assigneu una plantilla de pàgina que s’utilitzarà com a contingut per defecte de totes les pàgines noves d’aquest llibre. Tingueu en compte que només es farà servir si qui crea la pàgina té accés de visualització a la plantilla de pàgina elegida.', + 'books_default_template_select' => 'Seleccioneu una plantilla de pàgina', 'books_permissions' => 'Permisos del llibre', - 'books_permissions_updated' => 'S\'han actualitzat els permisos del llibre', + 'books_permissions_updated' => 'S’han actualitzat els permisos del llibre', 'books_empty_contents' => 'No hi ha cap pàgina ni cap capítol creat en aquest llibre.', 'books_empty_create_page' => 'Crea una pàgina nova', 'books_empty_sort_current_book' => 'Ordena el llibre actual', 'books_empty_add_chapter' => 'Afegeix un capítol', - 'books_permissions_active' => 'S\'han activat els permisos del llibre', + 'books_permissions_active' => 'S’han activat els permisos del llibre', 'books_search_this' => 'Cerca en aquest llibre', 'books_navigation' => 'Navegació pel llibre', 'books_sort' => 'Ordena el contingut del llibre', - 'books_sort_desc' => 'Move chapters and pages within a book to reorganise its contents. Other books can be added which allows easy moving of chapters and pages between books.', + 'books_sort_desc' => 'Moveu capítols i pàgines dins d’un llibre per a reorganitzar-ne el contingut. Podeu afegir altres llibres, la qual cosa permet moure fàcilment capítols i pàgines entre llibres.', 'books_sort_named' => 'Ordena el llibre :bookName', 'books_sort_name' => 'Ordena per nom', 'books_sort_created' => 'Ordena per data de creació', - 'books_sort_updated' => 'Ordena per data d\'actualització', + 'books_sort_updated' => 'Ordena per data d’actualització', 'books_sort_chapters_first' => 'Els capítols al principi', 'books_sort_chapters_last' => 'Els capítols al final', 'books_sort_show_other' => 'Mostra altres llibres', - 'books_sort_save' => 'Desa l\'ordre nou', - 'books_sort_show_other_desc' => 'Add other books here to include them in the sort operation, and allow easy cross-book reorganisation.', - 'books_sort_move_up' => 'Move Up', - 'books_sort_move_down' => 'Move Down', - 'books_sort_move_prev_book' => 'Move to Previous Book', - 'books_sort_move_next_book' => 'Move to Next Book', - 'books_sort_move_prev_chapter' => 'Move Into Previous Chapter', - 'books_sort_move_next_chapter' => 'Move Into Next Chapter', - 'books_sort_move_book_start' => 'Move to Start of Book', - 'books_sort_move_book_end' => 'Move to End of Book', - 'books_sort_move_before_chapter' => 'Move to Before Chapter', - 'books_sort_move_after_chapter' => 'Move to After Chapter', - 'books_copy' => 'Copy Book', - 'books_copy_success' => 'Book successfully copied', + 'books_sort_save' => 'Desa l’ordre nou', + 'books_sort_show_other_desc' => 'Afegiu aquí altres llibres per a incloure’ls a l’operació d’ordenació i permetre la reorganització entre llibres de manera fàcil.', + 'books_sort_move_up' => 'Mou amunt', + 'books_sort_move_down' => 'Mou avall', + 'books_sort_move_prev_book' => 'Mou al llibre anterior', + 'books_sort_move_next_book' => 'Mou al llibre següent', + 'books_sort_move_prev_chapter' => 'Mou al capítol anterior', + 'books_sort_move_next_chapter' => 'Mou al capítol següent', + 'books_sort_move_book_start' => 'Mou a l’inici del llibre', + 'books_sort_move_book_end' => 'Mou al final del llibre', + 'books_sort_move_before_chapter' => 'Mou al capítol anterior', + 'books_sort_move_after_chapter' => 'Mou al capítol següent', + 'books_copy' => 'Copia el llibre', + 'books_copy_success' => 'Llibre copiat correctament', // Chapters 'chapter' => 'Capítol', @@ -174,21 +177,21 @@ return [ 'chapters_create' => 'Crea un capítol nou', 'chapters_delete' => 'Suprimeix el capítol', 'chapters_delete_named' => 'Suprimeix el capítol :chapterName', - 'chapters_delete_explain' => 'Se suprimirà el capítol amb el nom \':chapterName\'. Totes les pàgines que contingui també se suprimiran.', + 'chapters_delete_explain' => 'Se suprimirà el capítol amb el nom «:chapterName». Totes les pàgines que contingui també se suprimiran.', 'chapters_delete_confirm' => 'Segur que voleu suprimir aquest capítol?', 'chapters_edit' => 'Edita el capítol', 'chapters_edit_named' => 'Edita el capítol :chapterName', 'chapters_save' => 'Desa el capítol', 'chapters_move' => 'Mou el capítol', 'chapters_move_named' => 'Mou el capítol :chapterName', - 'chapters_copy' => 'Copy Chapter', - 'chapters_copy_success' => 'Chapter successfully copied', + 'chapters_copy' => 'Copia el capítol', + 'chapters_copy_success' => 'Capítol copiat correctament', 'chapters_permissions' => 'Permisos del capítol', 'chapters_empty' => 'De moment, aquest capítol no conté cap pàgina.', - 'chapters_permissions_active' => 'S\'han activat els permisos del capítol', - 'chapters_permissions_success' => 'S\'han actualitzat els permisos del capítol', + 'chapters_permissions_active' => 'S’han activat els permisos del capítol', + 'chapters_permissions_success' => 'S’han actualitzat els permisos del capítol', 'chapters_search_this' => 'Cerca en aquest capítol', - 'chapter_sort_book' => 'Sort Book', + 'chapter_sort_book' => 'Ordena el llibre', // Pages 'page' => 'Pàgina', @@ -200,35 +203,36 @@ return [ 'pages_navigation' => 'Navegació per la pàgina', 'pages_delete' => 'Suprimeix la pàgina', 'pages_delete_named' => 'Suprimeix la pàgina :pageName', - 'pages_delete_draft_named' => 'Suprimeix l\'esborrany de pàgina :pageName', - 'pages_delete_draft' => 'Suprimeix l\'esborrany de pàgina', - 'pages_delete_success' => 'S\'ha suprimit la pàgina', - 'pages_delete_draft_success' => 'S\'ha suprimit l\'esborrany de pàgina', + 'pages_delete_draft_named' => 'Suprimeix l’esborrany de pàgina :pageName', + 'pages_delete_draft' => 'Suprimeix l’esborrany de pàgina', + 'pages_delete_success' => 'S’ha suprimit la pàgina', + 'pages_delete_draft_success' => 'S’ha suprimit l’esborrany de pàgina', + 'pages_delete_warning_template' => 'Aquesta pàgina es fa servir com a plantilla de pàgina per defecte en algun llibre. Quan l’hàgiu suprimida, aquests llibres ja no tindran assignada cap plantilla de pàgina per defecte.', 'pages_delete_confirm' => 'Segur que voleu suprimir aquesta pàgina?', 'pages_delete_draft_confirm' => 'Segur que voleu suprimir aquest esborrany de pàgina?', 'pages_editing_named' => 'Esteu editant :pageName', - 'pages_edit_draft_options' => 'Opcions d\'esborrany', - 'pages_edit_save_draft' => 'Desa l\'esborrany', - 'pages_edit_draft' => 'Edita l\'esborrany de pàgina', - 'pages_editing_draft' => 'Esteu editant l\'esborrany', + 'pages_edit_draft_options' => 'Opcions d’esborrany', + 'pages_edit_save_draft' => 'Desa l’esborrany', + 'pages_edit_draft' => 'Edita l’esborrany de pàgina', + 'pages_editing_draft' => 'Esteu editant l’esborrany', 'pages_editing_page' => 'Esteu editant la pàgina', 'pages_edit_draft_save_at' => 'Esborrany desat ', - 'pages_edit_delete_draft' => 'Suprimeix l\'esborrany', - 'pages_edit_delete_draft_confirm' => 'Are you sure you want to delete your draft page changes? All of your changes, since the last full save, will be lost and the editor will be updated with the latest page non-draft save state.', - 'pages_edit_discard_draft' => 'Descarta l\'esborrany', - 'pages_edit_switch_to_markdown' => 'Switch to Markdown Editor', - 'pages_edit_switch_to_markdown_clean' => '(Clean Content)', - 'pages_edit_switch_to_markdown_stable' => '(Stable Content)', - 'pages_edit_switch_to_wysiwyg' => 'Switch to WYSIWYG Editor', + 'pages_edit_delete_draft' => 'Suprimeix l’esborrany', + 'pages_edit_delete_draft_confirm' => 'Segur que voleu suprimir els canvis a l’esborrany de pàgina? Es perdran tots els vostres canvis d’ençà de la darrera vegada que heu desat i s’actualitzarà l’editor amb l’estat de la darrera pàgina desada sense ser un esborrany.', + 'pages_edit_discard_draft' => 'Descarta l’esborrany', + 'pages_edit_switch_to_markdown' => 'Canvia a l’editor Markdown', + 'pages_edit_switch_to_markdown_clean' => '(Contingut net)', + 'pages_edit_switch_to_markdown_stable' => '(Contingut estable)', + 'pages_edit_switch_to_wysiwyg' => 'Canvia a l’editor WYSIWYG', 'pages_edit_set_changelog' => 'Defineix el registre de canvis', 'pages_edit_enter_changelog_desc' => 'Introduïu una breu descripció dels canvis que heu fet', 'pages_edit_enter_changelog' => 'Introduïu un registre de canvis', - 'pages_editor_switch_title' => 'Switch Editor', - 'pages_editor_switch_are_you_sure' => 'Are you sure you want to change the editor for this page?', - 'pages_editor_switch_consider_following' => 'Consider the following when changing editors:', - 'pages_editor_switch_consideration_a' => 'Once saved, the new editor option will be used by any future editors, including those that may not be able to change editor type themselves.', - 'pages_editor_switch_consideration_b' => 'This can potentially lead to a loss of detail and syntax in certain circumstances.', - 'pages_editor_switch_consideration_c' => 'Tag or changelog changes, made since last save, won\'t persist across this change.', + 'pages_editor_switch_title' => 'Canvia d’editor', + 'pages_editor_switch_are_you_sure' => 'Segur que voleu canviar l’editor d’aquesta pàgina?', + 'pages_editor_switch_consider_following' => 'Considereu el següent en canviar d’editor:', + 'pages_editor_switch_consideration_a' => 'Quan hàgiu desat, l’opció del nou editor serà la que utilitzaran tots els futurs editors, incloent-hi els que no poden canviar de tipus d’editor amb el seu usuari.', + 'pages_editor_switch_consideration_b' => 'En algunes circumstàncies, això pot comportar una pèrdua de detalls i de sintaxi.', + 'pages_editor_switch_consideration_c' => 'Els canvis al registre de canvis o a les etiquetes fets d’ençà de la darrera vegada que s’ha desat no es mantindran en aquest canvi.', 'pages_save' => 'Desa la pàgina', 'pages_title' => 'Títol de la pàgina', 'pages_name' => 'Nom de la pàgina', @@ -237,110 +241,110 @@ return [ 'pages_md_insert_image' => 'Insereix una imatge', 'pages_md_insert_link' => 'Insereix un enllaç a una entitat', 'pages_md_insert_drawing' => 'Insereix un diagrama', - 'pages_md_show_preview' => 'Show preview', - 'pages_md_sync_scroll' => 'Sync preview scroll', - 'pages_drawing_unsaved' => 'Unsaved Drawing Found', - 'pages_drawing_unsaved_confirm' => 'Unsaved drawing data was found from a previous failed drawing save attempt. Would you like to restore and continue editing this unsaved drawing?', + 'pages_md_show_preview' => 'Mostra la previsualització', + 'pages_md_sync_scroll' => 'Sincronitza el desplaçament de la previsualització', + 'pages_drawing_unsaved' => 'S’ha trobat un diagrama no desat', + 'pages_drawing_unsaved_confirm' => 'S’han trobat dades d’un diagrama d’un intent de desat fallit anterior. Voleu restaurar-les i continuar editant aquest diagrama no desat?', 'pages_not_in_chapter' => 'La pàgina no pertany a cap capítol', 'pages_move' => 'Mou la pàgina', 'pages_copy' => 'Copia la pàgina', 'pages_copy_desination' => 'Destinació de la còpia', 'pages_copy_success' => 'Pàgina copiada correctament', 'pages_permissions' => 'Permisos de la pàgina', - 'pages_permissions_success' => 'S\'han actualitzat els permisos de la pàgina', + 'pages_permissions_success' => 'S’han actualitzat els permisos de la pàgina', 'pages_revision' => 'Revisió', 'pages_revisions' => 'Revisions de la pàgina', - 'pages_revisions_desc' => 'Listed below are all the past revisions of this page. You can look back upon, compare, and restore old page versions if permissions allow. The full history of the page may not be fully reflected here since, depending on system configuration, old revisions could be auto-deleted.', + 'pages_revisions_desc' => 'A continuació hi ha les revisions anteriors de la pàgina. Podeu mirar-les, comparar-les i restaurar-ne versions antigues si us ho permeten els permisos. És possible que l’historial complet de la pàgina no s’hi vegi reflectit perquè, depenent de la configuració del sistema, es poden haver esborrat automàticament revisions antigues.', 'pages_revisions_named' => 'Revisions de la pàgina :pageName', 'pages_revision_named' => 'Revisió de la pàgina :pageName', 'pages_revision_restored_from' => 'Restaurada de núm. :id; :summary', 'pages_revisions_created_by' => 'Creada per', 'pages_revisions_date' => 'Data de la revisió', 'pages_revisions_number' => 'Núm. ', - 'pages_revisions_sort_number' => 'Revision Number', + 'pages_revisions_sort_number' => 'Número de revisió', 'pages_revisions_numbered' => 'Revisió núm. :id', 'pages_revisions_numbered_changes' => 'Canvis de la revisió núm. :id', - 'pages_revisions_editor' => 'Editor Type', + 'pages_revisions_editor' => 'Tipus d’editor', 'pages_revisions_changelog' => 'Registre de canvis', 'pages_revisions_changes' => 'Canvis', 'pages_revisions_current' => 'Versió actual', 'pages_revisions_preview' => 'Previsualitza', 'pages_revisions_restore' => 'Restaura', 'pages_revisions_none' => 'Aquesta pàgina no té cap revisió', - 'pages_copy_link' => 'Copia l\'enllaç', - 'pages_edit_content_link' => 'Jump to section in editor', - 'pages_pointer_enter_mode' => 'Enter section select mode', - 'pages_pointer_label' => 'Page Section Options', - 'pages_pointer_permalink' => 'Page Section Permalink', - 'pages_pointer_include_tag' => 'Page Section Include Tag', - 'pages_pointer_toggle_link' => 'Permalink mode, Press to show include tag', - 'pages_pointer_toggle_include' => 'Include tag mode, Press to show permalink', - 'pages_permissions_active' => 'S\'han activat els permisos de la pàgina', + 'pages_copy_link' => 'Copia l’enllaç', + 'pages_edit_content_link' => 'Vés a la secció a l’editor', + 'pages_pointer_enter_mode' => 'Activa el mode de selecció de secció', + 'pages_pointer_label' => 'Opcions de la secció de la pàgina', + 'pages_pointer_permalink' => 'Enllaç permanent de la secció de la pàgina', + 'pages_pointer_include_tag' => 'Etiqueta d’inclusió de la secció de la pàgina', + 'pages_pointer_toggle_link' => 'Mode d’enllaç permanent, premeu per a mostrar l’etiqueta d‘inclusió', + 'pages_pointer_toggle_include' => 'Mode d’etiqueta d’inclusió, premeu per a mostrar l’enllaç permanent', + 'pages_permissions_active' => 'S’han activat els permisos de la pàgina', 'pages_initial_revision' => 'Publicació inicial', - 'pages_references_update_revision' => 'System auto-update of internal links', + 'pages_references_update_revision' => 'Actualització automàtica dels enllaços interns del sistema', 'pages_initial_name' => 'Pàgina nova', 'pages_editing_draft_notification' => 'Esteu editant un esborrany que es va desar per darrer cop :timeDiff.', - 'pages_draft_edited_notification' => 'Aquesta pàgina s\'ha actualitzat d\'ençà d\'aleshores. Us recomanem que descarteu aquest esborrany.', - 'pages_draft_page_changed_since_creation' => 'This page has been updated since this draft was created. It is recommended that you discard this draft or take care not to overwrite any page changes.', + 'pages_draft_edited_notification' => 'Aquesta pàgina s’ha actualitzat d’ençà d’aleshores. Us recomanem que descarteu aquest esborrany.', + 'pages_draft_page_changed_since_creation' => 'Aquesta pàgina s’ha actualitzat d‘ençà que es va crear l’esborrany. Us recomanem que descarteu aquest esborrany i que aneu amb compte de no sobreescriure els canvis de la pàgina.', 'pages_draft_edit_active' => [ 'start_a' => ':count usuaris han començat a editar aquesta pàgina', 'start_b' => ':userName ha començat a editar aquesta pàgina', - 'time_a' => 'd\'ençà que la pàgina es va actualitzar per darrer cop', + 'time_a' => 'd’ençà que la pàgina es va actualitzar per darrer cop', 'time_b' => 'en els darrers :minCount minuts', 'message' => ':start :time. Aneu amb compte de no trepitjar-vos les actualitzacions entre vosaltres!', ], - 'pages_draft_discarded' => 'Draft discarded! The editor has been updated with the current page content', - 'pages_draft_deleted' => 'Draft deleted! The editor has been updated with the current page content', + 'pages_draft_discarded' => 'S’ha descartat l’esborrany! S’ha actualitzat l’editor amb el contingut actual de la pàgina', + 'pages_draft_deleted' => 'S’ha suprimit l’esborrany! S’ha actualitzat l’editor amb el contingut actual de la pàgina', 'pages_specific' => 'Una pàgina específica', 'pages_is_template' => 'Plantilla de pàgina', // Editor Sidebar - 'toggle_sidebar' => 'Toggle Sidebar', + 'toggle_sidebar' => 'Commuta la barra lateral', 'page_tags' => 'Etiquetes de la pàgina', 'chapter_tags' => 'Etiquetes del capítol', 'book_tags' => 'Etiquetes del llibre', 'shelf_tags' => 'Etiquetes del prestatge', 'tag' => 'Etiqueta', 'tags' => 'Etiquetes', - 'tags_index_desc' => 'Tags can be applied to content within the system to apply a flexible form of categorization. Tags can have both a key and value, with the value being optional. Once applied, content can then be queried using the tag name and value.', - 'tag_name' => 'Nom de l\'etiqueta', - 'tag_value' => 'Valor de l\'etiqueta (opcional)', + 'tags_index_desc' => 'Es poden aplicar etiquetes al contingut dins del sistema per a aplicar un mode de categorització flexible. Les etiquetes poden tenir una clau i un valor, però el valor és opcional. Quan s’han aplican, el contingut es pot cercar fent servir el nom o el valor de l’etiqueta.', + 'tag_name' => 'Nom de l’etiqueta', + 'tag_value' => 'Valor de l’etiqueta (opcional)', 'tags_explain' => "Afegiu etiquetes per a categoritzar millor el contingut. \n Podeu assignar un valor a cada etiqueta per a una organització més detallada.", 'tags_add' => 'Afegeix una altra etiqueta', 'tags_remove' => 'Elimina aquesta etiqueta', - 'tags_usages' => 'Total tag usages', - 'tags_assigned_pages' => 'Assigned to Pages', - 'tags_assigned_chapters' => 'Assigned to Chapters', - 'tags_assigned_books' => 'Assigned to Books', - 'tags_assigned_shelves' => 'Assigned to Shelves', - 'tags_x_unique_values' => ':count unique values', - 'tags_all_values' => 'All values', - 'tags_view_tags' => 'View Tags', - 'tags_view_existing_tags' => 'View existing tags', - 'tags_list_empty_hint' => 'Tags can be assigned via the page editor sidebar or while editing the details of a book, chapter or shelf.', + 'tags_usages' => 'Usos totals de l’etiqueta', + 'tags_assigned_pages' => 'Assignada a pàgines', + 'tags_assigned_chapters' => 'Assignada a capítols', + 'tags_assigned_books' => 'Assignada a llibres', + 'tags_assigned_shelves' => 'Assignada a prestatges', + 'tags_x_unique_values' => ':count valors únics', + 'tags_all_values' => 'Tots els valors', + 'tags_view_tags' => 'Mostra les etiquetes', + 'tags_view_existing_tags' => 'Mostra les etiquetes existents', + 'tags_list_empty_hint' => 'Es poden assignar etiquetes mitjançant la barra lateral de l’editor de la pàgina o quan s’editen els detalls d’un llibre, capítol o prestatge.', 'attachments' => 'Adjuncions', 'attachments_explain' => 'Pugeu fitxers o adjunteu enllaços per a mostrar-los a la pàgina. Són visibles a la barra lateral de la pàgina.', 'attachments_explain_instant_save' => 'Els canvis fets aquí es desen instantàniament.', 'attachments_upload' => 'Puja un fitxer', 'attachments_link' => 'Adjunta un enllaç', - 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.', - 'attachments_set_link' => 'Defineix l\'enllaç', - 'attachments_delete' => 'Seguir que voleu suprimir aquesta adjunció?', - 'attachments_dropzone' => 'Drop files here to upload', - 'attachments_no_files' => 'No s\'ha pujat cap fitxer', + 'attachments_upload_drop' => 'De manera alternativa, podeu arrossegar i deixar anar un fitxer aquí per a pujar-lo com a adjunció.', + 'attachments_set_link' => 'Defineix l’enllaç', + 'attachments_delete' => 'Segur que voleu suprimir aquesta adjunció?', + 'attachments_dropzone' => 'Deixeu anar fitxers aquí per a pujar-los', + 'attachments_no_files' => 'No s’ha pujat cap fitxer', 'attachments_explain_link' => 'Podeu adjuntar un enllaç si preferiu no pujar un fitxer. Pot ser un enllaç a una altra pàgina o un enllaç a un fitxer al núvol.', - 'attachments_link_name' => 'Nom de l\'enllaç', - 'attachment_link' => 'Enllaç de l\'adjunció', + 'attachments_link_name' => 'Nom de l’enllaç', + 'attachment_link' => 'Enllaç de l’adjunció', 'attachments_link_url' => 'Enllaç al fitxer', 'attachments_link_url_hint' => 'URL del lloc o fitxer', 'attach' => 'Adjunta', - 'attachments_insert_link' => 'Afegeix un enllaç de l\'adjunció a la pàgina', + 'attachments_insert_link' => 'Afegeix un enllaç de l’adjunció a la pàgina', 'attachments_edit_file' => 'Edita el fitxer', 'attachments_edit_file_name' => 'Nom del fitxer', - 'attachments_edit_drop_upload' => 'Arrossegueu fitxers o feu clic aquí per a pujar-los i sobreescriure\'ls', - 'attachments_order_updated' => 'S\'ha actualitzat l\'ordre de les adjuncions', - 'attachments_updated_success' => 'S\'han actualitzat els detalls de les adjuncions', - 'attachments_deleted' => 'S\'ha suprimit l\'adjunció', + 'attachments_edit_drop_upload' => 'Arrossegueu fitxers o feu clic aquí per a pujar-los i sobreescriure’ls', + 'attachments_order_updated' => 'S’ha actualitzat l’ordre de les adjuncions', + 'attachments_updated_success' => 'S’han actualitzat els detalls de les adjuncions', + 'attachments_deleted' => 'S’ha suprimit l’adjunció', 'attachments_file_uploaded' => 'Fitxer pujat correctament', 'attachments_file_updated' => 'Fitxer actualitzat correctament', 'attachments_link_attached' => 'Enllaç adjuntat a la pàgina correctament', @@ -369,13 +373,13 @@ return [ 'comment_new' => 'Comentari nou', 'comment_created' => 'ha comentat :createDiff', 'comment_updated' => 'Actualitzat :updateDiff per :username', - 'comment_updated_indicator' => 'Updated', + 'comment_updated_indicator' => 'Actualitzat', 'comment_deleted_success' => 'Comentari suprimit', 'comment_created_success' => 'Comentari afegit', 'comment_updated_success' => 'Comentari actualitzat', 'comment_delete_confirm' => 'Segur que voleu suprimir aquest comentari?', 'comment_in_reply_to' => 'En resposta a :commentId', - 'comment_editor_explain' => 'Here are the comments that have been left on this page. Comments can be added & managed when viewing the saved page.', + 'comment_editor_explain' => 'Aquí hi ha els comentaris que s’han deixat en aquesta pàgina. Els comentaris es poden afegir i gestionar en veure una pàgina desada.', // Revision 'revision_delete_confirm' => 'Segur que voleu suprimir aquesta revisió?', @@ -383,51 +387,51 @@ return [ 'revision_cannot_delete_latest' => 'No es pot suprimir la darrera revisió.', // Copy view - 'copy_consider' => 'Please consider the below when copying content.', - 'copy_consider_permissions' => 'Custom permission settings will not be copied.', - 'copy_consider_owner' => 'You will become the owner of all copied content.', - 'copy_consider_images' => 'Page image files will not be duplicated & the original images will retain their relation to the page they were originally uploaded to.', - 'copy_consider_attachments' => 'Page attachments will not be copied.', - 'copy_consider_access' => 'A change of location, owner or permissions may result in this content being accessible to those previously without access.', + 'copy_consider' => 'Tingueu en compte el següent quan copieu contingut.', + 'copy_consider_permissions' => 'No es copiarà la configuració personalitzada de permisos.', + 'copy_consider_owner' => 'Esdevindreu el nou propietari de qualsevol contingut copiat.', + 'copy_consider_images' => 'Els fitxers d’imatge de les pàgines no es duplicaran i les imatges originals mantindran la relació amb la pàgina a la qual es van pujar originalment.', + 'copy_consider_attachments' => 'No es copiaran les adjuncions de la pàgina.', + 'copy_consider_access' => 'Un canvi d’ubicació, propietari o permisos pot provocar que aquest contingut esdevingui accessible a públic que abans no n’hi tenia.', // Conversions - 'convert_to_shelf' => 'Convert to Shelf', - 'convert_to_shelf_contents_desc' => 'You can convert this book to a new shelf with the same contents. Chapters contained within this book will be converted to new books. If this book contains any pages, that are not in a chapter, this book will be renamed and contain such pages, and this book will become part of the new shelf.', - 'convert_to_shelf_permissions_desc' => 'Any permissions set on this book will be copied to the new shelf and to all new child books that don\'t have their own permissions enforced. Note that permissions on shelves do not auto-cascade to content within, as they do for books.', - 'convert_book' => 'Convert Book', - 'convert_book_confirm' => 'Are you sure you want to convert this book?', - 'convert_undo_warning' => 'This cannot be as easily undone.', - 'convert_to_book' => 'Convert to Book', - 'convert_to_book_desc' => 'You can convert this chapter to a new book with the same contents. Any permissions set on this chapter will be copied to the new book but any inherited permissions, from the parent book, will not be copied which could lead to a change of access control.', - 'convert_chapter' => 'Convert Chapter', - 'convert_chapter_confirm' => 'Are you sure you want to convert this chapter?', + 'convert_to_shelf' => 'Converteix en prestatge', + 'convert_to_shelf_contents_desc' => 'Podeu convertir aquest llibre en un prestatge nou amb el mateix contingut. Els capítols continguts en aquest llibre es convertiran en nous lliures. Si aquest llibre conté pàgines que no pertanyin a cap capítol, aquest llibre canviarà de nom i les contindrà, i aquest llibre esdevindrà part del nou prestatge.', + 'convert_to_shelf_permissions_desc' => 'Qualsevol permís definit en aquest llibre es copiarà al nou prestatge i a tots els nous llibres fills que no tinguin permisos explícits. Tingueu en compte que els permisos dels prestatges no s’hereten automàticament al contingut que continguin de la mateixa manera que passa amb els llibres.', + 'convert_book' => 'Converteix el llibre', + 'convert_book_confirm' => 'Segur que voleu convertir aquest llibre?', + 'convert_undo_warning' => 'No es podrà desfer de manera fàcil.', + 'convert_to_book' => 'Converteix en llibre', + 'convert_to_book_desc' => 'Podeu convertir aquest capítol en un llibre nou amb el mateix contingut. Qualsevol permís definit en aquest capítol es copiarà al nou llibre, però qualsevol permís heretat del llibre pare no es copiarà, la qual cosa podria implicar canvis en el control d’accés.', + 'convert_chapter' => 'Converteix el capítol', + 'convert_chapter_confirm' => 'Segur que voleu convertir aquest capítol?', // References - 'references' => 'References', - 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references' => 'Referències', + 'references_none' => 'Ni hi ha cap referència detectada a aquest element.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options - 'watch' => 'Watch', - 'watch_title_default' => 'Default Preferences', - 'watch_desc_default' => 'Revert watching to just your default notification preferences.', - 'watch_title_ignore' => 'Ignore', - 'watch_desc_ignore' => 'Ignore all notifications, including those from user-level preferences.', - 'watch_title_new' => 'New Pages', - 'watch_desc_new' => 'Notify when any new page is created within this item.', - 'watch_title_updates' => 'All Page Updates', - 'watch_desc_updates' => 'Notify upon all new pages and page changes.', - 'watch_desc_updates_page' => 'Notify upon all page changes.', - 'watch_title_comments' => 'All Page Updates & Comments', - 'watch_desc_comments' => 'Notify upon all new pages, page changes and new comments.', - 'watch_desc_comments_page' => 'Notify upon page changes and new comments.', - 'watch_change_default' => 'Change default notification preferences', - 'watch_detail_ignore' => 'Ignoring notifications', - 'watch_detail_new' => 'Watching for new pages', - 'watch_detail_updates' => 'Watching new pages and updates', - 'watch_detail_comments' => 'Watching new pages, updates & comments', - 'watch_detail_parent_book' => 'Watching via parent book', - 'watch_detail_parent_book_ignore' => 'Ignoring via parent book', - 'watch_detail_parent_chapter' => 'Watching via parent chapter', - 'watch_detail_parent_chapter_ignore' => 'Ignoring via parent chapter', + 'watch' => 'Segueix', + 'watch_title_default' => 'Preferències per defecte', + 'watch_desc_default' => 'Restableix el seguiment a només les preferències de notificació per defecte.', + 'watch_title_ignore' => 'Ignora', + 'watch_desc_ignore' => 'Ignora totes les notificacions, incloent-hi les preferències a nivell d’usuari.', + 'watch_title_new' => 'Pàgines noves', + 'watch_desc_new' => 'Notifica’m quan es creï qualsevol pàgina nova dins d’aquest element.', + 'watch_title_updates' => 'Totes les actualitzacions de pàgines', + 'watch_desc_updates' => 'Notifica’m totes les pàgines noves i qualsevol canvi de pàgina.', + 'watch_desc_updates_page' => 'Notifica’m tots els canvis de pàgina.', + 'watch_title_comments' => 'Totes les actualitzacions de pàgines i comentaris', + 'watch_desc_comments' => 'Notifica’m totes les pàgines noves, qualsevol canvi de pàgina i comentaris nous.', + 'watch_desc_comments_page' => 'Notifica’m qualsevol canvi de pàgina i comentaris nous.', + 'watch_change_default' => 'Canvieu les preferències de notificació per deecte', + 'watch_detail_ignore' => 'S’ignoren les notificacions', + 'watch_detail_new' => 'Se segueixen pàgines noves', + 'watch_detail_updates' => 'Se segueixen pàgines noves i actualitzacions', + 'watch_detail_comments' => 'Se segueixen pàgines noves, actualitzacions i comentaris', + 'watch_detail_parent_book' => 'Se segueix mitjançant el llibre pare', + 'watch_detail_parent_book_ignore' => 'S’ignora mitjançant el llibre pare', + 'watch_detail_parent_chapter' => 'Se segueix mitjançant el capítol pare', + 'watch_detail_parent_chapter_ignore' => 'S’ignora mitjançant el capítol pare', ]; diff --git a/lang/ca/errors.php b/lang/ca/errors.php index ba53bd849..22ecb2b0e 100644 --- a/lang/ca/errors.php +++ b/lang/ca/errors.php @@ -6,115 +6,114 @@ return [ // Permissions 'permission' => 'No teniu permís per a accedir a la pàgina sol·licitada.', - 'permissionJson' => 'No teniu permís per a executar l\'acció sol·licitada.', + 'permissionJson' => 'No teniu permís per a executar l’acció sol·licitada.', // Auth - 'error_user_exists_different_creds' => 'Ja hi ha un usuari amb l\'adreça electrònica :email però amb credencials diferents.', - 'email_already_confirmed' => 'L\'adreça electrònica ja està confirmada. Proveu d\'iniciar la sessió.', - 'email_confirmation_invalid' => 'Aquest testimoni de confirmació no és vàlid o ja ha estat utilitzat. Proveu de tornar-vos a registrar.', - 'email_confirmation_expired' => 'El testimoni de confirmació ha caducat. S\'ha enviat un nou correu electrònic de confirmació.', - 'email_confirmation_awaiting' => 'Cal confirmar l\'adreça electrònica del compte que utilitzeu', - 'ldap_fail_anonymous' => 'L\'accés a l\'LDAP ha fallat fent servir un lligam anònim', - 'ldap_fail_authed' => 'L\'accés a l\'LDAP ha fallat fent servir els detalls de DN i contrasenya proporcionats', - 'ldap_extension_not_installed' => 'L\'extensió de l\'LDAP de PHP no està instal·lada', - 'ldap_cannot_connect' => 'No s\'ha pogut connectar amb el servidor de l\'LDAP, la connexió inicial ha fallat', + 'error_user_exists_different_creds' => 'Ja hi ha un usuari amb l’adreça electrònica :email però amb credencials diferents.', + 'email_already_confirmed' => 'L’adreça electrònica ja està confirmada. Proveu d’iniciar la sessió.', + 'email_confirmation_invalid' => 'Aquest testimoni de confirmació no és vàlid o ja s’ha utilitzat. Proveu de tornar-vos a registrar.', + 'email_confirmation_expired' => 'El testimoni de confirmació ha caducat. S’ha enviat un nou correu electrònic de confirmació.', + 'email_confirmation_awaiting' => 'Cal confirmar l’adreça electrònica del compte que utilitzeu', + 'ldap_fail_anonymous' => 'L’accés a l’LDAP ha fallat fent servir un lligam anònim', + 'ldap_fail_authed' => 'L’accés a l’LDAP ha fallat fent servir els detalls de DN i contrasenya proporcionats', + 'ldap_extension_not_installed' => 'L’extensió de l’LDAP del PHP no està instal·lada', + 'ldap_cannot_connect' => 'No s’ha pogut connectar amb el servidor de l’LDAP, la connexió inicial ha fallat', 'saml_already_logged_in' => 'Ja heu iniciat la sessió', - 'saml_user_not_registered' => 'L\'usuari :name no està registrat i els registres automàtics estan desactivats', - 'saml_no_email_address' => 'No s\'ha pogut trobar cap adreça electrònica, per a aquest usuari, en les dades proporcionades pel sistema d\'autenticació extern', - 'saml_invalid_response_id' => 'La petició del sistema d\'autenticació extern no és reconeguda per un procés iniciat per aquesta aplicació. Aquest problema podria ser causat per navegar endarrere després d\'iniciar la sessió.', - 'saml_fail_authed' => 'L\'inici de sessió fent servir :system ha fallat, el sistema no ha proporcionat una autorització satisfactòria', - 'oidc_already_logged_in' => 'Already logged in', - 'oidc_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', - 'oidc_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', - 'oidc_fail_authed' => 'Login using :system failed, system did not provide successful authorization', + 'saml_no_email_address' => 'No s’ha pogut trobar cap adreça electrònica per a aquest usuari en les dades proporcionades pel sistema d’autenticació extern', + 'saml_invalid_response_id' => 'La petició del sistema d’autenticació extern no és reconeguda per un procés iniciat per aquesta aplicació. Aquest problema podria ser causat per navegar endarrere després d’iniciar la sessió.', + 'saml_fail_authed' => 'L’inici de sessió fent servir :system ha fallat, el sistema no ha proporcionat una autorització satisfactòria', + 'oidc_already_logged_in' => 'Ja teniu una sessió iniciada', + 'oidc_user_not_registered' => 'L’usuari :name no està registrat i els registres automàtics estan desactivats', + 'oidc_no_email_address' => 'No s’ha pogut trobar cap adreça electrònica per a aquest usuari en les dades proporcionades pel sistema d’autenticació extern', + 'oidc_fail_authed' => 'L’inici de sessió fent servir :system ha fallat, el sistema no ha proporcionat una autorització satisfactòria', 'social_no_action_defined' => 'No hi ha cap acció definida', - 'social_login_bad_response' => "S'ha rebut un error mentre s'iniciava la sessió amb :socialAccount: \n:error", - 'social_account_in_use' => 'Aquest compte de :socialAccount ja està en ús, proveu d\'iniciar la sessió mitjançant l\'opció de :socialAccount.', - 'social_account_email_in_use' => 'L\'adreça electrònica :email ja està en ús. Si ja teniu un compte, podeu connectar-hi el vostre compte de :socialAccount a la configuració del vostre perfil.', + 'social_login_bad_response' => "S’ha rebut un error mentre s’iniciava la sessió amb :socialAccount: \n:error", + 'social_account_in_use' => 'Aquest compte de :socialAccount ja està en ús, proveu d’iniciar la sessió mitjançant l’opció de :socialAccount.', + 'social_account_email_in_use' => 'L’adreça electrònica :email ja està en ús. Si ja teniu un compte, podeu connectar-hi el vostre compte de :socialAccount a la configuració del vostre perfil.', 'social_account_existing' => 'Aquest compte de :socialAccount ja està associat al vostre perfil.', 'social_account_already_used_existing' => 'Aquest compte de :socialAccount ja el fa servir un altre usuari.', 'social_account_not_used' => 'Aquest compte de :socialAccount no està associat a cap usuari. Associeu-lo a la configuració del vostre perfil. ', - 'social_account_register_instructions' => 'Si encara no teniu cap compte, podeu registrar-vos fent servir l\'opció de :socialAccount.', - 'social_driver_not_found' => 'No s\'ha trobat el controlador social', + 'social_account_register_instructions' => 'Si encara no teniu cap compte, podeu registrar-vos fent servir l’opció de :socialAccount.', + '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.', + 'invite_token_expired' => 'Aquest enllaç d’invitació ha caducat. Podeu provar de restablir la contrasenya del vostre compte.', // System - 'path_not_writable' => 'No s\'ha pogut pujar al camí del fitxer :filePath. Assegureu-vos que el servidor hi té permisos d\'escriptura.', - 'cannot_get_image_from_url' => 'No s\'ha pogut obtenir la imatge de :url', - 'cannot_create_thumbs' => 'El servidor no pot crear miniatures. Reviseu que tingueu instal·lada l\'extensió GD del PHP.', - 'server_upload_limit' => 'El servidor no permet pujades d\'aquesta mida. Proveu-ho amb una mida de fitxer més petita.', - 'server_post_limit' => 'The server cannot receive the provided amount of data. Try again with less data or a smaller file.', - 'uploaded' => 'El servidor no permet pujades d\'aquesta mida. Proveu-ho amb una mida de fitxer més petita.', + 'path_not_writable' => 'No s’ha pogut pujar al camí del fitxer :filePath. Assegureu-vos que el servidor hi té permisos d’escriptura.', + 'cannot_get_image_from_url' => 'No s’ha pogut obtenir la imatge de :url', + 'cannot_create_thumbs' => 'El servidor no pot crear miniatures. Reviseu que tingueu instal·lada l’extensió GD del PHP.', + 'server_upload_limit' => 'El servidor no permet pujades d’aquesta mida. Proveu-ho amb una mida de fitxer més petita.', + 'server_post_limit' => 'El servidor no pot rebre la quantitat de dades que heu proporcionat. Torneu-ho a provar amb menys dades o un fitxer més petit.', + 'uploaded' => 'El servidor no permet pujades d’aquesta mida. Proveu-ho amb una mida de fitxer més petita.', // Drawing & Images - 'image_upload_error' => 'S\'ha produït un error en pujar la imatge', - 'image_upload_type_error' => 'El tipus d\'imatge que heu pujat no és vàlid', - 'image_upload_replace_type' => 'Image file replacements must be of the same type', - 'image_upload_memory_limit' => 'Failed to handle image upload and/or create thumbnails due to system resource limits.', - 'image_thumbnail_memory_limit' => 'Failed to create image size variations due to system resource limits.', - 'image_gallery_thumbnail_memory_limit' => 'Failed to create gallery thumbnails due to system resource limits.', - 'drawing_data_not_found' => 'Drawing data could not be loaded. The drawing file might no longer exist or you may not have permission to access it.', + 'image_upload_error' => 'S’ha produït un error en pujar la imatge', + 'image_upload_type_error' => 'El tipus d’imatge que heu pujat no és vàlid', + 'image_upload_replace_type' => 'Les substitucions de fitxers d’imatge han de ser el mateix tipus', + 'image_upload_memory_limit' => 'No s’ha pogut gestionar la pujada de la imatge i/o crear-ne miniatures a causa dels límits dels recursos del sistema.', + 'image_thumbnail_memory_limit' => 'No s’ha pogut crear les variacions de mida de la imatge a causa dels límits dels recursos del sistema.', + 'image_gallery_thumbnail_memory_limit' => 'No s’han pogut crear les miniatures de la galeria a causa dels límits dels recursos del sistema.', + 'drawing_data_not_found' => 'No s’han pogut carregar les dades de dibuix. És possible que el fitxer de dibuix ja no existeixi o que no tingueu permisos per a accedir-hi.', // Attachments - 'attachment_not_found' => 'No s\'ha trobat l\'adjunció', - 'attachment_upload_error' => 'An error occurred uploading the attachment file', + 'attachment_not_found' => 'No s’ha trobat l’adjunció', + 'attachment_upload_error' => 'S’ha produït un error en pujar el fitxer de l’adjunció', // Pages - 'page_draft_autosave_fail' => 'No s\'ha pogut desar l\'esborrany. Assegureu-vos que tingueu connexió a Internet abans de desar la pàgina', - 'page_draft_delete_fail' => 'Failed to delete page draft and fetch current page saved content', - 'page_custom_home_deletion' => 'No es pot suprimir una pàgina mentre estigui definida com a pàgina d\'inici', + 'page_draft_autosave_fail' => 'No s’ha pogut desar l’esborrany. Assegureu-vos que teniu connexió a Internet abans de desar la pàgina', + 'page_draft_delete_fail' => 'No s’ha pogut suprimir l’esborrany de la pàgina i obtenir el contingut desat actual de la pàgina', + 'page_custom_home_deletion' => 'No es pot suprimir una pàgina mentre estigui definida com a pàgina d’inici', // Entities - 'entity_not_found' => 'No s\'ha trobat l\'entitat', - 'bookshelf_not_found' => 'Shelf not found', - 'book_not_found' => 'No s\'ha trobat el llibre', - 'page_not_found' => 'No s\'ha trobat la pàgina', - 'chapter_not_found' => 'No s\'ha trobat el capítol', - 'selected_book_not_found' => 'No s\'ha trobat el llibre seleccionat', - 'selected_book_chapter_not_found' => 'No s\'ha trobat el llibre o el capítol seleccionat', + 'entity_not_found' => 'No s’ha trobat l’entitat', + 'bookshelf_not_found' => 'No s’ha trobat el prestatge', + 'book_not_found' => 'No s’ha trobat el llibre', + 'page_not_found' => 'No s’ha trobat la pàgina', + 'chapter_not_found' => 'No s’ha trobat el capítol', + 'selected_book_not_found' => 'No s’ha trobat el llibre seleccionat', + 'selected_book_chapter_not_found' => 'No s’ha trobat el llibre o el capítol seleccionat', 'guests_cannot_save_drafts' => 'Els convidats no poden desar esborranys', // Users - 'users_cannot_delete_only_admin' => 'No podeu suprimir l\'únic administrador', - 'users_cannot_delete_guest' => 'No podeu suprimir l\'usuari convidat', + 'users_cannot_delete_only_admin' => 'No podeu suprimir l’únic administrador', + 'users_cannot_delete_guest' => 'No podeu suprimir l’usuari convidat', // Roles 'role_cannot_be_edited' => 'Aquest rol no es pot editar', 'role_system_cannot_be_deleted' => 'Aquest rol és un rol del sistema i no es pot suprimir', 'role_registration_default_cannot_delete' => 'No es pot suprimir aquest rol mentre estigui definit com a rol per defecte dels registres', - 'role_cannot_remove_only_admin' => 'Aquest usuari és l\'únic usuari assignat al rol d\'administrador. Assigneu el rol d\'administrador a un altre usuari abans de provar de suprimir aquest.', + 'role_cannot_remove_only_admin' => 'Aquest usuari és l’únic usuari assignat al rol d’administrador. Assigneu el rol d’administrador a un altre usuari abans de provar de suprimir aquest.', // Comments - 'comment_list' => 'S\'ha produït un error en obtenir els comentaris.', + 'comment_list' => 'S’ha produït un error en obtenir els comentaris.', 'cannot_add_comment_to_draft' => 'No podeu afegir comentaris a un esborrany.', - 'comment_add' => 'S\'ha produït un error en afegir o actualitzar el comentari.', - 'comment_delete' => 'S\'ha produït un error en suprimir el comentari.', + 'comment_add' => 'S’ha produït un error en afegir o actualitzar el comentari.', + 'comment_delete' => 'S’ha produït un error en suprimir el comentari.', 'empty_comment' => 'No podeu afegir un comentari buit.', // Error pages - '404_page_not_found' => 'No s\'ha trobat la pàgina', + '404_page_not_found' => 'No s’ha trobat la pàgina', 'sorry_page_not_found' => 'No hem pogut trobar la pàgina que cerqueu.', 'sorry_page_not_found_permission_warning' => 'Si esperàveu que existís, és possible que no tingueu permisos per a veure-la.', - 'image_not_found' => 'Image Not Found', - 'image_not_found_subtitle' => 'Sorry, The image file you were looking for could not be found.', - 'image_not_found_details' => 'If you expected this image to exist it might have been deleted.', - 'return_home' => 'Torna a l\'inici', - 'error_occurred' => 'S\'ha produït un error', + 'image_not_found' => 'No s’ha trobat la imatge', + 'image_not_found_subtitle' => 'No ha estat possible trobar el fitxer de la imatge que cerqueu.', + 'image_not_found_details' => 'Si esperàveu que existís, és possible que s’hagi suprimit.', + 'return_home' => 'Torna a l’inici', + 'error_occurred' => 'S’ha produït un error', 'app_down' => ':appName està fora de servei en aquests moments', 'back_soon' => 'Tornarà a estar disponible aviat.', // API errors - 'api_no_authorization_found' => 'No s\'ha trobat cap testimoni d\'autorització a la petició', - 'api_bad_authorization_format' => 'S\'ha trobat un testimoni d\'autorització a la petició però el format sembla erroni', - 'api_user_token_not_found' => 'No s\'ha trobat cap testimoni d\'API per al testimoni d\'autorització proporcionat', - 'api_incorrect_token_secret' => 'El secret proporcionat per al testimoni d\'API proporcionat és incorrecte', - 'api_user_no_api_permission' => 'El propietari del testimoni d\'API utilitzat no té permís per a fer crides a l\'API', - 'api_user_token_expired' => 'El testimoni d\'autorització utilitzat ha caducat', + 'api_no_authorization_found' => 'No s’ha trobat cap testimoni d’autorització a la petició', + 'api_bad_authorization_format' => 'S’ha trobat un testimoni d’autorització a la petició, però el format sembla erroni', + 'api_user_token_not_found' => 'No s’ha trobat cap testimoni de l’API per al testimoni d’autorització proporcionat', + 'api_incorrect_token_secret' => 'El secret proporcionat per al testimoni de l’API proporcionat és incorrecte', + 'api_user_no_api_permission' => 'El propietari del testimoni de l’API utilitzat no té permís per a fer crides a l’API', + 'api_user_token_expired' => 'El testimoni d’autorització utilitzat ha caducat', // Settings & Maintenance - 'maintenance_test_email_failure' => 'S\'ha produït un error en enviar un correu electrònic de prova:', + 'maintenance_test_email_failure' => 'S’ha produït un error en enviar un correu electrònic de prova:', // HTTP errors - 'http_ssr_url_no_match' => 'The URL does not match the configured allowed SSR hosts', + 'http_ssr_url_no_match' => 'L’URL no coincideix amb els amfitrions SSR permesos segons la configuració', ]; diff --git a/lang/ca/notifications.php b/lang/ca/notifications.php index 5539ae9a9..8f86b85ad 100644 --- a/lang/ca/notifications.php +++ b/lang/ca/notifications.php @@ -4,23 +4,24 @@ */ return [ - 'new_comment_subject' => 'New comment on page: :pageName', - 'new_comment_intro' => 'A user has commented on a page in :appName:', - 'new_page_subject' => 'New page: :pageName', - 'new_page_intro' => 'A new page has been created in :appName:', - 'updated_page_subject' => 'Updated page: :pageName', - 'updated_page_intro' => 'A page has been updated in :appName:', - 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', + 'new_comment_subject' => 'Comentari nou a la pàgina :pageName', + 'new_comment_intro' => 'Un usuari ha comentat en una pàgina de :appName:', + 'new_page_subject' => 'Pàgina nova: :pageName', + 'new_page_intro' => 'S’ha creat una pàgina nova a :appName:', + 'updated_page_subject' => 'Pàgina actualitzada: :pageName', + 'updated_page_intro' => 'S’ha actualitzat una pàgina a :appName:', + 'updated_page_debounce' => 'Per a evitar les notificacions massives, no us enviarem notificacions si hi ha més edicions en aquesta pàgina fetes pel mateix editor.', - 'detail_page_name' => 'Page Name:', - 'detail_commenter' => 'Commenter:', - 'detail_comment' => 'Comment:', - 'detail_created_by' => 'Created By:', - 'detail_updated_by' => 'Updated By:', + 'detail_page_name' => 'Nom de la pàgina:', + 'detail_page_path' => 'Camí de la pàgina:', + 'detail_commenter' => 'Autor del comentari:', + 'detail_comment' => 'Comentari:', + 'detail_created_by' => 'Creat per:', + 'detail_updated_by' => 'Actualitzat per:', - 'action_view_comment' => 'View Comment', - 'action_view_page' => 'View Page', + 'action_view_comment' => 'Mostra el comentari', + 'action_view_page' => 'Mostra la pàgina', - 'footer_reason' => 'This notification was sent to you because :link cover this type of activity for this item.', - 'footer_reason_link' => 'your notification preferences', + 'footer_reason' => 'Rebeu aquesta notificació perquè :link cobreixen aquest tipus d’activitat en aquest element.', + 'footer_reason_link' => 'les vostres preferències de notificacions', ]; diff --git a/lang/ca/passwords.php b/lang/ca/passwords.php index 1f0f75915..60789c8a2 100644 --- a/lang/ca/passwords.php +++ b/lang/ca/passwords.php @@ -6,10 +6,10 @@ */ return [ - 'password' => 'Les contrasenyes han de tenir com a mínim vuit caràcters i la confirmació ha de coincidir.', - 'user' => "No s'ha trobat cap usuari amb aquest correu electrònic.", - 'token' => 'El token de restabliment de contrasenya no és vàlid per aquest correu electrònic.', - 'sent' => 'T\'hem enviat un enllaç per a restablir la contrasenya!', - 'reset' => 'S\'ha restablert la teva contrasenya!', + 'password' => 'Les contrasenyes han de tenir almenys vuit caràcters i coincidir amb la confirmació.', + 'user' => "No s’ha trobat cap usuari amb aquesta adreça electrònica.", + 'token' => 'El testimoni de restabliment de la contrasenya no és vàlid per a aquesta adreça electrònica.', + 'sent' => 'Us hem enviat un enllaç per a restablir la contrasenya!', + 'reset' => 'S’ha restablert la contrasenya!', ]; diff --git a/lang/ca/preferences.php b/lang/ca/preferences.php index 2b88f9671..b56b8b3bb 100644 --- a/lang/ca/preferences.php +++ b/lang/ca/preferences.php @@ -5,47 +5,47 @@ */ return [ - 'my_account' => 'My Account', + 'my_account' => 'El meu compte', - 'shortcuts' => 'Shortcuts', - 'shortcuts_interface' => 'UI Shortcut Preferences', - 'shortcuts_toggle_desc' => 'Here you can enable or disable keyboard system interface shortcuts, used for navigation and actions.', - 'shortcuts_customize_desc' => 'You can customize each of the shortcuts below. Just press your desired key combination after selecting the input for a shortcut.', - 'shortcuts_toggle_label' => 'Keyboard shortcuts enabled', - 'shortcuts_section_navigation' => 'Navigation', - 'shortcuts_section_actions' => 'Common Actions', - 'shortcuts_save' => 'Save Shortcuts', - 'shortcuts_overlay_desc' => 'Note: When shortcuts are enabled a helper overlay is available via pressing "?" which will highlight the available shortcuts for actions currently visible on the screen.', - 'shortcuts_update_success' => 'Shortcut preferences have been updated!', - 'shortcuts_overview_desc' => 'Manage keyboard shortcuts you can use to navigate the system user interface.', + 'shortcuts' => 'Dreceres', + 'shortcuts_interface' => 'Preferències de les dreceres de la interfície d’usuari', + 'shortcuts_toggle_desc' => 'Aquí podeu activar o desactivar les dreceres de teclat de la interfície del sistema, que s’utilitzen per a la navegació i les accions.', + 'shortcuts_customize_desc' => 'Podeu personalitzar cadascuna de les dreceres següents. Premeu la combinació de tecles desitjada després de seleccionar la casella d’una drecera.', + 'shortcuts_toggle_label' => 'Dreceres de teclat activades', + 'shortcuts_section_navigation' => 'Navegació', + 'shortcuts_section_actions' => 'Accions habituals', + 'shortcuts_save' => 'Desa les dreceres', + 'shortcuts_overlay_desc' => 'Nota: Quan s’activen les dreceres, hi ha una interfície d’ajuda disponible en prémer «?» que destaca les dreceres disponibles per a accions visibles actualment a la pantalla.', + 'shortcuts_update_success' => 'S’han actualitzat les preferències de les dreceres!', + 'shortcuts_overview_desc' => 'Gestioneu les dreceres de teclat que podeu utilitzar per a navegar per la interfície d’usuari del sistema.', - 'notifications' => 'Notification Preferences', - 'notifications_desc' => 'Control the email notifications you receive when certain activity is performed within the system.', - 'notifications_opt_own_page_changes' => 'Notify upon changes to pages I own', - 'notifications_opt_own_page_comments' => 'Notify upon comments on pages I own', - 'notifications_opt_comment_replies' => 'Notify upon replies to my comments', - 'notifications_save' => 'Save Preferences', - 'notifications_update_success' => 'Notification preferences have been updated!', - 'notifications_watched' => 'Watched & Ignored Items', - 'notifications_watched_desc' => ' Below are the items that have custom watch preferences applied. To update your preferences for these, view the item then find the watch options in the sidebar.', + 'notifications' => 'Preferències de notificació', + 'notifications_desc' => 'Controleu les notificacions per correu electrònic que rebeu quan es fan certes activitats dins del sistema.', + 'notifications_opt_own_page_changes' => 'Notifica’m quan hi hagi canvis a pàgines de les quals sóc propietari', + 'notifications_opt_own_page_comments' => 'Notifica’m quan hi hagi comentaris a pàgines de les quals sóc propietari', + 'notifications_opt_comment_replies' => 'Notifica’m quan hi hagi respostes als meus comentaris', + 'notifications_save' => 'Desa les preferències', + 'notifications_update_success' => 'S’han actualitzat les preferències de notificacions!', + 'notifications_watched' => 'Elements seguits i ignorats', + 'notifications_watched_desc' => ' A continuació hi ha els elements que tenen aplicades preferències de seguiment personalitzades. Per a actualitzar-ne les preferències, consulteu l’element i seleccioneu les opcions de seguiment a la barra lateral.', - 'auth' => 'Access & Security', - 'auth_change_password' => 'Change Password', - 'auth_change_password_desc' => 'Change the password you use to log-in to the application. This must be at least 8 characters long.', - 'auth_change_password_success' => 'Password has been updated!', + 'auth' => 'Accés i seguretat', + 'auth_change_password' => 'Canvia la contrasenya', + 'auth_change_password_desc' => 'Canvieu la contrasenya que feu servir per a iniciar la sessió a l’aplicació. Cal que tingui un mínim de 8 caràcters.', + 'auth_change_password_success' => 'S’ha actualitzat la contrasenya!', - 'profile' => 'Profile Details', - 'profile_desc' => 'Manage the details of your account which represents you to other users, in addition to details that are used for communication and system personalisation.', - 'profile_view_public' => 'View Public Profile', - 'profile_name_desc' => 'Configure your display name which will be visible to other users in the system through the activity you perform, and content you own.', - 'profile_email_desc' => 'This email will be used for notifications and, depending on active system authentication, system access.', - 'profile_email_no_permission' => 'Unfortunately you don\'t have permission to change your email address. If you want to change this, you\'d need to ask an administrator to change this for you.', - 'profile_avatar_desc' => 'Select an image which will be used to represent yourself to others in the system. Ideally this image should be square and about 256px in width and height.', - 'profile_admin_options' => 'Administrator Options', - 'profile_admin_options_desc' => 'Additional administrator-level options, like those to manage role assignments, can be found for your user account in the "Settings > Users" area of the application.', + 'profile' => 'Detalls del perfil', + 'profile_desc' => 'Gestioneu els detalls del vostre compte, que us representa davant d’altres usuaris, i també els detalls que s’utilitzen per a la comunicació i la personalització del sistema.', + 'profile_view_public' => 'Mostra el perfil públic', + 'profile_name_desc' => 'Configureu el vostre nom públic, que és visible als altres usuaris del sistema a través de les activitats que realitzeu i del contingut del qual sou propietari.', + 'profile_email_desc' => 'Aquest correu s’utilitza per a notificacions i, depenent de l’autenticació activa del sistema, per a l’accés al sistema.', + 'profile_email_no_permission' => 'Malauradament, no teniu permisos per a canviar l’adreça electrònica. Si voleu canviar-la, caldrà que demaneu a un administrador que us faci el canvi.', + 'profile_avatar_desc' => 'Seleccioneu una imatge que us representarà davant d’altres usuaris del sistema. Idealment, aquesta imatge hauria de ser un quadrat de 256 px d’alçada i d’amplada.', + 'profile_admin_options' => 'Opcions d’administració', + 'profile_admin_options_desc' => 'Podeu trobar opcions de nivell d’administració addicionals del vostre compte, com ara les que permeten gestionar les assignacions de rols, a l’àrea de l’aplicació «Configuració > Usuaris».', - 'delete_account' => 'Delete Account', - 'delete_my_account' => 'Delete My Account', - 'delete_my_account_desc' => 'This will fully delete your user account from the system. You will not be able to recover this account or revert this action. Content you\'ve created, such as created pages and uploaded images, will remain.', - 'delete_my_account_warning' => 'Are you sure you want to delete your account?', + 'delete_account' => 'Suprimeix el compte', + 'delete_my_account' => 'Suprimeix el meu compte', + 'delete_my_account_desc' => 'Se suprimirà completament el vostre compte d’usuari del sistema. No podreu recuperar aquest compte ni revertir aquesta acció. El contingut que hàgiu creat, com ara les pàgines creades o les imatges pujades, es mantindrà.', + 'delete_my_account_warning' => 'Segur que voleu suprimir el vostre compte?', ]; diff --git a/lang/ca/settings.php b/lang/ca/settings.php index 48a04e7e2..0305a5c23 100644 --- a/lang/ca/settings.php +++ b/lang/ca/settings.php @@ -9,51 +9,51 @@ return [ // Common Messages 'settings' => 'Configuració', 'settings_save' => 'Desa la configuració', - 'system_version' => 'System Version', + 'system_version' => 'Versió del sistema', 'categories' => 'Categories', // App Settings 'app_customization' => 'Personalització', 'app_features_security' => 'Funcionalitats i seguretat', - 'app_name' => 'Nom de l\'aplicació', + 'app_name' => 'Nom de l’aplicació', 'app_name_desc' => 'Aquest nom es mostra a la capçalera i en tots els correus electrònics enviats pel sistema.', 'app_name_header' => 'Mostra el nom a la capçalera', 'app_public_access' => 'Accés públic', 'app_public_access_desc' => 'Si activeu aquesta opció, es permetrà que els visitants que no hagin iniciat la sessió accedeixin al contingut de la vostra instància del BookStack.', - 'app_public_access_desc_guest' => 'Podeu controlar l\'accés dels visitants públics amb l\'usuari "Convidat".', - 'app_public_access_toggle' => 'Permet l\'accés públic', + 'app_public_access_desc_guest' => 'Podeu controlar l’accés dels visitants públics amb l’usuari «Convidat».', + 'app_public_access_toggle' => 'Permet l’accés públic', 'app_public_viewing' => 'Voleu permetre la visualització pública?', - 'app_secure_images' => 'Pujades d\'imatges amb més seguretat', - 'app_secure_images_toggle' => 'Activa les pujades d\'imatges amb més seguretat', - 'app_secure_images_desc' => 'Per motius de rendiment, totes les imatges són públiques. Aquesta opció afegeix una cadena aleatòria i difícil d\'endevinar al davant dels URL d\'imatges. Assegureu-vos que els índexs de directoris no estiguin activats per a evitar-hi l\'accés de manera fàcil.', - 'app_default_editor' => 'Default Page Editor', - 'app_default_editor_desc' => 'Select which editor will be used by default when editing new pages. This can be overridden at a page level where permissions allow.', + 'app_secure_images' => 'Pujades d’imatges amb més seguretat', + 'app_secure_images_toggle' => 'Activa les pujades d’imatges amb més seguretat', + 'app_secure_images_desc' => 'Per motius de rendiment, totes les imatges són públiques. Aquesta opció afegeix una cadena aleatòria i difícil d’endevinar al davant dels URL d’imatges. Assegureu-vos que els índexs de directoris no estiguin activats per a evitar-hi l’accés de manera fàcil.', + 'app_default_editor' => 'Editor de pàgines per defecte', + 'app_default_editor_desc' => 'Seleccioneu quin editor es farà servir per defecte en editar pàgines noves. Es pot canviar a nivell de pàgina si els permisos ho permeten.', 'app_custom_html' => 'Contingut personalitzat a la capçalera HTML', - 'app_custom_html_desc' => 'Aquí podeu afegir contingut que s\'inserirà a la part final de la secció de cada pàgina. És útil per a sobreescriure estils o afegir-hi codi d\'analítiques.', + 'app_custom_html_desc' => 'Aquí podeu afegir contingut que s’inserirà a la part final de la secció de cada pàgina. És útil per a sobreescriure estils o afegir-hi codi d’analítiques.', 'app_custom_html_disabled_notice' => 'El contingut personalitzat a la capçalera HTML es desactiva en aquesta pàgina de la configuració per a assegurar que qualsevol canvi que trenqui el web es pugui desfer.', - 'app_logo' => 'Logo de l\'aplicació', - '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_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' => 'Pàgina d\'inici de l\'aplicació', - 'app_homepage_desc' => 'Seleccioneu la visualització que es mostrarà a la pàgina d\'inici en lloc de la visualització per defecte. Els permisos de pàgines s\'ignoraran per a les pàgines seleccionades.', + 'app_logo' => 'Logo de l’aplicació', + 'app_logo_desc' => 'Es fa servir a la barra de la capçalera de l’aplicació, a banda d’altres zones. Aquesta imatge ha de fer 86 px d’alçada. Les imatges massa grosses es reduiran.', + 'app_icon' => 'Icona de l’aplicació', + 'app_icon_desc' => 'Aquesta icona es fa servir a la pestanya del navegador i a les icones de les dreceres. Hauria de ser una imatge PNG quadrada de 256 px.', + 'app_homepage' => 'Pàgina d’inici de l’aplicació', + 'app_homepage_desc' => 'Seleccioneu la visualització que es mostrarà a la pàgina d’inici en lloc de la visualització per defecte. Els permisos de pàgines s’ignoraran per a les pàgines seleccionades.', 'app_homepage_select' => 'Selecciona una pàgina', 'app_footer_links' => 'Enllaços al peu de pàgina', - 'app_footer_links_desc' => 'Afegiu enllaços que es mostraran al peu de pàgina del lloc. Es mostraran a la part inferior de la majoria de pàgines, incloent-hi les que no requereixen iniciar la sessió. Podeu utilitzar l\'etiqueta "trans::" per a fer servir traduccions definides pel sistema. Per exemple, si feu servir "trans::common.privacy_policy", es mostrarà el text traduït "Política de privadesa", i amb "trans::common.terms_of_service" es mostrarà el text traduït "Condicions del servei".', - 'app_footer_links_label' => 'Etiqueta de l\'enllaç', - 'app_footer_links_url' => 'URL de l\'enllaç', + 'app_footer_links_desc' => 'Afegiu enllaços que es mostraran al peu de pàgina del lloc. Es mostraran a la part inferior de la majoria de pàgines, incloent-hi les que no requereixen iniciar la sessió. Podeu utilitzar l’etiqueta «trans::» per a fer servir traduccions definides pel sistema. Per exemple, si feu servir «trans::common.privacy_policy», es mostrarà el text traduït «Política de privadesa», i amb «trans::common.terms_of_service» es mostrarà el text traduït «Condicions del servei».', + 'app_footer_links_label' => 'Etiqueta de l’enllaç', + 'app_footer_links_url' => 'URL de l’enllaç', 'app_footer_links_add' => 'Afegeix un enllaç al peu de pàgina', 'app_disable_comments' => 'Desactiva els comentaris', 'app_disable_comments_toggle' => 'Desactiva els comentaris', - 'app_disable_comments_desc' => 'Desactiva els comentaris a totes les pàgines de l\'aplicació.
Els comentaris existents no es mostraran.', + 'app_disable_comments_desc' => 'Desactiva els comentaris a totes les pàgines de l’aplicació.
Els comentaris existents no es mostraran.', // 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', - '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.', + 'color_scheme' => 'Esquema de colors de l’aplicació', + 'color_scheme_desc' => 'Definiu els colors que s’utilitzaran a la interfície d’usuari de l’aplicació. Els colors es poden configurar de manera separada per als modes fosc i clar perquè encaixin millor amb el tema i n’assegurin la llegibilitat.', + 'ui_colors_desc' => 'Definiu el color primari de l’aplicació i el color per defecte dels enllaços. El color primari es fa servir sobretot per a la capçalera, els botons i la decoració de la interfície. El color per defecte dels enllaços s’utilitza per als enllaços de text i les accions, tant al contingut escrit com a la interfície de l’aplicació.', + 'app_color' => 'Color primari', + 'link_color' => 'Color per defecte dels enllaços', + 'content_colors_desc' => 'Definiu els colors per a tots els elements de la jerarquia d’organització de pàgines. És recomanable triar colors amb una brillantor similar a la dels colors per defecte per a millorar la llegibilitat.', 'bookshelf_color' => 'Color dels prestatges', 'book_color' => 'Color dels llibres', 'chapter_color' => 'Color dels capítols', @@ -62,46 +62,46 @@ return [ // Registration Settings 'reg_settings' => 'Registre', - 'reg_enable' => 'Activa el registre d\'usuaris', - 'reg_enable_toggle' => 'Activa el registre d\'usuaris', - 'reg_enable_desc' => 'Si els registres estan activats, els usuaris podran registrar-se ells mateixos com a usuaris de l\'aplicació. Un cop registrats, se\'ls assigna un únic rol d\'usuari per defecte.', - 'reg_default_role' => 'Rol d\'usuari per defecte en registrar-se', - 'reg_enable_external_warning' => 'L\'opció anterior s\'ignora quan hi ha activada l\'autenticació SAML o LDAP externa. Els comptes d\'usuari de membres inexistents es creada automàticament si l\'autenticació contra el sistema extern és satisfactòria.', + 'reg_enable' => 'Activa el registre d’usuaris', + 'reg_enable_toggle' => 'Activa el registre d’usuaris', + 'reg_enable_desc' => 'Si els registres estan activats, els usuaris podran registrar-se ells mateixos com a usuaris de l’aplicació. Un cop registrats, se’ls assigna un únic rol d’usuari per defecte.', + 'reg_default_role' => 'Rol d’usuari per defecte en registrar-se', + 'reg_enable_external_warning' => 'L’opció anterior s’ignora quan hi ha activada l’autenticació SAML o LDAP externa. Els comptes d’usuari de membres inexistents es crearan automàticament si l’autenticació contra el sistema extern és satisfactòria.', 'reg_email_confirmation' => 'Confirmació de correu electrònic', 'reg_email_confirmation_toggle' => 'Requereix la confirmació per correu electrònic', - 'reg_confirm_email_desc' => 'Si s\'utilitza la restricció de dominis, serà obligatòria la confirmació per correu electrònic, i s\'ignorarà aquesta opció.', + 'reg_confirm_email_desc' => 'Si s’utilitza la restricció de dominis, serà obligatòria la confirmació per correu electrònic, i s’ignorarà aquesta opció.', 'reg_confirm_restrict_domain' => 'Restricció de dominis', - 'reg_confirm_restrict_domain_desc' => 'Introduïu una llista separada per comes de dominis de correu electrònic als quals voleu restringir els registres. S\'enviarà un correu electrònic als usuaris perquè confirmin la seva adreça abans de permetre\'ls interactuar amb l\'aplicació.
Tingueu en compte que els usuaris podran canviar les seves adreces electròniques després de registrar-se correctament.', + 'reg_confirm_restrict_domain_desc' => 'Introduïu una llista separada per comes de dominis de correu electrònic als quals voleu restringir els registres. S’enviarà un correu electrònic als usuaris perquè confirmin la seva adreça abans de permetre’ls interactuar amb l’aplicació.
Tingueu en compte que els usuaris podran canviar les seves adreces electròniques després de registrar-se correctament.', 'reg_confirm_restrict_domain_placeholder' => 'No hi ha cap restricció', // Maintenance settings 'maint' => 'Manteniment', 'maint_image_cleanup' => 'Neteja les imatges', - 'maint_image_cleanup_desc' => 'Escaneja el contingut de les pàgines i les revisions per a comprovar quines imatges i diagrames estan en ús actualment i quines imatges són redundants. Assegureu-vos de crear una còpia de seguretat completa de la base de dades i de les imatges abans d\'executar això.', + 'maint_image_cleanup_desc' => 'Escaneja el contingut de les pàgines i les revisions per a comprovar quines imatges i diagrames estan en ús actualment i quines imatges són redundants. Assegureu-vos de crear una còpia de seguretat completa de la base de dades i de les imatges abans d’executar això.', 'maint_delete_images_only_in_revisions' => 'Suprimeix també les imatges que només existeixin en revisions antigues de pàgines', 'maint_image_cleanup_run' => 'Executa la neteja', - 'maint_image_cleanup_warning' => 'S\'han trobat :count imatges potencialment no utilitzades. Segur que voleu suprimir aquestes imatges?', - 'maint_image_cleanup_success' => 'S\'han trobat i suprimit :count imatges potencialment no utilitzades!', - 'maint_image_cleanup_nothing_found' => 'No s\'ha trobat cap imatge no utilitzada, i no s\'ha suprimit res!', + 'maint_image_cleanup_warning' => 'S’han trobat :count imatges potencialment no utilitzades. Segur que voleu suprimir aquestes imatges?', + 'maint_image_cleanup_success' => 'S’han trobat i suprimit :count imatges potencialment no utilitzades!', + 'maint_image_cleanup_nothing_found' => 'No s’ha trobat cap imatge no utilitzada, així que no s’ha suprimit res!', 'maint_send_test_email' => 'Envia un correu electrònic de prova', - 'maint_send_test_email_desc' => 'Envia un correu electrònic de prova a l\'adreça electrònica que hàgiu especificat al perfil.', + 'maint_send_test_email_desc' => 'Envia un correu electrònic de prova a l’adreça electrònica que hàgiu especificat al perfil.', 'maint_send_test_email_run' => 'Envia el correu electrònic de prova', - 'maint_send_test_email_success' => 'S\'ha enviat el correu electrònic a :address', + 'maint_send_test_email_success' => 'S’ha enviat el correu electrònic a :address', 'maint_send_test_email_mail_subject' => 'Correu electrònic de prova', 'maint_send_test_email_mail_greeting' => 'El lliurament de correus electrònics sembla que funciona!', 'maint_send_test_email_mail_text' => 'Enhorabona! Com que heu rebut aquesta notificació per correu electrònic, la vostra configuració del correu electrònic sembla que està ben configurada.', - 'maint_recycle_bin_desc' => 'Els prestatges, llibres, capítols i pàgines eliminats s\'envien a la paperera de reciclatge perquè es puguin restaurar o suprimir de manera permanent. Pot ser que els elements més antics de la paperera de reciclatge se suprimeixin automàticament després d\'un temps, depenent de la configuració del sistema.', + 'maint_recycle_bin_desc' => 'Els prestatges, llibres, capítols i pàgines suprimits s’envien a la paperera de reciclatge perquè es puguin restaurar o suprimir de manera permanent. Pot ser que els elements més antics de la paperera de reciclatge se suprimeixin automàticament després d’un temps, depenent de la configuració del sistema.', 'maint_recycle_bin_open' => 'Obre la paperera de reciclatge', - 'maint_regen_references' => 'Regenerate References', - 'maint_regen_references_desc' => 'This action will rebuild the cross-item reference index within the database. This is usually handled automatically but this action can be useful to index old content or content added via unofficial methods.', - 'maint_regen_references_success' => 'Reference index has been regenerated!', - 'maint_timeout_command_note' => 'Note: This action can take time to run, which can lead to timeout issues in some web environments. As an alternative, this action be performed using a terminal command.', + 'maint_regen_references' => 'Regenera les referències', + 'maint_regen_references_desc' => 'Aquesta acció reconstruirà l’índex de referències entre elements de la base de dades. Normalment es gestiona automàticament, però aquesta acció pot ser útil per a indexar contingut antic o contingut afegit mitjançant mètodes no oficials.', + 'maint_regen_references_success' => 'L’índex de referències s’ha regenerat!', + 'maint_timeout_command_note' => 'Nota: Aquesta acció pot trigar estona a executar-se, la qual cosa pot provocar errors de temps d’expera excedits en alguns entorns web. Com a alternativa, podeu executar aquesta acció en una ordre al terminal.', // Recycle Bin 'recycle_bin' => 'Paperera de reciclatge', - 'recycle_bin_desc' => 'Aquí podeu restaurar els elements que hàgiu suprimit o triar suprimir-los del sistema de manera permanent. Aquesta llista no té cap filtre, al contrari que altres llistes d\'activitat similars en què es tenen en compte els filtres de permisos.', + 'recycle_bin_desc' => 'Aquí podeu restaurar els elements que hàgiu suprimit o triar suprimir-los del sistema de manera permanent. Aquesta llista no té cap filtre, al contrari que altres llistes d’activitat similars en què es tenen en compte els filtres de permisos.', 'recycle_bin_deleted_item' => 'Element suprimit', - 'recycle_bin_deleted_parent' => 'Parent', + 'recycle_bin_deleted_parent' => 'Pare', 'recycle_bin_deleted_by' => 'Suprimit per', 'recycle_bin_deleted_at' => 'Moment de la supressió', 'recycle_bin_permanently_delete' => 'Suprimeix permanentment', @@ -112,63 +112,63 @@ return [ 'recycle_bin_destroy_confirm' => 'Aquesta acció suprimirà del sistema de manera permanent aquest element, juntament amb tots els elements fills que es llisten a sota, i no podreu restaurar aquest contingut. Segur que voleu suprimir de manera permanent aquest element?', 'recycle_bin_destroy_list' => 'Elements que es destruiran', 'recycle_bin_restore_list' => 'Elements que es restauraran', - 'recycle_bin_restore_confirm' => 'Aquesta acció restaurarà l\'element suprimit, incloent-hi tots els elements fills, a la seva ubicació original. Si la ubicació original ha estat suprimida, i ara és a la paperera de reciclatge, caldrà que també en restaureu l\'element pare.', - 'recycle_bin_restore_deleted_parent' => 'El pare d\'aquest element també ha estat suprimit. L\'element es mantindrà suprimit fins que el pare també es restauri.', - 'recycle_bin_restore_parent' => 'Restore Parent', - 'recycle_bin_destroy_notification' => 'S\'han suprimit :count elements en total de la paperera de reciclatge.', - 'recycle_bin_restore_notification' => 'S\'han restaurat :count elements en total de la paperera de reciclatge.', + 'recycle_bin_restore_confirm' => 'Aquesta acció restaurarà l’element suprimit, incloent-hi tots els elements fills, a la seva ubicació original. Si la ubicació original ha estat suprimida, i ara és a la paperera de reciclatge, caldrà que també en restaureu l’element pare.', + 'recycle_bin_restore_deleted_parent' => 'El pare d’aquest element també ha estat suprimit. L’element es mantindrà suprimit fins que el pare també es restauri.', + 'recycle_bin_restore_parent' => 'Restaura’n el pare', + 'recycle_bin_destroy_notification' => 'S’han suprimit :count elements en total de la paperera de reciclatge.', + 'recycle_bin_restore_notification' => 'S’han restaurat :count elements en total de la paperera de reciclatge.', // Audit Log - 'audit' => 'Registre d\'auditoria', - 'audit_desc' => 'Aquest registre d\'auditoria mostra una llista d\'activitats registrades al sistema. Aquesta llista no té cap filtre, al contrari que altres llistes d\'activitat similars en què es tenen en compte els filtres de permisos.', - 'audit_event_filter' => 'Filtre d\'esdeveniments', + 'audit' => 'Registre d’auditoria', + 'audit_desc' => 'Aquest registre d’auditoria mostra una llista d’activitats registrades al sistema. Aquesta llista no té cap filtre, al contrari que altres llistes d’activitat similars en què es tenen en compte els filtres de permisos.', + 'audit_event_filter' => 'Filtre d’esdeveniments', 'audit_event_filter_no_filter' => 'Sense filtre', 'audit_deleted_item' => 'Element suprimit', 'audit_deleted_item_name' => 'Nom: :name', 'audit_table_user' => 'Usuari', 'audit_table_event' => 'Esdeveniment', 'audit_table_related' => 'Element relacionat o detall', - 'audit_table_ip' => 'IP Address', - 'audit_table_date' => 'Data de l\'activitat', + 'audit_table_ip' => 'Adreça IP', + 'audit_table_date' => 'Data de l’activitat', 'audit_date_from' => 'Rang de dates a partir de', 'audit_date_to' => 'Rang de rates fins a', // Role Settings 'roles' => 'Rols', - 'role_user_roles' => 'Rols d\'usuari', - '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_x_users_assigned' => ':count user assigned|:count users assigned', - 'roles_x_permissions_provided' => ':count permission|:count permissions', - 'roles_assigned_users' => 'Assigned Users', - 'roles_permissions_provided' => 'Provided Permissions', + 'role_user_roles' => 'Rols d’usuari', + 'roles_index_desc' => 'Els rols s’utilitzen per a agrupar usuaris i proporcionar permisos del sistema a llurs membres. Quan un usuari és membre de múltiples rols, els privilegis que li concedeixin s’acumularan i l’usuari heretarà totes les habilitats.', + 'roles_x_users_assigned' => ':count usuari assignat|:count usuaris assignats', + 'roles_x_permissions_provided' => ':count permís|:count permisos', + 'roles_assigned_users' => 'Usuaris assignats', + 'roles_permissions_provided' => 'Permisos proporcionats', 'role_create' => 'Crea un rol nou', 'role_delete' => 'Suprimeix el rol', - 'role_delete_confirm' => 'Se suprimirà el rol amb el nom \':roleName\'.', - 'role_delete_users_assigned' => 'Aquest rol té :userCount usuaris assignats. Si voleu migrar els usuaris d\'aquest rol, seleccioneu un rol nou a continuació.', + 'role_delete_confirm' => 'Se suprimirà el rol amb el nom «:roleName».', + 'role_delete_users_assigned' => 'Aquest rol té :userCount usuaris assignats. Si voleu migrar els usuaris d’aquest rol, seleccioneu un rol nou a continuació.', 'role_delete_no_migration' => "No migris els usuaris", 'role_delete_sure' => 'Segur que voleu suprimir aquest rol?', 'role_edit' => 'Edita el rol', 'role_details' => 'Detalls del rol', 'role_name' => 'Nom del rol', 'role_desc' => 'Descripció curta del rol', - 'role_mfa_enforced' => 'Requires Multi-Factor Authentication', - 'role_external_auth_id' => 'Identificadors d\'autenticació externa', + 'role_mfa_enforced' => 'Requereix autenticació de múltiple factor', + 'role_external_auth_id' => 'Identificadors d’autenticació externa', 'role_system' => 'Permisos del sistema', 'role_manage_users' => 'Gestiona usuaris', 'role_manage_roles' => 'Gestiona rols i permisos de rols', 'role_manage_entity_permissions' => 'Gestiona els permisos de tots els llibres, capítols i pàgines', 'role_manage_own_entity_permissions' => 'Gestiona els permisos dels llibres, capítols i pàgines propis', 'role_manage_page_templates' => 'Gestiona les plantilles de pàgines', - 'role_access_api' => 'Accedeix a l\'API del sistema', - 'role_manage_settings' => 'Gestiona la configuració de l\'aplicació', - 'role_export_content' => 'Export content', - 'role_editor_change' => 'Change page editor', - 'role_notifications' => 'Receive & manage notifications', + 'role_access_api' => 'Accedeix a l’API del sistema', + 'role_manage_settings' => 'Gestiona la configuració de l’aplicació', + 'role_export_content' => 'Exporta el contingut', + 'role_editor_change' => 'Canvia l’editor de pàgines', + 'role_notifications' => 'Rep i gestiona les notificacions', 'role_asset' => 'Permisos de recursos', - 'roles_system_warning' => 'Tingueu en compte que l\'accés a qualsevol dels tres permisos de dalt pot permetre que un usuari alteri els seus propis permisos o els privilegis d\'altres usuaris del sistema. Assigneu rols amb aquests permisos només a usuaris de confiança.', - 'role_asset_desc' => 'Aquests permisos controlen l\'accés per defecte als recursos del sistema. Els permisos de llibres, capítols i pàgines tindran més importància que aquests permisos.', - 'role_asset_admins' => 'Els administradors tenen accés automàticament a tot el contingut, però aquestes opcions poden mostrar o amagar opcions de la interfície d\'usuari.', - 'role_asset_image_view_note' => 'This relates to visibility within the image manager. Actual access of uploaded image files will be dependant upon system image storage option.', + 'roles_system_warning' => 'Tingueu en compte que l’accés a qualsevol dels tres permisos de dalt pot permetre que un usuari alteri els seus propis permisos o els privilegis d’altres usuaris del sistema. Assigneu rols amb aquests permisos només a usuaris de confiança.', + 'role_asset_desc' => 'Aquests permisos controlen l’accés per defecte als recursos del sistema. Els permisos de llibres, capítols i pàgines tindran més importància que aquests permisos.', + 'role_asset_admins' => 'Els administradors tenen accés automàticament a tot el contingut, però aquestes opcions poden mostrar o amagar opcions de la interfície d’usuari.', + 'role_asset_image_view_note' => 'Això és relatiu a la visibilitat dins del gestor d’imatges. L’accés real als fitxers d’imatge pujats dependrà de l’opció d’emmagatzematge d’imatges del sistema.', 'role_all' => 'Tot', 'role_own' => 'Propi', 'role_controlled_by_asset' => 'Controlat pel recurs en què es pugen', @@ -178,103 +178,103 @@ return [ // Users 'users' => 'Usuaris', - 'users_index_desc' => 'Create & manage individual user accounts within the system. User accounts are used for login and attribution of content & activity. Access permissions are primarily role-based but user content ownership, among other factors, may also affect permissions & access.', - 'user_profile' => 'Perfil de l\'usuari', + 'users_index_desc' => 'Creeu i gestioneu comptes d’usuari individuals dins del sistema. Els comptes d’usuari s’utilitzen per a iniciar la sessió i atribuir el contingut i les activitats. Els permisos d’accés són principalment basats en rols, però si un usuari és propietari o no d’un contingut, entre altres factors, també pot afectar-ne els permisos i l’accés.', + 'user_profile' => 'Perfil de l’usuari', 'users_add_new' => 'Afegeix un usuari nou', 'users_search' => 'Cerca usuaris', 'users_latest_activity' => 'Darrera activitat', - 'users_details' => 'Detalls de l\'usuari', - 'users_details_desc' => 'Definiu un nom públic i una adreça electrònica per a aquest usuari. L\'adreça electrònica es farà servir per a iniciar la sessió a l\'aplicació.', + 'users_details' => 'Detalls de l’usuari', + 'users_details_desc' => 'Definiu un nom públic i una adreça electrònica per a aquest usuari. L’adreça electrònica es farà servir per a iniciar la sessió a l’aplicació.', 'users_details_desc_no_email' => 'Definiu un nom públic per a aquest usuari perquè els altres el puguin reconèixer.', - 'users_role' => 'Rols de l\'usuari', - 'users_role_desc' => 'Seleccioneu a quins rols s\'assignarà l\'usuari. Si un usuari s\'assigna a múltiples rols, els permisos dels rols s\'acumularan i l\'usuari rebrà tots els permisos dels rols assignats.', - 'users_password' => 'Contrasenya de l\'usuari', - 'users_password_desc' => 'Set a password used to log-in to the application. This must be at least 8 characters long.', - 'users_send_invite_text' => 'Podeu elegir enviar un correu d\'invitació a aquest usuari, la qual cosa li permetrà definir la seva contrasenya, o podeu definir-li una contrasenya vós.', - 'users_send_invite_option' => 'Envia un correu d\'invitació a l\'usuari', - 'users_external_auth_id' => 'Identificador d\'autenticació extern', - 'users_external_auth_id_desc' => 'When an external authentication system is in use (such as SAML2, OIDC or LDAP) this is the ID which links this BookStack user to the authentication system account. You can ignore this field if using the default email-based authentication.', - 'users_password_warning' => 'Only fill the below if you would like to change the password for this user.', - 'users_system_public' => 'Aquest usuari representa qualsevol usuari convidat que visita la vostra instància. No es pot fer servir per a iniciar la sessió però s\'assigna automàticament.', - 'users_delete' => 'Suprimeix l\'usuari', - 'users_delete_named' => 'Suprimeix l\'usuari :userName', - 'users_delete_warning' => 'Se suprimirà completament del sistema l\'usuari amb el nom \':userName\'.', + 'users_role' => 'Rols de l’usuari', + 'users_role_desc' => 'Seleccioneu a quins rols s’assignarà l’usuari. Si un usuari s’assigna a múltiples rols, els permisos dels rols s’acumularan i l’usuari rebrà totes les habilitats dels rols assignats.', + 'users_password' => 'Contrasenya de l’usuari', + 'users_password_desc' => 'Definiu una contrasenya que s’utilitzarà per a iniciar la sessió a l’aplicació. Cal que tingui un mínim de 8 caràcters.', + 'users_send_invite_text' => 'Podeu elegir enviar un correu d’invitació a aquest usuari, la qual cosa li permetrà definir la seva contrasenya, o podeu definir-li una contrasenya vós.', + 'users_send_invite_option' => 'Envia un correu d’invitació a l’usuari', + 'users_external_auth_id' => 'Identificador d’autenticació extern', + 'users_external_auth_id_desc' => 'Quan es fa servir un sistema d’autenticació extern (com ara SAML2, OIDC o LDAP), aquest és l’identificador que enllaça aquest usuari del BookStack amb el compte del sistema d’autenticació. Podeu ignorar aquest camp si feu servir l’autenticació basada en correu electrònic per defecte.', + 'users_password_warning' => 'Ompliu-ho només si voleu canviar la contrasenya d’aquest usuari.', + 'users_system_public' => 'Aquest usuari representa qualsevol usuari convidat que visita la vostra instància. No es pot fer servir per a iniciar la sessió, però s’assigna automàticament.', + 'users_delete' => 'Suprimeix l’usuari', + 'users_delete_named' => 'Suprimeix l’usuari :userName', + 'users_delete_warning' => 'Se suprimirà completament del sistema l’usuari amb el nom «:userName».', 'users_delete_confirm' => 'Segur que voleu suprimir aquest usuari?', - 'users_migrate_ownership' => 'Migra l\'autoria', - 'users_migrate_ownership_desc' => 'Seleccioneu un usuari si voleu que un altre usuari esdevingui el propietari de tots els elements que ara són propietat d\'aquest usuari.', + 'users_migrate_ownership' => 'Migra l’autoria', + 'users_migrate_ownership_desc' => 'Seleccioneu un usuari si voleu que un altre usuari esdevingui el propietari de tots els elements que ara són propietat d’aquest usuari.', 'users_none_selected' => 'No hi ha cap usuari seleccionat', - 'users_edit' => 'Edita l\'usuari', + 'users_edit' => 'Edita l’usuari', 'users_edit_profile' => 'Edita el perfil', - 'users_avatar' => 'Avatar de l\'usuari', - 'users_avatar_desc' => 'Seleccioneu una imatge que representi aquest usuari. Hauria de ser un quadrat d\'aproximadament 256 px.', + 'users_avatar' => 'Avatar de l’usuari', + 'users_avatar_desc' => 'Seleccioneu una imatge que representi aquest usuari. Hauria de ser un quadrat d’aproximadament 256 px.', 'users_preferred_language' => 'Llengua preferida', - 'users_preferred_language_desc' => 'Aquesta opció canviarà la llengua utilitzada a la interfície d\'usuari de l\'aplicació. No afectarà el contingut creat pels usuaris.', + 'users_preferred_language_desc' => 'Aquesta opció canviarà la llengua utilitzada a la interfície d’usuari de l’aplicació. No afectarà el contingut creat pels usuaris.', 'users_social_accounts' => 'Comptes socials', - 'users_social_accounts_desc' => 'View the status of the connected social accounts for this user. Social accounts can be used in addition to the primary authentication system for system access.', - 'users_social_accounts_info' => 'Aquí podeu connectar altres comptes per a un inici de sessió més ràpid i còmode. Si desconnecteu un compte aquí, no en revoqueu l\'accés d\'autorització donat amb anterioritat. Revoqueu-hi l\'accés a la configuració del perfil del compte social que hàgiu connectat.', + 'users_social_accounts_desc' => 'Vegeu l’estat dels comptes socials connectats d’aquest usuari. Els comptes socials es poden fer servir per a accedir al sistema de manera addicional al sistema d’autenticació principal.', + 'users_social_accounts_info' => 'Aquí podeu connectar altres comptes per a un inici de sessió més ràpid i còmode. Si desconnecteu un compte aquí, no en revoqueu l’accés d’autorització donat amb anterioritat. Revoqueu-hi l’accés a la configuració del perfil del compte social que hàgiu connectat.', 'users_social_connect' => 'Connecta un compte', 'users_social_disconnect' => 'Desconnecta el compte', - 'users_social_status_connected' => 'Connected', - 'users_social_status_disconnected' => 'Disconnected', - 'users_social_connected' => 'El compte de :socialAccount s\'ha associat correctament al vostre perfil.', - 'users_social_disconnected' => 'El compte de :socialAccount s\'ha desassociat correctament del vostre perfil.', - 'users_api_tokens' => 'Testimonis d\'API', - 'users_api_tokens_desc' => 'Create and manage the access tokens used to authenticate with the BookStack REST API. Permissions for the API are managed via the user that the token belongs to.', - 'users_api_tokens_none' => 'No s\'ha creat cap testimoni d\'API per a aquest usuari', + 'users_social_status_connected' => 'Connectat', + 'users_social_status_disconnected' => 'Desconnectat', + 'users_social_connected' => 'El compte de :socialAccount s’ha associat correctament al vostre perfil.', + 'users_social_disconnected' => 'El compte de :socialAccount ’ha desassociat correctament del vostre perfil.', + 'users_api_tokens' => 'Testimonis de l’API', + 'users_api_tokens_desc' => 'Creeu i gestioneu els testimonis d’accés que s’utilitzen per a autenticar-vos a l’API REST del BookStack. Els permisos de l’API es gestionen fent servir l’usuari al qual pertany el testimoni.', + 'users_api_tokens_none' => 'No s’ha creat cap testimoni de l’API per a aquest usuari', 'users_api_tokens_create' => 'Crea un testimoni', 'users_api_tokens_expires' => 'Caducitat', - 'users_api_tokens_docs' => 'Documentació de l\'API', - 'users_mfa' => 'Multi-Factor Authentication', - 'users_mfa_desc' => 'Setup multi-factor authentication as an extra layer of security for your user account.', - 'users_mfa_x_methods' => ':count method configured|:count methods configured', - 'users_mfa_configure' => 'Configure Methods', + 'users_api_tokens_docs' => 'Documentació de l’API', + 'users_mfa' => 'Autenticació de múltiple factor', + 'users_mfa_desc' => 'Configureu l’autenticació de múltiple factor com a capa extra de seguretat en el vostre compte d’usuari.', + 'users_mfa_x_methods' => ':count mètode configurat|:count mètodes configurats', + 'users_mfa_configure' => 'Configura els mètodes', // API Tokens - 'user_api_token_create' => 'Crea un testimoni d\'API', + 'user_api_token_create' => 'Crea un testimoni de l’API', 'user_api_token_name' => 'Nom', 'user_api_token_name_desc' => 'Poseu un nom llegible al vostre testimoni com a recordatori futur del propòsit al qual el voleu destinar.', 'user_api_token_expiry' => 'Data de caducitat', - 'user_api_token_expiry_desc' => 'Definiu una data en què aquest testimoni caducarà. Després d\'aquesta data, les peticions fetes amb aquest testimoni deixaran de funcionar. Si deixeu aquest camp en blanc, es definirà una caducitat d\'aquí a 100 anys..', - 'user_api_token_create_secret_message' => 'Just després de crear aquest testimoni, es generaran i es mostraran un "Identificador del testimoni" i un "Secret del testimoni". El secret només es mostrarà una única vegada, assegureu-vos de copiar-lo a un lloc segur abans de continuar.', - 'user_api_token' => 'Testimoni d\'API', + 'user_api_token_expiry_desc' => 'Definiu una data en què aquest testimoni caducarà. Després d’aquesta data, les peticions fetes amb aquest testimoni deixaran de funcionar. Si deixeu aquest camp en blanc, es definirà una caducitat d’aquí a 100 anys.', + 'user_api_token_create_secret_message' => 'Just després de crear aquest testimoni, es generaran i es mostraran un «Identificador del testimoni» i un «Secret del testimoni». El secret només es mostrarà una única vegada: assegureu-vos de copiar-lo a un lloc segur abans de continuar.', + 'user_api_token' => 'Testimoni de l’API', 'user_api_token_id' => 'Identificador del testimoni', - 'user_api_token_id_desc' => 'Aquest identificador és generat pel sistema per a aquest testimoni i no és editable, caldrà que el proporcioneu a les peticions a l\'API.', + 'user_api_token_id_desc' => 'Aquest identificador és generat pel sistema per a aquest testimoni i no és editable i caldrà que el proporcioneu a les peticions a l’API.', 'user_api_token_secret' => 'Secret del testimoni', - 'user_api_token_secret_desc' => 'Aquest secret és generat pel sistema per a aquest testimoni, caldrà que el proporcioneu a les peticions a l\'API. Només es mostrarà aquesta única vegada, assegureu-vos de copiar-lo a un lloc segur.', + 'user_api_token_secret_desc' => 'Aquest secret és generat pel sistema per a aquest testimoni i caldrà que el proporcioneu a les peticions a l’API. Només es mostrarà aquesta única vegada, assegureu-vos de copiar-lo a un lloc segur.', 'user_api_token_created' => 'Testimoni creat :timeAgo', 'user_api_token_updated' => 'Testimoni actualitzat :timeAgo', 'user_api_token_delete' => 'Suprimeix el testimoni', - 'user_api_token_delete_warning' => 'Se suprimirà completament del sistema aquest testimoni d\'API amb el nom \':tokenName\'.', - 'user_api_token_delete_confirm' => 'Segur que voleu suprimir aquest testimoni d\'API?', + 'user_api_token_delete_warning' => 'Se suprimirà completament del sistema aquest testimoni de l’API amb el nom «:tokenName».', + 'user_api_token_delete_confirm' => 'Segur que voleu suprimir aquest testimoni de l’API?', // Webhooks 'webhooks' => 'Webhooks', - 'webhooks_index_desc' => 'Webhooks are a way to send data to external URLs when certain actions and events occur within the system which allows event-based integration with external platforms such as messaging or notification systems.', - 'webhooks_x_trigger_events' => ':count trigger event|:count trigger events', - 'webhooks_create' => 'Create New Webhook', - 'webhooks_none_created' => 'No webhooks have yet been created.', - 'webhooks_edit' => 'Edit Webhook', - 'webhooks_save' => 'Save Webhook', - 'webhooks_details' => 'Webhook Details', - 'webhooks_details_desc' => 'Provide a user friendly name and a POST endpoint as a location for the webhook data to be sent to.', - 'webhooks_events' => 'Webhook Events', - 'webhooks_events_desc' => 'Select all the events that should trigger this webhook to be called.', - 'webhooks_events_warning' => 'Keep in mind that these events will be triggered for all selected events, even if custom permissions are applied. Ensure that use of this webhook won\'t expose confidential content.', - 'webhooks_events_all' => 'All system events', - 'webhooks_name' => 'Webhook Name', - 'webhooks_timeout' => 'Webhook Request Timeout (Seconds)', - 'webhooks_endpoint' => 'Webhook Endpoint', - 'webhooks_active' => 'Webhook Active', - 'webhook_events_table_header' => 'Events', - 'webhooks_delete' => 'Delete Webhook', - 'webhooks_delete_warning' => 'This will fully delete this webhook, with the name \':webhookName\', from the system.', - 'webhooks_delete_confirm' => 'Are you sure you want to delete this webhook?', - 'webhooks_format_example' => 'Webhook Format Example', - 'webhooks_format_example_desc' => 'Webhook data is sent as a POST request to the configured endpoint as JSON following the format below. The "related_item" and "url" properties are optional and will depend on the type of event triggered.', - 'webhooks_status' => 'Webhook Status', - 'webhooks_last_called' => 'Last Called:', - 'webhooks_last_errored' => 'Last Errored:', - 'webhooks_last_error_message' => 'Last Error Message:', + 'webhooks_index_desc' => 'Els webhooks són una manera d’enviar dades a URL externs quan es produeixen certes accions i esdeveniments al sistema, la qual cosa permet una integració basada en esdeveniments amb plataformes externs, com ara sistemes de missatgeria o de notificacions.', + 'webhooks_x_trigger_events' => ':count esdeveniment disparador|:count elements disparadors', + 'webhooks_create' => 'Crea un webhook nou', + 'webhooks_none_created' => 'Encara no s’ha creat cap webhook.', + 'webhooks_edit' => 'Edita el webhook', + 'webhooks_save' => 'Desa el webhook', + 'webhooks_details' => 'Detalls del webhook', + 'webhooks_details_desc' => 'Proporcioneu un nom amigable i un endpoint POST com a ubicació on s’enviaran les dades del webhook.', + 'webhooks_events' => 'Esdeveniments del webhook', + 'webhooks_events_desc' => 'Seleccioneu tots els esdeveniments que haurien de fer que es cridés aquest webhook.', + 'webhooks_events_warning' => 'Tingueu en compte que aquests esdeveniments es produiran per a tots els esdeveniments seleccionats, fins i tot si s’hi apliquen permisos personalitzats. Assegureu-vos que aquest webhook no exposarà contingut confidencial.', + 'webhooks_events_all' => 'Tots els esdeveniments del sistema', + 'webhooks_name' => 'Nom del webhook', + 'webhooks_timeout' => 'Temps d’espera de les peticions al webhook (en segons)', + 'webhooks_endpoint' => 'Endpoint del webhook', + 'webhooks_active' => 'Webhook actiu', + 'webhook_events_table_header' => 'Esdeveniments', + 'webhooks_delete' => 'Suprimeix el webhook', + 'webhooks_delete_warning' => 'Se suprimirà completament del sistema el webhook amb el nom «:webhookName».', + 'webhooks_delete_confirm' => 'Segur que voleu suprimir aquest webhook?', + 'webhooks_format_example' => 'Exemple del format del webhook', + 'webhooks_format_example_desc' => 'Les dades del webhook s’envien com una petició POST a l’endpoint configurat amb un JSON que segueix el següent format. Les propietats «related_item» i «url» són opcionals i dependran del tipus d’esdeveniment produït.', + 'webhooks_status' => 'Estat del webhook', + 'webhooks_last_called' => 'Cridat per darrera vegada:', + 'webhooks_last_errored' => 'Error per darrera vegada:', + 'webhooks_last_error_message' => 'Darrer missatge d’error:', //! If editing translations files directly please ignore this in all @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/ca/validation.php b/lang/ca/validation.php index bc9be7d05..b73a66c5c 100644 --- a/lang/ca/validation.php +++ b/lang/ca/validation.php @@ -8,17 +8,17 @@ return [ // Standard laravel validation lines - 'accepted' => 'Cal que acceptis :attribute.', - 'active_url' => 'L\':attribute no és un URL vàlid.', + 'accepted' => 'Cal que accepteu el camp :attribute.', + 'active_url' => 'El camp :attribute no és un URL vàlid.', 'after' => 'El camp :attribute ha de ser una data posterior a :date.', 'alpha' => 'El camp :attribute només pot contenir lletres.', 'alpha_dash' => 'El camp :attribute només pot contenir lletres, números, guions i guions baixos.', 'alpha_num' => 'El camp :attribute només pot contenir lletres i números.', 'array' => 'El camp :attribute ha de ser un vector.', - 'backup_codes' => 'The provided code is not valid or has already been used.', + 'backup_codes' => 'El codi que heu proporcionat no és vàlid o ja s’ha fet servir.', 'before' => 'El camp :attribute ha de ser una data anterior a :date.', 'between' => [ - 'numeric' => 'El camp :attribute ha d\'estar entre :min i :max.', + 'numeric' => 'El camp :attribute ha d’estar entre :min i :max.', 'file' => 'El camp :attribute ha de tenir entre :min i :max kilobytes.', 'string' => 'El camp :attribute ha de tenir entre :min i :max caràcters.', 'array' => 'El camp :attribute ha de tenir entre :min i :max elements.', @@ -31,8 +31,8 @@ return [ 'digits' => 'El camp :attribute ha de tenir :digits dígits.', 'digits_between' => 'El camp :attribute ha de tenir entre :min i :max dígits.', 'email' => 'El camp :attribute ha de ser una adreça electrònica vàlida.', - 'ends_with' => 'El camp :attribute ha d\'acabar amb un dels següents valors: :values', - 'file' => 'The :attribute must be provided as a valid file.', + 'ends_with' => 'El camp :attribute ha d’acabar amb un dels següents valors: :values', + 'file' => 'El camp :attribute ha de ser un fitxer vàlid.', 'filled' => 'El camp :attribute és obligatori.', 'gt' => [ 'numeric' => 'El camp :attribute ha de ser més gran que :value.', @@ -46,9 +46,9 @@ return [ 'string' => 'El camp :attribute ha de tenir :value caràcters o més.', 'array' => 'El camp :attribute ha de tenir :value elements o més.', ], - 'exists' => 'El camp :attribute no és vàlid.', + 'exists' => 'El camp :attribute seleccionat no és vàlid.', 'image' => 'El camp :attribute ha de ser una imatge.', - 'image_extension' => 'El camp :attribute ha de tenir una extensió d\'imatge vàlida i suportada.', + 'image_extension' => 'El camp :attribute ha de tenir una extensió d’imatge vàlida i suportada.', 'in' => 'El camp :attribute seleccionat no és vàlid.', 'integer' => 'El camp :attribute ha de ser un enter.', 'ip' => 'El camp :attribute ha de ser una adreça IP vàlida.', @@ -87,11 +87,11 @@ return [ 'required' => 'El camp :attribute és obligatori.', 'required_if' => 'El camp :attribute és obligatori quan :other és :value.', 'required_with' => 'El camp :attribute és obligatori quan hi ha aquest valor: :values.', - 'required_with_all' => 'El camp :attribute és obligatori quan hi ha algun d\'aquests valors: :values.', + 'required_with_all' => 'El camp :attribute és obligatori quan hi ha algun d’aquests valors: :values.', 'required_without' => 'El camp :attribute és obligatori quan no hi ha aquest valor: :values.', - 'required_without_all' => 'El camp :attribute és obligatori quan no hi ha cap d\'aquests valors: :values.', + 'required_without_all' => 'El camp :attribute és obligatori quan no hi ha cap d’aquests valors: :values.', 'same' => 'Els camps :attribute i :other han de coincidir.', - 'safe_url' => 'L\'enllaç proporcionat podria no ser segur.', + 'safe_url' => 'L’enllaç proporcionat podria no ser segur.', 'size' => [ 'numeric' => 'El camp :attribute ha de ser :size.', 'file' => 'El camp :attribute ha de tenir :size kilobytes.', @@ -100,10 +100,10 @@ return [ ], 'string' => 'El camp :attribute ha de ser una cadena.', 'timezone' => 'El camp :attribute ha de ser una zona vàlida.', - 'totp' => 'The provided code is not valid or has expired.', - 'unique' => 'El camp :attribute ja està ocupat.', + 'totp' => 'El codi que heu proporcionat no és vàlid o ha caducat.', + 'unique' => 'El camp :attribute ja es fa servir.', 'url' => 'El format del camp :attribute no és vàlid.', - 'uploaded' => 'No s\'ha pogut pujar el fitxer. És possible que el servidor no accepti fitxers d\'aquesta mida.', + 'uploaded' => 'No s’ha pogut pujar el fitxer. És possible que el servidor no accepti fitxers d’aquesta mida.', // Custom validation lines 'custom' => [ diff --git a/lang/cs/common.php b/lang/cs/common.php index cf1b12922..506f53281 100644 --- a/lang/cs/common.php +++ b/lang/cs/common.php @@ -52,7 +52,7 @@ return [ 'filter_clear' => 'Zrušit filtr', 'download' => 'Stáhnout', 'open_in_tab' => 'Otevřít v nové záložce', - 'open' => 'Open', + 'open' => 'Otevřít', // Sort Options 'sort_options' => 'Možnosti řazení', diff --git a/lang/cs/components.php b/lang/cs/components.php index 8e5b7f009..d265d49b6 100644 --- a/lang/cs/components.php +++ b/lang/cs/components.php @@ -34,8 +34,8 @@ return [ 'image_delete_success' => 'Obrázek byl odstraněn', 'image_replace' => 'Nahradit obrázek', 'image_replace_success' => 'Obrázek úspěšně vytvořen', - 'image_rebuild_thumbs' => 'Regenerate Size Variations', - 'image_rebuild_thumbs_success' => 'Image size variations successfully rebuilt!', + 'image_rebuild_thumbs' => 'Přegenerovat všechny velikosti', + 'image_rebuild_thumbs_success' => 'Všechny velikostní varianty obrázku byly úspěšně znovu vytvořeny!', // Code Editor 'code_editor' => 'Upravit kód', diff --git a/lang/cs/entities.php b/lang/cs/entities.php index 6381c43f2..55b2e71de 100644 --- a/lang/cs/entities.php +++ b/lang/cs/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Aktualizováno :timeLength', 'meta_updated_name' => 'Aktualizováno :timeLength uživatelem :user', 'meta_owned_name' => 'Vlastník :user', - 'meta_reference_page_count' => 'Odkazováno na 1 stránce|Odkazováno na :count stranách', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Výběr entity', 'entity_select_lack_permission' => 'Nemáte dostatečná oprávnění k výběru této položky', 'images' => 'Obrázky', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Upravit knihu :bookName', 'books_form_book_name' => 'Název knihy', 'books_save' => 'Uložit knihu', + 'books_default_template' => 'Výchozí šablona stránky', + 'books_default_template_explain' => 'Přiřadit šablonu stránky, která bude použita jako výchozí obsah pro všechny nové stránky v této knize. Mějte na paměti, že šablona bude použita pouze v případě, že tvůrce stránek bude mít přístup k těmto vybraným stránkám šablony.', + 'books_default_template_select' => 'Vyberte šablonu stránky', 'books_permissions' => 'Oprávnění knihy', 'books_permissions_updated' => 'Oprávnění knihy byla aktualizována', 'books_empty_contents' => 'Pro tuto knihu nebyly vytvořeny žádné stránky ani kapitoly.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Odstranit koncept stránky', 'pages_delete_success' => 'Stránka odstraněna', 'pages_delete_draft_success' => 'Koncept stránky odstraněn', + 'pages_delete_warning_template' => 'Tato stránka je aktivní výchozí šablona. Tyto knihy již nebudou mít výchozí šablonu stránky přiřazenou po odstranění této stránky.', 'pages_delete_confirm' => 'Opravdu chcete odstranit tuto stránku?', 'pages_delete_draft_confirm' => 'Opravdu chcete odstranit tento koncept stránky?', 'pages_editing_named' => 'Úpravy stránky :pageName', @@ -295,7 +299,7 @@ return [ 'pages_is_template' => 'Šablona stránky', // Editor Sidebar - 'toggle_sidebar' => 'Toggle Sidebar', + 'toggle_sidebar' => 'Skrýt/Zobrazit postranní panel', 'page_tags' => 'Štítky stránky', 'chapter_tags' => 'Štítky kapitoly', 'book_tags' => 'Štítky knihy', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Odkazy', 'references_none' => 'Nebyly nalezeny žádné odkazy na tuto položku.', - 'references_to_desc' => 'Níže jsou uvedeny všechny známé stránky systému, které odkazují na tuto položku.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Sledovat', diff --git a/lang/cs/errors.php b/lang/cs/errors.php index 3b38ec00b..5d2cab690 100644 --- a/lang/cs/errors.php +++ b/lang/cs/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'Není nainstalováno rozšíření LDAP pro PHP', 'ldap_cannot_connect' => 'Nelze se připojit k adresáři LDAP. Prvotní připojení selhalo.', 'saml_already_logged_in' => 'Již jste přihlášeni', - 'saml_user_not_registered' => 'Uživatel :name není registrován a automatická registrace je zakázána', 'saml_no_email_address' => 'Nelze najít e-mailovou adresu pro tohoto uživatele v datech poskytnutých externím přihlašovacím systémem', 'saml_invalid_response_id' => 'Požadavek z externího ověřovacího systému nebyl rozpoznám procesem, který tato aplikace spustila. Tento problém může způsobit stisknutí tlačítka Zpět po přihlášení.', 'saml_fail_authed' => 'Přihlášení pomocí :system selhalo, systém neposkytl úspěšnou autorizaci', @@ -44,16 +43,16 @@ return [ 'cannot_get_image_from_url' => 'Nelze získat obrázek z adresy :url', 'cannot_create_thumbs' => 'Server nedokáže udělat náhledy. Zkontrolujte, že rozšíření GD pro PHP je nainstalováno.', 'server_upload_limit' => 'Server nepovoluje nahrávat tak veliké soubory. Zkuste prosím menší soubor.', - 'server_post_limit' => 'The server cannot receive the provided amount of data. Try again with less data or a smaller file.', + 'server_post_limit' => 'Server nemůže přijmout takové množství dat. Zkuste to znovu s méně daty nebo menším souborem.', 'uploaded' => 'Server nepovoluje nahrávat tak veliké soubory. Zkuste prosím menší soubor.', // Drawing & Images 'image_upload_error' => 'Nastala chyba během nahrávání souboru', 'image_upload_type_error' => 'Typ nahrávaného obrázku je neplatný.', 'image_upload_replace_type' => 'Náhrady souboru obrázku musí být stejného typu', - 'image_upload_memory_limit' => 'Failed to handle image upload and/or create thumbnails due to system resource limits.', - 'image_thumbnail_memory_limit' => 'Failed to create image size variations due to system resource limits.', - 'image_gallery_thumbnail_memory_limit' => 'Failed to create gallery thumbnails due to system resource limits.', + 'image_upload_memory_limit' => 'Nepodařilo se zpracovat nahrávaný obrázek anebo vytvořit náhledy z důvodu omezených systémových prostředků.', + 'image_thumbnail_memory_limit' => 'Nepodařilo se vytvořit všechny velikostní varianty obrázku z důvodu omezených systémových prostředků.', + 'image_gallery_thumbnail_memory_limit' => 'Nepodařilo se vytvořit náhledy alba z důvodu omezených systémových prostředků.', 'drawing_data_not_found' => 'Data výkresu nelze načíst. Výkresový soubor již nemusí existovat nebo nemusí mít oprávnění k němu přistupovat.', // Attachments diff --git a/lang/cs/notifications.php b/lang/cs/notifications.php index 00c4030a4..b16eb3429 100644 --- a/lang/cs/notifications.php +++ b/lang/cs/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'Aby se zabránilo hromadnému zasílání upozornění, na nějakou dobu nebudete posílat oznámení o dalších úpravách této stránky stejným editorem.', 'detail_page_name' => 'Název stránky:', + 'detail_page_path' => 'Cesta ke stránce:', 'detail_commenter' => 'Komentoval:', 'detail_comment' => 'Komentář:', 'detail_created_by' => 'Vytvořil:', diff --git a/lang/cs/preferences.php b/lang/cs/preferences.php index 638fe4c63..295fb5ca1 100644 --- a/lang/cs/preferences.php +++ b/lang/cs/preferences.php @@ -5,10 +5,10 @@ */ return [ - 'my_account' => 'My Account', + 'my_account' => 'Můj účet', 'shortcuts' => 'Zkratky', - 'shortcuts_interface' => 'UI Shortcut Preferences', + 'shortcuts_interface' => 'Nastavení klávesových zkratek', 'shortcuts_toggle_desc' => 'Zde můžete povolit nebo zakázat klávesové zkratky systémového rozhraní používané pro navigaci a akce.', 'shortcuts_customize_desc' => 'Po výběru vstupu pro zástupce si můžete přizpůsobit všechny klávesové zkratky.', 'shortcuts_toggle_label' => 'Klávesové zkratky povoleny', @@ -29,23 +29,23 @@ return [ 'notifications_watched' => 'Sledované a ignorované položky', 'notifications_watched_desc' => ' Níže jsou položky, které mají vlastní nastavení hodinek. Chcete-li aktualizovat vaše předvolby, podívejte se na položku a pak najděte možnosti hodinek v postranním panelu.', - 'auth' => 'Access & Security', - 'auth_change_password' => 'Change Password', - 'auth_change_password_desc' => 'Change the password you use to log-in to the application. This must be at least 8 characters long.', - 'auth_change_password_success' => 'Password has been updated!', + 'auth' => 'Přístup a zabezpečení', + 'auth_change_password' => 'Změnit heslo', + 'auth_change_password_desc' => 'Změňte heslo, které používáte pro přihlášení do aplikace. Musí být minimálně 8 znaků dlouhé.', + 'auth_change_password_success' => 'Heslo bylo aktualizováno!', - 'profile' => 'Profile Details', - 'profile_desc' => 'Manage the details of your account which represents you to other users, in addition to details that are used for communication and system personalisation.', - 'profile_view_public' => 'View Public Profile', - 'profile_name_desc' => 'Configure your display name which will be visible to other users in the system through the activity you perform, and content you own.', - 'profile_email_desc' => 'This email will be used for notifications and, depending on active system authentication, system access.', - 'profile_email_no_permission' => 'Unfortunately you don\'t have permission to change your email address. If you want to change this, you\'d need to ask an administrator to change this for you.', - 'profile_avatar_desc' => 'Select an image which will be used to represent yourself to others in the system. Ideally this image should be square and about 256px in width and height.', - 'profile_admin_options' => 'Administrator Options', - 'profile_admin_options_desc' => 'Additional administrator-level options, like those to manage role assignments, can be found for your user account in the "Settings > Users" area of the application.', + 'profile' => 'Podrobnosti profilu', + 'profile_desc' => 'Spravujte údaje k vašemu účtu, které vás reprezentují před ostatními uživateli, kromě údajů, které se používají pro komunikaci a přizpůsobení systému.', + 'profile_view_public' => 'Zobrazit veřejný profil', + 'profile_name_desc' => 'Nastavte vaše zobrazované jméno, které bude viditelné ostatním uživatelům v systému prostřednictvím provedených aktivit a vlastního obsahu.', + 'profile_email_desc' => 'Tento e-mail bude použit pro oznámení a přístup do systému v závislosti na systémové autentizaci.', + 'profile_email_no_permission' => 'Bohužel nemáte oprávnění ke změně své e-mailové adresy. Pokud ji chcete změnit, musíte požádat správce, aby provedl tuto změnu za vás.', + 'profile_avatar_desc' => 'Vyberte obrázek, který bude použit k vaší prezentaci pro ostatní v systému. Ideálně by tento obrázek měl být čtverec o velikosti 256px na šířku a výšku.', + 'profile_admin_options' => 'Možnosti správce', + 'profile_admin_options_desc' => 'Další možnosti na úrovni administrátora. Například ty, které spravují přiřazení rolí lze najít pro váš účet v sekci "Nastavení > Uživatelé".', - 'delete_account' => 'Delete Account', - 'delete_my_account' => 'Delete My Account', - 'delete_my_account_desc' => 'This will fully delete your user account from the system. You will not be able to recover this account or revert this action. Content you\'ve created, such as created pages and uploaded images, will remain.', - 'delete_my_account_warning' => 'Are you sure you want to delete your account?', + 'delete_account' => 'Smazat účet', + 'delete_my_account' => 'Smazat můj účet', + 'delete_my_account_desc' => 'Tímto zcela smažete váš účet ze systému. Nebudete moci tento účet obnovit nebo tuto akci vrátit. Obsah, který jste vytvořili, jako jsou vytvořené stránky a nahrané obrázky, zůstanou zachovány.', + 'delete_my_account_warning' => 'Opravdu si přejete smazat váš účet?', ]; diff --git a/lang/cs/settings.php b/lang/cs/settings.php index 04c290634..9542debe7 100644 --- a/lang/cs/settings.php +++ b/lang/cs/settings.php @@ -9,7 +9,7 @@ return [ // Common Messages 'settings' => 'Nastavení', 'settings_save' => 'Uložit nastavení', - 'system_version' => 'Verze systému: ', + 'system_version' => 'Verze systému', 'categories' => 'Kategorie', // App Settings @@ -193,8 +193,8 @@ return [ 'users_send_invite_text' => 'Uživateli můžete poslat pozvánku e-mailem, která umožní uživateli, aby si zvolil sám svoje heslo do aplikace a nebo můžete zadat heslo sami.', 'users_send_invite_option' => 'Poslat uživateli pozvánku e-mailem', 'users_external_auth_id' => 'Přihlašovací identifikátor třetích stran', - 'users_external_auth_id_desc' => 'When an external authentication system is in use (such as SAML2, OIDC or LDAP) this is the ID which links this BookStack user to the authentication system account. You can ignore this field if using the default email-based authentication.', - 'users_password_warning' => 'Only fill the below if you would like to change the password for this user.', + 'users_external_auth_id_desc' => 'Při použití externího autentizačního systému (např. SAML2, OIDC nebo LDAP) toto je ID, které spojuje tohoto BookStack uživatele s ověřovacím systémem. Toto pole můžete ignorovat, pokud používáte ověření pomocí e-mailu.', + 'users_password_warning' => 'Vyplňte pouze v případě, že chcete změnit heslo pro tohoto uživatele.', 'users_system_public' => 'Symbolizuje každého nepřihlášeného návštěvníka, který navštívil aplikaci. Nelze ho použít k přihlášení ale je přiřazen automaticky nepřihlášeným.', 'users_delete' => 'Odstranit uživatele', 'users_delete_named' => 'Odstranit uživatele :userName', @@ -210,16 +210,16 @@ return [ 'users_preferred_language' => 'Preferovaný jazyk', 'users_preferred_language_desc' => 'Tato volba ovlivní pouze jazyk používaný v uživatelském rozhraní aplikace. Volba nemá vliv na žádný uživateli vytvářený obsah.', 'users_social_accounts' => 'Sociální účty', - 'users_social_accounts_desc' => 'View the status of the connected social accounts for this user. Social accounts can be used in addition to the primary authentication system for system access.', + 'users_social_accounts_desc' => 'Zobrazit stav připojených sociálních účtů tohoto uživatele. Sociální účty mohou být použity pro přístup do systému vedle hlavního systému ověřování.', 'users_social_accounts_info' => 'Zde můžete přidat vaše účty ze sociálních sítí pro pohodlnější přihlašování. Odpojení účtů neznamená, že tato aplikace ztratí práva číst detaily z vašeho účtu. Zakázat této aplikaci přístup k detailům vašeho účtu musíte přímo ve svém profilu na dané sociální síti.', 'users_social_connect' => 'Připojit účet', 'users_social_disconnect' => 'Odpojit účet', - 'users_social_status_connected' => 'Connected', - 'users_social_status_disconnected' => 'Disconnected', + 'users_social_status_connected' => 'Připojeno', + 'users_social_status_disconnected' => 'Odpojeno', 'users_social_connected' => 'Účet :socialAccount byl připojen k vašemu profilu.', 'users_social_disconnected' => 'Účet :socialAccount byl odpojen od vašeho profilu.', 'users_api_tokens' => 'API Tokeny', - 'users_api_tokens_desc' => 'Create and manage the access tokens used to authenticate with the BookStack REST API. Permissions for the API are managed via the user that the token belongs to.', + 'users_api_tokens_desc' => 'Vytvořte a spravujte přístupové tokeny používané pro ověření k REST API aplikace BookStack. Oprávnění pro API jsou spravována prostřednictvím uživatele, kterému token patří.', 'users_api_tokens_none' => 'Tento uživatel nemá vytvořené žádné API Tokeny', 'users_api_tokens_create' => 'Vytvořit Token', 'users_api_tokens_expires' => 'Vyprší', @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/cy/entities.php b/lang/cy/entities.php index cfb5aae1a..f1f915544 100644 --- a/lang/cy/entities.php +++ b/lang/cy/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Updated :timeLength', 'meta_updated_name' => 'Updated :timeLength by :user', 'meta_owned_name' => 'Owned by :user', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Entity Select', 'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item', 'images' => 'Images', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Edit Book :bookName', 'books_form_book_name' => 'Book Name', 'books_save' => 'Save Book', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Book Permissions', 'books_permissions_updated' => 'Book Permissions Updated', 'books_empty_contents' => 'No pages or chapters have been created for this book.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Delete Draft Page', 'pages_delete_success' => 'Page deleted', 'pages_delete_draft_success' => 'Draft page deleted', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Are you sure you want to delete this page?', 'pages_delete_draft_confirm' => 'Are you sure you want to delete this draft page?', 'pages_editing_named' => 'Editing Page :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'References', 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/cy/errors.php b/lang/cy/errors.php index 5ba7edf59..a85f74fd5 100644 --- a/lang/cy/errors.php +++ b/lang/cy/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'Estyniad PHP LDAP heb ei osod', 'ldap_cannot_connect' => 'Methu cysylltu i weinydd ldap, cysylltiad cychwynnol wedi methu', 'saml_already_logged_in' => 'Wedi mewngofnodi yn barod', - 'saml_user_not_registered' => 'Nid yw\'r defnyddiwr :name wedi\'i gofrestru ac mae cofrestriad awtomatig wedi\'i analluogi', 'saml_no_email_address' => 'Methu dod o hyd i gyfeiriad e-bost, ar gyfer y defnyddiwr hwn, yn y data a ddarparwyd gan y system ddilysu allanol', 'saml_invalid_response_id' => 'Nid yw\'r cais o\'r system ddilysu allanol yn cael ei gydnabod gan broses a ddechreuwyd gan y cais hwn. Gallai llywio yn ôl ar ôl mewngofnodi achosi\'r broblem hon.', 'saml_fail_authed' => 'Wedi methu mewngofnodi gan ddefnyddio :system, ni roddodd y system awdurdodiad llwyddiannus', diff --git a/lang/cy/notifications.php b/lang/cy/notifications.php index 5539ae9a9..1afd23f1d 100644 --- a/lang/cy/notifications.php +++ b/lang/cy/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/cy/settings.php b/lang/cy/settings.php index c5ca662c3..03e9bf462 100644 --- a/lang/cy/settings.php +++ b/lang/cy/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/da/entities.php b/lang/da/entities.php index 6453d92ce..88945019c 100644 --- a/lang/da/entities.php +++ b/lang/da/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Opdateret :timeLength', 'meta_updated_name' => 'Opdateret :timeLength af :user', 'meta_owned_name' => 'Ejet af :user', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Vælg emne', 'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item', 'images' => 'Billeder', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Rediger bog :bookName', 'books_form_book_name' => 'Bognavn', 'books_save' => 'Gem bog', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Bogtilladelser', 'books_permissions_updated' => 'Bogtilladelser opdateret', 'books_empty_contents' => 'Ingen sider eller kapitler er blevet oprettet i denne bog.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Slet kladdeside', 'pages_delete_success' => 'Side slettet', 'pages_delete_draft_success' => 'Kladdeside slettet', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Er du sikker på, du vil slette denne side?', 'pages_delete_draft_confirm' => 'Er du sikker på at du vil slette denne kladdesidde?', 'pages_editing_named' => 'Redigerer :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'References', 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/da/errors.php b/lang/da/errors.php index 5c64219c9..162a74763 100644 --- a/lang/da/errors.php +++ b/lang/da/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'LDAP PHP udvidelse er ikke installeret', 'ldap_cannot_connect' => 'Kan ikke forbinde til ldap server. Indledende forbindelse mislykkedes', 'saml_already_logged_in' => 'Allerede logget ind', - 'saml_user_not_registered' => 'Brugeren :name er ikke registreret, og automatisk registrering er slået fra', 'saml_no_email_address' => 'Kunne ikke finde en e-mail-adresse for denne bruger i de data, der leveres af det eksterne godkendelsessystem', 'saml_invalid_response_id' => 'Anmodningen fra det eksterne godkendelsessystem genkendes ikke af en proces, der er startet af denne applikation. Navigering tilbage efter et login kan forårsage dette problem.', 'saml_fail_authed' => 'Login ved hjælp af :system failed, systemet har ikke givet tilladelse', diff --git a/lang/da/notifications.php b/lang/da/notifications.php index 5539ae9a9..1afd23f1d 100644 --- a/lang/da/notifications.php +++ b/lang/da/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/da/settings.php b/lang/da/settings.php index 3cecd1b86..13ef813c6 100644 --- a/lang/da/settings.php +++ b/lang/da/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'Hebraisk', 'hr' => 'Hrvatski', diff --git a/lang/de/entities.php b/lang/de/entities.php index 2d223ef42..21a0d3bef 100644 --- a/lang/de/entities.php +++ b/lang/de/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Zuletzt aktualisiert: :timeLength', 'meta_updated_name' => 'Zuletzt aktualisiert: :timeLength von :user', 'meta_owned_name' => 'Im Besitz von :user', - 'meta_reference_page_count' => 'Verwiesen auf 1 Seite|Verwiesen auf :count Seiten', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Eintrag auswählen', 'entity_select_lack_permission' => 'Sie haben nicht die benötigte Berechtigung, um dieses Element auszuwählen', 'images' => 'Bilder', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Buch ":bookName" bearbeiten', 'books_form_book_name' => 'Name des Buches', 'books_save' => 'Buch speichern', + 'books_default_template' => 'Standard Seitentemplate', + 'books_default_template_explain' => 'Zuweisen einer Seitenvorlage, die als Standardinhalt für alle neuen Seiten in diesem Buch verwendet wird. Beachten Sie, dass dies nur dann verwendet wird, wenn der Ersteller einer Seite Zugriff auf die ausgewählte Template-Seite hat.', + 'books_default_template_select' => 'Template-Seite auswählen', 'books_permissions' => 'Buch-Berechtigungen', 'books_permissions_updated' => 'Buch-Berechtigungen aktualisiert', 'books_empty_contents' => 'Es sind noch keine Seiten oder Kapitel zu diesem Buch hinzugefügt worden.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Seitenentwurf löschen', 'pages_delete_success' => 'Seite gelöscht', 'pages_delete_draft_success' => 'Seitenentwurf gelöscht', + 'pages_delete_warning_template' => 'Diese Seite wird aktiv als Standardvorlage für Seiten in diesem Buch verwendet. Diese Bücher haben nach dem Löschen dieser Seite keine Standardvorlage mehr zugewiesen.', 'pages_delete_confirm' => 'Sind Sie sicher, dass Sie diese Seite löschen möchen?', 'pages_delete_draft_confirm' => 'Sind Sie sicher, dass Sie diesen Seitenentwurf löschen möchten?', 'pages_editing_named' => 'Seite ":pageName" bearbeiten', @@ -212,7 +216,7 @@ return [ 'pages_edit_draft' => 'Seitenentwurf bearbeiten', 'pages_editing_draft' => 'Seitenentwurf bearbeiten', 'pages_editing_page' => 'Seite bearbeiten', - 'pages_edit_draft_save_at' => 'Entwurf gespeichert um ', + 'pages_edit_draft_save_at' => 'Entwurf gesichert um ', 'pages_edit_delete_draft' => 'Entwurf löschen', 'pages_edit_delete_draft_confirm' => 'Sind Sie sicher, dass Sie Ihren Entwurf löschen möchten? Alle Ihre Änderungen seit dem letzten vollständigen Speichern gehen verloren und der Editor wird mit dem letzten Speicherzustand aktualisiert, der kein Entwurf ist.', 'pages_edit_discard_draft' => 'Entwurf verwerfen', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Verweise', 'references_none' => 'Es gibt keine nachverfolgten Referenzen zu diesem Element.', - 'references_to_desc' => 'Nachfolgend sind alle bekannten Seiten im System aufgeführt, die auf diesen Artikel verweisen.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Beobachten', diff --git a/lang/de/errors.php b/lang/de/errors.php index 639373f34..2fd34c00d 100644 --- a/lang/de/errors.php +++ b/lang/de/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'LDAP-PHP-Erweiterung ist nicht installiert.', 'ldap_cannot_connect' => 'Die Verbindung zum LDAP-Server ist fehlgeschlagen. Beim initialen Verbindungsaufbau trat ein Fehler auf.', 'saml_already_logged_in' => 'Sie sind bereits angemeldet', - 'saml_user_not_registered' => 'Es ist kein Benutzer mit ID :name registriert und die automatische Registrierung ist deaktiviert', 'saml_no_email_address' => 'Es konnte keine E-Mail-Adresse für diesen Benutzer in den vom externen Authentifizierungssystem zur Verfügung gestellten Daten gefunden werden', 'saml_invalid_response_id' => 'Die Anfrage vom externen Authentifizierungssystem wird von einem von dieser Anwendung gestarteten Prozess nicht erkannt. Das Zurückgehen nach einer Anmeldung könnte dieses Problem verursachen.', 'saml_fail_authed' => 'Anmeldung mit :system fehlgeschlagen, System konnte keine erfolgreiche Autorisierung bereitstellen', diff --git a/lang/de/notifications.php b/lang/de/notifications.php index 314f0bfe3..f3b86b502 100644 --- a/lang/de/notifications.php +++ b/lang/de/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'Um eine Flut von Benachrichtigungen zu vermeiden, werden Sie für eine gewisse Zeit keine Benachrichtigungen für weitere Bearbeitungen dieser Seite durch denselben Bearbeiter erhalten.', 'detail_page_name' => 'Name der Seite:', + 'detail_page_path' => 'Seitenpfad:', 'detail_commenter' => 'Kommentator:', 'detail_comment' => 'Kommentar:', 'detail_created_by' => 'Erstellt von:', diff --git a/lang/de/settings.php b/lang/de/settings.php index c97a1715c..8769a8253 100644 --- a/lang/de/settings.php +++ b/lang/de/settings.php @@ -297,6 +297,7 @@ Hinweis: Benutzer können ihre E-Mail-Adresse nach erfolgreicher Registrierung 'et' => 'Estnisch', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Französisch', 'he' => 'Hebräisch', 'hr' => 'Kroatisch', diff --git a/lang/de_informal/entities.php b/lang/de_informal/entities.php index 063d51967..2da655c1f 100644 --- a/lang/de_informal/entities.php +++ b/lang/de_informal/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Zuletzt aktualisiert: :timeLength', 'meta_updated_name' => 'Zuletzt aktualisiert: :timeLength von :user', 'meta_owned_name' => 'Im Besitz von :user', - 'meta_reference_page_count' => 'Verwiesen auf 1 Seite|Verwiesen auf :count Seiten', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Eintrag auswählen', 'entity_select_lack_permission' => 'Du hast nicht die benötigte Berechtigung, um dieses Element auszuwählen', 'images' => 'Bilder', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Buch ":bookName" bearbeiten', 'books_form_book_name' => 'Name des Buches', 'books_save' => 'Buch speichern', + 'books_default_template' => 'Standard Seitentemplate', + 'books_default_template_explain' => 'Zuweisen einer Seitenvorlage, die als Standardinhalt für alle neuen Seiten in diesem Buch verwendet wird. Beachte, dass dies nur dann verwendet wird, wenn der Ersteller einer Seite Zugriff auf die ausgewählte Template-Seite hat.', + 'books_default_template_select' => 'Template-Seite auswählen', 'books_permissions' => 'Buch-Berechtigungen', 'books_permissions_updated' => 'Buch-Berechtigungen aktualisiert', 'books_empty_contents' => 'Es sind noch keine Seiten oder Kapitel zu diesem Buch hinzugefügt worden.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Seitenentwurf löschen', 'pages_delete_success' => 'Seite gelöscht', 'pages_delete_draft_success' => 'Seitenentwurf gelöscht', + 'pages_delete_warning_template' => 'Diese Seite wird aktiv als Standardvorlage für Seiten in diesem Buch verwendet. Diese Bücher haben nach dem Löschen dieser Seite keine Standardvorlage mehr zugewiesen.', 'pages_delete_confirm' => 'Bist du sicher, dass du diese Seite löschen möchtest?', 'pages_delete_draft_confirm' => 'Bist du sicher, dass du diesen Seitenentwurf löschen möchtest?', 'pages_editing_named' => 'Seite ":pageName" bearbeiten', @@ -212,7 +216,7 @@ return [ 'pages_edit_draft' => 'Seitenentwurf bearbeiten', 'pages_editing_draft' => 'Seitenentwurf bearbeiten', 'pages_editing_page' => 'Seite bearbeiten', - 'pages_edit_draft_save_at' => 'Entwurf gespeichert um ', + 'pages_edit_draft_save_at' => 'Entwurf gesichert um ', 'pages_edit_delete_draft' => 'Entwurf löschen', 'pages_edit_delete_draft_confirm' => 'Bist du sicher, dass du deinen Entwurf löschen möchtest? Alle deine Änderungen seit dem letzten vollständigen Speichern gehen verloren und der Editor wird mit dem letzten Speicherzustand aktualisiert, der kein Entwurf ist.', 'pages_edit_discard_draft' => 'Entwurf verwerfen', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Verweise', 'references_none' => 'Es gibt keine nachverfolgten Referenzen zu diesem Element.', - 'references_to_desc' => 'Nachfolgend sind alle bekannten Seiten im System aufgeführt, die auf diesen Artikel verweisen.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Beobachten', diff --git a/lang/de_informal/errors.php b/lang/de_informal/errors.php index c91fede4f..ad7a36d23 100644 --- a/lang/de_informal/errors.php +++ b/lang/de_informal/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'LDAP-PHP-Erweiterung ist nicht installiert', 'ldap_cannot_connect' => 'Die Verbindung zum LDAP-Server ist fehlgeschlagen. Beim initialen Verbindungsaufbau trat ein Fehler auf', 'saml_already_logged_in' => 'Du bist bereits angemeldet', - 'saml_user_not_registered' => 'Kein Benutzer mit ID :name registriert und die automatische Registrierung ist deaktiviert', 'saml_no_email_address' => 'Es konnte keine E-Mail-Adresse für diesen Benutzer in den vom externen Authentifizierungssystem zur Verfügung gestellten Daten gefunden werden', 'saml_invalid_response_id' => 'Die Anfrage vom externen Authentifizierungssystem wird von einem von dieser Anwendung gestarteten Prozess nicht erkannt. Das Zurückblättern nach einem Login könnte dieses Problem verursachen.', 'saml_fail_authed' => 'Anmeldung mit :system fehlgeschlagen, System konnte keine erfolgreiche Autorisierung bereitstellen', diff --git a/lang/de_informal/notifications.php b/lang/de_informal/notifications.php index fc6204d50..0bf7739f4 100644 --- a/lang/de_informal/notifications.php +++ b/lang/de_informal/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'Um eine Flut von Benachrichtigungen zu vermeiden, wirst du für eine gewisse Zeit keine Benachrichtigungen für weitere Bearbeitungen dieser Seite durch denselben Bearbeiter erhalten.', 'detail_page_name' => 'Seitenname:', + 'detail_page_path' => 'Seitenpfad:', 'detail_commenter' => 'Kommentator:', 'detail_comment' => 'Kommentar:', 'detail_created_by' => 'Erstellt von:', diff --git a/lang/de_informal/settings.php b/lang/de_informal/settings.php index dc5721ac9..5cd898240 100644 --- a/lang/de_informal/settings.php +++ b/lang/de_informal/settings.php @@ -297,6 +297,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'et' => 'Estnisch', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Französisch', 'he' => 'עברית', 'hr' => 'Kroatisch', diff --git a/lang/el/entities.php b/lang/el/entities.php index 031844662..8aabdda0a 100644 --- a/lang/el/entities.php +++ b/lang/el/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Ενημερώθηκε :timeLength', 'meta_updated_name' => 'Ενημερώθηκε :timeLength από :user', 'meta_owned_name' => 'Ανήκει στον :user', - 'meta_reference_page_count' => 'Αναφορά σε :count σελίδας|Αναφορά στο :count σελίδες', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Επιλογή Οντότητας', 'entity_select_lack_permission' => 'Δεν έχετε τα απαιτούμενα δικαιώματα για να επιλέξετε αυτό το στοιχείο', 'images' => 'Εικόνες', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Επεξεργασία Βιβλίου :bookname', 'books_form_book_name' => 'Όνομα Βιβλίου', 'books_save' => 'Αποθήκευση Βιβλίου', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Άδειες Βιβλίου', 'books_permissions_updated' => 'Τα Δικαιώματα Βιβλίου Ενημερώθηκαν', 'books_empty_contents' => 'Δεν έχουν δημιουργηθεί σελίδες ή κεφάλαια για αυτό το βιβλίο.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Διαγραφή Προσχέδιας Σελίδας', 'pages_delete_success' => 'Η σελίδα διαγράφηκε', 'pages_delete_draft_success' => 'Η προσχέδια (πρόχειρη) σελίδα διαγράφηκε', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτή τη σελίδα;', 'pages_delete_draft_confirm' => 'Θέλετε σίγουρα να διαγράψετε την προσχέδια σελίδα;', 'pages_editing_named' => 'Επεξεργασία Σελίδας :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Αναφορές', 'references_none' => 'Δεν υπάρχουν αναφορές παρακολούθησης σε αυτό το στοιχείο.', - 'references_to_desc' => 'Παρακάτω εμφανίζονται όλες οι γνωστές σελίδες του συστήματος που συνδέονται με αυτό το στοιχείο.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/el/errors.php b/lang/el/errors.php index e42d0a855..efb20b1b6 100644 --- a/lang/el/errors.php +++ b/lang/el/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'Η επέκταση LDAP PHP δεν εγκαταστάθηκε', 'ldap_cannot_connect' => 'Αδυναμία σύνδεσης στο διακομιστή ldap, η αρχική σύνδεση απέτυχε', 'saml_already_logged_in' => 'Ήδη συνδεδεμένος', - 'saml_user_not_registered' => 'Ο χρήστης :name δεν είναι εγγεγραμμένος και η αυτόματη εγγραφή είναι απενεργοποιημένη', 'saml_no_email_address' => 'Δεν ήταν δυνατή η εύρεση μιας διεύθυνσης ηλεκτρονικού ταχυδρομείου, για αυτόν τον χρήστη, στα δεδομένα που παρέχονται από το εξωτερικό σύστημα ελέγχου ταυτότητας', 'saml_invalid_response_id' => 'Το αίτημα από το εξωτερικό σύστημα ελέγχου ταυτότητας δεν αναγνωρίζεται από μια διαδικασία που ξεκίνησε από αυτή την εφαρμογή. Η πλοήγηση πίσω μετά από μια σύνδεση θα μπορούσε να προκαλέσει αυτό το ζήτημα.', 'saml_fail_authed' => 'Η σύνδεση με τη χρήση :system απέτυχε, το σύστημα δεν παρείχε επιτυχή εξουσιοδότηση', diff --git a/lang/el/notifications.php b/lang/el/notifications.php index 5539ae9a9..1afd23f1d 100644 --- a/lang/el/notifications.php +++ b/lang/el/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/el/settings.php b/lang/el/settings.php index f9c199fc3..0c3497e64 100644 --- a/lang/el/settings.php +++ b/lang/el/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/en/entities.php b/lang/en/entities.php index cfb5aae1a..f1f915544 100644 --- a/lang/en/entities.php +++ b/lang/en/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Updated :timeLength', 'meta_updated_name' => 'Updated :timeLength by :user', 'meta_owned_name' => 'Owned by :user', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Entity Select', 'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item', 'images' => 'Images', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Edit Book :bookName', 'books_form_book_name' => 'Book Name', 'books_save' => 'Save Book', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Book Permissions', 'books_permissions_updated' => 'Book Permissions Updated', 'books_empty_contents' => 'No pages or chapters have been created for this book.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Delete Draft Page', 'pages_delete_success' => 'Page deleted', 'pages_delete_draft_success' => 'Draft page deleted', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Are you sure you want to delete this page?', 'pages_delete_draft_confirm' => 'Are you sure you want to delete this draft page?', 'pages_editing_named' => 'Editing Page :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'References', 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/en/errors.php b/lang/en/errors.php index 8813cf90a..607b6ea83 100644 --- a/lang/en/errors.php +++ b/lang/en/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'LDAP PHP extension not installed', 'ldap_cannot_connect' => 'Cannot connect to ldap server, Initial connection failed', 'saml_already_logged_in' => 'Already logged in', - 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', diff --git a/lang/en/notifications.php b/lang/en/notifications.php index 5539ae9a9..1afd23f1d 100644 --- a/lang/en/notifications.php +++ b/lang/en/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/en/settings.php b/lang/en/settings.php index c5ca662c3..03e9bf462 100644 --- a/lang/en/settings.php +++ b/lang/en/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/es/entities.php b/lang/es/entities.php index ff2b8b8d5..82cf3e692 100644 --- a/lang/es/entities.php +++ b/lang/es/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Actualizado :timeLength', 'meta_updated_name' => 'Actualizado :timeLength por :user', 'meta_owned_name' => 'Propiedad de :user', - 'meta_reference_page_count' => 'Referido en :count página | Referido en :count paginas', + 'meta_reference_count' => 'Referido en :count página | Referido en :count paginas', 'entity_select' => 'Seleccione entidad', 'entity_select_lack_permission' => 'No tiene los permisos necesarios para seleccionar este elemento', 'images' => 'Imágenes', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Editar Libro :bookName', 'books_form_book_name' => 'Nombre de libro', 'books_save' => 'Guardar libro', + 'books_default_template' => 'Plantilla de página por defecto', + 'books_default_template_explain' => 'Asigne una plantilla de página que se utilizará como contenido predeterminado para todas las páginas nuevas de este libro. Tenga en cuenta que esto sólo se utilizará si el creador de páginas tiene acceso a la página elegida.', + 'books_default_template_select' => 'Seleccione una página de plantilla', 'books_permissions' => 'Permisos del libro', 'books_permissions_updated' => 'Permisos del libro actualizados', 'books_empty_contents' => 'Ninguna página o capítulo ha sido creada para este libro.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Borrar borrador de página', 'pages_delete_success' => 'Página borrada', 'pages_delete_draft_success' => 'Borrador de página borrado', + 'pages_delete_warning_template' => 'Esta página está en uso como plantilla de página predeterminada del libro. Estos libros ya no tendrán una plantilla de página predeterminada asignada después de eliminar esta página.', 'pages_delete_confirm' => '¿Está seguro de borrar esta página?', 'pages_delete_draft_confirm' => '¿Está seguro de que desea borrar este borrador de página?', 'pages_editing_named' => 'Editando página :pageName', diff --git a/lang/es/errors.php b/lang/es/errors.php index f32aa1cec..9fb7afba4 100644 --- a/lang/es/errors.php +++ b/lang/es/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'La extensión LDAP PHP no se encuentra instalada', 'ldap_cannot_connect' => 'No se puede conectar con el servidor ldap, la conexión inicial ha fallado', 'saml_already_logged_in' => 'Ya estás conectado', - 'saml_user_not_registered' => 'El usuario :name no está registrado y el registro automático está deshabilitado', 'saml_no_email_address' => 'No se pudo encontrar una dirección de correo electrónico, para este usuario, en los datos proporcionados por el sistema de autenticación externo', 'saml_invalid_response_id' => 'La solicitud del sistema de autenticación externo no está reconocida por un proceso iniciado por esta aplicación. Navegar hacia atrás después de un inicio de sesión podría causar este problema.', 'saml_fail_authed' => 'El inicio de sesión con :system falló, el sistema no proporcionó una autorización correcta', diff --git a/lang/es/notifications.php b/lang/es/notifications.php index 4e76a5924..5ebc42129 100644 --- a/lang/es/notifications.php +++ b/lang/es/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'Para prevenir notificaciones en masa, durante un tiempo no se enviarán notificaciones para futuras ediciones de esta página por el mismo editor.', 'detail_page_name' => 'Nombre de página:', + 'detail_page_path' => 'Ruta de la página:', 'detail_commenter' => 'Autor del comentario:', 'detail_comment' => 'Comentario:', 'detail_created_by' => 'Creado por:', diff --git a/lang/es/settings.php b/lang/es/settings.php index 221a96e1c..0d0cf221e 100644 --- a/lang/es/settings.php +++ b/lang/es/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Francés', 'he' => 'עברית', 'hr' => 'Croata', diff --git a/lang/es_AR/entities.php b/lang/es_AR/entities.php index 32c1b24b4..3afb54bcd 100644 --- a/lang/es_AR/entities.php +++ b/lang/es_AR/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Actualizado el :timeLength', 'meta_updated_name' => 'Actualizado el :timeLength por :user', 'meta_owned_name' => 'Propiedad de :user', - 'meta_reference_page_count' => 'Referido en :count página | Referido en :count paginas', + 'meta_reference_count' => 'Referido en :count página | Referido en :count paginas', 'entity_select' => 'Seleccione entidad', 'entity_select_lack_permission' => 'No tiene los permisos necesarios para seleccionar este elemento', 'images' => 'Imágenes', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Editar Libro :bookName', 'books_form_book_name' => 'Nombre de libro', 'books_save' => 'Guardar libro', + 'books_default_template' => 'Plantilla de página por defecto', + 'books_default_template_explain' => 'Asigne una plantilla de página que se utilizará como contenido predeterminado para todas las páginas nuevas de este libro. Tenga en cuenta que esto sólo se utilizará si el creador de páginas tiene acceso a la página elegida.', + 'books_default_template_select' => 'Seleccione una página de plantilla', 'books_permissions' => 'permisos de libro', 'books_permissions_updated' => 'Permisos de libro actualizados', 'books_empty_contents' => 'Ninguna página o capítulo ha sido creada para este libro.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Borrar borrador de página', 'pages_delete_success' => 'Página borrada', 'pages_delete_draft_success' => 'Borrador de página borrado', + 'pages_delete_warning_template' => 'Esta página está en uso como plantilla de página predeterminada del libro. Estos libros ya no tendrán una plantilla de página predeterminada asignada después de eliminar esta página.', 'pages_delete_confirm' => '¿Está seguro de borrar esta página?', 'pages_delete_draft_confirm' => 'Está seguro de que desea borrar este borrador de página?', 'pages_editing_named' => 'Editando página :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Referencias', 'references_none' => 'No hay referencias a este elemento.', - 'references_to_desc' => 'A continuación se muestran todas las páginas en el sistema que tienen un enlace a este elemento.', + 'references_to_desc' => 'A continuación se muestran todas las páginas en el sistema que enlazan a este elemento.', // Watch Options 'watch' => 'Suscribirme', diff --git a/lang/es_AR/errors.php b/lang/es_AR/errors.php index d5e08220a..e784b5092 100644 --- a/lang/es_AR/errors.php +++ b/lang/es_AR/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'La extensión LDAP PHP no se encuentra instalada', 'ldap_cannot_connect' => 'No se puede conectar con el servidor ldap, la conexión inicial ha fallado', 'saml_already_logged_in' => 'Ya estás conectado', - 'saml_user_not_registered' => 'El usuario :name no está registrado y el registro automático está deshabilitado', 'saml_no_email_address' => 'No se pudo encontrar una dirección de correo electrónico, para este usuario, en los datos proporcionados por el sistema de autenticación externo', 'saml_invalid_response_id' => 'La solicitud del sistema de autenticación externo no está reconocida por un proceso iniciado por esta aplicación. Navegar hacia atrás después de un inicio de sesión podría causar este problema.', 'saml_fail_authed' => 'El inicio de sesión con :system falló, el sistema no proporcionó una autorización correcta', diff --git a/lang/es_AR/notifications.php b/lang/es_AR/notifications.php index 4e76a5924..5ebc42129 100644 --- a/lang/es_AR/notifications.php +++ b/lang/es_AR/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'Para prevenir notificaciones en masa, durante un tiempo no se enviarán notificaciones para futuras ediciones de esta página por el mismo editor.', 'detail_page_name' => 'Nombre de página:', + 'detail_page_path' => 'Ruta de la página:', 'detail_commenter' => 'Autor del comentario:', 'detail_comment' => 'Comentario:', 'detail_created_by' => 'Creado por:', diff --git a/lang/es_AR/settings.php b/lang/es_AR/settings.php index 50d2e7c70..7c1cba813 100644 --- a/lang/es_AR/settings.php +++ b/lang/es_AR/settings.php @@ -297,6 +297,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Francés', 'he' => 'עברית', 'hr' => 'Croata', diff --git a/lang/et/entities.php b/lang/et/entities.php index 8e6a84e10..cd9606c63 100644 --- a/lang/et/entities.php +++ b/lang/et/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Muudetud :timeLength', 'meta_updated_name' => 'Muudetud :timeLength kasutaja :user poolt', 'meta_owned_name' => 'Kuulub kasutajale :user', - 'meta_reference_page_count' => 'Viidatud :count lehel|Viidatud :count lehel', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Objekti valik', 'entity_select_lack_permission' => 'Sul pole õiguseid selle objekti valimiseks', 'images' => 'Pildid', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Muuda raamatut :bookName', 'books_form_book_name' => 'Raamatu pealkiri', 'books_save' => 'Salvesta raamat', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Raamatu õigused', 'books_permissions_updated' => 'Raamatu õigused muudetud', 'books_empty_contents' => 'Ühtegi lehte ega peatükki pole lisatud.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Kustuta mustand', 'pages_delete_success' => 'Leht kustutatud', 'pages_delete_draft_success' => 'Mustand kustutatud', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Kas oled kindel, et soovid selle lehe kustutada?', 'pages_delete_draft_confirm' => 'Kas oled kindel, et soovid selle mustandi kustutada?', 'pages_editing_named' => 'Lehe :pageName muutmine', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Viited', 'references_none' => 'Sellele objektile ei ole viiteid.', - 'references_to_desc' => 'Allpool on kõik teadaolevad lehed, mis sellele objektile viitavad.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Jälgi', diff --git a/lang/et/errors.php b/lang/et/errors.php index 3145a0b29..56e8c9cd6 100644 --- a/lang/et/errors.php +++ b/lang/et/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'PHP LDAP laiendus ei ole paigaldatud', 'ldap_cannot_connect' => 'Ühendus LDAP serveriga ebaõnnestus', 'saml_already_logged_in' => 'Juba sisse logitud', - 'saml_user_not_registered' => 'Kasutaja :name ei ole registreeritud ning automaatne registreerimine on keelatud', 'saml_no_email_address' => 'Selle kasutaja e-posti aadressi ei õnnestunud välisest autentimissüsteemist leida', 'saml_invalid_response_id' => 'Välisest autentimissüsteemist tulnud päringut ei algatatud sellest rakendusest. Seda viga võib põhjustada pärast sisselogimist tagasi liikumine.', 'saml_fail_authed' => 'Sisenemine :system kaudu ebaõnnestus, süsteem ei andnud volitust', diff --git a/lang/et/notifications.php b/lang/et/notifications.php index 6a2c2d8bf..0b5fc814c 100644 --- a/lang/et/notifications.php +++ b/lang/et/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'Et vältida liigseid teavitusi, ei saadeta sulle mõnda aega teavitusi selle lehe muutmiste kohta sama kasutaja poolt.', 'detail_page_name' => 'Lehe nimetus:', + 'detail_page_path' => 'Lehe asukoht:', 'detail_commenter' => 'Kommenteerija:', 'detail_comment' => 'Kommentaar:', 'detail_created_by' => 'Autor:', diff --git a/lang/et/preferences.php b/lang/et/preferences.php index ee3b9e5ea..9ac77a965 100644 --- a/lang/et/preferences.php +++ b/lang/et/preferences.php @@ -35,7 +35,7 @@ return [ 'auth_change_password_success' => 'Parool on muudetud!', 'profile' => 'Profiili detailid', - 'profile_desc' => 'Manage the details of your account which represents you to other users, in addition to details that are used for communication and system personalisation.', + 'profile_desc' => 'Halda oma konto andmeid, mis sind teistele kasutajatele esindab, lisaks andmetele, mida kasutatakse suhtluseks ja süsteemi kohaldamiseks.', 'profile_view_public' => 'Vaata avalikku profiili', 'profile_name_desc' => 'Seadista oma avalik nimi, mis on nähtav teistele kasutajatele sinu tehtud tegevuste ja sulle kuuluva sisu kaudu.', 'profile_email_desc' => 'Seda e-posti aadressi kasutatakse teavituste saatmiseks ning, sõltuvalt aktiivsest autentimismeetodist, süsteemile ligipääsemiseks.', diff --git a/lang/et/settings.php b/lang/et/settings.php index b4a5ca174..01822ed81 100644 --- a/lang/et/settings.php +++ b/lang/et/settings.php @@ -193,8 +193,8 @@ return [ 'users_send_invite_text' => 'Sa võid kasutajale saata e-postiga kutse, mis võimaldab neil ise parooli seada. Vastasel juhul määra parool ise.', 'users_send_invite_option' => 'Saada e-postiga kutse', 'users_external_auth_id' => 'Välise autentimise ID', - 'users_external_auth_id_desc' => 'When an external authentication system is in use (such as SAML2, OIDC or LDAP) this is the ID which links this BookStack user to the authentication system account. You can ignore this field if using the default email-based authentication.', - 'users_password_warning' => 'Only fill the below if you would like to change the password for this user.', + 'users_external_auth_id_desc' => 'Kui kasutusel on väline autentimissüsteem (nagu SAML2, OIDC või LDAP), siis see ID ühendab selle BookStack kasutaja autentimissüsteemi kasutajakontoga. Kui kasutad vaikimisi e-posti põhist autentimist, võid seda välja ignoreerida.', + 'users_password_warning' => 'Täida allolevad väljad ainult siis, kui soovid selle kasutaja parooli muuta.', 'users_system_public' => 'See kasutaja tähistab kõiki külalisi, kes su rakendust vaatavad. Selle kontoga ei saa sisse logida, see määratakse automaatselt.', 'users_delete' => 'Kustuta kasutaja', 'users_delete_named' => 'Kustuta kasutaja :userName', @@ -210,16 +210,16 @@ return [ 'users_preferred_language' => 'Eelistatud keel', 'users_preferred_language_desc' => 'See valik muudab rakenduse kasutajaliidese keelt. Kasutajate loodud sisu see ei mõjuta.', 'users_social_accounts' => 'Sotsiaalmeedia kontod', - 'users_social_accounts_desc' => 'View the status of the connected social accounts for this user. Social accounts can be used in addition to the primary authentication system for system access.', + 'users_social_accounts_desc' => 'Vaata selle kasutaja ühendatud sotsiaalmeedia kontode seisundit. Sotsiaalmeedia kontosid saab kasutada süsteemile ligipääsemiseks, lisaks primaarsele autentimissüsteemile.', 'users_social_accounts_info' => 'Siin saad seostada teised kontod, millega kiiremini ja lihtsamini sisse logida. Siit konto eemaldamine ei tühista varem lubatud ligipääsu. Ligipääsu saad tühistada ühendatud konto profiili seadetest.', 'users_social_connect' => 'Lisa konto', 'users_social_disconnect' => 'Eemalda konto', - 'users_social_status_connected' => 'Connected', - 'users_social_status_disconnected' => 'Disconnected', + 'users_social_status_connected' => 'Ühendatud', + 'users_social_status_disconnected' => 'Ühendus katkestatud', 'users_social_connected' => ':socialAccount konto lisati su profiilile.', 'users_social_disconnected' => ':socialAccount konto eemaldati su profiililt.', 'users_api_tokens' => 'API tunnused', - 'users_api_tokens_desc' => 'Create and manage the access tokens used to authenticate with the BookStack REST API. Permissions for the API are managed via the user that the token belongs to.', + 'users_api_tokens_desc' => 'Lisa ja halda BookStack REST API-ga autentimiseks mõeldud ligipääsutunnuseid. API kasutamise õigused on määratud ksautaja kaudu, kellele ligipääsutunnus kuulub.', 'users_api_tokens_none' => 'Sellel kasutajal pole API tunnuseid', 'users_api_tokens_create' => 'Lisa tunnus', 'users_api_tokens_expires' => 'Aegub', @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français (prantsuse keel)', 'he' => 'עברית (heebrea keel)', 'hr' => 'Hrvatski (horvaadi keel)', diff --git a/lang/eu/entities.php b/lang/eu/entities.php index bc31d372e..d3582283f 100644 --- a/lang/eu/entities.php +++ b/lang/eu/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Aldatua :timeLength', 'meta_updated_name' => ':timeLength aldatuta. Erabiltzailea :user', 'meta_owned_name' => ':user da jabea', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Aukeratutako entitatea', 'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item', 'images' => 'Irudiak', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Editatu :bookName liburua', 'books_form_book_name' => 'Liburu izena', 'books_save' => 'Gorde Liburua', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Liburu baimenak', 'books_permissions_updated' => 'Liburu baimenak eguneratuta', 'books_empty_contents' => 'Ez da orri edo kapitulurik sortu liburu honentzat.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Delete Draft Page', 'pages_delete_success' => 'Orria ezabatua', 'pages_delete_draft_success' => 'Draft page deleted', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Ziur al zaude orri hau ezabatu nahi duzula?', 'pages_delete_draft_confirm' => 'Are you sure you want to delete this draft page?', 'pages_editing_named' => 'Editing Page :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'References', 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/eu/errors.php b/lang/eu/errors.php index 1028d3802..2244e0142 100644 --- a/lang/eu/errors.php +++ b/lang/eu/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'PHP LDAP extentsioa ez dago instalatuta', 'ldap_cannot_connect' => 'Ezin izan da ldap zerbitzarira konektatu, hasierako konexioak huts egin du', 'saml_already_logged_in' => 'Saioa aurretik hasita dago', - 'saml_user_not_registered' => ':name erabiltzailea ez dago erregistratua eta erregistro automatikoa ezgaituta dago', 'saml_no_email_address' => 'Ezin izan dugu posta helbiderik aurkitu erabiltzaile honentzat, kanpoko autentifikazio zerbitzuak bidalitako datuetan', 'saml_invalid_response_id' => 'Kanpoko egiazkotasun-sistemaren eskaria ez du onartzen aplikazio honek abiarazitako prozesu batek. Loginean atzera egitea izan daiteke arrazoia.', 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', diff --git a/lang/eu/notifications.php b/lang/eu/notifications.php index 5539ae9a9..1afd23f1d 100644 --- a/lang/eu/notifications.php +++ b/lang/eu/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/eu/settings.php b/lang/eu/settings.php index a9aa41dba..0e6fa2444 100644 --- a/lang/eu/settings.php +++ b/lang/eu/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/fa/entities.php b/lang/fa/entities.php index 900a91b92..bbdbe5b6a 100644 --- a/lang/fa/entities.php +++ b/lang/fa/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'به روزرسانی شده :timeLength', 'meta_updated_name' => 'به روزرسانی شده :timeLength توسط :user', 'meta_owned_name' => 'متعلق به :user', - 'meta_reference_page_count' => 'در 1 صفحه به آن ارجاع داده شده|در :count صفحه به آن ارجاع داده شده', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'انتخاب موجودیت', 'entity_select_lack_permission' => 'شما مجوزهای لازم برای انتخاب این مورد را ندارید', 'images' => 'عکس‌ها', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'ویرایش کتاب:bookName', 'books_form_book_name' => 'نام کتاب', 'books_save' => 'ذخیره کتاب', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'مجوزهای کتاب', 'books_permissions_updated' => 'مجوزهای کتاب به روز شد', 'books_empty_contents' => 'هیچ صفحه یا فصلی برای این کتاب ایجاد نشده است.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'حذف صفحه پیش نویس', 'pages_delete_success' => 'صفحه حذف شد', 'pages_delete_draft_success' => 'صفحه پیش نویس حذف شد', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'آیا مطمئن هستید که می خواهید این صفحه را حذف کنید؟', 'pages_delete_draft_confirm' => 'آیا مطمئن هستید که می خواهید این صفحه پیش نویس را حذف کنید؟', 'pages_editing_named' => 'ویرایش صفحه :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'مراجع', 'references_none' => 'هیچ رفرنسی برای این قلم یافت نشد.', - 'references_to_desc' => 'در زیر تمام صفحات شناخته شده در سیستم که به این مورد پیوند دارند، نشان داده شده است.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'نظارت', diff --git a/lang/fa/errors.php b/lang/fa/errors.php index 2dc4b18e9..6632246da 100644 --- a/lang/fa/errors.php +++ b/lang/fa/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'افزونه PHP LDAP نصب نشده است', 'ldap_cannot_connect' => 'اتصال به سرور LDAP امکان پذیر نیست، اتصال اولیه برقرار نشد', 'saml_already_logged_in' => 'قبلا وارد سیستم شده اید', - 'saml_user_not_registered' => 'کاربر :name ثبت نشده است و ثبت نام خودکار غیرفعال است', 'saml_no_email_address' => 'آدرس داده ای برای این کاربر در داده های ارائه شده توسط سیستم احراز هویت خارجی یافت نشد', 'saml_invalid_response_id' => 'درخواست از سیستم احراز هویت خارجی توسط فرایندی که توسط این نرم افزار آغاز شده است شناخته نمی شود. بازگشت به سیستم پس از ورود به سیستم می تواند باعث این مسئله شود.', 'saml_fail_authed' => 'ورود به سیستم :system انجام نشد، سیستم مجوز موفقیت آمیز ارائه نکرد', diff --git a/lang/fa/notifications.php b/lang/fa/notifications.php index 573c75113..675eaa762 100644 --- a/lang/fa/notifications.php +++ b/lang/fa/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'برای جلوگیری از انبوه اعلان‌ها، برای مدتی اعلان‌ ویرایش‌هایی که توسط همان ویرایشگر در این صفحه انجام می‌شود، ارسال نخواهد شد.', 'detail_page_name' => 'نام صفحه:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'نظر دهنده:', 'detail_comment' => 'نظر:', 'detail_created_by' => 'ایجاد شده توسط:', diff --git a/lang/fa/settings.php b/lang/fa/settings.php index 1b3b04eb5..0659cde46 100644 --- a/lang/fa/settings.php +++ b/lang/fa/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/fi/activities.php b/lang/fi/activities.php index d5b55c03d..6bb267c70 100644 --- a/lang/fi/activities.php +++ b/lang/fi/activities.php @@ -6,119 +6,119 @@ return [ // Pages - 'page_create' => 'created page', - 'page_create_notification' => 'Page successfully created', - 'page_update' => 'updated page', - 'page_update_notification' => 'Page successfully updated', - 'page_delete' => 'deleted page', - 'page_delete_notification' => 'Page successfully deleted', - 'page_restore' => 'restored page', - 'page_restore_notification' => 'Page successfully restored', - 'page_move' => 'moved page', - 'page_move_notification' => 'Page successfully moved', + 'page_create' => 'loi sivun', + 'page_create_notification' => 'Sivu luotiin onnistuneesti', + 'page_update' => 'päivitti sivun', + 'page_update_notification' => 'Sivu päivitettiin onnistuneesti', + 'page_delete' => 'poisti sivun', + 'page_delete_notification' => 'Sivu poistettiin onnistuneesti', + 'page_restore' => 'palautti sivun', + 'page_restore_notification' => 'Sivu palautettiin onnistuneesti', + 'page_move' => 'siirsi sivun', + 'page_move_notification' => 'Sivu siirrettiin onnistuneesti', // Chapters - 'chapter_create' => 'created chapter', - 'chapter_create_notification' => 'Chapter successfully created', - 'chapter_update' => 'updated chapter', - 'chapter_update_notification' => 'Chapter successfully updated', - 'chapter_delete' => 'deleted chapter', - 'chapter_delete_notification' => 'Chapter successfully deleted', - 'chapter_move' => 'moved chapter', - 'chapter_move_notification' => 'Chapter successfully moved', + 'chapter_create' => 'loi luvun', + 'chapter_create_notification' => 'Luku luotiin onnistuneesti', + 'chapter_update' => 'päivitti luvun', + 'chapter_update_notification' => 'Luku päivitettiin onnistuneesti', + 'chapter_delete' => 'poisti luvun', + 'chapter_delete_notification' => 'Sivu poistettiin onnistuneesti', + 'chapter_move' => 'siirsi luvun', + 'chapter_move_notification' => 'Sivu siirrettiin onnistuneesti', // Books - 'book_create' => 'created book', - 'book_create_notification' => 'Book successfully created', - 'book_create_from_chapter' => 'converted chapter to book', - 'book_create_from_chapter_notification' => 'Chapter successfully converted to a book', - 'book_update' => 'updated book', - 'book_update_notification' => 'Book successfully updated', - 'book_delete' => 'deleted book', - 'book_delete_notification' => 'Book successfully deleted', - 'book_sort' => 'sorted book', - 'book_sort_notification' => 'Book successfully re-sorted', + 'book_create' => 'loi kirjan', + 'book_create_notification' => 'Kirja luotiin onnistuneesti', + 'book_create_from_chapter' => 'muunsi luvun kirjaksi', + 'book_create_from_chapter_notification' => 'Luku muunnettiin onnistuneesti kirjaksi', + 'book_update' => 'päivitti kirjan', + 'book_update_notification' => 'Kirja päivitettiin onnistuneesti', + 'book_delete' => 'poisti kirjan', + 'book_delete_notification' => 'Kirja poistettiin onnistuneesti', + 'book_sort' => 'järjesti kirjan', + 'book_sort_notification' => 'Kirja järjestettiin uudelleen onnistuneesti', // Bookshelves - 'bookshelf_create' => 'created shelf', - 'bookshelf_create_notification' => 'Shelf successfully created', - 'bookshelf_create_from_book' => 'converted book to shelf', - 'bookshelf_create_from_book_notification' => 'Book successfully converted to a shelf', - 'bookshelf_update' => 'updated shelf', - 'bookshelf_update_notification' => 'Shelf successfully updated', - 'bookshelf_delete' => 'deleted shelf', - 'bookshelf_delete_notification' => 'Shelf successfully deleted', + 'bookshelf_create' => 'loi hyllyn', + 'bookshelf_create_notification' => 'Hylly luotiin onnistuneesti', + 'bookshelf_create_from_book' => 'muunsi kirjan hyllyksi', + 'bookshelf_create_from_book_notification' => 'Kirja muunnettiin onnistuneesti hyllyksi', + 'bookshelf_update' => 'päivitti hyllyn', + 'bookshelf_update_notification' => 'Hylly päivitettiin onnistuneesti', + 'bookshelf_delete' => 'poisti hyllyn', + 'bookshelf_delete_notification' => 'Hylly poistettiin onnistuneesti', // Revisions - 'revision_restore' => 'restored revision', - 'revision_delete' => 'deleted revision', - 'revision_delete_notification' => 'Revision successfully deleted', + 'revision_restore' => 'palautti version', + 'revision_delete' => 'poisti version', + 'revision_delete_notification' => 'Versio poistettiin onnistuneesti', // Favourites - 'favourite_add_notification' => '":name" has been added to your favourites', - 'favourite_remove_notification' => '":name" has been removed from your favourites', + 'favourite_add_notification' => '":name" on lisätty suosikkeihisi', + 'favourite_remove_notification' => '":name" on poistettu suosikeistasi', // Watching - 'watch_update_level_notification' => 'Watch preferences successfully updated', + 'watch_update_level_notification' => 'Seurannan asetukset päivitetty onnistuneesti', // Auth - 'auth_login' => 'logged in', - 'auth_register' => 'registered as new user', - 'auth_password_reset_request' => 'requested user password reset', - 'auth_password_reset_update' => 'reset user password', - 'mfa_setup_method' => 'configured MFA method', - 'mfa_setup_method_notification' => 'Multi-factor method successfully configured', - 'mfa_remove_method' => 'removed MFA method', - 'mfa_remove_method_notification' => 'Multi-factor method successfully removed', + 'auth_login' => 'kirjautui sisään', + 'auth_register' => 'rekisteröityi uudeksi käyttäjäksi', + 'auth_password_reset_request' => 'pyysi käyttäjän salasanan palautusta', + 'auth_password_reset_update' => 'palautti käyttäjän salasana', + 'mfa_setup_method' => 'määritti monivaiheisen tunnistaumisen menetelmän', + 'mfa_setup_method_notification' => 'Monivaiheisen tunnistautumisen menetelmän määrittäminen onnistui', + 'mfa_remove_method' => 'poisti monivaiheisen tunnistautumisen menetelmän', + 'mfa_remove_method_notification' => 'Monivaiheisen tunnistautumisen menetelmä poistettiin onnistuneesti', // Settings - 'settings_update' => 'updated settings', - 'settings_update_notification' => 'Settings successfully updated', - 'maintenance_action_run' => 'ran maintenance action', + 'settings_update' => 'päivitti asetukset', + 'settings_update_notification' => 'Asetukset päivitettiin onnistuneesti', + 'maintenance_action_run' => 'suoritti huoltotoimenpiteen', // Webhooks - 'webhook_create' => 'created webhook', - 'webhook_create_notification' => 'Webhook successfully created', - 'webhook_update' => 'updated webhook', - 'webhook_update_notification' => 'Webhook successfully updated', - 'webhook_delete' => 'deleted webhook', - 'webhook_delete_notification' => 'Webhook successfully deleted', + 'webhook_create' => 'loi toimintokutsun', + 'webhook_create_notification' => 'Toimintokutsu luotiin onnistuneesti', + 'webhook_update' => 'päivitti toimintokutsun', + 'webhook_update_notification' => 'Toimintokutsu päivitettiin onnistuneesti', + 'webhook_delete' => 'poisti toimintokutsun', + 'webhook_delete_notification' => 'Toimintokutsu poistettiin onnistuneesti', // Users - 'user_create' => 'created user', - 'user_create_notification' => 'User successfully created', - 'user_update' => 'updated user', - 'user_update_notification' => 'User successfully updated', - 'user_delete' => 'deleted user', - 'user_delete_notification' => 'User successfully removed', + 'user_create' => 'loi käyttäjän', + 'user_create_notification' => 'Käyttäjä luotiin onnistuneesti', + 'user_update' => 'päivitti käyttäjän', + 'user_update_notification' => 'Käyttäjä päivitettiin onnistuneesti', + 'user_delete' => 'poisti käyttäjän', + 'user_delete_notification' => 'Käyttäjä poistettiin onnistuneesti', // API Tokens - 'api_token_create' => 'created api token', - 'api_token_create_notification' => 'API token successfully created', - 'api_token_update' => 'updated api token', - 'api_token_update_notification' => 'API token successfully updated', - 'api_token_delete' => 'deleted api token', - 'api_token_delete_notification' => 'API token successfully deleted', + 'api_token_create' => 'loi API-tunnisteen', + 'api_token_create_notification' => 'API-tunniste luotiin onnistuneesti', + 'api_token_update' => 'päivitti API-tunnisteen', + 'api_token_update_notification' => 'API-tunniste päivitettiin onnistuneesti', + 'api_token_delete' => 'poisti API-tunnisteen', + 'api_token_delete_notification' => 'API-tunniste poistettiin onnistuneesti', // Roles - 'role_create' => 'created role', - 'role_create_notification' => 'Role successfully created', - 'role_update' => 'updated role', - 'role_update_notification' => 'Role successfully updated', - 'role_delete' => 'deleted role', - 'role_delete_notification' => 'Role successfully deleted', + 'role_create' => 'loi roolin', + 'role_create_notification' => 'Rooli luotiin onnistuneesti', + 'role_update' => 'päivitti roolin', + 'role_update_notification' => 'Rooli päivitettiin onnistuneesti', + 'role_delete' => 'poisti roolin', + 'role_delete_notification' => 'Rooli poistettiin onnistuneesti', // Recycle Bin - 'recycle_bin_empty' => 'emptied recycle bin', - 'recycle_bin_restore' => 'restored from recycle bin', - 'recycle_bin_destroy' => 'removed from recycle bin', + 'recycle_bin_empty' => 'tyhjensi roskakorin', + 'recycle_bin_restore' => 'palautti roskakorista', + 'recycle_bin_destroy' => 'poisti roskakorista', // Comments - 'commented_on' => 'commented on', - 'comment_create' => 'added comment', - 'comment_update' => 'updated comment', - 'comment_delete' => 'deleted comment', + 'commented_on' => 'kommentoi', + 'comment_create' => 'lisäsi kommentin', + 'comment_update' => 'päivitti kommentin', + 'comment_delete' => 'poisti kommentin', // Other - 'permissions_update' => 'updated permissions', + 'permissions_update' => 'päivitti käyttöoikeudet', ]; diff --git a/lang/fi/auth.php b/lang/fi/auth.php index dc4b242a0..40aca0695 100644 --- a/lang/fi/auth.php +++ b/lang/fi/auth.php @@ -6,112 +6,112 @@ */ return [ - 'failed' => 'These credentials do not match our records.', - 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', + 'failed' => 'Annettuja käyttäjätietoja ei löydy.', + 'throttle' => 'Liikaa kirjautumisyrityksiä. Yritä uudelleen :seconds sekunnin päästä.', // Login & Register - 'sign_up' => 'Sign up', - 'log_in' => 'Log in', - 'log_in_with' => 'Login with :socialDriver', - 'sign_up_with' => 'Sign up with :socialDriver', - 'logout' => 'Logout', + 'sign_up' => 'Rekisteröidy', + 'log_in' => 'Kirjaudu sisään', + 'log_in_with' => 'Kirjaudu sisään palvelulla :socialDriver', + 'sign_up_with' => 'Rekisteröidy palvelulla :socialDriver', + 'logout' => 'Kirjaudu ulos', - 'name' => 'Name', - 'username' => 'Username', - 'email' => 'Email', - 'password' => 'Password', - 'password_confirm' => 'Confirm Password', - 'password_hint' => 'Must be at least 8 characters', - 'forgot_password' => 'Forgot Password?', - 'remember_me' => 'Remember Me', - 'ldap_email_hint' => 'Please enter an email to use for this account.', - 'create_account' => 'Create Account', - 'already_have_account' => 'Already have an account?', - 'dont_have_account' => 'Don\'t have an account?', - 'social_login' => 'Social Login', - 'social_registration' => 'Social Registration', - 'social_registration_text' => 'Register and sign in using another service.', + 'name' => 'Nimi', + 'username' => 'Käyttäjätunnus', + 'email' => 'Sähköposti', + 'password' => 'Salasana', + 'password_confirm' => 'Vahvista salasana', + 'password_hint' => 'Tulee olla vähintään 8 merkkiä', + 'forgot_password' => 'Unohditko salasanan?', + 'remember_me' => 'Muista minut', + 'ldap_email_hint' => 'Ole hyvä ja anna käyttäjätilin sähköpostiosoite.', + 'create_account' => 'Luo käyttäjätili', + 'already_have_account' => 'Onko sinulla jo käyttäjätili?', + 'dont_have_account' => 'Eikö sinulla ole käyttäjätiliä?', + 'social_login' => 'Kirjaudu sosiaalisen median käyttäjätilillä', + 'social_registration' => 'Rekisteröidy sosiaalisen median käyttäjätilillä', + 'social_registration_text' => 'Rekisteröidy ja kirjaudu sisään käyttämällä toista palvelua.', - 'register_thanks' => 'Thanks for registering!', - 'register_confirm' => 'Please check your email and click the confirmation button to access :appName.', - 'registrations_disabled' => 'Registrations are currently disabled', - 'registration_email_domain_invalid' => 'That email domain does not have access to this application', - 'register_success' => 'Thanks for signing up! You are now registered and signed in.', + 'register_thanks' => 'Kiitos rekisteröitymisestä!', + 'register_confirm' => 'Tarkista sähköpostisi ja paina vahvistuspainiketta päästäksesi sovellukseen :appName.', + 'registrations_disabled' => 'Rekisteröityminen on tällä hetkellä pois käytöstä', + 'registration_email_domain_invalid' => 'Tämän sähköpostiosoitteen verkkotunnuksella ei ole pääsyä tähän sovellukseen', + 'register_success' => 'Kiitos liittymisestä! Olet nyt rekisteröitynyt ja kirjautunut sisään.', // Login auto-initiation - 'auto_init_starting' => 'Attempting Login', - 'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.', - 'auto_init_start_link' => 'Proceed with authentication', + 'auto_init_starting' => 'Kirjautumisyritys', + 'auto_init_starting_desc' => 'Otamme yhteyttä tunnistautumisjärjestelmääsi aloittaaksemme kirjautumisprosessin. Jos 5 sekunnin jälkeen ei tapahdu mitään, voit yrittää klikata alla olevaa linkkiä.', + 'auto_init_start_link' => 'Jatka tunnistautumisen avulla', // Password Reset - 'reset_password' => 'Reset Password', - 'reset_password_send_instructions' => 'Enter your email below and you will be sent an email with a password reset link.', - 'reset_password_send_button' => 'Send Reset Link', - 'reset_password_sent' => 'A password reset link will be sent to :email if that email address is found in the system.', - 'reset_password_success' => 'Your password has been successfully reset.', - 'email_reset_subject' => 'Reset your :appName password', - 'email_reset_text' => 'You are receiving this email because we received a password reset request for your account.', - 'email_reset_not_requested' => 'If you did not request a password reset, no further action is required.', + 'reset_password' => 'Palauta salasana', + 'reset_password_send_instructions' => 'Syötä sähköpostiosoitteesi alla olevaan kenttään, niin sinulle lähetetään sähköpostiviesti, jossa on salasanan palautuslinkki.', + 'reset_password_send_button' => 'Lähetä palautuslinkki', + 'reset_password_sent' => 'Salasanan palautuslinkki lähetetään osoitteeseen :email, jos kyseinen sähköpostiosoite löytyy järjestelmästä.', + 'reset_password_success' => 'Salasanasi on onnistuneesti palautettu.', + 'email_reset_subject' => 'Palauta salasanasi sivustolle :appName', + 'email_reset_text' => 'Saat tämän sähköpostiviestin, koska saimme käyttäjätiliäsi koskevan salasanan palautuspyynnön.', + 'email_reset_not_requested' => 'Jos et ole pyytänyt salasanan palauttamista, mitään toimenpiteitä ei tarvita.', // Email Confirmation - 'email_confirm_subject' => 'Confirm your email on :appName', - 'email_confirm_greeting' => 'Thanks for joining :appName!', - 'email_confirm_text' => 'Please confirm your email address by clicking the button below:', - 'email_confirm_action' => 'Confirm Email', - 'email_confirm_send_error' => 'Email confirmation required but the system could not send the email. Contact the admin to ensure email is set up correctly.', - 'email_confirm_success' => 'Your email has been confirmed! You should now be able to login using this email address.', - 'email_confirm_resent' => 'Confirmation email resent, Please check your inbox.', - 'email_confirm_thanks' => 'Thanks for confirming!', - 'email_confirm_thanks_desc' => 'Please wait a moment while your confirmation is handled. If you are not redirected after 3 seconds press the "Continue" link below to proceed.', + 'email_confirm_subject' => 'Vahvista sähköpostisi sovelluksessa :appName', + 'email_confirm_greeting' => 'Kiitos liittymisestä sovellukseen :appName!', + 'email_confirm_text' => 'Vahvista sähköpostiosoitteesi klikkaamalla alla olevaa painiketta:', + 'email_confirm_action' => 'Vahvista sähköpostiosoite', + 'email_confirm_send_error' => 'Sähköpostivahvistusta vaaditaan, mutta järjestelmä ei pystynyt lähettämään sähköpostia. Ota yhteyttä ylläpitäjään varmistaaksesi, että sähköpostiasetukset on määritetty oikein.', + 'email_confirm_success' => 'Sähköpostisi on vahvistettu! Sinun pitäisi nyt pystyä kirjautumaan sisään tällä sähköpostiosoitteella.', + 'email_confirm_resent' => 'Vahvistussähköposti on lähetetty uudelleen, tarkista saapuneet sähköpostisi.', + 'email_confirm_thanks' => 'Kiitos vahvistuksesta!', + 'email_confirm_thanks_desc' => 'Odota hetki, kun vahvistuksesi käsitellään. Jos sinua ei ohjata uudelleen 3 sekunnin kuluttua, paina alla olevaa "Jatka"-linkkiä.', - 'email_not_confirmed' => 'Email Address Not Confirmed', - 'email_not_confirmed_text' => 'Your email address has not yet been confirmed.', - 'email_not_confirmed_click_link' => 'Please click the link in the email that was sent shortly after you registered.', - 'email_not_confirmed_resend' => 'If you cannot find the email you can re-send the confirmation email by submitting the form below.', - 'email_not_confirmed_resend_button' => 'Resend Confirmation Email', + 'email_not_confirmed' => 'Sähköpostiosoitetta ei ole vahvistettu', + 'email_not_confirmed_text' => 'Sähköpostiosoitettasi ei ole vielä vahvistettu.', + 'email_not_confirmed_click_link' => 'Klikkaa rekisteröitymisen jälkeen saapuneessa sähköpostissa olevaa vahvistuslinkkiä.', + 'email_not_confirmed_resend' => 'Jos et löydä sähköpostia, voit lähettää sen uudelleen alla olevalla lomakkeella.', + 'email_not_confirmed_resend_button' => 'Lähetä vahvistusviesti uudelleen', // User Invite - 'user_invite_email_subject' => 'You have been invited to join :appName!', - 'user_invite_email_greeting' => 'An account has been created for you on :appName.', - 'user_invite_email_text' => 'Click the button below to set an account password and gain access:', - 'user_invite_email_action' => 'Set Account Password', - 'user_invite_page_welcome' => 'Welcome to :appName!', - 'user_invite_page_text' => 'To finalise your account and gain access you need to set a password which will be used to log-in to :appName on future visits.', - 'user_invite_page_confirm_button' => 'Confirm Password', - 'user_invite_success_login' => 'Password set, you should now be able to login using your set password to access :appName!', + 'user_invite_email_subject' => 'Sinut on kutsuttu liittymään sivustoon :appName!', + 'user_invite_email_greeting' => 'Sinulle on luotu käyttäjätili sivustolla :appName.', + 'user_invite_email_text' => 'Klikkaa alla olevaa painiketta asettaaksesi tilin salasanan ja saadaksesi pääsyn:', + 'user_invite_email_action' => 'Aseta käyttäjätilin salasana', + 'user_invite_page_welcome' => 'Tervetuloa sivustolle :appName!', + 'user_invite_page_text' => 'Viimeistelläksesi käyttäjätilisi ja saadaksesi pääsyn sinun on asetettava salasana, jolla kirjaudut jatkossa sivustolle :appName.', + 'user_invite_page_confirm_button' => 'Vahvista salasana', + 'user_invite_success_login' => 'Salasana asetettu, sinun pitäisi nyt pystyä kirjautumaan sivustolle :appName käyttämällä antamaasi salasanaa!', // Multi-factor Authentication - 'mfa_setup' => 'Setup Multi-Factor Authentication', - 'mfa_setup_desc' => 'Setup multi-factor authentication as an extra layer of security for your user account.', - 'mfa_setup_configured' => 'Already configured', - 'mfa_setup_reconfigure' => 'Reconfigure', - 'mfa_setup_remove_confirmation' => 'Are you sure you want to remove this multi-factor authentication method?', - 'mfa_setup_action' => 'Setup', - 'mfa_backup_codes_usage_limit_warning' => 'You have less than 5 backup codes remaining, Please generate and store a new set before you run out of codes to prevent being locked out of your account.', - 'mfa_option_totp_title' => 'Mobile App', - 'mfa_option_totp_desc' => 'To use multi-factor authentication you\'ll need a mobile application that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator.', - 'mfa_option_backup_codes_title' => 'Backup Codes', - 'mfa_option_backup_codes_desc' => 'Securely store a set of one-time-use backup codes which you can enter to verify your identity.', - 'mfa_gen_confirm_and_enable' => 'Confirm and Enable', - 'mfa_gen_backup_codes_title' => 'Backup Codes Setup', - 'mfa_gen_backup_codes_desc' => 'Store the below list of codes in a safe place. When accessing the system you\'ll be able to use one of the codes as a second authentication mechanism.', - 'mfa_gen_backup_codes_download' => 'Download Codes', - 'mfa_gen_backup_codes_usage_warning' => 'Each code can only be used once', - 'mfa_gen_totp_title' => 'Mobile App Setup', - 'mfa_gen_totp_desc' => 'To use multi-factor authentication you\'ll need a mobile application that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator.', - 'mfa_gen_totp_scan' => 'Scan the QR code below using your preferred authentication app to get started.', - 'mfa_gen_totp_verify_setup' => 'Verify Setup', - 'mfa_gen_totp_verify_setup_desc' => 'Verify that all is working by entering a code, generated within your authentication app, in the input box below:', - 'mfa_gen_totp_provide_code_here' => 'Provide your app generated code here', - 'mfa_verify_access' => 'Verify Access', - 'mfa_verify_access_desc' => 'Your user account requires you to confirm your identity via an additional level of verification before you\'re granted access. Verify using one of your configured methods to continue.', - 'mfa_verify_no_methods' => 'No Methods Configured', - 'mfa_verify_no_methods_desc' => 'No multi-factor authentication methods could be found for your account. You\'ll need to set up at least one method before you gain access.', - 'mfa_verify_use_totp' => 'Verify using a mobile app', - 'mfa_verify_use_backup_codes' => 'Verify using a backup code', - 'mfa_verify_backup_code' => 'Backup Code', - 'mfa_verify_backup_code_desc' => 'Enter one of your remaining backup codes below:', - 'mfa_verify_backup_code_enter_here' => 'Enter backup code here', - 'mfa_verify_totp_desc' => 'Enter the code, generated using your mobile app, below:', - 'mfa_setup_login_notification' => 'Multi-factor method configured, Please now login again using the configured method.', + 'mfa_setup' => 'Määritä monivaiheinen tunnistautuminen', + 'mfa_setup_desc' => 'Määritä monivaiheinen tunnistautuminen käyttäjätilisi turvallisuuden parantamiseksi.', + 'mfa_setup_configured' => 'Määritetty', + 'mfa_setup_reconfigure' => 'Uudelleenmäärittele', + 'mfa_setup_remove_confirmation' => 'Oletko varma, että haluat poistaa tämän monivaiheisen tunnistautumisen menetelmän?', + 'mfa_setup_action' => 'Asetukset', + 'mfa_backup_codes_usage_limit_warning' => 'Sinulla on alle 5 varmistuskoodia jäljellä. Luo ja tallenna uusi sarja ennen kuin koodit loppuvat, jotta käyttäjätilisi ei lukitu.', + 'mfa_option_totp_title' => 'Mobiilisovellus', + 'mfa_option_totp_desc' => 'Jos haluat käyttää monivaiheista tunnistautumista, tarvitset mobiilisovelluksen, joka tukee TOTP:tä, kuten Google Authenticator, Authy tai Microsoft Authenticator.', + 'mfa_option_backup_codes_title' => 'Varmistuskoodit', + 'mfa_option_backup_codes_desc' => 'Tallenna turvallisesti joukko kertakäyttöisiä varmistuskoodeja, jotka voit syöttää henkilöllisyytesi varmentamiseksi.', + 'mfa_gen_confirm_and_enable' => 'Vahvista ja ota käyttöön', + 'mfa_gen_backup_codes_title' => 'Varmistuskoodien asetukset', + 'mfa_gen_backup_codes_desc' => 'Säilytä alla oleva luettelo koodeista turvallisessa paikassa. Kun käytät järjestelmää, voit käyttää yhtä koodeista toisena tunnistautumistapana.', + 'mfa_gen_backup_codes_download' => 'Lataa koodit', + 'mfa_gen_backup_codes_usage_warning' => 'Jokainen koodi voidaan käyttää vain kerran', + 'mfa_gen_totp_title' => 'Mobiilisovelluksen asetukset', + 'mfa_gen_totp_desc' => 'Jos haluat käyttää monivaiheista tunnistautumista, tarvitset mobiilisovelluksen, joka tukee TOTP: tä, kuten Google Authenticator, Authy tai Microsoft Authenticator.', + 'mfa_gen_totp_scan' => 'Skannaa alla oleva QR-koodi haluamallasi todennussovelluksella päästäksesi alkuun.', + 'mfa_gen_totp_verify_setup' => 'Vahvista asetukset', + 'mfa_gen_totp_verify_setup_desc' => 'Vahvista, että kaikki toimii syöttämällä tunnistautumissovelluksessa luotu koodi alla olevaan kenttään:', + 'mfa_gen_totp_provide_code_here' => 'Anna sovelluksen luoma koodi', + 'mfa_verify_access' => 'Vahvista pääsy', + 'mfa_verify_access_desc' => 'Käyttäjätilisi vaatii kirjautumiseen monivaiheisen tunnistautumisen. Vahvista kirjautuminen jollakin määrittelemälläsi menetelmällä jatkaaksesi.', + 'mfa_verify_no_methods' => 'Ei määriteltyjä Menetelmiä', + 'mfa_verify_no_methods_desc' => 'Käyttäjätilillesi ei löytynyt monivaiheisen tunnistautumisen menetelmiä. Kirjautumiseen vaaditaan vähintään yksi menetelmä.', + 'mfa_verify_use_totp' => 'Vahvista käyttämällä mobiilisovellusta', + 'mfa_verify_use_backup_codes' => 'Vahvista käyttämällä varmistuskoodia', + 'mfa_verify_backup_code' => 'Varmistuskoodi', + 'mfa_verify_backup_code_desc' => 'Syötä yksi jäljellä olevista varmistukoodeistasi:', + 'mfa_verify_backup_code_enter_here' => 'Syötä varmistuskoodi', + 'mfa_verify_totp_desc' => 'Anna mobiilisovelluksella luotu koodi alle:', + 'mfa_setup_login_notification' => 'Monivaiheisen tunnistautumisen menetelmä määritetty. Kirjaudu nyt uudelleen käyttämällä määritettyä menetelmää.', ]; diff --git a/lang/fi/common.php b/lang/fi/common.php index 27037babe..76c5cc41f 100644 --- a/lang/fi/common.php +++ b/lang/fi/common.php @@ -5,106 +5,106 @@ return [ // Buttons - 'cancel' => 'Cancel', - 'close' => 'Close', - 'confirm' => 'Confirm', - 'back' => 'Back', - 'save' => 'Save', - 'continue' => 'Continue', - 'select' => 'Select', - 'toggle_all' => 'Toggle All', - 'more' => 'More', + 'cancel' => 'Peruuta', + 'close' => 'Sulje', + 'confirm' => 'Vahvista', + 'back' => 'Takaisin', + 'save' => 'Tallenna', + 'continue' => 'Jatka', + 'select' => 'Valitse', + 'toggle_all' => 'Vaihda kaikki', + 'more' => 'Lisää', // Form Labels - 'name' => 'Name', - 'description' => 'Description', - 'role' => 'Role', - 'cover_image' => 'Cover image', - 'cover_image_description' => 'This image should be approx 440x250px.', + 'name' => 'Nimi', + 'description' => 'Kuvaus', + 'role' => 'Rooli', + 'cover_image' => 'Kansikuva', + 'cover_image_description' => 'Kuvan tulee olla noin 440x250px.', // Actions - 'actions' => 'Actions', - 'view' => 'View', - 'view_all' => 'View All', - 'new' => 'New', - 'create' => 'Create', - 'update' => 'Update', - 'edit' => 'Edit', - 'sort' => 'Sort', - 'move' => 'Move', - 'copy' => 'Copy', - 'reply' => 'Reply', - 'delete' => 'Delete', - 'delete_confirm' => 'Confirm Deletion', - 'search' => 'Search', - 'search_clear' => 'Clear Search', - 'reset' => 'Reset', - 'remove' => 'Remove', - 'add' => 'Add', - 'configure' => 'Configure', - 'manage' => 'Manage', - 'fullscreen' => 'Fullscreen', - 'favourite' => 'Favourite', - 'unfavourite' => 'Unfavourite', - 'next' => 'Next', - 'previous' => 'Previous', - 'filter_active' => 'Active Filter:', - 'filter_clear' => 'Clear Filter', - 'download' => 'Download', - 'open_in_tab' => 'Open in Tab', - 'open' => 'Open', + 'actions' => 'Toiminnot', + 'view' => 'Näytä', + 'view_all' => 'Näytä kaikki', + 'new' => 'Uusi', + 'create' => 'Luo', + 'update' => 'Päivitä', + 'edit' => 'Muokkaa', + 'sort' => 'Järjestä', + 'move' => 'Siirrä', + 'copy' => 'Kopioi', + 'reply' => 'Vastaa', + 'delete' => 'Poista', + 'delete_confirm' => 'Vahvista poistaminen', + 'search' => 'Hae', + 'search_clear' => 'Tyhjennä haku', + 'reset' => 'Palauta', + 'remove' => 'Poista', + 'add' => 'Lisää', + 'configure' => 'Määritä', + 'manage' => 'Hallinnoi', + 'fullscreen' => 'Koko näyttö', + 'favourite' => 'Suosikki', + 'unfavourite' => 'Poista suosikki', + 'next' => 'Seuraava', + 'previous' => 'Edellinen', + 'filter_active' => 'Aktiivinen suodatin:', + 'filter_clear' => 'Tyhjennä suodatin', + 'download' => 'Lataa', + 'open_in_tab' => 'Avaa välilehdessä', + 'open' => 'Avaa', // Sort Options - 'sort_options' => 'Sort Options', - 'sort_direction_toggle' => 'Sort Direction Toggle', - 'sort_ascending' => 'Sort Ascending', - 'sort_descending' => 'Sort Descending', - 'sort_name' => 'Name', - 'sort_default' => 'Default', - 'sort_created_at' => 'Created Date', - 'sort_updated_at' => 'Updated Date', + 'sort_options' => 'Järjestyksen asetukset', + 'sort_direction_toggle' => 'Järjestyssuunnan vaihto', + 'sort_ascending' => 'Järjestä nousevasti', + 'sort_descending' => 'Järjestä laskevasti', + 'sort_name' => 'Nimi', + 'sort_default' => 'Oletus', + 'sort_created_at' => 'Luontipäiväys', + 'sort_updated_at' => 'Päivityksen päiväys', // Misc - 'deleted_user' => 'Deleted User', - 'no_activity' => 'No activity to show', - 'no_items' => 'No items available', - 'back_to_top' => 'Back to top', - 'skip_to_main_content' => 'Skip to main content', - 'toggle_details' => 'Toggle Details', - 'toggle_thumbnails' => 'Toggle Thumbnails', - 'details' => 'Details', - 'grid_view' => 'Grid View', - 'list_view' => 'List View', - 'default' => 'Default', - 'breadcrumb' => 'Breadcrumb', - 'status' => 'Status', - 'status_active' => 'Active', - 'status_inactive' => 'Inactive', - 'never' => 'Never', - 'none' => 'None', + 'deleted_user' => 'Poistettu käyttäjä', + 'no_activity' => 'Ei näytettävää toimintaa', + 'no_items' => 'Ei kohteita saatavilla', + 'back_to_top' => 'Palaa alkuun', + 'skip_to_main_content' => 'Siirry pääsisältöön', + 'toggle_details' => 'Näytä tiedot', + 'toggle_thumbnails' => 'Näytä pienoiskuvat', + 'details' => 'Tiedot', + 'grid_view' => 'Ruudukkonäkymä', + 'list_view' => 'Luettelonäkymä', + 'default' => 'Oletus', + 'breadcrumb' => 'Navigointipolku', + 'status' => 'Tila', + 'status_active' => 'Aktiivinen', + 'status_inactive' => 'Ei aktiivinen', + 'never' => 'Ei koskaan', + 'none' => 'Ei mitään', // Header - 'homepage' => 'Homepage', - 'header_menu_expand' => 'Expand Header Menu', - 'profile_menu' => 'Profile Menu', - 'view_profile' => 'View Profile', - 'edit_profile' => 'Edit Profile', - 'dark_mode' => 'Dark Mode', - 'light_mode' => 'Light Mode', - 'global_search' => 'Global Search', + 'homepage' => 'Kotisivu', + 'header_menu_expand' => 'Laajenna päävalikko', + 'profile_menu' => 'Profiilivalikko', + 'view_profile' => 'Näytä profiili', + 'edit_profile' => 'Muokkaa profiilia', + 'dark_mode' => 'Tumma tila', + 'light_mode' => 'Vaalea tila', + 'global_search' => 'Yleishaku', // Layout tabs 'tab_info' => 'Info', - 'tab_info_label' => 'Tab: Show Secondary Information', - 'tab_content' => 'Content', - 'tab_content_label' => 'Tab: Show Primary Content', + 'tab_info_label' => 'Välilehti: Näytä toissijaiset tiedot', + 'tab_content' => 'Sisältö', + 'tab_content_label' => 'Välilehti: Näytä ensisijainen sisältö', // Email Content - 'email_action_help' => 'If you’re having trouble clicking the ":actionText" button, copy and paste the URL below into your web browser:', - 'email_rights' => 'All rights reserved', + 'email_action_help' => 'Jos sinulla on ongelmia ":actionText"-painikkeen klikkaamisessa, kopioi ja liitä alla oleva URL-osoite selaimeesi:', + 'email_rights' => 'Kaikki oikeudet pidätetään', // Footer Link Options // Not directly used but available for convenience to users. - 'privacy_policy' => 'Privacy Policy', - 'terms_of_service' => 'Terms of Service', + 'privacy_policy' => 'Tietosuojaseloste', + 'terms_of_service' => 'Palvelun käyttöehdot', ]; diff --git a/lang/fi/components.php b/lang/fi/components.php index c33b1d0b7..570318158 100644 --- a/lang/fi/components.php +++ b/lang/fi/components.php @@ -5,42 +5,42 @@ return [ // Image Manager - 'image_select' => 'Image Select', - 'image_list' => 'Image List', - 'image_details' => 'Image Details', - 'image_upload' => 'Upload Image', - 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.', - 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.', - 'image_all' => 'All', - 'image_all_title' => 'View all images', - 'image_book_title' => 'View images uploaded to this book', - 'image_page_title' => 'View images uploaded to this page', - 'image_search_hint' => 'Search by image name', - 'image_uploaded' => 'Uploaded :uploadedDate', - 'image_uploaded_by' => 'Uploaded by :userName', - 'image_uploaded_to' => 'Uploaded to :pageLink', - 'image_updated' => 'Updated :updateDate', - 'image_load_more' => 'Load More', - 'image_image_name' => 'Image Name', - 'image_delete_used' => 'This image is used in the pages below.', - 'image_delete_confirm_text' => 'Are you sure you want to delete this image?', - 'image_select_image' => 'Select Image', - 'image_dropzone' => 'Drop images or click here to upload', - 'image_dropzone_drop' => 'Drop images here to upload', - 'images_deleted' => 'Images Deleted', - 'image_preview' => 'Image Preview', - 'image_upload_success' => 'Image uploaded successfully', - 'image_update_success' => 'Image details successfully updated', - 'image_delete_success' => 'Image successfully deleted', - 'image_replace' => 'Replace Image', - 'image_replace_success' => 'Image file successfully updated', - 'image_rebuild_thumbs' => 'Regenerate Size Variations', - 'image_rebuild_thumbs_success' => 'Image size variations successfully rebuilt!', + 'image_select' => 'Kuvan valinta', + 'image_list' => 'Kuvalista', + 'image_details' => 'Kuvan tiedot', + 'image_upload' => 'Lataa kuva', + 'image_intro' => 'Täällä voit valita ja hallita kuvia, jotka on aiemmin ladattu järjestelmään.', + 'image_intro_upload' => 'Lataa uusi kuva vetämällä kuvatiedosto tähän ikkunaan tai käyttämällä yllä olevaa "Lataa kuva" -painiketta.', + 'image_all' => 'Kaikki', + 'image_all_title' => 'Näytä kaikki kuvat', + 'image_book_title' => 'Näytä tähän kirjaan ladatut kuvat', + 'image_page_title' => 'Näytä tähän sivuun ladatut kuvat', + 'image_search_hint' => 'Hae kuvan nimellä', + 'image_uploaded' => 'Ladattu :uploadedDate', + 'image_uploaded_by' => 'Lataaja :userName', + 'image_uploaded_to' => 'Ladattu sivulle :pageLink', + 'image_updated' => 'Päivitetty :updateDate', + 'image_load_more' => 'Lataa lisää', + 'image_image_name' => 'Kuvan nimi', + 'image_delete_used' => 'Tätä kuvaa käytetään alla mainituilla sivuilla.', + 'image_delete_confirm_text' => 'Haluatko varmasti poistaa tämän kuvan?', + 'image_select_image' => 'Valitse kuva', + 'image_dropzone' => 'Pudota kuvat tai lataa ne klikkaamalla tästä', + 'image_dropzone_drop' => 'Pudota kuvat tähän ladattavaksi', + 'images_deleted' => 'Kuvat poistettu', + 'image_preview' => 'Kuvan esikatselu', + 'image_upload_success' => 'Kuva ladattiin onnistuneesti', + 'image_update_success' => 'Kuvan tiedot päivitettiin onnistuneesti', + 'image_delete_success' => 'Kuva poistettiin onnistuneesti', + 'image_replace' => 'Vaihda kuva', + 'image_replace_success' => 'Kuvatiedosto päivitettiin onnistuneesti', + 'image_rebuild_thumbs' => 'Luo kokovaihtoehdot uudelleen', + 'image_rebuild_thumbs_success' => 'Kuvan kokovaihtoehdot luotiin onnistuneesti uudelleen!', // Code Editor - 'code_editor' => 'Edit Code', - 'code_language' => 'Code Language', - 'code_content' => 'Code Content', - 'code_session_history' => 'Session History', - 'code_save' => 'Save Code', + 'code_editor' => 'Muokkaa koodia', + 'code_language' => 'Koodin kieli', + 'code_content' => 'Koodin sisältö', + 'code_session_history' => 'Istuntohistoria', + 'code_save' => 'Tallenna koodi', ]; diff --git a/lang/fi/editor.php b/lang/fi/editor.php index 670c1c5e1..7954aa603 100644 --- a/lang/fi/editor.php +++ b/lang/fi/editor.php @@ -7,168 +7,168 @@ */ return [ // General editor terms - 'general' => 'General', - 'advanced' => 'Advanced', - 'none' => 'None', - 'cancel' => 'Cancel', - 'save' => 'Save', - 'close' => 'Close', - 'undo' => 'Undo', - 'redo' => 'Redo', - 'left' => 'Left', - 'center' => 'Center', - 'right' => 'Right', - 'top' => 'Top', - 'middle' => 'Middle', - 'bottom' => 'Bottom', - 'width' => 'Width', - 'height' => 'Height', - 'More' => 'More', - 'select' => 'Select...', + 'general' => 'Yleinen', + 'advanced' => 'Lisäasetukset', + 'none' => 'Ei mitään', + 'cancel' => 'Peruuta', + 'save' => 'Tallenna', + 'close' => 'Sulje', + 'undo' => 'Kumoa', + 'redo' => 'Tee uudelleen', + 'left' => 'Vasen', + 'center' => 'Keskellä', + 'right' => 'Oikea', + 'top' => 'Ylhäällä', + 'middle' => 'Keskellä', + 'bottom' => 'Alhaalla', + 'width' => 'Leveys', + 'height' => 'Korkeus', + 'More' => 'Enemmän', + 'select' => 'Valitse...', // Toolbar - 'formats' => 'Formats', - 'header_large' => 'Large Header', - 'header_medium' => 'Medium Header', - 'header_small' => 'Small Header', - 'header_tiny' => 'Tiny Header', - 'paragraph' => 'Paragraph', - 'blockquote' => 'Blockquote', - 'inline_code' => 'Inline code', - 'callouts' => 'Callouts', - 'callout_information' => 'Information', - 'callout_success' => 'Success', - 'callout_warning' => 'Warning', - 'callout_danger' => 'Danger', - 'bold' => 'Bold', - 'italic' => 'Italic', - 'underline' => 'Underline', - 'strikethrough' => 'Strikethrough', - 'superscript' => 'Superscript', - 'subscript' => 'Subscript', - 'text_color' => 'Text color', - 'custom_color' => 'Custom color', - 'remove_color' => 'Remove color', - 'background_color' => 'Background color', - 'align_left' => 'Align left', - 'align_center' => 'Align center', - 'align_right' => 'Align right', - 'align_justify' => 'Justify', - 'list_bullet' => 'Bullet list', - 'list_numbered' => 'Numbered list', - 'list_task' => 'Task list', - 'indent_increase' => 'Increase indent', - 'indent_decrease' => 'Decrease indent', - 'table' => 'Table', - 'insert_image' => 'Insert image', - 'insert_image_title' => 'Insert/Edit Image', - 'insert_link' => 'Insert/edit link', - 'insert_link_title' => 'Insert/Edit Link', - 'insert_horizontal_line' => 'Insert horizontal line', - 'insert_code_block' => 'Insert code block', - 'edit_code_block' => 'Edit code block', - 'insert_drawing' => 'Insert/edit drawing', - 'drawing_manager' => 'Drawing manager', - 'insert_media' => 'Insert/edit media', - 'insert_media_title' => 'Insert/Edit Media', - 'clear_formatting' => 'Clear formatting', - 'source_code' => 'Source code', - 'source_code_title' => 'Source Code', - 'fullscreen' => 'Fullscreen', - 'image_options' => 'Image options', + 'formats' => 'Formaatit', + 'header_large' => 'Iso otsikko', + 'header_medium' => 'Keskikokoinen otsikko', + 'header_small' => 'Pieni otsikko', + 'header_tiny' => 'Hyvin pieni otsikko', + 'paragraph' => 'Kappale', + 'blockquote' => 'Sitaatti', + 'inline_code' => 'Koodi', + 'callouts' => 'Huomautukset', + 'callout_information' => 'Tietoja', + 'callout_success' => 'Onnistuminen', + 'callout_warning' => 'Varoitus', + 'callout_danger' => 'Vaara', + 'bold' => 'Lihavointi', + 'italic' => 'Kursivointi', + 'underline' => 'Alleviivaus', + 'strikethrough' => 'Yliviivaus', + 'superscript' => 'Yläindeksi', + 'subscript' => 'Alaindeksi', + 'text_color' => 'Tekstin väri', + 'custom_color' => 'Mukautettu väri', + 'remove_color' => 'Poista väri', + 'background_color' => 'Taustaväri', + 'align_left' => 'Tasaa vasemmalle', + 'align_center' => 'Tasaa keskelle', + 'align_right' => 'Tasaa oikealle', + 'align_justify' => 'Tasaa molemmat reunat', + 'list_bullet' => 'Lajittelematon lista', + 'list_numbered' => 'Numeroitu lista', + 'list_task' => 'Tehtävälista', + 'indent_increase' => 'Lisää sisennystä', + 'indent_decrease' => 'Vähennä sisennystä', + 'table' => 'Taulukko', + 'insert_image' => 'Lisää kuva', + 'insert_image_title' => 'Lisää/muokkaa kuvaa', + 'insert_link' => 'Lisää/muokkaa linkkiä', + 'insert_link_title' => 'Lisää/muokkaa linkkiä', + 'insert_horizontal_line' => 'Lisää vaakaviiva', + 'insert_code_block' => 'Lisää koodilohko', + 'edit_code_block' => 'Muokkaa koodilohkoa', + 'insert_drawing' => 'Lisää/muokkaa piirrosta', + 'drawing_manager' => 'Piirroksen hallinta', + 'insert_media' => 'Lisää/muokkaa mediaa', + 'insert_media_title' => 'Lisää/muokkaa mediaa', + 'clear_formatting' => 'Poista muotoilu', + 'source_code' => 'Lähdekoodi', + 'source_code_title' => 'Lähdekoodi', + 'fullscreen' => 'Koko näyttö', + 'image_options' => 'Kuvan asetukset', // Tables - 'table_properties' => 'Table properties', - 'table_properties_title' => 'Table Properties', - 'delete_table' => 'Delete table', - 'insert_row_before' => 'Insert row before', - 'insert_row_after' => 'Insert row after', - 'delete_row' => 'Delete row', - 'insert_column_before' => 'Insert column before', - 'insert_column_after' => 'Insert column after', - 'delete_column' => 'Delete column', - 'table_cell' => 'Cell', - 'table_row' => 'Row', - 'table_column' => 'Column', - 'cell_properties' => 'Cell properties', - 'cell_properties_title' => 'Cell Properties', - 'cell_type' => 'Cell type', - 'cell_type_cell' => 'Cell', - 'cell_scope' => 'Scope', - 'cell_type_header' => 'Header cell', - 'merge_cells' => 'Merge cells', - 'split_cell' => 'Split cell', - 'table_row_group' => 'Row Group', - 'table_column_group' => 'Column Group', - 'horizontal_align' => 'Horizontal align', - 'vertical_align' => 'Vertical align', - 'border_width' => 'Border width', - 'border_style' => 'Border style', - 'border_color' => 'Border color', - 'row_properties' => 'Row properties', - 'row_properties_title' => 'Row Properties', - 'cut_row' => 'Cut row', - 'copy_row' => 'Copy row', - 'paste_row_before' => 'Paste row before', - 'paste_row_after' => 'Paste row after', - 'row_type' => 'Row type', - 'row_type_header' => 'Header', - 'row_type_body' => 'Body', - 'row_type_footer' => 'Footer', - 'alignment' => 'Alignment', - 'cut_column' => 'Cut column', - 'copy_column' => 'Copy column', - 'paste_column_before' => 'Paste column before', - 'paste_column_after' => 'Paste column after', - 'cell_padding' => 'Cell padding', - 'cell_spacing' => 'Cell spacing', - 'caption' => 'Caption', - 'show_caption' => 'Show caption', - 'constrain' => 'Constrain proportions', - 'cell_border_solid' => 'Solid', - 'cell_border_dotted' => 'Dotted', - 'cell_border_dashed' => 'Dashed', - 'cell_border_double' => 'Double', - 'cell_border_groove' => 'Groove', - 'cell_border_ridge' => 'Ridge', - 'cell_border_inset' => 'Inset', - 'cell_border_outset' => 'Outset', - 'cell_border_none' => 'None', - 'cell_border_hidden' => 'Hidden', + 'table_properties' => 'Taulukon ominaisuudet', + 'table_properties_title' => 'Taulukon ominaisuudet', + 'delete_table' => 'Poista taulukko', + 'insert_row_before' => 'Lisää rivi ennen', + 'insert_row_after' => 'Lisää rivi jälkeen', + 'delete_row' => 'Poista rivi', + 'insert_column_before' => 'Liitä sarake ennen', + 'insert_column_after' => 'Lisää sarake jälkeen', + 'delete_column' => 'Poista sarake', + 'table_cell' => 'Solu', + 'table_row' => 'Rivi', + 'table_column' => 'Sarake', + 'cell_properties' => 'Solun ominaisuudet', + 'cell_properties_title' => 'Solun ominaisuudet', + 'cell_type' => 'Solun tyyppi', + 'cell_type_cell' => 'Solu', + 'cell_scope' => 'Laajuus', + 'cell_type_header' => 'Otsikkosolu', + 'merge_cells' => 'Yhdistä solut', + 'split_cell' => 'Jaa solu', + 'table_row_group' => 'Riviryhmä', + 'table_column_group' => 'Sarakeryhmä', + 'horizontal_align' => 'Vaaka-asettelu', + 'vertical_align' => 'Pystyasettelu', + 'border_width' => 'Reunuksen leveys', + 'border_style' => 'Reunuksen tyyli', + 'border_color' => 'Reunuksen väri', + 'row_properties' => 'Rivin ominaisuudet', + 'row_properties_title' => 'Rivin ominaisuudet', + 'cut_row' => 'Leikkaa rivi', + 'copy_row' => 'Kopioi rivi', + 'paste_row_before' => 'Liitä rivi ennen', + 'paste_row_after' => 'Liitä rivi jälkeen', + 'row_type' => 'Rivin tyyppi', + 'row_type_header' => 'Ylätunniste', + 'row_type_body' => 'Sisältö', + 'row_type_footer' => 'Alatunniste', + 'alignment' => 'Tasaus', + 'cut_column' => 'Leikkaa sarake', + 'copy_column' => 'Kopioi sarake', + 'paste_column_before' => 'Liitä sarake ennen', + 'paste_column_after' => 'Liitä sarake jälkeen', + 'cell_padding' => 'Solun reunus', + 'cell_spacing' => 'Solun välistys', + 'caption' => 'Otsikko', + 'show_caption' => 'Näytä otsikko', + 'constrain' => 'Rajaa mittasuhteet', + 'cell_border_solid' => 'Kiinteä', + 'cell_border_dotted' => 'Pisteviiva', + 'cell_border_dashed' => 'Katkoviiva', + 'cell_border_double' => 'Kaksinkertainen viiva', + 'cell_border_groove' => 'Ura', + 'cell_border_ridge' => 'Harjanne', + 'cell_border_inset' => 'Sisenevä', + 'cell_border_outset' => 'Ulkoneva', + 'cell_border_none' => 'Ei mitään', + 'cell_border_hidden' => 'Piilotettu', // Images, links, details/summary & embed - 'source' => 'Source', - 'alt_desc' => 'Alternative description', - 'embed' => 'Embed', - 'paste_embed' => 'Paste your embed code below:', - 'url' => 'URL', - 'text_to_display' => 'Text to display', - 'title' => 'Title', - 'open_link' => 'Open link', - 'open_link_in' => 'Open link in...', - 'open_link_current' => 'Current window', - 'open_link_new' => 'New window', - 'remove_link' => 'Remove link', - 'insert_collapsible' => 'Insert collapsible block', - 'collapsible_unwrap' => 'Unwrap', - 'edit_label' => 'Edit label', - 'toggle_open_closed' => 'Toggle open/closed', - 'collapsible_edit' => 'Edit collapsible block', - 'toggle_label' => 'Toggle label', + 'source' => 'Lähde', + 'alt_desc' => 'Vaihtoehtoinen kuvaus', + 'embed' => 'Upota', + 'paste_embed' => 'Liitä upotuskoodisi alle:', + 'url' => 'URL-osoite', + 'text_to_display' => 'Näytettävä teksti', + 'title' => 'Otsikko', + 'open_link' => 'Avaa linkki', + 'open_link_in' => 'Avaa linkki...', + 'open_link_current' => 'Nykyinen ikkuna', + 'open_link_new' => 'Uusi ikkuna', + 'remove_link' => 'Poista linkki', + 'insert_collapsible' => 'Lisää kokoontaitettava lohko', + 'collapsible_unwrap' => 'Poista ympäröivä lohko', + 'edit_label' => 'Muokkaa nimikettä', + 'toggle_open_closed' => 'Auki/kiinni', + 'collapsible_edit' => 'Muokkaa kokoontaitettavaa lohkoa', + 'toggle_label' => 'Näytä nimike', // About view - 'about' => 'About the editor', - 'about_title' => 'About the WYSIWYG Editor', - 'editor_license' => 'Editor License & Copyright', - 'editor_tiny_license' => 'This editor is built using :tinyLink which is provided under the MIT license.', - 'editor_tiny_license_link' => 'The copyright and license details of TinyMCE can be found here.', - 'save_continue' => 'Save Page & Continue', - 'callouts_cycle' => '(Keep pressing to toggle through types)', - 'link_selector' => 'Link to content', - 'shortcuts' => 'Shortcuts', - 'shortcut' => 'Shortcut', - 'shortcuts_intro' => 'The following shortcuts are available in the editor:', + 'about' => 'Tietoja editorista', + 'about_title' => 'Tietoja WYSIWYG-editorista', + 'editor_license' => 'Editorin lisenssi ja tekijänoikeus', + 'editor_tiny_license' => 'Tämä editori on rakennettu käyttäen sovellusta :tinyLink, joka on MIT-lisenssin alainen.', + 'editor_tiny_license_link' => 'TinyMCE-editorin tekijänoikeus- ja lisenssitiedot löytyvät täältä.', + 'save_continue' => 'Tallenna sivu ja jatka', + 'callouts_cycle' => '(Pidä painettuna valitaksesi tyyppien välillä)', + 'link_selector' => 'Linkki sisältöön', + 'shortcuts' => 'Pikanäppäimet', + 'shortcut' => 'Pikanäppäin', + 'shortcuts_intro' => 'Editorissa on saatavilla seuraavat pikanäppäimet:', 'windows_linux' => '(Windows/Linux)', 'mac' => '(Mac)', - 'description' => 'Description', + 'description' => 'Kuvaus', ]; diff --git a/lang/fi/entities.php b/lang/fi/entities.php index cfb5aae1a..dc43388a3 100644 --- a/lang/fi/entities.php +++ b/lang/fi/entities.php @@ -6,428 +6,432 @@ return [ // Shared - 'recently_created' => 'Recently Created', - 'recently_created_pages' => 'Recently Created Pages', - 'recently_updated_pages' => 'Recently Updated Pages', - 'recently_created_chapters' => 'Recently Created Chapters', - 'recently_created_books' => 'Recently Created Books', - 'recently_created_shelves' => 'Recently Created Shelves', - 'recently_update' => 'Recently Updated', - 'recently_viewed' => 'Recently Viewed', - 'recent_activity' => 'Recent Activity', - 'create_now' => 'Create one now', - 'revisions' => 'Revisions', - 'meta_revision' => 'Revision #:revisionCount', - 'meta_created' => 'Created :timeLength', - 'meta_created_name' => 'Created :timeLength by :user', - 'meta_updated' => 'Updated :timeLength', - 'meta_updated_name' => 'Updated :timeLength by :user', - 'meta_owned_name' => 'Owned by :user', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', - 'entity_select' => 'Entity Select', - 'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item', - 'images' => 'Images', - 'my_recent_drafts' => 'My Recent Drafts', - 'my_recently_viewed' => 'My Recently Viewed', - 'my_most_viewed_favourites' => 'My Most Viewed Favourites', - 'my_favourites' => 'My Favourites', - 'no_pages_viewed' => 'You have not viewed any pages', - 'no_pages_recently_created' => 'No pages have been recently created', - 'no_pages_recently_updated' => 'No pages have been recently updated', - 'export' => 'Export', - 'export_html' => 'Contained Web File', - 'export_pdf' => 'PDF File', - 'export_text' => 'Plain Text File', - 'export_md' => 'Markdown File', + 'recently_created' => 'Viimeksi luodut', + 'recently_created_pages' => 'Viimeksi luodut sivut', + 'recently_updated_pages' => 'Viimeksi päivitetyt sivut', + 'recently_created_chapters' => 'Viimeksi luodut luvut', + 'recently_created_books' => 'Viimeksi luodut kirjat', + 'recently_created_shelves' => 'Viimeksi luodut hyllyt', + 'recently_update' => 'Viimeksi päivitetyt', + 'recently_viewed' => 'Viimeksi katsotut', + 'recent_activity' => 'Viimeaikainen toiminta', + 'create_now' => 'Luo uusi', + 'revisions' => 'Versiot', + 'meta_revision' => 'Versio #:revisionCount', + 'meta_created' => 'Luotu :timeLength', + 'meta_created_name' => 'Luotu :timeLength käyttäjän :user toimesta', + 'meta_updated' => 'Päivitetty :timeLength', + 'meta_updated_name' => 'Päivitetty :timeLength käyttäjän :user toimesta', + 'meta_owned_name' => 'Omistaja :user', + 'meta_reference_count' => 'Viittaa :count kohteeseen|Viittaa :count kohteeseen', + 'entity_select' => 'Kohteen valinta', + 'entity_select_lack_permission' => 'Sinulla ei ole tarvittavia oikeuksia tämän kohteen valitsemiseen', + 'images' => 'Kuvat', + 'my_recent_drafts' => 'Viimeisimmät luonnokseni', + 'my_recently_viewed' => 'Omat viimeksi katsotut', + 'my_most_viewed_favourites' => 'Omat katsotuimmat suosikit', + 'my_favourites' => 'Omat suosikit', + 'no_pages_viewed' => 'Et ole katsonut yhtään sivua', + 'no_pages_recently_created' => 'Yhtään sivua ei ole luotu äskettäin', + 'no_pages_recently_updated' => 'Yhtään sivua ei ole päivitetty äskettäin', + 'export' => 'Vie', + 'export_html' => 'HTML-tiedosto', + 'export_pdf' => 'PDF-tiedosto', + 'export_text' => 'Tekstitiedosto', + 'export_md' => 'Markdown-tiedosto', // Permissions and restrictions - 'permissions' => 'Permissions', - 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', - 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', - 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', - 'permissions_save' => 'Save Permissions', - 'permissions_owner' => 'Owner', - 'permissions_role_everyone_else' => 'Everyone Else', - 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', - 'permissions_role_override' => 'Override permissions for role', - 'permissions_inherit_defaults' => 'Inherit defaults', + 'permissions' => 'Käyttöoikeudet', + 'permissions_desc' => 'Määritä tässä käyttöoikeudet ohittaaksesi käyttäjäroolien antamat oletusoikeudet.', + 'permissions_book_cascade' => 'Kirjoille määritetyt käyttöoikeudet siirtyvät automaattisesti lukuihin ja -sivuihin, ellei niille ole määritelty omia käyttöoikeuksia.', + 'permissions_chapter_cascade' => 'Luvuille määritetyt käyttöoikeudet siirtyvät automaattisesti sivuille, ellei niille ole määritelty omia käyttöoikeuksia.', + 'permissions_save' => 'Tallenna käyttöoikeudet', + 'permissions_owner' => 'Omistaja', + 'permissions_role_everyone_else' => 'Kaikki muut', + 'permissions_role_everyone_else_desc' => 'Aseta käyttöoikeudet kaikille rooleille, joita ei ole erikseen ohitettu.', + 'permissions_role_override' => 'Ohita roolin käyttöoikeudet', + 'permissions_inherit_defaults' => 'Peritään oletusarvot', // Search - 'search_results' => 'Search Results', - 'search_total_results_found' => ':count result found|:count total results found', - 'search_clear' => 'Clear Search', - 'search_no_pages' => 'No pages matched this search', - 'search_for_term' => 'Search for :term', - 'search_more' => 'More Results', - 'search_advanced' => 'Advanced Search', - 'search_terms' => 'Search Terms', - 'search_content_type' => 'Content Type', - 'search_exact_matches' => 'Exact Matches', - 'search_tags' => 'Tag Searches', - 'search_options' => 'Options', - 'search_viewed_by_me' => 'Viewed by me', - 'search_not_viewed_by_me' => 'Not viewed by me', - 'search_permissions_set' => 'Permissions set', - 'search_created_by_me' => 'Created by me', - 'search_updated_by_me' => 'Updated by me', - 'search_owned_by_me' => 'Owned by me', - 'search_date_options' => 'Date Options', - 'search_updated_before' => 'Updated before', - 'search_updated_after' => 'Updated after', - 'search_created_before' => 'Created before', - 'search_created_after' => 'Created after', - 'search_set_date' => 'Set Date', - 'search_update' => 'Update Search', + 'search_results' => 'Hakutulokset', + 'search_total_results_found' => 'löytyi :count osuma|löytyi :count osumaa', + 'search_clear' => 'Tyhjennä haku', + 'search_no_pages' => 'Haulla ei löytynyt yhtään sivua', + 'search_for_term' => 'Hae sanaa :term', + 'search_more' => 'Lisää tuloksia', + 'search_advanced' => 'Tarkennettu haku', + 'search_terms' => 'Hakusanat', + 'search_content_type' => 'Sisältötyyppi', + 'search_exact_matches' => 'Täsmälliset vastineet', + 'search_tags' => 'Tunnisteen haut', + 'search_options' => 'Valinnat', + 'search_viewed_by_me' => 'Olen katsonut', + 'search_not_viewed_by_me' => 'En ole katsonut', + 'search_permissions_set' => 'Käyttöoikeudet asetettu', + 'search_created_by_me' => 'Minun luomani', + 'search_updated_by_me' => 'Minun päivittämäni', + 'search_owned_by_me' => 'Minun omistamani', + 'search_date_options' => 'Päiväyksen valinnat', + 'search_updated_before' => 'Päivitetty ennen', + 'search_updated_after' => 'Päivitetty jälkeen', + 'search_created_before' => 'Luotu ennen', + 'search_created_after' => 'Luotu jälkeen', + 'search_set_date' => 'Aseta päiväys', + 'search_update' => 'Päivitä haku', // Shelves - 'shelf' => 'Shelf', - 'shelves' => 'Shelves', - 'x_shelves' => ':count Shelf|:count Shelves', - 'shelves_empty' => 'No shelves have been created', - 'shelves_create' => 'Create New Shelf', - 'shelves_popular' => 'Popular Shelves', - 'shelves_new' => 'New Shelves', - 'shelves_new_action' => 'New Shelf', - 'shelves_popular_empty' => 'The most popular shelves will appear here.', - 'shelves_new_empty' => 'The most recently created shelves will appear here.', - 'shelves_save' => 'Save Shelf', - 'shelves_books' => 'Books on this shelf', - 'shelves_add_books' => 'Add books to this shelf', - 'shelves_drag_books' => 'Drag books below to add them to this shelf', - 'shelves_empty_contents' => 'This shelf has no books assigned to it', - 'shelves_edit_and_assign' => 'Edit shelf to assign books', - 'shelves_edit_named' => 'Edit Shelf :name', - 'shelves_edit' => 'Edit Shelf', - 'shelves_delete' => 'Delete Shelf', - 'shelves_delete_named' => 'Delete Shelf :name', - 'shelves_delete_explain' => "This will delete the shelf with the name ':name'. Contained books will not be deleted.", - 'shelves_delete_confirmation' => 'Are you sure you want to delete this shelf?', - 'shelves_permissions' => 'Shelf Permissions', - 'shelves_permissions_updated' => 'Shelf Permissions Updated', - 'shelves_permissions_active' => 'Shelf Permissions Active', - 'shelves_permissions_cascade_warning' => 'Permissions on shelves do not automatically cascade to contained books. This is because a book can exist on multiple shelves. Permissions can however be copied down to child books using the option found below.', - 'shelves_permissions_create' => 'Shelf create permissions are only used for copying permissions to child books using the action below. They do not control the ability to create books.', - 'shelves_copy_permissions_to_books' => 'Copy Permissions to Books', - 'shelves_copy_permissions' => 'Copy Permissions', - 'shelves_copy_permissions_explain' => 'This will apply the current permission settings of this shelf to all books contained within. Before activating, ensure any changes to the permissions of this shelf have been saved.', - 'shelves_copy_permission_success' => 'Shelf permissions copied to :count books', + 'shelf' => 'Hylly', + 'shelves' => 'Hyllyt', + 'x_shelves' => ':count hylly|:count hyllyä', + 'shelves_empty' => 'Hyllyjä ei ole luotu', + 'shelves_create' => 'Luo uusi hylly', + 'shelves_popular' => 'Suositut hyllyt', + 'shelves_new' => 'Uudet hyllyt', + 'shelves_new_action' => 'Uusi hylly', + 'shelves_popular_empty' => 'Suosituimmat hyllyt näkyvät tässä.', + 'shelves_new_empty' => 'Viimeksi luodut hyllyt näkyvät tässä.', + 'shelves_save' => 'Tallenna hylly', + 'shelves_books' => 'Tässä hyllyssä olevat kirjat', + 'shelves_add_books' => 'Lisää kirjoja tähän hyllyyn', + 'shelves_drag_books' => 'Vedä alla olevia kirjoja lisätäksesi ne tähän hyllyyn', + 'shelves_empty_contents' => 'Tälle hyllylle ei ole lisätty kirjoja', + 'shelves_edit_and_assign' => 'Muokkaa hyllyä lisätäksesi kirjoja', + 'shelves_edit_named' => 'Muokkaa hyllyä :name', + 'shelves_edit' => 'Muokkaa hyllyä', + 'shelves_delete' => 'Poista hylly', + 'shelves_delete_named' => 'Poista hylly :name', + 'shelves_delete_explain' => "Tämä poistaa hyllyn, jonka nimi on ':nimi'. Sisältyviä kirjoja ei poisteta.", + 'shelves_delete_confirmation' => 'Haluatko varmasti poistaa tämän hyllyn?', + 'shelves_permissions' => 'Hyllyn käyttöoikeudet', + 'shelves_permissions_updated' => 'Hyllyn käyttöoikeudet päivitetty', + 'shelves_permissions_active' => 'Hyllyn käyttöoikeudet käytössä', + 'shelves_permissions_cascade_warning' => 'Hyllyjen käyttöoikeudet eivät siirry automaattisesti kirjoihin. Tämä johtuu siitä, että kirja voi olla useammassa hyllyssä. Käyttöoikeudet voidaan kuitenkin kopioida kaikkiin hyllyn kirjoihin käyttämällä alla olevaa valintaa.', + 'shelves_permissions_create' => 'Hyllyjen luontioikeuksia käytetään vain kopioidessa oikeuksia hyllyn kirjoihin alla olevan toiminnon avulla. Ne eivät vaikuta mahdollisuuteen luoda kirjoja.', + 'shelves_copy_permissions_to_books' => 'Kopioi käyttöoikeudet kirjoihin', + 'shelves_copy_permissions' => 'Kopioi käyttöoikeudet', + 'shelves_copy_permissions_explain' => 'Tämä valinta siirtää hyllyn nykyiset käyttöoikeusasetukset kaikkiin hyllyssä oleviin kirjoihin. Varmista ennen aktivointia, että kaikki tämän hyllyn käyttöoikeuksiin tehdyt muutokset on tallennettu.', + 'shelves_copy_permission_success' => 'Hyllyn käyttöoikeudet kopioitu :count kirjaan', // Books - 'book' => 'Book', - 'books' => 'Books', - 'x_books' => ':count Book|:count Books', - 'books_empty' => 'No books have been created', - 'books_popular' => 'Popular Books', - 'books_recent' => 'Recent Books', - 'books_new' => 'New Books', - 'books_new_action' => 'New Book', - 'books_popular_empty' => 'The most popular books will appear here.', - 'books_new_empty' => 'The most recently created books will appear here.', - 'books_create' => 'Create New Book', - 'books_delete' => 'Delete Book', - 'books_delete_named' => 'Delete Book :bookName', - 'books_delete_explain' => 'This will delete the book with the name \':bookName\'. All pages and chapters will be removed.', - 'books_delete_confirmation' => 'Are you sure you want to delete this book?', - 'books_edit' => 'Edit Book', - 'books_edit_named' => 'Edit Book :bookName', - 'books_form_book_name' => 'Book Name', - 'books_save' => 'Save Book', - 'books_permissions' => 'Book Permissions', - 'books_permissions_updated' => 'Book Permissions Updated', - 'books_empty_contents' => 'No pages or chapters have been created for this book.', - 'books_empty_create_page' => 'Create a new page', - 'books_empty_sort_current_book' => 'Sort the current book', - 'books_empty_add_chapter' => 'Add a chapter', - 'books_permissions_active' => 'Book Permissions Active', - 'books_search_this' => 'Search this book', - 'books_navigation' => 'Book Navigation', - 'books_sort' => 'Sort Book Contents', - 'books_sort_desc' => 'Move chapters and pages within a book to reorganise its contents. Other books can be added which allows easy moving of chapters and pages between books.', - 'books_sort_named' => 'Sort Book :bookName', - 'books_sort_name' => 'Sort by Name', - 'books_sort_created' => 'Sort by Created Date', - 'books_sort_updated' => 'Sort by Updated Date', - 'books_sort_chapters_first' => 'Chapters First', - 'books_sort_chapters_last' => 'Chapters Last', - 'books_sort_show_other' => 'Show Other Books', - 'books_sort_save' => 'Save New Order', - 'books_sort_show_other_desc' => 'Add other books here to include them in the sort operation, and allow easy cross-book reorganisation.', - 'books_sort_move_up' => 'Move Up', - 'books_sort_move_down' => 'Move Down', - 'books_sort_move_prev_book' => 'Move to Previous Book', - 'books_sort_move_next_book' => 'Move to Next Book', - 'books_sort_move_prev_chapter' => 'Move Into Previous Chapter', - 'books_sort_move_next_chapter' => 'Move Into Next Chapter', - 'books_sort_move_book_start' => 'Move to Start of Book', - 'books_sort_move_book_end' => 'Move to End of Book', - 'books_sort_move_before_chapter' => 'Move to Before Chapter', - 'books_sort_move_after_chapter' => 'Move to After Chapter', - 'books_copy' => 'Copy Book', - 'books_copy_success' => 'Book successfully copied', + 'book' => 'Kirja', + 'books' => 'Kirjat', + 'x_books' => ':count kirja|:count kirjaa', + 'books_empty' => 'Kirjoja ei ole luotu', + 'books_popular' => 'Suositut kirjat', + 'books_recent' => 'Viimeisimmät kirjat', + 'books_new' => 'Uudet kirjat', + 'books_new_action' => 'Uusi kirja', + 'books_popular_empty' => 'Suosituimmat kirjat näkyvät tässä.', + 'books_new_empty' => 'Viimeksi luodut kirjat näkyvät tässä.', + 'books_create' => 'Luo uusi kirja', + 'books_delete' => 'Poista kirja', + 'books_delete_named' => 'Poista kirja :bookName', + 'books_delete_explain' => 'Tämä poistaa kirjan, jonka nimi on \':bookName\'. Kaikki sivut ja luvut poistetaan.', + 'books_delete_confirmation' => 'Haluatko varmasti poistaa tämän kirjan?', + 'books_edit' => 'Muokkaa kirjaa', + 'books_edit_named' => 'Muokkaa kirjaa :bookName', + 'books_form_book_name' => 'Kirjan nimi', + 'books_save' => 'Tallenna kirja', + 'books_default_template' => 'Oletusmallipohja', + 'books_default_template_explain' => 'Määritä mallipohja, jota käytetään oletuksena kaikille tämän kirjan uusille sivuille. Muista, että mallipohjaa käytetään vain, jos sivun luojalla on katseluoikeudet valittuun mallipohjaan.', + 'books_default_template_select' => 'Valitse mallipohja', + 'books_permissions' => 'Kirjan käyttöoikeudet', + 'books_permissions_updated' => 'Kirjan käyttöoikeudet päivitetty', + 'books_empty_contents' => 'Tähän kirjaan ei ole luotu sivuja tai lukuja.', + 'books_empty_create_page' => 'Luo uusi sivu', + 'books_empty_sort_current_book' => 'Järjestä nykyistä kirjaa', + 'books_empty_add_chapter' => 'Lisää luku', + 'books_permissions_active' => 'Kirjan käyttöoikeudet käytössä', + 'books_search_this' => 'Hae tästä kirjasta', + 'books_navigation' => 'Kirjan navigaatio', + 'books_sort' => 'Järjestä kirjan sisältö', + 'books_sort_desc' => 'Siirrä lukuja ja sivuja kirjan sisällä järjestelläksesi sen sisältöä uudelleen. Voit lisätä muita kirjoja, jolloin lukujen ja sivujen siirtäminen kirjojen välillä on helppoa.', + 'books_sort_named' => 'Järjestä kirja :bookName', + 'books_sort_name' => 'Järjestä nimen mukaan', + 'books_sort_created' => 'Järjestä luontipäiväyksen mukaan', + 'books_sort_updated' => 'Järjestä päivityksen päiväyksen mukaan', + 'books_sort_chapters_first' => 'Luvut ensin', + 'books_sort_chapters_last' => 'Luvut viimeisenä', + 'books_sort_show_other' => 'Näytä muita kirjoja', + 'books_sort_save' => 'Tallenna uusi järjestys', + 'books_sort_show_other_desc' => 'Voit lisätä tähän muita kirjoja järjestämistä varten ja mahdollistaa sujuvan kirjojen välisen uudelleenjärjestelyn.', + 'books_sort_move_up' => 'Siirrä ylös', + 'books_sort_move_down' => 'Siirrä alas', + 'books_sort_move_prev_book' => 'Siirrä edelliseen kirjaan', + 'books_sort_move_next_book' => 'Siirrä seuraavaan kirjaan', + 'books_sort_move_prev_chapter' => 'Siirrä edelliseen lukuun', + 'books_sort_move_next_chapter' => 'Siirrä seuraavaan lukuun', + 'books_sort_move_book_start' => 'Siirrä kirjan alkuun', + 'books_sort_move_book_end' => 'Siirrä kirjan loppuun', + 'books_sort_move_before_chapter' => 'Siirrä luvun edelle', + 'books_sort_move_after_chapter' => 'Siirrä luvun jälkeen', + 'books_copy' => 'Kopioi kirja', + 'books_copy_success' => 'Kirja kopioitiin onnistuneesti', // Chapters - 'chapter' => 'Chapter', - 'chapters' => 'Chapters', - 'x_chapters' => ':count Chapter|:count Chapters', - 'chapters_popular' => 'Popular Chapters', - 'chapters_new' => 'New Chapter', - 'chapters_create' => 'Create New Chapter', - 'chapters_delete' => 'Delete Chapter', - 'chapters_delete_named' => 'Delete Chapter :chapterName', - 'chapters_delete_explain' => 'This will delete the chapter with the name \':chapterName\'. All pages that exist within this chapter will also be deleted.', - 'chapters_delete_confirm' => 'Are you sure you want to delete this chapter?', - 'chapters_edit' => 'Edit Chapter', - 'chapters_edit_named' => 'Edit Chapter :chapterName', - 'chapters_save' => 'Save Chapter', - 'chapters_move' => 'Move Chapter', - 'chapters_move_named' => 'Move Chapter :chapterName', - 'chapters_copy' => 'Copy Chapter', - 'chapters_copy_success' => 'Chapter successfully copied', - 'chapters_permissions' => 'Chapter Permissions', - 'chapters_empty' => 'No pages are currently in this chapter.', - 'chapters_permissions_active' => 'Chapter Permissions Active', - 'chapters_permissions_success' => 'Chapter Permissions Updated', - 'chapters_search_this' => 'Search this chapter', - 'chapter_sort_book' => 'Sort Book', + 'chapter' => 'Luku', + 'chapters' => 'Luvut', + 'x_chapters' => ':count luku|:count lukua', + 'chapters_popular' => 'Suositut luvut', + 'chapters_new' => 'Uusi luku', + 'chapters_create' => 'Luo uusi luku', + 'chapters_delete' => 'Poista luku', + 'chapters_delete_named' => 'Poista luku :chapterName', + 'chapters_delete_explain' => 'Tämä poistaa luvun nimeltä \':chapterName\'. Myös kaikki luvun sisällä olevat sivut poistetaan.', + 'chapters_delete_confirm' => 'Haluatko varmasti poistaa tämän luvun?', + 'chapters_edit' => 'Muokkaa lukua', + 'chapters_edit_named' => 'Muokkaa lukua :chapterName', + 'chapters_save' => 'Tallenna luku', + 'chapters_move' => 'Siirrä luku', + 'chapters_move_named' => 'Siirrä lukua :chapterName', + 'chapters_copy' => 'Kopioi luku', + 'chapters_copy_success' => 'Luku kopioitiin onnistuneesti', + 'chapters_permissions' => 'Luvun käyttöoikeudet', + 'chapters_empty' => 'Tässä luvussa ei ole tällä hetkellä sivuja.', + 'chapters_permissions_active' => 'Luvun käyttöoikeudet käytössä', + 'chapters_permissions_success' => 'Luvun käyttöoikeudet päivitetty', + 'chapters_search_this' => 'Hae tästä luvusta', + 'chapter_sort_book' => 'Järjestä kirja', // Pages - 'page' => 'Page', - 'pages' => 'Pages', - 'x_pages' => ':count Page|:count Pages', - 'pages_popular' => 'Popular Pages', - 'pages_new' => 'New Page', - 'pages_attachments' => 'Attachments', - 'pages_navigation' => 'Page Navigation', - 'pages_delete' => 'Delete Page', - 'pages_delete_named' => 'Delete Page :pageName', - 'pages_delete_draft_named' => 'Delete Draft Page :pageName', - 'pages_delete_draft' => 'Delete Draft Page', - 'pages_delete_success' => 'Page deleted', - 'pages_delete_draft_success' => 'Draft page deleted', - 'pages_delete_confirm' => 'Are you sure you want to delete this page?', - 'pages_delete_draft_confirm' => 'Are you sure you want to delete this draft page?', - 'pages_editing_named' => 'Editing Page :pageName', - 'pages_edit_draft_options' => 'Draft Options', - 'pages_edit_save_draft' => 'Save Draft', - 'pages_edit_draft' => 'Edit Page Draft', - 'pages_editing_draft' => 'Editing Draft', - 'pages_editing_page' => 'Editing Page', - 'pages_edit_draft_save_at' => 'Draft saved at ', - 'pages_edit_delete_draft' => 'Delete Draft', - 'pages_edit_delete_draft_confirm' => 'Are you sure you want to delete your draft page changes? All of your changes, since the last full save, will be lost and the editor will be updated with the latest page non-draft save state.', - 'pages_edit_discard_draft' => 'Discard Draft', - 'pages_edit_switch_to_markdown' => 'Switch to Markdown Editor', - 'pages_edit_switch_to_markdown_clean' => '(Clean Content)', - 'pages_edit_switch_to_markdown_stable' => '(Stable Content)', - 'pages_edit_switch_to_wysiwyg' => 'Switch to WYSIWYG Editor', - 'pages_edit_set_changelog' => 'Set Changelog', - 'pages_edit_enter_changelog_desc' => 'Enter a brief description of the changes you\'ve made', - 'pages_edit_enter_changelog' => 'Enter Changelog', - 'pages_editor_switch_title' => 'Switch Editor', - 'pages_editor_switch_are_you_sure' => 'Are you sure you want to change the editor for this page?', - 'pages_editor_switch_consider_following' => 'Consider the following when changing editors:', - 'pages_editor_switch_consideration_a' => 'Once saved, the new editor option will be used by any future editors, including those that may not be able to change editor type themselves.', - 'pages_editor_switch_consideration_b' => 'This can potentially lead to a loss of detail and syntax in certain circumstances.', - 'pages_editor_switch_consideration_c' => 'Tag or changelog changes, made since last save, won\'t persist across this change.', - 'pages_save' => 'Save Page', - 'pages_title' => 'Page Title', - 'pages_name' => 'Page Name', - 'pages_md_editor' => 'Editor', - 'pages_md_preview' => 'Preview', - 'pages_md_insert_image' => 'Insert Image', - 'pages_md_insert_link' => 'Insert Entity Link', - 'pages_md_insert_drawing' => 'Insert Drawing', - 'pages_md_show_preview' => 'Show preview', - 'pages_md_sync_scroll' => 'Sync preview scroll', - 'pages_drawing_unsaved' => 'Unsaved Drawing Found', - 'pages_drawing_unsaved_confirm' => 'Unsaved drawing data was found from a previous failed drawing save attempt. Would you like to restore and continue editing this unsaved drawing?', - 'pages_not_in_chapter' => 'Page is not in a chapter', - 'pages_move' => 'Move Page', - 'pages_copy' => 'Copy Page', - 'pages_copy_desination' => 'Copy Destination', - 'pages_copy_success' => 'Page successfully copied', - 'pages_permissions' => 'Page Permissions', - 'pages_permissions_success' => 'Page permissions updated', - 'pages_revision' => 'Revision', - 'pages_revisions' => 'Page Revisions', - 'pages_revisions_desc' => 'Listed below are all the past revisions of this page. You can look back upon, compare, and restore old page versions if permissions allow. The full history of the page may not be fully reflected here since, depending on system configuration, old revisions could be auto-deleted.', - 'pages_revisions_named' => 'Page Revisions for :pageName', - 'pages_revision_named' => 'Page Revision for :pageName', - 'pages_revision_restored_from' => 'Restored from #:id; :summary', - 'pages_revisions_created_by' => 'Created By', - 'pages_revisions_date' => 'Revision Date', + 'page' => 'Sivu', + 'pages' => 'Sivut', + 'x_pages' => ':count sivu|:count sivua', + 'pages_popular' => 'Suositut sivut', + 'pages_new' => 'Uusi sivu', + 'pages_attachments' => 'Liitteet', + 'pages_navigation' => 'Sivun navigaatio', + 'pages_delete' => 'Poista sivu', + 'pages_delete_named' => 'Poista sivu :pageName', + 'pages_delete_draft_named' => 'Poista luonnos :pageName', + 'pages_delete_draft' => 'Poista luonnos', + 'pages_delete_success' => 'Sivu poistettu', + 'pages_delete_draft_success' => 'Luonnos poistettu', + 'pages_delete_warning_template' => 'Tätä sivua käytetään oletusmallipohjana. Näillä kirjoilla ei ole enää oletusmallipohjaa, jos tämä sivu poistetaan.', + 'pages_delete_confirm' => 'Oletko varma, että haluat poistaa tämän sivun?', + 'pages_delete_draft_confirm' => 'Haluatko varmasti poistaa tämän luonnoksen?', + 'pages_editing_named' => 'Muokataan sivua :pageName', + 'pages_edit_draft_options' => 'Luonnoksen asetukset', + 'pages_edit_save_draft' => 'Tallenna luonnos', + 'pages_edit_draft' => 'Muokkaa luonnosta', + 'pages_editing_draft' => 'Muokataan luonnosta', + 'pages_editing_page' => 'Muokataan sivua', + 'pages_edit_draft_save_at' => 'Luonnos tallennettu ', + 'pages_edit_delete_draft' => 'Poista luonnos', + 'pages_edit_delete_draft_confirm' => 'Oletko varma, että haluat poistaa luonnoksen muutokset? Kaikki muutokset viimeisimmästä tallennuksesta lähtien häviävät, ja editori päivitetään viimeisimpään tallennettuun sivun versioon.', + 'pages_edit_discard_draft' => 'Hylkää luonnos', + 'pages_edit_switch_to_markdown' => 'Vaihda Markdown-editoriin', + 'pages_edit_switch_to_markdown_clean' => '(Puhdas sisältö)', + 'pages_edit_switch_to_markdown_stable' => '(Vakaa sisältö)', + 'pages_edit_switch_to_wysiwyg' => 'Vaihda WYSIWYG-editoriin', + 'pages_edit_set_changelog' => 'Aseta muutosloki', + 'pages_edit_enter_changelog_desc' => 'Kirjoita lyhyt kuvaus tekemistäsi muutoksista', + 'pages_edit_enter_changelog' => 'Syötä muutosloki', + 'pages_editor_switch_title' => 'Vaihda editoria', + 'pages_editor_switch_are_you_sure' => 'Haluatko varmasti vaihtaa tämän sivun editorin?', + 'pages_editor_switch_consider_following' => 'Ota huomioon seuraavat asiat, kun vaihdat editoria:', + 'pages_editor_switch_consideration_a' => 'Tallennuksen jälkeen kaikki tulevat muokkaajat käyttävät uutta editorivaihtoehtoa, myös käyttäjät, jotka eivät ehkä pysty itse vaihtamaan editoria.', + 'pages_editor_switch_consideration_b' => 'Tämä voi joissain tapauksissa johtaa yksityiskohtien ja muotoilujen häviämiseen.', + 'pages_editor_switch_consideration_c' => 'Viimeisimmän tallennuksen jälkeen tehdyt tunniste- tai muutoslokimuutokset eivät säily.', + 'pages_save' => 'Tallenna sivu', + 'pages_title' => 'Sivun otsikko', + 'pages_name' => 'Sivun nimi', + 'pages_md_editor' => 'Editori', + 'pages_md_preview' => 'Esikatselu', + 'pages_md_insert_image' => 'Lisää kuva', + 'pages_md_insert_link' => 'Lisää linkki', + 'pages_md_insert_drawing' => 'Lisää piirustus', + 'pages_md_show_preview' => 'Näytä esikatselu', + 'pages_md_sync_scroll' => 'Vieritä esikatselua koodin vierityksen mukaan', + 'pages_drawing_unsaved' => 'Tallentamaton piirustus löytyi', + 'pages_drawing_unsaved_confirm' => 'Järjestelmä löysi tallentamattoman piirustuksen. Haluatko palauttaa piirustuksen ja jatkaa sen muokkaamista?', + 'pages_not_in_chapter' => 'Sivu ei kuulu mihinkään lukuun', + 'pages_move' => 'Siirrä sivu', + 'pages_copy' => 'Kopioi sivu', + 'pages_copy_desination' => 'Kopioinnin kohde', + 'pages_copy_success' => 'Sivu kopioitiin onnistuneesti', + 'pages_permissions' => 'Sivun käyttöoikeudet', + 'pages_permissions_success' => 'Sivun käyttöoikeudet päivitetty', + 'pages_revision' => 'Versio', + 'pages_revisions' => 'Sivun versiot', + 'pages_revisions_desc' => 'Alla on kaikki tämän sivun aiemmat versiot. Voit tarkastella, vertailla ja palauttaa vanhoja versioita, jos käyttöoikeudet sallivat. Sivun koko historia ei välttämättä näy kokonaan, sillä järjestelmän asetuksista riippuen vanhat versiot saatetaan poistaa automaattisesti.', + 'pages_revisions_named' => 'Sivun :pageName versiot', + 'pages_revision_named' => 'Sivun :pageName versio', + 'pages_revision_restored_from' => 'Palautettu versiosta #:id; :summary', + 'pages_revisions_created_by' => 'Luonut', + 'pages_revisions_date' => 'Version päiväys', 'pages_revisions_number' => '#', - 'pages_revisions_sort_number' => 'Revision Number', - 'pages_revisions_numbered' => 'Revision #:id', - 'pages_revisions_numbered_changes' => 'Revision #:id Changes', - 'pages_revisions_editor' => 'Editor Type', - 'pages_revisions_changelog' => 'Changelog', - 'pages_revisions_changes' => 'Changes', - 'pages_revisions_current' => 'Current Version', - 'pages_revisions_preview' => 'Preview', - 'pages_revisions_restore' => 'Restore', - 'pages_revisions_none' => 'This page has no revisions', - 'pages_copy_link' => 'Copy Link', - 'pages_edit_content_link' => 'Jump to section in editor', - 'pages_pointer_enter_mode' => 'Enter section select mode', - 'pages_pointer_label' => 'Page Section Options', - 'pages_pointer_permalink' => 'Page Section Permalink', - 'pages_pointer_include_tag' => 'Page Section Include Tag', - 'pages_pointer_toggle_link' => 'Permalink mode, Press to show include tag', - 'pages_pointer_toggle_include' => 'Include tag mode, Press to show permalink', - 'pages_permissions_active' => 'Page Permissions Active', - 'pages_initial_revision' => 'Initial publish', - 'pages_references_update_revision' => 'System auto-update of internal links', - 'pages_initial_name' => 'New Page', - 'pages_editing_draft_notification' => 'You are currently editing a draft that was last saved :timeDiff.', - 'pages_draft_edited_notification' => 'This page has been updated by since that time. It is recommended that you discard this draft.', - 'pages_draft_page_changed_since_creation' => 'This page has been updated since this draft was created. It is recommended that you discard this draft or take care not to overwrite any page changes.', + 'pages_revisions_sort_number' => 'Versionumero', + 'pages_revisions_numbered' => 'Versio #:id', + 'pages_revisions_numbered_changes' => 'Version #:id muutokset', + 'pages_revisions_editor' => 'Editorin tyyppi', + 'pages_revisions_changelog' => 'Muutoshistoria', + 'pages_revisions_changes' => 'Muutokset', + 'pages_revisions_current' => 'Nykyinen versio', + 'pages_revisions_preview' => 'Esikatselu', + 'pages_revisions_restore' => 'Palauta', + 'pages_revisions_none' => 'Tällä sivulla ei ole versioita', + 'pages_copy_link' => 'Kopioi linkki', + 'pages_edit_content_link' => 'Siirry osioon editorissa', + 'pages_pointer_enter_mode' => 'Siirry osion valintatilaan', + 'pages_pointer_label' => 'Sivun osion valinnat', + 'pages_pointer_permalink' => 'Sivun osion pysyvä linkki', + 'pages_pointer_include_tag' => 'Sivun osion viitetunniste', + 'pages_pointer_toggle_link' => 'Pysyvä linkki, valitse viitetunniste painamalla', + 'pages_pointer_toggle_include' => 'Viitetunniste, valitse pysyvä linkki painamalla', + 'pages_permissions_active' => 'Sivun käyttöoikeudet käytössä', + 'pages_initial_revision' => 'Alkuperäinen julkaisu', + 'pages_references_update_revision' => 'Sisäisten linkkien automaattinen päivitys', + 'pages_initial_name' => 'Uusi sivu', + 'pages_editing_draft_notification' => 'Muokkaat luonnosta, joka on viimeksi tallennettu :timeDiff.', + 'pages_draft_edited_notification' => 'Tätä sivua on päivitetty myöhemmin. Tämä luonnos suositellaan poistettavaksi.', + 'pages_draft_page_changed_since_creation' => 'Sivua on päivitetty tämän luonnoksen luomisen jälkeen. On suositeltavaa, että poistat tämän luonnoksen tai huolehdit siitä, ettet korvaa uusia sivun muutoksia.', 'pages_draft_edit_active' => [ - 'start_a' => ':count users have started editing this page', - 'start_b' => ':userName has started editing this page', - 'time_a' => 'since the page was last updated', - 'time_b' => 'in the last :minCount minutes', - 'message' => ':start :time. Take care not to overwrite each other\'s updates!', + 'start_a' => ':count käyttäjää muokkaa tätä sivua', + 'start_b' => ':userName muokkaa tätä sivua', + 'time_a' => 'sivun viimeisimmän päivityksen jälkeen', + 'time_b' => 'viimeisen :minCount minuutin aikana', + 'message' => ':start :time. Huolehdi siitä, että ette ylikirjoita toistenne päivityksiä!', ], - 'pages_draft_discarded' => 'Draft discarded! The editor has been updated with the current page content', - 'pages_draft_deleted' => 'Draft deleted! The editor has been updated with the current page content', - 'pages_specific' => 'Specific Page', - 'pages_is_template' => 'Page Template', + 'pages_draft_discarded' => 'Luonnos on hylätty! Editoriin on päivitetty sivun nykyinen sisältö', + 'pages_draft_deleted' => 'Luonnos on poistettu! Editoriin on päivitetty sivun nykyinen sisältö', + 'pages_specific' => 'Tietty sivu', + 'pages_is_template' => 'Mallipohja', // Editor Sidebar - 'toggle_sidebar' => 'Toggle Sidebar', - 'page_tags' => 'Page Tags', - 'chapter_tags' => 'Chapter Tags', - 'book_tags' => 'Book Tags', - 'shelf_tags' => 'Shelf Tags', - 'tag' => 'Tag', - 'tags' => 'Tags', - 'tags_index_desc' => 'Tags can be applied to content within the system to apply a flexible form of categorization. Tags can have both a key and value, with the value being optional. Once applied, content can then be queried using the tag name and value.', - 'tag_name' => 'Tag Name', - 'tag_value' => 'Tag Value (Optional)', - 'tags_explain' => "Add some tags to better categorise your content. \n You can assign a value to a tag for more in-depth organisation.", - 'tags_add' => 'Add another tag', - 'tags_remove' => 'Remove this tag', - 'tags_usages' => 'Total tag usages', - 'tags_assigned_pages' => 'Assigned to Pages', - 'tags_assigned_chapters' => 'Assigned to Chapters', - 'tags_assigned_books' => 'Assigned to Books', - 'tags_assigned_shelves' => 'Assigned to Shelves', - 'tags_x_unique_values' => ':count unique values', - 'tags_all_values' => 'All values', - 'tags_view_tags' => 'View Tags', - 'tags_view_existing_tags' => 'View existing tags', - 'tags_list_empty_hint' => 'Tags can be assigned via the page editor sidebar or while editing the details of a book, chapter or shelf.', - 'attachments' => 'Attachments', - 'attachments_explain' => 'Upload some files or attach some links to display on your page. These are visible in the page sidebar.', - 'attachments_explain_instant_save' => 'Changes here are saved instantly.', - 'attachments_upload' => 'Upload File', - 'attachments_link' => 'Attach Link', - 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.', - 'attachments_set_link' => 'Set Link', - 'attachments_delete' => 'Are you sure you want to delete this attachment?', - 'attachments_dropzone' => 'Drop files here to upload', - 'attachments_no_files' => 'No files have been uploaded', - 'attachments_explain_link' => 'You can attach a link if you\'d prefer not to upload a file. This can be a link to another page or a link to a file in the cloud.', - 'attachments_link_name' => 'Link Name', - 'attachment_link' => 'Attachment link', - 'attachments_link_url' => 'Link to file', - 'attachments_link_url_hint' => 'Url of site or file', - 'attach' => 'Attach', - 'attachments_insert_link' => 'Add Attachment Link to Page', - 'attachments_edit_file' => 'Edit File', - 'attachments_edit_file_name' => 'File Name', - 'attachments_edit_drop_upload' => 'Drop files or click here to upload and overwrite', - 'attachments_order_updated' => 'Attachment order updated', - 'attachments_updated_success' => 'Attachment details updated', - 'attachments_deleted' => 'Attachment deleted', - 'attachments_file_uploaded' => 'File successfully uploaded', - 'attachments_file_updated' => 'File successfully updated', - 'attachments_link_attached' => 'Link successfully attached to page', - 'templates' => 'Templates', - 'templates_set_as_template' => 'Page is a template', - 'templates_explain_set_as_template' => 'You can set this page as a template so its contents be utilized when creating other pages. Other users will be able to use this template if they have view permissions for this page.', - 'templates_replace_content' => 'Replace page content', - 'templates_append_content' => 'Append to page content', - 'templates_prepend_content' => 'Prepend to page content', + 'toggle_sidebar' => 'Näytä/piilota sivupalkki', + 'page_tags' => 'Sivun tunnisteet', + 'chapter_tags' => 'Lukujen tunnisteet', + 'book_tags' => 'Kirjojen tunnisteet', + 'shelf_tags' => 'Hyllyjen tunnisteet', + 'tag' => 'Tunniste', + 'tags' => 'Tunnisteet', + 'tags_index_desc' => 'Järjestelmässä oleva sisältöä voidaan luokitella joustavasti tunnisteiden avulla. Tunnisteilla voi olla sekä avain että arvo. Arvo on valinnainen. Tunnisteella merkittyjä sisältöjä voidaan hakea käyttämällä tunnisteen nimeä ja arvoa.', + 'tag_name' => 'Tunnisteen nimi', + 'tag_value' => 'Tunnisteen arvo (valinnainen)', + 'tags_explain' => "Lisää tunnisteita sisällön luokittelua varten. \n Tunnisteiden arvojen avulla luokittelua voi edelleen tarkentaa.", + 'tags_add' => 'Lisää uusi tunniste', + 'tags_remove' => 'Poista tämä tunniste', + 'tags_usages' => 'Tunnisteen käyttökerrat', + 'tags_assigned_pages' => 'Lisätty sivuille', + 'tags_assigned_chapters' => 'Lisätty lukuihin', + 'tags_assigned_books' => 'Lisätty kirjoihin', + 'tags_assigned_shelves' => 'Lisätty hyllyihin', + 'tags_x_unique_values' => ':count yksilöllistä arvoa', + 'tags_all_values' => 'Kaikki arvot', + 'tags_view_tags' => 'Näytä tunnisteita', + 'tags_view_existing_tags' => 'Näytä käytetyt tunnisteet', + 'tags_list_empty_hint' => 'Tunnisteet voidaan määrittää editorin sivupalkissa tai kirjan, luvun tai hyllyn tietoja muokattaessa.', + 'attachments' => 'Liitteet', + 'attachments_explain' => 'Lataa tiedostoja tai liitä linkkejä, jotka näytetään sivulla. Nämä näkyvät sivun sivupalkissa.', + 'attachments_explain_instant_save' => 'Tässä tehdyt muutokset tallentuvat välittömästi.', + 'attachments_upload' => 'Lataa tiedosto', + 'attachments_link' => 'Liitä linkki', + 'attachments_upload_drop' => 'Vaihtoehtoisesti voit raahata ja pudottaa tiedoston tähän ladataksesi sen liitetiedostoksi.', + 'attachments_set_link' => 'Aseta linkki', + 'attachments_delete' => 'Haluatko varmasti poistaa tämän liitteen?', + 'attachments_dropzone' => 'Pudota siirrettävät tiedostot tähän', + 'attachments_no_files' => 'Yhtään tiedostoa ei ole ladattu', + 'attachments_explain_link' => 'Voit antaa linkin, jos et halua ladata tiedostoa. Se voi olla linkki toiselle sivulle tai linkki pilvipalvelussa olevaan tiedostoon.', + 'attachments_link_name' => 'Linkin nimi', + 'attachment_link' => 'Liitteen linkki', + 'attachments_link_url' => 'Linkki tiedostoon', + 'attachments_link_url_hint' => 'Sivuston tai tiedoston osoite', + 'attach' => 'Liitä', + 'attachments_insert_link' => 'Lisää liitteen linkki sivulle', + 'attachments_edit_file' => 'Muokkaa tiedostoa', + 'attachments_edit_file_name' => 'Tiedoston nimi', + 'attachments_edit_drop_upload' => 'Pudota tiedostoja tai klikkaa tästä ladataksesi ja korvataksesi', + 'attachments_order_updated' => 'Liitteiden järjestys päivitetty', + 'attachments_updated_success' => 'Liitteen tiedot päivitetty', + 'attachments_deleted' => 'Liite poistettu', + 'attachments_file_uploaded' => 'Tiedosto ladattiin onnistuneesti', + 'attachments_file_updated' => 'Tiedosto päivitettiin onnistuneesti', + 'attachments_link_attached' => 'Linkki liitettiin onnistuneesti sivulle', + 'templates' => 'Mallipohjat', + 'templates_set_as_template' => 'Sivu on mallipohja', + 'templates_explain_set_as_template' => 'Voit tehdä tästä sivusta mallipohjan, jolloin sen sisältöä voidaan käyttää muiden sivujen luomisessa. Muut käyttäjät voivat käyttää tätä mallipohjaa, jos heillä on pääsyoikeus sivuun.', + 'templates_replace_content' => 'Korvaa sivun sisältö', + 'templates_append_content' => 'Liitä sivun sisällön jatkoksi', + 'templates_prepend_content' => 'Liitä sivun sisällön alkuun', // Profile View - 'profile_user_for_x' => 'User for :time', - 'profile_created_content' => 'Created Content', - 'profile_not_created_pages' => ':userName has not created any pages', - 'profile_not_created_chapters' => ':userName has not created any chapters', - 'profile_not_created_books' => ':userName has not created any books', - 'profile_not_created_shelves' => ':userName has not created any shelves', + 'profile_user_for_x' => 'Ollut käyttäjä :time', + 'profile_created_content' => 'Luotu sisältö', + 'profile_not_created_pages' => ':userName ei ole luonut sivuja', + 'profile_not_created_chapters' => ':userName ei ole luonut lukuja', + 'profile_not_created_books' => ':userName ei ole luonut kirjoja', + 'profile_not_created_shelves' => ':userName ei ole luonut hyllyjä', // Comments - 'comment' => 'Comment', - 'comments' => 'Comments', - 'comment_add' => 'Add Comment', - 'comment_placeholder' => 'Leave a comment here', - 'comment_count' => '{0} No Comments|{1} 1 Comment|[2,*] :count Comments', - 'comment_save' => 'Save Comment', - 'comment_new' => 'New Comment', - 'comment_created' => 'commented :createDiff', - 'comment_updated' => 'Updated :updateDiff by :username', - 'comment_updated_indicator' => 'Updated', - 'comment_deleted_success' => 'Comment deleted', - 'comment_created_success' => 'Comment added', - 'comment_updated_success' => 'Comment updated', - 'comment_delete_confirm' => 'Are you sure you want to delete this comment?', - 'comment_in_reply_to' => 'In reply to :commentId', - 'comment_editor_explain' => 'Here are the comments that have been left on this page. Comments can be added & managed when viewing the saved page.', + 'comment' => 'Kommentti', + 'comments' => 'Kommentit', + 'comment_add' => 'Lisää kommentti', + 'comment_placeholder' => 'Jätä kommentti tähän', + 'comment_count' => '{0} Ei kommentteja|{1} 1 kommentti|[2,*] :count kommenttia', + 'comment_save' => 'Tallenna kommentti', + 'comment_new' => 'Uusi kommentti', + 'comment_created' => 'kommentoi :createDiff', + 'comment_updated' => 'Päivitetty :updateDiff :username toimesta', + 'comment_updated_indicator' => 'Päivitetty', + 'comment_deleted_success' => 'Kommentti poistettu', + 'comment_created_success' => 'Kommentti lisätty', + 'comment_updated_success' => 'Kommentti päivitetty', + 'comment_delete_confirm' => 'Haluatko varmasti poistaa tämän kommentin?', + 'comment_in_reply_to' => 'Vastaus kommenttiin :commentId', + 'comment_editor_explain' => 'Tässä ovat sivulle jätetyt komentit. Kommentteja voi lisätä ja hallita, kun tarkastelet tallennettua sivua.', // Revision - 'revision_delete_confirm' => 'Are you sure you want to delete this revision?', - 'revision_restore_confirm' => 'Are you sure you want to restore this revision? The current page contents will be replaced.', - 'revision_cannot_delete_latest' => 'Cannot delete the latest revision.', + 'revision_delete_confirm' => 'Haluatko varmasti poistaa tämän version?', + 'revision_restore_confirm' => 'Oletko varma, että haluat palauttaa tämän version? Sivun nykyinen sisältö korvataan.', + 'revision_cannot_delete_latest' => 'Uusinta versiota ei voi poistaa.', // Copy view - 'copy_consider' => 'Please consider the below when copying content.', - 'copy_consider_permissions' => 'Custom permission settings will not be copied.', - 'copy_consider_owner' => 'You will become the owner of all copied content.', - 'copy_consider_images' => 'Page image files will not be duplicated & the original images will retain their relation to the page they were originally uploaded to.', - 'copy_consider_attachments' => 'Page attachments will not be copied.', - 'copy_consider_access' => 'A change of location, owner or permissions may result in this content being accessible to those previously without access.', + 'copy_consider' => 'Ota huomioon seuraavat asiat sisältöä kopioidessasi.', + 'copy_consider_permissions' => 'Mukautettuja käyttöoikeusasetuksia ei kopioida.', + 'copy_consider_owner' => 'Sinusta tulee kaiken kopioidun sisällön omistaja.', + 'copy_consider_images' => 'Sivun kuvatiedostoja ei kopioida, ja alkuperäiset kuvat säilyttävät suhteensa siihen sivuun, jolle ne alun perin ladattiin.', + 'copy_consider_attachments' => 'Sivun liitteitä ei kopioida.', + 'copy_consider_access' => 'Sijainnin, omistajan tai käyttöoikeuksien vaihtuminen voi johtaa siihen, että tämä sisältö on sellaisten käyttäjien saatavilla, joilla ei ole aiemmin ollut siihen pääsyä.', // Conversions - 'convert_to_shelf' => 'Convert to Shelf', - 'convert_to_shelf_contents_desc' => 'You can convert this book to a new shelf with the same contents. Chapters contained within this book will be converted to new books. If this book contains any pages, that are not in a chapter, this book will be renamed and contain such pages, and this book will become part of the new shelf.', - 'convert_to_shelf_permissions_desc' => 'Any permissions set on this book will be copied to the new shelf and to all new child books that don\'t have their own permissions enforced. Note that permissions on shelves do not auto-cascade to content within, as they do for books.', - 'convert_book' => 'Convert Book', - 'convert_book_confirm' => 'Are you sure you want to convert this book?', - 'convert_undo_warning' => 'This cannot be as easily undone.', - 'convert_to_book' => 'Convert to Book', - 'convert_to_book_desc' => 'You can convert this chapter to a new book with the same contents. Any permissions set on this chapter will be copied to the new book but any inherited permissions, from the parent book, will not be copied which could lead to a change of access control.', - 'convert_chapter' => 'Convert Chapter', - 'convert_chapter_confirm' => 'Are you sure you want to convert this chapter?', + 'convert_to_shelf' => 'Muunna hyllyksi', + 'convert_to_shelf_contents_desc' => 'Voit muuntaa tämän kirjan uudeksi hyllyksi, jossa on sama sisältö. Kirjan sisältämät luvut muunnetaan uusiksi kirjoiksi. Jos kirja sisältää sivuja, jotka eivät kuulu mihinkään lukuun, kirja nimetään uudelleen ja siitä tulee osa uutta hyllyä, joka sisältää kyseiset sivut.', + 'convert_to_shelf_permissions_desc' => 'Kaikki tälle kirjalle asetetut käyttöoikeudet kopioidaan uuteen hyllyyn ja kaikkiin uusiin hyllyn kirjoihin, joilla ei ole omia käyttöoikeuksia. Huomaa, että hyllyjen käyttöoikeudet eivät siirry automaattisesti hyllyssä olevaan sisältöön, kuten kirjoissa.', + 'convert_book' => 'Muunna kirja', + 'convert_book_confirm' => 'Haluatko varmasti muuntaa tämän kirjan?', + 'convert_undo_warning' => 'Tätä ei voi yhtä helposti perua.', + 'convert_to_book' => 'Muunna kirjaksi', + 'convert_to_book_desc' => 'Voit muuntaa tämän luvun uudeksi kirjaksi, jonka sisältö on sama. Kaikki tälle luvulle asetetut käyttöoikeudet kopioidaan uuteen kirjaan, mutta alkuperäisestä kirjasta perittyjä käyttöoikeuksia ei kopioida, mikä voi johtaa käyttöoikeuksien muuttumiseen.', + 'convert_chapter' => 'Muunna luku', + 'convert_chapter_confirm' => 'Haluatko varmasti muuntaa tämän luvun?', // References - 'references' => 'References', - 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references' => 'Viitteet', + 'references_none' => 'Tähän kohteeseen ei ole viittauksia.', + 'references_to_desc' => 'Lista kohteeseen viittaavasta sisällöstä.', // Watch Options - 'watch' => 'Watch', - 'watch_title_default' => 'Default Preferences', - 'watch_desc_default' => 'Revert watching to just your default notification preferences.', - 'watch_title_ignore' => 'Ignore', - 'watch_desc_ignore' => 'Ignore all notifications, including those from user-level preferences.', - 'watch_title_new' => 'New Pages', - 'watch_desc_new' => 'Notify when any new page is created within this item.', - 'watch_title_updates' => 'All Page Updates', - 'watch_desc_updates' => 'Notify upon all new pages and page changes.', - 'watch_desc_updates_page' => 'Notify upon all page changes.', - 'watch_title_comments' => 'All Page Updates & Comments', - 'watch_desc_comments' => 'Notify upon all new pages, page changes and new comments.', - 'watch_desc_comments_page' => 'Notify upon page changes and new comments.', - 'watch_change_default' => 'Change default notification preferences', - 'watch_detail_ignore' => 'Ignoring notifications', - 'watch_detail_new' => 'Watching for new pages', - 'watch_detail_updates' => 'Watching new pages and updates', - 'watch_detail_comments' => 'Watching new pages, updates & comments', - 'watch_detail_parent_book' => 'Watching via parent book', - 'watch_detail_parent_book_ignore' => 'Ignoring via parent book', - 'watch_detail_parent_chapter' => 'Watching via parent chapter', - 'watch_detail_parent_chapter_ignore' => 'Ignoring via parent chapter', + 'watch' => 'Seuraa', + 'watch_title_default' => 'Oletusasetukset', + 'watch_desc_default' => 'Palauta seuranta omiin oletusasetuksiin.', + 'watch_title_ignore' => 'Ohita', + 'watch_desc_ignore' => 'Ohita kaikki ilmoitukset, myös käyttäjäasetuksissa määritellyt ilmoitukset.', + 'watch_title_new' => 'Uudet sivut', + 'watch_desc_new' => 'Ilmoita, kun tähän kohteeseen luodaan uusi sivu.', + 'watch_title_updates' => 'Kaikki sivupäivitykset', + 'watch_desc_updates' => 'Ilmoita kaikista uusista sivuista ja sivujen muutoksista.', + 'watch_desc_updates_page' => 'Ilmoita kaikista sivujen muutoksista.', + 'watch_title_comments' => 'Kaikki sivupäivitykset ja kommentit', + 'watch_desc_comments' => 'Ilmoita kaikista uusista sivuista, sivujen muutoksista ja uusista kommenteista.', + 'watch_desc_comments_page' => 'Ilmoita sivujen muutoksista ja uusista kommenteista.', + 'watch_change_default' => 'Muuta oletusilmoitusasetuksia', + 'watch_detail_ignore' => 'Ilmoitusten ohittaminen', + 'watch_detail_new' => 'Uusien sivujen seuraaminen', + 'watch_detail_updates' => 'Uusien sivujen ja päivitysten seuraaminen', + 'watch_detail_comments' => 'Uusien sivujen, päivitysten ja kommenttien seuraaminen', + 'watch_detail_parent_book' => 'Seuraaminen kirjan perusteella', + 'watch_detail_parent_book_ignore' => 'Huomioimatta jättäminen kirjan perusteella', + 'watch_detail_parent_chapter' => 'Seuraaminen luvun perusteella', + 'watch_detail_parent_chapter_ignore' => 'Huomioimatta jättäminen luvun perusteella', ]; diff --git a/lang/fi/errors.php b/lang/fi/errors.php index 8813cf90a..082cac242 100644 --- a/lang/fi/errors.php +++ b/lang/fi/errors.php @@ -5,116 +5,116 @@ return [ // Permissions - 'permission' => 'You do not have permission to access the requested page.', - 'permissionJson' => 'You do not have permission to perform the requested action.', + 'permission' => 'Sinulla ei ole pääsyoikeutta pyydettyyn sivuun.', + 'permissionJson' => 'Sinulla ei ole oikeutta suorittaa pyydettyä toimintoa.', // Auth - 'error_user_exists_different_creds' => 'A user with the email :email already exists but with different credentials.', - 'email_already_confirmed' => 'Email has already been confirmed, Try logging in.', - 'email_confirmation_invalid' => 'This confirmation token is not valid or has already been used, Please try registering again.', - 'email_confirmation_expired' => 'The confirmation token has expired, A new confirmation email has been sent.', - 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', - 'ldap_fail_anonymous' => 'LDAP access failed using anonymous bind', - 'ldap_fail_authed' => 'LDAP access failed using given dn & password details', - 'ldap_extension_not_installed' => 'LDAP PHP extension not installed', - 'ldap_cannot_connect' => 'Cannot connect to ldap server, Initial connection failed', - 'saml_already_logged_in' => 'Already logged in', - 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', - 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', - 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', - 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', - 'oidc_already_logged_in' => 'Already logged in', - 'oidc_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', - 'oidc_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', - 'oidc_fail_authed' => 'Login using :system failed, system did not provide successful authorization', - 'social_no_action_defined' => 'No action defined', - 'social_login_bad_response' => "Error received during :socialAccount login: \n:error", - 'social_account_in_use' => 'This :socialAccount account is already in use, Try logging in via the :socialAccount option.', - 'social_account_email_in_use' => 'The email :email is already in use. If you already have an account you can connect your :socialAccount account from your profile settings.', - 'social_account_existing' => 'This :socialAccount is already attached to your profile.', - 'social_account_already_used_existing' => 'This :socialAccount account is already used by another user.', - 'social_account_not_used' => 'This :socialAccount account is not linked to any users. Please attach it in your profile settings. ', - 'social_account_register_instructions' => 'If you do not yet have an account, You can register an account using the :socialAccount option.', - '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.', + 'error_user_exists_different_creds' => 'Sähköpostiosoite :email on jo käytössä toisessa käyttäjätunnuksessa.', + 'email_already_confirmed' => 'Sähköposti on jo vahvistettu, yritä kirjautua sisään.', + 'email_confirmation_invalid' => 'Tämä vahvistuslinkki ei ole voimassa tai sitä on jo käytetty, yritä rekisteröityä uudelleen.', + 'email_confirmation_expired' => 'Vahvistuslinkki on vanhentunut, uusi vahvistussähköposti on lähetetty.', + 'email_confirmation_awaiting' => 'Tämän tilin sähköpostiosoite pitää vahvistaa', + 'ldap_fail_anonymous' => 'Anonyymi LDAP-todennus epäonnistui', + 'ldap_fail_authed' => 'LDAP-todennus epäonnistui annetulla nimellä ja salasanalla', + 'ldap_extension_not_installed' => 'PHP:n LDAP-laajennusta ei ole asennettu', + 'ldap_cannot_connect' => 'Yhteyttä LDAP-palvelimeen ei voida muodostaa, alustava yhteys epäonnistui', + 'saml_already_logged_in' => 'Olet jo kirjautunut sisään', + 'saml_no_email_address' => 'Tämän käyttäjän sähköpostiosoitetta ei löytynyt ulkoisesta todennuspalvelusta', + 'saml_invalid_response_id' => 'Tämän sovelluksen käynnistämä prosessi ei tunnista ulkoisen todennusjärjestelmän pyyntöä. +Sovellus ei tunnista ulkoisen todennuspalvelun pyyntöä. Ongelman voi aiheuttaa siirtyminen selaimessa takaisin edelliseen näkymään kirjautumisen jälkeen.', + 'saml_fail_authed' => 'Sisäänkirjautuminen :system käyttäen epäonnistui, järjestelmä ei antanut valtuutusta', + 'oidc_already_logged_in' => 'Olet jo kirjautunut sisään', + 'oidc_user_not_registered' => 'Käyttäjää :nimi ei ole rekisteröity ja automaattinen rekisteröinti on pois käytöstä', + 'oidc_no_email_address' => 'Ulkoisen todennuspalvelun antamista tiedoista ei löytynyt tämän käyttäjän sähköpostiosoitetta', + 'oidc_fail_authed' => 'Sisäänkirjautuminen :system käyttäen epäonnistui, järjestelmä ei antanut valtuutusta', + 'social_no_action_defined' => 'Ei määriteltyä toimenpidettä', + 'social_login_bad_response' => "Virhe :socialAccount-kirjautumisen aikana: \n:error", + 'social_account_in_use' => 'Tämä :socialAccount-tili on jo käytössä, yritä kirjautua sisään :socialAccount-vaihtoehdon kautta.', + 'social_account_email_in_use' => 'Sähköposti :email on jo käytössä. Jos sinulla on jo sivustolla käyttäjätili, voit yhdistää :socialAccount-tilisi profiiliasetuksista.', + 'social_account_existing' => 'Tämä :socialAccount-tili on jo liitetty profiiliisi.', + 'social_account_already_used_existing' => 'Tämä :socialAccount-tili on jo toisen käyttäjän käytössä.', + 'social_account_not_used' => 'Tätä :socialAccount-tiliä ei ole liitetty mihinkään käyttäjään. Voit liittää sen profiiliasetuksistasi. ', + 'social_account_register_instructions' => 'Jos sinulla ei vielä ole käyttäjätiliä, voit rekisteröidä tilin käyttämällä :socialAccount-vaihtoehtoa.', + '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.', // System - 'path_not_writable' => 'File path :filePath could not be uploaded to. Ensure it is writable to the server.', - 'cannot_get_image_from_url' => 'Cannot get image from :url', - 'cannot_create_thumbs' => 'The server cannot create thumbnails. Please check you have the GD PHP extension installed.', - 'server_upload_limit' => 'The server does not allow uploads of this size. Please try a smaller file size.', - 'server_post_limit' => 'The server cannot receive the provided amount of data. Try again with less data or a smaller file.', - 'uploaded' => 'The server does not allow uploads of this size. Please try a smaller file size.', + 'path_not_writable' => 'Tiedostopolkuun :filePath ei voitu ladata tiedostoa. Tarkista polun kirjoitusoikeudet.', + 'cannot_get_image_from_url' => 'Kuvan hakeminen osoitteesta :url ei onnistu', + 'cannot_create_thumbs' => 'Palvelin ei voi luoda pikkukuvia. Tarkista, että PHP:n GD-laajennus on asennettu.', + 'server_upload_limit' => 'Palvelin ei salli näin suuria tiedostoja. Kokeile pienempää tiedostokokoa.', + 'server_post_limit' => 'Palvelin ei pysty vastaanottamaan annettua tietomäärää. Yritä uudelleen pienemmällä tiedostolla.', + 'uploaded' => 'Palvelin ei salli näin suuria tiedostoja. Kokeile pienempää tiedostokokoa.', // Drawing & Images - 'image_upload_error' => 'An error occurred uploading the image', - 'image_upload_type_error' => 'The image type being uploaded is invalid', - 'image_upload_replace_type' => 'Image file replacements must be of the same type', - 'image_upload_memory_limit' => 'Failed to handle image upload and/or create thumbnails due to system resource limits.', - 'image_thumbnail_memory_limit' => 'Failed to create image size variations due to system resource limits.', - 'image_gallery_thumbnail_memory_limit' => 'Failed to create gallery thumbnails due to system resource limits.', - 'drawing_data_not_found' => 'Drawing data could not be loaded. The drawing file might no longer exist or you may not have permission to access it.', + 'image_upload_error' => 'Kuvan lataamisessa tapahtui virhe', + 'image_upload_type_error' => 'Ladattavan kuvan tyyppi on virheellinen', + 'image_upload_replace_type' => 'Korvaavan kuvatiedoston tulee olla samaa tyyppiä kuin alkuperäinen kuva', + 'image_upload_memory_limit' => 'Kuvan lataaminen ja/tai pikkukuvien luominen epäonnistui järjestelmän resurssirajoitusten vuoksi.', + 'image_thumbnail_memory_limit' => 'Kuvan kokovaihtoehtojen luominen epäonnistui järjestelmän resurssirajoitusten vuoksi.', + 'image_gallery_thumbnail_memory_limit' => 'Gallerian pikkukuvien luominen epäonnistui järjestelmän resurssirajoitusten vuoksi.', + 'drawing_data_not_found' => 'Piirustuksen tietoja ei voitu ladata. Piirustustiedostoa ei ehkä ole enää olemassa tai sinulla ei ole oikeutta käyttää sitä.', // Attachments - 'attachment_not_found' => 'Attachment not found', - 'attachment_upload_error' => 'An error occurred uploading the attachment file', + 'attachment_not_found' => 'Liitettä ei löytynyt', + 'attachment_upload_error' => 'Liitteen lataamisessa tapahtui virhe', // Pages - 'page_draft_autosave_fail' => 'Failed to save draft. Ensure you have internet connection before saving this page', - 'page_draft_delete_fail' => 'Failed to delete page draft and fetch current page saved content', - 'page_custom_home_deletion' => 'Cannot delete a page while it is set as a homepage', + 'page_draft_autosave_fail' => 'Luonnoksen tallentaminen epäonnistui. Varmista, että sinulla on toimiva internetyhteys ennen sivun tallentamista', + 'page_draft_delete_fail' => 'Luonnoksen poistaminen ja sivun tallennetun sisällön noutaminen epäonnistui', + 'page_custom_home_deletion' => 'Sivua ei voi poistaa, koska se on asetettu etusivuksi', // Entities - 'entity_not_found' => 'Entity not found', - 'bookshelf_not_found' => 'Shelf not found', - 'book_not_found' => 'Book not found', - 'page_not_found' => 'Page not found', - 'chapter_not_found' => 'Chapter not found', - 'selected_book_not_found' => 'The selected book was not found', - 'selected_book_chapter_not_found' => 'The selected Book or Chapter was not found', - 'guests_cannot_save_drafts' => 'Guests cannot save drafts', + 'entity_not_found' => 'Kohdetta ei löydy', + 'bookshelf_not_found' => 'Hyllyä ei löytynyt', + 'book_not_found' => 'Kirjaa ei löytynyt', + 'page_not_found' => 'Sivua ei löytynyt', + 'chapter_not_found' => 'Lukua ei löytynyt', + 'selected_book_not_found' => 'Valittua kirjaa ei löytynyt', + 'selected_book_chapter_not_found' => 'Valittua kirjaa tai lukua ei löytynyt', + 'guests_cannot_save_drafts' => 'Vieraat eivät voi tallentaa luonnoksia', // Users - 'users_cannot_delete_only_admin' => 'You cannot delete the only admin', - 'users_cannot_delete_guest' => 'You cannot delete the guest user', + 'users_cannot_delete_only_admin' => 'Ainoaa ylläpitäjää ei voi poistaa', + 'users_cannot_delete_guest' => 'Vieraskäyttäjää ei voi poistaa', // Roles - 'role_cannot_be_edited' => 'This role cannot be edited', - 'role_system_cannot_be_deleted' => 'This role is a system role and cannot be deleted', - 'role_registration_default_cannot_delete' => 'This role cannot be deleted while set as the default registration role', - 'role_cannot_remove_only_admin' => 'This user is the only user assigned to the administrator role. Assign the administrator role to another user before attempting to remove it here.', + 'role_cannot_be_edited' => 'Tätä roolia ei voi muokata', + 'role_system_cannot_be_deleted' => 'Tämä rooli on järjestelmärooli, eikä sitä voi poistaa', + 'role_registration_default_cannot_delete' => 'Tätä roolia ei voi poistaa, kun se on asetettu oletusrooliksi uusille rekisteröityville käyttäjille', + 'role_cannot_remove_only_admin' => 'Tämä käyttäjä on ainoa käyttäjä, jolle on määritetty ylläpitäjän rooli. Määritä ylläpitäjän rooli toiselle käyttäjälle, ennen kuin yrität poistaa tämän käyttäjän.', // Comments - 'comment_list' => 'An error occurred while fetching the comments.', - 'cannot_add_comment_to_draft' => 'You cannot add comments to a draft.', - 'comment_add' => 'An error occurred while adding / updating the comment.', - 'comment_delete' => 'An error occurred while deleting the comment.', - 'empty_comment' => 'Cannot add an empty comment.', + 'comment_list' => 'Kommenttien noutamisessa tapahtui virhe.', + 'cannot_add_comment_to_draft' => 'Luonnokseen ei voi lisätä kommentteja.', + 'comment_add' => 'Kommentin lisäämisessä tai päivittämisessä tapahtui virhe.', + 'comment_delete' => 'Kommentin poistamisessa tapahtui virhe.', + 'empty_comment' => 'Tyhjää kommenttia ei voi lisätä.', // Error pages - '404_page_not_found' => 'Page Not Found', - 'sorry_page_not_found' => 'Sorry, The page you were looking for could not be found.', - 'sorry_page_not_found_permission_warning' => 'If you expected this page to exist, you might not have permission to view it.', - 'image_not_found' => 'Image Not Found', - 'image_not_found_subtitle' => 'Sorry, The image file you were looking for could not be found.', - 'image_not_found_details' => 'If you expected this image to exist it might have been deleted.', - 'return_home' => 'Return to home', - 'error_occurred' => 'An Error Occurred', - 'app_down' => ':appName is down right now', - 'back_soon' => 'It will be back up soon.', + '404_page_not_found' => 'Sivua ei löydy', + 'sorry_page_not_found' => 'Valitettavasti etsimääsi sivua ei löytynyt.', + 'sorry_page_not_found_permission_warning' => 'Jos oletit, että tämä sivu on olemassa, sinulla ei ehkä ole lupaa tarkastella sitä.', + 'image_not_found' => 'Kuvaa ei löytynyt', + 'image_not_found_subtitle' => 'Valitettavasti etsimääsi kuvatiedostoa ei löytynyt.', + 'image_not_found_details' => 'Jos oletit, että tämä kuva on olemassa, se on ehkä poistettu.', + 'return_home' => 'Palaa etusivulle', + 'error_occurred' => 'Tapahtui virhe', + 'app_down' => ':appName on kaatunut', + 'back_soon' => 'Se palautetaan pian.', // API errors - 'api_no_authorization_found' => 'No authorization token found on the request', - 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', - 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', - 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', - 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', - 'api_user_token_expired' => 'The authorization token used has expired', + 'api_no_authorization_found' => 'Pyynnöstä ei löytynyt valtuutuskoodia', + 'api_bad_authorization_format' => 'Pyynnöstä löytyi valtuutuskoodi, mutta sen muoto oli virheellinen', + 'api_user_token_not_found' => 'Annetulle valtuutuskoodille ei löytynyt vastaavaa API-tunnistetta', + 'api_incorrect_token_secret' => 'API-tunnisteelle annettu salainen avain on virheellinen', + 'api_user_no_api_permission' => 'Käytetyn API-tunnisteen omistajalla ei ole oikeutta tehdä API-kutsuja', + 'api_user_token_expired' => 'Käytetty valtuutuskoodi on vanhentunut', // Settings & Maintenance - 'maintenance_test_email_failure' => 'Error thrown when sending a test email:', + 'maintenance_test_email_failure' => 'Virhe testisähköpostia lähetettäessä:', // HTTP errors - 'http_ssr_url_no_match' => 'The URL does not match the configured allowed SSR hosts', + 'http_ssr_url_no_match' => 'URL-osoite ei vastaa määritettyjä sallittuja SSR-isäntiä', ]; diff --git a/lang/fi/notifications.php b/lang/fi/notifications.php index 5539ae9a9..a737ad7d9 100644 --- a/lang/fi/notifications.php +++ b/lang/fi/notifications.php @@ -4,23 +4,24 @@ */ return [ - 'new_comment_subject' => 'New comment on page: :pageName', - 'new_comment_intro' => 'A user has commented on a page in :appName:', - 'new_page_subject' => 'New page: :pageName', - 'new_page_intro' => 'A new page has been created in :appName:', - 'updated_page_subject' => 'Updated page: :pageName', - 'updated_page_intro' => 'A page has been updated in :appName:', - 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', + 'new_comment_subject' => 'Uusi kommentti sivulla: :pageName', + 'new_comment_intro' => 'Käyttäjä on kommentoinut sivua sivustolla :appName:', + 'new_page_subject' => 'Uusi sivu: :pageName', + 'new_page_intro' => 'Uusi sivu on luotu sivustolla :appName:', + 'updated_page_subject' => 'Päivitetty sivu: :pageName', + 'updated_page_intro' => 'Sivu on päivitetty sivustolla :appName:', + 'updated_page_debounce' => 'Useiden ilmoitusten välttämiseksi sinulle ei toistaiseksi lähetetä ilmoituksia saman toimittajan tekemistä uusista muokkauksista tälle sivulle.', - 'detail_page_name' => 'Page Name:', - 'detail_commenter' => 'Commenter:', - 'detail_comment' => 'Comment:', - 'detail_created_by' => 'Created By:', - 'detail_updated_by' => 'Updated By:', + 'detail_page_name' => 'Sivun nimi:', + 'detail_page_path' => 'Sivun polku:', + 'detail_commenter' => 'Kommentoija:', + 'detail_comment' => 'Kommentti:', + 'detail_created_by' => 'Luonut', + 'detail_updated_by' => 'Päivittänyt', - 'action_view_comment' => 'View Comment', - 'action_view_page' => 'View Page', + 'action_view_comment' => 'Näytä kommentti', + 'action_view_page' => 'Näytä sivu', - 'footer_reason' => 'This notification was sent to you because :link cover this type of activity for this item.', - 'footer_reason_link' => 'your notification preferences', + 'footer_reason' => 'Tämä ilmoitus lähetettiin sinulle, koska :link kattaa tämän tyyppisen toiminnan tälle kohteelle.', + 'footer_reason_link' => 'omat ilmoitusasetukset', ]; diff --git a/lang/fi/pagination.php b/lang/fi/pagination.php index 85bd12fc3..ebd8085c2 100644 --- a/lang/fi/pagination.php +++ b/lang/fi/pagination.php @@ -6,7 +6,7 @@ */ return [ - 'previous' => '« Previous', - 'next' => 'Next »', + 'previous' => '« Edellinen', + 'next' => 'Seuraava »', ]; diff --git a/lang/fi/passwords.php b/lang/fi/passwords.php index b408f3c2f..86e4e189d 100644 --- a/lang/fi/passwords.php +++ b/lang/fi/passwords.php @@ -6,10 +6,10 @@ */ return [ - 'password' => 'Passwords must be at least eight characters and match the confirmation.', - 'user' => "We can't find a user with that e-mail address.", - 'token' => 'The password reset token is invalid for this email address.', - 'sent' => 'We have e-mailed your password reset link!', - 'reset' => 'Your password has been reset!', + 'password' => 'Salasanan on oltava vähintään kahdeksan merkkiä pitkä ja täsmättävä vahvistuksen kanssa.', + 'user' => "Emme löydä käyttäjää, jolla on kyseinen sähköpostiosoite.", + 'token' => 'Salasanan palautuslinkki ei täsmää sähköpostin kanssa.', + 'sent' => 'Olemme lähettäneet salasanasi palautuslinkin sähköpostitse!', + 'reset' => 'Salasanasi on palautettu!', ]; diff --git a/lang/fi/preferences.php b/lang/fi/preferences.php index 2b88f9671..25cd76bf7 100644 --- a/lang/fi/preferences.php +++ b/lang/fi/preferences.php @@ -5,47 +5,47 @@ */ return [ - 'my_account' => 'My Account', + 'my_account' => 'Oma tili', - 'shortcuts' => 'Shortcuts', - 'shortcuts_interface' => 'UI Shortcut Preferences', - 'shortcuts_toggle_desc' => 'Here you can enable or disable keyboard system interface shortcuts, used for navigation and actions.', - 'shortcuts_customize_desc' => 'You can customize each of the shortcuts below. Just press your desired key combination after selecting the input for a shortcut.', - 'shortcuts_toggle_label' => 'Keyboard shortcuts enabled', - 'shortcuts_section_navigation' => 'Navigation', - 'shortcuts_section_actions' => 'Common Actions', - 'shortcuts_save' => 'Save Shortcuts', - 'shortcuts_overlay_desc' => 'Note: When shortcuts are enabled a helper overlay is available via pressing "?" which will highlight the available shortcuts for actions currently visible on the screen.', - 'shortcuts_update_success' => 'Shortcut preferences have been updated!', - 'shortcuts_overview_desc' => 'Manage keyboard shortcuts you can use to navigate the system user interface.', + 'shortcuts' => 'Pikanäppäimet', + 'shortcuts_interface' => 'Käyttöliittymän pikanäppäinten asetukset', + 'shortcuts_toggle_desc' => 'Tästä voit ottaa käyttöön tai poistaa käytöstä järjestelmän käyttöliittymän pikanäppäimet, joita käytetään navigointiin ja toimintoihin.', + 'shortcuts_customize_desc' => 'Voit mukauttaa alla olevia pikanäppäimiä. Paina haluamaasi näppäinyhdistelmää sen jälkeen, kun olet valinnut pikanäppäimen syöttökentän.', + 'shortcuts_toggle_label' => 'Pikanäppäimet käytössä', + 'shortcuts_section_navigation' => 'Navigointi', + 'shortcuts_section_actions' => 'Yleiset toiminnot', + 'shortcuts_save' => 'Tallenna pikanäppäimet', + 'shortcuts_overlay_desc' => 'Huomautus: kun pikanäppäimet ovat käytössä, voit painaa "?"-näppäintä, joka korostaa näytöllä näkyviin toimintoihin liitetyt pikanäppäimet.', + 'shortcuts_update_success' => 'Pikanäppäinten asetukset on päivitetty!', + 'shortcuts_overview_desc' => 'Hallitse pikanäppäimiä, joilla voit navigoida järjestelmän käyttöliittymässä.', - 'notifications' => 'Notification Preferences', - 'notifications_desc' => 'Control the email notifications you receive when certain activity is performed within the system.', - 'notifications_opt_own_page_changes' => 'Notify upon changes to pages I own', - 'notifications_opt_own_page_comments' => 'Notify upon comments on pages I own', - 'notifications_opt_comment_replies' => 'Notify upon replies to my comments', - 'notifications_save' => 'Save Preferences', - 'notifications_update_success' => 'Notification preferences have been updated!', - 'notifications_watched' => 'Watched & Ignored Items', - 'notifications_watched_desc' => ' Below are the items that have custom watch preferences applied. To update your preferences for these, view the item then find the watch options in the sidebar.', + 'notifications' => 'Ilmoitusasetukset', + 'notifications_desc' => 'Hallitse järjestelmän toimintoihin liittyviä sähköposti-ilmoituksia.', + 'notifications_opt_own_page_changes' => 'Ilmoita omistamilleni sivuille tehdyistä muutoksista', + 'notifications_opt_own_page_comments' => 'Ilmoita omistamilleni sivuille tehdyistä kommenteista', + 'notifications_opt_comment_replies' => 'Ilmoita vastauksista kommentteihini', + 'notifications_save' => 'Tallenna asetukset', + 'notifications_update_success' => 'Ilmoitusasetukset on päivitetty!', + 'notifications_watched' => 'Seuratut ja huomiotta jätetyt kohteet', + 'notifications_watched_desc' => 'Alla oleviin kohteisiin sovelletaan muokautettuja seuranta-asetuksia. Voit päivittää kohteita koskevat asetukset avaamalla kohde ja valitsemalla seuranta-asetukset sivupalkista.', - 'auth' => 'Access & Security', - 'auth_change_password' => 'Change Password', - 'auth_change_password_desc' => 'Change the password you use to log-in to the application. This must be at least 8 characters long.', - 'auth_change_password_success' => 'Password has been updated!', + 'auth' => 'Pääsy ja turvallisuus', + 'auth_change_password' => 'Vaihda salasana', + 'auth_change_password_desc' => 'Vaihda kirjautumiseen käytettävä salasana. Salasanan on oltava vähintään 8 merkkiä pitkä.', + 'auth_change_password_success' => 'Salasana on päivitetty!', - 'profile' => 'Profile Details', - 'profile_desc' => 'Manage the details of your account which represents you to other users, in addition to details that are used for communication and system personalisation.', - 'profile_view_public' => 'View Public Profile', - 'profile_name_desc' => 'Configure your display name which will be visible to other users in the system through the activity you perform, and content you own.', - 'profile_email_desc' => 'This email will be used for notifications and, depending on active system authentication, system access.', - 'profile_email_no_permission' => 'Unfortunately you don\'t have permission to change your email address. If you want to change this, you\'d need to ask an administrator to change this for you.', - 'profile_avatar_desc' => 'Select an image which will be used to represent yourself to others in the system. Ideally this image should be square and about 256px in width and height.', - 'profile_admin_options' => 'Administrator Options', - 'profile_admin_options_desc' => 'Additional administrator-level options, like those to manage role assignments, can be found for your user account in the "Settings > Users" area of the application.', + 'profile' => 'Profiilitiedot', + 'profile_desc' => 'Hallitse muille käyttäjille näkyviä käyttäjätilisi tietoja, sekä tietoja, joita käytetään viestintään ja järjestelmän personointiin.', + 'profile_view_public' => 'Näytä julkinen profiili', + 'profile_name_desc' => 'Määritä näyttönimesi, joka näkyy muille käyttäjille järjestelmässä suorittamiesi toimintojen ja omistamasi sisällön yhteydessä.', + 'profile_email_desc' => 'Tätä sähköpostia käytetään ilmoituksiin ja käytössä olevasta tunnistautumistavasta riippuen järjestelmään pääsyyn.', + 'profile_email_no_permission' => 'Valitettavasti sinulla ei ole lupaa muuttaa sähköpostiosoitettasi. Jos haluat muuttaa sen, sinun on pyydettävä ylläpitäjää muuttamaan se puolestasi.', + 'profile_avatar_desc' => 'Valitse kuva, joka näkyy järjestelmän muille käyttäjille. Kuvan tulisi olla neliön muotoinen ja leveydeltään ja korkeudeltaan noin 256 pikseliä.', + 'profile_admin_options' => 'Ylläpitäjän asetukset', + 'profile_admin_options_desc' => 'Ylläpitäjän lisäasetukset, kuten roolien osoittamiseen liittyvät valinnat, löytyvät käyttäjätiliäsi varten järjestelmän kohdasta "Asetukset > Käyttäjät".', - 'delete_account' => 'Delete Account', - 'delete_my_account' => 'Delete My Account', - 'delete_my_account_desc' => 'This will fully delete your user account from the system. You will not be able to recover this account or revert this action. Content you\'ve created, such as created pages and uploaded images, will remain.', - 'delete_my_account_warning' => 'Are you sure you want to delete your account?', + 'delete_account' => 'Poista käyttäjätili', + 'delete_my_account' => 'Poista oma käyttäjätili', + 'delete_my_account_desc' => 'Tämä poistaa käyttäjätilisi kokonaan järjestelmästä. Et voi palauttaa tiliäsi tai peruuttaa tätä toimenpidettä. Luomasi sisältö, kuten luodut sivut ja ladatut kuvat, säilyvät.', + 'delete_my_account_warning' => 'Haluatko varmasti poistaa käyttäjätilisi?', ]; diff --git a/lang/fi/settings.php b/lang/fi/settings.php index c5ca662c3..03517b6e5 100644 --- a/lang/fi/settings.php +++ b/lang/fi/settings.php @@ -7,274 +7,274 @@ return [ // Common Messages - 'settings' => 'Settings', - 'settings_save' => 'Save Settings', - 'system_version' => 'System Version', - 'categories' => 'Categories', + 'settings' => 'Asetukset', + 'settings_save' => 'Tallenna asetukset', + 'system_version' => 'Järjestelmän versio', + 'categories' => 'Kategoriat', // App Settings - 'app_customization' => 'Customization', - 'app_features_security' => 'Features & Security', - 'app_name' => 'Application Name', - 'app_name_desc' => 'This name is shown in the header and in any system-sent emails.', - 'app_name_header' => 'Show name in header', - 'app_public_access' => 'Public Access', - 'app_public_access_desc' => 'Enabling this option will allow visitors, that are not logged-in, to access content in your BookStack instance.', - 'app_public_access_desc_guest' => 'Access for public visitors can be controlled through the "Guest" user.', - 'app_public_access_toggle' => 'Allow public access', - 'app_public_viewing' => 'Allow public viewing?', - 'app_secure_images' => 'Higher Security Image Uploads', - 'app_secure_images_toggle' => 'Enable higher security image uploads', - 'app_secure_images_desc' => 'For performance reasons, all images are public. This option adds a random, hard-to-guess string in front of image urls. Ensure directory indexes are not enabled to prevent easy access.', - 'app_default_editor' => 'Default Page Editor', - 'app_default_editor_desc' => 'Select which editor will be used by default when editing new pages. This can be overridden at a page level where permissions allow.', - 'app_custom_html' => 'Custom HTML Head Content', - 'app_custom_html_desc' => 'Any content added here will be inserted into the bottom of the section of every page. This is handy for overriding styles or adding analytics code.', - 'app_custom_html_disabled_notice' => 'Custom HTML head content is disabled on this settings page to ensure any breaking changes can be reverted.', - 'app_logo' => 'Application Logo', - '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_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' => 'Application Homepage', - 'app_homepage_desc' => 'Select a view to show on the homepage instead of the default view. Page permissions are ignored for selected pages.', - 'app_homepage_select' => 'Select a page', - 'app_footer_links' => 'Footer Links', - 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', - 'app_footer_links_label' => 'Link Label', - 'app_footer_links_url' => 'Link URL', - 'app_footer_links_add' => 'Add Footer Link', - 'app_disable_comments' => 'Disable Comments', - 'app_disable_comments_toggle' => 'Disable comments', - 'app_disable_comments_desc' => 'Disables comments across all pages in the application.
Existing comments are not shown.', + 'app_customization' => 'Mukauttaminen', + 'app_features_security' => 'Ominaisuudet ja turvallisuus', + 'app_name' => 'Sivuston nimi', + 'app_name_desc' => 'Tämä nimi näkyy ylätunnisteessa ja kaikissa järjestelmän lähettämissä sähköpostiviesteissä.', + 'app_name_header' => 'Näytä nimi ylätunnisteessa', + 'app_public_access' => 'Julkinen pääsy', + 'app_public_access_desc' => 'Ottamalla tämä asetus käyttöön vierailijat voivat lukea sisältöjä kirjautumatta sisään.', + 'app_public_access_desc_guest' => 'Vierailijoiden pääsyoikeuksia voidaan hallinnoida "Vierailija"-käyttäjän asetuksista.', + 'app_public_access_toggle' => 'Salli julkinen pääsy', + 'app_public_viewing' => 'Salli julkinen katselu?', + 'app_secure_images' => 'Turvallisemmat kuvien lataukset', + 'app_secure_images_toggle' => 'Ota käyttöön turvallisemmat kuvien lataukset', + 'app_secure_images_desc' => 'Paremman suorituskyvyn takia kaikki kuvat ovat julkisia. Tämä asetus lisää satunnaisen, vaikeasti arvattavan merkkijonon kuvien url-osoitteisiin. Varmista, että hakemistojen indeksit eivät ole palvelimen asetuksissa päällä, jotta niitä ei pääse selaamaan.', + 'app_default_editor' => 'Sivujen oletuseditori', + 'app_default_editor_desc' => 'Valitse editori, jota käytetään oletuksena uusia sivuja muokattaessa. Valinnan voi ohittaa sivutasolla, jos käyttäjän oikeudet sallivat sen.', + 'app_custom_html' => 'HTML-otsakkeen mukautettu sisältö', + 'app_custom_html_desc' => 'Tähän annettu sisältö lisätään jokaisen sivun -osan loppuun. Tällä tavalla voit lisätä kätevästi esimerkiksi omia CSS-tyylejä tai analytiikkapalveluiden vaatimia koodeja.', + 'app_custom_html_disabled_notice' => 'Mukautettu HTML-otsakkeen sisältö ei ole käytössä tällä asetussivulla, jotta kaikki virheitä aiheuttavat muutokset voidaan poistaa.', + 'app_logo' => 'Sivuston logo', + 'app_logo_desc' => 'Kuvaa käytetään esimerkiksi sivuston otsikkopalkissa. Kuvan korkeuden tulisi olla 86 pikseliä. Suuremmat kuvat skaalataan pienemmiksi.', + 'app_icon' => 'Sivuston kuvake', + 'app_icon_desc' => 'Kuvaketta käytetään selaimen välilehdissä ja pikakuvakkeissa. Kuvakkeen tulisi olla 256 pikselin neliönmuotoinen PNG-kuva.', + 'app_homepage' => 'Sivuston kotisivu', + 'app_homepage_desc' => 'Valitse näkymä, joka näytetään etusivuna oletusnäkymän sijaan. Sivun käyttöoikeuksia ei oteta huomioon valituilla sivuilla.', + 'app_homepage_select' => 'Valitse sivu', + 'app_footer_links' => 'Alatunnisteen linkit', + 'app_footer_links_desc' => 'Lisää linkkejä sivuston alatunnisteeseen. Nämä näkyvät useimpien sivujen alareunassa, myös niiden, jotka eivät vaadi kirjautumista. Voit käyttää merkintää "trans::" käyttääksesi järjestelmän määrittelemiä käännöksiä. Esimerkiksi käyttämällä "trans::common.privacy_policy" saadaan käännetty teksti "Tietosuojaseloste" ja "trans::common.terms_of_service" saadaan käännetty teksti "Palvelun käyttöehdot".', + 'app_footer_links_label' => 'Linkin nimi', + 'app_footer_links_url' => 'Linkin URL-osoite', + 'app_footer_links_add' => 'Lisää alatunnisteen linkki', + 'app_disable_comments' => 'Poista kommentit käytöstä', + 'app_disable_comments_toggle' => 'Poista kommentit käytöstä', + 'app_disable_comments_desc' => 'Poistaa kommentit käytöstä kaikilla sivuilla.
Lisättyjä kommentteja ei näytetä.', // 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', - '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' => 'Shelf Color', - 'book_color' => 'Book Color', - 'chapter_color' => 'Chapter Color', - 'page_color' => 'Page Color', - 'page_draft_color' => 'Page Draft Color', + 'color_scheme' => 'Sivuston värimalli', + 'color_scheme_desc' => 'Määritä sivuston käyttöliittymässä käytettävät värit. Värit voidaan määrittää erikseen tummalle ja vaalealle tilalle, jotta ne sopivat parhaiten teemaan ja varmistavat luettavuuden.', + 'ui_colors_desc' => 'Aseta sivuston pääväri ja linkin oletusväri. Ensisijaista väriä käytetään pääasiassa yläpalkissa, painikkeissa ja käyttöliittymän koristeissa. Linkin oletusväriä käytetään tekstipohjaisissa linkeissä ja toiminnoissa sekä kirjoitetussa sisällössä että sivuston käyttöliittymässä.', + 'app_color' => 'Pääväri', + 'link_color' => 'Linkin oletusväri', + 'content_colors_desc' => 'Määritä eri sisältötyyppien värit. Luettavuuden ja saavutettavuuden kannalta on suositeltavaa valita värit, joiden kirkkaus on samankaltainen kuin oletusvärien.', + 'bookshelf_color' => 'Hyllyn väri', + 'book_color' => 'Kirjan väri', + 'chapter_color' => 'Luvun väri', + 'page_color' => 'Sivun väri', + 'page_draft_color' => 'Luonnoksen väri', // Registration Settings - 'reg_settings' => 'Registration', - 'reg_enable' => 'Enable Registration', - 'reg_enable_toggle' => 'Enable registration', - 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', - 'reg_default_role' => 'Default user role after registration', - 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', - 'reg_email_confirmation' => 'Email Confirmation', - 'reg_email_confirmation_toggle' => 'Require email confirmation', - 'reg_confirm_email_desc' => 'If domain restriction is used then email confirmation will be required and this option will be ignored.', - 'reg_confirm_restrict_domain' => 'Domain Restriction', - 'reg_confirm_restrict_domain_desc' => 'Enter a comma separated list of email domains you would like to restrict registration to. Users will be sent an email to confirm their address before being allowed to interact with the application.
Note that users will be able to change their email addresses after successful registration.', - 'reg_confirm_restrict_domain_placeholder' => 'No restriction set', + 'reg_settings' => 'Rekisteröityminen', + 'reg_enable' => 'Salli rekisteröityminen', + 'reg_enable_toggle' => 'Salli rekisteröityminen', + 'reg_enable_desc' => 'Kun rekisteröityminen on käytössä, vierailijat voivat rekisteröityä sivuston käyttäjiksi. Rekisteröitymisen yhteydessä heille annetaan oletuskäyttäjärooli.', + 'reg_default_role' => 'Oletuskäyttäjärooli rekisteröitymisen jälkeen', + 'reg_enable_external_warning' => 'Yllä olevaa vaihtoehtoa ei oteta huomioon, kun ulkoinen LDAP- tai SAML-todennus on käytössä. Käyttäjätilit luodaan automaattisesti, jos tunnistautuminen käytössä olevaan ulkoiseen järjestelmään onnistuu.', + 'reg_email_confirmation' => 'Sähköpostivahvistus', + 'reg_email_confirmation_toggle' => 'Vaadi sähköpostivahvistus', + 'reg_confirm_email_desc' => 'Jos domain-rajoitus on käytössä, sähköpostivahvistus on oletuksena päällä, eikä tätä valintaa oteta huomioon.', + 'reg_confirm_restrict_domain' => 'Domain-rajoitus', + 'reg_confirm_restrict_domain_desc' => 'Kirjoita pilkulla erotettu luettelo sähköpostien domain-nimistä, joihin haluat rajoittaa rekisteröitymisen. Käyttäjille lähetetään sähköpostiviesti osoitteen vahvistamiseksi, ennen kuin he pääsevät käyttämään sivustoa.
Huomaa, että käyttäjät voivat muuttaa sähköpostiosoitteensa onnistuneen rekisteröinnin jälkeen.', + 'reg_confirm_restrict_domain_placeholder' => 'Ei rajoituksia', // Maintenance settings - 'maint' => 'Maintenance', - 'maint_image_cleanup' => 'Cleanup Images', - 'maint_image_cleanup_desc' => 'Scans page & revision content to check which images and drawings are currently in use and which images are redundant. Ensure you create a full database and image backup before running this.', - 'maint_delete_images_only_in_revisions' => 'Also delete images that only exist in old page revisions', - 'maint_image_cleanup_run' => 'Run Cleanup', - 'maint_image_cleanup_warning' => ':count potentially unused images were found. Are you sure you want to delete these images?', - 'maint_image_cleanup_success' => ':count potentially unused images found and deleted!', - 'maint_image_cleanup_nothing_found' => 'No unused images found, Nothing deleted!', - 'maint_send_test_email' => 'Send a Test Email', - 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', - 'maint_send_test_email_run' => 'Send test email', - 'maint_send_test_email_success' => 'Email sent to :address', - 'maint_send_test_email_mail_subject' => 'Test Email', - 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', - 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', - 'maint_recycle_bin_desc' => 'Deleted shelves, books, chapters & pages are sent to the recycle bin so they can be restored or permanently deleted. Older items in the recycle bin may be automatically removed after a while depending on system configuration.', - 'maint_recycle_bin_open' => 'Open Recycle Bin', - 'maint_regen_references' => 'Regenerate References', - 'maint_regen_references_desc' => 'This action will rebuild the cross-item reference index within the database. This is usually handled automatically but this action can be useful to index old content or content added via unofficial methods.', - 'maint_regen_references_success' => 'Reference index has been regenerated!', - 'maint_timeout_command_note' => 'Note: This action can take time to run, which can lead to timeout issues in some web environments. As an alternative, this action be performed using a terminal command.', + 'maint' => 'Huolto', + 'maint_image_cleanup' => 'Siivoa kuvat', + 'maint_image_cleanup_desc' => 'Tarkistaa kuvista ja luonnoksista mitkä kuvat ja piirustukset ovat tällä hetkellä käytössä ja mitkä ovat tarpeettomia. Varmista, että olet varmuuskopioinut tietokannan ja kuvat ennen tämän toiminnon suorittamista.', + 'maint_delete_images_only_in_revisions' => 'Poista myös kuvat, jotka ovat olemassa vain vanhoissa sivujen versioissa', + 'maint_image_cleanup_run' => 'Suorita siivous', + 'maint_image_cleanup_warning' => ':count mahdollisesti käyttämätöntä kuvaa löytyi. Haluatko varmasti poistaa nämä kuvat?', + 'maint_image_cleanup_success' => ':count mahdollisesti käyttämätöntä kuvaa löydetty ja poistettu!', + 'maint_image_cleanup_nothing_found' => 'Käyttämättömiä kuvia ei löytynyt, mitään ei poistettu!', + 'maint_send_test_email' => 'Lähetä testisähköposti', + 'maint_send_test_email_desc' => 'Toiminto lähettää testisähköpostin profiilissasi määritettyyn sähköpostiosoitteeseen.', + 'maint_send_test_email_run' => 'Lähetä testisähköposti', + 'maint_send_test_email_success' => 'Sähköposti lähetetty osoitteeseen :address', + 'maint_send_test_email_mail_subject' => 'Testisähköpostiviesti', + 'maint_send_test_email_mail_greeting' => 'Sähköpostin lähetys näyttää toimivan!', + 'maint_send_test_email_mail_text' => 'Onnittelut! Koska sait tämän sähköposti-ilmoituksen, sähköpostiasetuksesi näyttävät olevan oikein määritetty.', + 'maint_recycle_bin_desc' => 'Poistetut hyllyt, kirjat, luvut ja sivut siirretään roskakoriin, josta ne voidaan palauttaa tai poistaa pysyvästi. Vanhemmat kohteet roskakorissa saatetaan poistaa automaattisesti jonkin ajan kuluttua järjestelmän asetuksista riippuen.', + 'maint_recycle_bin_open' => 'Avaa roskakori', + 'maint_regen_references' => 'Luo viitteet uudelleen', + 'maint_regen_references_desc' => 'Tämä toiminto rakentaa sisältöjen väliset viittaukset uudelleen. Tämä tapahtuu yleensä automaattisesti, mutta tämä toiminto voi olla hyödyllinen indeksoitaessa vanhaa sisältöä tai vaihtoehtoisin menetelmin lisättyä sisältöä.', + 'maint_regen_references_success' => 'Viiteindeksi on luotu uudelleen!', + 'maint_timeout_command_note' => 'Huomautus: tämän toiminnon suorittaminen voi kestää jonkin aikaa, mikä voi johtaa aikakatkaisusta johtuviin ongelmiin joissakin verkkoympäristöissä. Vaihtoehtoisesti tämä toiminto voidaan suorittaa komentoriviltä.', // Recycle Bin - 'recycle_bin' => 'Recycle Bin', - 'recycle_bin_desc' => 'Here you can restore items that have been deleted or choose to permanently remove them from the system. This list is unfiltered unlike similar activity lists in the system where permission filters are applied.', - 'recycle_bin_deleted_item' => 'Deleted Item', - 'recycle_bin_deleted_parent' => 'Parent', - 'recycle_bin_deleted_by' => 'Deleted By', - 'recycle_bin_deleted_at' => 'Deletion Time', - 'recycle_bin_permanently_delete' => 'Permanently Delete', - 'recycle_bin_restore' => 'Restore', - 'recycle_bin_contents_empty' => 'The recycle bin is currently empty', - 'recycle_bin_empty' => 'Empty Recycle Bin', - 'recycle_bin_empty_confirm' => 'This will permanently destroy all items in the recycle bin including content contained within each item. Are you sure you want to empty the recycle bin?', - 'recycle_bin_destroy_confirm' => 'This action will permanently delete this item, along with any child elements listed below, from the system and you will not be able to restore this content. Are you sure you want to permanently delete this item?', - 'recycle_bin_destroy_list' => 'Items to be Destroyed', - 'recycle_bin_restore_list' => 'Items to be Restored', - 'recycle_bin_restore_confirm' => 'This action will restore the deleted item, including any child elements, to their original location. If the original location has since been deleted, and is now in the recycle bin, the parent item will also need to be restored.', - 'recycle_bin_restore_deleted_parent' => 'The parent of this item has also been deleted. These will remain deleted until that parent is also restored.', - 'recycle_bin_restore_parent' => 'Restore Parent', - 'recycle_bin_destroy_notification' => 'Deleted :count total items from the recycle bin.', - 'recycle_bin_restore_notification' => 'Restored :count total items from the recycle bin.', + 'recycle_bin' => 'Roskakori', + 'recycle_bin_desc' => 'Tässä voit palauttaa poistetut kohteet tai poistaa ne pysyvästi järjestelmästä. Tämä luettelo on suodattamaton, toisin kuin järjestelmän vastaavat toimintoluettelot, joihin sovelletaan käyttöoikeussuodattimia.', + 'recycle_bin_deleted_item' => 'Poistettu kohde', + 'recycle_bin_deleted_parent' => 'Vanhempi', + 'recycle_bin_deleted_by' => 'Poistanut', + 'recycle_bin_deleted_at' => 'Poistoaika', + 'recycle_bin_permanently_delete' => 'Poista pysyvästi', + 'recycle_bin_restore' => 'Palauta', + 'recycle_bin_contents_empty' => 'Roskakori on tällä hetkellä tyhjä', + 'recycle_bin_empty' => 'Tyhjennä roskakori', + 'recycle_bin_empty_confirm' => 'Tämä tuhoaa pysyvästi kaikki kohteet roskakorissa, mukaan lukien kunkin kohteen sisältämän sisällön. Haluatko varmasti tyhjentää roskakorin?', + 'recycle_bin_destroy_confirm' => 'Tämä toiminto poistaa tämän kohteen ja kaikki alla luetellut sisältyvät kohteet pysyvästi järjestelmästä, etkä voi enää palauttaa tätä sisältöä. Haluatko varmasti poistaa tämän kohteen pysyvästi?', + 'recycle_bin_destroy_list' => 'Poistettavat kohteet', + 'recycle_bin_restore_list' => 'Palautettavat kohteet', + 'recycle_bin_restore_confirm' => 'Tämä toiminto palauttaa poistetun kohteen, mukaan lukien kaikki siihen sisältyvät kohteet, alkuperäiseen sijaintiinsa. Jos alkuperäinen sijainti on sittemmin poistettu ja on nyt roskakorissa, myös sitä koskeva kohde on palautettava.', + 'recycle_bin_restore_deleted_parent' => 'Kohde, johon tämä kohde sisältyy on myös poistettu. Kohteet pysyvät poistettuina, kunnes kyseinen vanhempi on palautettu.', + 'recycle_bin_restore_parent' => 'Palauta vanhempi', + 'recycle_bin_destroy_notification' => 'Poistettu yhteensä :count kohdetta roskakorista.', + 'recycle_bin_restore_notification' => 'Palautettu yhteensä :count kohdetta roskakorista.', // Audit Log - 'audit' => 'Audit Log', - 'audit_desc' => 'This audit log displays a list of activities tracked in the system. This list is unfiltered unlike similar activity lists in the system where permission filters are applied.', - 'audit_event_filter' => 'Event Filter', - 'audit_event_filter_no_filter' => 'No Filter', - 'audit_deleted_item' => 'Deleted Item', - 'audit_deleted_item_name' => 'Name: :name', - 'audit_table_user' => 'User', - 'audit_table_event' => 'Event', - 'audit_table_related' => 'Related Item or Detail', - 'audit_table_ip' => 'IP Address', - 'audit_table_date' => 'Activity Date', - 'audit_date_from' => 'Date Range From', - 'audit_date_to' => 'Date Range To', + 'audit' => 'Tarkastusloki', + 'audit_desc' => 'Tämä tarkastusloki näyttää listauksen järjestelmässä suoritetuista toiminnoista. Lista on suodattamaton toisin kuin vastaavat järjestelmässä olevat listat, joihin sovelletaan käyttöoikeussuodattimia.', + 'audit_event_filter' => 'Tapahtumasuodatin', + 'audit_event_filter_no_filter' => 'Ei suodatinta', + 'audit_deleted_item' => 'Poistettu kohde', + 'audit_deleted_item_name' => 'Nimi: :name', + 'audit_table_user' => 'Käyttäjä', + 'audit_table_event' => 'Tapahtuma', + 'audit_table_related' => 'Liittyvä kohde tai tieto', + 'audit_table_ip' => 'IP-osoite', + 'audit_table_date' => 'Toiminnan päiväys', + 'audit_date_from' => 'Päiväys alkaen', + 'audit_date_to' => 'Päiväys saakka', // Role Settings - 'roles' => 'Roles', - 'role_user_roles' => '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_x_users_assigned' => ':count user assigned|:count users assigned', - 'roles_x_permissions_provided' => ':count permission|:count permissions', - 'roles_assigned_users' => 'Assigned Users', - 'roles_permissions_provided' => 'Provided Permissions', - 'role_create' => 'Create New Role', - 'role_delete' => 'Delete Role', - 'role_delete_confirm' => 'This will delete the role with the name \':roleName\'.', - 'role_delete_users_assigned' => 'This role has :userCount users assigned to it. If you would like to migrate the users from this role select a new role below.', - 'role_delete_no_migration' => "Don't migrate users", - 'role_delete_sure' => 'Are you sure you want to delete this role?', - 'role_edit' => 'Edit Role', - 'role_details' => 'Role Details', - 'role_name' => 'Role Name', - 'role_desc' => 'Short Description of Role', - 'role_mfa_enforced' => 'Requires Multi-Factor Authentication', - 'role_external_auth_id' => 'External Authentication IDs', - 'role_system' => 'System Permissions', - 'role_manage_users' => 'Manage users', - 'role_manage_roles' => 'Manage roles & role permissions', - 'role_manage_entity_permissions' => 'Manage all book, chapter & page permissions', - 'role_manage_own_entity_permissions' => 'Manage permissions on own book, chapter & pages', - 'role_manage_page_templates' => 'Manage page templates', - 'role_access_api' => 'Access system API', - 'role_manage_settings' => 'Manage app settings', - 'role_export_content' => 'Export content', - 'role_editor_change' => 'Change page editor', - 'role_notifications' => 'Receive & manage notifications', - 'role_asset' => 'Asset Permissions', - 'roles_system_warning' => 'Be aware that access to any of the above three permissions can allow a user to alter their own privileges or the privileges of others in the system. Only assign roles with these permissions to trusted users.', - 'role_asset_desc' => 'These permissions control default access to the assets within the system. Permissions on Books, Chapters and Pages will override these permissions.', - 'role_asset_admins' => 'Admins are automatically given access to all content but these options may show or hide UI options.', - 'role_asset_image_view_note' => 'This relates to visibility within the image manager. Actual access of uploaded image files will be dependant upon system image storage option.', - 'role_all' => 'All', - 'role_own' => 'Own', - 'role_controlled_by_asset' => 'Controlled by the asset they are uploaded to', - 'role_save' => 'Save Role', - 'role_users' => 'Users in this role', - 'role_users_none' => 'No users are currently assigned to this role', + 'roles' => 'Roolit', + 'role_user_roles' => 'Käyttäjäroolit', + 'roles_index_desc' => 'Rooleja käytetään käyttäjien ryhmittelyyn ja järjestelmän käyttöoikeuksien antamiseen. Kun käyttäjä on useamman roolin jäsen, hän saa kaikkien omien rooliensa kyvyt.', + 'roles_x_users_assigned' => ':count käyttäjä osoitettu|:count käyttäjää osoitettu', + 'roles_x_permissions_provided' => ':count käyttöoikeus|:count käyttöoikeutta', + 'roles_assigned_users' => 'Osoitetut käyttäjät', + 'roles_permissions_provided' => 'Annetut käyttöoikeudet', + 'role_create' => 'Luo uusi rooli', + 'role_delete' => 'Poista rooli', + 'role_delete_confirm' => 'Tämä poistaa roolin \':roleName\'.', + 'role_delete_users_assigned' => 'Tähän rooliin on osoitettu :userCount käyttäjää. Jos haluat siirtää käyttäjät tästä roolista, valitse uusi rooli alta.', + 'role_delete_no_migration' => "Älä siirrä käyttäjiä", + 'role_delete_sure' => 'Oletko varma, että haluat poistaa tämän roolin?', + 'role_edit' => 'Muokkaa roolia', + 'role_details' => 'Roolin tiedot', + 'role_name' => 'Roolin nimi', + 'role_desc' => 'Lyhyt kuvaus roolista', + 'role_mfa_enforced' => 'Vaatii monivaiheisen tunnistautumisen', + 'role_external_auth_id' => 'Ulkoisen tunnistautumisen tunnukset', + 'role_system' => 'Järjestelmän käyttöoikeudet', + 'role_manage_users' => 'Hallinnoi käyttäjiä', + 'role_manage_roles' => 'Hallinnoi rooleja ja roolien käyttöoikeuksia', + 'role_manage_entity_permissions' => 'Hallinnoi kaikkien kirjojen, lukujen ja sivujen käyttöoikeuksia', + 'role_manage_own_entity_permissions' => 'Hallinnoi omien kirjojen, lukujen ja sivujen käyttöoikeuksia', + 'role_manage_page_templates' => 'Hallinnoi mallipohjia', + 'role_access_api' => 'Pääsy järjestelmän ohjelmointirajapintaan', + 'role_manage_settings' => 'Hallinnoi sivuston asetuksia', + 'role_export_content' => 'Vie sisältöjä', + 'role_editor_change' => 'Vaihda sivun editoria', + 'role_notifications' => 'Vastaanota ja hallinnoi ilmoituksia', + 'role_asset' => 'Sisältöjen oikeudet', + 'roles_system_warning' => 'Huomaa, että minkä tahansa edellä mainituista kolmesta käyttöoikeudesta voi antaa käyttäjälle mahdollisuuden muuttaa omia tai muiden järjestelmän käyttäjien oikeuksia. Anna näitä oikeuksia sisältävät roolit vain luotetuille käyttäjille.', + 'role_asset_desc' => 'Näillä asetuksilla hallitaan oletuksena annettavia käyttöoikeuksia järjestelmässä oleviin sisältöihin. Yksittäisten kirjojen, lukujen ja sivujen käyttöoikeudet kumoavat nämä käyttöoikeudet.', + 'role_asset_admins' => 'Ylläpitäjät saavat automaattisesti pääsyn kaikkeen sisältöön, mutta nämä vaihtoehdot voivat näyttää tai piilottaa käyttöliittymävalintoja.', + 'role_asset_image_view_note' => 'Tämä tarkoittaa näkyvyyttä kuvien hallinnassa. Pääsy ladattuihin kuvatiedostoihin riippuu asetetusta kuvien tallennusvaihtoehdosta.', + 'role_all' => 'Kaikki', + 'role_own' => 'Omat', + 'role_controlled_by_asset' => 'Määräytyy sen sisällön mukaan, johon ne on ladattu', + 'role_save' => 'Tallenna rooli', + 'role_users' => 'Käyttäjät tässä roolissa', + 'role_users_none' => 'Yhtään käyttäjää ei ole osoitettuna tähän rooliin', // Users - 'users' => 'Users', - 'users_index_desc' => 'Create & manage individual user accounts within the system. User accounts are used for login and attribution of content & activity. Access permissions are primarily role-based but user content ownership, among other factors, may also affect permissions & access.', - 'user_profile' => 'User Profile', - 'users_add_new' => 'Add New User', - 'users_search' => 'Search Users', - 'users_latest_activity' => 'Latest Activity', - 'users_details' => 'User Details', - 'users_details_desc' => 'Set a display name and an email address for this user. The email address will be used for logging into the application.', - 'users_details_desc_no_email' => 'Set a display name for this user so others can recognise them.', - 'users_role' => 'User Roles', - 'users_role_desc' => 'Select which roles this user will be assigned to. If a user is assigned to multiple roles the permissions from those roles will stack and they will receive all abilities of the assigned roles.', - 'users_password' => 'User Password', - 'users_password_desc' => 'Set a password used to log-in to the application. This must be at least 8 characters long.', - 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', - 'users_send_invite_option' => 'Send user invite email', - 'users_external_auth_id' => 'External Authentication ID', - 'users_external_auth_id_desc' => 'When an external authentication system is in use (such as SAML2, OIDC or LDAP) this is the ID which links this BookStack user to the authentication system account. You can ignore this field if using the default email-based authentication.', - 'users_password_warning' => 'Only fill the below if you would like to change the password for this user.', - 'users_system_public' => 'This user represents any guest users that visit your instance. It cannot be used to log in but is assigned automatically.', - 'users_delete' => 'Delete User', - 'users_delete_named' => 'Delete user :userName', - 'users_delete_warning' => 'This will fully delete this user with the name \':userName\' from the system.', - 'users_delete_confirm' => 'Are you sure you want to delete this user?', - 'users_migrate_ownership' => 'Migrate Ownership', - 'users_migrate_ownership_desc' => 'Select a user here if you want another user to become the owner of all items currently owned by this user.', - 'users_none_selected' => 'No user selected', - 'users_edit' => 'Edit User', - 'users_edit_profile' => 'Edit Profile', - 'users_avatar' => 'User Avatar', - 'users_avatar_desc' => 'Select an image to represent this user. This should be approx 256px square.', - 'users_preferred_language' => 'Preferred Language', - 'users_preferred_language_desc' => 'This option will change the language used for the user-interface of the application. This will not affect any user-created content.', - 'users_social_accounts' => 'Social Accounts', - 'users_social_accounts_desc' => 'View the status of the connected social accounts for this user. Social accounts can be used in addition to the primary authentication system for system access.', - 'users_social_accounts_info' => 'Here you can connect your other accounts for quicker and easier login. Disconnecting an account here does not revoke previously authorized access. Revoke access from your profile settings on the connected social account.', - 'users_social_connect' => 'Connect Account', - 'users_social_disconnect' => 'Disconnect Account', - 'users_social_status_connected' => 'Connected', - 'users_social_status_disconnected' => 'Disconnected', - 'users_social_connected' => ':socialAccount account was successfully attached to your profile.', - 'users_social_disconnected' => ':socialAccount account was successfully disconnected from your profile.', - 'users_api_tokens' => 'API Tokens', - 'users_api_tokens_desc' => 'Create and manage the access tokens used to authenticate with the BookStack REST API. Permissions for the API are managed via the user that the token belongs to.', - 'users_api_tokens_none' => 'No API tokens have been created for this user', - 'users_api_tokens_create' => 'Create Token', - 'users_api_tokens_expires' => 'Expires', - 'users_api_tokens_docs' => 'API Documentation', - 'users_mfa' => 'Multi-Factor Authentication', - 'users_mfa_desc' => 'Setup multi-factor authentication as an extra layer of security for your user account.', - 'users_mfa_x_methods' => ':count method configured|:count methods configured', - 'users_mfa_configure' => 'Configure Methods', + 'users' => 'Käyttäjät', + 'users_index_desc' => 'Luo ja hallinnoi yksittäisiä käyttäjätilejä järjestelmässä. Käyttäjätilejä käytetään kirjautumiseen sekä käyttöoikeuksien hallinnointiin. Käyttöoikeudet perustuvat ensisijaisesti rooleihin, mutta käyttöoikeuksiin voi vaikuttaa myös se, onko käyttäjä tietyn sisällön omistaja.', + 'user_profile' => 'Käyttäjäprofiili', + 'users_add_new' => 'Lisää uusi käyttäjä', + 'users_search' => 'Hae käyttäjiä', + 'users_latest_activity' => 'Viimeisin toiminta', + 'users_details' => 'Käyttäjän tiedot', + 'users_details_desc' => 'Aseta tälle käyttäjälle näyttönimi ja sähköpostiosoite. Sähköpostiosoitetta käytetään sovellukseen kirjautumiseen.', + 'users_details_desc_no_email' => 'Aseta tälle käyttäjälle näyttönimi, jonka perusteella käyttäjä voidaan tunnistaa.', + 'users_role' => 'Käyttäjäroolit', + 'users_role_desc' => 'Valitse, mitä rooleja tälle käyttäjälle annetaan. Jos käyttäjälle on määritetty useita rooleja, näiden roolien käyttöoikeudet yhdistetään ja hän saa kaikki osoitettujen roolien kyvyt.', + 'users_password' => 'Käyttäjän salasana', + 'users_password_desc' => 'Aseta salasana, jota käytetään sovellukseen kirjautumiseen. Sen on oltava vähintään 8 merkkiä pitkä.', + 'users_send_invite_text' => 'Voit lähettää käyttäjälle sähköpostilla kutsun ja antaa käyttäjän asettaa oman salasanansa. Vaihtoehtoisesti voit asettaa salasanan itse.', + 'users_send_invite_option' => 'Lähetä kutsu', + 'users_external_auth_id' => 'Ulkoisen tunnistautumisen tunnus', + 'users_external_auth_id_desc' => 'Tätä tunnusta käytetään BookStack-käyttäjätilin ja ulkoisen tunnistautumisen (kuten SAML2, OIDC tai LDAP) kautta käytettävän tilin yhdistämiseen. Voit jättää tämän kentän huomiotta, jos käytät oletuksena sähköpostipohjaista todennusta.', + 'users_password_warning' => 'Täytä alla oleva kenttä vain, jos haluat vaihtaa tämän käyttäjän salasanan.', + 'users_system_public' => 'Tämä käyttäjä tarkoittaa kaikkia vieraita, jotka vierailevat sivustollasi. Sitä ei voi käyttää kirjautumiseen ja se annetaan automaattisesti.', + 'users_delete' => 'Poista käyttäjä', + 'users_delete_named' => 'Poista käyttäjä :userName', + 'users_delete_warning' => 'Tämä poistaa käyttäjän \':userName\' kokonaan järjestelmästä.', + 'users_delete_confirm' => 'Haluatko varmasti poistaa tämän käyttäjän?', + 'users_migrate_ownership' => 'Omistusoikeuden siirto', + 'users_migrate_ownership_desc' => 'Valitse käyttäjä, jolle haluat siirtää kaikki poistettavan käyttäjän omistamat sisällöt.', + 'users_none_selected' => 'Yhtään käyttäjää ei ole valittu', + 'users_edit' => 'Muokkaa käyttäjää', + 'users_edit_profile' => 'Muokkaa profiilia', + 'users_avatar' => 'Käyttäjän kuva', + 'users_avatar_desc' => 'Valitse käyttäjän kuva. Kuvan tulisi olla noin 256 pikselin kokoinen neliö.', + 'users_preferred_language' => 'Ensisijainen kieli', + 'users_preferred_language_desc' => 'Tämä valinta vaihtaa sovelluksen käyttöliittymässä käytettävän kielen. Tämä ei vaikuta käyttäjän luomaan sisältöön.', + 'users_social_accounts' => 'Sosiaalisen median tilit', + 'users_social_accounts_desc' => 'Näytä tämän käyttäjän yhdistettyjen sosiaalisen median tilien tila. Sosiaalisen median tilejä voidaan käyttää ensisijaisen tunnistautumistavan ohella.', + 'users_social_accounts_info' => 'Täällä voit yhdistää muut tilisi ja nopeuttaa kirjautumista. Yhteyden katkaisu tiliin ei peruuta palvelulle annettua käyttöoikeutta. Käyttöoikeus tulee peruuttaa yhdistetyn sosiaalisen median tilin asetuksista.', + 'users_social_connect' => 'Yhdistä tili', + 'users_social_disconnect' => 'Katkaise yhteys tiliin', + 'users_social_status_connected' => 'Yhdistetty', + 'users_social_status_disconnected' => 'Yhteys katkaistu', + 'users_social_connected' => ':socialAccount-tili liitettiin onnistuneesti profiiliisi.', + 'users_social_disconnected' => ':Yhteys socialAccount-tiliin katkaistiin onnistuneesti profiilistasi.', + 'users_api_tokens' => 'API-tunnisteet', + 'users_api_tokens_desc' => 'Luo ja hallinnoi tunnisteita, joita käytetään BookStack REST-rajapinnan todennukseen. Rajapinnan käyttöoikeuksia hallinnoidaan sen käyttäjän asetuksista, jolle tunniste kuuluu.', + 'users_api_tokens_none' => 'Tälle käyttäjälle ei ole luotu API-tunnisteita', + 'users_api_tokens_create' => 'Luo tunniste', + 'users_api_tokens_expires' => 'Vanhenee', + 'users_api_tokens_docs' => 'API-dokumentaatio', + 'users_mfa' => 'Monivaiheinen tunnistautuminen', + 'users_mfa_desc' => 'Paranna käyttäjätilisi turvallisuutta ja ota käyttöön monivaiheinen tunnistautuminen.', + 'users_mfa_x_methods' => ':count menetelmä määritetty|:count menetelmää määritetty', + 'users_mfa_configure' => 'Määritä menetelmiä', // API Tokens - 'user_api_token_create' => 'Create API Token', - 'user_api_token_name' => 'Name', - 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', - 'user_api_token_expiry' => 'Expiry Date', - 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', - 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', - 'user_api_token' => 'API Token', - 'user_api_token_id' => 'Token ID', - 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', - 'user_api_token_secret' => 'Token Secret', - 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', - 'user_api_token_created' => 'Token created :timeAgo', - 'user_api_token_updated' => 'Token updated :timeAgo', - 'user_api_token_delete' => 'Delete Token', - 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', - 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_create' => 'Luo uusi API-tunniste', + 'user_api_token_name' => 'Nimi', + 'user_api_token_name_desc' => 'Anna tunnisteelle helppolukuinen nimi, josta muistaa sen käyttötarkoituksen.', + 'user_api_token_expiry' => 'Viimeinen voimassaolopäivä', + 'user_api_token_expiry_desc' => 'Aseta päiväys, jolloin tämä tunniste vanhenee. Tämän päiväyksen jälkeen tätä tunnistetta käyttäen tehdyt pyynnöt eivät enää toimi. Tämän kentän jättäminen tyhjäksi asettaa voimassaolon päättymisen 100 vuoden päähän tulevaisuuteen.', + 'user_api_token_create_secret_message' => 'Välittömästi tämän tunnisteen luomisen jälkeen luodaan ja näytetään "Tunnisteen ID" ja "Tunnisteen salaisuus". Salaisuus näytetään vain kerran, joten kopioi arvo jonnekin turvalliseen paikkaan ennen kuin jatkat.', + 'user_api_token' => 'API-tunniste', + 'user_api_token_id' => 'Tunnisteen ID', + 'user_api_token_id_desc' => 'Tämä on järjestelmän luoma tunniste, jota ei voi muokata ja jota on käytettävä API-pyynnöissä.', + 'user_api_token_secret' => 'Tunnisteen salaisuus', + 'user_api_token_secret_desc' => 'Tämä on järjestelmän tälle tunnisteelle luoma salaisuus, jota on käytettävä API-pyynnöissä. Tämä näytetään vain kerran, joten kopioi tämä arvo jonnekin turvalliseen paikkaan.', + 'user_api_token_created' => 'Tunniste luotu :timeAgo', + 'user_api_token_updated' => 'Tunniste päivitetty :timeAgo', + 'user_api_token_delete' => 'Poista tunniste', + 'user_api_token_delete_warning' => 'Tämä poistaa API-tunnisteen \':tokenName\' kokonaan järjestelmästä.', + 'user_api_token_delete_confirm' => 'Oletko varma, että haluat poistaa tämän API-tunnisteen?', // Webhooks - 'webhooks' => 'Webhooks', - 'webhooks_index_desc' => 'Webhooks are a way to send data to external URLs when certain actions and events occur within the system which allows event-based integration with external platforms such as messaging or notification systems.', - 'webhooks_x_trigger_events' => ':count trigger event|:count trigger events', - 'webhooks_create' => 'Create New Webhook', - 'webhooks_none_created' => 'No webhooks have yet been created.', - 'webhooks_edit' => 'Edit Webhook', - 'webhooks_save' => 'Save Webhook', - 'webhooks_details' => 'Webhook Details', - 'webhooks_details_desc' => 'Provide a user friendly name and a POST endpoint as a location for the webhook data to be sent to.', - 'webhooks_events' => 'Webhook Events', - 'webhooks_events_desc' => 'Select all the events that should trigger this webhook to be called.', - 'webhooks_events_warning' => 'Keep in mind that these events will be triggered for all selected events, even if custom permissions are applied. Ensure that use of this webhook won\'t expose confidential content.', - 'webhooks_events_all' => 'All system events', - 'webhooks_name' => 'Webhook Name', - 'webhooks_timeout' => 'Webhook Request Timeout (Seconds)', - 'webhooks_endpoint' => 'Webhook Endpoint', - 'webhooks_active' => 'Webhook Active', - 'webhook_events_table_header' => 'Events', - 'webhooks_delete' => 'Delete Webhook', - 'webhooks_delete_warning' => 'This will fully delete this webhook, with the name \':webhookName\', from the system.', - 'webhooks_delete_confirm' => 'Are you sure you want to delete this webhook?', - 'webhooks_format_example' => 'Webhook Format Example', - 'webhooks_format_example_desc' => 'Webhook data is sent as a POST request to the configured endpoint as JSON following the format below. The "related_item" and "url" properties are optional and will depend on the type of event triggered.', - 'webhooks_status' => 'Webhook Status', - 'webhooks_last_called' => 'Last Called:', - 'webhooks_last_errored' => 'Last Errored:', - 'webhooks_last_error_message' => 'Last Error Message:', + 'webhooks' => 'Toimintokutsut', + 'webhooks_index_desc' => 'Toimintokutsut ovat tapa lähettää tietoja ulkoisiin URL-osoitteisiin, kun järjestelmässä tapahtuu tiettyjä toimintoja ja tapahtumia. Tämä mahdollistaa näihin tapahtumiin perustuvan integroinnin muihin alustoihin, esimerkiksi viesti- tai ilmoitusjärjestelmiin.', + 'webhooks_x_trigger_events' => ':count käynnistävä tapahtuma|:count käynnistävää tapahtumaa', + 'webhooks_create' => 'Luo uusi toimintokutsu', + 'webhooks_none_created' => 'Toimintokutsuja ei ole luotu.', + 'webhooks_edit' => 'Muokkaa toimintokutsua', + 'webhooks_save' => 'Tallenna toimintokutsu', + 'webhooks_details' => 'Toimintokutsun tiedot', + 'webhooks_details_desc' => 'Anna selkeä nimi ja POST-päätepisteen sijainti, johon toimintokutsun tiedot lähetetään.', + 'webhooks_events' => 'Toimintokutsun tapahtumat', + 'webhooks_events_desc' => 'Valitse kaikki tapahtumat, jotka käynnistävät tämän toimintokutsun.', + 'webhooks_events_warning' => 'Huomaa, että toimintokutsu käynnistetään kaikissa valituissa tapahtumissa, vaikka niihin liittyisi muokautettuja käyttöoikeuksia. Varmista, että tämän toimintokutsun käyttö ei paljasta luottamuksellista sisältöä.', + 'webhooks_events_all' => 'Kaikki järjestelmän tapahtumat', + 'webhooks_name' => 'Toimintokutsun nimi', + 'webhooks_timeout' => 'Toimintokutsun aikakatkaisu (sekuntia)', + 'webhooks_endpoint' => 'Toimintokutsun päätepiste', + 'webhooks_active' => 'Toimintokutsu aktiivinen', + 'webhook_events_table_header' => 'Tapahtumat', + 'webhooks_delete' => 'Poista toimintokutsu', + 'webhooks_delete_warning' => 'Tämä poistaa toimintokutsun \':webhookName\' kokonaan järjestelmästä.', + 'webhooks_delete_confirm' => 'Oletko varma, että haluat poistaa tämän toimintokutsun?', + 'webhooks_format_example' => 'Esimerkki toimintokutsusta', + 'webhooks_format_example_desc' => 'Toimintokutsun tiedot lähetetään JSON-muodossa POST-pyyntönä määritettyyn päätepisteeseen alla näkyvän mallin mukaisesti. Ominaisuudet "related_item" ja "url" ovat valinnaisia ja riippuvat käynnistetyn tapahtuman tyypistä.', + 'webhooks_status' => 'Toimintokutsun tila', + 'webhooks_last_called' => 'Viimeksi kutsuttu:', + 'webhooks_last_errored' => 'Viimeisin virhe:', + 'webhooks_last_error_message' => 'Viimeisin virheviesti:', //! If editing translations files directly please ignore this in all @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/fi/validation.php b/lang/fi/validation.php index 2a676c7c4..35c5f1924 100644 --- a/lang/fi/validation.php +++ b/lang/fi/validation.php @@ -8,107 +8,107 @@ return [ // Standard laravel validation lines - 'accepted' => 'The :attribute must be accepted.', - 'active_url' => 'The :attribute is not a valid URL.', - 'after' => 'The :attribute must be a date after :date.', - 'alpha' => 'The :attribute may only contain letters.', - 'alpha_dash' => 'The :attribute may only contain letters, numbers, dashes and underscores.', - 'alpha_num' => 'The :attribute may only contain letters and numbers.', - 'array' => 'The :attribute must be an array.', - 'backup_codes' => 'The provided code is not valid or has already been used.', - 'before' => 'The :attribute must be a date before :date.', + 'accepted' => ':attribute tulee hyväksyä.', + 'active_url' => ':attribute ei ole kelvollinen URL.', + 'after' => ':attribute tulee olla päiväyksen :date jälkeinen päiväys.', + 'alpha' => ':attribute voi sisältää vain kirjaimia.', + 'alpha_dash' => ':attribute voi sisältää vain kirjaimia, numeroita, yhdys- ja alaviivoja.', + 'alpha_num' => ':attribute voi sisältää vain kirjaimia ja numeroita.', + 'array' => ':attribute tulee olla taulukkomuuttuja.', + 'backup_codes' => 'Annettu koodi ei ole kelvollinen tai se on jo käytetty.', + 'before' => ':attribute päiväyksen tulee olla ennen :date.', 'between' => [ - 'numeric' => 'The :attribute must be between :min and :max.', - 'file' => 'The :attribute must be between :min and :max kilobytes.', - 'string' => 'The :attribute must be between :min and :max characters.', - 'array' => 'The :attribute must have between :min and :max items.', + 'numeric' => ':attribute tulee olla välillä :min ja :max.', + 'file' => ':attribute tulee olla :min - :max kilotavua.', + 'string' => ':attribute tulee olla :min - :max merkkiä pitkä.', + 'array' => ':attribute tulee sisältää :min - :max kohdetta.', ], - 'boolean' => 'The :attribute field must be true or false.', - 'confirmed' => 'The :attribute confirmation does not match.', - 'date' => 'The :attribute is not a valid date.', - 'date_format' => 'The :attribute does not match the format :format.', - 'different' => 'The :attribute and :other must be different.', - 'digits' => 'The :attribute must be :digits digits.', - 'digits_between' => 'The :attribute must be between :min and :max digits.', - 'email' => 'The :attribute must be a valid email address.', - 'ends_with' => 'The :attribute must end with one of the following: :values', - 'file' => 'The :attribute must be provided as a valid file.', - 'filled' => 'The :attribute field is required.', + 'boolean' => ':attribute tulee olla tosi tai epätosi.', + 'confirmed' => ':attribute vahvistus ei täsmää.', + 'date' => ':attribute ei ole kelvollinen päiväys.', + 'date_format' => ':attribute ei täsmää muodon :format kanssa.', + 'different' => ':attribute ja :other tulee erota toisistaan.', + 'digits' => ':attribute tulee olla :digits numeroa pitkä.', + 'digits_between' => ':attribute tulee olla :min - :max numeroa.', + 'email' => ':attribute tulee olla kelvollinen sähköpostiosoite.', + 'ends_with' => ':attribute arvon tulee päättyä johonkin seuraavista: :values', + 'file' => ':attribute tulee olla kelvollinen tiedosto.', + 'filled' => 'Kenttä :attribute vaaditaan.', 'gt' => [ - 'numeric' => 'The :attribute must be greater than :value.', - 'file' => 'The :attribute must be greater than :value kilobytes.', - 'string' => 'The :attribute must be greater than :value characters.', - 'array' => 'The :attribute must have more than :value items.', + 'numeric' => ':attribute tulee olla suurempi kuin :value.', + 'file' => ':attribute tulee olla suurempi kuin :value kilotavua.', + 'string' => ':attribute tulee olla suurempi kuin :value merkkiä.', + 'array' => ':attribute tulee sisältää vähintään :value kohdetta.', ], 'gte' => [ - 'numeric' => 'The :attribute must be greater than or equal :value.', - 'file' => 'The :attribute must be greater than or equal :value kilobytes.', - 'string' => 'The :attribute must be greater than or equal :value characters.', - 'array' => 'The :attribute must have :value items or more.', + 'numeric' => ':attribute on oltava suurempi tai samansuuruinen kuin :value.', + 'file' => ':attribute on oltava suurempi tai samansuuruinen kuin :value kilotavua.', + 'string' => ':attribute on oltava suurempi tai samansuuruinen kuin :value merkkiä.', + 'array' => ':attribute tulee sisältää vähintään :value kohdetta tai enemmän.', ], - 'exists' => 'The selected :attribute is invalid.', - 'image' => 'The :attribute must be an image.', - 'image_extension' => 'The :attribute must have a valid & supported image extension.', - 'in' => 'The selected :attribute is invalid.', - 'integer' => 'The :attribute must be an integer.', - 'ip' => 'The :attribute must be a valid IP address.', - 'ipv4' => 'The :attribute must be a valid IPv4 address.', - 'ipv6' => 'The :attribute must be a valid IPv6 address.', - 'json' => 'The :attribute must be a valid JSON string.', + 'exists' => 'Valittu :attribute ei ole kelvollinen.', + 'image' => ':attribute on oltava kuva.', + 'image_extension' => ':-attribute tulee sisältää kelvollisen ja tuetun kuvan tiedostopäätteen.', + 'in' => 'Valittu :attribute ei ole kelvollinen.', + 'integer' => ':attribute tulee olla kokonaisluku.', + 'ip' => ':attribute tulee olla kelvollinen IP-osoite.', + 'ipv4' => ':attribute tulee olla kelvollinen IPv4-osoite.', + 'ipv6' => ':attribute tulee olla kelvollinen IPv6 -osoite.', + 'json' => ':attribute tulee olla kelvollinen JSON-merkkijono.', 'lt' => [ - 'numeric' => 'The :attribute must be less than :value.', - 'file' => 'The :attribute must be less than :value kilobytes.', - 'string' => 'The :attribute must be less than :value characters.', - 'array' => 'The :attribute must have less than :value items.', + 'numeric' => ':attribute tulee olla vähemmän kuin :value.', + 'file' => ':attribute tulee olla vähemmän kuin :value kilotavua.', + 'string' => ':attribute tulee olla vähemmän kuin :value merkkiä.', + 'array' => ':attribute tulee sisältää vähemmän kuin :value kohdetta.', ], 'lte' => [ - 'numeric' => 'The :attribute must be less than or equal :value.', - 'file' => 'The :attribute must be less than or equal :value kilobytes.', - 'string' => 'The :attribute must be less than or equal :value characters.', - 'array' => 'The :attribute must not have more than :value items.', + 'numeric' => ':attribute tulee olla vähemmän tai yhtä suuri kuin :value.', + 'file' => ':attribute tulee olla vähemmän tai yhtä suuri kuin :value kilotavua.', + 'string' => ':attribute tulee olla vähemmän tai yhtä suuri kuin :value merkkiä.', + 'array' => ':attribute ei tule sisältää enempää kuin :value kohdetta.', ], 'max' => [ - 'numeric' => 'The :attribute may not be greater than :max.', - 'file' => 'The :attribute may not be greater than :max kilobytes.', - 'string' => 'The :attribute may not be greater than :max characters.', - 'array' => 'The :attribute may not have more than :max items.', + 'numeric' => ':attribute ei saa olla suurempi kuin :max.', + 'file' => ':attribute ei saa olla suurempi kuin :max kilotavua.', + 'string' => ':attribute ei saa olla suurempi kuin :max merkkiä.', + 'array' => ':attribute ei saa sisältää enempää kuin :max kohdetta.', ], - 'mimes' => 'The :attribute must be a file of type: :values.', + 'mimes' => ':attribute tulee olla tiedosto jonka tyyppi on :values.', 'min' => [ - 'numeric' => 'The :attribute must be at least :min.', - 'file' => 'The :attribute must be at least :min kilobytes.', - 'string' => 'The :attribute must be at least :min characters.', - 'array' => 'The :attribute must have at least :min items.', + 'numeric' => ':attribute tulee olla vähintään :min.', + 'file' => ':attribute tulee olla vähintään :min kilotavua.', + 'string' => ':attribute tulee olla vähintään :min merkkiä.', + 'array' => ':attribute tulee sisältää vähintään :min kohdetta.', ], - 'not_in' => 'The selected :attribute is invalid.', - 'not_regex' => 'The :attribute format is invalid.', - 'numeric' => 'The :attribute must be a number.', - 'regex' => 'The :attribute format is invalid.', - 'required' => 'The :attribute field is required.', - 'required_if' => 'The :attribute field is required when :other is :value.', - 'required_with' => 'The :attribute field is required when :values is present.', - 'required_with_all' => 'The :attribute field is required when :values is present.', - 'required_without' => 'The :attribute field is required when :values is not present.', - 'required_without_all' => 'The :attribute field is required when none of :values are present.', - 'same' => 'The :attribute and :other must match.', - 'safe_url' => 'The provided link may not be safe.', + 'not_in' => 'Valittu :attribute ei ole kelvollinen.', + 'not_regex' => ':attribute muoto ei ole kelvollinen.', + 'numeric' => ':attribute tulee olla numero.', + 'regex' => ':attribute muoto ei ole kelvollinen.', + 'required' => 'Kenttä :attribute vaaditaan.', + 'required_if' => 'Kenttä :attribute vaaditaan, kun :other on :value.', + 'required_with' => 'Kenttä :attribute vaaditaan, kun :values on määritettynä.', + 'required_with_all' => 'Kenttä :attribute vaaditaan, kun kaikki näistä on määritettynä :values.', + 'required_without' => 'Kenttä :attribute vaaditaan, kun :values ei ole määritettynä.', + 'required_without_all' => 'Kenttä :attribute vaaditaan, kun mikään näistä ei ole määritettynä :values.', + 'same' => ':attribute ja :other tulee täsmätä.', + 'safe_url' => 'Annettu linkki ei ole mahdollisesti turvallinen.', 'size' => [ - 'numeric' => 'The :attribute must be :size.', - 'file' => 'The :attribute must be :size kilobytes.', - 'string' => 'The :attribute must be :size characters.', - 'array' => 'The :attribute must contain :size items.', + 'numeric' => ':attribute tulee olla :size.', + 'file' => ':attribute tulee olla :size kilotavua.', + 'string' => ':attribute tulee olla :size merkkiä.', + 'array' => ':attribute tulee sisältää :size kohdetta.', ], - 'string' => 'The :attribute must be a string.', - 'timezone' => 'The :attribute must be a valid zone.', - 'totp' => 'The provided code is not valid or has expired.', - 'unique' => 'The :attribute has already been taken.', - 'url' => 'The :attribute format is invalid.', - 'uploaded' => 'The file could not be uploaded. The server may not accept files of this size.', + 'string' => ':attribute tulee olla merkkijono.', + 'timezone' => ':attribute tulee olla kelvollinen aikavyöhyke.', + 'totp' => 'Annettu koodi ei ole kelvollinen tai se on vanhentunut.', + 'unique' => ':attribute on jo käytössä.', + 'url' => ':attribute muoto ei ole kelvollinen.', + 'uploaded' => 'Tiedostoa ei voitu ladata. Palvelin ei ehkä hyväksy tämän kokoisia tiedostoja.', // Custom validation lines 'custom' => [ 'password-confirm' => [ - 'required_with' => 'Password confirmation required', + 'required_with' => 'Salasanan vahvistus vaaditaan', ], ], diff --git a/lang/fr/entities.php b/lang/fr/entities.php index 5b813b4f6..e890c2787 100644 --- a/lang/fr/entities.php +++ b/lang/fr/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Mis à jour :timeLength', 'meta_updated_name' => 'Mis à jour :timeLength par :user', 'meta_owned_name' => 'Appartient à :user', - 'meta_reference_page_count' => 'Référencé sur :count page|Référencé sur :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Sélectionner l\'entité', 'entity_select_lack_permission' => 'Vous n\'avez pas les permissions requises pour sélectionner cet élément', 'images' => 'Images', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Modifier le livre :bookName', 'books_form_book_name' => 'Nom du livre', 'books_save' => 'Enregistrer le livre', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Permissions du livre', 'books_permissions_updated' => 'Permissions du livre mises à jour', 'books_empty_contents' => 'Aucune page ou chapitre n\'a été ajouté à ce livre.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Supprimer le brouillon', 'pages_delete_success' => 'Page supprimée', 'pages_delete_draft_success' => 'Brouillon supprimé', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Êtes-vous sûr(e) de vouloir supprimer cette page ?', 'pages_delete_draft_confirm' => 'Êtes-vous sûr(e) de vouloir supprimer ce brouillon ?', 'pages_editing_named' => 'Modification de la page :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Références', 'references_none' => 'Il n\'y a pas de références suivies à cet élément.', - 'references_to_desc' => 'Vous trouverez ci-dessous toutes les pages connues du système qui ont un lien vers cet élément.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Suivre', diff --git a/lang/fr/errors.php b/lang/fr/errors.php index ce4ae1bb5..2e4cfa216 100644 --- a/lang/fr/errors.php +++ b/lang/fr/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'L\'extension PHP LDAP n\'est pas installée', 'ldap_cannot_connect' => 'Impossible de se connecter au serveur LDAP, la connexion initiale a échoué', 'saml_already_logged_in' => 'Déjà connecté', - 'saml_user_not_registered' => 'L\'utilisateur :name n\'est pas enregistré et l\'enregistrement automatique est désactivé', 'saml_no_email_address' => 'Impossible de trouver une adresse e-mail, pour cet utilisateur, dans les données fournies par le système d\'authentification externe', 'saml_invalid_response_id' => 'La requête du système d\'authentification externe n\'est pas reconnue par un processus démarré par cette application. Naviguer après une connexion peut causer ce problème.', 'saml_fail_authed' => 'Connexion avec :system échouée, le système n\'a pas fourni l\'autorisation réussie', diff --git a/lang/fr/notifications.php b/lang/fr/notifications.php index 37b40882d..eb97ddfda 100644 --- a/lang/fr/notifications.php +++ b/lang/fr/notifications.php @@ -4,15 +4,16 @@ */ return [ - 'new_comment_subject' => 'Nouveau commentaire sur la page : :pageName', + 'new_comment_subject' => 'Nouveau commentaire sur la page: :pageName', 'new_comment_intro' => 'Un utilisateur a commenté une page dans :appName:', - 'new_page_subject' => 'Nouvelle page : :pageName', + 'new_page_subject' => 'Nouvelle page: :pageName', 'new_page_intro' => 'Une nouvelle page a été créée dans :appName:', - 'updated_page_subject' => 'Page mise à jour : :pageName', + 'updated_page_subject' => 'Page mise à jour: :pageName', 'updated_page_intro' => 'Une page a été mise à jour dans :appName:', 'updated_page_debounce' => 'Pour éviter de nombreuses notifications, pendant un certain temps, vous ne recevrez pas de notifications pour d\'autres modifications de cette page par le même éditeur.', 'detail_page_name' => 'Nom de la page :', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenta·teur·trice :', 'detail_comment' => 'Commentaire :', 'detail_created_by' => 'Créé par :', diff --git a/lang/fr/settings.php b/lang/fr/settings.php index 731770e83..928fed4b3 100644 --- a/lang/fr/settings.php +++ b/lang/fr/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Estonien', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'Hébreu', 'hr' => 'Croate', diff --git a/lang/he/entities.php b/lang/he/entities.php index 6813cfcea..113af659b 100644 --- a/lang/he/entities.php +++ b/lang/he/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'עודכן :timeLength', 'meta_updated_name' => 'עודכן :timeLength על ידי :user', 'meta_owned_name' => 'Owned by :user', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'בחר יישות', 'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item', 'images' => 'תמונות', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'עריכת ספר :bookName', 'books_form_book_name' => 'שם הספר', 'books_save' => 'שמור ספר', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'הרשאות ספר', 'books_permissions_updated' => 'הרשאות הספר עודכנו', 'books_empty_contents' => 'לא נוצרו פרקים או דפים עבור ספר זה', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'מחק טיוטת דף', 'pages_delete_success' => 'הדף נמחק', 'pages_delete_draft_success' => 'טיוטת דף נמחקה', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'האם ברצונך למחוק דף זה?', 'pages_delete_draft_confirm' => 'האם ברצונך למחוק את טיוטת הדף הזה?', 'pages_editing_named' => 'עריכת דף :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'References', 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/he/errors.php b/lang/he/errors.php index abf028417..4de4d88c5 100644 --- a/lang/he/errors.php +++ b/lang/he/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'הרחבת LDAP עבור PHP לא מותקנת', 'ldap_cannot_connect' => 'Cannot connect to ldap server, Initial connection failed', 'saml_already_logged_in' => 'כבר מחובר', - 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', diff --git a/lang/he/notifications.php b/lang/he/notifications.php index 5539ae9a9..1afd23f1d 100644 --- a/lang/he/notifications.php +++ b/lang/he/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/he/settings.php b/lang/he/settings.php index 26b79394c..ead74732c 100644 --- a/lang/he/settings.php +++ b/lang/he/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/hr/entities.php b/lang/hr/entities.php index 67fada531..6a69a0d92 100644 --- a/lang/hr/entities.php +++ b/lang/hr/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Ažurirano :timeLength', 'meta_updated_name' => 'Ažurirano :timeLength od :user', 'meta_owned_name' => 'Vlasništvo :user', - 'meta_reference_page_count' => 'Referencirano na :count stranici|Referencirano na :count stranica', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Odaberi subjekt', 'entity_select_lack_permission' => 'Nemate potrebne ovlasti za odabir ovog elementa', 'images' => 'Slike', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Uredi knjigu :bookName', 'books_form_book_name' => 'Ime knjige', 'books_save' => 'Spremi knjigu', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Dopuštenja za knjigu', 'books_permissions_updated' => 'Ažurirana dopuštenja za knjigu', 'books_empty_contents' => 'U ovoj knjizi još nema stranica ni poglavlja.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Izbriši nacrt stranice', 'pages_delete_success' => 'Izbrisana stranica', 'pages_delete_draft_success' => 'Izbrisan nacrt stranice', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Jeste li sigurni da želite izbrisati stranicu?', 'pages_delete_draft_confirm' => 'Jeste li sigurni da želite izbrisati nacrt stranice?', 'pages_editing_named' => 'Uređivanje stranice :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Reference', 'references_none' => 'Nema praćenih referenci na ovu stavku.', - 'references_to_desc' => 'U nastavku su prikazane sve poznate stranice u sustavu koje se povezuju s ovom stavkom.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Prati', diff --git a/lang/hr/errors.php b/lang/hr/errors.php index 1b789c6c5..608c05e29 100644 --- a/lang/hr/errors.php +++ b/lang/hr/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'LDAP PHP ekstenzija nije instalirana', 'ldap_cannot_connect' => 'Nemoguće pristupiti ldap serveru, problem s mrežom', 'saml_already_logged_in' => 'Već ste prijavljeni', - 'saml_user_not_registered' => 'Korisnik :name nije registriran i automatska registracija je onemogućena', 'saml_no_email_address' => 'Nismo pronašli email adresu za ovog korisnika u vanjskim sustavima', 'saml_invalid_response_id' => 'Sustav za autentifikaciju nije prepoznat. Ovaj problem možda je nastao zbog vraćanja nakon prijave.', 'saml_fail_authed' => 'Prijava pomoću :system nije uspjela zbog neuspješne autorizacije', diff --git a/lang/hr/notifications.php b/lang/hr/notifications.php index e50d57dfe..c3a38cdfa 100644 --- a/lang/hr/notifications.php +++ b/lang/hr/notifications.php @@ -15,6 +15,7 @@ Ažurirana stranica: :pageName', 'updated_page_debounce' => 'Kako biste spriječili velik broj obavijesti, nećete primati obavijesti o daljnjim izmjenama ove stranice od istog urednika neko vrijeme.', 'detail_page_name' => 'Naziv Stranice:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Komentator:', 'detail_comment' => 'Komentar:', 'detail_created_by' => 'Kreirao Korisnik:', diff --git a/lang/hr/settings.php b/lang/hr/settings.php index 4d66abfaa..6040489ac 100644 --- a/lang/hr/settings.php +++ b/lang/hr/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/hu/entities.php b/lang/hu/entities.php index 97c8b206d..339a8d100 100644 --- a/lang/hu/entities.php +++ b/lang/hu/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Frissítve :timeLength', 'meta_updated_name' => ':user frissítette :timeLength', 'meta_owned_name' => ':user tulajdona', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Entitás kiválasztása', 'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item', 'images' => 'Képek', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => ':bookName könyv szerkesztése', 'books_form_book_name' => 'Könyv neve', 'books_save' => 'Könyv mentése', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Könyv jogosultságok', 'books_permissions_updated' => 'Könyv jogosultságok frissítve', 'books_empty_contents' => 'Ehhez a könyvhöz nincsenek oldalak vagy fejezetek létrehozva.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Vázlat oldal törlése', 'pages_delete_success' => 'Oldal törölve', 'pages_delete_draft_success' => 'Vázlat oldal törölve', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Biztosan törölhető ez az oldal?', 'pages_delete_draft_confirm' => 'Biztosan törölhető ez a vázlatoldal?', 'pages_editing_named' => ':pageName oldal szerkesztése', @@ -405,7 +409,7 @@ return [ // References 'references' => 'References', 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/hu/errors.php b/lang/hu/errors.php index 19407a8e9..e51ef633f 100644 --- a/lang/hu/errors.php +++ b/lang/hu/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'LDAP PHP kiterjesztés nincs telepítve', 'ldap_cannot_connect' => 'Nem lehet kapcsolódni az LDAP kiszolgálóhoz, a kezdeti kapcsolatfelvétel nem sikerült', 'saml_already_logged_in' => 'Már bejelentkezett', - 'saml_user_not_registered' => ':name felhasználó nincs regisztrálva és az automatikus regisztráció le van tiltva', 'saml_no_email_address' => 'Ehhez a felhasználóhoz nem található email cím a külső hitelesítő rendszer által átadott adatokban', 'saml_invalid_response_id' => 'A külső hitelesítő rendszerből érkező kérést nem ismerte fel az alkalmazás által indított folyamat. Bejelentkezés után az előző oldalra történő visszalépés okozhatja ezt a hibát.', 'saml_fail_authed' => 'Bejelentkezés :system használatával sikertelen, a rendszer nem biztosított sikeres hitelesítést', diff --git a/lang/hu/notifications.php b/lang/hu/notifications.php index 5539ae9a9..1afd23f1d 100644 --- a/lang/hu/notifications.php +++ b/lang/hu/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/hu/settings.php b/lang/hu/settings.php index 45f6437c4..333b82574 100644 --- a/lang/hu/settings.php +++ b/lang/hu/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/id/entities.php b/lang/id/entities.php index 7f80d6258..0c7c7a9ef 100644 --- a/lang/id/entities.php +++ b/lang/id/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Diperbaharui :timeLength', 'meta_updated_name' => 'Diperbaharui :timeLength oleh :user', 'meta_owned_name' => 'Dimiliki oleh :user', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Pilihan Entitas', 'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item', 'images' => 'Gambar-gambar', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Sunting Buku :bookName', 'books_form_book_name' => 'Nama Buku', 'books_save' => 'Simpan Buku', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Izin Buku', 'books_permissions_updated' => 'Izin Buku Diperbarui', 'books_empty_contents' => 'Tidak ada halaman atau bab yang telah dibuat untuk buku ini.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Hapus Halaman Draf', 'pages_delete_success' => 'Halaman dihapus', 'pages_delete_draft_success' => 'Halaman draf dihapus', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Anda yakin ingin menghapus halaman ini?', 'pages_delete_draft_confirm' => 'Anda yakin ingin menghapus halaman draf ini?', 'pages_editing_named' => 'Menyunting Halaman :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'References', 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/id/errors.php b/lang/id/errors.php index 6843e62ea..7ed7f2e11 100644 --- a/lang/id/errors.php +++ b/lang/id/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'Ekstensi LDAP PHP tidak terpasang', 'ldap_cannot_connect' => 'Tidak dapat terhubung ke server ldap, Koneksi awal gagal', 'saml_already_logged_in' => 'Telah masuk', - 'saml_user_not_registered' => 'Pengguna :name tidak terdaftar dan pendaftaran otomatis dinonaktifkan', 'saml_no_email_address' => 'Tidak dapat menemukan sebuah alamat email untuk pengguna ini, dalam data yang diberikan oleh sistem autentikasi eksternal', 'saml_invalid_response_id' => 'Permintaan dari sistem otentikasi eksternal tidak dikenali oleh sebuah proses yang dimulai oleh aplikasi ini. Menavigasi kembali setelah masuk dapat menyebabkan masalah ini.', 'saml_fail_authed' => 'Masuk menggunakan :system gagal, sistem tidak memberikan otorisasi yang berhasil', diff --git a/lang/id/notifications.php b/lang/id/notifications.php index 5539ae9a9..1afd23f1d 100644 --- a/lang/id/notifications.php +++ b/lang/id/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/id/settings.php b/lang/id/settings.php index 866f30984..515d4bd95 100644 --- a/lang/id/settings.php +++ b/lang/id/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/it/entities.php b/lang/it/entities.php index a0d570732..383cb4e7c 100644 --- a/lang/it/entities.php +++ b/lang/it/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Aggiornato :timeLength', 'meta_updated_name' => 'Aggiornato :timeLength da :user', 'meta_owned_name' => 'Creati da :user', - 'meta_reference_page_count' => 'Referenziato su :count page|Referenziato su :count pages', + 'meta_reference_count' => 'Referenziato da :count item|Referenziato da :count items', 'entity_select' => 'Selezione Entità', 'entity_select_lack_permission' => 'Non hai i permessi necessari per selezionare questo elemento', 'images' => 'Immagini', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Modifica il libro :bookName', 'books_form_book_name' => 'Nome Libro', 'books_save' => 'Salva Libro', + 'books_default_template' => 'Pagina template predefinita', + 'books_default_template_explain' => 'Assegnare una pagina template che verrà utilizzata come contenuto predefinito per tutte le nuove pagine di questo libro. Tenete presente che questa sarà usata solo se il creatore della pagina ha accesso di visualizzazione alla pagina template scelta.', + 'books_default_template_select' => 'Selezionare una pagina template', 'books_permissions' => 'Permessi Libro', 'books_permissions_updated' => 'Permessi del libro aggiornati', 'books_empty_contents' => 'Non ci sono pagine o capitoli per questo libro.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Elimina Bozza Pagina', 'pages_delete_success' => 'Pagina eliminata', 'pages_delete_draft_success' => 'Bozza di una pagina eliminata', + 'pages_delete_warning_template' => 'Questa pagina è in uso come pagina template predefinita di un libro. Dopo l\'eliminazione di questa pagina, a questi libri non verrà più assegnato una pagina template predefinita.', 'pages_delete_confirm' => 'Sei sicuro di voler eliminare questa pagina?', 'pages_delete_draft_confirm' => 'Sei sicuro di voler eliminare la bozza di questa pagina?', 'pages_editing_named' => 'Modifica :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Riferimenti', 'references_none' => 'Non ci sono riferimenti tracciati a questa voce.', - 'references_to_desc' => 'Di seguito sono riportate tutte le pagine conosciute nel sistema che collegano a questo elemento.', + 'references_to_desc' => 'Di seguito sono elencati tutti i contenuti noti del sistema che rimandano a questo elemento.', // Watch Options 'watch' => 'Osserva', diff --git a/lang/it/errors.php b/lang/it/errors.php index ab05b406c..6ec9c36a0 100644 --- a/lang/it/errors.php +++ b/lang/it/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'L\'estensione PHP LDAP non è installata', 'ldap_cannot_connect' => 'Impossibile connettersi al server ldap, connessione iniziale fallita', 'saml_already_logged_in' => 'Già loggato', - 'saml_user_not_registered' => 'L\'utente :name non è registrato e la registrazione automatica è disabilitata', 'saml_no_email_address' => 'Impossibile trovare un indirizzo email per questo utente nei dati forniti dal sistema di autenticazione esterno', 'saml_invalid_response_id' => 'La richiesta dal sistema di autenticazione esterno non è riconosciuta da un processo iniziato da questa applicazione. Tornare indietro dopo un login potrebbe causare questo problema.', 'saml_fail_authed' => 'Accesso con :system non riuscito, il sistema non ha fornito l\'autorizzazione corretta', diff --git a/lang/it/notifications.php b/lang/it/notifications.php index a17abe368..3b902600f 100644 --- a/lang/it/notifications.php +++ b/lang/it/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'Per evitare una massa di notifiche, per un po \'non verranno inviate notifiche per ulteriori modifiche a questa pagina dallo stesso editor.', 'detail_page_name' => 'Nome Della Pagina:', + 'detail_page_path' => 'Percorso della pagina:', 'detail_commenter' => 'Commentatore:', 'detail_comment' => 'Commento:', 'detail_created_by' => 'Creato Da:', diff --git a/lang/it/settings.php b/lang/it/settings.php index fac7e36f5..9ddde05b4 100644 --- a/lang/it/settings.php +++ b/lang/it/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Estone', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Francese', 'he' => 'Ebraico', 'hr' => 'Croato', diff --git a/lang/ja/entities.php b/lang/ja/entities.php index fd396b1de..dd4c27469 100644 --- a/lang/ja/entities.php +++ b/lang/ja/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => '更新: :timeLength', 'meta_updated_name' => '更新: :timeLength (:user)', 'meta_owned_name' => '所有者: :user', - 'meta_reference_page_count' => '{0}ページの参照はありません|[1,9]:count つのページから参照|[10,*]:count ページから参照', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'エンティティ選択', 'entity_select_lack_permission' => 'この項目を選択するために必要な権限がありません', 'images' => '画像', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'ブック「:bookName」を編集', 'books_form_book_name' => 'ブック名', 'books_save' => 'ブックを保存', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'ブックの権限', 'books_permissions_updated' => 'ブックの権限を更新しました', 'books_empty_contents' => 'まだページまたはチャプターが作成されていません。', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'ページの下書きを削除', 'pages_delete_success' => 'ページを削除しました', 'pages_delete_draft_success' => 'ページの下書きを削除しました', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'このページを削除してもよろしいですか?', 'pages_delete_draft_confirm' => 'このページの下書きを削除してもよろしいですか?', 'pages_editing_named' => 'ページ :pageName を編集', @@ -406,7 +410,7 @@ return [ // References 'references' => '参照', 'references_none' => 'この項目への追跡された参照はありません。', - 'references_to_desc' => 'この項目にリンクしている、システム内のすべての既知のページを以下に示します。', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'ウォッチ', diff --git a/lang/ja/errors.php b/lang/ja/errors.php index b54479a2d..26de050e4 100644 --- a/lang/ja/errors.php +++ b/lang/ja/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'LDAP PHP extensionがインストールされていません', 'ldap_cannot_connect' => 'LDAPサーバに接続できませんでした', 'saml_already_logged_in' => '既にログインしています', - 'saml_user_not_registered' => 'ユーザー :name は登録されておらず、自動登録は無効になっています', 'saml_no_email_address' => '外部認証システムから提供されたデータに、このユーザーのメールアドレスが見つかりませんでした', 'saml_invalid_response_id' => '外部認証システムからの要求がアプリケーションによって開始されたプロセスによって認識されません。ログイン後に戻るとこの問題が発生する可能性があります。', 'saml_fail_authed' => ':systemを利用したログインに失敗しました。システムは正常な認証を提供しませんでした。', diff --git a/lang/ja/notifications.php b/lang/ja/notifications.php index 820b13c8f..364b4a3aa 100644 --- a/lang/ja/notifications.php +++ b/lang/ja/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => '大量の通知を防ぐために、しばらくの間は同じユーザがこのページをさらに編集しても通知は送信されません。', 'detail_page_name' => 'ページ名:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'コメントユーザ:', 'detail_comment' => 'コメント:', 'detail_created_by' => '作成ユーザ:', diff --git a/lang/ja/settings.php b/lang/ja/settings.php index a1a9b74e9..1ef109d79 100644 --- a/lang/ja/settings.php +++ b/lang/ja/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/ka/entities.php b/lang/ka/entities.php index cfb5aae1a..f1f915544 100644 --- a/lang/ka/entities.php +++ b/lang/ka/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Updated :timeLength', 'meta_updated_name' => 'Updated :timeLength by :user', 'meta_owned_name' => 'Owned by :user', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Entity Select', 'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item', 'images' => 'Images', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Edit Book :bookName', 'books_form_book_name' => 'Book Name', 'books_save' => 'Save Book', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Book Permissions', 'books_permissions_updated' => 'Book Permissions Updated', 'books_empty_contents' => 'No pages or chapters have been created for this book.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Delete Draft Page', 'pages_delete_success' => 'Page deleted', 'pages_delete_draft_success' => 'Draft page deleted', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Are you sure you want to delete this page?', 'pages_delete_draft_confirm' => 'Are you sure you want to delete this draft page?', 'pages_editing_named' => 'Editing Page :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'References', 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/ka/errors.php b/lang/ka/errors.php index 8813cf90a..607b6ea83 100644 --- a/lang/ka/errors.php +++ b/lang/ka/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'LDAP PHP extension not installed', 'ldap_cannot_connect' => 'Cannot connect to ldap server, Initial connection failed', 'saml_already_logged_in' => 'Already logged in', - 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', diff --git a/lang/ka/notifications.php b/lang/ka/notifications.php index 5539ae9a9..1afd23f1d 100644 --- a/lang/ka/notifications.php +++ b/lang/ka/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/ka/settings.php b/lang/ka/settings.php index c5ca662c3..03e9bf462 100644 --- a/lang/ka/settings.php +++ b/lang/ka/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/ko/activities.php b/lang/ko/activities.php index 96313de1a..f9002431b 100644 --- a/lang/ko/activities.php +++ b/lang/ko/activities.php @@ -50,9 +50,9 @@ return [ 'bookshelf_delete_notification' => '책꽃이가 삭제되었습니다.', // Revisions - 'revision_restore' => 'restored revision', - 'revision_delete' => 'deleted revision', - 'revision_delete_notification' => 'Revision successfully deleted', + 'revision_restore' => '버전 복원', + 'revision_delete' => '버전 삭제', + 'revision_delete_notification' => '버전 삭제 성공', // Favourites 'favourite_add_notification' => '":name" 북마크에 추가함', @@ -63,17 +63,17 @@ return [ // Auth 'auth_login' => 'logged in', - 'auth_register' => 'registered as new user', - 'auth_password_reset_request' => 'requested user password reset', - 'auth_password_reset_update' => 'reset user password', + 'auth_register' => '신규 사용자 등록', + 'auth_password_reset_request' => '사용자 비밀번호 초기화 요청', + 'auth_password_reset_update' => '사용자 비밀번호 초기화', 'mfa_setup_method' => 'configured MFA method', 'mfa_setup_method_notification' => '다중 인증 설정함', 'mfa_remove_method' => 'removed MFA method', 'mfa_remove_method_notification' => '다중 인증 해제함', // Settings - 'settings_update' => 'updated settings', - 'settings_update_notification' => 'Settings successfully updated', + 'settings_update' => '설정 변경', + 'settings_update_notification' => '설졍 변경 성공', 'maintenance_action_run' => 'ran maintenance action', // Webhooks @@ -85,15 +85,15 @@ return [ 'webhook_delete_notification' => '웹 훅 삭제함', // Users - 'user_create' => 'created user', - 'user_create_notification' => 'User successfully created', - 'user_update' => 'updated user', + 'user_create' => '사용자 생성', + 'user_create_notification' => '사용자 생성 성공', + 'user_update' => '사용자 갱신', 'user_update_notification' => '사용자가 업데이트되었습니다', - 'user_delete' => 'deleted user', + 'user_delete' => '사용자 삭제', 'user_delete_notification' => '사용자가 삭제되었습니다', // API Tokens - 'api_token_create' => 'created api token', + 'api_token_create' => 'aPI 토큰 생성', 'api_token_create_notification' => 'API token successfully created', 'api_token_update' => 'updated api token', 'api_token_update_notification' => 'API token successfully updated', @@ -101,11 +101,11 @@ return [ 'api_token_delete_notification' => 'API token successfully deleted', // Roles - 'role_create' => 'created role', + 'role_create' => '역활 생성', 'role_create_notification' => '역할이 생성되었습니다', - 'role_update' => 'updated role', + 'role_update' => '역활 갱신', 'role_update_notification' => '역할이 수정되었습니다', - 'role_delete' => 'deleted role', + 'role_delete' => '역활 삭제', 'role_delete_notification' => '역할이 삭제되었습니다', // Recycle Bin @@ -115,9 +115,9 @@ return [ // Comments 'commented_on' => '댓글 쓰기', - 'comment_create' => 'added comment', - 'comment_update' => 'updated comment', - 'comment_delete' => 'deleted comment', + 'comment_create' => '댓글 생성', + 'comment_update' => '댓글 변경', + 'comment_delete' => '댓글 삭제', // Other 'permissions_update' => '권한 수정함', diff --git a/lang/ko/components.php b/lang/ko/components.php index 8df54a19e..66e1bde18 100644 --- a/lang/ko/components.php +++ b/lang/ko/components.php @@ -6,9 +6,9 @@ return [ // Image Manager 'image_select' => '이미지 선택', - 'image_list' => 'Image List', - 'image_details' => 'Image Details', - 'image_upload' => 'Upload Image', + 'image_list' => '이미지 목록', + 'image_details' => '이미지 상세정보', + 'image_upload' => '이미지 업로드', 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.', 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.', 'image_all' => '모든 이미지', @@ -17,22 +17,22 @@ return [ 'image_page_title' => '이 문서에서 쓰고 있는 이미지', 'image_search_hint' => '이미지 이름 검색', 'image_uploaded' => '올림 :uploadedDate', - 'image_uploaded_by' => 'Uploaded by :userName', - 'image_uploaded_to' => 'Uploaded to :pageLink', - 'image_updated' => 'Updated :updateDate', + 'image_uploaded_by' => '업로드:유저 닉네임', + 'image_uploaded_to' => '업로드:링크', + 'image_updated' => '갱신:갱신일', 'image_load_more' => '더 로드하기', 'image_image_name' => '이미지 이름', 'image_delete_used' => '이 이미지는 다음 문서들이 쓰고 있습니다.', 'image_delete_confirm_text' => '이 이미지를 지울 건가요?', 'image_select_image' => '이미지 선택', 'image_dropzone' => '여기에 이미지를 드롭하거나 여기를 클릭하세요. 이미지를 올릴 수 있습니다.', - 'image_dropzone_drop' => 'Drop images here to upload', + 'image_dropzone_drop' => '업로드 할 이미지 파일을 여기에 놓으세요.', 'images_deleted' => '이미지 삭제함', 'image_preview' => '이미지 미리 보기', 'image_upload_success' => '이미지 올림', 'image_update_success' => '이미지 정보 수정함', 'image_delete_success' => '이미지 삭제함', - 'image_replace' => 'Replace Image', + 'image_replace' => '이미지 교체', 'image_replace_success' => 'Image file successfully updated', 'image_rebuild_thumbs' => 'Regenerate Size Variations', 'image_rebuild_thumbs_success' => 'Image size variations successfully rebuilt!', diff --git a/lang/ko/entities.php b/lang/ko/entities.php index 86d4b9347..cd56d3ed8 100644 --- a/lang/ko/entities.php +++ b/lang/ko/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => '수정함 :timeLength', 'meta_updated_name' => '수정함 :timeLength, :user', 'meta_owned_name' => '소유함 :user', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => '항목 선택', 'entity_select_lack_permission' => '이 항목을 선택하기 위해 필요한 권한이 없습니다', 'images' => '이미지', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => ':bookName(을)를 바꿉니다.', 'books_form_book_name' => '책 이름', 'books_save' => '저장', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => '책 권한', 'books_permissions_updated' => '권한 저장함', 'books_empty_contents' => '이 책에 챕터나 문서가 없습니다.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => '초안 문서 삭제하기', 'pages_delete_success' => '문서 지움', 'pages_delete_draft_success' => '초안 문서 지움', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => '이 문서를 지울 건가요?', 'pages_delete_draft_confirm' => '이 초안을 지울 건가요?', 'pages_editing_named' => ':pageName 수정', @@ -405,7 +409,7 @@ return [ // References 'references' => 'References', 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/ko/errors.php b/lang/ko/errors.php index 464774d29..a652cc697 100644 --- a/lang/ko/errors.php +++ b/lang/ko/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'PHP에 LDAP 확장 도구를 설치하세요.', 'ldap_cannot_connect' => 'LDAP 서버에 연결할 수 없습니다.', 'saml_already_logged_in' => '로그인 중입니다.', - 'saml_user_not_registered' => ':name 사용자가 없습니다. 자동 가입 옵션이 비활성 상태입니다.', 'saml_no_email_address' => '인증 시스템이 제공한 메일 주소가 없습니다.', 'saml_invalid_response_id' => '인증 시스템이 요청을 받지 못했습니다. 인증 후 이전 페이지로 돌아갈 때 발생할 수 있는 현상입니다.', 'saml_fail_authed' => ':system에 로그인할 수 없습니다.', diff --git a/lang/ko/notifications.php b/lang/ko/notifications.php index 5539ae9a9..1afd23f1d 100644 --- a/lang/ko/notifications.php +++ b/lang/ko/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/ko/settings.php b/lang/ko/settings.php index e2174ebc5..e60bb6646 100644 --- a/lang/ko/settings.php +++ b/lang/ko/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => '히브리어', 'hr' => 'Hrvatski', diff --git a/lang/lt/entities.php b/lang/lt/entities.php index 42a7e6018..9880ebb79 100644 --- a/lang/lt/entities.php +++ b/lang/lt/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Atnaujintas :timeLength', 'meta_updated_name' => 'Atnaujinta :timeLength naudotojo :user', 'meta_owned_name' => 'Priklauso :user', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Pasirinkti subjektą', 'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item', 'images' => 'Nuotraukos', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Redaguoti knygą :bookName', 'books_form_book_name' => 'Knygos pavadinimas', 'books_save' => 'Išsaugoti knygą', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Knygos leidimas', 'books_permissions_updated' => 'Knygos leidimas atnaujintas', 'books_empty_contents' => 'Jokių puslapių ar skyrių nebuvo skurta šiai knygai', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Ištrinti juodraščio puslapį', 'pages_delete_success' => 'Puslapis ištrintas', 'pages_delete_draft_success' => 'Juodraščio puslapis ištrintas', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Ar esate tikri, kad norite ištrinti šį puslapį?', 'pages_delete_draft_confirm' => 'Ar esate tikri, kad norite ištrinti šį juodraščio puslapį?', 'pages_editing_named' => 'Redaguojamas puslapis :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'References', 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/lt/errors.php b/lang/lt/errors.php index 44c9ace08..0e14b6517 100644 --- a/lang/lt/errors.php +++ b/lang/lt/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'LDAP PHP išplėtimas neįdiegtas', 'ldap_cannot_connect' => 'Negalima prisijungti prie LDAP serverio, nepavyko prisijungti', 'saml_already_logged_in' => 'Jau prisijungta', - 'saml_user_not_registered' => 'Naudotojas :name neužregistruotas ir automatinė registracija yra išjungta', 'saml_no_email_address' => 'Nerandamas šio naudotojo elektroninio pašto adresas išorinės autentifikavimo sistemos pateiktuose duomenyse', 'saml_invalid_response_id' => 'Prašymas iš išorinės autentifikavimo sistemos nėra atpažintas proceso, kurį pradėjo ši programa. Naršymas po prisijungimo gali sukelti šią problemą.', 'saml_fail_authed' => 'Prisijungimas, naudojant :system nepavyko, sistema nepateikė sėkmingo leidimo.', diff --git a/lang/lt/notifications.php b/lang/lt/notifications.php index 5539ae9a9..1afd23f1d 100644 --- a/lang/lt/notifications.php +++ b/lang/lt/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/lt/settings.php b/lang/lt/settings.php index 1e467ca3e..000e018c6 100644 --- a/lang/lt/settings.php +++ b/lang/lt/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/lv/entities.php b/lang/lv/entities.php index d23e27210..40115afff 100644 --- a/lang/lv/entities.php +++ b/lang/lv/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Atjaunināts :timeLength', 'meta_updated_name' => ':user atjauninājis pirms :timeLength', 'meta_owned_name' => 'Īpašnieks :user', - 'meta_reference_page_count' => 'Atsauce :count lapā|Atsauce :count lapās', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Izvēlēties vienumu', 'entity_select_lack_permission' => 'Jums nav nepieciešamās piekļuves tiesības, lai izvēlētu šo vienumu', 'images' => 'Attēli', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Labot grāmatu :bookName', 'books_form_book_name' => 'Grāmatas nosaukums', 'books_save' => 'Saglabāt grāmatu', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Grāmatas atļaujas', 'books_permissions_updated' => 'Grāmatas atļaujas atjauninātas', 'books_empty_contents' => 'Lapas vai nodaļas vēl nav izveidotas šai grāmatai.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Dzēst melnrakstu', 'pages_delete_success' => 'Lapa ir dzēsta', 'pages_delete_draft_success' => 'Melnraksts ir dzēsts', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Vai esat pārliecināts, ka vēlaties dzēst šo lapu?', 'pages_delete_draft_confirm' => 'Vai esat pārliecināts, ka vēlaties dzēst šo melnrakstu?', 'pages_editing_named' => 'Rediģē lapu :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Atsauces', 'references_none' => 'Uz šo vienumu nav atrasta neviena atsauce.', - 'references_to_desc' => 'Zemāk parādītas visas sistēmā atrastās lapas, kas norāda uz šo vienumu.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/lv/errors.php b/lang/lv/errors.php index d85a4f7fc..72abed6e6 100644 --- a/lang/lv/errors.php +++ b/lang/lv/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'LDAP PHP paplašinājums nav instalēts', 'ldap_cannot_connect' => 'Nav iespējams pieslēgties LDAP serverim, sākotnējais pieslēgums neveiksmīgs', 'saml_already_logged_in' => 'Jau ielogojies', - 'saml_user_not_registered' => 'Lietotājs :name nav reģistrēts un automātiska reģistrācija ir izslēgta', 'saml_no_email_address' => 'Ārējās autentifikācijas sistēmas sniegtajos datos nevarēja atrast šī lietotāja e-pasta adresi', 'saml_invalid_response_id' => 'Ārējās autentifikācijas sistēmas pieprasījums neatpazīst procesu, kuru sākusi šī lietojumprogramma. Pārvietojoties atpakaļ pēc pieteikšanās var rasties šāda problēma.', 'saml_fail_authed' => 'Piekļuve ar :system neizdevās, sistēma nepieļāva veiksmīgu autorizāciju', diff --git a/lang/lv/notifications.php b/lang/lv/notifications.php index b1cc3b6de..d0fee3950 100644 --- a/lang/lv/notifications.php +++ b/lang/lv/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Lapas nosaukums:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Komentētājs:', 'detail_comment' => 'Komentārs:', 'detail_created_by' => 'Izveidoja:', diff --git a/lang/lv/settings.php b/lang/lv/settings.php index 0864c6b37..a443d4977 100644 --- a/lang/lv/settings.php +++ b/lang/lv/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Igauņu', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/nb/common.php b/lang/nb/common.php index bcbf8e13a..92950250f 100644 --- a/lang/nb/common.php +++ b/lang/nb/common.php @@ -44,8 +44,8 @@ return [ 'configure' => 'Konfigurer', 'manage' => 'Administrer', 'fullscreen' => 'Fullskjerm', - 'favourite' => 'Favorisér', - 'unfavourite' => 'Avfavorisér', + 'favourite' => 'Favoriser', + 'unfavourite' => 'Avfavoriser', 'next' => 'Neste', 'previous' => 'Forrige', 'filter_active' => 'Aktivt filter:', diff --git a/lang/nb/components.php b/lang/nb/components.php index 8a8c69f17..e424e6493 100644 --- a/lang/nb/components.php +++ b/lang/nb/components.php @@ -20,7 +20,7 @@ return [ 'image_uploaded_by' => 'Lastet opp av :userName', 'image_uploaded_to' => 'Lastet opp til :pageLink', 'image_updated' => 'Oppdatert :updateDate', - 'image_load_more' => 'Last in flere', + 'image_load_more' => 'Last inn flere', 'image_image_name' => 'Bildenavn', 'image_delete_used' => 'Dette bildet er brukt på sidene nedenfor.', 'image_delete_confirm_text' => 'Vil du slette dette bildet?', diff --git a/lang/nb/entities.php b/lang/nb/entities.php index 87fbf5138..b843fcc0d 100644 --- a/lang/nb/entities.php +++ b/lang/nb/entities.php @@ -23,9 +23,9 @@ return [ 'meta_updated' => 'Oppdatert :timeLength', 'meta_updated_name' => 'Oppdatert :timeLength av :user', 'meta_owned_name' => 'Eies av :user', - 'meta_reference_page_count' => 'Sitert på :count side|Sitert på :count sider', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Velg entitet', - 'entity_select_lack_permission' => 'Do har ikke tilgang til å velge dette elementet', + 'entity_select_lack_permission' => 'Du har ikke tilgang til å velge dette elementet', 'images' => 'Bilder', 'my_recent_drafts' => 'Mine nylige utkast', 'my_recently_viewed' => 'Mine nylige visninger', @@ -44,7 +44,7 @@ return [ 'permissions' => 'Tilganger', 'permissions_desc' => 'Endringer gjort her vil overstyre standardrettigheter gitt via brukerroller.', 'permissions_book_cascade' => 'Rettigheter satt på bøker vil automatisk arves ned til sidenivå. Du kan overstyre arv ved å definere egne rettigheter på kapitler eller sider.', - 'permissions_chapter_cascade' => 'Rettigheter satt på kapitler vi automatisk arves ned til sider. Du kan overstyre arv ved å definere rettigheter på enkeltsider.', + 'permissions_chapter_cascade' => 'Rettigheter satt på kapitler vil automatisk arves ned til sider. Du kan overstyre arv ved å definere rettigheter på enkeltsider.', 'permissions_save' => 'Lagre tillatelser', 'permissions_owner' => 'Eier', 'permissions_role_everyone_else' => 'Alle andre', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Endre boken :bookName', 'books_form_book_name' => 'Boktittel', 'books_save' => 'Lagre bok', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Boktilganger', 'books_permissions_updated' => 'Boktilganger oppdatert', 'books_empty_contents' => 'Ingen sider eller kapitler finnes i denne boken.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Slett utkastet', 'pages_delete_success' => 'Siden er slettet', 'pages_delete_draft_success' => 'Sideutkastet ble slettet', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Er du sikker på at du vil slette siden?', 'pages_delete_draft_confirm' => 'Er du sikker på at du vil slette utkastet?', 'pages_editing_named' => 'Redigerer :pageName (side)', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Referanser', 'references_none' => 'Det er ingen sporede referanser til dette elementet.', - 'references_to_desc' => 'Nedenfor vises alle de kjente sidene i systemet som lenker til denne oppføringen.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Overvåk', diff --git a/lang/nb/errors.php b/lang/nb/errors.php index 941158744..c167fd49a 100644 --- a/lang/nb/errors.php +++ b/lang/nb/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'LDAP PHP modulen er ikke installert.', 'ldap_cannot_connect' => 'Klarer ikke koble til LDAP på denne adressen', 'saml_already_logged_in' => 'Allerede logget inn', - 'saml_user_not_registered' => 'Kontoen med navn :name er ikke registert, registrering er også deaktivert.', 'saml_no_email_address' => 'Denne kontoinformasjonen finnes ikke i det eksterne autentiseringssystemet.', 'saml_invalid_response_id' => 'Forespørselen fra det eksterne autentiseringssystemet gjenkjennes ikke av en prosess som startes av dette programmet. Å navigere tilbake etter pålogging kan forårsake dette problemet.', 'saml_fail_authed' => 'Innlogging gjennom :system feilet. Fikk ikke kontakt med autentiseringstjeneren.', diff --git a/lang/nb/notifications.php b/lang/nb/notifications.php index 78aad7181..0d4bc266f 100644 --- a/lang/nb/notifications.php +++ b/lang/nb/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'For å forhindre mange varslinger, vil du ikke få nye varslinger for endringer på denne siden fra samme forfatter.', 'detail_page_name' => 'Sidenavn:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Kommentar fra:', 'detail_comment' => 'Kommentar:', 'detail_created_by' => 'Opprettet av:', diff --git a/lang/nb/settings.php b/lang/nb/settings.php index 9f607519e..5d038c4f7 100644 --- a/lang/nb/settings.php +++ b/lang/nb/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/nl/entities.php b/lang/nl/entities.php index a408aa1e5..48625edd6 100644 --- a/lang/nl/entities.php +++ b/lang/nl/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Bijgewerkt: :timeLength', 'meta_updated_name' => 'Bijgewerkt: :timeLength door :user', 'meta_owned_name' => 'Eigendom van :user', - 'meta_reference_page_count' => 'Naartoe verwezen op :count pagina|Naartoe verwezen op :count pagina\'s', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Entiteit selecteren', 'entity_select_lack_permission' => 'Je hebt niet de vereiste machtiging om dit item te selecteren', 'images' => 'Afbeeldingen', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Bewerk boek :bookName', 'books_form_book_name' => 'Boek naam', 'books_save' => 'Boek opslaan', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Boek machtigingen', 'books_permissions_updated' => 'Boek Machtigingen Bijgewerkt', 'books_empty_contents' => 'Er zijn nog geen hoofdstukken en pagina\'s voor dit boek gemaakt.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Verwijder concept pagina', 'pages_delete_success' => 'Pagina verwijderd', 'pages_delete_draft_success' => 'Concept verwijderd', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Weet je zeker dat je deze pagina wilt verwijderen?', 'pages_delete_draft_confirm' => 'Weet je zeker dat je dit concept wilt verwijderen?', 'pages_editing_named' => 'Pagina :pageName bewerken', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Verwijzingen', 'references_none' => 'Er zijn geen verwijzingen naar dit artikel bijgehouden.', - 'references_to_desc' => 'Hieronder staan alle gekende pagina\'s in het systeem die naar dit item linken.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Volg', diff --git a/lang/nl/errors.php b/lang/nl/errors.php index f30014702..7a026615a 100644 --- a/lang/nl/errors.php +++ b/lang/nl/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'LDAP PHP-extensie is niet geïnstalleerd', 'ldap_cannot_connect' => 'Kan geen verbinding maken met de ldap server, initiële verbinding is mislukt', 'saml_already_logged_in' => 'Reeds ingelogd', - 'saml_user_not_registered' => 'De gebruiker :name is niet geregistreerd en automatische registratie is uitgeschakeld', 'saml_no_email_address' => 'In de gegevens van het externe verificatiesysteem kon voor deze gebruiker geen e-mailadres gevonden worden', 'saml_invalid_response_id' => 'Het verzoek van het externe authenticatiesysteem wordt niet herkend door een proces dat door deze applicatie wordt gestart. Terugkeren na inloggen kan dit probleem veroorzaken.', 'saml_fail_authed' => 'Inloggen met :system mislukt, het systeem gaf geen succesvolle autorisatie', diff --git a/lang/nl/notifications.php b/lang/nl/notifications.php index 9e173dff5..79c7e7e8b 100644 --- a/lang/nl/notifications.php +++ b/lang/nl/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'Om een stortvloed aan meldingen te voorkomen, zul je een tijdje geen meldingen ontvangen voor verdere bewerkingen van deze pagina door dezelfde redacteur.', 'detail_page_name' => 'Pagina Naam:', + 'detail_page_path' => 'Paginapad:', 'detail_commenter' => 'Reageerder:', 'detail_comment' => 'Opmerking:', 'detail_created_by' => 'Gemaakt Door:', diff --git a/lang/nl/settings.php b/lang/nl/settings.php index 6ef1d4a3c..c6e2ad2ae 100644 --- a/lang/nl/settings.php +++ b/lang/nl/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel (Estisch)', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français (Frans)', 'he' => 'עברית (Hebreeuws)', 'hr' => 'Hrvatski (Kroatisch)', diff --git a/lang/nn/activities.php b/lang/nn/activities.php index 3545db129..dfb7043c4 100644 --- a/lang/nn/activities.php +++ b/lang/nn/activities.php @@ -41,7 +41,7 @@ return [ // Bookshelves 'bookshelf_create' => 'oppretta hylle', - 'bookshelf_create_notification' => 'Hylla vart opprettet', + 'bookshelf_create_notification' => 'Hylla vart oppretta', 'bookshelf_create_from_book' => 'endra frå bok til hylle', 'bookshelf_create_from_book_notification' => 'Boka vart konvertert til ei bokhylle', 'bookshelf_update' => 'oppdaterte hylle', @@ -59,7 +59,7 @@ return [ 'favourite_remove_notification' => '«:name» vart fjerna frå dine favorittar', // Watching - 'watch_update_level_notification' => 'Overvåkingsinnstillingene vart oppdatert', + 'watch_update_level_notification' => 'Overvakingsinnstillingane vart oppdatert', // Auth 'auth_login' => 'logga inn', @@ -103,7 +103,7 @@ return [ // Roles 'role_create' => 'oppretta rolle', 'role_create_notification' => 'Rolla vart oppretta', - 'role_update' => 'oppdatert rolla', + 'role_update' => 'oppdatert rolle', 'role_update_notification' => 'Rolla vart oppdatert', 'role_delete' => 'sletta rolla', 'role_delete_notification' => 'Rolla vart fjerna', diff --git a/lang/nn/auth.php b/lang/nn/auth.php index 615f7bb9c..a6ae5917a 100644 --- a/lang/nn/auth.php +++ b/lang/nn/auth.php @@ -40,78 +40,78 @@ return [ // Login auto-initiation 'auto_init_starting' => 'Prøver innlogging', - 'auto_init_starting_desc' => 'Me kontaktar autentiseringssystemet ditt for å starte innloggingsprosessen. Dersom det ikkje er noko fremdrift i løpet av fem sekunder kan du trykke på lenka under.', + 'auto_init_starting_desc' => 'Me kontaktar autentiseringssystemet ditt for å starte innloggingsprosessen. Dersom det ikkje er noko framdrift i løpet av fem sekunder kan du trykke på lenka under.', 'auto_init_start_link' => 'Fortsett med autentisering', // Password Reset 'reset_password' => 'Nullstill passord', 'reset_password_send_instructions' => 'Oppgi e-posten kobla til kontoen din, så sender me ein e-post der du kan nullstille passordet.', 'reset_password_send_button' => 'Send nullstillingslenke', - 'reset_password_sent' => 'Ein nullstillingslenke vart sendt til :email om den eksisterer i systemet.', + 'reset_password_sent' => 'Ei nullstillingslenke vart sendt til :email om den eksisterer i systemet.', 'reset_password_success' => 'Passordet vart nullstilt.', 'email_reset_subject' => 'Nullstill ditt :appName passord', 'email_reset_text' => 'Du mottar denne e-posten fordi det er blitt bedt om ei nullstilling av passord for denne kontoen.', - 'email_reset_not_requested' => 'Om det ikkje var deg, så trenger du ikkje gjere noko.', + 'email_reset_not_requested' => 'Om det ikkje var deg, så treng du ikkje gjere noko.', // Email Confirmation - 'email_confirm_subject' => 'Stadfest epost-adressa for :appName', + 'email_confirm_subject' => 'Stadfest e-postadressa for :appName', 'email_confirm_greeting' => 'Takk for at du registrerte deg på :appName!', 'email_confirm_text' => 'Stadfest e-posten din ved å trykke på knappen under:', 'email_confirm_action' => 'Stadfest e-post', - 'email_confirm_send_error' => 'Bekreftelse er krevd av systemet, men systemet kan ikke sende disse. Kontakt admin for å løse problemet.', - 'email_confirm_success' => 'Epost-adressen din er verifisert! Du kan nå logge inn ved å bruke denne ved innlogging.', - 'email_confirm_resent' => 'Bekreftelsespost ble sendt, sjekk innboksen din.', - 'email_confirm_thanks' => 'Takk for verifiseringen!', - 'email_confirm_thanks_desc' => 'Vent et øyeblikk mens verifiseringen blir utført. Om du ikke blir videresendt i løpet av tre sekunder kan du trykke «Fortsett» nedenfor.', + 'email_confirm_send_error' => 'Stadfesting er krevd av systemet, men systemet kan ikkje sende desse. Kontakt admin for å løyse problemet.', + 'email_confirm_success' => 'E-postadressa di er verifisert! Du kan no logge inn ved å bruke denne ved innlogging.', + 'email_confirm_resent' => 'Stadfesting sendt på e-post, sjekk innboksen din.', + 'email_confirm_thanks' => 'Takk for verifiseringa!', + 'email_confirm_thanks_desc' => 'Vent litt medan me verifiserer. Om du ikkje vert sendt vidare i løpet av tre sekunder, kan du klikke på "Fortsett" under.', - 'email_not_confirmed' => 'E-posten er ikke bekreftet.', - 'email_not_confirmed_text' => 'Epost-adressen er ennå ikke bekreftet.', - 'email_not_confirmed_click_link' => 'Trykk på lenken i e-posten du fikk vedrørende din registrering.', - 'email_not_confirmed_resend' => 'Om du ikke finner den i innboksen eller søppelboksen, kan du få tilsendt ny ved å trykke på knappen under.', - 'email_not_confirmed_resend_button' => 'Send bekreftelsespost på nytt', + 'email_not_confirmed' => 'E-posten er ikkje stadfesta', + 'email_not_confirmed_text' => 'E-postadressa er ennå ikkje stadfesta.', + 'email_not_confirmed_click_link' => 'Trykk på lenka i e-posten du fekk då du registrerte deg.', + 'email_not_confirmed_resend' => 'Finner du den ikkje i innboks eller useriøs e-post? Trykk på knappen under for å få ny.', + 'email_not_confirmed_resend_button' => 'Send stadfesting på e-post på nytt', // User Invite 'user_invite_email_subject' => 'Du har blitt invitert til :appName!', - 'user_invite_email_greeting' => 'En konto har blitt opprettet for deg på :appName.', - 'user_invite_email_text' => 'Trykk på knappen under for å opprette et sikkert passord:', - 'user_invite_email_action' => 'Angi passord', + 'user_invite_email_greeting' => 'Ein konto har blitt oppretta for deg på :appName.', + 'user_invite_email_text' => 'Trykk på knappen under for å opprette eit sikkert passord:', + 'user_invite_email_action' => 'Skriv inn passord', 'user_invite_page_welcome' => 'Velkommen til :appName!', - 'user_invite_page_text' => 'For å fullføre prosessen må du oppgi et passord som sikrer din konto på :appName for fremtidige besøk.', - 'user_invite_page_confirm_button' => 'Bekreft passord', - 'user_invite_success_login' => 'Passordet ble satt, du skal nå kunne logge inn med ditt nye passord for å få tilgang til :appName!', + 'user_invite_page_text' => 'For å fullføre prosessen må du oppgi eit passord som sikrar din konto på :appName for neste besøk.', + 'user_invite_page_confirm_button' => 'Stadfest passord', + 'user_invite_success_login' => 'Passordet vart lagra, du skal nå kunne logge inn med ditt nye passord for å få tilgang til :appName!', // Multi-factor Authentication - 'mfa_setup' => 'Konfigurer flerfaktor-autentisering', - 'mfa_setup_desc' => 'Konfigurer flerfaktor-autentisering som et ekstra lag med sikkerhet for brukerkontoen din.', - 'mfa_setup_configured' => 'Allerede konfigurert', - 'mfa_setup_reconfigure' => 'Omkonfigurer', - 'mfa_setup_remove_confirmation' => 'Er du sikker på at du vil deaktivere denne flerfaktor-autentiseringsmetoden?', + 'mfa_setup' => 'Konfigurer fleirfaktor-autentisering', + 'mfa_setup_desc' => 'Konfigurer fleirfaktor-autentisering som eit ekstra lag med tryggleik for brukarkontoen din.', + 'mfa_setup_configured' => 'Allereie konfigurert', + 'mfa_setup_reconfigure' => 'Konfigurer på nytt', + 'mfa_setup_remove_confirmation' => 'Er du sikker på at du vil deaktivere denne fleirfaktor-autentiseringsmetoden?', 'mfa_setup_action' => 'Konfigurasjon', - 'mfa_backup_codes_usage_limit_warning' => 'Du har mindre enn 5 sikkerhetskoder igjen; vennligst generer og lagre ett nytt sett før du går tom for koder, for å unngå å bli låst ute av kontoen din.', + 'mfa_backup_codes_usage_limit_warning' => 'Du har mindre enn 5 tryggleikskodar igjen; generer gjerne nye og lagre eit nytt sett før du går tom for kodar. Då slepper du å bli låst ute frå kontoen din.', 'mfa_option_totp_title' => 'Mobilapplikasjon', - 'mfa_option_totp_desc' => 'For å bruke flerfaktorautentisering trenger du en mobilapplikasjon som støtter TOTP-teknologien, slik som Google Authenticator, Authy eller Microsoft Authenticator.', - 'mfa_option_backup_codes_title' => 'Sikkerhetskoder', - 'mfa_option_backup_codes_desc' => 'Lagre sikkerhetskoder til engangsbruk på et trygt sted, disse kan du bruke for å verifisere identiteten din.', - 'mfa_gen_confirm_and_enable' => 'Bekreft og aktiver', - 'mfa_gen_backup_codes_title' => 'Konfigurasjon av sikkerhetskoder', - 'mfa_gen_backup_codes_desc' => 'Lagre nedeforstående liste med koder på et trygt sted. Når du skal ha tilgang til systemet kan du bruke en av disse som en faktor under innlogging.', - 'mfa_gen_backup_codes_download' => 'Last ned koder', - 'mfa_gen_backup_codes_usage_warning' => 'Hver kode kan kun brukes en gang', + 'mfa_option_totp_desc' => 'For å bruka fleirfaktorautentisering treng du ein mobilapplikasjon som støttar TOTP-teknologien, slik som Google Authenticator, Authy eller Microsoft Authenticator.', + 'mfa_option_backup_codes_title' => 'Tryggleikskodar', + 'mfa_option_backup_codes_desc' => 'Lagre tryggleiksskodar til eingongsbruk på ein trygg stad, desse kan du bruka for å verifisera identiteten din.', + 'mfa_gen_confirm_and_enable' => 'Stadfest og aktiver', + 'mfa_gen_backup_codes_title' => 'Konfigurasjon av tryggleikskodar', + 'mfa_gen_backup_codes_desc' => 'Lagre lista under med kodar på ein trygg stad. Når du skal ha tilgang til systemet kan du bruka ein av desse som ein faktor under innlogging.', + 'mfa_gen_backup_codes_download' => 'Last ned kodar', + 'mfa_gen_backup_codes_usage_warning' => 'Kvar kode kan berre brukast ein gong', 'mfa_gen_totp_title' => 'Oppsett for mobilapplikasjon', - 'mfa_gen_totp_desc' => 'For å bruke flerfaktorautentisering trenger du en mobilapplikasjon som støtter TOTP-teknologien, slik som Google Authenticator, Authy eller Microsoft Authenticator.', - 'mfa_gen_totp_scan' => 'Scan QR-koden nedenfor med valgt TOTP-applikasjon for å starte.', - 'mfa_gen_totp_verify_setup' => 'Bekreft oppsett', - 'mfa_gen_totp_verify_setup_desc' => 'Bekreft at oppsettet fungerer ved å skrive inn koden fra TOTP-applikasjonen i boksen nedenfor:', + 'mfa_gen_totp_desc' => 'For å bruka fleirfaktorautentisering treng du ein mobilapplikasjon som støttar TOTP-teknologien, slik som Google Authenticator, Authy eller Microsoft Authenticator.', + 'mfa_gen_totp_scan' => 'Scan QR-koden nedanfor med vald TOTP-applikasjon for å starta.', + 'mfa_gen_totp_verify_setup' => 'Stadfest oppsett', + 'mfa_gen_totp_verify_setup_desc' => 'Stadfest at oppsettet fungerer ved å skrive inn koden fra TOTP-applikasjonen i boksen nedanfor:', 'mfa_gen_totp_provide_code_here' => 'Skriv inn den genererte koden her', - 'mfa_verify_access' => 'Bekreft tilgang', - 'mfa_verify_access_desc' => 'Brukerkontoen din krever at du bekrefter din identitet med en ekstra autentiseringsfaktor før du får tilgang. Bekreft identiteten med en av dine konfigurerte metoder for å fortsette.', - 'mfa_verify_no_methods' => 'Ingen metoder er konfigurert', - 'mfa_verify_no_methods_desc' => 'Ingen flerfaktorautentiseringsmetoder er satt opp for din konto. Du må sette opp minst en metode for å få tilgang.', - 'mfa_verify_use_totp' => 'Bekreft med mobilapplikasjon', - 'mfa_verify_use_backup_codes' => 'Bekreft med sikkerhetskode', - 'mfa_verify_backup_code' => 'Sikkerhetskode', - 'mfa_verify_backup_code_desc' => 'Skriv inn en av dine ubrukte sikkerhetskoder under:', - 'mfa_verify_backup_code_enter_here' => 'Skriv inn sikkerhetskode her', - 'mfa_verify_totp_desc' => 'Skriv inn koden, generert ved hjelp av mobilapplikasjonen, nedenfor:', - 'mfa_setup_login_notification' => 'Flerfaktorautentisering er konfigurert, vennligst logg inn på nytt med denne metoden.', + 'mfa_verify_access' => 'Stadfest tilgang', + 'mfa_verify_access_desc' => 'Brukarkontoen din krev at du stadfestar identiteten din med ein ekstra autentiseringsfaktor før du får tilgang. Stadfest identiteten med ein av dine konfigurerte metodar for å halda fram.', + 'mfa_verify_no_methods' => 'Ingen metodar er konfigurert', + 'mfa_verify_no_methods_desc' => 'Ingen fleirfaktorautentiseringsmetoder er satt opp for din konto. Du må setje opp minst ein metode for å få tilgang.', + 'mfa_verify_use_totp' => 'Stadfest med mobilapplikasjon', + 'mfa_verify_use_backup_codes' => 'Stadfest med tryggleikskode', + 'mfa_verify_backup_code' => 'Tryggleikskode', + 'mfa_verify_backup_code_desc' => 'Skriv inn ein av dei ubrukte tryggleikskodane dine under:', + 'mfa_verify_backup_code_enter_here' => 'Skriv inn tryggleikskode her', + 'mfa_verify_totp_desc' => 'Skriv inn koden, generert ved hjelp av mobilapplikasjonen, nedanfor:', + 'mfa_setup_login_notification' => 'Fleirfaktorautentisering er konfigurert, vennlegast logg inn på nytt med denne metoden.', ]; diff --git a/lang/nn/common.php b/lang/nn/common.php index d817fc355..74b39efa2 100644 --- a/lang/nn/common.php +++ b/lang/nn/common.php @@ -7,23 +7,23 @@ return [ // Buttons 'cancel' => 'Avbryt', 'close' => 'Lukk', - 'confirm' => 'Bekreft', + 'confirm' => 'Stadfest', 'back' => 'Tilbake', 'save' => 'Lagre', 'continue' => 'Fortsett', - 'select' => 'Velg', - 'toggle_all' => 'Bytt alle', - 'more' => 'Mer', + 'select' => 'Vel', + 'toggle_all' => 'Byt alle', + 'more' => 'Meir', // Form Labels - 'name' => 'Navn', - 'description' => 'Beskrivelse', + 'name' => 'Namn', + 'description' => 'Skildring', 'role' => 'Rolle', - 'cover_image' => 'Forside', - 'cover_image_description' => 'Bildet bør være ca. 440x250px.', + 'cover_image' => 'Framside', + 'cover_image_description' => 'Bilete bør vere ca. 440x250px.', // Actions - 'actions' => 'Handlinger', + 'actions' => 'Handlingar', 'view' => 'Vis', 'view_all' => 'Vis alle', 'new' => 'Ny', @@ -35,7 +35,7 @@ return [ 'copy' => 'Kopier', 'reply' => 'Svar', 'delete' => 'Slett', - 'delete_confirm' => 'Bekreft sletting', + 'delete_confirm' => 'Stadfest sletting', 'search' => 'Søk', 'search_clear' => 'Nullstill søk', 'reset' => 'Nullstill', @@ -44,39 +44,39 @@ return [ 'configure' => 'Konfigurer', 'manage' => 'Administrer', 'fullscreen' => 'Fullskjerm', - 'favourite' => 'Favorisér', - 'unfavourite' => 'Avfavorisér', + 'favourite' => 'Merk som favoritt', + 'unfavourite' => 'Fjern som favoritt', 'next' => 'Neste', - 'previous' => 'Forrige', + 'previous' => 'Førre', 'filter_active' => 'Aktivt filter:', 'filter_clear' => 'Tøm filter', 'download' => 'Last ned', - 'open_in_tab' => 'Åpne i fane', + 'open_in_tab' => 'Opne i fane', 'open' => 'Opne', // Sort Options - 'sort_options' => 'Sorteringsalternativer', + 'sort_options' => 'Sorteringsalternativ', 'sort_direction_toggle' => 'Sorteringsretning', - 'sort_ascending' => 'Stigende sortering', - 'sort_descending' => 'Synkende sortering', - 'sort_name' => 'Navn', + 'sort_ascending' => 'Stigande sortering', + 'sort_descending' => 'Synkande sortering', + 'sort_name' => 'Namn', 'sort_default' => 'Standard', - 'sort_created_at' => 'Dato opprettet', + 'sort_created_at' => 'Dato oppretta', 'sort_updated_at' => 'Dato oppdatert', // Misc - 'deleted_user' => 'Slett bruker', + 'deleted_user' => 'Slett brukar', 'no_activity' => 'Ingen aktivitet å vise', - 'no_items' => 'Ingen ting å vise', - 'back_to_top' => 'Hopp til toppen', - 'skip_to_main_content' => 'Gå til hovedinnhold', - 'toggle_details' => 'Vis/skjul detaljer', - 'toggle_thumbnails' => 'Vis/skjul miniatyrbilder', - 'details' => 'Detaljer', - 'grid_view' => 'Rutenettvisning', - 'list_view' => 'Listevisning', + 'no_items' => 'Ingenting å vise', + 'back_to_top' => 'Tilbake til toppen', + 'skip_to_main_content' => 'Gå til hovudinnhald', + 'toggle_details' => 'Vis/skjul detaljar', + 'toggle_thumbnails' => 'Vis/skjul miniatyrbilete', + 'details' => 'Detaljar', + 'grid_view' => 'Rutenettvising', + 'list_view' => 'Listevising', 'default' => 'Standard', - 'breadcrumb' => 'Brødsmuler', + 'breadcrumb' => 'Brødsmular', 'status' => 'Status', 'status_active' => 'Aktiv', 'status_inactive' => 'Inaktiv', @@ -84,11 +84,11 @@ return [ 'none' => 'Ingen', // Header - 'homepage' => 'Hjemmeside', + 'homepage' => 'Heimeside', 'header_menu_expand' => 'Utvid toppmeny', 'profile_menu' => 'Profilmeny', 'view_profile' => 'Vis profil', - 'edit_profile' => 'Endre Profile', + 'edit_profile' => 'Endre profil', 'dark_mode' => 'Kveldsmodus', 'light_mode' => 'Dagmodus', 'global_search' => 'Globalt søk', @@ -96,15 +96,15 @@ return [ // Layout tabs 'tab_info' => 'Informasjon', 'tab_info_label' => 'Fane: Vis tilleggsinfo', - 'tab_content' => 'Innhold', - 'tab_content_label' => 'Fane: Vis hovedinnhold', + 'tab_content' => 'Innhald', + 'tab_content_label' => 'Fane: Vis hovudinnhald', // Email Content - 'email_action_help' => 'Om du har problemer med å trykke på «:actionText»-knappen, bruk nettadressen under for å gå direkte dit:', - 'email_rights' => 'Kopibeskyttet', + 'email_action_help' => 'Om du har problem med å trykkja på ":actionText"-knappen, bruk nettadressa under for å gå direkte dit:', + 'email_rights' => 'Kopibeskytta', // Footer Link Options // Not directly used but available for convenience to users. - 'privacy_policy' => 'Personvernregler', + 'privacy_policy' => 'Personvernreglar', 'terms_of_service' => 'Bruksvilkår', ]; diff --git a/lang/nn/components.php b/lang/nn/components.php index 20abbc3af..881156427 100644 --- a/lang/nn/components.php +++ b/lang/nn/components.php @@ -5,42 +5,42 @@ return [ // Image Manager - 'image_select' => 'Velg bilde', - 'image_list' => 'Bilde liste', - 'image_details' => 'Bildedetaljer', - 'image_upload' => 'Last opp bilde', - 'image_intro' => 'Her kan du velge og behandle bilder som tidligere har blitt lastet opp til systemet.', - 'image_intro_upload' => 'Last opp et nytt bilde ved å dra et bilde i dette vinduet, eller ved å bruke knappen "Last opp bilde" ovenfor.', + 'image_select' => 'Vel bilete', + 'image_list' => 'Bileteliste', + 'image_details' => 'Biletedetaljar', + 'image_upload' => 'Last opp bilete', + 'image_intro' => 'Her kan du velja og behandla bilete som tidlegare har vorte lasta opp til systemet.', + 'image_intro_upload' => 'Last opp eit nytt bilete ved å dra eit bilete i dette vindauget, eller ved å bruka knappen "Last opp bilete" ovanfor.', 'image_all' => 'Alle', - 'image_all_title' => 'Vis alle bilder', - 'image_book_title' => 'Vis bilder som er lastet opp i denne boken', - 'image_page_title' => 'Vis bilder lastet opp til denne siden', - 'image_search_hint' => 'Søk på bilder etter navn', - 'image_uploaded' => 'Opplastet :uploadedDate', - 'image_uploaded_by' => 'Lastet opp av :userName', - 'image_uploaded_to' => 'Lastet opp til :pageLink', + 'image_all_title' => 'Vis alle bilete', + 'image_book_title' => 'Vis bilete som er lasta opp i denne boka', + 'image_page_title' => 'Vis bilete lastet opp til denne sida', + 'image_search_hint' => 'Søk på bilete etter namn', + 'image_uploaded' => 'Lasta opp :uploadedDate', + 'image_uploaded_by' => 'Lasta opp av :userName', + 'image_uploaded_to' => 'Lasta opp til :pageLink', 'image_updated' => 'Oppdatert :updateDate', - 'image_load_more' => 'Last in flere', - 'image_image_name' => 'Bildenavn', - 'image_delete_used' => 'Dette bildet er brukt på sidene nedenfor.', - 'image_delete_confirm_text' => 'Vil du slette dette bildet?', - 'image_select_image' => 'Velg bilde', - 'image_dropzone' => 'Dra og slipp eller trykk her for å laste opp bilder', - 'image_dropzone_drop' => 'Slipp bilder her for å laste opp', - 'images_deleted' => 'Bilder slettet', - 'image_preview' => 'Hurtigvisning av bilder', - 'image_upload_success' => 'Bilde ble lastet opp', - 'image_update_success' => 'Bildedetaljer ble oppdatert', - 'image_delete_success' => 'Bilde ble slettet', - 'image_replace' => 'Erstatt bilde', - 'image_replace_success' => 'Bildefil ble oppdatert', + 'image_load_more' => 'Last inn fleire', + 'image_image_name' => 'Biletenavn', + 'image_delete_used' => 'Dette biletet er brukt på sidene nedanfor.', + 'image_delete_confirm_text' => 'Vil du slette dette biletet?', + 'image_select_image' => 'Velg bilete', + 'image_dropzone' => 'Dra og slepp eller trykk her for å laste opp bilete', + 'image_dropzone_drop' => 'Slepp bilete her for å laste opp', + 'images_deleted' => 'Bilete sletta', + 'image_preview' => 'Snøggvising av bilete', + 'image_upload_success' => 'Bilete vart lasta opp', + 'image_update_success' => 'Biletedetaljar vart oppdatert', + 'image_delete_success' => 'Bilete vart sletta', + 'image_replace' => 'Erstatt bilete', + 'image_replace_success' => 'Biletefil vart oppdatert', 'image_rebuild_thumbs' => 'Regenerer ulike storleikar', 'image_rebuild_thumbs_success' => 'Bilete i ulike storleikar vart bygd på nytt!', // Code Editor 'code_editor' => 'Endre kode', 'code_language' => 'Kodespråk', - 'code_content' => 'Kodeinnhold', + 'code_content' => 'Kodeinnhald', 'code_session_history' => 'Sesjonshistorikk', 'code_save' => 'Lagre kode', ]; diff --git a/lang/nn/entities.php b/lang/nn/entities.php index bed008b73..f2ad69677 100644 --- a/lang/nn/entities.php +++ b/lang/nn/entities.php @@ -6,76 +6,76 @@ return [ // Shared - 'recently_created' => 'Nylig opprettet', - 'recently_created_pages' => 'Nylig opprettede sider', - 'recently_updated_pages' => 'Nylig oppdaterte sider', - 'recently_created_chapters' => 'Nylig opprettede kapitler', - 'recently_created_books' => 'Nylig opprettede bøker', - 'recently_created_shelves' => 'Nylig opprettede bokhyller', - 'recently_update' => 'Nylig oppdatert', - 'recently_viewed' => 'Nylig vist', - 'recent_activity' => 'Nylig aktivitet', - 'create_now' => 'Opprett en nå', - 'revisions' => 'Revisjoner', + 'recently_created' => 'Nylig oppretta', + 'recently_created_pages' => 'Nyleg oppretta sider', + 'recently_updated_pages' => 'Nyleg oppdaterte sider', + 'recently_created_chapters' => 'Nyleg oppretta kapitler', + 'recently_created_books' => 'Nyleg oppretta bøker', + 'recently_created_shelves' => 'Nyleg oppretta bokhyller', + 'recently_update' => 'Nyleg oppdatert', + 'recently_viewed' => 'Nyleg vist', + 'recent_activity' => 'Nyleg aktivitet', + 'create_now' => 'Opprett ein no', + 'revisions' => 'Revisjonar', 'meta_revision' => 'Revisjon #:revisionCount', - 'meta_created' => 'Opprettet :timeLength', - 'meta_created_name' => 'Opprettet :timeLength av :user', + 'meta_created' => 'Oppretta :timeLength', + 'meta_created_name' => 'Oppretta :timeLength av :user', 'meta_updated' => 'Oppdatert :timeLength', 'meta_updated_name' => 'Oppdatert :timeLength av :user', - 'meta_owned_name' => 'Eies av :user', - 'meta_reference_page_count' => 'Sitert på :count side|Sitert på :count sider', + 'meta_owned_name' => 'Eigd av :user', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Velg entitet', - 'entity_select_lack_permission' => 'Do har ikke tilgang til å velge dette elementet', - 'images' => 'Bilder', - 'my_recent_drafts' => 'Mine nylige utkast', - 'my_recently_viewed' => 'Mine nylige visninger', - 'my_most_viewed_favourites' => 'Mine mest sette favoritter', - 'my_favourites' => 'Mine favoritter', - 'no_pages_viewed' => 'Du har ikke sett på noen sider', - 'no_pages_recently_created' => 'Ingen sider har nylig blitt opprettet', + 'entity_select_lack_permission' => 'Du har ikkje tilgang til å velge dette elementet', + 'images' => 'Bilete', + 'my_recent_drafts' => 'Mine nylege utkast', + 'my_recently_viewed' => 'Mine nylege visingar', + 'my_most_viewed_favourites' => 'Mine mest sette favorittar', + 'my_favourites' => 'Mine favorittar', + 'no_pages_viewed' => 'Du har ikkje sett på nokre sider', + 'no_pages_recently_created' => 'Ingen sider har nylig blitt oppretta', 'no_pages_recently_updated' => 'Ingen sider har nylig blitt oppdatert', 'export' => 'Eksporter', 'export_html' => 'Nettside med alt', - 'export_pdf' => 'PDF Fil', + 'export_pdf' => 'PDF-fil', 'export_text' => 'Tekstfil', 'export_md' => 'Markdownfil', // Permissions and restrictions - 'permissions' => 'Tilganger', - 'permissions_desc' => 'Endringer gjort her vil overstyre standardrettigheter gitt via brukerroller.', - 'permissions_book_cascade' => 'Rettigheter satt på bøker vil automatisk arves ned til sidenivå. Du kan overstyre arv ved å definere egne rettigheter på kapitler eller sider.', - 'permissions_chapter_cascade' => 'Rettigheter satt på kapitler vi automatisk arves ned til sider. Du kan overstyre arv ved å definere rettigheter på enkeltsider.', - 'permissions_save' => 'Lagre tillatelser', - 'permissions_owner' => 'Eier', + 'permissions' => 'Tilgongar', + 'permissions_desc' => 'Endringar gjort her vil overstyra standardrettar gitt via brukarroller.', + 'permissions_book_cascade' => 'Rettar sett på bøker vil automatisk arvast ned til sidenivå. Du kan overstyra arv ved å definera eigne rettar på kapittel eller sider.', + 'permissions_chapter_cascade' => 'Rettar sett på kapittel vil automatisk arvast ned til sider. Du kan overstyra arv ved å definera rettar på enkeltsider.', + 'permissions_save' => 'Lagre løyve', + 'permissions_owner' => 'Eigar', 'permissions_role_everyone_else' => 'Alle andre', - 'permissions_role_everyone_else_desc' => 'Angi rettigheter for alle roller som ikke blir overstyrt (arvede rettigheter).', - 'permissions_role_override' => 'Overstyr rettigheter for rolle', - 'permissions_inherit_defaults' => 'Arv standardrettigheter', + 'permissions_role_everyone_else_desc' => 'Angi rettar for alle roller som ikkje blir overstyrt (arva rettar).', + 'permissions_role_override' => 'Overstyr rettar for rolle', + 'permissions_inherit_defaults' => 'Arv standardrettar', // Search - 'search_results' => 'Søkeresultater', - 'search_total_results_found' => ':count resultater funnet|:count totalt', + 'search_results' => 'Søkeresultat', + 'search_total_results_found' => ':count resultat funne|:count totalt', 'search_clear' => 'Nullstill søk', - 'search_no_pages' => 'Ingen sider passer med søket', + 'search_no_pages' => 'Ingen sider passar med søket', 'search_for_term' => 'Søk etter :term', - 'search_more' => 'Flere resultater', + 'search_more' => 'Fleire resultat', 'search_advanced' => 'Avansert søk', 'search_terms' => 'Søkeord', - 'search_content_type' => 'Innholdstype', + 'search_content_type' => 'Innhaldstype', 'search_exact_matches' => 'Eksakte ord', - 'search_tags' => 'Søk på merker', - 'search_options' => 'ALternativer', + 'search_tags' => 'Søk på merke', + 'search_options' => 'Alternativ', 'search_viewed_by_me' => 'Sett av meg', - 'search_not_viewed_by_me' => 'Ikke sett av meg', - 'search_permissions_set' => 'Tilganger er angitt', - 'search_created_by_me' => 'Opprettet av meg', + 'search_not_viewed_by_me' => 'Ikkje sett av meg', + 'search_permissions_set' => 'Tilgongar er sett', + 'search_created_by_me' => 'Oppretta av meg', 'search_updated_by_me' => 'Oppdatert av meg', - 'search_owned_by_me' => 'Eid av meg', - 'search_date_options' => 'Datoalternativer', + 'search_owned_by_me' => 'Eigd av meg', + 'search_date_options' => 'Datoalternativ', 'search_updated_before' => 'Oppdatert før', 'search_updated_after' => 'Oppdatert etter', - 'search_created_before' => 'Opprettet før', - 'search_created_after' => 'Opprettet etter', + 'search_created_before' => 'Oppretta før', + 'search_created_after' => 'Oppretta etter', 'search_set_date' => 'Angi dato', 'search_update' => 'Oppdater søk', @@ -83,34 +83,34 @@ return [ 'shelf' => 'Hylle', 'shelves' => 'Hyller', 'x_shelves' => ':count hylle|:count hyller', - 'shelves_empty' => 'Ingen bokhyller er opprettet', + 'shelves_empty' => 'Ingen bokhyller er oppretta', 'shelves_create' => 'Opprett ny bokhylle', 'shelves_popular' => 'Populære bokhyller', 'shelves_new' => 'Nye bokhyller', 'shelves_new_action' => 'Ny bokhylle', - 'shelves_popular_empty' => 'De mest populære bokhyllene blir vist her.', + 'shelves_popular_empty' => 'Dei mest populære bokhyllene blir vist her.', 'shelves_new_empty' => 'Nylig opprettede bokhyller vises her.', 'shelves_save' => 'Lagre hylle', - 'shelves_books' => 'Bøker på denne hyllen', + 'shelves_books' => 'Bøker på denne hylla', 'shelves_add_books' => 'Legg til bøker på denne hyllen', - 'shelves_drag_books' => 'Dra og slipp bøker nedenfor for å legge dem til i denne hyllen', + 'shelves_drag_books' => 'Dra og slepp bøker nedanfor for å legge dei til i denne hylla', 'shelves_empty_contents' => 'Ingen bøker er stabla i denne hylla', 'shelves_edit_and_assign' => 'Endre hylla for å legge til bøker', 'shelves_edit_named' => 'Rediger :name (hylle)', 'shelves_edit' => 'Rediger hylle', 'shelves_delete' => 'Fjern hylle', 'shelves_delete_named' => 'Fjern :name (hylle)', - 'shelves_delete_explain' => "Dette vil fjerne hyllen «:name». Bøkene på hyllen vil ikke bli slettet fra systemet.", - 'shelves_delete_confirmation' => 'Er du sikker på at du vil fjerne denne hyllen?', - 'shelves_permissions' => 'Hyllerettigheter', - 'shelves_permissions_updated' => 'Oppdaterte hyllerettigheter', - 'shelves_permissions_active' => 'Aktiverte hyllerettigheter', - 'shelves_permissions_cascade_warning' => 'Rettigheter på en hylle blir ikke automatisk arvet av bøker på hylla. Dette er fordi en bok kan finnes på flere hyller samtidig. Rettigheter kan likevel kopieres til bøker på hylla ved å bruke alternativene under.', - 'shelves_permissions_create' => 'Bokhylle-tillatelser brukes kun for kopiering av tillatelser til under-bøker ved hjelp av handlingen nedenfor. De kontrollerer ikke muligheten til å lage bøker.', - 'shelves_copy_permissions_to_books' => 'Kopier tilganger til bøkene på hylla', - 'shelves_copy_permissions' => 'Kopier tilganger', - 'shelves_copy_permissions_explain' => 'Dette vil kopiere rettighetene på denne hylla til alle bøkene som er plassert på den. Før du starter kopieringen bør du sjekke at rettighetene på hylla er lagret først.', - 'shelves_copy_permission_success' => 'Rettighetene ble kopiert til :count bøker', + 'shelves_delete_explain' => "Dette vil fjerne hylla «:name». Bøkene på hylla vil ikkje bli sletta frå systemet.", + 'shelves_delete_confirmation' => 'Er du sikker på at du vil fjerne denne hylla?', + 'shelves_permissions' => 'Hylletilgangar', + 'shelves_permissions_updated' => 'Oppdaterte hylletilgangar', + 'shelves_permissions_active' => 'Aktiverte hylletilgangar', + 'shelves_permissions_cascade_warning' => 'Tilgangar på ei hylle vert ikkje automatisk arva av bøker på hylla. Dette er fordi ei bok kan finnast på fleire hyller samstundes. Tilgangar kan likevel verte kopiert til bøker på hylla ved å bruke alternativa under.', + 'shelves_permissions_create' => 'Bokhylle-tilgangar vert brukt for kopiering av løyver til under-bøker ved hjelp av handlinga nedanfor. Dei kontrollerer ikkje rettane til å lage bøker.', + 'shelves_copy_permissions_to_books' => 'Kopier tilgangar til bøkene på hylla', + 'shelves_copy_permissions' => 'Kopier tilgangar', + 'shelves_copy_permissions_explain' => 'Dette vil kopiere tilgangar på denne hylla til alle bøkene som er plassert på den. Før du starter kopieringen bør du sjekke at tilgangane på hylla er lagra.', + 'shelves_copy_permission_success' => 'Løyver vart kopiert til :count bøker', // Books 'book' => 'Bok', @@ -132,58 +132,61 @@ return [ 'books_edit_named' => 'Endre boken :bookName', 'books_form_book_name' => 'Boktittel', 'books_save' => 'Lagre bok', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Boktilganger', 'books_permissions_updated' => 'Boktilganger oppdatert', - 'books_empty_contents' => 'Ingen sider eller kapitler finnes i denne boken.', - 'books_empty_create_page' => 'Skriv en ny side', - 'books_empty_sort_current_book' => 'Sorter innholdet i boken', + 'books_empty_contents' => 'Ingen sider eller kapittel finst i denne boka.', + 'books_empty_create_page' => 'Skriv ei ny side', + 'books_empty_sort_current_book' => 'Sorter innhaldet i boka', 'books_empty_add_chapter' => 'Start på nytt kapittel', - 'books_permissions_active' => 'Boktilganger er aktive', - 'books_search_this' => 'Søk i boken', + 'books_permissions_active' => 'Boktilgangar er aktive', + 'books_search_this' => 'Søk i boka', 'books_navigation' => 'Boknavigasjon', - 'books_sort' => 'Sorter bokinnhold', - 'books_sort_desc' => 'Flytt kapitler og sider inni en bok for å omorganisere dem. Andre bøker kan bli lagt til slik at det er enklere å flytte frem og tilbake mellom dem.', - 'books_sort_named' => 'Omorganisér :bookName (bok)', - 'books_sort_name' => 'Sorter på navn', - 'books_sort_created' => 'Sorter på opprettet dato', + 'books_sort' => 'Sorter bokinnhald', + 'books_sort_desc' => 'Flytt kapittel og sider i ei bok for å omorganisere dei. Andre bøker kan bli lagt til slik at det er enklere å flytte fram og tilbake mellom dei.', + 'books_sort_named' => 'Omorganiser :bookName', + 'books_sort_name' => 'Sorter på namn', + 'books_sort_created' => 'Sorter på oppretta dato', 'books_sort_updated' => 'Sorter på oppdatert dato', - 'books_sort_chapters_first' => 'Kapitler først', - 'books_sort_chapters_last' => 'Kapitler sist', + 'books_sort_chapters_first' => 'Kapittel først', + 'books_sort_chapters_last' => 'Kapittel sist', 'books_sort_show_other' => 'Vis andre bøker', 'books_sort_save' => 'Lagre sortering', - 'books_sort_show_other_desc' => 'Legg til andre bøker her for å inkludere dem i omorganiseringen og muliggjør enkel flytting på tvers av dem.', + 'books_sort_show_other_desc' => 'Legg til andre bøker her for å inkludere dei i omorganiseringa og gjer det enklare å flytte på tvers av dei.', 'books_sort_move_up' => 'Flytt opp', 'books_sort_move_down' => 'Flytt ned', - 'books_sort_move_prev_book' => 'Flytt til forrige bok', + 'books_sort_move_prev_book' => 'Flytt til førre bok', 'books_sort_move_next_book' => 'Flytt til neste bok', - 'books_sort_move_prev_chapter' => 'Flytt inn i forrige kapittel', + 'books_sort_move_prev_chapter' => 'Flytt inn i førre kapittel', 'books_sort_move_next_chapter' => 'Flytt inn i neste kapittel', - 'books_sort_move_book_start' => 'Flytt til starten av boken', - 'books_sort_move_book_end' => 'Flytt til slutten av boken', + 'books_sort_move_book_start' => 'Flytt til starten av boka', + 'books_sort_move_book_end' => 'Flytt til slutten av boka', 'books_sort_move_before_chapter' => 'Flytt før kapittel', 'books_sort_move_after_chapter' => 'Flytt etter kapittel', - 'books_copy' => 'Kopiér bok', - 'books_copy_success' => 'Boken ble kopiert', + 'books_copy' => 'Kopier bok', + 'books_copy_success' => 'Boka vart kopiert', // Chapters 'chapter' => 'Kapittel', - 'chapters' => 'Kapitler', - 'x_chapters' => ':count kapittel|:count kapitler', - 'chapters_popular' => 'Populære kapitler', + 'chapters' => 'Kapittel', + 'x_chapters' => ':count kapittel|:count kapittel', + 'chapters_popular' => 'Populære kapittel', 'chapters_new' => 'Nytt kapittel', 'chapters_create' => 'Skriv nytt kapittel', 'chapters_delete' => 'Riv ut kapittel', - 'chapters_delete_named' => 'Slett :chapterName (kapittel)', - 'chapters_delete_explain' => 'Dette vil slette «:chapterName» (kapittel). Alle sider i kapittelet vil også slettes.', + 'chapters_delete_named' => 'Slett :chapterName', + 'chapters_delete_explain' => 'Dette vil slette «:chapterName». Alle sider i kapittelet vil og verte sletta.', 'chapters_delete_confirm' => 'Er du sikker på at du vil slette dette kapittelet?', - 'chapters_edit' => 'Redigér kapittel', - 'chapters_edit_named' => 'Redigér :chapterName (kapittel)', + 'chapters_edit' => 'Rediger kapittel', + 'chapters_edit_named' => 'Rediger :chapterName', 'chapters_save' => 'Lagre kapittel', 'chapters_move' => 'Flytt kapittel', - 'chapters_move_named' => 'Flytt :chapterName (kapittel)', - 'chapters_copy' => 'Kopiér kapittel', - 'chapters_copy_success' => 'Kapitelet ble kopiert', - 'chapters_permissions' => 'Kapitteltilganger', + 'chapters_move_named' => 'Flytt :chapterName', + 'chapters_copy' => 'Kopier kapittel', + 'chapters_copy_success' => 'Kapittelet vart kopiert', + 'chapters_permissions' => 'Kapitteltilgongar', 'chapters_empty' => 'Det finnes ingen sider i dette kapittelet.', 'chapters_permissions_active' => 'Kapitteltilganger er aktivert', 'chapters_permissions_success' => 'Kapitteltilgager er oppdatert', @@ -203,7 +206,8 @@ return [ 'pages_delete_draft_named' => 'Slett utkastet :pageName (side)', 'pages_delete_draft' => 'Slett utkastet', 'pages_delete_success' => 'Siden er slettet', - 'pages_delete_draft_success' => 'Sideutkastet ble slettet', + 'pages_delete_draft_success' => 'Sideutkastet vart sletta', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Er du sikker på at du vil slette siden?', 'pages_delete_draft_confirm' => 'Er du sikker på at du vil slette utkastet?', 'pages_editing_named' => 'Redigerer :pageName (side)', @@ -221,54 +225,54 @@ return [ 'pages_edit_switch_to_markdown_stable' => '(Urørt innhold)', 'pages_edit_switch_to_wysiwyg' => 'Bytt til WYSIWYG tekstredigering', 'pages_edit_set_changelog' => 'Angi endringslogg', - 'pages_edit_enter_changelog_desc' => 'Gi en kort beskrivelse av endringene dine', - 'pages_edit_enter_changelog' => 'Se endringslogg', + 'pages_edit_enter_changelog_desc' => 'Gi ei kort skildring av endringane dine', + 'pages_edit_enter_changelog' => 'Sjå endringslogg', 'pages_editor_switch_title' => 'Bytt tekstredigeringsprogram', - 'pages_editor_switch_are_you_sure' => 'Er du sikker på at du vil bytte tekstredigeringsprogram for denne siden?', - 'pages_editor_switch_consider_following' => 'Husk dette når du bytter tekstredigeringsprogram:', - 'pages_editor_switch_consideration_a' => 'Når du bytter, vil den nye tekstredigereren bli satt for alle fremtidige redaktører. Dette inkluderer alle redaktører som ikke kan endre type selv.', - 'pages_editor_switch_consideration_b' => 'Dette kan potensielt føre til tap av formatdetaljer eller syntaks i noen tilfeller.', - 'pages_editor_switch_consideration_c' => 'Etikett- eller redigeringslogg-endringer loggført siden siste lagring vil ikke føres videre etter endringen.', + 'pages_editor_switch_are_you_sure' => 'Er du sikker på at du vil bytte tekstredigeringsprogram for denne sida?', + 'pages_editor_switch_consider_following' => 'Hugs dette når du byttar tekstredigeringsprogram:', + 'pages_editor_switch_consideration_a' => 'Når du bytter, vil den nye tekstredigeraren bli valgt for alle framtidige redaktørar. Dette inkluderer alle redaktørar som ikkje kan endre type sjølv.', + 'pages_editor_switch_consideration_b' => 'I visse tilfeller kan det føre til tap av detaljar og syntaks.', + 'pages_editor_switch_consideration_c' => 'Etikett- eller redigeringslogg-endringar loggført sidan siste lagring vil ikkje føres vidare etter endringa.', 'pages_save' => 'Lagre side', 'pages_title' => 'Sidetittel', - 'pages_name' => 'Sidenavn', - 'pages_md_editor' => 'Tekstbehandler', - 'pages_md_preview' => 'Forhåndsvisning', - 'pages_md_insert_image' => 'Sett inn bilde', + 'pages_name' => 'Sidenamn', + 'pages_md_editor' => 'Tekstbehandlar', + 'pages_md_preview' => 'Førehandsvising', + 'pages_md_insert_image' => 'Sett inn bilete', 'pages_md_insert_link' => 'Sett inn lenke', 'pages_md_insert_drawing' => 'Sett inn tegning', - 'pages_md_show_preview' => 'Forhåndsvisning', - 'pages_md_sync_scroll' => 'Synkroniser forhåndsvisningsrulle', - 'pages_drawing_unsaved' => 'Ulagret tegning funnet', - 'pages_drawing_unsaved_confirm' => 'Ulagret tegningsdata ble funnet fra en tidligere mislykket lagring. Vil du gjenopprette og fortsette å redigere denne ulagrede tegningen?', - 'pages_not_in_chapter' => 'Siden tilhører ingen kapittel', - 'pages_move' => 'Flytt side', - 'pages_copy' => 'Kopiér side', + 'pages_md_show_preview' => 'Førhandsvisning', + 'pages_md_sync_scroll' => 'Synkroniser førehandsvisingsrulle', + 'pages_drawing_unsaved' => 'Ulagra teikning funne', + 'pages_drawing_unsaved_confirm' => 'Ulagra teikninga vart funne frå ei tidligare mislykka lagring. Vil du gjenopprette og fortsette å redigere denne ulagra teikninga?', + 'pages_not_in_chapter' => 'Sida tilhøyrer ingen kapittel', + 'pages_move' => 'Flytt sida', + 'pages_copy' => 'Kopier side', 'pages_copy_desination' => 'Destinasjon', - 'pages_copy_success' => 'Siden ble flyttet', - 'pages_permissions' => 'Sidetilganger', - 'pages_permissions_success' => 'Sidens tilganger ble endret', + 'pages_copy_success' => 'Sida vart flytta', + 'pages_permissions' => 'Sidetilgangar', + 'pages_permissions_success' => 'Sidetilgangar vart endra', 'pages_revision' => 'Revisjon', - 'pages_revisions' => 'Sidens revisjoner', - 'pages_revisions_desc' => 'Oppført nedenfor er alle tidligere revisjoner av denne siden. Du kan se tilbake igjen, sammenligne og gjenopprette tidligere sideversjoner hvis du tillater det. Den hele sidens historikk kan kanskje ikke gjenspeiles fullstendig her, avhengig av systemkonfigurasjonen, kan gamle revisjoner bli slettet automatisk.', - 'pages_revisions_named' => 'Revisjoner for :pageName', - 'pages_revision_named' => 'Revisjoner for :pageName', - 'pages_revision_restored_from' => 'Gjenopprettet fra #:id; :summary', - 'pages_revisions_created_by' => 'Skrevet av', + 'pages_revisions' => 'Revisjonar for sida', + 'pages_revisions_desc' => 'Nedanfor er alle tidlegare revisjonar av denne sida. Du kan sjå tilbake igjen, samanlikna og retta opp igjen tidlegare sideversjonar viss du tillet det. Den heile historikken til sida kan kanskje ikkje speglast fullstendig her. Avhengig av systemkonfigurasjonen, kan gamle revisjonar bli sletta automatisk.', + 'pages_revisions_named' => 'Revisjonar for :pageName', + 'pages_revision_named' => 'Revisjonar for :pageName', + 'pages_revision_restored_from' => 'Gjenoppretta fra #:id; :summary', + 'pages_revisions_created_by' => 'Skrive av', 'pages_revisions_date' => 'Revideringsdato', 'pages_revisions_number' => '#', 'pages_revisions_sort_number' => 'Revisjonsnummer', 'pages_revisions_numbered' => 'Revisjon #:id', - 'pages_revisions_numbered_changes' => 'Endringer på revisjon #:id', + 'pages_revisions_numbered_changes' => 'Endringar på revisjon #:id', 'pages_revisions_editor' => 'Tekstredigeringstype', 'pages_revisions_changelog' => 'Endringslogg', - 'pages_revisions_changes' => 'Endringer', + 'pages_revisions_changes' => 'Endringar', 'pages_revisions_current' => 'Siste versjon', 'pages_revisions_preview' => 'Forhåndsvisning', 'pages_revisions_restore' => 'Gjenopprett', 'pages_revisions_none' => 'Denne siden har ingen revisjoner', 'pages_copy_link' => 'Kopier lenke', - 'pages_edit_content_link' => 'Hopp til seksjonen i tekstbehandleren', + 'pages_edit_content_link' => 'Hopp til seksjonen i tekstbehandlaren', 'pages_pointer_enter_mode' => 'Gå til seksjonen velg modus', 'pages_pointer_label' => 'Sidens seksjon alternativer', 'pages_pointer_permalink' => 'Sideseksjons permalenke', @@ -279,18 +283,18 @@ return [ 'pages_initial_revision' => 'Første publisering', 'pages_references_update_revision' => 'Automatisk oppdatering av interne lenker', 'pages_initial_name' => 'Ny side', - 'pages_editing_draft_notification' => 'Du skriver på et utkast som sist ble lagret :timeDiff.', + 'pages_editing_draft_notification' => 'Du skriver på eit utkast som sist vart lagra :timeDiff.', 'pages_draft_edited_notification' => 'Siden har blitt endret siden du startet. Det anbefales at du forkaster dine endringer.', - 'pages_draft_page_changed_since_creation' => 'Denne siden er blitt oppdatert etter at dette utkastet ble opprettet. Det anbefales at du forkaster dette utkastet, eller er ekstra forsiktig slik at du ikke overskriver noen sideendringer.', + 'pages_draft_page_changed_since_creation' => 'Denne siden har blitt oppdatert etter at dette utkastet ble oppretta. Me trur det er lurt å forkaste dette utkastet, eller er ekstra forsiktig, slik at du ikkje overskriver andre sine sideendringar.', 'pages_draft_edit_active' => [ 'start_a' => ':count forfattere har begynt å endre denne siden.', 'start_b' => ':userName skriver på siden for øyeblikket', - 'time_a' => 'siden sist siden ble oppdatert', + 'time_a' => 'sidan sist sida vart oppdatert', 'time_b' => 'i løpet av de siste :minCount minuttene', 'message' => ':start :time. Prøv å ikke overskriv hverandres endringer!', ], 'pages_draft_discarded' => 'Utkastet er forkastet! Redigeringsprogrammet er oppdatert med gjeldende sideinnhold', - 'pages_draft_deleted' => 'Utkast slettet! Redigeringsprogrammet er oppdatert med gjeldende sideinnhold', + 'pages_draft_deleted' => 'Utkast sletta! Redigeringsprogrammet er oppdatert med gjeldande sideinnhald', 'pages_specific' => 'Bestemt side', 'pages_is_template' => 'Sidemal', @@ -341,9 +345,9 @@ return [ 'attachments_order_updated' => 'Vedleggssortering endret', 'attachments_updated_success' => 'Vedleggsdetaljer endret', 'attachments_deleted' => 'Vedlegg fjernet', - 'attachments_file_uploaded' => 'Vedlegg ble lastet opp', - 'attachments_file_updated' => 'Vedlegget ble oppdatert', - 'attachments_link_attached' => 'Lenken ble festet til siden', + 'attachments_file_uploaded' => 'Vedlegg vart lasta opp', + 'attachments_file_updated' => 'Vedlegget vart oppdatert', + 'attachments_link_attached' => 'Lenka vart festa til sida', 'templates' => 'Maler', 'templates_set_as_template' => 'Siden er en mal', 'templates_explain_set_as_template' => 'Du kan angi denne siden som en mal slik at innholdet kan brukes når du oppretter andre sider. Andre brukere vil kunne bruke denne malen hvis de har visningstillatelser for denne siden.', @@ -386,7 +390,7 @@ return [ 'copy_consider' => 'Vennligst vurder nedenfor når du kopierer innholdet.', 'copy_consider_permissions' => 'Egendefinerte tilgangsinnstillinger vil ikke bli kopiert.', 'copy_consider_owner' => 'Du vil bli eier av alt kopiert innhold.', - 'copy_consider_images' => 'Sidebildefiler vil ikke bli duplisert og de opprinnelige bildene beholder relasjonen til siden de opprinnelig ble lastet opp til.', + 'copy_consider_images' => 'Sidebildefiler vil ikkle bli duplisert og dei opprinnelege bileta beholder relasjonen til sida dei opprinnelig vart lasta opp til.', 'copy_consider_attachments' => 'Sidevedlegg vil ikke bli kopiert.', 'copy_consider_access' => 'Endring av sted, eier eller rettigheter kan føre til at innholdet er tilgjengelig for dem som tidligere har vært uten adgang.', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Referanser', 'references_none' => 'Det er ingen sporede referanser til dette elementet.', - 'references_to_desc' => 'Nedenfor vises alle de kjente sidene i systemet som lenker til denne oppføringen.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Overvåk', diff --git a/lang/nn/errors.php b/lang/nn/errors.php index 5cea95da0..e9087bac4 100644 --- a/lang/nn/errors.php +++ b/lang/nn/errors.php @@ -19,12 +19,11 @@ return [ 'ldap_extension_not_installed' => 'LDAP PHP modulen er ikke installert.', 'ldap_cannot_connect' => 'Klarer ikke koble til LDAP på denne adressen', 'saml_already_logged_in' => 'Allerede logget inn', - 'saml_user_not_registered' => 'Kontoen med navn :name er ikke registert, registrering er også deaktivert.', 'saml_no_email_address' => 'Denne kontoinformasjonen finnes ikke i det eksterne autentiseringssystemet.', 'saml_invalid_response_id' => 'Forespørselen fra det eksterne autentiseringssystemet gjenkjennes ikke av en prosess som startes av dette programmet. Å navigere tilbake etter pålogging kan forårsake dette problemet.', 'saml_fail_authed' => 'Innlogging gjennom :system feilet. Fikk ikke kontakt med autentiseringstjeneren.', 'oidc_already_logged_in' => 'Allerede logget inn', - 'oidc_user_not_registered' => 'Brukeren :name er ikke registrert og automatisk registrering er deaktivert', + 'oidc_user_not_registered' => 'Brukeren :name er ikkje registrert og automatisk registrering er deaktivert', 'oidc_no_email_address' => 'Finner ikke en e-postadresse, for denne brukeren, i dataene som leveres av det eksterne autentiseringssystemet', 'oidc_fail_authed' => 'Innlogging ved hjelp av :system feilet, systemet ga ikke vellykket godkjenning', 'social_no_action_defined' => 'Ingen handlinger er definert', @@ -40,17 +39,17 @@ return [ 'invite_token_expired' => 'Invitasjonslenken har utgått, du kan forsøke å be om nytt passord istede.', // System - 'path_not_writable' => 'Filstien :filePath aksepterer ikke filer, du må sjekke filstitilganger i systemet.', - 'cannot_get_image_from_url' => 'Kan ikke hente bilde fra :url', - 'cannot_create_thumbs' => 'Kan ikke opprette miniatyrbilder. GD PHP er ikke installert.', + 'path_not_writable' => 'Filstien :filePath aksepterer ikkje filer, du må sjekke filstitilganger i systemet.', + 'cannot_get_image_from_url' => 'Kan ikkje hente bilete frå :url', + 'cannot_create_thumbs' => 'Kan ikkje opprette miniatyrbilete. GD PHP er ikkje installert.', 'server_upload_limit' => 'Vedlegget er for stort, forsøk med et mindre vedlegg.', 'server_post_limit' => 'Serveren kan ikkje ta i mot denne mengda med data. Prøv igjen med mindre data eller ei mindre fil.', 'uploaded' => 'Tjenesten aksepterer ikke vedlegg som er så stor.', // Drawing & Images - 'image_upload_error' => 'Bildet kunne ikke lastes opp, forsøk igjen.', - 'image_upload_type_error' => 'Bildeformatet støttes ikke, forsøk med et annet format.', - 'image_upload_replace_type' => 'Bildeerstatning må være av samme type', + 'image_upload_error' => 'Biletet kunne ikkje lastast opp, prøv igjen', + 'image_upload_type_error' => 'Bileteformatet er ikkje støtta, prøv med eit anna format', + 'image_upload_replace_type' => 'Bileteerstatning må vere av same type', 'image_upload_memory_limit' => 'Klarte ikkje å ta i mot bilete og lage miniatyrbilete grunna grenser knytt til systemet.', 'image_thumbnail_memory_limit' => 'Klarte ikkje å lage miniatyrbilete grunna grenser knytt til systemet.', 'image_gallery_thumbnail_memory_limit' => 'Klarte ikkje å lage miniatyrbilete grunna grenser knytt til systemet.', @@ -96,9 +95,9 @@ return [ '404_page_not_found' => 'Siden finnes ikke', 'sorry_page_not_found' => 'Beklager, siden du leter etter ble ikke funnet.', 'sorry_page_not_found_permission_warning' => 'Hvis du forventet at denne siden skulle eksistere, har du kanskje ikke tillatelse til å se den.', - 'image_not_found' => 'Bildet ble ikke funnet', - 'image_not_found_subtitle' => 'Beklager, bildefilen du ser etter ble ikke funnet.', - 'image_not_found_details' => 'Om du forventet at dette bildet skal eksistere, er det mulig det er slettet.', + 'image_not_found' => 'Bilete vart ikkje funne', + 'image_not_found_subtitle' => 'Orsak, biletefila vart ikkje funne.', + 'image_not_found_details' => 'Det kan sjå ut til at biletet du leiter etter er sletta.', 'return_home' => 'Gå til hovedside', 'error_occurred' => 'En feil oppsto', 'app_down' => ':appName er nede for øyeblikket', diff --git a/lang/nn/notifications.php b/lang/nn/notifications.php index 78aad7181..98c686e44 100644 --- a/lang/nn/notifications.php +++ b/lang/nn/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'For å forhindre mange varslinger, vil du ikke få nye varslinger for endringer på denne siden fra samme forfatter.', 'detail_page_name' => 'Sidenavn:', + 'detail_page_path' => 'Sidenamn:', 'detail_commenter' => 'Kommentar fra:', 'detail_comment' => 'Kommentar:', 'detail_created_by' => 'Opprettet av:', diff --git a/lang/nn/settings.php b/lang/nn/settings.php index a6d848331..f269c35bc 100644 --- a/lang/nn/settings.php +++ b/lang/nn/settings.php @@ -14,7 +14,7 @@ return [ // App Settings 'app_customization' => 'Tilpassing', - 'app_features_security' => 'Funksjoner og sikkerhet', + 'app_features_security' => 'Funksjonar og tryggleik', 'app_name' => 'Applikasjonsnavn', 'app_name_desc' => 'Dette navnet vises i overskriften og i alle e-postmeldinger som sendes av systemet.', 'app_name_header' => 'Vis navn i topptekst', @@ -23,8 +23,8 @@ return [ 'app_public_access_desc_guest' => 'Tilgang for offentlige besøkende kan kontrolleres gjennom "Gjest" -brukeren.', 'app_public_access_toggle' => 'Tillat offentlig tilgang', 'app_public_viewing' => 'Tillat offentlig visning?', - 'app_secure_images' => 'Høyere sikkerhet på bildeopplastinger', - 'app_secure_images_toggle' => 'Enable høyere sikkerhet på bildeopplastinger', + 'app_secure_images' => 'Høyere tryggleik på bileteopplastingar', + 'app_secure_images_toggle' => 'Skru på høgare tryggleik på bileteopplastingar', 'app_secure_images_desc' => 'Av ytelsesgrunner er alle bilder offentlige. Dette alternativet legger til en tilfeldig streng som er vanskelig å gjette foran bildets nettadresser. Forsikre deg om at katalogindekser ikke er aktivert for å forhindre enkel tilgang.', 'app_default_editor' => 'Standard sideredigeringsprogram', 'app_default_editor_desc' => 'Velg hvilken tekstbehandler som skal brukes som standard når du redigerer nye sider. Dette kan overskrives på et sidenivå der tillatelser tillates.', @@ -76,8 +76,8 @@ return [ // Maintenance settings 'maint' => 'Vedlikehold', - 'maint_image_cleanup' => 'Bildeopprydding', - 'maint_image_cleanup_desc' => 'Skanner side og revisjonsinnhold for å sjekke hvilke bilder og tegninger som for øyeblikket er i bruk, og hvilke bilder som er overflødige. Forsikre deg om at du lager en full database og sikkerhetskopiering av bilder før du kjører denne.', + 'maint_image_cleanup' => 'Rydd opp bilete', + 'maint_image_cleanup_desc' => 'Skanner side og revisjonsinnhold for å sjekke kva bilete og teikninar som for er i bruk no, og kva bilete som er til overs. Sørg for å tryggleikskopiere heile databasen og alle bilete før du kjører denne.', 'maint_delete_images_only_in_revisions' => 'Slett også bilder som bare finnes i game siderevisjoner', 'maint_image_cleanup_run' => 'Kjør opprydding', 'maint_image_cleanup_warning' => ':count potensielt ubrukte bilder ble funnet. Er du sikker på at du vil slette disse bildene?', @@ -109,7 +109,7 @@ return [ 'recycle_bin_contents_empty' => 'Papirkurven er for øyeblikket tom', 'recycle_bin_empty' => 'Tøm papirkurven', 'recycle_bin_empty_confirm' => 'Dette vil slette alle elementene i papirkurven permanent. Dette inkluderer innhold i hvert element. Er du sikker på at du vil tømme papirkurven?', - 'recycle_bin_destroy_confirm' => 'Denne handlingen vil permanent slette dette elementet og alle dets underelementer fra systemet, som beskrevet nedenfor. Du vil ikke kunne gjenopprette dette innholdet med mindre du har en tidligere sikkerhetskopi av databasen. Er du sikker på at du vil fortsette?', + 'recycle_bin_destroy_confirm' => 'Denne handlinga vil permanent slette dette elementet og alle dets underelementer frå systemet, som skildra nedanfor. Du vil ikkje kunne gjenopprette dette innholdet, med mindre du har ein tidligere tryggleiksskopi av databasen. Er du sikker på at du vil fortsette?', 'recycle_bin_destroy_list' => 'Elementer som skal slettes', 'recycle_bin_restore_list' => 'Elementer som skal gjenopprettes', 'recycle_bin_restore_confirm' => 'Denne handlingen vil hente opp elementet fra papirkurven, inkludert underliggende innhold, til sin opprinnelige sted. Om den opprinnelige plassen har blitt slettet i mellomtiden og nå befinner seg i papirkurven, vil også dette bli hentet opp igjen.', @@ -225,7 +225,7 @@ return [ 'users_api_tokens_expires' => 'Utløper', 'users_api_tokens_docs' => 'API-dokumentasjon', 'users_mfa' => 'Flerfaktorautentisering', - 'users_mfa_desc' => 'Konfigurer flerfaktorautentisering som et ekstra lag med sikkerhet for din konto.', + 'users_mfa_desc' => 'Konfigurer flerfaktorautentisering som eit ekstra lag med tryggleik for din konto.', 'users_mfa_x_methods' => ':count metode konfigurert|:count metoder konfigurert', 'users_mfa_configure' => 'Konfigurer metoder', @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/pl/common.php b/lang/pl/common.php index 8006bd539..13939f0e0 100644 --- a/lang/pl/common.php +++ b/lang/pl/common.php @@ -52,7 +52,7 @@ return [ 'filter_clear' => 'Wyczyść Filtr', 'download' => 'Pobierz', 'open_in_tab' => 'Otwórz w karcie', - 'open' => 'Open', + 'open' => 'Otwórz', // Sort Options 'sort_options' => 'Opcje sortowania', diff --git a/lang/pl/components.php b/lang/pl/components.php index fcc5a32a8..0aa3f0741 100644 --- a/lang/pl/components.php +++ b/lang/pl/components.php @@ -34,8 +34,8 @@ return [ 'image_delete_success' => 'Obrazek usunięty pomyślnie', 'image_replace' => 'Zastąp obraz', 'image_replace_success' => 'Plik obrazu zaktualizowany pomyślnie', - 'image_rebuild_thumbs' => 'Regenerate Size Variations', - 'image_rebuild_thumbs_success' => 'Image size variations successfully rebuilt!', + 'image_rebuild_thumbs' => 'Zregeneruj warianty rozmiaru', + 'image_rebuild_thumbs_success' => 'Warianty rozmiaru obrazu przebudowane pomyślnie!', // Code Editor 'code_editor' => 'Edytuj kod', diff --git a/lang/pl/entities.php b/lang/pl/entities.php index ae2bbc20b..6d1bb4348 100644 --- a/lang/pl/entities.php +++ b/lang/pl/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Zaktualizowano :timeLength', 'meta_updated_name' => 'Zaktualizowano :timeLength przez :user', 'meta_owned_name' => 'Właściciel: :user', - 'meta_reference_page_count' => 'Odniesienie na :count stronie|Odniesienie na :count stronach', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Wybór obiektu', 'entity_select_lack_permission' => 'Nie masz wymaganych uprawnień do wybrania tej pozycji', 'images' => 'Obrazki', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Edytuj książkę :bookName', 'books_form_book_name' => 'Nazwa książki', 'books_save' => 'Zapisz książkę', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Uprawnienia książki', 'books_permissions_updated' => 'Zaktualizowano uprawnienia książki', 'books_empty_contents' => 'Brak stron lub rozdziałów w tej książce.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Usuń wersje roboczą', 'pages_delete_success' => 'Strona usunięta pomyślnie', 'pages_delete_draft_success' => 'Werjsa robocza usunięta pomyślnie', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Czy na pewno chcesz usunąć tę stronę?', 'pages_delete_draft_confirm' => 'Czy na pewno chcesz usunąć wersje roboczą strony?', 'pages_editing_named' => 'Edytowanie strony :pageName', @@ -295,7 +299,7 @@ return [ 'pages_is_template' => 'Szablon strony', // Editor Sidebar - 'toggle_sidebar' => 'Toggle Sidebar', + 'toggle_sidebar' => 'Przełącz pasek boczny', 'page_tags' => 'Tagi strony', 'chapter_tags' => 'Tagi rozdziału', 'book_tags' => 'Tagi książki', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Odniesienia', 'references_none' => 'Brak śledzonych odwołań do tego elementu.', - 'references_to_desc' => 'Poniżej znajdują się wszystkie znane strony w systemie, które odnoszą się do tego elementu.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Obserwuj', diff --git a/lang/pl/errors.php b/lang/pl/errors.php index 3e9bce6f7..d4ba103e8 100644 --- a/lang/pl/errors.php +++ b/lang/pl/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'Rozszerzenie LDAP PHP nie zostało zainstalowane', 'ldap_cannot_connect' => 'Nie można połączyć z serwerem LDAP, połączenie nie zostało ustanowione', 'saml_already_logged_in' => 'Już zalogowany', - 'saml_user_not_registered' => 'Użytkownik :name nie jest zarejestrowany i automatyczna rejestracja jest wyłączona', 'saml_no_email_address' => 'Nie można odnaleźć adresu email dla tego użytkownika w danych dostarczonych przez zewnętrzny system uwierzytelniania', 'saml_invalid_response_id' => 'Żądanie z zewnętrznego systemu uwierzytelniania nie zostało rozpoznane przez proces rozpoczęty przez tę aplikację. Cofnięcie po zalogowaniu mogło spowodować ten problem.', 'saml_fail_authed' => 'Logowanie przy użyciu :system nie powiodło się, system nie mógł pomyślnie ukończyć uwierzytelniania', @@ -44,16 +43,16 @@ return [ 'cannot_get_image_from_url' => 'Nie można pobrać obrazka z :url', 'cannot_create_thumbs' => 'Serwer nie może utworzyć miniaturek. Upewnij się że rozszerzenie GD PHP zostało zainstalowane.', 'server_upload_limit' => 'Serwer nie pozwala na przyjęcie pliku o tym rozmiarze. Spróbuj przesłać plik o mniejszym rozmiarze.', - 'server_post_limit' => 'The server cannot receive the provided amount of data. Try again with less data or a smaller file.', + 'server_post_limit' => 'Serwer nie może przyjąć tej ilości danych. Spróbuj ponownie z mniejszą ilością danych lub mniejszym plikiem.', 'uploaded' => 'Serwer nie pozwala na przyjęcie pliku o tym rozmiarze. Spróbuj przesłać plik o mniejszym rozmiarze.', // Drawing & Images 'image_upload_error' => 'Wystąpił błąd podczas przesyłania obrazka', 'image_upload_type_error' => 'Typ przesłanego obrazka jest nieprwidłowy.', 'image_upload_replace_type' => 'Zamienniki plików graficznych muszą być tego samego typu', - 'image_upload_memory_limit' => 'Failed to handle image upload and/or create thumbnails due to system resource limits.', - 'image_thumbnail_memory_limit' => 'Failed to create image size variations due to system resource limits.', - 'image_gallery_thumbnail_memory_limit' => 'Failed to create gallery thumbnails due to system resource limits.', + 'image_upload_memory_limit' => 'Nie udało się obsłużyć przesyłania zdjęć i/lub tworzenia miniatur ze względu na limity zasobów systemowych.', + 'image_thumbnail_memory_limit' => 'Nie udało się utworzyć wariantów rozmiaru obrazu ze względu na limity zasobów systemowych.', + 'image_gallery_thumbnail_memory_limit' => 'Nie udało się utworzyć miniatur galerii ze względu na limity zasobów systemowych.', 'drawing_data_not_found' => 'Nie można załadować danych rysunku. Plik rysunku może już nie istnieć lub nie masz uprawnień dostępu do niego.', // Attachments diff --git a/lang/pl/notifications.php b/lang/pl/notifications.php index d3f86d02d..661149994 100644 --- a/lang/pl/notifications.php +++ b/lang/pl/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'Aby zapobiec nadmiarowi powiadomień, przez jakiś czas nie będziesz otrzymywać powiadomień o dalszych edycjach tej strony przez tego samego edytora.', 'detail_page_name' => 'Nazwa strony:', + 'detail_page_path' => 'Ścieżka strony:', 'detail_commenter' => 'Skomentował:', 'detail_comment' => 'Komentarz:', 'detail_created_by' => 'Utworzono przez:', diff --git a/lang/pl/preferences.php b/lang/pl/preferences.php index 5b664fd50..6d67dc1b3 100644 --- a/lang/pl/preferences.php +++ b/lang/pl/preferences.php @@ -5,10 +5,10 @@ */ return [ - 'my_account' => 'My Account', + 'my_account' => 'Moje konto', 'shortcuts' => 'Skróty', - 'shortcuts_interface' => 'UI Shortcut Preferences', + 'shortcuts_interface' => 'Ustawienia skrótów interfejsu użytkownika', 'shortcuts_toggle_desc' => 'Tutaj możesz włączyć lub wyłączyć interfejs skrótów klawiszowych używanych do nawigacji i akcji.', 'shortcuts_customize_desc' => 'Możesz dostosować każdy z poniższych skrótów. Wystarczy nacisnąć wybraną kombinację klawiszy po wybraniu wprowadzania dla danego skrótu.', 'shortcuts_toggle_label' => 'Skróty klawiszowe włączone', @@ -29,23 +29,23 @@ return [ 'notifications_watched' => 'Obserwowane i ignorowane elementy', 'notifications_watched_desc' => ' Poniżej znajdują się elementy, które mają własne preferencje obserwowania. Aby zaktualizować swoje preferencje, zobacz dany element, a następnie znajdź opcje obserwowania na pasku bocznym.', - 'auth' => 'Access & Security', - 'auth_change_password' => 'Change Password', - 'auth_change_password_desc' => 'Change the password you use to log-in to the application. This must be at least 8 characters long.', - 'auth_change_password_success' => 'Password has been updated!', + 'auth' => 'Dostęp i bezpieczeństwo', + 'auth_change_password' => 'Zmień hasło', + 'auth_change_password_desc' => 'Zmień hasło logowania do aplikacji. Hasło musi mieć minimum 8 znaków.', + 'auth_change_password_success' => 'Hasło zostało zaktualizowane!', - 'profile' => 'Profile Details', - 'profile_desc' => 'Manage the details of your account which represents you to other users, in addition to details that are used for communication and system personalisation.', - 'profile_view_public' => 'View Public Profile', - 'profile_name_desc' => 'Configure your display name which will be visible to other users in the system through the activity you perform, and content you own.', - 'profile_email_desc' => 'This email will be used for notifications and, depending on active system authentication, system access.', - 'profile_email_no_permission' => 'Unfortunately you don\'t have permission to change your email address. If you want to change this, you\'d need to ask an administrator to change this for you.', - 'profile_avatar_desc' => 'Select an image which will be used to represent yourself to others in the system. Ideally this image should be square and about 256px in width and height.', - 'profile_admin_options' => 'Administrator Options', - 'profile_admin_options_desc' => 'Additional administrator-level options, like those to manage role assignments, can be found for your user account in the "Settings > Users" area of the application.', + 'profile' => 'Szczegóły profilu', + 'profile_desc' => 'Zarządzaj szczegółami swojego konta, które widzą inni użytkownicy, oprócz danych używanych do komunikacji i personalizacji systemu.', + 'profile_view_public' => 'Zobacz profil publiczny', + 'profile_name_desc' => 'Skonfiguruj wyświetlaną nazwę, która będzie widoczna dla innych użytkowników systemu poprzez wykonywane zadania i posiadaną treść.', + 'profile_email_desc' => 'Ten e-mail będzie używany do powiadomień, a w zależności od wybranego sposobu uwierzytelniania, również do dostępu do systemu.', + 'profile_email_no_permission' => 'Niestety nie masz uprawnień do zmiany adresu e-mail. Jeśli chcesz to zmienić, musisz poprosić administratora, aby zrobił to za ciebie.', + 'profile_avatar_desc' => 'Wybierz obraz, który będzie cię reprezentował wśród innych w systemie. Obraz powinien być kwadratem o długości boku około 256 pikseli.', + 'profile_admin_options' => 'Opcje administratora', + 'profile_admin_options_desc' => 'Dodatkowe opcje na poziomie administratora dla twojego konta, takie jak zarządzanie przydzielaniem ról można znaleźć w sekcji "Ustawienia > Użytkownicy".', - 'delete_account' => 'Delete Account', - 'delete_my_account' => 'Delete My Account', - 'delete_my_account_desc' => 'This will fully delete your user account from the system. You will not be able to recover this account or revert this action. Content you\'ve created, such as created pages and uploaded images, will remain.', - 'delete_my_account_warning' => 'Are you sure you want to delete your account?', + 'delete_account' => 'Usuń konto', + 'delete_my_account' => 'Usuń moje konto', + 'delete_my_account_desc' => 'Spowoduje to całkowite usunięcie twojego konta z systemu. Nie będziesz miał możliwości odzyskania konta lub cofnięcia tej czynności. Stworzona przez Ciebie zawartość, taka jak utworzone strony i przesłane obrazy, pozostanie niezmieniona.', + 'delete_my_account_warning' => 'Jesteś pewny, że chcesz usunąć swoje konto?', ]; diff --git a/lang/pl/settings.php b/lang/pl/settings.php index 80e320d56..4d0bc9f7a 100644 --- a/lang/pl/settings.php +++ b/lang/pl/settings.php @@ -193,8 +193,8 @@ return [ 'users_send_invite_text' => 'Możesz wybrać wysłanie do tego użytkownika wiadomości e-mail z zaproszeniem, która pozwala mu ustawić własne hasło, w przeciwnym razie możesz ustawić je samemu.', 'users_send_invite_option' => 'Wyślij e-mail z zaproszeniem', 'users_external_auth_id' => 'Zewnętrzne identyfikatory autentykacji', - 'users_external_auth_id_desc' => 'When an external authentication system is in use (such as SAML2, OIDC or LDAP) this is the ID which links this BookStack user to the authentication system account. You can ignore this field if using the default email-based authentication.', - 'users_password_warning' => 'Only fill the below if you would like to change the password for this user.', + 'users_external_auth_id_desc' => 'Gdy używany jest zewnętrzny system uwierzytelniania (np. SAML2, OIDC lub LDAP), to jest ID, które łączy tego użytkownika BookStack z kontem w systemie uwierzytelniania. Możesz zignorować to pole, jeśli używasz domyślnego uwierzytelniania e-mailem.', + 'users_password_warning' => 'Wypełnij poniższe tylko, jeśli chcesz zmienić hasło dla tego użytkownika.', 'users_system_public' => 'Ten użytkownik reprezentuje każdego gościa odwiedzającego tę aplikację. Nie można się na niego zalogować, lecz jest przyznawany automatycznie.', 'users_delete' => 'Usuń użytkownika', 'users_delete_named' => 'Usuń :userName', @@ -210,16 +210,16 @@ return [ 'users_preferred_language' => 'Preferowany język', 'users_preferred_language_desc' => 'Opcja ta zmieni język używany w interfejsie użytkownika aplikacji. Nie wpłynie to na zawartość stworzoną przez użytkownika.', 'users_social_accounts' => 'Konta społecznościowe', - 'users_social_accounts_desc' => 'View the status of the connected social accounts for this user. Social accounts can be used in addition to the primary authentication system for system access.', + 'users_social_accounts_desc' => 'Zobacz status połączonych kont społecznościowych dla tego użytkownika. Konta społecznościowe mogą być używane jako uzupełnienie podstawowego systemu uwierzytelniania w celu uzyskania dostępu do systemu.', 'users_social_accounts_info' => 'Tutaj możesz połączyć kilka kont społecznościowych w celu łatwiejszego i szybszego logowania. Odłączenie konta tutaj nie autoryzowało dostępu. Odwołaj dostęp z ustawień profilu na podłączonym koncie społecznościowym.', 'users_social_connect' => 'Podłącz konto', 'users_social_disconnect' => 'Odłącz konto', - 'users_social_status_connected' => 'Connected', - 'users_social_status_disconnected' => 'Disconnected', + 'users_social_status_connected' => 'Połączono', + 'users_social_status_disconnected' => 'Rozłączono', 'users_social_connected' => ':socialAccount zostało dodane do Twojego profilu.', 'users_social_disconnected' => ':socialAccount zostało odłączone od Twojego profilu.', 'users_api_tokens' => 'Tokeny API', - 'users_api_tokens_desc' => 'Create and manage the access tokens used to authenticate with the BookStack REST API. Permissions for the API are managed via the user that the token belongs to.', + 'users_api_tokens_desc' => 'Twórz i zarządzaj tokenami dostępu używanymi do uwierzytelniania z BookStack REST API. Uprawnienia dla API są zarządzane za pośrednictwem użytkownika, do którego należy token.', 'users_api_tokens_none' => 'Nie utworzono tokenów API dla tego użytkownika', 'users_api_tokens_create' => 'Utwórz token', 'users_api_tokens_expires' => 'Wygasa', @@ -296,6 +296,7 @@ return [ 'et' => 'Estoński', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/pt/activities.php b/lang/pt/activities.php index 18645acf9..d12d640cb 100644 --- a/lang/pt/activities.php +++ b/lang/pt/activities.php @@ -59,7 +59,7 @@ return [ 'favourite_remove_notification' => '":name" foi removido dos seus favoritos', // Watching - 'watch_update_level_notification' => 'Watch preferences successfully updated', + 'watch_update_level_notification' => 'Ver preferências atualizadas com sucesso', // Auth 'auth_login' => 'sessão iniciada', @@ -115,9 +115,9 @@ return [ // Comments 'commented_on' => 'comentado a', - 'comment_create' => 'added comment', - 'comment_update' => 'updated comment', - 'comment_delete' => 'deleted comment', + 'comment_create' => 'comentário adicionado', + 'comment_update' => 'comentário atualizado', + 'comment_delete' => 'comentário eliminado', // Other 'permissions_update' => 'permissões atualizadas', diff --git a/lang/pt/common.php b/lang/pt/common.php index d2d373911..586ac1911 100644 --- a/lang/pt/common.php +++ b/lang/pt/common.php @@ -42,7 +42,7 @@ return [ 'remove' => 'Remover', 'add' => 'Adicionar', 'configure' => 'Configurar', - 'manage' => 'Manage', + 'manage' => 'Gerir', 'fullscreen' => 'Ecrã completo', 'favourite' => 'Favorito', 'unfavourite' => 'Retirar Favorito', @@ -52,7 +52,7 @@ return [ 'filter_clear' => 'Limpar Filtro', 'download' => 'Transferir', 'open_in_tab' => 'Abrir em novo separador', - 'open' => 'Open', + 'open' => 'Abrir', // Sort Options 'sort_options' => 'Opções de Ordenação', diff --git a/lang/pt/components.php b/lang/pt/components.php index 1bf504dd1..67e8c2f01 100644 --- a/lang/pt/components.php +++ b/lang/pt/components.php @@ -34,8 +34,8 @@ return [ 'image_delete_success' => 'Imagem eliminada com sucesso', 'image_replace' => 'Substituir Imagem', 'image_replace_success' => 'Imagem carregada com sucesso', - 'image_rebuild_thumbs' => 'Regenerate Size Variations', - 'image_rebuild_thumbs_success' => 'Image size variations successfully rebuilt!', + 'image_rebuild_thumbs' => 'Recriar Variação de Tamanho', + 'image_rebuild_thumbs_success' => 'Variações de tamanho da imagem reconstruídas com sucesso!', // Code Editor 'code_editor' => 'Editar Código', diff --git a/lang/pt/entities.php b/lang/pt/entities.php index 3da42f432..b2171ba64 100644 --- a/lang/pt/entities.php +++ b/lang/pt/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Atualizado :timeLength', 'meta_updated_name' => 'Atualizado :timeLength por :user', 'meta_owned_name' => 'Propriedade de :user', - 'meta_reference_page_count' => 'Referenciado em :count página|Referenciado em :count páginas', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Seleção de Entidade', 'entity_select_lack_permission' => 'Não tem as permissões necessárias para selecionar este item', 'images' => 'Imagens', @@ -106,7 +106,7 @@ return [ 'shelves_permissions_updated' => 'Permissões da Estante Atualizada', 'shelves_permissions_active' => 'Permissões da Estante Ativas', 'shelves_permissions_cascade_warning' => 'As permissões nas estantes não são passadas automaticamente em efeito dominó para os livros contidos. Isto acontece porque um livro pode existir em várias estantes. As permissões podem, no entanto, ser copiadas para livros filhos usando a opção abaixo.', - 'shelves_permissions_create' => 'Shelf create permissions are only used for copying permissions to child books using the action below. They do not control the ability to create books.', + 'shelves_permissions_create' => 'As permissões de criação de prateleira são usadas apenas para copiar livros filhos usando a ação abaixo. Eles não controlam a capacidade de criar livros.', 'shelves_copy_permissions_to_books' => 'Copiar Permissões para Livros', 'shelves_copy_permissions' => 'Copiar Permissões', 'shelves_copy_permissions_explain' => 'Isto aplicará as configurações de permissões atuais desta estante a todos os livros nela contidos. Antes de ativar, assegure-se de que quaisquer alterações nas permissões desta estante foram guardadas.', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Editar Livro :bookName', 'books_form_book_name' => 'Nome do Livro', 'books_save' => 'Guardar Livro', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Permissões do Livro', 'books_permissions_updated' => 'Permissões do Livro Atualizadas', 'books_empty_contents' => 'Nenhuma página ou capítulo foram criados para este livro.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Eliminar Rascunho de Página', 'pages_delete_success' => 'Página eliminada', 'pages_delete_draft_success' => 'Rascunho de página eliminado', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Tem certeza que deseja eliminar a página?', 'pages_delete_draft_confirm' => 'Tem certeza que deseja eliminar o rascunho de página?', 'pages_editing_named' => 'A Editar a Página :pageName', @@ -239,8 +243,8 @@ return [ 'pages_md_insert_drawing' => 'Inserir Desenho', 'pages_md_show_preview' => 'Mostrar pré-visualização', 'pages_md_sync_scroll' => 'Sincronizar pré-visualização', - 'pages_drawing_unsaved' => 'Unsaved Drawing Found', - 'pages_drawing_unsaved_confirm' => 'Unsaved drawing data was found from a previous failed drawing save attempt. Would you like to restore and continue editing this unsaved drawing?', + 'pages_drawing_unsaved' => 'Encontrado um rascunho não guardado', + 'pages_drawing_unsaved_confirm' => 'Dados de um rascunho não guardado foi encontrado de um tentativa anteriormente falhada. Deseja restaurar e continuar a edição desse rascunho?', 'pages_not_in_chapter' => 'A página não está dentro de um capítulo', 'pages_move' => 'Mover Página', 'pages_copy' => 'Copiar Página', @@ -295,7 +299,7 @@ return [ 'pages_is_template' => 'Modelo de Página', // Editor Sidebar - 'toggle_sidebar' => 'Toggle Sidebar', + 'toggle_sidebar' => 'Alternar barra lateral', 'page_tags' => 'Etiquetas de Página', 'chapter_tags' => 'Etiquetas do Capítulo', 'book_tags' => 'Etiquetas do Livro', @@ -405,29 +409,29 @@ return [ // References 'references' => 'Referências', 'references_none' => 'Não há referências registadas para este item.', - 'references_to_desc' => 'Abaixo estão todas as páginas conhecidas do sistema que vinculam este item.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options - 'watch' => 'Watch', - 'watch_title_default' => 'Default Preferences', - 'watch_desc_default' => 'Revert watching to just your default notification preferences.', - 'watch_title_ignore' => 'Ignore', - 'watch_desc_ignore' => 'Ignore all notifications, including those from user-level preferences.', - 'watch_title_new' => 'New Pages', - 'watch_desc_new' => 'Notify when any new page is created within this item.', - 'watch_title_updates' => 'All Page Updates', - 'watch_desc_updates' => 'Notify upon all new pages and page changes.', - 'watch_desc_updates_page' => 'Notify upon all page changes.', - 'watch_title_comments' => 'All Page Updates & Comments', - 'watch_desc_comments' => 'Notify upon all new pages, page changes and new comments.', - 'watch_desc_comments_page' => 'Notify upon page changes and new comments.', - 'watch_change_default' => 'Change default notification preferences', - 'watch_detail_ignore' => 'Ignoring notifications', + 'watch' => 'Ver', + 'watch_title_default' => 'Preferências Predefinidas', + 'watch_desc_default' => 'Reverter visualização para as preferências de notificação padrão.', + 'watch_title_ignore' => 'Ignorar', + 'watch_desc_ignore' => 'Ignorar todas as notificações, incluindo as de preferências de nível de usuário.', + 'watch_title_new' => 'Novas Páginas', + 'watch_desc_new' => 'Notificar quando qualquer nova página for criada dentro deste item.', + 'watch_title_updates' => 'Todas as atualizações da página', + 'watch_desc_updates' => 'Notificar sobre todas as novas páginas e alterações na página.', + 'watch_desc_updates_page' => 'Notificar sobre todas as alterações da página.', + 'watch_title_comments' => 'Todas as atualizações e comentários da página', + 'watch_desc_comments' => 'Notificar sobre todas as novas páginas, alterações de página e novos comentários.', + 'watch_desc_comments_page' => 'Notificar sobre alterações na página e novos comentários.', + 'watch_change_default' => 'Alterar preferências padrão de notificação', + 'watch_detail_ignore' => 'Ignorar notificações', 'watch_detail_new' => 'Watching for new pages', 'watch_detail_updates' => 'Watching new pages and updates', 'watch_detail_comments' => 'Watching new pages, updates & comments', 'watch_detail_parent_book' => 'Watching via parent book', - 'watch_detail_parent_book_ignore' => 'Ignoring via parent book', + 'watch_detail_parent_book_ignore' => 'A ignorar através do livro pai', 'watch_detail_parent_chapter' => 'Watching via parent chapter', 'watch_detail_parent_chapter_ignore' => 'Ignoring via parent chapter', ]; diff --git a/lang/pt/errors.php b/lang/pt/errors.php index 381337561..34613872e 100644 --- a/lang/pt/errors.php +++ b/lang/pt/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'A extensão LDAP PHP não está instalada', 'ldap_cannot_connect' => 'Não foi possível conectar ao servidor LDAP. Conexão inicial falhou', 'saml_already_logged_in' => 'Sessão já iniciada', - 'saml_user_not_registered' => 'O utilizador :name não está registado e o registo automático está desativado', 'saml_no_email_address' => 'Não foi possível encontrar um endereço de e-mail para este utilizador nos dados providenciados pelo sistema de autenticação externa', 'saml_invalid_response_id' => 'A requisição do sistema de autenticação externa não foi reconhecia por um processo iniciado por esta aplicação. Navegar para o caminho anterior após o inicio de sessão pode provocar este problema.', 'saml_fail_authed' => 'Inicio de sessão com :system falhou. O sistema não forneceu uma autorização bem sucedida', @@ -44,7 +43,7 @@ return [ 'cannot_get_image_from_url' => 'Não foi possível obter a imagem a partir de :url', 'cannot_create_thumbs' => 'O servidor não pôde criar as miniaturas de imagem. Por favor, verifique se a extensão GD PHP está instalada.', 'server_upload_limit' => 'O servidor não permite o carregamento de arquivos com esse tamanho. Por favor, tente fazer o carregamento de arquivos mais pequenos.', - 'server_post_limit' => 'The server cannot receive the provided amount of data. Try again with less data or a smaller file.', + 'server_post_limit' => 'O servidor não pode receber a quantidade de dados fornecida. Tente novamente com menos dados ou um arquivo menor.', 'uploaded' => 'O servidor não permite o carregamento de arquivos com esse tamanho. Por favor, tente fazer o carregamento de arquivos mais pequenos.', // Drawing & Images diff --git a/lang/pt/notifications.php b/lang/pt/notifications.php index 5539ae9a9..1243c6680 100644 --- a/lang/pt/notifications.php +++ b/lang/pt/notifications.php @@ -4,23 +4,24 @@ */ return [ - 'new_comment_subject' => 'New comment on page: :pageName', - 'new_comment_intro' => 'A user has commented on a page in :appName:', - 'new_page_subject' => 'New page: :pageName', - 'new_page_intro' => 'A new page has been created in :appName:', - 'updated_page_subject' => 'Updated page: :pageName', - 'updated_page_intro' => 'A page has been updated in :appName:', - 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', + 'new_comment_subject' => 'Novo comentário na página: :pageName', + 'new_comment_intro' => 'Um utilizador comentou uma página em :appName:', + 'new_page_subject' => 'Nova página: :pageName', + 'new_page_intro' => 'Uma nova página foi criada em :appName:', + 'updated_page_subject' => 'Página atualizada: :pageName', + 'updated_page_intro' => 'Uma página foi atualizada em :appName:', + 'updated_page_debounce' => 'Para evitar um grande volume de notificações, durante algum tempo não serão enviadas notificações de edições futuras para esta página através do mesmo editor.', - 'detail_page_name' => 'Page Name:', - 'detail_commenter' => 'Commenter:', - 'detail_comment' => 'Comment:', - 'detail_created_by' => 'Created By:', - 'detail_updated_by' => 'Updated By:', + 'detail_page_name' => 'Nome da Página:', + 'detail_page_path' => 'Page Path:', + 'detail_commenter' => 'Comentador:', + 'detail_comment' => 'Comentário:', + 'detail_created_by' => 'Criado Por:', + 'detail_updated_by' => 'Atualizado Por:', - 'action_view_comment' => 'View Comment', - 'action_view_page' => 'View Page', + 'action_view_comment' => 'Ver Comentário', + 'action_view_page' => 'Ver Página', - 'footer_reason' => 'This notification was sent to you because :link cover this type of activity for this item.', - 'footer_reason_link' => 'your notification preferences', + 'footer_reason' => 'Esta notificação foi enviada a você porque :link cobre este tipo de atividade para este item.', + 'footer_reason_link' => 'suas preferências de notificação', ]; diff --git a/lang/pt/preferences.php b/lang/pt/preferences.php index 8cf0697b4..ae7e2cc43 100644 --- a/lang/pt/preferences.php +++ b/lang/pt/preferences.php @@ -5,10 +5,10 @@ */ return [ - 'my_account' => 'My Account', + 'my_account' => 'A Minha Conta', 'shortcuts' => 'Atalhos', - 'shortcuts_interface' => 'UI Shortcut Preferences', + 'shortcuts_interface' => 'Preferências de Atalho UI', 'shortcuts_toggle_desc' => 'Aqui pode ativar ou desativar os atalhos de teclado do sistema, usados para navegação e ações.', 'shortcuts_customize_desc' => 'Pode personalizar cada um dos atalhos abaixo. Pressione a combinação de tecla desejada após selecionar a entrada para um atalho.', 'shortcuts_toggle_label' => 'Atalhos de teclado ativados', @@ -19,7 +19,7 @@ return [ 'shortcuts_update_success' => 'As suas preferências de atalhos foram guardadas!', 'shortcuts_overview_desc' => 'Manage keyboard shortcuts you can use to navigate the system user interface.', - 'notifications' => 'Notification Preferences', + 'notifications' => 'Preferências das Notificações', 'notifications_desc' => 'Control the email notifications you receive when certain activity is performed within the system.', 'notifications_opt_own_page_changes' => 'Notify upon changes to pages I own', 'notifications_opt_own_page_comments' => 'Notify upon comments on pages I own', @@ -29,14 +29,14 @@ return [ 'notifications_watched' => 'Watched & Ignored Items', 'notifications_watched_desc' => ' Below are the items that have custom watch preferences applied. To update your preferences for these, view the item then find the watch options in the sidebar.', - 'auth' => 'Access & Security', - 'auth_change_password' => 'Change Password', - 'auth_change_password_desc' => 'Change the password you use to log-in to the application. This must be at least 8 characters long.', - 'auth_change_password_success' => 'Password has been updated!', + 'auth' => 'Acesso e Segurança', + 'auth_change_password' => 'Alterar Palavra-passe', + 'auth_change_password_desc' => 'Altere a palavra-passe que você usa para entrar no aplicativo. Ela deve ter pelo menos 8 caracteres.', + 'auth_change_password_success' => 'A palavra-passe foi atualizada!', - 'profile' => 'Profile Details', + 'profile' => 'Detalhes Do Perfil', 'profile_desc' => 'Manage the details of your account which represents you to other users, in addition to details that are used for communication and system personalisation.', - 'profile_view_public' => 'View Public Profile', + 'profile_view_public' => 'Visualizar Perfil Público', 'profile_name_desc' => 'Configure your display name which will be visible to other users in the system through the activity you perform, and content you own.', 'profile_email_desc' => 'This email will be used for notifications and, depending on active system authentication, system access.', 'profile_email_no_permission' => 'Unfortunately you don\'t have permission to change your email address. If you want to change this, you\'d need to ask an administrator to change this for you.', @@ -44,8 +44,8 @@ return [ 'profile_admin_options' => 'Administrator Options', 'profile_admin_options_desc' => 'Additional administrator-level options, like those to manage role assignments, can be found for your user account in the "Settings > Users" area of the application.', - 'delete_account' => 'Delete Account', - 'delete_my_account' => 'Delete My Account', - 'delete_my_account_desc' => 'This will fully delete your user account from the system. You will not be able to recover this account or revert this action. Content you\'ve created, such as created pages and uploaded images, will remain.', - 'delete_my_account_warning' => 'Are you sure you want to delete your account?', + 'delete_account' => 'Excluir Conta', + 'delete_my_account' => 'Excluir a Minha Conta', + 'delete_my_account_desc' => 'Isto excluirá completamente sua conta de utilizador do sistema. Você não poderá recuperar esta conta ou reverter esta ação. O conteúdo que você criou, como páginas criadas e imagens carregadas, permanecerá.', + 'delete_my_account_warning' => 'Tem certeza que deseja excluir sua conta?', ]; diff --git a/lang/pt/settings.php b/lang/pt/settings.php index 45bea9d05..94da707f3 100644 --- a/lang/pt/settings.php +++ b/lang/pt/settings.php @@ -214,8 +214,8 @@ return [ 'users_social_accounts_info' => 'Aqui pode ligar outras contas para acesso mais rápido. Desligar uma conta não retira a possibilidade de acesso usando-a. Para revogar o acesso ao perfil através da conta social, você deverá fazê-lo na sua conta social.', 'users_social_connect' => 'Contas Associadas', 'users_social_disconnect' => 'Dissociar Conta', - 'users_social_status_connected' => 'Connected', - 'users_social_status_disconnected' => 'Disconnected', + 'users_social_status_connected' => 'Conectado', + 'users_social_status_disconnected' => 'Desconectado', 'users_social_connected' => 'A conta:socialAccount foi associada com sucesso ao seu perfil.', 'users_social_disconnected' => 'A conta:socialAccount foi dissociada com sucesso de seu perfil.', 'users_api_tokens' => 'Tokens de API', @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/pt_BR/entities.php b/lang/pt_BR/entities.php index e012042c8..6e32f2801 100644 --- a/lang/pt_BR/entities.php +++ b/lang/pt_BR/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Atualizado :timeLength', 'meta_updated_name' => 'Atualizado :timeLength por :user', 'meta_owned_name' => 'De :user', - 'meta_reference_page_count' => 'Referenciado em :count página|Referenciado em :count páginas', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Seleção de Entidade', 'entity_select_lack_permission' => 'Você não tem as permissões necessárias para selecionar este item', 'images' => 'Imagens', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Editar Livro :bookName', 'books_form_book_name' => 'Nome do Livro', 'books_save' => 'Salvar Livro', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Permissões do Livro', 'books_permissions_updated' => 'Permissões do Livro Atualizadas', 'books_empty_contents' => 'Nenhuma página ou capítulo foram criados para este livro.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Excluir Rascunho de Página', 'pages_delete_success' => 'Página excluída', 'pages_delete_draft_success' => 'Rascunho de página excluído', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Tem certeza que deseja excluir a página?', 'pages_delete_draft_confirm' => 'Tem certeza que deseja excluir o rascunho de página?', 'pages_editing_named' => 'Editando a Página :pageName', @@ -295,7 +299,7 @@ return [ 'pages_is_template' => 'Modelo de Página', // Editor Sidebar - 'toggle_sidebar' => 'Toggle Sidebar', + 'toggle_sidebar' => '', 'page_tags' => 'Tags de Página', 'chapter_tags' => 'Tags de Capítulo', 'book_tags' => 'Tags de Livro', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Referências', 'references_none' => 'Não há referências rastreadas para este item.', - 'references_to_desc' => 'Abaixo estão todas as páginas conhecidas no sistema que vinculam a este item.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Acompanhar', diff --git a/lang/pt_BR/errors.php b/lang/pt_BR/errors.php index c7d82e18d..93ed24a59 100644 --- a/lang/pt_BR/errors.php +++ b/lang/pt_BR/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'A extensão LDAP PHP não está instalada', 'ldap_cannot_connect' => 'Não foi possível conectar ao servidor LDAP. Conexão inicial falhou', 'saml_already_logged_in' => 'Login já efetuado', - 'saml_user_not_registered' => 'O usuário :name não está cadastrado e o cadastro automático está desativado', 'saml_no_email_address' => 'Não foi possível encontrar um endereço de e-mail para este usuário nos dados providos pelo sistema de autenticação externa', 'saml_invalid_response_id' => 'A requisição do sistema de autenticação externa não foi reconhecia por um processo iniciado por esta aplicação. Após o login, navegar para o caminho anterior pode causar um problema.', 'saml_fail_authed' => 'Login utilizando :system falhou. Sistema não forneceu autorização bem sucedida', diff --git a/lang/pt_BR/notifications.php b/lang/pt_BR/notifications.php index 2c315d4f1..e8fc217ad 100644 --- a/lang/pt_BR/notifications.php +++ b/lang/pt_BR/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'Para prevenir notificações em massa, por enquanto notificações não serão enviadas para você para próximas edições nessa página pelo mesmo editor.', 'detail_page_name' => 'Nome da Página:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Comentador:', 'detail_comment' => 'Comentário:', 'detail_created_by' => 'Criado por: ', diff --git a/lang/pt_BR/settings.php b/lang/pt_BR/settings.php index f9e1bfdb3..3502a0e92 100644 --- a/lang/pt_BR/settings.php +++ b/lang/pt_BR/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/ro/entities.php b/lang/ro/entities.php index bcaa41695..c203df437 100644 --- a/lang/ro/entities.php +++ b/lang/ro/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Actualizat :timeLength', 'meta_updated_name' => 'Actualizat :timeLength de :user', 'meta_owned_name' => 'Deținut de :user', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Selectare entitate', 'entity_select_lack_permission' => 'Nu ai drepturile necesare pentru a selecta acest element', 'images' => 'Imagini', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Editează cartea :bookName', 'books_form_book_name' => 'Nume carte', 'books_save' => 'Salvează cartea', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Permisiuni carte', 'books_permissions_updated' => 'Permisiuni carte actualizate', 'books_empty_contents' => 'Nu au fost create pagini sau capitole pentru această carte.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Șterge ciorna', 'pages_delete_success' => 'Pagină ștearsă', 'pages_delete_draft_success' => 'Pagină ciornă ștearsă', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Ești sigur că dorești să ștergi acestă pagină?', 'pages_delete_draft_confirm' => 'Ești sigur că vrei să ștergi această pagină schiță?', 'pages_editing_named' => 'Editare pagină :pageNume', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Referințe', 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/ro/errors.php b/lang/ro/errors.php index 1ed422f71..b1ce69cfd 100644 --- a/lang/ro/errors.php +++ b/lang/ro/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'Extensia LDAP PHP nu este instalată', 'ldap_cannot_connect' => 'Nu se poate conecta la serverul ldap, conexiunea inițială a eșuat', 'saml_already_logged_in' => 'Deja conectat', - 'saml_user_not_registered' => 'Utilizatorul :name nu este înregistrat și înregistrarea automată este dezactivată', 'saml_no_email_address' => 'Nu s-a putut găsi o adresă de e-mail, pentru acest utilizator, în datele furnizate de sistemul extern de autentificare', 'saml_invalid_response_id' => 'Solicitarea de la sistemul extern de autentificare nu este recunoscută de un proces inițiat de această aplicație. Navigarea înapoi după o autentificare ar putea cauza această problemă.', 'saml_fail_authed' => 'Autentificarea folosind :system a eșuat, sistemul nu a furnizat autorizare cu succes', diff --git a/lang/ro/notifications.php b/lang/ro/notifications.php index 26a901575..676eeb814 100644 --- a/lang/ro/notifications.php +++ b/lang/ro/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'Pentru a preveni notificări în masă, pentru un timp nu veți primi notificări suplimentare la această pagină de către același editor.', 'detail_page_name' => 'Nume pagină:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Cine a comentat:', 'detail_comment' => 'Comentariu:', 'detail_created_by' => 'Creat de:', diff --git a/lang/ro/preferences.php b/lang/ro/preferences.php index f4018b171..893b44eaf 100644 --- a/lang/ro/preferences.php +++ b/lang/ro/preferences.php @@ -5,7 +5,7 @@ */ return [ - 'my_account' => 'My Account', + 'my_account' => 'Contul meu', 'shortcuts' => 'Scurtături', 'shortcuts_interface' => 'UI Shortcut Preferences', @@ -29,14 +29,14 @@ return [ 'notifications_watched' => 'Articole urmărite și ignorate', 'notifications_watched_desc' => ' Mai jos sunt elementele care au fost aplicate preferințe personalizate. Pentru a actualiza preferințele pentru acestea, vizualizați elementul și apoi găsiți opțiunile de ceas în bara laterală.', - 'auth' => 'Access & Security', - 'auth_change_password' => 'Change Password', + 'auth' => 'Acces & Securitate', + 'auth_change_password' => 'Schimbă Parola', 'auth_change_password_desc' => 'Change the password you use to log-in to the application. This must be at least 8 characters long.', 'auth_change_password_success' => 'Password has been updated!', - 'profile' => 'Profile Details', + 'profile' => 'Detalii Profil', 'profile_desc' => 'Manage the details of your account which represents you to other users, in addition to details that are used for communication and system personalisation.', - 'profile_view_public' => 'View Public Profile', + 'profile_view_public' => 'Vezi profilul Public', 'profile_name_desc' => 'Configure your display name which will be visible to other users in the system through the activity you perform, and content you own.', 'profile_email_desc' => 'This email will be used for notifications and, depending on active system authentication, system access.', 'profile_email_no_permission' => 'Unfortunately you don\'t have permission to change your email address. If you want to change this, you\'d need to ask an administrator to change this for you.', diff --git a/lang/ro/settings.php b/lang/ro/settings.php index 91b1c8064..062d402bc 100644 --- a/lang/ro/settings.php +++ b/lang/ro/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/ru/entities.php b/lang/ru/entities.php index 066dc48f9..a08912445 100644 --- a/lang/ru/entities.php +++ b/lang/ru/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Обновлено :timeLength', 'meta_updated_name' => ':user обновил :timeLength', 'meta_owned_name' => 'Владелец :user', - 'meta_reference_page_count' => 'Ссылается на :count страницу|Ссылается на :count страниц', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Выбор объекта', 'entity_select_lack_permission' => 'У вас нет разрешения на выбор этого элемента', 'images' => 'Изображения', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Редактировать книгу :bookName', 'books_form_book_name' => 'Название книги', 'books_save' => 'Сохранить книгу', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Разрешения на книгу', 'books_permissions_updated' => 'Разрешения на книгу обновлены', 'books_empty_contents' => 'Для этой книги нет страниц или разделов.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Удалить черновик', 'pages_delete_success' => 'Страница удалена', 'pages_delete_draft_success' => 'Черновик удален', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Вы действительно хотите удалить эту страницу?', 'pages_delete_draft_confirm' => 'Вы действительно хотите удалить этот черновик?', 'pages_editing_named' => 'Редактирование страницы :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Ссылки', 'references_none' => 'Нет отслеживаемых ссылок на этот элемент.', - 'references_to_desc' => 'Ниже показаны все известные страницы в системе, которые ссылаются на этот элемент.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/ru/errors.php b/lang/ru/errors.php index ca9eed368..2b18494e7 100644 --- a/lang/ru/errors.php +++ b/lang/ru/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'LDAP расширение для PHP не установлено', 'ldap_cannot_connect' => 'Не удается подключиться к серверу LDAP, не удалось выполнить начальное соединение', 'saml_already_logged_in' => 'Уже вошли в систему', - 'saml_user_not_registered' => 'Пользователь :name не зарегистрирован. Автоматическая регистрация отключена', 'saml_no_email_address' => 'Не удалось найти email для этого пользователя в данных, предоставленных внешней системой аутентификации', 'saml_invalid_response_id' => 'Запрос от внешней системы аутентификации не распознается процессом, запущенным этим приложением. Переход назад после входа в систему может вызвать эту проблему.', 'saml_fail_authed' => 'Вход с помощью :system не удался, система не предоставила успешную авторизацию', diff --git a/lang/ru/notifications.php b/lang/ru/notifications.php index 888fb8b0e..f37f11986 100644 --- a/lang/ru/notifications.php +++ b/lang/ru/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Имя страницы:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Комментатор:', 'detail_comment' => 'Комментарий:', 'detail_created_by' => 'Создано:', diff --git a/lang/ru/settings.php b/lang/ru/settings.php index f49fd092b..ef11be4bd 100644 --- a/lang/ru/settings.php +++ b/lang/ru/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/sk/entities.php b/lang/sk/entities.php index 315033f4d..0d74c691a 100644 --- a/lang/sk/entities.php +++ b/lang/sk/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Aktualizované :timeLength', 'meta_updated_name' => 'Aktualizované :timeLength používateľom :user', 'meta_owned_name' => 'Vlastník :user', - 'meta_reference_page_count' => 'Referencia na :count page|Referencia na :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Entita vybraná', 'entity_select_lack_permission' => 'Na výber tejto položky nemáte potrebné povolenia', 'images' => 'Obrázky', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Upraviť knihu :bookName', 'books_form_book_name' => 'Názov knihy', 'books_save' => 'Uložiť knihu', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Oprávnenia knihy', 'books_permissions_updated' => 'Oprávnenia knihy aktualizované', 'books_empty_contents' => 'Pre túto knihu neboli vytvorené žiadne stránky alebo kapitoly.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Zmazať koncept', 'pages_delete_success' => 'Stránka zmazaná', 'pages_delete_draft_success' => 'Koncept stránky zmazaný', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Ste si istý, že chcete zmazať túto stránku?', 'pages_delete_draft_confirm' => 'Ste si istý, že chcete zmazať tento koncept stránky?', 'pages_editing_named' => 'Upraviť stránku :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Referencie', 'references_none' => 'Neexistujú žiadne sledované referencie na túto položku.', - 'references_to_desc' => 'Nižšie sú zobrazené všetky známe stránky v systéme, ktoré odkazujú na túto položku.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/sk/errors.php b/lang/sk/errors.php index ed22e542a..06f396f17 100644 --- a/lang/sk/errors.php +++ b/lang/sk/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'Rozšírenie LDAP PHP nie je nainštalované', 'ldap_cannot_connect' => 'Nedá sa pripojiť k serveru ldap, počiatočné pripojenie zlyhalo', 'saml_already_logged_in' => 'Používateľ sa už prihlásil', - 'saml_user_not_registered' => 'Používateľ :name nie je zaregistrovaný a automatická registrácia je zakázaná', 'saml_no_email_address' => 'V údajoch poskytnutých externým overovacím systémom sa nepodarilo nájsť e-mailovú adresu tohto používateľa', 'saml_invalid_response_id' => 'Požiadavka z externého autentifikačného systému nie je rozpoznaná procesom spusteným touto aplikáciou. Tento problém môže spôsobiť navigácia späť po prihlásení.', 'saml_fail_authed' => 'Prihlásenie pomocou :system zlyhalo, systém neposkytol úspešnú autorizáciu', diff --git a/lang/sk/notifications.php b/lang/sk/notifications.php index 5539ae9a9..1afd23f1d 100644 --- a/lang/sk/notifications.php +++ b/lang/sk/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/sk/settings.php b/lang/sk/settings.php index d1b614705..0192066de 100644 --- a/lang/sk/settings.php +++ b/lang/sk/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/sl/entities.php b/lang/sl/entities.php index f6628dd1e..591dd009e 100644 --- a/lang/sl/entities.php +++ b/lang/sl/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Posodobljeno :timeLength', 'meta_updated_name' => 'Posodobil :timeLength uporabnik :user', 'meta_owned_name' => 'V lasti :user', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Izbira entitete', 'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item', 'images' => 'Slike', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Uredi knjigo :bookName', 'books_form_book_name' => 'Ime knjige', 'books_save' => 'Shrani knjigo', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Dovoljenja knjige', 'books_permissions_updated' => 'Posodobljena dovoljenja knjige', 'books_empty_contents' => 'V tej knjigi ni bila ustvarjena še nobena stran ali poglavje.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Izbriši osnutek strani', 'pages_delete_success' => 'Stran izbirsana', 'pages_delete_draft_success' => 'Osnutek strani izbrisan', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Ste prepričani, da želite izbrisati to stran?', 'pages_delete_draft_confirm' => 'Ali ste prepričani, da želite izbrisati ta osnutek?', 'pages_editing_named' => 'Urejanje strani :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'References', 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/sl/errors.php b/lang/sl/errors.php index ffabee7ec..51c34132b 100644 --- a/lang/sl/errors.php +++ b/lang/sl/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'PHP razširitev za LDAP ni nameščena', 'ldap_cannot_connect' => 'Ne morem se povezati na LDAP strežnik, neuspešna začetna povezava', 'saml_already_logged_in' => 'Že prijavljen', - 'saml_user_not_registered' => 'Uporabniško ime :name ni registrirano in avtomatska registracija je onemogočena', 'saml_no_email_address' => 'Nisem našel e-naslova za tega uporabnika v podatkih iz zunanjega sistema za preverjanje pristnosti', 'saml_invalid_response_id' => 'Zahteva iz zunanjega sistema za preverjanje pristnosti ni prepoznana s strani procesa zagnanega s strani te aplikacije. Pomik nazaj po prijavi je lahko vzrok teh težav.', 'saml_fail_authed' => 'Prijava z uporabo :system ni uspela, sistem ni zagotovil uspešne avtorizacije', diff --git a/lang/sl/notifications.php b/lang/sl/notifications.php index 5539ae9a9..1afd23f1d 100644 --- a/lang/sl/notifications.php +++ b/lang/sl/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/sl/settings.php b/lang/sl/settings.php index a4469e53b..9b543040d 100644 --- a/lang/sl/settings.php +++ b/lang/sl/settings.php @@ -297,6 +297,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/sq/entities.php b/lang/sq/entities.php index cfb5aae1a..f1f915544 100644 --- a/lang/sq/entities.php +++ b/lang/sq/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Updated :timeLength', 'meta_updated_name' => 'Updated :timeLength by :user', 'meta_owned_name' => 'Owned by :user', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Entity Select', 'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item', 'images' => 'Images', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Edit Book :bookName', 'books_form_book_name' => 'Book Name', 'books_save' => 'Save Book', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Book Permissions', 'books_permissions_updated' => 'Book Permissions Updated', 'books_empty_contents' => 'No pages or chapters have been created for this book.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Delete Draft Page', 'pages_delete_success' => 'Page deleted', 'pages_delete_draft_success' => 'Draft page deleted', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Are you sure you want to delete this page?', 'pages_delete_draft_confirm' => 'Are you sure you want to delete this draft page?', 'pages_editing_named' => 'Editing Page :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'References', 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/sq/errors.php b/lang/sq/errors.php index 8813cf90a..607b6ea83 100644 --- a/lang/sq/errors.php +++ b/lang/sq/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'LDAP PHP extension not installed', 'ldap_cannot_connect' => 'Cannot connect to ldap server, Initial connection failed', 'saml_already_logged_in' => 'Already logged in', - 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', diff --git a/lang/sq/notifications.php b/lang/sq/notifications.php index 5539ae9a9..1afd23f1d 100644 --- a/lang/sq/notifications.php +++ b/lang/sq/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/sq/settings.php b/lang/sq/settings.php index c5ca662c3..03e9bf462 100644 --- a/lang/sq/settings.php +++ b/lang/sq/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/sv/entities.php b/lang/sv/entities.php index a1c0a97d7..5ff5cfe20 100644 --- a/lang/sv/entities.php +++ b/lang/sv/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Uppdaterad :timeLength', 'meta_updated_name' => 'Uppdaterad :timeLength av :user', 'meta_owned_name' => 'Ägs av :user', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Välj enhet', 'entity_select_lack_permission' => 'Du har inte den behörighet som krävs för att välja det här objektet', 'images' => 'Bilder', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Redigera bok :bookName', 'books_form_book_name' => 'Bokens namn', 'books_save' => 'Spara bok', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Rättigheter för boken', 'books_permissions_updated' => 'Bokens rättigheter har uppdaterats', 'books_empty_contents' => 'Det finns inga sidor eller kapitel i den här boken.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Ta bort utkast', 'pages_delete_success' => 'Sidan har tagits bort', 'pages_delete_draft_success' => 'Utkastet har tagits bort', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Är du säker på att du vill ta bort den här sidan?', 'pages_delete_draft_confirm' => 'Är du säker på att du vill ta bort det här utkastet?', 'pages_editing_named' => 'Redigerar sida :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Referenser', 'references_none' => 'Det finns inga referenser kopplade till detta objekt.', - 'references_to_desc' => 'Nedan visas alla kända sidor i systemet som länkar till detta objekt.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/sv/errors.php b/lang/sv/errors.php index 865a067c7..e24e54807 100644 --- a/lang/sv/errors.php +++ b/lang/sv/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'LDAP PHP-tillägg inte installerat', 'ldap_cannot_connect' => 'Kan inte ansluta till ldap-servern. Anslutningen misslyckades', 'saml_already_logged_in' => 'Redan inloggad', - 'saml_user_not_registered' => 'Användarnamnet är inte registrerat och automatisk registrering är inaktiverad', 'saml_no_email_address' => 'Kunde inte hitta en e-postadress för den här användaren i data som tillhandahålls av det externa autentiseringssystemet', 'saml_invalid_response_id' => 'En begäran från det externa autentiseringssystemet känns inte igen av en process som startats av denna applikation. Att navigera bakåt efter en inloggning kan orsaka detta problem.', 'saml_fail_authed' => 'Inloggning med :system misslyckades, systemet godkände inte auktoriseringen', diff --git a/lang/sv/notifications.php b/lang/sv/notifications.php index b7702558c..9d2269ed8 100644 --- a/lang/sv/notifications.php +++ b/lang/sv/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/sv/settings.php b/lang/sv/settings.php index e0b2564f4..830680b65 100644 --- a/lang/sv/settings.php +++ b/lang/sv/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/tr/activities.php b/lang/tr/activities.php index be6a0777e..6a0c6ec5d 100644 --- a/lang/tr/activities.php +++ b/lang/tr/activities.php @@ -10,7 +10,7 @@ return [ 'page_create_notification' => 'Sayfa Başarıyla Oluşturuldu', 'page_update' => 'sayfayı güncelledi', 'page_update_notification' => 'Sayfa başarıyla güncellendi', - 'page_delete' => 'sayfayı sildi', + 'page_delete' => 'sayfa silindi', 'page_delete_notification' => 'Sayfa başarıyla silindi', 'page_restore' => 'sayfayı eski haline getirdi', 'page_restore_notification' => 'Sayfa Başarıyla Eski Haline Getirildi', @@ -32,7 +32,7 @@ return [ 'book_create_notification' => 'Kitap başarıyla oluşturuldu', 'book_create_from_chapter' => 'converted chapter to book', 'book_create_from_chapter_notification' => 'Bölüm başarıyla kitaba dönüştürüldü', - 'book_update' => 'kitabı güncelledi', + 'book_update' => 'güncellenen kitap', 'book_update_notification' => 'Kitap başarıyla güncellendi', 'book_delete' => 'kitabı sildi', 'book_delete_notification' => 'Kitap başarıyla silindi', @@ -65,7 +65,7 @@ return [ 'auth_login' => 'oturum açıldı', 'auth_register' => 'yeni kullanıcı olarak kayıt yapıldı', 'auth_password_reset_request' => 'requested user password reset', - 'auth_password_reset_update' => 'reset user password', + 'auth_password_reset_update' => 'Kullanıcı parolasını sıfırla', 'mfa_setup_method' => 'configured MFA method', 'mfa_setup_method_notification' => 'Çok aşamalı kimlik doğrulama yöntemi başarıyla yapılandırıldı', 'mfa_remove_method' => 'removed MFA method', @@ -97,13 +97,13 @@ return [ 'api_token_create_notification' => 'API anahtarı başarıyla oluşturuldu', 'api_token_update' => 'updated api token', 'api_token_update_notification' => 'API anahtarı başarıyla güncellendi', - 'api_token_delete' => 'deleted api token', + 'api_token_delete' => 'silinen sayfa tokenı', 'api_token_delete_notification' => 'API anahtarı başarıyla silindi', // Roles - 'role_create' => 'created role', + 'role_create' => 'oluşturulan rol', 'role_create_notification' => 'Rol başarıyla oluşturuldu', - 'role_update' => 'updated role', + 'role_update' => 'güncellenmiş rol', 'role_update_notification' => 'Rol başarıyla güncellendi', 'role_delete' => 'deleted role', 'role_delete_notification' => 'Rol başarıyla silindi', diff --git a/lang/tr/entities.php b/lang/tr/entities.php index 07922b647..9cc6774ea 100644 --- a/lang/tr/entities.php +++ b/lang/tr/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => ':timeLength güncellendi', 'meta_updated_name' => ':user tarafından :timeLength güncellendi', 'meta_owned_name' => ':user kişisine ait', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Öge Seçimi', 'entity_select_lack_permission' => 'Bu öğeyi seçmek için gerekli izinlere sahip değilsiniz', 'images' => 'Görseller', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => ':bookName Kitabını Düzenle', 'books_form_book_name' => 'Kitap Adı', 'books_save' => 'Kitabı Kaydet', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Kitap İzinleri', 'books_permissions_updated' => 'Kitap İzinleri Güncellendi', 'books_empty_contents' => 'Bu kitaba ait sayfa veya bölüm oluşturulmamış.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Sayfa Taslağını Sil', 'pages_delete_success' => 'Sayfa silindi', 'pages_delete_draft_success' => 'Sayfa taslağı silindi', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Bu sayfayı silmek istediğinize emin misiniz?', 'pages_delete_draft_confirm' => 'Bu sayfa taslağını silmek istediğinize emin misiniz?', 'pages_editing_named' => ':pageName Sayfası Düzenleniyor', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Referanslar', 'references_none' => 'Bu öğeye ilişkin takip edilen bir referans bulunmamaktadır.', - 'references_to_desc' => 'Aşağıda, sistemde bu öğeye bağlantı veren bilinen tüm sayfalar gösterilmektedir.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/tr/errors.php b/lang/tr/errors.php index 3e301b34e..587ba9b4c 100644 --- a/lang/tr/errors.php +++ b/lang/tr/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'LDAP PHP eklentisi kurulu değil', 'ldap_cannot_connect' => 'LDAP sunucusuna bağlanılamadı, ilk bağlantı başarısız oldu', 'saml_already_logged_in' => 'Zaten giriş yapılmış', - 'saml_user_not_registered' => ':name adlı kullanıcı kayıtlı değil ve otomatik kaydolma devre dışı bırakılmış', 'saml_no_email_address' => 'Harici kimlik doğrulama sisteminden gelen veriler, bu kullanıcının e-posta adresini içermiyor', 'saml_invalid_response_id' => 'Harici doğrulama sistemi tarafından sağlanan bir veri talebi, bu uygulama tarafından başlatılan bir işlem tarafından tanınamadı. Giriş yaptıktan sonra geri dönmek bu soruna yol açmış olabilir.', 'saml_fail_authed' => ':system kullanarak giriş yapma başarısız oldu; sistem, başarılı bir kimlik doğrulama sağlayamadı', diff --git a/lang/tr/notifications.php b/lang/tr/notifications.php index 5539ae9a9..1afd23f1d 100644 --- a/lang/tr/notifications.php +++ b/lang/tr/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/tr/settings.php b/lang/tr/settings.php index 1f039b072..ce312f1c3 100644 --- a/lang/tr/settings.php +++ b/lang/tr/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'İbranice', 'hr' => 'Hrvatski', diff --git a/lang/uk/activities.php b/lang/uk/activities.php index ce952049e..1ab0eca61 100644 --- a/lang/uk/activities.php +++ b/lang/uk/activities.php @@ -25,7 +25,7 @@ return [ 'chapter_delete' => 'видалив розділ', 'chapter_delete_notification' => 'Розділ успішно видалено', 'chapter_move' => 'перемістив розділ', - 'chapter_move_notification' => 'Chapter successfully moved', + 'chapter_move_notification' => 'Розділ успішно перенесений', // Books 'book_create' => 'створив книгу', @@ -50,31 +50,31 @@ return [ 'bookshelf_delete_notification' => 'Полиця успішно видалена', // Revisions - 'revision_restore' => 'restored revision', - 'revision_delete' => 'deleted revision', - 'revision_delete_notification' => 'Revision successfully deleted', + 'revision_restore' => 'відновлено версію', + 'revision_delete' => 'видалена версія', + 'revision_delete_notification' => 'Версію успішно видалено', // Favourites 'favourite_add_notification' => '":ім\'я" було додане до ваших улюлених', 'favourite_remove_notification' => '":ім\'я" було видалено з ваших улюблених', // Watching - 'watch_update_level_notification' => 'Watch preferences successfully updated', + 'watch_update_level_notification' => 'Налаштування перегляду успішно оновлено', // Auth - 'auth_login' => 'logged in', - 'auth_register' => 'registered as new user', - 'auth_password_reset_request' => 'requested user password reset', - 'auth_password_reset_update' => 'reset user password', - 'mfa_setup_method' => 'configured MFA method', + 'auth_login' => 'ввійшли', + 'auth_register' => 'зареєстрований як новий користувач', + 'auth_password_reset_request' => 'запит на скидання пароля користувача', + 'auth_password_reset_update' => 'скинути пароль користувача', + 'mfa_setup_method' => 'налаштований метод MFA', 'mfa_setup_method_notification' => 'Багатофакторний метод успішно налаштований', - 'mfa_remove_method' => 'removed MFA method', + 'mfa_remove_method' => 'видалив метод MFA', 'mfa_remove_method_notification' => 'Багатофакторний метод успішно видалений', // Settings - 'settings_update' => 'updated settings', - 'settings_update_notification' => 'Settings successfully updated', - 'maintenance_action_run' => 'ran maintenance action', + 'settings_update' => 'оновлені налаштування', + 'settings_update_notification' => 'Налаштування успішно оновлено', + 'maintenance_action_run' => 'виконуються дії щодо обслуговування', // Webhooks 'webhook_create' => 'створений вебхук', @@ -85,38 +85,38 @@ return [ 'webhook_delete_notification' => 'Вебхуки успішно видалено', // Users - 'user_create' => 'created user', - 'user_create_notification' => 'User successfully created', - 'user_update' => 'updated user', + 'user_create' => 'створений користувач', + 'user_create_notification' => 'Користувач успішно створений', + 'user_update' => 'оновлений користувач', 'user_update_notification' => 'Користувача було успішно оновлено', - 'user_delete' => 'deleted user', + 'user_delete' => 'вилучений користувач', 'user_delete_notification' => 'Користувача успішно видалено', // API Tokens - 'api_token_create' => 'created api token', - 'api_token_create_notification' => 'API token successfully created', - 'api_token_update' => 'updated api token', - 'api_token_update_notification' => 'API token successfully updated', - 'api_token_delete' => 'deleted api token', - 'api_token_delete_notification' => 'API token successfully deleted', + 'api_token_create' => 'створений APi токен', + 'api_token_create_notification' => 'API токен успішно створений', + 'api_token_update' => 'оновлено API токен', + 'api_token_update_notification' => 'Токен API успішно оновлено', + 'api_token_delete' => 'видалено API токен', + 'api_token_delete_notification' => 'API-токен успішно видалено', // Roles - 'role_create' => 'created role', + 'role_create' => 'створену роль', 'role_create_notification' => 'Роль успішно створена', - 'role_update' => 'updated role', + 'role_update' => 'оновлена роль', 'role_update_notification' => 'Роль успішно оновлена', - 'role_delete' => 'deleted role', + 'role_delete' => 'видалена роль', 'role_delete_notification' => 'Роль успішно видалена', // Recycle Bin - 'recycle_bin_empty' => 'emptied recycle bin', - 'recycle_bin_restore' => 'restored from recycle bin', - 'recycle_bin_destroy' => 'removed from recycle bin', + 'recycle_bin_empty' => 'очищено кошик', + 'recycle_bin_restore' => 'відновлено із кошику', + 'recycle_bin_destroy' => 'видалено з кошика', // Comments 'commented_on' => 'прокоментував', - 'comment_create' => 'added comment', - 'comment_update' => 'updated comment', + 'comment_create' => 'додано коментар', + 'comment_update' => 'оновлено коментар', 'comment_delete' => 'видалений коментар', // Other diff --git a/lang/uk/common.php b/lang/uk/common.php index 4459e2cb4..7d79b53f2 100644 --- a/lang/uk/common.php +++ b/lang/uk/common.php @@ -6,7 +6,7 @@ return [ // Buttons 'cancel' => 'Скасувати', - 'close' => 'Close', + 'close' => 'Закрити', 'confirm' => 'Застосувати', 'back' => 'Назад', 'save' => 'Зберегти', @@ -42,7 +42,7 @@ return [ 'remove' => 'Видалити', 'add' => 'Додати', 'configure' => 'Налаштувати', - 'manage' => 'Manage', + 'manage' => 'Управління', 'fullscreen' => 'На весь екран', 'favourite' => 'Улюблене', 'unfavourite' => 'Прибрати з обраного', @@ -52,7 +52,7 @@ return [ 'filter_clear' => 'Очистити фільтр', 'download' => 'Завантажити', 'open_in_tab' => 'Відкрити в новій вкладці', - 'open' => 'Open', + 'open' => 'Відкрити', // Sort Options 'sort_options' => 'Параметри сортування', diff --git a/lang/uk/components.php b/lang/uk/components.php index 9276c6e2f..bbcfbfe1e 100644 --- a/lang/uk/components.php +++ b/lang/uk/components.php @@ -6,36 +6,36 @@ return [ // Image Manager 'image_select' => 'Вибрати зображення', - 'image_list' => 'Image List', - 'image_details' => 'Image Details', - 'image_upload' => 'Upload Image', - 'image_intro' => 'Here you can select and manage images that have been previously uploaded to the system.', - 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.', + 'image_list' => 'Список зображень', + 'image_details' => 'Деталі зображення', + 'image_upload' => 'Завантажити зображення', + 'image_intro' => 'Тут ви можете вибрати і керувати зображеннями, які раніше були завантажені в систему.', + 'image_intro_upload' => 'Завантажте нове зображення, перетягуючи файл зображення до цього вікна або скориставшись кнопкою "Завантажити зображення" вище.', 'image_all' => 'Всі', 'image_all_title' => 'Переглянути всі зображення', 'image_book_title' => 'Переглянути зображення, завантажені в цю книгу', 'image_page_title' => 'Переглянути зображення, завантажені на цю сторінку', 'image_search_hint' => 'Пошук по імені зображення', 'image_uploaded' => 'Завантажено :uploadedDate', - 'image_uploaded_by' => 'Uploaded by :userName', - 'image_uploaded_to' => 'Uploaded to :pageLink', - 'image_updated' => 'Updated :updateDate', + 'image_uploaded_by' => 'Завантажено :userName', + 'image_uploaded_to' => 'Завантажено на :pageLink', + 'image_updated' => 'Оновлено :updateDate', 'image_load_more' => 'Завантажити ще', 'image_image_name' => 'Назва зображення', 'image_delete_used' => 'Це зображення використовується на наступних сторінках.', 'image_delete_confirm_text' => 'Ви дійсно хочете видалити це зображення?', 'image_select_image' => 'Вибрати зображення', 'image_dropzone' => 'Перетягніть зображення, або натисніть тут для завантаження', - 'image_dropzone_drop' => 'Drop images here to upload', + 'image_dropzone_drop' => 'Перетягніть зображення сюди для завантаження', 'images_deleted' => 'Зображень видалено', 'image_preview' => 'Попередній перегляд зображення', 'image_upload_success' => 'Зображення завантажено успішно', 'image_update_success' => 'Деталі зображення успішно оновлені', 'image_delete_success' => 'Зображення успішно видалено', - 'image_replace' => 'Replace Image', - 'image_replace_success' => 'Image file successfully updated', - 'image_rebuild_thumbs' => 'Regenerate Size Variations', - 'image_rebuild_thumbs_success' => 'Image size variations successfully rebuilt!', + 'image_replace' => 'Замінити зображення', + 'image_replace_success' => 'Файл зображення успішно оновлено', + 'image_rebuild_thumbs' => 'Оновити розмір', + 'image_rebuild_thumbs_success' => 'Варіації розміру зображень успішно перебудовані!', // Code Editor 'code_editor' => 'Редагувати код', diff --git a/lang/uk/entities.php b/lang/uk/entities.php index 88b7449c5..3e657cf1f 100644 --- a/lang/uk/entities.php +++ b/lang/uk/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Оновлено :timeLength', 'meta_updated_name' => ':user оновив :timeLength', 'meta_owned_name' => 'Власник :user', - 'meta_reference_page_count' => 'Посилання на :count сторінки|Посилання на :count сторінок', + 'meta_reference_count' => 'Посилання на :count елемент|Посилання – :count елементів', 'entity_select' => 'Вибір об\'єкта', 'entity_select_lack_permission' => 'У вас немає необхідних прав для вибору цього елемента', 'images' => 'Зображення', @@ -106,7 +106,7 @@ return [ 'shelves_permissions_updated' => 'Дозволи полиці оновлено', 'shelves_permissions_active' => 'Дозволи полиці активні', 'shelves_permissions_cascade_warning' => 'Дозволи на полицях не каскадують автоматично до вміщених книг. Це тому, що книга може стояти на кількох полицях. Однак дозволи можна скопіювати до дочірніх книг за допомогою наведеної нижче опції.', - 'shelves_permissions_create' => 'Shelf create permissions are only used for copying permissions to child books using the action below. They do not control the ability to create books.', + 'shelves_permissions_create' => 'Створення привілеїв для копіювання дозволів для дочірніх книг, використовуючи наведену нижче дію. Вони не контролюють можливість створення книг.', 'shelves_copy_permissions_to_books' => 'Копіювати дозволи на книги', 'shelves_copy_permissions' => 'Копіювати дозволи', 'shelves_copy_permissions_explain' => 'Це застосує поточні налаштування дозволів цієї полиці до всіх книг, які містяться в ній. Перед активацією переконайтеся, що будь-які зміни в дозволах цієї полиці збережено.', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Редагувати книгу :bookName', 'books_form_book_name' => 'Назва книги', 'books_save' => 'Зберегти книгу', + 'books_default_template' => 'Типовий шаблон сторінки', + 'books_default_template_explain' => 'Призначити шаблон сторінки, який буде використовуватися як типовий вміст для всіх нових сторінок цієї книги. Майте на увазі, що це буде використано лише в тому випадку, якщо творець сторінки має доступ до обраної сторінки шаблону.', + 'books_default_template_select' => 'Виберіть сторінку шаблону', 'books_permissions' => 'Дозволи на книгу', 'books_permissions_updated' => 'Дозволи на книгу оновлено', 'books_empty_contents' => 'Для цієї книги не створено жодної сторінки або розділів.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Видалити чернетку', 'pages_delete_success' => 'Сторінка видалена', 'pages_delete_draft_success' => 'Чернетка видалена', + 'pages_delete_warning_template' => 'Ця сторінка використовується як шаблон сторінки за промовчанням. У цих книгах немає стандартного шаблону сторінки, призначеного після видалення цієї сторінки.', 'pages_delete_confirm' => 'Ви впевнені, що хочете видалити цю сторінку?', 'pages_delete_draft_confirm' => 'Ви впевнені, що хочете видалити цю чернетку?', 'pages_editing_named' => 'Редагування сторінки :pageName', @@ -214,7 +218,7 @@ return [ 'pages_editing_page' => 'Редагування сторінки', 'pages_edit_draft_save_at' => 'Чернетка збережена о ', 'pages_edit_delete_draft' => 'Видалити чернетку', - 'pages_edit_delete_draft_confirm' => 'Are you sure you want to delete your draft page changes? All of your changes, since the last full save, will be lost and the editor will be updated with the latest page non-draft save state.', + 'pages_edit_delete_draft_confirm' => 'Ви дійсно бажаєте видалити зміни у чернетці? Всі зміни, починаючи з останнього повного збереження, будуть втрачені і редактор буде оновлений з останньою сторінкою збереження без чернетки.', 'pages_edit_discard_draft' => 'Відхилити чернетку', 'pages_edit_switch_to_markdown' => 'Змінити редактор на Markdown', 'pages_edit_switch_to_markdown_clean' => '(Очистити вміст)', @@ -239,8 +243,8 @@ return [ 'pages_md_insert_drawing' => 'Вставити малюнок', 'pages_md_show_preview' => 'Показати попередній перегляд', 'pages_md_sync_scroll' => 'Синхронізація прокручування попереднього перегляду', - 'pages_drawing_unsaved' => 'Unsaved Drawing Found', - 'pages_drawing_unsaved_confirm' => 'Unsaved drawing data was found from a previous failed drawing save attempt. Would you like to restore and continue editing this unsaved drawing?', + 'pages_drawing_unsaved' => 'Знайдено незбережену чернетку', + 'pages_drawing_unsaved_confirm' => 'Незбережені чернетки були знайдені з попередньої спроби зберегти звіт. Хочете відновити і продовжити редагування цієї чернетки?', 'pages_not_in_chapter' => 'Сторінка не знаходиться в розділі', 'pages_move' => 'Перемістити сторінку', 'pages_copy' => 'Копіювати сторінку', @@ -268,13 +272,13 @@ return [ 'pages_revisions_restore' => 'Відновити', 'pages_revisions_none' => 'Ця сторінка не має версій', 'pages_copy_link' => 'Копіювати посилання', - 'pages_edit_content_link' => 'Jump to section in editor', - 'pages_pointer_enter_mode' => 'Enter section select mode', - 'pages_pointer_label' => 'Page Section Options', - 'pages_pointer_permalink' => 'Page Section Permalink', - 'pages_pointer_include_tag' => 'Page Section Include Tag', - 'pages_pointer_toggle_link' => 'Permalink mode, Press to show include tag', - 'pages_pointer_toggle_include' => 'Include tag mode, Press to show permalink', + 'pages_edit_content_link' => 'Перейти до розділу в редакторі', + 'pages_pointer_enter_mode' => 'Введіть режим вибору розділу', + 'pages_pointer_label' => 'Параметри розділу сторінки', + 'pages_pointer_permalink' => 'Постійне посилання на секцію сторінок', + 'pages_pointer_include_tag' => ' Секція сторінки включаючи тег', + 'pages_pointer_toggle_link' => 'Постійне посилання, натисніть для включення тегу', + 'pages_pointer_toggle_include' => 'Включити режим тегів, натисніть для відображення постійного посилання', 'pages_permissions_active' => 'Активні дозволи сторінки', 'pages_initial_revision' => 'Початкова публікація', 'pages_references_update_revision' => 'Автоматичне оновлення системних посилань', @@ -289,13 +293,13 @@ return [ 'time_b' => 'за останні :minCount хвилин', 'message' => ':start :time. Будьте обережні, щоб не перезаписати оновлення інших!', ], - 'pages_draft_discarded' => 'Draft discarded! The editor has been updated with the current page content', - 'pages_draft_deleted' => 'Draft deleted! The editor has been updated with the current page content', + 'pages_draft_discarded' => 'Чернетку відкинуто! Редактор був оновлений з поточним вмістом сторінки', + 'pages_draft_deleted' => 'Чернетку видалено! Редактор був оновлений з поточною сторінкою вмісту', 'pages_specific' => 'Конкретна сторінка', 'pages_is_template' => 'Шаблон сторінки', // Editor Sidebar - 'toggle_sidebar' => 'Toggle Sidebar', + 'toggle_sidebar' => 'Перемикач бічної панелі', 'page_tags' => 'Теги сторінки', 'chapter_tags' => 'Теги розділів', 'book_tags' => 'Теги книг', @@ -323,10 +327,10 @@ return [ 'attachments_explain_instant_save' => 'Зміни тут зберігаються миттєво.', 'attachments_upload' => 'Завантажити файл', 'attachments_link' => 'Приєднати посилання', - 'attachments_upload_drop' => 'Alternatively you can drag and drop a file here to upload it as an attachment.', + 'attachments_upload_drop' => 'Крім того, ви можете перетягувати файл тут і завантажити його в якості вкладення.', 'attachments_set_link' => 'Встановити посилання', 'attachments_delete' => 'Дійсно хочете видалити це вкладення?', - 'attachments_dropzone' => 'Drop files here to upload', + 'attachments_dropzone' => 'Для завантаження перетягніть файли', 'attachments_no_files' => 'Файли не завантажені', 'attachments_explain_link' => 'Ви можете приєднати посилання, якщо не бажаєте завантажувати файл. Це може бути посилання на іншу сторінку або посилання на файл у хмарі.', 'attachments_link_name' => 'Назва посилання', @@ -369,13 +373,13 @@ return [ 'comment_new' => 'Новий коментар', 'comment_created' => 'прокоментував :createDiff', 'comment_updated' => 'Оновлено :updateDiff користувачем :username', - 'comment_updated_indicator' => 'Updated', + 'comment_updated_indicator' => 'Оновлено', 'comment_deleted_success' => 'Коментар видалено', 'comment_created_success' => 'Коментар додано', 'comment_updated_success' => 'Коментар оновлено', 'comment_delete_confirm' => 'Ви впевнені, що хочете видалити цей коментар?', 'comment_in_reply_to' => 'У відповідь на :commentId', - 'comment_editor_explain' => 'Here are the comments that have been left on this page. Comments can be added & managed when viewing the saved page.', + 'comment_editor_explain' => 'Ось коментарі, які залишилися на цій сторінці. Коментарі можна додати та керовані при перегляді збереженої сторінки.', // Revision 'revision_delete_confirm' => 'Ви впевнені, що хочете видалити цю версію?', @@ -405,29 +409,29 @@ return [ // References 'references' => 'Посилання', 'references_none' => 'Немає відслідковуваних посилань для цього елемента.', - 'references_to_desc' => 'Показані нижче всі відомі сторінки в системі, що посилаються на цей елемент.', + 'references_to_desc' => 'У списку наведений нижче всі відомі вміст системи, посилання на цей вузол.', // Watch Options - 'watch' => 'Watch', - 'watch_title_default' => 'Default Preferences', - 'watch_desc_default' => 'Revert watching to just your default notification preferences.', - 'watch_title_ignore' => 'Ignore', - 'watch_desc_ignore' => 'Ignore all notifications, including those from user-level preferences.', - 'watch_title_new' => 'New Pages', - 'watch_desc_new' => 'Notify when any new page is created within this item.', - 'watch_title_updates' => 'All Page Updates', - 'watch_desc_updates' => 'Notify upon all new pages and page changes.', - 'watch_desc_updates_page' => 'Notify upon all page changes.', - 'watch_title_comments' => 'All Page Updates & Comments', - 'watch_desc_comments' => 'Notify upon all new pages, page changes and new comments.', - 'watch_desc_comments_page' => 'Notify upon page changes and new comments.', - 'watch_change_default' => 'Change default notification preferences', - 'watch_detail_ignore' => 'Ignoring notifications', - 'watch_detail_new' => 'Watching for new pages', - 'watch_detail_updates' => 'Watching new pages and updates', - 'watch_detail_comments' => 'Watching new pages, updates & comments', - 'watch_detail_parent_book' => 'Watching via parent book', - 'watch_detail_parent_book_ignore' => 'Ignoring via parent book', - 'watch_detail_parent_chapter' => 'Watching via parent chapter', - 'watch_detail_parent_chapter_ignore' => 'Ignoring via parent chapter', + 'watch' => 'Дивитися', + 'watch_title_default' => 'Властивості по замовчуванню', + 'watch_desc_default' => 'Відновити перегляд лише до типових налаштувань сповіщень.', + 'watch_title_ignore' => 'Ігнорувати', + 'watch_desc_ignore' => 'Ігнорувати всі повідомлення, у тому числі з налаштувань рівня користувача.', + 'watch_title_new' => 'Нові сторінки', + 'watch_desc_new' => 'Сповіщати при створенні нової сторінки у цьому елементі.', + 'watch_title_updates' => 'Оновлення всієї сторінки', + 'watch_desc_updates' => 'Сповіщати про всі нові сторінки і зміни сторінок.', + 'watch_desc_updates_page' => 'Сповіщати про зміни на всіх сторінках.', + 'watch_title_comments' => 'Всі оновлення та коментарі до сторінки', + 'watch_desc_comments' => 'Повідомляти про всі нові сторінки, зміни до сторінки і нові коментарі.', + 'watch_desc_comments_page' => 'Повідомляти про зміни сторінки і нові коментарі.', + 'watch_change_default' => 'Змінити налаштування сповіщень за замовчуванням', + 'watch_detail_ignore' => 'Ігнорування сповіщень', + 'watch_detail_new' => 'Перегляд нових сторінок', + 'watch_detail_updates' => 'Перегляд нових сторінок і оновлень', + 'watch_detail_comments' => 'Перегляд нових сторінок, оновлень та коментарів', + 'watch_detail_parent_book' => 'Перегляд за допомогою батьківської книги', + 'watch_detail_parent_book_ignore' => 'Ігнорування за допомогою батьківської книги', + 'watch_detail_parent_chapter' => 'Перегляд через батьківську главу', + 'watch_detail_parent_chapter_ignore' => 'Ігнорування через батьківську главу', ]; diff --git a/lang/uk/errors.php b/lang/uk/errors.php index e07e85668..533d3a1e2 100644 --- a/lang/uk/errors.php +++ b/lang/uk/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'Розширення PHP LDAP не встановлено', 'ldap_cannot_connect' => 'Неможливо підключитися до ldap-сервера, Помилка з\'єднання', 'saml_already_logged_in' => 'Вже увійшли', - 'saml_user_not_registered' => 'Користувач «:name» не зареєстрований, а автоматична реєстрація вимкнена', 'saml_no_email_address' => 'Не вдалося знайти електронну адресу для цього користувача у даних, наданих зовнішньою системою аутентифікації', 'saml_invalid_response_id' => 'Запит із зовнішньої системи аутентифікації не розпізнається процесом, розпочатим цим додатком. Повернення назад після входу могла спричинити цю проблему.', 'saml_fail_authed' => 'Вхід із використанням «:system» не вдався, система не здійснила успішну авторизацію', @@ -44,25 +43,25 @@ return [ 'cannot_get_image_from_url' => 'Неможливо отримати зображення з :url', 'cannot_create_thumbs' => 'Сервер не може створювати ескізи. Будь ласка, перевірте, чи встановлено розширення GD PHP.', 'server_upload_limit' => 'Сервер не дозволяє завантажувати файли такого розміру. Спробуйте менший розмір файлу.', - 'server_post_limit' => 'The server cannot receive the provided amount of data. Try again with less data or a smaller file.', + 'server_post_limit' => 'Сервер не може отримати вказаний обсяг даних. Спробуйте ще раз з меншими даними або меншим файлом.', 'uploaded' => 'Сервер не дозволяє завантажувати файли такого розміру. Спробуйте менший розмір файлу.', // Drawing & Images 'image_upload_error' => 'Виникла помилка під час завантаження зображення', 'image_upload_type_error' => 'Тип завантаженого зображення недійсний', - 'image_upload_replace_type' => 'Image file replacements must be of the same type', - 'image_upload_memory_limit' => 'Failed to handle image upload and/or create thumbnails due to system resource limits.', - 'image_thumbnail_memory_limit' => 'Failed to create image size variations due to system resource limits.', - 'image_gallery_thumbnail_memory_limit' => 'Failed to create gallery thumbnails due to system resource limits.', + 'image_upload_replace_type' => 'Замінники файлів зображень повинні мати однаковий тип', + 'image_upload_memory_limit' => 'Не вдалося завантажити зображення і/або створити ескізи через обмеження системних ресурсів.', + 'image_thumbnail_memory_limit' => 'Не вдалося створити варіації розміру зображення через обмеження системних ресурсів.', + 'image_gallery_thumbnail_memory_limit' => 'Не вдалося створити галерею через обмеження системних ресурсів.', 'drawing_data_not_found' => 'Не вдалося завантажити дані малюнка. Файл малюнка може більше не існувати або у вас немає дозволу на доступ до нього.', // Attachments 'attachment_not_found' => 'Вкладення не знайдено', - 'attachment_upload_error' => 'An error occurred uploading the attachment file', + 'attachment_upload_error' => 'Сталася помилка при завантаженні файлу', // Pages 'page_draft_autosave_fail' => 'Не вдалося зберегти чернетку. Перед збереженням цієї сторінки переконайтеся, що у вас є зв\'язок з сервером.', - 'page_draft_delete_fail' => 'Failed to delete page draft and fetch current page saved content', + 'page_draft_delete_fail' => 'Не вдалося видалити чернетку сторінки та отримати збережений вміст сторінки', 'page_custom_home_deletion' => 'Неможливо видалити сторінку, коли вона встановлена як домашня сторінка', // Entities @@ -116,5 +115,5 @@ return [ 'maintenance_test_email_failure' => 'Помилка під час надсилання тестового електронного листа:', // HTTP errors - 'http_ssr_url_no_match' => 'The URL does not match the configured allowed SSR hosts', + 'http_ssr_url_no_match' => 'URL-адреса не відповідає налаштованим дозволеним SSR хостів', ]; diff --git a/lang/uk/notifications.php b/lang/uk/notifications.php index 5539ae9a9..a08b9a100 100644 --- a/lang/uk/notifications.php +++ b/lang/uk/notifications.php @@ -4,23 +4,24 @@ */ return [ - 'new_comment_subject' => 'New comment on page: :pageName', - 'new_comment_intro' => 'A user has commented on a page in :appName:', - 'new_page_subject' => 'New page: :pageName', - 'new_page_intro' => 'A new page has been created in :appName:', - 'updated_page_subject' => 'Updated page: :pageName', - 'updated_page_intro' => 'A page has been updated in :appName:', - 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', + 'new_comment_subject' => 'Новий коментар на сторінці: :pageName', + 'new_comment_intro' => 'Користувач прокоментував на сторінці у :appName:', + 'new_page_subject' => 'Нова сторінка: :pageName', + 'new_page_intro' => 'Створено сторінку у :appName:', + 'updated_page_subject' => 'Оновлено сторінку: :pageName', + 'updated_page_intro' => 'Оновлено сторінку у :appName:', + 'updated_page_debounce' => 'Для запобігання кількості сповіщень, деякий час ви не будете відправлені повідомлення для подальших змін на цій сторінці тим самим редактором.', - 'detail_page_name' => 'Page Name:', - 'detail_commenter' => 'Commenter:', - 'detail_comment' => 'Comment:', - 'detail_created_by' => 'Created By:', - 'detail_updated_by' => 'Updated By:', + 'detail_page_name' => 'Назва сторінки:', + 'detail_page_path' => 'Шлях до сторінки:', + 'detail_commenter' => 'Коментатор:', + 'detail_comment' => 'Коментар:', + 'detail_created_by' => 'Створено:', + 'detail_updated_by' => 'Оновлено:', - 'action_view_comment' => 'View Comment', - 'action_view_page' => 'View Page', + 'action_view_comment' => 'Переглянути коментар', + 'action_view_page' => 'Дивитись сторінку', - 'footer_reason' => 'This notification was sent to you because :link cover this type of activity for this item.', - 'footer_reason_link' => 'your notification preferences', + 'footer_reason' => 'Дане повідомлення було надіслано вам тому, що :link покриває цю діяльність для цього елемента.', + 'footer_reason_link' => 'ваші налаштування сповіщень', ]; diff --git a/lang/uk/preferences.php b/lang/uk/preferences.php index 25683e38f..2383c6793 100644 --- a/lang/uk/preferences.php +++ b/lang/uk/preferences.php @@ -5,10 +5,10 @@ */ return [ - 'my_account' => 'My Account', + 'my_account' => 'Мій аккаунт', 'shortcuts' => 'Ярлики', - 'shortcuts_interface' => 'UI Shortcut Preferences', + 'shortcuts_interface' => 'Налаштування ярлика інтерфейсу', 'shortcuts_toggle_desc' => 'Тут ви можете увімкнути або вимкнути ярлики інтерфейсу клавіатури, які використовуються для навігації та дій.', 'shortcuts_customize_desc' => 'Ви можете налаштувати кожен з ярликів нижче. Просто натисніть на комбінацію бажаного ключа після вибору вводу для ярлика.', 'shortcuts_toggle_label' => 'Клавіатурні скорочення увімкнено', @@ -17,35 +17,35 @@ return [ 'shortcuts_save' => 'Зберегти ярлики', 'shortcuts_overlay_desc' => 'Примітка: якщо ярлики ввімкнено, допоміжне накладання доступне, натиснувши "?" який виділить доступні ярлики для дій, які зараз видно на екрані.', 'shortcuts_update_success' => 'Налаштування ярликів оновлено!', - 'shortcuts_overview_desc' => 'Manage keyboard shortcuts you can use to navigate the system user interface.', + 'shortcuts_overview_desc' => 'Керуйте комбінаціями клавіатур можна використовувати для навігації інтерфейсу системи користувача.', - 'notifications' => 'Notification Preferences', - 'notifications_desc' => 'Control the email notifications you receive when certain activity is performed within the system.', - 'notifications_opt_own_page_changes' => 'Notify upon changes to pages I own', - 'notifications_opt_own_page_comments' => 'Notify upon comments on pages I own', - 'notifications_opt_comment_replies' => 'Notify upon replies to my comments', - 'notifications_save' => 'Save Preferences', - 'notifications_update_success' => 'Notification preferences have been updated!', - 'notifications_watched' => 'Watched & Ignored Items', - 'notifications_watched_desc' => ' Below are the items that have custom watch preferences applied. To update your preferences for these, view the item then find the watch options in the sidebar.', + 'notifications' => 'Налаштування сповіщень', + 'notifications_desc' => 'Контролюйте сповіщення по електронній пошті, які ви отримуєте, коли виконується певна активність у системі.', + 'notifications_opt_own_page_changes' => 'Повідомляти при змінах сторінок якими я володію', + 'notifications_opt_own_page_comments' => 'Повідомляти при коментарях на моїх сторінках', + 'notifications_opt_comment_replies' => 'Повідомляти про відповіді на мої коментарі', + 'notifications_save' => 'Зберегти налаштування', + 'notifications_update_success' => 'Налаштування сповіщень було оновлено!', + 'notifications_watched' => 'Переглянуті та ігноровані елементи', + 'notifications_watched_desc' => ' Нижче наведені предмети, які мають застосовані налаштування перегляду. Щоб оновити ваші налаштування для них, перегляньте елемент, а потім знайдіть параметри перегляду на бічній панелі.', - 'auth' => 'Access & Security', - 'auth_change_password' => 'Change Password', - 'auth_change_password_desc' => 'Change the password you use to log-in to the application. This must be at least 8 characters long.', - 'auth_change_password_success' => 'Password has been updated!', + 'auth' => 'Доступ і безпека', + 'auth_change_password' => 'Змінити пароль', + 'auth_change_password_desc' => 'Змініть пароль, який ви використовуєте для входу в програму. Це має бути щонайменше 8 символів.', + 'auth_change_password_success' => 'Пароль оновлено!', - 'profile' => 'Profile Details', - 'profile_desc' => 'Manage the details of your account which represents you to other users, in addition to details that are used for communication and system personalisation.', - 'profile_view_public' => 'View Public Profile', - 'profile_name_desc' => 'Configure your display name which will be visible to other users in the system through the activity you perform, and content you own.', - 'profile_email_desc' => 'This email will be used for notifications and, depending on active system authentication, system access.', - 'profile_email_no_permission' => 'Unfortunately you don\'t have permission to change your email address. If you want to change this, you\'d need to ask an administrator to change this for you.', - 'profile_avatar_desc' => 'Select an image which will be used to represent yourself to others in the system. Ideally this image should be square and about 256px in width and height.', - 'profile_admin_options' => 'Administrator Options', - 'profile_admin_options_desc' => 'Additional administrator-level options, like those to manage role assignments, can be found for your user account in the "Settings > Users" area of the application.', + 'profile' => 'Деталі профілю', + 'profile_desc' => 'Керуйте інформацією вашого облікового запису, що представляє вам інші користувачі, додатково до деталей, що використовуються для комунікації та особистості системи.', + 'profile_view_public' => 'Перегляд загального профілю', + 'profile_name_desc' => 'Налаштування відображуваного імена, які будуть видимі іншим користувачам в системі через здійснені вами дії та власний контент.', + 'profile_email_desc' => 'Цей email буде використовуватися для сповіщення і в залежності від активної автентифікації системи, доступу до системи.', + 'profile_email_no_permission' => 'На жаль, у вас немає дозволу на зміну адреси електронної пошти. Якщо ви хочете змінити це, ви маєте попросити адміністратора змінити це для вас.', + 'profile_avatar_desc' => 'Виберіть зображення, яке буде використовуватися для того, щоб представити себе іншим у системі. В ідеалі це зображення має бути квадратне і близько 256пікс в ширину і висоту.', + 'profile_admin_options' => 'Параметри адміністратора', + 'profile_admin_options_desc' => 'Додаткові параметри на рівні адміністратора, так як і для управління призначеннями роль, ви можете знайти для вашого облікового запису в області "Налаштування> Користувачі" додатку.', - 'delete_account' => 'Delete Account', - 'delete_my_account' => 'Delete My Account', - 'delete_my_account_desc' => 'This will fully delete your user account from the system. You will not be able to recover this account or revert this action. Content you\'ve created, such as created pages and uploaded images, will remain.', - 'delete_my_account_warning' => 'Are you sure you want to delete your account?', + 'delete_account' => 'Видалити обліковий запис', + 'delete_my_account' => 'Видалити мій обліковий запис', + 'delete_my_account_desc' => 'Це повністю видалить ваш обліковий запис з системи. Ви не зможете відновити або скасувати цю дію. Контент, який Ви створили, наприклад створені сторінки і вивантажені зображення, залишиться.', + 'delete_my_account_warning' => 'Ви впевнені, що хочете видалити свій обліковий запис?', ]; diff --git a/lang/uk/settings.php b/lang/uk/settings.php index b3323f33b..bd1a20ec8 100644 --- a/lang/uk/settings.php +++ b/lang/uk/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/uz/entities.php b/lang/uz/entities.php index 9385670a4..0effadf46 100644 --- a/lang/uz/entities.php +++ b/lang/uz/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => ':timeLength da yangilangan', 'meta_updated_name' => ':user tomonidan :timeLength da yangilangan', 'meta_owned_name' => 'Muallif: foydalanuvchi', - 'meta_reference_page_count' => ':count sahifasida havola qilingan :count sahifalarida havola qilingan', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Ob\'ektni tanlash', 'entity_select_lack_permission' => 'Sizda bu elementni tanlash uchun kerakli ruxsatlar yo‘q', 'images' => 'Rasmlar', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Kitobni tahrirlash: kitob nomi', 'books_form_book_name' => 'Kitob nomi', 'books_save' => 'Kitobni saqlash', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Kitob ruxsatnomalari', 'books_permissions_updated' => 'Kitob ruxsatnomalari yangilandi', 'books_empty_contents' => 'Ushbu kitob uchun hech qanday sahifa yoki bob yaratilmagan.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Qoralama sahifani oʻchirish', 'pages_delete_success' => 'Sahifa oʻchirildi', 'pages_delete_draft_success' => 'Qoralama sahifa oʻchirildi', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Haqiqatan ham bu sahifani oʻchirib tashlamoqchimisiz?', 'pages_delete_draft_confirm' => 'Haqiqatan ham bu qoralama sahifani oʻchirib tashlamoqchimisiz?', 'pages_editing_named' => 'Sahifani tahrirlash :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'Ma\'lumotnomalar', 'references_none' => 'Bu elementga kuzatilgan havolalar mavjud emas.', - 'references_to_desc' => 'Quyida ushbu elementga bog\'langan tizimdagi barcha ma\'lum sahifalar ko\'rsatilgan.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Tomosha qiling', diff --git a/lang/uz/errors.php b/lang/uz/errors.php index 3f1c11165..e37ca8bbe 100644 --- a/lang/uz/errors.php +++ b/lang/uz/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'LDAP PHP kengaytmasi oʻrnatilmagan', 'ldap_cannot_connect' => 'Ldap serveriga ulanib boʻlmadi, Dastlabki ulanish amalga oshmadi', 'saml_already_logged_in' => 'Allaqachon tizimga kirgan', - 'saml_user_not_registered' => 'Foydalanuvchi :name roʻyxatdan oʻtmagan va avtomatik roʻyxatdan oʻtish oʻchirilgan', 'saml_no_email_address' => 'Tashqi autentifikatsiya tizimi tomonidan taqdim etilgan maʼlumotlarda ushbu foydalanuvchi uchun elektron pochta manzili topilmadi', 'saml_invalid_response_id' => 'Tashqi autentifikatsiya tizimidagi so‘rov ushbu ilova tomonidan boshlangan jarayon tomonidan tan olinmaydi. Kirishdan keyin orqaga qaytish bu muammoga olib kelishi mumkin.', 'saml_fail_authed' => ':tizim yordamida tizimga kirish amalga oshmadi, tizim muvaffaqiyatli avtorizatsiyani taqdim etmadi', diff --git a/lang/uz/notifications.php b/lang/uz/notifications.php index 46e636c6f..bec9b3925 100644 --- a/lang/uz/notifications.php +++ b/lang/uz/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'Xabarnomalar koʻp boʻlishining oldini olish uchun bir muncha vaqt oʻsha muharrir tomonidan ushbu sahifaga keyingi tahrirlar haqida bildirishnomalar yuborilmaydi.', 'detail_page_name' => 'Sahifa nomi:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Izoh egasi:', 'detail_comment' => 'Izoh:', 'detail_created_by' => 'Tomonidan yaratildi:', diff --git a/lang/uz/settings.php b/lang/uz/settings.php index 2286ee14d..f0c23e445 100644 --- a/lang/uz/settings.php +++ b/lang/uz/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/vi/entities.php b/lang/vi/entities.php index b98361fd1..5740a3483 100644 --- a/lang/vi/entities.php +++ b/lang/vi/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Được cập nhật :timeLength', 'meta_updated_name' => 'Được cập nhật :timeLength bởi :user', 'meta_owned_name' => 'Được sở hữu bởi :user', - 'meta_reference_page_count' => 'Được tham chiếu trên :count page|Được tham chiếu trên :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => 'Chọn thực thể', 'entity_select_lack_permission' => 'Bạn không có quyền để chọn mục này', 'images' => 'Ảnh', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => 'Sửa sách :bookName', 'books_form_book_name' => 'Tên sách', 'books_save' => 'Lưu sách', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => 'Các quyền của cuốn sách', 'books_permissions_updated' => 'Các quyền của cuốn sách đã được cập nhật', 'books_empty_contents' => 'Không có trang hay chương nào được tạo cho cuốn sách này.', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => 'Xóa Trang Nháp', 'pages_delete_success' => 'Đã xóa Trang', 'pages_delete_draft_success' => 'Đã xóa trang Nháp', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => 'Bạn có chắc chắn muốn xóa trang này?', 'pages_delete_draft_confirm' => 'Bạn có chắc chắn muốn xóa trang nháp này?', 'pages_editing_named' => 'Đang chỉnh sửa Trang :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'References', 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/vi/errors.php b/lang/vi/errors.php index 4fe7f3829..1b69b5818 100644 --- a/lang/vi/errors.php +++ b/lang/vi/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => 'Tiện ích mở rộng LDAP PHP chưa được cài đặt', 'ldap_cannot_connect' => 'Không thể kết nối đến máy chủ LDAP, mở đầu kết nối thất bại', 'saml_already_logged_in' => 'Đã đăng nhập', - 'saml_user_not_registered' => 'Người dùng :name chưa được đăng ký và tự động đăng ký đang bị tắt', 'saml_no_email_address' => 'Không tìm thấy địa chỉ email cho người dùng này trong dữ liệu được cung cấp bới hệ thống xác thực ngoài', 'saml_invalid_response_id' => 'Yêu cầu từ hệ thống xác thực bên ngoài không được nhận diện bởi quy trình chạy cho ứng dụng này. Điều hướng trở lại sau khi đăng nhập có thể đã gây ra vấn đề này.', 'saml_fail_authed' => 'Đăng nhập sử dụng :system thất bại, hệ thống không cung cấp được sự xác thực thành công', diff --git a/lang/vi/notifications.php b/lang/vi/notifications.php index 5539ae9a9..1afd23f1d 100644 --- a/lang/vi/notifications.php +++ b/lang/vi/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/vi/settings.php b/lang/vi/settings.php index 4bda6fcee..929f1f7b2 100644 --- a/lang/vi/settings.php +++ b/lang/vi/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/zh_CN/entities.php b/lang/zh_CN/entities.php index a4bd4664a..a0c32fa4f 100644 --- a/lang/zh_CN/entities.php +++ b/lang/zh_CN/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => '更新于 :timeLength', 'meta_updated_name' => '由 :user 更新于 :timeLength', 'meta_owned_name' => '拥有者 :user', - 'meta_reference_page_count' => '被 :count 个页面引用|被 :count 个页面引用', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => '选择项目', 'entity_select_lack_permission' => '您没有选择此项目所需的权限', 'images' => '图片', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => '编辑图书「:bookName」', 'books_form_book_name' => '书名', 'books_save' => '保存图书', + 'books_default_template' => '默认页面模板', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => '选择模板页面', 'books_permissions' => '图书权限', 'books_permissions_updated' => '图书权限已更新', 'books_empty_contents' => '本书目前没有页面或章节。', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => '删除草稿页面', 'pages_delete_success' => '页面已删除', 'pages_delete_draft_success' => '草稿页面已删除', + 'pages_delete_warning_template' => '此页面是当前的书籍默认页面模板。删除此页面后,将不再为这些书籍分配默认页面模板。', 'pages_delete_confirm' => '您确定要删除此页面吗?', 'pages_delete_draft_confirm' => '您确定要删除此草稿页面吗?', 'pages_editing_named' => '正在编辑页面“:pageName”', @@ -405,7 +409,7 @@ return [ // References 'references' => '引用', 'references_none' => '没有跟踪到对此项目的引用。', - 'references_to_desc' => '下面显示的是系统中所有已知链接到这个项目的页面。', + 'references_to_desc' => '下方列出了系统中链接到此项目的所有已知内容。', // Watch Options 'watch' => '关注', diff --git a/lang/zh_CN/errors.php b/lang/zh_CN/errors.php index 42e2378d9..3dbf3c490 100644 --- a/lang/zh_CN/errors.php +++ b/lang/zh_CN/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => '未安装LDAP PHP扩展程序', 'ldap_cannot_connect' => '无法连接到ldap服务器,初始连接失败', 'saml_already_logged_in' => '您已经登陆了', - 'saml_user_not_registered' => '用户 :name 未注册且自动注册功能已被禁用', 'saml_no_email_address' => '无法找到有效Email地址,此用户数据由外部身份验证系统托管', 'saml_invalid_response_id' => '来自外部身份验证系统的请求没有被本应用程序认证,在登录后返回上一页可能会导致此问题。', 'saml_fail_authed' => '使用 :system 登录失败,登录系统未返回成功登录授权信息。', diff --git a/lang/zh_CN/notifications.php b/lang/zh_CN/notifications.php index 363ba134b..52c9822bc 100644 --- a/lang/zh_CN/notifications.php +++ b/lang/zh_CN/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => '为了防止出现大量通知,一段时间内您不会收到同一编辑者再次编辑本页面的通知。', 'detail_page_name' => '页面名称:', + 'detail_page_path' => '页面路径:', 'detail_commenter' => '评论者:', 'detail_comment' => '评论:', 'detail_created_by' => '创建者:', diff --git a/lang/zh_CN/settings.php b/lang/zh_CN/settings.php index b6daf33f4..4bf868af6 100644 --- a/lang/zh_CN/settings.php +++ b/lang/zh_CN/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => 'עברית', 'hr' => 'Hrvatski', diff --git a/lang/zh_TW/entities.php b/lang/zh_TW/entities.php index 13d4acefd..a7eb9b151 100644 --- a/lang/zh_TW/entities.php +++ b/lang/zh_TW/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => '更新於 :timeLength', 'meta_updated_name' => '由 :user 更新於 :timeLength', 'meta_owned_name' => ':user 所擁有', - 'meta_reference_page_count' => 'Referenced on :count page|Referenced on :count pages', + 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', 'entity_select' => '選取項目', 'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item', 'images' => '圖片', @@ -132,6 +132,9 @@ return [ 'books_edit_named' => '編輯書本「:bookName」', 'books_form_book_name' => '書本名稱', 'books_save' => '儲存書本', + 'books_default_template' => 'Default Page Template', + 'books_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'books_default_template_select' => 'Select a template page', 'books_permissions' => '書本權限', 'books_permissions_updated' => '書本權限已更新', 'books_empty_contents' => '本書目前沒有頁面或章節。', @@ -204,6 +207,7 @@ return [ 'pages_delete_draft' => '刪除草稿頁面', 'pages_delete_success' => '頁面已刪除', 'pages_delete_draft_success' => '草稿頁面已刪除', + 'pages_delete_warning_template' => 'This page is in active use as a book default page template. These books will no longer have a default page template assigned after this page is deleted.', 'pages_delete_confirm' => '您確定要刪除此頁面嗎?', 'pages_delete_draft_confirm' => '您確定要刪除此草稿頁面嗎?', 'pages_editing_named' => '正在編輯頁面 :pageName', @@ -405,7 +409,7 @@ return [ // References 'references' => 'References', 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options 'watch' => 'Watch', diff --git a/lang/zh_TW/errors.php b/lang/zh_TW/errors.php index 19ae6dda0..044377a75 100644 --- a/lang/zh_TW/errors.php +++ b/lang/zh_TW/errors.php @@ -19,7 +19,6 @@ return [ 'ldap_extension_not_installed' => '未安裝 PHP 的 LDAP 擴充程式', 'ldap_cannot_connect' => '無法連線至 LDAP 伺服器,初始化連線失敗', 'saml_already_logged_in' => '已登入', - 'saml_user_not_registered' => '使用者 :name 未註冊,並已停用自動註冊', 'saml_no_email_address' => '在外部認證系統提供的資料中找不到該使用者的電子郵件地址', 'saml_invalid_response_id' => '此應用程式啟動的處理程序無法識別來自外部認證系統的請求。登入後回上一頁可能會造成此問題。', 'saml_fail_authed' => '使用 :system 登入失敗,系統未提供成功的授權', diff --git a/lang/zh_TW/notifications.php b/lang/zh_TW/notifications.php index 5539ae9a9..1afd23f1d 100644 --- a/lang/zh_TW/notifications.php +++ b/lang/zh_TW/notifications.php @@ -13,6 +13,7 @@ return [ 'updated_page_debounce' => 'To prevent a mass of notifications, for a while you won\'t be sent notifications for further edits to this page by the same editor.', 'detail_page_name' => 'Page Name:', + 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', 'detail_comment' => 'Comment:', 'detail_created_by' => 'Created By:', diff --git a/lang/zh_TW/settings.php b/lang/zh_TW/settings.php index fd1656bee..ee05b2024 100644 --- a/lang/zh_TW/settings.php +++ b/lang/zh_TW/settings.php @@ -296,6 +296,7 @@ return [ 'et' => 'Eesti keel', 'eu' => 'Euskara', 'fa' => 'فارسی', + 'fi' => 'Suomi', 'fr' => 'Français', 'he' => '希伯來語', 'hr' => 'Hrvatski', diff --git a/package-lock.json b/package-lock.json index 1445eba2c..99dbf1da8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,40 +5,40 @@ "packages": { "": { "dependencies": { - "@codemirror/commands": "^6.2.4", + "@codemirror/commands": "^6.3.2", "@codemirror/lang-css": "^6.2.1", - "@codemirror/lang-html": "^6.4.5", - "@codemirror/lang-javascript": "^6.1.9", + "@codemirror/lang-html": "^6.4.7", + "@codemirror/lang-javascript": "^6.2.1", "@codemirror/lang-json": "^6.0.1", - "@codemirror/lang-markdown": "^6.2.0", + "@codemirror/lang-markdown": "^6.2.3", "@codemirror/lang-php": "^6.0.1", "@codemirror/lang-xml": "^6.0.2", - "@codemirror/language": "^6.9.0", + "@codemirror/language": "^6.9.3", "@codemirror/legacy-modes": "^6.3.3", - "@codemirror/state": "^6.2.1", + "@codemirror/state": "^6.3.3", "@codemirror/theme-one-dark": "^6.1.2", - "@codemirror/view": "^6.16.0", - "@lezer/highlight": "^1.1.6", + "@codemirror/view": "^6.22.2", + "@lezer/highlight": "^1.2.0", "@ssddanbrown/codemirror-lang-smarty": "^1.0.0", "@ssddanbrown/codemirror-lang-twig": "^1.0.0", "codemirror": "^6.0.1", "idb-keyval": "^6.2.1", - "markdown-it": "^13.0.1", + "markdown-it": "^13.0.2", "markdown-it-task-lists": "^2.1.1", "snabbdom": "^3.5.1", - "sortablejs": "^1.15.0" + "sortablejs": "^1.15.1" }, "devDependencies": { - "@lezer/generator": "^1.4.2", + "@lezer/generator": "^1.5.1", "chokidar-cli": "^3.0", "esbuild": "^0.19", - "eslint": "^8.47.0", + "eslint": "^8.55.0", "eslint-config-airbnb-base": "^15.0.0", - "eslint-plugin-import": "^2.28.1", + "eslint-plugin-import": "^2.29.0", "livereload": "^0.9.3", "npm-run-all": "^4.1.5", - "punycode": "^2.3.0", - "sass": "^1.66.1" + "punycode": "^2.3.1", + "sass": "^1.69.5" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -68,9 +68,9 @@ } }, "node_modules/@codemirror/commands": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.3.0.tgz", - "integrity": "sha512-tFfcxRIlOWiQDFhjBSWJ10MxcvbCIsRr6V64SgrcaY0MwNk32cUOcCuNlWo8VjV4qRQCgNgUAnIeo0svkk4R5Q==", + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.3.2.tgz", + "integrity": "sha512-tjoi4MCWDNxgIpoLZ7+tezdS9OEB6pkiDKhfKx9ReJ/XBcs2G2RXIu+/FxXBlWsPTsz6C9q/r4gjzrsxpcnqCQ==", "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.2.0", @@ -91,9 +91,9 @@ } }, "node_modules/@codemirror/lang-html": { - "version": "6.4.6", - "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.6.tgz", - "integrity": "sha512-E4C8CVupBksXvgLSme/zv31x91g06eZHSph7NczVxZW+/K+3XgJGWNT//2WLzaKSBoxpAjaOi5ZnPU1SHhjh3A==", + "version": "6.4.7", + "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.7.tgz", + "integrity": "sha512-y9hWSSO41XlcL4uYwWyk0lEgTHcelWWfRuqmvcAmxfCs0HNWZdriWo/EU43S63SxEZpc1Hd50Itw7ktfQvfkUg==", "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/lang-css": "^6.0.0", @@ -130,9 +130,9 @@ } }, "node_modules/@codemirror/lang-markdown": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.2.2.tgz", - "integrity": "sha512-wmwM9Y5n/e4ndU51KcYDaQnb9goYdhXjU71dDW9goOc1VUTIPph6WKAPdJ6BzC0ZFy+UTsDwTXGWSP370RH69Q==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.2.3.tgz", + "integrity": "sha512-wCewRLWpdefWi7uVkHIDiE8+45Fe4buvMDZkihqEom5uRUQrl76Zb13emjeK3W+8pcRgRfAmwelURBbxNEKCIg==", "dependencies": { "@codemirror/autocomplete": "^6.7.1", "@codemirror/lang-html": "^6.0.0", @@ -168,9 +168,9 @@ } }, "node_modules/@codemirror/language": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.9.1.tgz", - "integrity": "sha512-lWRP3Y9IUdOms6DXuBpoWwjkR7yRmnS0hKYCbSfPz9v6Em1A1UCRujAkDiCrdYfs1Z0Eu4dGtwovNPStIfkgNA==", + "version": "6.9.3", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.9.3.tgz", + "integrity": "sha512-qq48pYzoi6ldYWV/52+Z9Ou6QouVI+8YwvxFbUypI33NbjG2UeRHKENRyhwljTTiOqjQ33FjyZj6EREQ9apAOQ==", "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", @@ -209,9 +209,9 @@ } }, "node_modules/@codemirror/state": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.3.1.tgz", - "integrity": "sha512-88e4HhMtKJyw6fKprGaN/yZfiaoGYOi2nM45YCUC6R/kex9sxFWBDGatS1vk4lMgnWmdIIB9tk8Gj1LmL8YfvA==" + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.3.3.tgz", + "integrity": "sha512-0wufKcTw2dEwEaADajjHf6hBy1sh3M6V0e+q4JKIhLuiMSe5td5HOWpUdvKth1fT1M9VYOboajoBHpkCd7PG7A==" }, "node_modules/@codemirror/theme-one-dark": { "version": "6.1.2", @@ -225,9 +225,9 @@ } }, "node_modules/@codemirror/view": { - "version": "6.21.3", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.21.3.tgz", - "integrity": "sha512-8l1aSQ6MygzL4Nx7GVYhucSXvW4jQd0F6Zm3v9Dg+6nZEfwzJVqi4C2zHfDljID+73gsQrWp9TgHc81xU15O4A==", + "version": "6.22.2", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.22.2.tgz", + "integrity": "sha512-cJp64cPXm7QfSBWEXK+76+hsZCGHupUgy8JAbSzMG6Lr0rfK73c1CaWITVW6hZVkOnAFxJTxd0PIuynNbzxYPw==", "dependencies": { "@codemirror/state": "^6.1.4", "style-mod": "^4.1.0", @@ -611,9 +611,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -634,9 +634,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", - "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", + "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -703,9 +703,9 @@ } }, "node_modules/@lezer/highlight": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.6.tgz", - "integrity": "sha512-cmSJYa2us+r3SePpRCjN5ymCqCPv+zyXmDl0ciWtVaNiORT/MxM7ZgOMQZADD0o51qOaOg24qc/zBViOIwAjJg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.0.tgz", + "integrity": "sha512-WrS5Mw51sGrpqjlh3d4/fOwpEV2Hd3YOkp9DBt4k8XZQcoTHZFB7sx030A6OcahF4J1nDQAa3jXlTVVYH50IFA==", "dependencies": { "@lezer/common": "^1.0.0" } @@ -829,10 +829,16 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1497,18 +1503,19 @@ } }, "node_modules/eslint": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", - "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", + "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.51.0", - "@humanwhocodes/config-array": "^0.11.11", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.55.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -1616,26 +1623,26 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.28.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz", - "integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==", + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz", + "integrity": "sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==", "dev": true, "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.findlastindex": "^1.2.2", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", + "eslint-import-resolver-node": "^0.3.9", "eslint-module-utils": "^2.8.0", - "has": "^1.0.3", - "is-core-module": "^2.13.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.fromentries": "^2.0.6", - "object.groupby": "^1.0.0", - "object.values": "^1.1.6", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", "semver": "^6.3.1", "tsconfig-paths": "^3.14.2" }, @@ -2122,6 +2129,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -2134,9 +2153,9 @@ "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==" }, "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", "dev": true, "engines": { "node": ">= 4" @@ -2276,12 +2295,12 @@ } }, "node_modules/is-core-module": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", - "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3170,9 +3189,9 @@ } }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" @@ -3363,9 +3382,9 @@ } }, "node_modules/sass": { - "version": "1.69.4", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.69.4.tgz", - "integrity": "sha512-+qEreVhqAy8o++aQfCJwp0sklr2xyEzkm9Pp/Igu9wNPoe7EZEQ8X/MBvvXggI2ql607cxKg/RKOwDj6pp2XDA==", + "version": "1.69.5", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.69.5.tgz", + "integrity": "sha512-qg2+UCJibLr2LCVOt3OlPhr/dqVHWOa9XtZf2OjbLs/T4VPSJ00udtgJxH3neXZm+QqX8B+3cU7RaLqp1iVfcQ==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -3476,9 +3495,9 @@ } }, "node_modules/sortablejs": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz", - "integrity": "sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w==" + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.1.tgz", + "integrity": "sha512-P5Cjvb0UG1ZVNiDPj/n4V+DinttXG6K8n7vM/HQf0C25K3YKQTQY6fsr/sEGsJGpQ9exmPxluHxKBc0mLKU1lQ==" }, "node_modules/source-map-js": { "version": "1.0.2", diff --git a/package.json b/package.json index 21f2b1752..ca5f69071 100644 --- a/package.json +++ b/package.json @@ -17,40 +17,40 @@ "fix": "eslint --fix \"resources/**/*.js\" \"resources/**/*.mjs\"" }, "devDependencies": { - "@lezer/generator": "^1.4.2", + "@lezer/generator": "^1.5.1", "chokidar-cli": "^3.0", "esbuild": "^0.19", - "eslint": "^8.47.0", + "eslint": "^8.55.0", "eslint-config-airbnb-base": "^15.0.0", - "eslint-plugin-import": "^2.28.1", + "eslint-plugin-import": "^2.29.0", "livereload": "^0.9.3", "npm-run-all": "^4.1.5", - "punycode": "^2.3.0", - "sass": "^1.66.1" + "punycode": "^2.3.1", + "sass": "^1.69.5" }, "dependencies": { - "@codemirror/commands": "^6.2.4", + "@codemirror/commands": "^6.3.2", "@codemirror/lang-css": "^6.2.1", - "@codemirror/lang-html": "^6.4.5", - "@codemirror/lang-javascript": "^6.1.9", + "@codemirror/lang-html": "^6.4.7", + "@codemirror/lang-javascript": "^6.2.1", "@codemirror/lang-json": "^6.0.1", - "@codemirror/lang-markdown": "^6.2.0", + "@codemirror/lang-markdown": "^6.2.3", "@codemirror/lang-php": "^6.0.1", "@codemirror/lang-xml": "^6.0.2", - "@codemirror/language": "^6.9.0", + "@codemirror/language": "^6.9.3", "@codemirror/legacy-modes": "^6.3.3", - "@codemirror/state": "^6.2.1", + "@codemirror/state": "^6.3.3", "@codemirror/theme-one-dark": "^6.1.2", - "@codemirror/view": "^6.16.0", - "@lezer/highlight": "^1.1.6", + "@codemirror/view": "^6.22.2", + "@lezer/highlight": "^1.2.0", "@ssddanbrown/codemirror-lang-smarty": "^1.0.0", "@ssddanbrown/codemirror-lang-twig": "^1.0.0", "codemirror": "^6.0.1", "idb-keyval": "^6.2.1", - "markdown-it": "^13.0.1", + "markdown-it": "^13.0.2", "markdown-it-task-lists": "^2.1.1", "snabbdom": "^3.5.1", - "sortablejs": "^1.15.0" + "sortablejs": "^1.15.1" }, "eslintConfig": { "root": true, diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 936d5a91a..5fec36c2f 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,5 @@ includes: - - ./vendor/nunomaduro/larastan/extension.neon + - ./vendor/larastan/larastan/extension.neon parameters: diff --git a/public/libs/tinymce/icons/default/icons.min.js b/public/libs/tinymce/icons/default/icons.min.js index 252210cf5..e3750c673 100644 --- a/public/libs/tinymce/icons/default/icons.min.js +++ b/public/libs/tinymce/icons/default/icons.min.js @@ -1 +1 @@ -tinymce.IconManager.add("default",{icons:{"accessibility-check":'',"accordion-toggle":'',accordion:'',"action-next":'',"action-prev":'',addtag:'',"align-center":'',"align-justify":'',"align-left":'',"align-none":'',"align-right":'',"arrow-left":'',"arrow-right":'',bold:'',bookmark:'',"border-style":'',"border-width":'',brightness:'',browse:'',cancel:'',"cell-background-color":'',"cell-border-color":'',"change-case":'',"character-count":'',"checklist-rtl":'',checklist:'',checkmark:'',"chevron-down":'',"chevron-left":'',"chevron-right":'',"chevron-up":'',close:'',"code-sample":'',"color-levels":'',"color-picker":'',"color-swatch-remove-color":'',"color-swatch":'',"comment-add":'',comment:'',contrast:'',copy:'',crop:'',"cut-column":'',"cut-row":'',cut:'',"document-properties":'',drag:'',"duplicate-column":'',"duplicate-row":'',duplicate:'',"edit-block":'',"edit-image":'',"embed-page":'',embed:'',emoji:'',export:'',fill:'',"flip-horizontally":'',"flip-vertically":'',footnote:'',"format-painter":'',format:'',fullscreen:'',gallery:'',gamma:'',help:'',"highlight-bg-color":'',home:'',"horizontal-rule":'',"image-options":'',image:'',indent:'',info:'',"insert-character":'',"insert-time":'',invert:'',italic:'',language:'',"line-height":'',line:'',link:'',"list-bull-circle":'',"list-bull-default":'',"list-bull-square":'',"list-num-default-rtl":'',"list-num-default":'',"list-num-lower-alpha-rtl":'',"list-num-lower-alpha":'',"list-num-lower-greek-rtl":'',"list-num-lower-greek":'',"list-num-lower-roman-rtl":'',"list-num-lower-roman":'',"list-num-upper-alpha-rtl":'',"list-num-upper-alpha":'',"list-num-upper-roman-rtl":'',"list-num-upper-roman":'',lock:'',ltr:'',minus:'',"more-drawer":'',"new-document":'',"new-tab":'',"non-breaking":'',notice:'',"ordered-list-rtl":'',"ordered-list":'',orientation:'',outdent:'',"page-break":'',paragraph:'',"paste-column-after":'',"paste-column-before":'',"paste-row-after":'',"paste-row-before":'',"paste-text":'',paste:'',"permanent-pen":'',plus:'',preferences:'',preview:'',print:'',quote:'',redo:'',reload:'',"remove-formatting":'',remove:'',"resize-handle":'',resize:'',"restore-draft":'',"rotate-left":'',"rotate-right":'',rtl:'',save:'',search:'',"select-all":'',selected:'',settings:'',sharpen:'',sourcecode:'',"spell-check":'',"strike-through":'',subscript:'',superscript:'',"table-caption":'',"table-cell-classes":'',"table-cell-properties":'',"table-cell-select-all":'',"table-cell-select-inner":'',"table-classes":'',"table-delete-column":'',"table-delete-row":'',"table-delete-table":'',"table-insert-column-after":'',"table-insert-column-before":'',"table-insert-row-above":'',"table-insert-row-after":'',"table-left-header":'',"table-merge-cells":'',"table-row-numbering-rtl":'',"table-row-numbering":'',"table-row-properties":'',"table-split-cells":'',"table-top-header":'',table:'',"template-add":'',template:'',"temporary-placeholder":'',"text-color":'',"text-size-decrease":'',"text-size-increase":'',toc:'',translate:'',typography:'',underline:'',undo:'',unlink:'',unlock:'',"unordered-list":'',unselected:'',upload:'',user:'',"vertical-align":'',visualblocks:'',visualchars:'',warning:'',"zoom-in":'',"zoom-out":''}}); \ No newline at end of file +tinymce.IconManager.add("default",{icons:{"accessibility-check":'',"accordion-toggle":'',accordion:'',"action-next":'',"action-prev":'',addtag:'',"ai-prompt":'',ai:'',"align-center":'',"align-justify":'',"align-left":'',"align-none":'',"align-right":'',"arrow-left":'',"arrow-right":'',bold:'',bookmark:'',"border-style":'',"border-width":'',brightness:'',browse:'',cancel:'',"cell-background-color":'',"cell-border-color":'',"change-case":'',"character-count":'',"checklist-rtl":'',checklist:'',checkmark:'',"chevron-down":'',"chevron-left":'',"chevron-right":'',"chevron-up":'',close:'',"code-sample":'',"color-levels":'',"color-picker":'',"color-swatch-remove-color":'',"color-swatch":'',"comment-add":'',comment:'',contrast:'',copy:'',crop:'',"cut-column":'',"cut-row":'',cut:'',"document-properties":'',drag:'',"duplicate-column":'',"duplicate-row":'',duplicate:'',"edit-block":'',"edit-image":'',"embed-page":'',embed:'',emoji:'',export:'',fill:'',"flip-horizontally":'',"flip-vertically":'',footnote:'',"format-painter":'',format:'',fullscreen:'',gallery:'',gamma:'',help:'',"highlight-bg-color":'',home:'',"horizontal-rule":'',"image-options":'',image:'',indent:'',info:'',"insert-character":'',"insert-time":'',invert:'',italic:'',language:'',"line-height":'',line:'',link:'',"list-bull-circle":'',"list-bull-default":'',"list-bull-square":'',"list-num-default-rtl":'',"list-num-default":'',"list-num-lower-alpha-rtl":'',"list-num-lower-alpha":'',"list-num-lower-greek-rtl":'',"list-num-lower-greek":'',"list-num-lower-roman-rtl":'',"list-num-lower-roman":'',"list-num-upper-alpha-rtl":'',"list-num-upper-alpha":'',"list-num-upper-roman-rtl":'',"list-num-upper-roman":'',lock:'',ltr:'',minus:'',"more-drawer":'',"new-document":'',"new-tab":'',"non-breaking":'',notice:'',"ordered-list-rtl":'',"ordered-list":'',orientation:'',outdent:'',"page-break":'',paragraph:'',"paste-column-after":'',"paste-column-before":'',"paste-row-after":'',"paste-row-before":'',"paste-text":'',paste:'',"permanent-pen":'',plus:'',preferences:'',preview:'',print:'',quote:'',redo:'',reload:'',"remove-formatting":'',remove:'',"resize-handle":'',resize:'',"restore-draft":'',"rotate-left":'',"rotate-right":'',rtl:'',save:'',search:'',"select-all":'',selected:'',send:'',settings:'',sharpen:'',sourcecode:'',"spell-check":'',"strike-through":'',subscript:'',superscript:'',"table-caption":'',"table-cell-classes":'',"table-cell-properties":'',"table-cell-select-all":'',"table-cell-select-inner":'',"table-classes":'',"table-delete-column":'',"table-delete-row":'',"table-delete-table":'',"table-insert-column-after":'',"table-insert-column-before":'',"table-insert-row-above":'',"table-insert-row-after":'',"table-left-header":'',"table-merge-cells":'',"table-row-numbering-rtl":'',"table-row-numbering":'',"table-row-properties":'',"table-split-cells":'',"table-top-header":'',table:'',"template-add":'',template:'',"temporary-placeholder":'',"text-color":'',"text-size-decrease":'',"text-size-increase":'',toc:'',translate:'',typography:'',underline:'',undo:'',unlink:'',unlock:'',"unordered-list":'',unselected:'',upload:'',user:'',"vertical-align":'',visualblocks:'',visualchars:'',warning:'',"zoom-in":'',"zoom-out":''}}); \ No newline at end of file diff --git a/public/libs/tinymce/models/dom/model.min.js b/public/libs/tinymce/models/dom/model.min.js index 8065e3eaa..a6b505321 100644 --- a/public/libs/tinymce/models/dom/model.min.js +++ b/public/libs/tinymce/models/dom/model.min.js @@ -1,4 +1,4 @@ /** - * TinyMCE version 6.5.1 (2023-06-19) + * TinyMCE version 6.7.2 (2023-10-25) */ !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.ModelManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(o=n=e,(r=String).prototype.isPrototypeOf(o)||(null===(s=n.constructor)||void 0===s?void 0:s.name)===r.name)?"string":t;var o,n,r,s})(t)===e,o=e=>t=>typeof t===e,n=e=>t=>e===t,r=t("string"),s=t("object"),l=t("array"),a=n(null),c=o("boolean"),i=n(void 0),m=e=>!(e=>null==e)(e),d=o("function"),u=o("number"),f=()=>{},g=e=>()=>e,h=e=>e,p=(e,t)=>e===t;function w(e,...t){return(...o)=>{const n=t.concat(o);return e.apply(null,n)}}const b=e=>t=>!e(t),v=e=>e(),y=g(!1),x=g(!0);class C{constructor(e,t){this.tag=e,this.value=t}static some(e){return new C(!0,e)}static none(){return C.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?C.some(e(this.value)):C.none()}bind(e){return this.tag?e(this.value):C.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:C.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return m(e)?C.some(e):C.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}C.singletonNone=new C(!1);const S=Array.prototype.slice,T=Array.prototype.indexOf,R=Array.prototype.push,D=(e,t)=>{return o=e,n=t,T.call(o,n)>-1;var o,n},O=(e,t)=>{for(let o=0,n=e.length;o{const o=[];for(let n=0;n{const o=e.length,n=new Array(o);for(let r=0;r{for(let o=0,n=e.length;o{const o=[],n=[];for(let r=0,s=e.length;r{const o=[];for(let n=0,r=e.length;n(((e,t)=>{for(let o=e.length-1;o>=0;o--)t(e[o],o)})(e,((e,n)=>{o=t(o,e,n)})),o),A=(e,t,o)=>(N(e,((e,n)=>{o=t(o,e,n)})),o),L=(e,t)=>((e,t,o)=>{for(let n=0,r=e.length;n{for(let o=0,n=e.length;o{const t=[];for(let o=0,n=e.length;oM(E(e,t)),P=(e,t)=>{for(let o=0,n=e.length;o{const o={};for(let n=0,r=e.length;nt>=0&&tF(e,0),$=e=>F(e,e.length-1),V=(e,t)=>{for(let o=0;o{const o=q(e);for(let n=0,r=o.length;nY(e,((e,o)=>({k:o,v:t(e,o)}))),Y=(e,t)=>{const o={};return G(e,((e,n)=>{const r=t(e,n);o[r.k]=r.v})),o},J=(e,t)=>{const o=[];return G(e,((e,n)=>{o.push(t(e,n))})),o},Q=e=>J(e,h),X=(e,t)=>U.call(e,t),Z="undefined"!=typeof window?window:Function("return this;")(),ee=(e,t)=>((e,t)=>{let o=null!=t?t:Z;for(let t=0;t{const t=ee("ownerDocument.defaultView",e);return s(e)&&((e=>((e,t)=>{const o=((e,t)=>ee(e,t))(e,t);if(null==o)throw new Error(e+" not available on this browser");return o})("HTMLElement",e))(t).prototype.isPrototypeOf(e)||/^HTML\w*Element$/.test(te(e).constructor.name))},ne=e=>e.dom.nodeName.toLowerCase(),re=e=>e.dom.nodeType,se=e=>t=>re(t)===e,le=e=>8===re(e)||"#comment"===ne(e),ae=e=>ce(e)&&oe(e.dom),ce=se(1),ie=se(3),me=se(9),de=se(11),ue=e=>t=>ce(t)&&ne(t)===e,fe=(e,t,o)=>{if(!(r(o)||c(o)||u(o)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",o,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,o+"")},ge=(e,t,o)=>{fe(e.dom,t,o)},he=(e,t)=>{const o=e.dom;G(t,((e,t)=>{fe(o,t,e)}))},pe=(e,t)=>{const o=e.dom.getAttribute(t);return null===o?void 0:o},we=(e,t)=>C.from(pe(e,t)),be=(e,t)=>{e.dom.removeAttribute(t)},ve=e=>A(e.dom.attributes,((e,t)=>(e[t.name]=t.value,e)),{}),ye=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},xe={fromHtml:(e,t)=>{const o=(t||document).createElement("div");if(o.innerHTML=e,!o.hasChildNodes()||o.childNodes.length>1){const t="HTML does not have a single root node";throw console.error(t,e),new Error(t)}return ye(o.childNodes[0])},fromTag:(e,t)=>{const o=(t||document).createElement(e);return ye(o)},fromText:(e,t)=>{const o=(t||document).createTextNode(e);return ye(o)},fromDom:ye,fromPoint:(e,t,o)=>C.from(e.dom.elementFromPoint(t,o)).map(ye)},Ce=(e,t)=>{const o=e.dom;if(1!==o.nodeType)return!1;{const e=o;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},Se=e=>1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType||0===e.childElementCount,Te=(e,t)=>{const o=void 0===t?document:t.dom;return Se(o)?C.none():C.from(o.querySelector(e)).map(xe.fromDom)},Re=(e,t)=>e.dom===t.dom,De=(e,t)=>{const o=e.dom,n=t.dom;return o!==n&&o.contains(n)},Oe=Ce,ke=e=>xe.fromDom(e.dom.ownerDocument),Ee=e=>me(e)?e:ke(e),Ne=e=>C.from(e.dom.parentNode).map(xe.fromDom),Be=e=>C.from(e.dom.parentElement).map(xe.fromDom),_e=(e,t)=>{const o=d(t)?t:y;let n=e.dom;const r=[];for(;null!==n.parentNode&&void 0!==n.parentNode;){const e=n.parentNode,t=xe.fromDom(e);if(r.push(t),!0===o(t))break;n=e}return r},ze=e=>C.from(e.dom.previousSibling).map(xe.fromDom),Ae=e=>C.from(e.dom.nextSibling).map(xe.fromDom),Le=e=>E(e.dom.childNodes,xe.fromDom),We=(e,t)=>{const o=e.dom.childNodes;return C.from(o[t]).map(xe.fromDom)},Me=(e,t)=>{Ne(e).each((o=>{o.dom.insertBefore(t.dom,e.dom)}))},je=(e,t)=>{Ae(e).fold((()=>{Ne(e).each((e=>{Ie(e,t)}))}),(e=>{Me(e,t)}))},Pe=(e,t)=>{const o=(e=>We(e,0))(e);o.fold((()=>{Ie(e,t)}),(o=>{e.dom.insertBefore(t.dom,o.dom)}))},Ie=(e,t)=>{e.dom.appendChild(t.dom)},Fe=(e,t)=>{Me(e,t),Ie(t,e)},He=(e,t)=>{N(t,((o,n)=>{const r=0===n?e:t[n-1];je(r,o)}))},$e=(e,t)=>{N(t,(t=>{Ie(e,t)}))},Ve=e=>{e.dom.textContent="",N(Le(e),(e=>{qe(e)}))},qe=e=>{const t=e.dom;null!==t.parentNode&&t.parentNode.removeChild(t)},Ue=e=>{const t=Le(e);t.length>0&&He(e,t),qe(e)},Ge=(e,t)=>xe.fromDom(e.dom.cloneNode(t)),Ke=e=>Ge(e,!1),Ye=e=>Ge(e,!0),Je=(e,t)=>{const o=xe.fromTag(t),n=ve(e);return he(o,n),o},Qe=["tfoot","thead","tbody","colgroup"],Xe=(e,t,o)=>({element:e,rowspan:t,colspan:o}),Ze=(e,t,o)=>({element:e,cells:t,section:o}),et=(e,t,o)=>({element:e,isNew:t,isLocked:o}),tt=(e,t,o,n)=>({element:e,cells:t,section:o,isNew:n}),ot=d(Element.prototype.attachShadow)&&d(Node.prototype.getRootNode),nt=g(ot),rt=ot?e=>xe.fromDom(e.dom.getRootNode()):Ee,st=e=>xe.fromDom(e.dom.host),lt=e=>{const t=ie(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const o=t.ownerDocument;return(e=>{const t=rt(e);return de(o=t)&&m(o.dom.host)?C.some(t):C.none();var o})(xe.fromDom(t)).fold((()=>o.body.contains(t)),(n=lt,r=st,e=>n(r(e))));var n,r},at=e=>{const t=e.dom.body;if(null==t)throw new Error("Body is not available yet");return xe.fromDom(t)},ct=(e,t)=>{let o=[];return N(Le(e),(e=>{t(e)&&(o=o.concat([e])),o=o.concat(ct(e,t))})),o},it=(e,t,o)=>((e,o,n)=>_(_e(e,n),(e=>Ce(e,t))))(e,0,o),mt=(e,t)=>((e,o)=>_(Le(e),(e=>Ce(e,t))))(e),dt=(e,t)=>((e,t)=>{const o=void 0===t?document:t.dom;return Se(o)?[]:E(o.querySelectorAll(e),xe.fromDom)})(t,e);var ut=(e,t,o,n,r)=>e(o,n)?C.some(o):d(r)&&r(o)?C.none():t(o,n,r);const ft=(e,t,o)=>{let n=e.dom;const r=d(o)?o:y;for(;n.parentNode;){n=n.parentNode;const e=xe.fromDom(n);if(t(e))return C.some(e);if(r(e))break}return C.none()},gt=(e,t,o)=>ut(((e,t)=>t(e)),ft,e,t,o),ht=(e,t,o)=>ft(e,(e=>Ce(e,t)),o),pt=(e,t)=>((e,o)=>L(e.dom.childNodes,(e=>{return o=xe.fromDom(e),Ce(o,t);var o})).map(xe.fromDom))(e),wt=(e,t)=>Te(t,e),bt=(e,t,o)=>ut(((e,t)=>Ce(e,t)),ht,e,t,o),vt=(e,t,o=p)=>e.exists((e=>o(e,t))),yt=e=>{const t=[],o=e=>{t.push(e)};for(let t=0;te?C.some(t):C.none(),Ct=(e,t,o)=>""===t||e.length>=t.length&&e.substr(o,o+t.length)===t,St=(e,t,o=0,n)=>{const r=e.indexOf(t,o);return-1!==r&&(!!i(n)||r+t.length<=n)},Tt=(e,t)=>Ct(e,t,0),Rt=(e,t)=>Ct(e,t,e.length-t.length),Dt=(e=>t=>t.replace(e,""))(/^\s+|\s+$/g),Ot=e=>e.length>0,kt=e=>void 0!==e.style&&d(e.style.getPropertyValue),Et=(e,t,o)=>{if(!r(o))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",o,":: Element ",e),new Error("CSS value must be a string: "+o);kt(e)&&e.style.setProperty(t,o)},Nt=(e,t,o)=>{const n=e.dom;Et(n,t,o)},Bt=(e,t)=>{const o=e.dom;G(t,((e,t)=>{Et(o,t,e)}))},_t=(e,t)=>{const o=e.dom,n=window.getComputedStyle(o).getPropertyValue(t);return""!==n||lt(e)?n:zt(o,t)},zt=(e,t)=>kt(e)?e.style.getPropertyValue(t):"",At=(e,t)=>{const o=e.dom,n=zt(o,t);return C.from(n).filter((e=>e.length>0))},Lt=(e,t)=>{((e,t)=>{kt(e)&&e.style.removeProperty(t)})(e.dom,t),vt(we(e,"style").map(Dt),"")&&be(e,"style")},Wt=(e,t,o=0)=>we(e,t).map((e=>parseInt(e,10))).getOr(o),Mt=(e,t)=>Wt(e,t,1),jt=e=>ue("col")(e)?Wt(e,"span",1)>1:Mt(e,"colspan")>1,Pt=e=>Mt(e,"rowspan")>1,It=(e,t)=>parseInt(_t(e,t),10),Ft=g(10),Ht=g(10),$t=(e,t)=>Vt(e,t,x),Vt=(e,t,o)=>j(Le(e),(e=>Ce(e,t)?o(e)?[e]:[]:Vt(e,t,o))),qt=(e,t)=>((e,t,o=y)=>o(t)?C.none():D(e,ne(t))?C.some(t):ht(t,e.join(","),(e=>Ce(e,"table")||o(e))))(["td","th"],e,t),Ut=e=>$t(e,"th,td"),Gt=e=>Ce(e,"colgroup")?mt(e,"col"):j(Jt(e),(e=>mt(e,"col"))),Kt=(e,t)=>bt(e,"table",t),Yt=e=>$t(e,"tr"),Jt=e=>Kt(e).fold(g([]),(e=>mt(e,"colgroup"))),Qt=(e,t)=>E(e,(e=>{if("colgroup"===ne(e)){const t=E(Gt(e),(e=>{const t=Wt(e,"span",1);return Xe(e,1,t)}));return Ze(e,t,"colgroup")}{const o=E(Ut(e),(e=>{const t=Wt(e,"rowspan",1),o=Wt(e,"colspan",1);return Xe(e,t,o)}));return Ze(e,o,t(e))}})),Xt=e=>Ne(e).map((e=>{const t=ne(e);return(e=>D(Qe,e))(t)?t:"tbody"})).getOr("tbody"),Zt=e=>{const t=Yt(e),o=[...Jt(e),...t];return Qt(o,Xt)},eo=e=>{let t,o=!1;return(...n)=>(o||(o=!0,t=e.apply(null,n)),t)},to=()=>oo(0,0),oo=(e,t)=>({major:e,minor:t}),no={nu:oo,detect:(e,t)=>{const o=String(t).toLowerCase();return 0===e.length?to():((e,t)=>{const o=((e,t)=>{for(let o=0;oNumber(t.replace(o,"$"+e));return oo(n(1),n(2))})(e,o)},unknown:to},ro=(e,t)=>{const o=String(t).toLowerCase();return L(e,(e=>e.search(o)))},so=/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,lo=e=>t=>St(t,e),ao=[{name:"Edge",versionRegexes:[/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],search:e=>St(e,"edge/")&&St(e,"chrome")&&St(e,"safari")&&St(e,"applewebkit")},{name:"Chromium",brand:"Chromium",versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/,so],search:e=>St(e,"chrome")&&!St(e,"chromeframe")},{name:"IE",versionRegexes:[/.*?msie\ ?([0-9]+)\.([0-9]+).*/,/.*?rv:([0-9]+)\.([0-9]+).*/],search:e=>St(e,"msie")||St(e,"trident")},{name:"Opera",versionRegexes:[so,/.*?opera\/([0-9]+)\.([0-9]+).*/],search:lo("opera")},{name:"Firefox",versionRegexes:[/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],search:lo("firefox")},{name:"Safari",versionRegexes:[so,/.*?cpu os ([0-9]+)_([0-9]+).*/],search:e=>(St(e,"safari")||St(e,"mobile/"))&&St(e,"applewebkit")}],co=[{name:"Windows",search:lo("win"),versionRegexes:[/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]},{name:"iOS",search:e=>St(e,"iphone")||St(e,"ipad"),versionRegexes:[/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,/.*cpu os ([0-9]+)_([0-9]+).*/,/.*cpu iphone os ([0-9]+)_([0-9]+).*/]},{name:"Android",search:lo("android"),versionRegexes:[/.*?android\ ?([0-9]+)\.([0-9]+).*/]},{name:"macOS",search:lo("mac os x"),versionRegexes:[/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]},{name:"Linux",search:lo("linux"),versionRegexes:[]},{name:"Solaris",search:lo("sunos"),versionRegexes:[]},{name:"FreeBSD",search:lo("freebsd"),versionRegexes:[]},{name:"ChromeOS",search:lo("cros"),versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/]}],io={browsers:g(ao),oses:g(co)},mo="Edge",uo="Chromium",fo="Opera",go="Firefox",ho="Safari",po=e=>{const t=e.current,o=e.version,n=e=>()=>t===e;return{current:t,version:o,isEdge:n(mo),isChromium:n(uo),isIE:n("IE"),isOpera:n(fo),isFirefox:n(go),isSafari:n(ho)}},wo=()=>po({current:void 0,version:no.unknown()}),bo=po,vo=(g(mo),g(uo),g("IE"),g(fo),g(go),g(ho),"Windows"),yo="Android",xo="Linux",Co="macOS",So="Solaris",To="FreeBSD",Ro="ChromeOS",Do=e=>{const t=e.current,o=e.version,n=e=>()=>t===e;return{current:t,version:o,isWindows:n(vo),isiOS:n("iOS"),isAndroid:n(yo),isMacOS:n(Co),isLinux:n(xo),isSolaris:n(So),isFreeBSD:n(To),isChromeOS:n(Ro)}},Oo=()=>Do({current:void 0,version:no.unknown()}),ko=Do,Eo=(g(vo),g("iOS"),g(yo),g(xo),g(Co),g(So),g(To),g(Ro),e=>window.matchMedia(e).matches);let No=eo((()=>((e,t,o)=>{const n=io.browsers(),r=io.oses(),s=t.bind((e=>((e,t)=>V(t.brands,(t=>{const o=t.brand.toLowerCase();return L(e,(e=>{var t;return o===(null===(t=e.brand)||void 0===t?void 0:t.toLowerCase())})).map((e=>({current:e.name,version:no.nu(parseInt(t.version,10),0)})))})))(n,e))).orThunk((()=>((e,t)=>ro(e,t).map((e=>{const o=no.detect(e.versionRegexes,t);return{current:e.name,version:o}})))(n,e))).fold(wo,bo),l=((e,t)=>ro(e,t).map((e=>{const o=no.detect(e.versionRegexes,t);return{current:e.name,version:o}})))(r,e).fold(Oo,ko),a=((e,t,o,n)=>{const r=e.isiOS()&&!0===/ipad/i.test(o),s=e.isiOS()&&!r,l=e.isiOS()||e.isAndroid(),a=l||n("(pointer:coarse)"),c=r||!s&&l&&n("(min-device-width:768px)"),i=s||l&&!c,m=t.isSafari()&&e.isiOS()&&!1===/safari/i.test(o),d=!i&&!c&&!m;return{isiPad:g(r),isiPhone:g(s),isTablet:g(c),isPhone:g(i),isTouch:g(a),isAndroid:e.isAndroid,isiOS:e.isiOS,isWebView:g(m),isDesktop:g(d)}})(l,s,e,o);return{browser:s,os:l,deviceType:a}})(navigator.userAgent,C.from(navigator.userAgentData),Eo)));const Bo=()=>No(),_o=(e,t)=>{const o=o=>{const n=t(o);if(n<=0||null===n){const t=_t(o,e);return parseFloat(t)||0}return n},n=(e,t)=>A(t,((t,o)=>{const n=_t(e,o),r=void 0===n?0:parseInt(n,10);return isNaN(r)?t:t+r}),0);return{set:(t,o)=>{if(!u(o)&&!o.match(/^[0-9]+$/))throw new Error(e+".set accepts only positive integer values. Value was "+o);const n=t.dom;kt(n)&&(n.style[e]=o+"px")},get:o,getOuter:o,aggregate:n,max:(e,t,o)=>{const r=n(e,o);return t>r?t-r:0}}},zo=(e,t,o)=>((e,t)=>(e=>{const t=parseFloat(e);return isNaN(t)?C.none():C.some(t)})(e).getOr(t))(_t(e,t),o),Ao=_o("width",(e=>e.dom.offsetWidth)),Lo=e=>Ao.get(e),Wo=e=>Ao.getOuter(e),Mo=e=>((e,t)=>{const o=e.dom,n=o.getBoundingClientRect().width||o.offsetWidth;return"border-box"===t?n:((e,t,o,n)=>t-zo(e,`padding-${o}`,0)-zo(e,`padding-${n}`,0)-zo(e,`border-${o}-width`,0)-zo(e,`border-${n}-width`,0))(e,n,"left","right")})(e,"content-box"),jo=(e,t,o)=>{const n=e.cells,r=n.slice(0,t),s=n.slice(t),l=r.concat(o).concat(s);return Fo(e,l)},Po=(e,t,o)=>jo(e,t,[o]),Io=(e,t,o)=>{e.cells[t]=o},Fo=(e,t)=>tt(e.element,t,e.section,e.isNew),Ho=(e,t)=>e.cells[t],$o=(e,t)=>Ho(e,t).element,Vo=e=>e.cells.length,qo=e=>{const t=B(e,(e=>"colgroup"===e.section));return{rows:t.fail,cols:t.pass}},Uo=(e,t,o)=>{const n=E(e.cells,o);return tt(t(e.element),n,e.section,!0)},Go="data-snooker-locked-cols",Ko=e=>we(e,Go).bind((e=>C.from(e.match(/\d+/g)))).map((e=>I(e,x))),Yo=e=>{const t=A(qo(e).rows,((e,t)=>(N(t.cells,((t,o)=>{t.isLocked&&(e[o]=!0)})),e)),{}),o=J(t,((e,t)=>parseInt(t,10)));return((e,t)=>{const o=S.call(e,0);return o.sort(void 0),o})(o)},Jo=(e,t)=>e+","+t,Qo=(e,t)=>{const o=j(e.all,(e=>e.cells));return _(o,t)},Xo=e=>{const t={},o=[],n=H(e).map((e=>e.element)).bind(Kt).bind(Ko).getOr({});let r=0,s=0,l=0;const{pass:a,fail:c}=B(e,(e=>"colgroup"===e.section));N(c,(e=>{const a=[];N(e.cells,(e=>{let o=0;for(;void 0!==t[Jo(l,o)];)o++;const r=((e,t)=>X(e,t)&&void 0!==e[t]&&null!==e[t])(n,o.toString()),c=((e,t,o,n,r,s)=>({element:e,rowspan:t,colspan:o,row:n,column:r,isLocked:s}))(e.element,e.rowspan,e.colspan,l,o,r);for(let n=0;n{const t=(e=>{const t={};let o=0;return N(e.cells,(e=>{const n=e.colspan;k(n,(r=>{const s=o+r;t[s]=((e,t,o)=>({element:e,colspan:t,column:o}))(e.element,n,s)})),o+=n})),t})(e),o=((e,t)=>({element:e,columns:t}))(e.element,Q(t));return{colgroups:[o],columns:t}})).getOrThunk((()=>({colgroups:[],columns:{}}))),d=((e,t)=>({rows:e,columns:t}))(r,s);return{grid:d,access:t,all:o,columns:i,colgroups:m}},Zo=e=>{const t=Zt(e);return Xo(t)},en=Xo,tn=(e,t,o)=>C.from(e.access[Jo(t,o)]),on=(e,t,o)=>{const n=Qo(e,(e=>o(t,e.element)));return n.length>0?C.some(n[0]):C.none()},nn=Qo,rn=e=>j(e.all,(e=>e.cells)),sn=e=>Q(e.columns),ln=e=>q(e.columns).length>0,an=(e,t)=>C.from(e.columns[t]),cn=(e,t=x)=>{const o=e.grid,n=k(o.columns,h),r=k(o.rows,h);return E(n,(o=>mn((()=>j(r,(t=>tn(e,t,o).filter((e=>e.column===o)).toArray()))),(e=>1===e.colspan&&t(e.element)),(()=>tn(e,0,o)))))},mn=(e,t,o)=>{const n=e();return L(n,t).orThunk((()=>C.from(n[0]).orThunk(o))).map((e=>e.element))},dn=e=>{const t=e.grid,o=k(t.rows,h),n=k(t.columns,h);return E(o,(t=>mn((()=>j(n,(o=>tn(e,t,o).filter((e=>e.row===t)).fold(g([]),(e=>[e]))))),(e=>1===e.rowspan),(()=>tn(e,t,0)))))},un=(e,t)=>o=>"rtl"===fn(o)?t:e,fn=e=>"rtl"===_t(e,"direction")?"rtl":"ltr",gn=_o("height",(e=>{const t=e.dom;return lt(e)?t.getBoundingClientRect().height:t.offsetHeight})),hn=e=>gn.get(e),pn=e=>gn.getOuter(e),wn=(e,t)=>({left:e,top:t,translate:(o,n)=>wn(e+o,t+n)}),bn=wn,vn=(e,t)=>void 0!==e?e:void 0!==t?t:0,yn=e=>{const t=e.dom.ownerDocument,o=t.body,n=t.defaultView,r=t.documentElement;if(o===e.dom)return bn(o.offsetLeft,o.offsetTop);const s=vn(null==n?void 0:n.pageYOffset,r.scrollTop),l=vn(null==n?void 0:n.pageXOffset,r.scrollLeft),a=vn(r.clientTop,o.clientTop),c=vn(r.clientLeft,o.clientLeft);return xn(e).translate(l-c,s-a)},xn=e=>{const t=e.dom,o=t.ownerDocument.body;return o===t?bn(o.offsetLeft,o.offsetTop):lt(e)?(e=>{const t=e.getBoundingClientRect();return bn(t.left,t.top)})(t):bn(0,0)},Cn=(e,t)=>({row:e,y:t}),Sn=(e,t)=>({col:e,x:t}),Tn=e=>yn(e).left+Wo(e),Rn=e=>yn(e).left,Dn=(e,t)=>Sn(e,Rn(t)),On=(e,t)=>Sn(e,Tn(t)),kn=e=>yn(e).top,En=(e,t)=>Cn(e,kn(t)),Nn=(e,t)=>Cn(e,kn(t)+pn(t)),Bn=(e,t,o)=>{if(0===o.length)return[];const n=E(o.slice(1),((t,o)=>t.map((t=>e(o,t))))),r=o[o.length-1].map((e=>t(o.length-1,e)));return n.concat([r])},_n={delta:h,positions:e=>Bn(En,Nn,e),edge:kn},zn=un({delta:h,edge:Rn,positions:e=>Bn(Dn,On,e)},{delta:e=>-e,edge:Tn,positions:e=>Bn(On,Dn,e)}),An={delta:(e,t)=>zn(t).delta(e,t),positions:(e,t)=>zn(t).positions(e,t),edge:e=>zn(e).edge(e)},Ln={unsupportedLength:["em","ex","cap","ch","ic","rem","lh","rlh","vw","vh","vi","vb","vmin","vmax","cm","mm","Q","in","pc","pt","px"],fixed:["px","pt"],relative:["%"],empty:[""]},Wn=(()=>{const e="[0-9]+",t="[eE][+-]?"+e,o=e=>`(?:${e})?`,n=["Infinity",e+"\\."+o(e)+o(t),"\\."+e+o(t),e+o(t)].join("|");return new RegExp(`^([+-]?(?:${n}))(.*)$`)})(),Mn=/(\d+(\.\d+)?)%/,jn=/(\d+(\.\d+)?)px|em/,Pn=ue("col"),In=(e,t,o)=>{const n=Be(e).getOrThunk((()=>at(ke(e))));return t(e)/o(n)*100},Fn=(e,t)=>{Nt(e,"width",t+"px")},Hn=(e,t)=>{Nt(e,"width",t+"%")},$n=(e,t)=>{Nt(e,"height",t+"px")},Vn=e=>{const t=(e=>{return zo(t=e,"height",t.dom.offsetHeight)+"px";var t})(e);return t?((e,t,o,n)=>{const r=parseFloat(e);return Rt(e,"%")&&"table"!==ne(t)?((e,t,o,n)=>{const r=Kt(e).map((e=>{const n=o(e);return Math.floor(t/100*n)})).getOr(t);return n(e,r),r})(t,r,o,n):r})(t,e,hn,$n):hn(e)},qn=(e,t)=>At(e,t).orThunk((()=>we(e,t).map((e=>e+"px")))),Un=e=>qn(e,"width"),Gn=e=>In(e,Lo,Mo),Kn=e=>{return Pn(e)?Lo(e):zo(t=e,"width",t.dom.offsetWidth);var t},Yn=e=>((e,t,o)=>o(e)/Mt(e,"rowspan"))(e,0,Vn),Jn=(e,t,o)=>{Nt(e,"width",t+o)},Qn=e=>In(e,Lo,Mo)+"%",Xn=g(Mn),Zn=ue("col"),er=e=>Un(e).getOrThunk((()=>Kn(e)+"px")),tr=e=>{return(t=e,qn(t,"height")).getOrThunk((()=>Yn(e)+"px"));var t},or=(e,t,o,n,r,s)=>e.filter(n).fold((()=>s(((e,t)=>{if(t<0||t>=e.length-1)return C.none();const o=e[t].fold((()=>{const o=(e=>{const t=S.call(e,0);return t.reverse(),t})(e.slice(0,t));return V(o,((e,t)=>e.map((e=>({value:e,delta:t+1})))))}),(e=>C.some({value:e,delta:0}))),n=e[t+1].fold((()=>{const o=e.slice(t+1);return V(o,((e,t)=>e.map((e=>({value:e,delta:t+1})))))}),(e=>C.some({value:e,delta:1})));return o.bind((e=>n.map((t=>{const o=t.delta+e.delta;return Math.abs(t.value-e.value)/o}))))})(o,t))),(e=>r(e))),nr=(e,t,o,n)=>{const r=cn(e),s=ln(e)?(e=>E(sn(e),(e=>C.from(e.element))))(e):r,l=[C.some(An.edge(t))].concat(E(An.positions(r,t),(e=>e.map((e=>e.x))))),a=b(jt);return E(s,((e,t)=>or(e,t,l,a,(e=>{if((e=>{const t=Bo().browser,o=t.isChromium()||t.isFirefox();return!Zn(e)||o})(e))return o(e);{const e=null!=(s=r[t])?h(s):C.none();return or(e,t,l,a,(e=>n(C.some(Lo(e)))),n)}var s}),n)))},rr=e=>e.map((e=>e+"px")).getOr(""),sr=(e,t,o)=>nr(e,t,Kn,(e=>e.getOrThunk(o.minCellWidth))),lr=(e,t,o,n,r)=>{const s=dn(e),l=[C.some(o.edge(t))].concat(E(o.positions(s,t),(e=>e.map((e=>e.y)))));return E(s,((e,t)=>or(e,t,l,b(Pt),n,r)))},ar=(e,t)=>()=>lt(e)?t(e):parseFloat(At(e,"width").getOr("0")),cr=e=>{const t=ar(e,(e=>parseFloat(Qn(e)))),o=ar(e,Lo);return{width:t,pixelWidth:o,getWidths:(t,o)=>((e,t,o)=>nr(e,t,Gn,(e=>e.fold((()=>o.minCellWidth()),(e=>e/o.pixelWidth()*100)))))(t,e,o),getCellDelta:e=>e/o()*100,singleColumnWidth:(e,t)=>[100-e],minCellWidth:()=>Ft()/o()*100,setElementWidth:Hn,adjustTableWidth:o=>{const n=t();Hn(e,n+o/100*n)},isRelative:!0,label:"percent"}},ir=e=>{const t=ar(e,Lo);return{width:t,pixelWidth:t,getWidths:(t,o)=>sr(t,e,o),getCellDelta:h,singleColumnWidth:(e,t)=>[Math.max(Ft(),e+t)-e],minCellWidth:Ft,setElementWidth:Fn,adjustTableWidth:o=>{const n=t()+o;Fn(e,n)},isRelative:!1,label:"pixel"}},mr=e=>Un(e).fold((()=>(e=>{const t=ar(e,Lo),o=g(0);return{width:t,pixelWidth:t,getWidths:(t,o)=>sr(t,e,o),getCellDelta:o,singleColumnWidth:g([0]),minCellWidth:o,setElementWidth:f,adjustTableWidth:f,isRelative:!0,label:"none"}})(e)),(t=>((e,t)=>null!==Xn().exec(t)?cr(e):ir(e))(e,t))),dr=ir,ur=cr,fr=(e,t,o)=>{const n=e[o].element,r=xe.fromTag("td");Ie(r,xe.fromTag("br")),(t?Ie:Pe)(n,r)},gr=((e,t)=>{const o=t=>e(t)?C.from(t.dom.nodeValue):C.none();return{get:t=>{if(!e(t))throw new Error("Can only get text value of a text node");return o(t).getOr("")},getOption:o,set:(t,o)=>{if(!e(t))throw new Error("Can only set raw text value of a text node");t.dom.nodeValue=o}}})(ie),hr=e=>gr.get(e),pr=e=>gr.getOption(e),wr=(e,t)=>gr.set(e,t),br=e=>"img"===ne(e)?1:pr(e).fold((()=>Le(e).length),(e=>e.length)),vr=["img","br"],yr=e=>pr(e).filter((e=>0!==e.trim().length||e.indexOf("\xa0")>-1)).isSome()||D(vr,ne(e))||(e=>ae(e)&&"false"===pe(e,"contenteditable"))(e),xr=e=>((e,t)=>{const o=e=>{for(let n=0;nSr(e,yr),Sr=(e,t)=>{const o=e=>{const n=Le(e);for(let e=n.length-1;e>=0;e--){const r=n[e];if(t(r))return C.some(r);const s=o(r);if(s.isSome())return s}return C.none()};return o(e)},Tr={scope:["row","col"]},Rr=e=>()=>{const t=xe.fromTag("td",e.dom);return Ie(t,xe.fromTag("br",e.dom)),t},Dr=e=>()=>xe.fromTag("col",e.dom),Or=e=>()=>xe.fromTag("colgroup",e.dom),kr=e=>()=>xe.fromTag("tr",e.dom),Er=(e,t,o)=>{const n=((e,t)=>{const o=Je(e,t),n=Le(Ye(e));return $e(o,n),o})(e,t);return G(o,((e,t)=>{null===e?be(n,t):ge(n,t,e)})),n},Nr=e=>e,Br=(e,t,o)=>{const n=(e,t)=>{((e,t)=>{const o=e.dom,n=t.dom;kt(o)&&kt(n)&&(n.style.cssText=o.style.cssText)})(e.element,t),Lt(t,"height"),1!==e.colspan&&Lt(t,"width")};return{col:o=>{const r=xe.fromTag(ne(o.element),t.dom);return n(o,r),e(o.element,r),r},colgroup:Or(t),row:kr(t),cell:r=>{const s=xe.fromTag(ne(r.element),t.dom),l=o.getOr(["strong","em","b","i","span","font","h1","h2","h3","h4","h5","h6","p","div"]),a=l.length>0?((e,t,o)=>xr(e).map((n=>{const r=o.join(","),s=it(n,r,(t=>Re(t,e)));return z(s,((e,t)=>{const o=Ke(t);return Ie(e,o),o}),t)})).getOr(t))(r.element,s,l):s;return Ie(a,xe.fromTag("br")),n(r,s),((e,t)=>{G(Tr,((o,n)=>we(e,n).filter((e=>D(o,e))).each((e=>ge(t,n,e)))))})(r.element,s),e(r.element,s),s},replace:Er,colGap:Dr(t),gap:Rr(t)}},_r=e=>({col:Dr(e),colgroup:Or(e),row:kr(e),cell:Rr(e),replace:Nr,colGap:Dr(e),gap:Rr(e)}),zr=e=>t=>t.options.get(e),Ar="100%",Lr=e=>{var t;const o=e.dom,n=null!==(t=o.getParent(e.selection.getStart(),o.isBlock))&&void 0!==t?t:e.getBody();return Mo(xe.fromDom(n))+"px"},Wr=e=>C.from(e.options.get("table_clone_elements")),Mr=zr("table_header_type"),jr=zr("table_column_resizing"),Pr=e=>"preservetable"===jr(e),Ir=e=>"resizetable"===jr(e),Fr=zr("table_sizing_mode"),Hr=e=>"relative"===Fr(e),$r=e=>"fixed"===Fr(e),Vr=e=>"responsive"===Fr(e),qr=zr("table_resize_bars"),Ur=zr("table_style_by_css"),Gr=zr("table_merge_content_on_paste"),Kr=e=>{const t=e.options,o=t.get("table_default_attributes");return t.isSet("table_default_attributes")?o:((e,t)=>Vr(e)||Ur(e)?t:$r(e)?{...t,width:Lr(e)}:{...t,width:Ar})(e,o)},Yr=zr("table_use_colgroups"),Jr=e=>bt(e,"[contenteditable]"),Qr=(e,t=!1)=>lt(e)?e.dom.isContentEditable:Jr(e).fold(g(t),(e=>"true"===Xr(e))),Xr=e=>e.dom.contentEditable,Zr=e=>xe.fromDom(e.getBody()),es=e=>t=>Re(t,Zr(e)),ts=e=>{be(e,"data-mce-style");const t=e=>be(e,"data-mce-style");N(Ut(e),t),N(Gt(e),t),N(Yt(e),t)},os=e=>xe.fromDom(e.selection.getStart()),ns=e=>e.getBoundingClientRect().width,rs=e=>e.getBoundingClientRect().height,ss=e=>gt(e,ue("table")).exists(Qr),ls=(e,t)=>{const o=t.column,n=t.column+t.colspan-1,r=t.row,s=t.row+t.rowspan-1;return o<=e.finishCol&&n>=e.startCol&&r<=e.finishRow&&s>=e.startRow},as=(e,t)=>t.column>=e.startCol&&t.column+t.colspan-1<=e.finishCol&&t.row>=e.startRow&&t.row+t.rowspan-1<=e.finishRow,cs=(e,t,o)=>{const n=on(e,t,Re),r=on(e,o,Re);return n.bind((e=>r.map((t=>{return o=e,n=t,{startRow:Math.min(o.row,n.row),startCol:Math.min(o.column,n.column),finishRow:Math.max(o.row+o.rowspan-1,n.row+n.rowspan-1),finishCol:Math.max(o.column+o.colspan-1,n.column+n.colspan-1)};var o,n}))))},is=(e,t,o)=>cs(e,t,o).map((t=>{const o=nn(e,w(ls,t));return E(o,(e=>e.element))})),ms=(e,t)=>on(e,t,((e,t)=>De(t,e))).map((e=>e.element)),ds=(e,t,o)=>{const n=fs(e);return is(n,t,o)},us=(e,t,o,n,r)=>{const s=fs(e),l=Re(e,o)?C.some(t):ms(s,t),a=Re(e,r)?C.some(n):ms(s,n);return l.bind((e=>a.bind((t=>is(s,e,t)))))},fs=Zo;var gs=["body","p","div","article","aside","figcaption","figure","footer","header","nav","section","ol","ul","li","table","thead","tbody","tfoot","caption","tr","td","th","h1","h2","h3","h4","h5","h6","blockquote","pre","address"],hs=()=>({up:g({selector:ht,closest:bt,predicate:ft,all:_e}),down:g({selector:dt,predicate:ct}),styles:g({get:_t,getRaw:At,set:Nt,remove:Lt}),attrs:g({get:pe,set:ge,remove:be,copyTo:(e,t)=>{const o=ve(e);he(t,o)}}),insert:g({before:Me,after:je,afterAll:He,append:Ie,appendAll:$e,prepend:Pe,wrap:Fe}),remove:g({unwrap:Ue,remove:qe}),create:g({nu:xe.fromTag,clone:e=>xe.fromDom(e.dom.cloneNode(!1)),text:xe.fromText}),query:g({comparePosition:(e,t)=>e.dom.compareDocumentPosition(t.dom),prevSibling:ze,nextSibling:Ae}),property:g({children:Le,name:ne,parent:Ne,document:e=>Ee(e).dom,isText:ie,isComment:le,isElement:ce,isSpecial:e=>{const t=ne(e);return D(["script","noscript","iframe","noframes","noembed","title","style","textarea","xmp"],t)},getLanguage:e=>ce(e)?we(e,"lang"):C.none(),getText:hr,setText:wr,isBoundary:e=>!!ce(e)&&("body"===ne(e)||D(gs,ne(e))),isEmptyTag:e=>!!ce(e)&&D(["br","img","hr","input"],ne(e)),isNonEditable:e=>ce(e)&&"false"===pe(e,"contenteditable")}),eq:Re,is:Oe});const ps=(e,t,o,n)=>{const r=t(e,o);return z(n,((o,n)=>{const r=t(e,n);return ws(e,o,r)}),r)},ws=(e,t,o)=>t.bind((t=>o.filter(w(e.eq,t)))),bs=hs(),vs=(e,t)=>((e,t,o)=>o.length>0?((e,t,o,n)=>n(e,t,o[0],o.slice(1)))(e,t,o,ps):C.none())(bs,((t,o)=>e(o)),t),ys=e=>ht(e,"table"),xs=(e,t,o)=>{const n=e=>t=>void 0!==o&&o(t)||Re(t,e);return Re(e,t)?C.some({boxes:C.some([e]),start:e,finish:t}):ys(e).bind((r=>ys(t).bind((s=>{if(Re(r,s))return C.some({boxes:ds(r,e,t),start:e,finish:t});if(De(r,s)){const o=it(t,"td,th",n(r)),l=o.length>0?o[o.length-1]:t;return C.some({boxes:us(r,e,r,t,s),start:e,finish:l})}if(De(s,r)){const o=it(e,"td,th",n(s)),l=o.length>0?o[o.length-1]:e;return C.some({boxes:us(s,e,r,t,s),start:e,finish:l})}return((e,t,o)=>((e,t,o,n=y)=>{const r=[t].concat(e.up().all(t)),s=[o].concat(e.up().all(o)),l=e=>W(e,n).fold((()=>e),(t=>e.slice(0,t+1))),a=l(r),c=l(s),i=L(a,(t=>O(c,((e,t)=>w(e.eq,t))(e,t))));return{firstpath:a,secondpath:c,shared:i}})(bs,e,t,void 0))(e,t).shared.bind((l=>bt(l,"table",o).bind((o=>{const l=it(t,"td,th",n(o)),a=l.length>0?l[l.length-1]:t,c=it(e,"td,th",n(o)),i=c.length>0?c[c.length-1]:e;return C.some({boxes:us(o,e,r,t,s),start:i,finish:a})}))))}))))},Cs=(e,t)=>{const o=dt(e,t);return o.length>0?C.some(o):C.none()},Ss=(e,t,o)=>wt(e,t).bind((t=>wt(e,o).bind((e=>vs(ys,[t,e]).map((o=>({first:t,last:e,table:o}))))))),Ts=(e,t,o,n,r)=>((e,t)=>L(e,(e=>Ce(e,t))))(e,r).bind((e=>((e,t,o)=>Kt(e).bind((n=>((e,t,o,n)=>on(e,t,Re).bind((t=>{const r=o>0?t.row+t.rowspan-1:t.row,s=n>0?t.column+t.colspan-1:t.column;return tn(e,r+o,s+n).map((e=>e.element))})))(fs(n),e,t,o))))(e,t,o).bind((e=>((e,t)=>ht(e,"table").bind((o=>wt(o,t).bind((t=>xs(t,e).bind((e=>e.boxes.map((t=>({boxes:t,start:e.start,finish:e.finish}))))))))))(e,n))))),Rs=(e,t)=>Cs(e,t),Ds=(e,t,o)=>Ss(e,t,o).bind((t=>{const o=t=>Re(e,t),n="thead,tfoot,tbody,table",r=ht(t.first,n,o),s=ht(t.last,n,o);return r.bind((e=>s.bind((o=>Re(e,o)?((e,t,o)=>((e,t,o)=>cs(e,t,o).bind((t=>((e,t)=>{let o=!0;const n=w(as,t);for(let r=t.startRow;r<=t.finishRow;r++)for(let s=t.startCol;s<=t.finishCol;s++)o=o&&tn(e,r,s).exists(n);return o?C.some(t):C.none()})(e,t))))(fs(e),t,o))(t.table,t.first,t.last):C.none()))))})),Os=h,ks=e=>{const t=(e,t)=>we(e,t).exists((e=>parseInt(e,10)>1));return e.length>0&&P(e,(e=>t(e,"rowspan")||t(e,"colspan")))?C.some(e):C.none()},Es=(e,t,o)=>t.length<=1?C.none():Ds(e,o.firstSelectedSelector,o.lastSelectedSelector).map((e=>({bounds:e,cells:t}))),Ns="data-mce-selected",Bs="data-mce-first-selected",_s="data-mce-last-selected",zs="["+Ns+"]",As={selected:Ns,selectedSelector:"td["+Ns+"],th["+Ns+"]",firstSelected:Bs,firstSelectedSelector:"td["+Bs+"],th["+Bs+"]",lastSelected:_s,lastSelectedSelector:"td["+_s+"],th["+_s+"]"},Ls=(e,t,o)=>({element:o,mergable:Es(t,e,As),unmergable:ks(e),selection:Os(e)}),Ws=e=>(t,o)=>{const n=ne(t),r="col"===n||"colgroup"===n?Kt(s=t).bind((e=>Rs(e,As.firstSelectedSelector))).fold(g(s),(e=>e[0])):t;var s;return bt(r,e,o)},Ms=Ws("th,td,caption"),js=Ws("th,td"),Ps=e=>{return t=e.model.table.getSelectedCells(),E(t,xe.fromDom);var t},Is=(e,t)=>{e.on("BeforeGetContent",(t=>{const o=o=>{t.preventDefault(),(e=>Kt(e[0]).map((e=>{const t=((e,t)=>{const o=e=>Ce(e.element,t),n=Ye(e),r=Zt(n),s=mr(e),l=en(r),a=((e,t)=>{const o=e.grid.columns;let n=e.grid.rows,r=o,s=0,l=0;const a=[],c=[];return G(e.access,(e=>{if(a.push(e),t(e)){c.push(e);const t=e.row,o=t+e.rowspan-1,a=e.column,i=a+e.colspan-1;ts&&(s=o),al&&(l=i)}})),((e,t,o,n,r,s)=>({minRow:e,minCol:t,maxRow:o,maxCol:n,allCells:r,selectedCells:s}))(n,r,s,l,a,c)})(l,o),c="th:not("+t+"),td:not("+t+")",i=Vt(n,"th,td",(e=>Ce(e,c)));N(i,qe),((e,t,o,n)=>{const r=_(e,(e=>"colgroup"!==e.section)),s=t.grid.columns,l=t.grid.rows;for(let e=0;eo.maxRow||ao.maxCol||(tn(t,e,a).filter(n).isNone()?fr(r,l,e):l=!0)}})(r,l,a,o);const m=((e,t,o,n)=>{if(0===n.minCol&&t.grid.columns===n.maxCol+1)return 0;const r=sr(t,e,o),s=A(r,((e,t)=>e+t),0),l=A(r.slice(n.minCol,n.maxCol+1),((e,t)=>e+t),0),a=l/s*o.pixelWidth()-o.pixelWidth();return o.getCellDelta(a)})(e,Zo(e),s,a);return((e,t,o,n)=>{G(o.columns,(e=>{(e.columnt.maxCol)&&qe(e.element)}));const r=_($t(e,"tr"),(e=>0===e.dom.childElementCount));N(r,qe),t.minCol!==t.maxCol&&t.minRow!==t.maxRow||N($t(e,"th,td"),(e=>{be(e,"rowspan"),be(e,"colspan")})),be(e,Go),be(e,"data-snooker-col-series"),mr(e).adjustTableWidth(n)})(n,a,l,m),n})(e,zs);return ts(t),[t]})))(o).each((o=>{t.content="text"===t.format?(e=>E(e,(e=>e.dom.innerText)).join(""))(o):((e,t)=>E(t,(t=>e.selection.serializer.serialize(t.dom,{}))).join(""))(e,o)}))};if(!0===t.selection){const t=(e=>_(Ps(e),(e=>Ce(e,As.selectedSelector))))(e);t.length>=1&&o(t)}})),e.on("BeforeSetContent",(o=>{if(!0===o.selection&&!0===o.paste){const n=Ps(e);H(n).each((n=>{Kt(n).each((r=>{const s=_(((e,t)=>{const o=document.createElement("div");return o.innerHTML=e,Le(xe.fromDom(o))})(o.content),(e=>"meta"!==ne(e))),l=ue("table");if(Gr(e)&&1===s.length&&l(s[0])){o.preventDefault();const l=xe.fromDom(e.getDoc()),a=_r(l),c=((e,t,o)=>({element:e,clipboard:t,generators:o}))(n,s[0],a);t.pasteCells(r,c).each((()=>{e.focus()}))}}))}))}}))},Fs=(e,t)=>({element:e,offset:t}),Hs=(e,t,o)=>e.property().isText(t)&&0===e.property().getText(t).trim().length||e.property().isComment(t)?o(t).bind((t=>Hs(e,t,o).orThunk((()=>C.some(t))))):C.none(),$s=(e,t)=>e.property().isText(t)?e.property().getText(t).length:e.property().children(t).length,Vs=(e,t)=>{const o=Hs(e,t,e.query().prevSibling).getOr(t);if(e.property().isText(o))return Fs(o,$s(e,o));const n=e.property().children(o);return n.length>0?Vs(e,n[n.length-1]):Fs(o,$s(e,o))},qs=Vs,Us=hs(),Gs=(e,t)=>{if(!jt(e)){const o=(e=>Un(e).bind((e=>{return t=e,o=["fixed","relative","empty"],C.from(Wn.exec(t)).bind((e=>{const t=Number(e[1]),n=e[2];return((e,t)=>O(t,(t=>O(Ln[t],(t=>e===t)))))(n,o)?C.some({value:t,unit:n}):C.none()}));var t,o})))(e);o.each((o=>{const n=o.value/2;Jn(e,n,o.unit),Jn(t,n,o.unit)}))}},Ks=e=>E(e,g(0)),Ys=(e,t,o,n,r)=>r(e.slice(0,t)).concat(n).concat(r(e.slice(o))),Js=e=>(t,o,n,r)=>{if(e(n)){const e=Math.max(r,t[o]-Math.abs(n)),s=Math.abs(e-t[o]);return n>=0?s:-s}return n},Qs=Js((e=>e<0)),Xs=Js(x),Zs=()=>{const e=(e,t,o,n)=>{const r=(100+o)/100,s=Math.max(n,(e[t]+o)/r);return E(e,((e,o)=>(o===t?s:e/r)-e))},t=(t,o,n,r,s,l)=>l?e(t,o,r,s):((e,t,o,n,r)=>{const s=Qs(e,t,n,r);return Ys(e,t,o+1,[s,0],Ks)})(t,o,n,r,s);return{resizeTable:(e,t)=>e(t),clampTableDelta:Qs,calcLeftEdgeDeltas:t,calcMiddleDeltas:(e,o,n,r,s,l,a)=>t(e,n,r,s,l,a),calcRightEdgeDeltas:(t,o,n,r,s,l)=>{if(l)return e(t,n,r,s);{const e=Qs(t,n,r,s);return Ks(t.slice(0,n)).concat([e])}},calcRedestributedWidths:(e,t,o,n)=>{if(n){const n=(t+o)/t,r=E(e,(e=>e/n));return{delta:100*n-100,newSizes:r}}return{delta:o,newSizes:e}}}},el=()=>{const e=(e,t,o,n,r)=>{const s=Xs(e,n>=0?o:t,n,r);return Ys(e,t,o+1,[s,-s],Ks)};return{resizeTable:(e,t,o)=>{o&&e(t)},clampTableDelta:(e,t,o,n,r)=>{if(r){if(o>=0)return o;{const t=A(e,((e,t)=>e+t-n),0);return Math.max(-t,o)}}return Qs(e,t,o,n)},calcLeftEdgeDeltas:e,calcMiddleDeltas:(t,o,n,r,s,l)=>e(t,n,r,s,l),calcRightEdgeDeltas:(e,t,o,n,r,s)=>{if(s)return Ks(e);{const t=n/e.length;return E(e,g(t))}},calcRedestributedWidths:(e,t,o,n)=>({delta:0,newSizes:e})}},tl=e=>Zo(e).grid,ol=ue("th"),nl=e=>P(e,(e=>ol(e.element))),rl=(e,t)=>e&&t?"sectionCells":e?"section":"cells",sl=e=>{const t="thead"===e.section,o=vt(ll(e.cells),"th");return"tfoot"===e.section?{type:"footer"}:t||o?{type:"header",subType:rl(t,o)}:{type:"body"}},ll=e=>{const t=_(e,(e=>ol(e.element)));return 0===t.length?C.some("td"):t.length===e.length?C.some("th"):C.none()},al=(e,t,o)=>et(o(e.element,t),!0,e.isLocked),cl=(e,t)=>e.section!==t?tt(e.element,e.cells,t,e.isNew):e,il=()=>({transformRow:cl,transformCell:(e,t,o)=>{const n=o(e.element,t),r="td"!==ne(n)?((e,t)=>{const o=Je(e,"td");je(e,o);const n=Le(e);return $e(o,n),qe(e),o})(n):n;return et(r,e.isNew,e.isLocked)}}),ml=()=>({transformRow:cl,transformCell:al}),dl=()=>({transformRow:(e,t)=>cl(e,"thead"===t?"tbody":t),transformCell:al}),ul=il,fl=ml,gl=dl,hl=()=>({transformRow:h,transformCell:al}),pl=(e,t,o,n)=>{o===n?be(e,t):ge(e,t,o)},wl=(e,t,o)=>{$(mt(e,t)).fold((()=>Pe(e,o)),(e=>je(e,o)))},bl=(e,t)=>{const o=[],n=[],r=e=>E(e,(e=>{e.isNew&&o.push(e.element);const t=e.element;return Ve(t),N(e.cells,(e=>{e.isNew&&n.push(e.element),pl(e.element,"colspan",e.colspan,1),pl(e.element,"rowspan",e.rowspan,1),Ie(t,e.element)})),t})),s=e=>j(e,(e=>E(e.cells,(e=>(pl(e.element,"span",e.colspan,1),e.element))))),l=(t,o)=>{const n=((e,t)=>{const o=pt(e,t).getOrThunk((()=>{const o=xe.fromTag(t,ke(e).dom);return"thead"===t?wl(e,"caption,colgroup",o):"colgroup"===t?wl(e,"caption",o):Ie(e,o),o}));return Ve(o),o})(e,o),l=("colgroup"===o?s:r)(t);$e(n,l)},a=(t,o)=>{t.length>0?l(t,o):(t=>{pt(e,t).each(qe)})(o)},c=[],i=[],m=[],d=[];return N(t,(e=>{switch(e.section){case"thead":c.push(e);break;case"tbody":i.push(e);break;case"tfoot":m.push(e);break;case"colgroup":d.push(e)}})),a(d,"colgroup"),a(c,"thead"),a(i,"tbody"),a(m,"tfoot"),{newRows:o,newCells:n}},vl=(e,t)=>{if(0===e.length)return 0;const o=e[0];return W(e,(e=>!t(o.element,e.element))).getOr(e.length)},yl=(e,t)=>{const o=E(e,(e=>E(e.cells,y)));return E(e,((n,r)=>{const s=j(n.cells,((n,s)=>{if(!1===o[r][s]){const m=((e,t,o,n)=>{const r=((e,t)=>e[t])(e,t),s="colgroup"===r.section,l=vl(r.cells.slice(o),n),a=s?1:vl(((e,t)=>E(e,(e=>Ho(e,t))))(e.slice(t),o),n);return{colspan:l,rowspan:a}})(e,r,s,t);return((e,t,n,r)=>{for(let s=e;s({element:e,cells:t,section:o,isNew:n}))(n.element,s,n.section,n.isNew)}))},xl=(e,t,o)=>{const n=[];N(e.colgroups,(r=>{const s=[];for(let n=0;net(e.element,o,!1))).getOrThunk((()=>et(t.colGap(),!0,!1)));s.push(r)}n.push(tt(r.element,s,"colgroup",o))}));for(let r=0;ret(e.element,o,e.isLocked))).getOrThunk((()=>et(t.gap(),!0,!1)));s.push(l)}const l=e.all[r],a=tt(l.element,s,l.section,o);n.push(a)}return n},Cl=e=>yl(e,Re),Sl=(e,t)=>V(e.all,(e=>L(e.cells,(e=>Re(t,e.element))))),Tl=(e,t,o)=>{const n=E(t.selection,(t=>qt(t).bind((t=>Sl(e,t))).filter(o))),r=yt(n);return xt(r.length>0,r)},Rl=(e,t,o,n,r)=>(s,l,a,c)=>{const i=Zo(s),m=C.from(null==c?void 0:c.section).getOrThunk(hl);return t(i,l).map((t=>{const o=((e,t)=>xl(e,t,!1))(i,a),n=e(o,t,Re,r(a),m),s=Yo(n.grid);return{info:t,grid:Cl(n.grid),cursor:n.cursor,lockedColumns:s}})).bind((e=>{const t=bl(s,e.grid),r=C.from(null==c?void 0:c.sizing).getOrThunk((()=>mr(s))),l=C.from(null==c?void 0:c.resize).getOrThunk(el);return o(s,e.grid,e.info,{sizing:r,resize:l,section:m}),n(s),be(s,Go),e.lockedColumns.length>0&&ge(s,Go,e.lockedColumns.join(",")),C.some({cursor:e.cursor,newRows:t.newRows,newCells:t.newCells})}))},Dl=(e,t)=>Tl(e,t,x).map((e=>({cells:e,generators:t.generators,clipboard:t.clipboard}))),Ol=(e,t)=>Tl(e,t,x),kl=(e,t)=>Tl(e,t,(e=>!e.isLocked)),El=(e,t)=>P(t,(t=>((e,t)=>Sl(e,t).exists((e=>!e.isLocked)))(e,t))),Nl=(e,t,o,n)=>{const r=qo(e).rows;let s=!0;for(let e=0;e{const t=t=>t(e),o=g(e),n=()=>r,r={tag:!0,inner:e,fold:(t,o)=>o(e),isValue:x,isError:y,map:t=>zl.value(t(e)),mapError:n,bind:t,exists:t,forall:t,getOr:o,or:n,getOrThunk:o,orThunk:n,getOrDie:o,each:t=>{t(e)},toOptional:()=>C.some(e)};return r},_l=e=>{const t=()=>o,o={tag:!1,inner:e,fold:(t,o)=>t(e),isValue:y,isError:x,map:t,mapError:t=>zl.error(t(e)),bind:t,exists:y,forall:x,getOr:h,or:h,getOrThunk:v,orThunk:v,getOrDie:(n=String(e),()=>{throw new Error(n)}),each:f,toOptional:C.none};var n;return o},zl={value:Bl,error:_l,fromOption:(e,t)=>e.fold((()=>_l(t)),Bl)},Al=(e,t)=>({rowDelta:0,colDelta:Vo(e[0])-Vo(t[0])}),Ll=(e,t)=>({rowDelta:e.length-t.length,colDelta:0}),Wl=(e,t,o,n)=>{const r="colgroup"===t.section?o.col:o.cell;return k(e,(e=>et(r(),!0,n(e))))},Ml=(e,t,o,n)=>{const r=e[e.length-1];return e.concat(k(t,(()=>{const e="colgroup"===r.section?o.colgroup:o.row,t=Uo(r,e,h),s=Wl(t.cells.length,t,o,(e=>X(n,e.toString())));return Fo(t,s)})))},jl=(e,t,o,n)=>E(e,(e=>{const r=Wl(t,e,o,y);return jo(e,n,r)})),Pl=(e,t,o)=>{const n=t.colDelta<0?jl:h,r=t.rowDelta<0?Ml:h,s=Yo(e),l=Vo(e[0]),a=O(s,(e=>e===l-1)),c=n(e,Math.abs(t.colDelta),o,a?l-1:l),i=Yo(c);return r(c,Math.abs(t.rowDelta),o,I(i,x))},Il=(e,t,o,n)=>{const r=w(n,Ho(e[t],o).element),s=e[t];return e.length>1&&Vo(s)>1&&(o>0&&r($o(s,o-1))||o0&&r($o(e[t-1],o))||t_(o,(o=>o>=e.column&&o<=Vo(t[0])+e.column)),Hl=(e,t,o,n,r)=>{((e,t,o,n)=>{t>0&&t{const r=e.cells[t-1];let s=0;const l=n();for(;e.cells.length>t+s&&o(r.element,e.cells[t+s].element);)Io(e,t+s,et(l,!0,e.cells[t+s].isLocked)),s++}))})(t,e,r,n.cell);const s=Ll(o,t),l=Pl(o,s,n),a=Ll(t,l),c=Pl(t,a,n);return E(c,((t,o)=>jo(t,e,l[o].cells)))},$l=(e,t,o,n,r)=>{((e,t,o,n)=>{const r=qo(e).rows;if(t>0&&tA(e,((e,o)=>O(e,(e=>t(e.element,o.element)))?e:e.concat([o])),[]))(r[t-1].cells,o);N(e,(e=>{let s=C.none();for(let l=t;l{Io(a,t,et(e,!0,c.isLocked))})))}}))}})(t,e,r,n.cell);const s=Yo(t),l=Al(t,o),a={...l,colDelta:l.colDelta-s.length},c=Pl(t,a,n),{cols:i,rows:m}=qo(c),d=Yo(c),u=Al(o,t),f={...u,colDelta:u.colDelta+d.length},g=(p=n,w=d,E(o,(e=>A(w,((t,o)=>{const n=Wl(1,e,p,x)[0];return Po(t,o,n)}),e)))),h=Pl(g,f,n);var p,w;return[...i,...m.slice(0,e),...h,...m.slice(e,m.length)]},Vl=(e,t,o,n,r)=>{const{rows:s,cols:l}=qo(e),a=s.slice(0,t),c=s.slice(t);return[...l,...a,((e,t,o,n)=>Uo(e,(e=>n(e,o)),t))(s[o],((e,o)=>t>0&&tE(e,(e=>{const s=t>0&&t{if("colgroup"!==o&&n)return Ho(e,t);{const t=Ho(e,r);return et(l(t.element,s),!0,!1)}})(e,t,e.section,s,o,n,r);return Po(e,t,l)})),Ul=(e,t,o,n)=>((e,t,o,n)=>void 0!==$o(e[t],o)&&t>0&&n($o(e[t-1],o),$o(e[t],o)))(e,t,o,n)||((e,t,o)=>t>0&&o($o(e,t-1),$o(e,t)))(e[t],o,n),Gl=(e,t,o,n)=>{const r=e=>(e=>"row"===e?Pt(t):jt(t))(e)?`${e}group`:e;return e?ol(t)?r(o):null:n&&ol(t)?r("row"===o?"col":"row"):null},Kl=(e,t,o)=>et(o(e.element,t),!0,e.isLocked),Yl=(e,t,o,n,r,s,l)=>E(e,((e,a)=>((e,c)=>{const i=e.cells,m=E(i,((e,c)=>{if((e=>O(t,(t=>o(e.element,t.element))))(e)){const t=l(e,a,c)?r(e,o,n):e;return s(t,a,c).each((e=>{var o,n;o=t.element,n={scope:C.from(e)},G(n,((e,t)=>{e.fold((()=>{be(o,t)}),(e=>{fe(o.dom,t,e)}))}))})),t}return e}));return tt(e.element,m,e.section,e.isNew)})(e))),Jl=(e,t,o)=>j(e,((n,r)=>Ul(e,r,t,o)?[]:[Ho(n,t)])),Ql=(e,t,o,n,r)=>{const s=qo(e).rows,l=j(t,(e=>Jl(s,e,n))),a=E(s,(e=>nl(e.cells))),c=((e,t)=>P(t,h)&&nl(e)?x:(e,o,n)=>!("th"===ne(e.element)&&t[o]))(l,a),i=((e,t)=>(o,n)=>C.some(Gl(e,o.element,"row",t[n])))(o,a);return Yl(e,l,n,r,Kl,i,c)},Xl=(e,t,o,n)=>{const r=qo(e).rows,s=E(t,(e=>Ho(r[e.row],e.column)));return Yl(e,s,o,n,Kl,C.none,x)},Zl=e=>{if(!l(e))throw new Error("cases must be an array");if(0===e.length)throw new Error("there must be at least one case");const t=[],o={};return N(e,((n,r)=>{const s=q(n);if(1!==s.length)throw new Error("one and only one name per case");const a=s[0],c=n[a];if(void 0!==o[a])throw new Error("duplicate key detected:"+a);if("cata"===a)throw new Error("cannot have a case named cata (sorry)");if(!l(c))throw new Error("case arguments must be an array");t.push(a),o[a]=(...o)=>{const n=o.length;if(n!==c.length)throw new Error("Wrong number of arguments to case "+a+". Expected "+c.length+" ("+c+"), got "+n);return{fold:(...t)=>{if(t.length!==e.length)throw new Error("Wrong number of arguments to fold. Expected "+e.length+", got "+t.length);return t[r].apply(null,o)},match:e=>{const n=q(e);if(t.length!==n.length)throw new Error("Wrong number of arguments to match. Expected: "+t.join(",")+"\nActual: "+n.join(","));if(!P(t,(e=>D(n,e))))throw new Error("Not all branches were specified when using match. Specified: "+n.join(", ")+"\nRequired: "+t.join(", "));return e[a].apply(null,o)},log:e=>{console.log(e,{constructors:t,constructor:a,params:o})}}}})),o},ea={...Zl([{none:[]},{only:["index"]},{left:["index","next"]},{middle:["prev","index","next"]},{right:["prev","index"]}])},ta=(e,t,o)=>{let n=0;for(let r=e;r{const o=rn(e);return E(o,(e=>{const o=ta(e.row,e.row+e.rowspan,t);return{element:e.element,height:o,rowspan:e.rowspan}}))},na=(e,t,o)=>{const n=((e,t)=>ln(e)?((e,t)=>{const o=sn(e);return E(o,((e,o)=>({element:e.element,width:t[o],colspan:e.colspan})))})(e,t):((e,t)=>{const o=rn(e);return E(o,(e=>{const o=ta(e.column,e.column+e.colspan,t);return{element:e.element,width:o,colspan:e.colspan}}))})(e,t))(e,t);N(n,(e=>{o.setElementWidth(e.element,e.width)}))},ra=(e,t,o,n,r)=>{const s=Zo(e),l=r.getCellDelta(t),a=r.getWidths(s,r),c=o===s.grid.columns-1,i=n.clampTableDelta(a,o,l,r.minCellWidth(),c),m=((e,t,o,n,r)=>{const s=e.slice(0),l=((e,t)=>0===e.length?ea.none():1===e.length?ea.only(0):0===t?ea.left(0,1):t===e.length-1?ea.right(t-1,t):t>0&&tn.singleColumnWidth(s[e],o)),((e,t)=>r.calcLeftEdgeDeltas(s,e,t,o,n.minCellWidth(),n.isRelative)),((e,t,l)=>r.calcMiddleDeltas(s,e,t,l,o,n.minCellWidth(),n.isRelative)),((e,t)=>r.calcRightEdgeDeltas(s,e,t,o,n.minCellWidth(),n.isRelative)))})(a,o,i,r,n),d=E(m,((e,t)=>e+a[t]));na(s,d,r),n.resizeTable(r.adjustTableWidth,i,c)},sa=e=>A(e,((e,t)=>O(e,(e=>e.column===t.column))?e:e.concat([t])),[]).sort(((e,t)=>e.column-t.column)),la=ue("col"),aa=ue("colgroup"),ca=e=>"tr"===ne(e)||aa(e),ia=e=>({element:e,colspan:Wt(e,"colspan",1),rowspan:Wt(e,"rowspan",1)}),ma=e=>we(e,"scope").map((e=>e.substr(0,3))),da=(e,t=ia)=>{const o=o=>{if(ca(o))return aa((r={element:o}).element)?e.colgroup(r):e.row(r);{const r=o,s=(t=>la(t.element)?e.col(t):e.cell(t))(t(r));return n=C.some({item:r,replacement:s}),s}var r};let n=C.none();return{getOrInit:(e,t)=>n.fold((()=>o(e)),(n=>t(e,n.item)?n.replacement:o(e)))}},ua=e=>t=>{const o=[],n=n=>{const r="td"===e?{scope:null}:{},s=t.replace(n,e,r);return o.push({item:n,sub:s}),s};return{replaceOrInit:(e,t)=>{if(ca(e)||la(e))return e;{const r=e;return((e,t)=>L(o,(o=>t(o.item,e))))(r,t).fold((()=>n(r)),(o=>t(e,o.item)?o.sub:n(r)))}}}},fa=e=>({unmerge:t=>{const o=ma(t);return o.each((e=>ge(t,"scope",e))),()=>{const n=e.cell({element:t,colspan:1,rowspan:1});return Lt(n,"width"),Lt(t,"width"),o.each((e=>ge(n,"scope",e))),n}},merge:e=>(Lt(e[0],"width"),(()=>{const t=yt(E(e,ma));if(0===t.length)return C.none();{const e=t[0],o=["row","col"];return O(t,(t=>t!==e&&D(o,t)))?C.none():C.from(e)}})().fold((()=>be(e[0],"scope")),(t=>ge(e[0],"scope",t+"group"))),g(e[0]))}),ga=["body","p","div","article","aside","figcaption","figure","footer","header","nav","section","ol","ul","table","thead","tfoot","tbody","caption","tr","td","th","h1","h2","h3","h4","h5","h6","blockquote","pre","address"],ha=hs(),pa=e=>((e,t)=>{const o=e.property().name(t);return D(ga,o)})(ha,e),wa=e=>((e,t)=>{const o=e.property().name(t);return D(["ol","ul"],o)})(ha,e),ba=e=>{const t=ue("br"),o=e=>Cr(e).bind((o=>{const n=Ae(o).map((e=>!!pa(e)||!!((e,t)=>D(["br","img","hr","input"],e.property().name(t)))(ha,e)&&"img"!==ne(e))).getOr(!1);return Ne(o).map((r=>{return!0===n||("li"===ne(s=r)||ft(s,wa).isSome())||t(o)||pa(r)&&!Re(e,r)?[]:[xe.fromTag("br")];var s}))})).getOr([]),n=(()=>{const n=j(e,(e=>{const n=Le(e);return(e=>P(e,(e=>t(e)||ie(e)&&0===hr(e).trim().length)))(n)?[]:n.concat(o(e))}));return 0===n.length?[xe.fromTag("br")]:n})();Ve(e[0]),$e(e[0],n)},va=e=>Qr(e,!0),ya=e=>{0===Ut(e).length&&qe(e)},xa=(e,t)=>({grid:e,cursor:t}),Ca=(e,t,o)=>{const n=((e,t,o)=>{var n,r;const s=qo(e).rows;return C.from(null===(r=null===(n=s[t])||void 0===n?void 0:n.cells[o])||void 0===r?void 0:r.element).filter(va).orThunk((()=>(e=>V(e,(e=>V(e.cells,(e=>{const t=e.element;return xt(va(t),t)})))))(s)))})(e,t,o);return xa(e,n)},Sa=e=>A(e,((e,t)=>O(e,(e=>e.row===t.row))?e:e.concat([t])),[]).sort(((e,t)=>e.row-t.row)),Ta=(e,t)=>(o,n,r,s,l)=>{const a=Sa(n),c=E(a,(e=>e.row)),i=((e,t,o,n,r,s,l)=>{const{cols:a,rows:c}=qo(e),i=c[t[0]],m=j(t,(e=>((e,t,o)=>{const n=e[t];return j(n.cells,((n,r)=>Ul(e,t,r,o)?[]:[n]))})(c,e,r))),d=E(i.cells,((e,t)=>nl(Jl(c,t,r)))),u=[...c];N(t,(e=>{u[e]=l.transformRow(c[e],o)}));const f=[...a,...u],g=((e,t)=>P(t,h)&&nl(e.cells)?x:(e,o,n)=>!("th"===ne(e.element)&&t[n]))(i,d),p=((e,t)=>(o,n,r)=>C.some(Gl(e,o.element,"col",t[r])))(n,d);return Yl(f,m,r,s,l.transformCell,p,g)})(o,c,e,t,r,s.replaceOrInit,l);return Ca(i,n[0].row,n[0].column)},Ra=Ta("thead",!0),Da=Ta("tbody",!1),Oa=Ta("tfoot",!1),ka=(e,t,o)=>{const n=((e,t)=>Qt(e,(()=>t)))(e,o.section),r=en(n);return xl(r,t,!0)},Ea=(e,t,o,n)=>((e,t,o,n)=>{const r=en(t),s=n.getWidths(r,n);na(r,s,n)})(0,t,0,n.sizing),Na=(e,t,o,n)=>((e,t,o,n,r)=>{const s=en(t),l=n.getWidths(s,n),a=n.pixelWidth(),{newSizes:c,delta:i}=r.calcRedestributedWidths(l,a,o.pixelDelta,n.isRelative);na(s,c,n),n.adjustTableWidth(i)})(0,t,o,n.sizing,n.resize),Ba=(e,t)=>O(t,(e=>0===e.column&&e.isLocked)),_a=(e,t)=>O(t,(t=>t.column+t.colspan>=e.grid.columns&&t.isLocked)),za=(e,t)=>{const o=cn(e),n=sa(t);return A(n,((e,t)=>e+o[t.column].map(Wo).getOr(0)),0)},Aa=e=>(t,o)=>Ol(t,o).filter((o=>!(e?Ba:_a)(t,o))).map((e=>({details:e,pixelDelta:za(t,e)}))),La=e=>(t,o)=>Dl(t,o).filter((o=>!(e?Ba:_a)(t,o.cells))),Wa=ua("th"),Ma=ua("td"),ja=Rl(((e,t,o,n)=>{const r=t[0].row,s=Sa(t),l=z(s,((e,t)=>({grid:Vl(e.grid,r,t.row+e.delta,o,n.getOrInit),delta:e.delta+1})),{grid:e,delta:0}).grid;return Ca(l,r,t[0].column)}),Ol,f,f,da),Pa=Rl(((e,t,o,n)=>{const r=Sa(t),s=r[r.length-1],l=s.row+s.rowspan,a=z(r,((e,t)=>Vl(e,l,t.row,o,n.getOrInit)),e);return Ca(a,l,t[0].column)}),Ol,f,f,da),Ia=Rl(((e,t,o,n)=>{const r=t.details,s=sa(r),l=s[0].column,a=z(s,((e,t)=>({grid:ql(e.grid,l,t.column+e.delta,o,n.getOrInit),delta:e.delta+1})),{grid:e,delta:0}).grid;return Ca(a,r[0].row,l)}),Aa(!0),Na,f,da),Fa=Rl(((e,t,o,n)=>{const r=t.details,s=r[r.length-1],l=s.column+s.colspan,a=sa(r),c=z(a,((e,t)=>ql(e,l,t.column,o,n.getOrInit)),e);return Ca(c,r[0].row,l)}),Aa(!1),Na,f,da),Ha=Rl(((e,t,o,n)=>{const r=sa(t.details),s=((e,t)=>j(e,(e=>{const o=e.cells,n=z(t,((e,t)=>t>=0&&t0?[tt(e.element,n,e.section,e.isNew)]:[]})))(e,E(r,(e=>e.column))),l=s.length>0?s[0].cells.length-1:0;return Ca(s,r[0].row,Math.min(r[0].column,l))}),((e,t)=>kl(e,t).map((t=>({details:t,pixelDelta:-za(e,t)})))),Na,ya,da),$a=Rl(((e,t,o,n)=>{const r=Sa(t),s=((e,t,o)=>{const{rows:n,cols:r}=qo(e);return[...r,...n.slice(0,t),...n.slice(o+1)]})(e,r[0].row,r[r.length-1].row),l=s.length>0?s.length-1:0;return Ca(s,Math.min(t[0].row,l),t[0].column)}),Ol,f,ya,da),Va=Rl(((e,t,o,n)=>{const r=sa(t),s=E(r,(e=>e.column)),l=Ql(e,s,!0,o,n.replaceOrInit);return Ca(l,t[0].row,t[0].column)}),kl,f,f,Wa),qa=Rl(((e,t,o,n)=>{const r=sa(t),s=E(r,(e=>e.column)),l=Ql(e,s,!1,o,n.replaceOrInit);return Ca(l,t[0].row,t[0].column)}),kl,f,f,Ma),Ua=Rl(Ra,kl,f,f,Wa),Ga=Rl(Da,kl,f,f,Ma),Ka=Rl(Oa,kl,f,f,Ma),Ya=Rl(((e,t,o,n)=>{const r=Xl(e,t,o,n.replaceOrInit);return Ca(r,t[0].row,t[0].column)}),kl,f,f,Wa),Ja=Rl(((e,t,o,n)=>{const r=Xl(e,t,o,n.replaceOrInit);return Ca(r,t[0].row,t[0].column)}),kl,f,f,Ma),Qa=Rl(((e,t,o,n)=>{const r=t.cells;ba(r);const s=((e,t,o,n)=>{const r=qo(e).rows;if(0===r.length)return e;for(let e=t.startRow;e<=t.finishRow;e++)for(let o=t.startCol;o<=t.finishCol;o++){const t=r[e],s=Ho(t,o).isLocked;Io(t,o,et(n(),!1,s))}return e})(e,t.bounds,0,n.merge(r));return xa(s,C.from(r[0]))}),((e,t)=>((e,t)=>t.mergable)(0,t).filter((t=>El(e,t.cells)))),Ea,f,fa),Xa=Rl(((e,t,o,n)=>{const r=z(t,((e,t)=>Nl(e,t,o,n.unmerge(t))),e);return xa(r,C.from(t[0]))}),((e,t)=>((e,t)=>t.unmergable)(0,t).filter((t=>El(e,t)))),Ea,f,fa),Za=Rl(((e,t,o,n)=>{const r=((e,t)=>{const o=Zo(e);return xl(o,t,!0)})(t.clipboard,t.generators);var s,l;return((e,t,o,n,r)=>{const s=Yo(t),l=((e,t,o)=>{const n=Vo(t[0]),r=qo(t).cols.length+e.row,s=k(n-e.column,(t=>t+e.column));return{row:r,column:L(s,(e=>P(o,(t=>t!==e)))).getOr(n-1)}})(e,t,s),a=qo(o).rows,c=Fl(l,a,s),i=((e,t,o)=>{if(e.row>=t.length||e.column>Vo(t[0]))return zl.error("invalid start address out of table bounds, row: "+e.row+", column: "+e.column);const n=t.slice(e.row),r=n[0].cells.slice(e.column),s=Vo(o[0]),l=o.length;return zl.value({rowDelta:n.length-l,colDelta:r.length-s})})(l,t,a);return i.map((e=>{const o={...e,colDelta:e.colDelta-c.length},s=Pl(t,o,n),i=Yo(s),m=Fl(l,a,i);return((e,t,o,n,r,s)=>{const l=e.row,a=e.column,c=l+o.length,i=a+Vo(o[0])+s.length,m=I(s,x);for(let e=l;exa(e,C.some(t.element))),(e=>Ca(e,t.row,t.column)))}),((e,t)=>qt(t.element).bind((o=>Sl(e,o).map((e=>({...e,generators:t.generators,clipboard:t.clipboard})))))),Ea,f,da),ec=Rl(((e,t,o,n)=>{const r=qo(e).rows,s=t.cells[0].column,l=r[t.cells[0].row],a=ka(t.clipboard,t.generators,l),c=Hl(s,e,a,t.generators,o);return Ca(c,t.cells[0].row,t.cells[0].column)}),La(!0),f,f,da),tc=Rl(((e,t,o,n)=>{const r=qo(e).rows,s=t.cells[t.cells.length-1].column+t.cells[t.cells.length-1].colspan,l=r[t.cells[0].row],a=ka(t.clipboard,t.generators,l),c=Hl(s,e,a,t.generators,o);return Ca(c,t.cells[0].row,t.cells[0].column)}),La(!1),f,f,da),oc=Rl(((e,t,o,n)=>{const r=qo(e).rows,s=t.cells[0].row,l=r[s],a=ka(t.clipboard,t.generators,l),c=$l(s,e,a,t.generators,o);return Ca(c,t.cells[0].row,t.cells[0].column)}),Dl,f,f,da),nc=Rl(((e,t,o,n)=>{const r=qo(e).rows,s=t.cells[t.cells.length-1].row+t.cells[t.cells.length-1].rowspan,l=r[t.cells[0].row],a=ka(t.clipboard,t.generators,l),c=$l(s,e,a,t.generators,o);return Ca(c,t.cells[0].row,t.cells[0].column)}),Dl,f,f,da),rc=(e,t)=>{const o=Zo(e);return Ol(o,t).bind((e=>{const t=e[e.length-1],n=e[0].column,r=t.column+t.colspan,s=M(E(o.all,(e=>_(e.cells,(e=>e.column>=n&&e.column{const o=Zo(e);return Ol(o,t).bind(ll).getOr("")},lc=(e,t)=>{const o=Zo(e);return Ol(o,t).bind((e=>{const t=e[e.length-1],n=e[0].row,r=t.row+t.rowspan;return(e=>{const t=E(e,(e=>sl(e).type)),o=D(t,"header"),n=D(t,"footer");if(o||n){const e=D(t,"body");return!o||e||n?o||e||!n?C.none():C.some("footer"):C.some("header")}return C.some("body")})(o.all.slice(n,r))})).getOr("")},ac=(e,t)=>e.dispatch("NewRow",{node:t}),cc=(e,t)=>e.dispatch("NewCell",{node:t}),ic=(e,t,o)=>{e.dispatch("TableModified",{...o,table:t})},mc={structure:!1,style:!0},dc={structure:!0,style:!1},uc={structure:!0,style:!0},fc=(e,t)=>Hr(e)?ur(t):$r(e)?dr(t):mr(t),gc=(e,t,o)=>{const n=e=>"table"===ne(Zr(e)),r=Wr(e),s=Ir(e)?f:Gs,l=t=>{switch(Mr(e)){case"section":return ul();case"sectionCells":return fl();case"cells":return gl();default:return((e,t)=>{var o;switch((o=Zo(e),V(o.all,(e=>{const t=sl(e);return"header"===t.type?C.from(t.subType):C.none()}))).getOr(t)){case"section":return il();case"sectionCells":return ml();case"cells":return dl()}})(t,"section")}},a=(n,s,a,c)=>(i,m,d=!1)=>{ts(i);const u=xe.fromDom(e.getDoc()),f=Br(a,u,r),g={sizing:fc(e,i),resize:Ir(e)?Zs():el(),section:l(i)};return s(i)?n(i,m,f,g).bind((n=>{t.refresh(i.dom),N(n.newRows,(t=>{ac(e,t.dom)})),N(n.newCells,(t=>{cc(e,t.dom)}));const r=((t,n)=>n.cursor.fold((()=>{const n=Ut(t);return H(n).filter(lt).map((n=>{o.clearSelectedCells(t.dom);const r=e.dom.createRng();return r.selectNode(n.dom),e.selection.setRng(r),ge(n,"data-mce-selected","1"),r}))}),(n=>{const r=qs(Us,n),s=e.dom.createRng();return s.setStart(r.element.dom,r.offset),s.setEnd(r.element.dom,r.offset),e.selection.setRng(s),o.clearSelectedCells(t.dom),C.some(s)})))(i,n);return lt(i)&&(ts(i),d||ic(e,i.dom,c)),r.map((e=>({rng:e,effect:c})))})):C.none()},c=a($a,(t=>!n(e)||tl(t).rows>1),f,dc),i=a(Ha,(t=>!n(e)||tl(t).columns>1),f,dc);return{deleteRow:c,deleteColumn:i,insertRowsBefore:a(ja,x,f,dc),insertRowsAfter:a(Pa,x,f,dc),insertColumnsBefore:a(Ia,x,s,dc),insertColumnsAfter:a(Fa,x,s,dc),mergeCells:a(Qa,x,f,dc),unmergeCells:a(Xa,x,f,dc),pasteColsBefore:a(ec,x,f,dc),pasteColsAfter:a(tc,x,f,dc),pasteRowsBefore:a(oc,x,f,dc),pasteRowsAfter:a(nc,x,f,dc),pasteCells:a(Za,x,f,uc),makeCellsHeader:a(Ya,x,f,dc),unmakeCellsHeader:a(Ja,x,f,dc),makeColumnsHeader:a(Va,x,f,dc),unmakeColumnsHeader:a(qa,x,f,dc),makeRowsHeader:a(Ua,x,f,dc),makeRowsBody:a(Ga,x,f,dc),makeRowsFooter:a(Ka,x,f,dc),getTableRowType:lc,getTableCellType:sc,getTableColType:rc}},hc=(e,t,o)=>{const n=Wt(e,t,1);1===o||n<=1?be(e,t):ge(e,t,Math.min(o,n))},pc=(e,t)=>o=>{const n=o.column+o.colspan-1,r=o.column;return n>=e&&r{const n=o.substring(0,o.length-e.length),r=parseFloat(n);return n===r.toString()?t(r):wc.invalid(o)},vc={...wc,from:e=>Rt(e,"%")?bc("%",wc.percent,e):Rt(e,"px")?bc("px",wc.pixels,e):wc.invalid(e)},yc=(e,t,o)=>{const n=vc.from(o),r=P(e,(e=>"0px"===e))?((e,t)=>{const o=e.fold((()=>g("")),(e=>g(e/t+"px")),(()=>g(100/t+"%")));return k(t,o)})(n,e.length):((e,t,o)=>e.fold((()=>t),(e=>((e,t,o)=>{const n=o/t;return E(e,(e=>vc.from(e).fold((()=>e),(e=>e*n+"px"),(e=>e/100*o+"px"))))})(t,o,e)),(e=>((e,t)=>E(e,(e=>vc.from(e).fold((()=>e),(e=>e/t*100+"%"),(e=>e+"%")))))(t,o))))(n,e,t);return Sc(r)},xc=(e,t)=>0===e.length?t:z(e,((e,t)=>vc.from(t).fold(g(0),h,h)+e),0),Cc=(e,t)=>vc.from(e).fold(g(e),(e=>e+t+"px"),(e=>e+t+"%")),Sc=e=>{if(0===e.length)return e;const t=z(e,((e,t)=>{const o=vc.from(t).fold((()=>({value:t,remainder:0})),(e=>((e,t)=>{const o=Math.floor(e);return{value:o+"px",remainder:e-o}})(e)),(e=>({value:e+"%",remainder:0})));return{output:[o.value].concat(e.output),remainder:e.remainder+o.remainder}}),{output:[],remainder:0}),o=t.output;return o.slice(0,o.length-1).concat([Cc(o[o.length-1],Math.round(t.remainder))])},Tc=vc.from,Rc=e=>Tc(e).fold(g("px"),g("px"),g("%")),Dc=(e,t,o)=>{const n=Zo(e),r=n.all,s=rn(n),l=sn(n);t.each((t=>{const o=Rc(t),r=Lo(e),a=((e,t)=>nr(e,t,er,rr))(n,e),c=yc(a,r,t);ln(n)?((e,t,o)=>{N(t,((t,n)=>{const r=xc([e[n]],Ft());Nt(t.element,"width",r+o)}))})(c,l,o):((e,t,o)=>{N(t,(t=>{const n=e.slice(t.column,t.colspan+t.column),r=xc(n,Ft());Nt(t.element,"width",r+o)}))})(c,s,o),Nt(e,"width",t)})),o.each((t=>{const o=Rc(t),l=hn(e),a=((e,t,o)=>lr(e,t,o,tr,rr))(n,e,_n);((e,t,o,n)=>{N(o,(t=>{const o=e.slice(t.row,t.rowspan+t.row),r=xc(o,Ht());Nt(t.element,"height",r+n)})),N(t,((t,o)=>{Nt(t.element,"height",e[o])}))})(yc(a,l,t),r,s,o),Nt(e,"height",t)}))},Oc=e=>Un(e).exists((e=>Mn.test(e))),kc=e=>Un(e).exists((e=>jn.test(e))),Ec=e=>Un(e).isNone(),Nc=e=>{be(e,"width")},Bc=e=>{const t=Qn(e);Dc(e,C.some(t),C.none()),Nc(e)},_c=e=>{const t=(e=>Lo(e)+"px")(e);Dc(e,C.some(t),C.none()),Nc(e)},zc=e=>{Lt(e,"width");const t=Gt(e),o=t.length>0?t:Ut(e);N(o,(e=>{Lt(e,"width"),Nc(e)})),Nc(e)},Ac={styles:{"border-collapse":"collapse",width:"100%"},attributes:{border:"1"},colGroups:!1},Lc=(e,t,o,n)=>k(e,(e=>((e,t,o,n)=>{const r=xe.fromTag("tr");for(let s=0;s{e.selection.select(t.dom,!0),e.selection.collapse(!0)},Mc=(e,t,o,n,s)=>{const l=(e=>{const t=e.options,o=t.get("table_default_styles");return t.isSet("table_default_styles")?o:((e,t)=>Vr(e)||!Ur(e)?t:$r(e)?{...t,width:Lr(e)}:{...t,width:Ar})(e,o)})(e),a={styles:l,attributes:Kr(e),colGroups:Yr(e)};return e.undoManager.ignore((()=>{const r=((e,t,o,n,r,s=Ac)=>{const l=xe.fromTag("table"),a="cells"!==r;Bt(l,s.styles),he(l,s.attributes),s.colGroups&&Ie(l,(e=>{const t=xe.fromTag("colgroup");return k(e,(()=>Ie(t,xe.fromTag("col")))),t})(t));const c=Math.min(e,o);if(a&&o>0){const e=xe.fromTag("thead");Ie(l,e);const s=Lc(o,t,"sectionCells"===r?c:0,n);$e(e,s)}const i=xe.fromTag("tbody");Ie(l,i);const m=Lc(a?e-c:e,t,a?0:o,n);return $e(i,m),l})(o,t,s,n,Mr(e),a);ge(r,"data-mce-id","__mce");const l=(e=>{const t=xe.fromTag("div"),o=xe.fromDom(e.dom.cloneNode(!0));return Ie(t,o),(e=>e.dom.innerHTML)(t)})(r);e.insertContent(l),e.addVisual()})),wt(Zr(e),'table[data-mce-id="__mce"]').map((t=>($r(e)?_c(t):Vr(e)?zc(t):(Hr(e)||(e=>r(e)&&-1!==e.indexOf("%"))(l.width))&&Bc(t),ts(t),be(t,"data-mce-id"),((e,t)=>{N(dt(t,"tr"),(t=>{ac(e,t.dom),N(dt(t,"th,td"),(t=>{cc(e,t.dom)}))}))})(e,t),((e,t)=>{wt(t,"td,th").each(w(Wc,e))})(e,t),t.dom))).getOrNull()};var jc=tinymce.util.Tools.resolve("tinymce.FakeClipboard");const Pc="x-tinymce/dom-table-",Ic=Pc+"rows",Fc=Pc+"columns",Hc=e=>{const t=jc.FakeClipboardItem(e);jc.write([t])},$c=e=>{var t;const o=null!==(t=jc.read())&&void 0!==t?t:[];return V(o,(t=>C.from(t.getType(e))))},Vc=e=>{$c(e).isSome()&&jc.clear()},qc=e=>{e.fold(Gc,(e=>Hc({[Ic]:e})))},Uc=()=>$c(Ic),Gc=()=>Vc(Ic),Kc=e=>{e.fold(Jc,(e=>Hc({[Fc]:e})))},Yc=()=>$c(Fc),Jc=()=>Vc(Fc),Qc=e=>Ms(os(e),es(e)).filter(ss),Xc=(e,t)=>{const o=es(e),n=e=>Kt(e,o),l=t=>(e=>js(os(e),es(e)).filter(ss))(e).bind((e=>n(e).map((o=>t(o,e))))),a=t=>{e.focus()},c=(t,o=!1)=>l(((n,r)=>{const s=Ls(Ps(e),n,r);t(n,s,o).each(a)})),i=()=>l(((t,o)=>((e,t,o)=>{const n=Zo(e);return Ol(n,t).bind((e=>{const t=xl(n,o,!1),r=qo(t).rows.slice(e[0].row,e[e.length-1].row+e[e.length-1].rowspan),s=j(r,(e=>{const t=_(e.cells,(e=>!e.isLocked));return t.length>0?[{...e,cells:t}]:[]})),l=Cl(s);return xt(l.length>0,l)})).map((e=>E(e,(e=>{const t=Ke(e.element);return N(e.cells,(e=>{const o=Ye(e.element);pl(o,"colspan",e.colspan,1),pl(o,"rowspan",e.rowspan,1),Ie(t,o)})),t}))))})(t,Ls(Ps(e),t,o),Br(f,xe.fromDom(e.getDoc()),C.none())))),m=()=>l(((t,o)=>((e,t)=>{const o=Zo(e);return kl(o,t).map((e=>{const t=e[e.length-1],n=e[0].column,r=t.column+t.colspan,s=((e,t,o)=>{if(ln(e)){const n=_(sn(e),pc(t,o)),r=E(n,(e=>{const n=Ye(e.element);return hc(n,"span",o-t),n})),s=xe.fromTag("colgroup");return $e(s,r),[s]}return[]})(o,n,r),l=((e,t,o)=>E(e.all,(e=>{const n=_(e.cells,pc(t,o)),r=E(n,(e=>{const n=Ye(e.element);return hc(n,"colspan",o-t),n})),s=xe.fromTag("tr");return $e(s,r),s})))(o,n,r);return[...s,...l]}))})(t,Ls(Ps(e),t,o)))),d=(t,o)=>o().each((o=>{const n=E(o,(e=>Ye(e)));l(((o,r)=>{const s=_r(xe.fromDom(e.getDoc())),l=((e,t,o,n)=>({selection:Os(e),clipboard:o,generators:n}))(Ps(e),0,n,s);t(o,l).each(a)}))})),g=e=>(t,o)=>((e,t)=>X(e,t)?C.from(e[t]):C.none())(o,"type").each((t=>{c(e(t),o.no_events)}));G({mceTableSplitCells:()=>c(t.unmergeCells),mceTableMergeCells:()=>c(t.mergeCells),mceTableInsertRowBefore:()=>c(t.insertRowsBefore),mceTableInsertRowAfter:()=>c(t.insertRowsAfter),mceTableInsertColBefore:()=>c(t.insertColumnsBefore),mceTableInsertColAfter:()=>c(t.insertColumnsAfter),mceTableDeleteCol:()=>c(t.deleteColumn),mceTableDeleteRow:()=>c(t.deleteRow),mceTableCutCol:()=>m().each((e=>{Kc(e),c(t.deleteColumn)})),mceTableCutRow:()=>i().each((e=>{qc(e),c(t.deleteRow)})),mceTableCopyCol:()=>m().each((e=>Kc(e))),mceTableCopyRow:()=>i().each((e=>qc(e))),mceTablePasteColBefore:()=>d(t.pasteColsBefore,Yc),mceTablePasteColAfter:()=>d(t.pasteColsAfter,Yc),mceTablePasteRowBefore:()=>d(t.pasteRowsBefore,Uc),mceTablePasteRowAfter:()=>d(t.pasteRowsAfter,Uc),mceTableDelete:()=>Qc(e).each((t=>{Kt(t,o).filter(b(o)).each((t=>{const o=xe.fromText("");if(je(t,o),qe(t),e.dom.isEmpty(e.getBody()))e.setContent(""),e.selection.setCursorLocation();else{const t=e.dom.createRng();t.setStart(o.dom,0),t.setEnd(o.dom,0),e.selection.setRng(t),e.nodeChanged()}}))})),mceTableCellToggleClass:(t,o)=>{l((t=>{const n=Ps(e),r=P(n,(t=>e.formatter.match("tablecellclass",{value:o},t.dom))),s=r?e.formatter.remove:e.formatter.apply;N(n,(e=>s("tablecellclass",{value:o},e.dom))),ic(e,t.dom,mc)}))},mceTableToggleClass:(t,o)=>{l((t=>{e.formatter.toggle("tableclass",{value:o},t.dom),ic(e,t.dom,mc)}))},mceTableToggleCaption:()=>{Qc(e).each((t=>{Kt(t,o).each((o=>{pt(o,"caption").fold((()=>{const t=xe.fromTag("caption");Ie(t,xe.fromText("Caption")),((e,t,o)=>{We(e,0).fold((()=>{Ie(e,t)}),(e=>{Me(e,t)}))})(o,t),e.selection.setCursorLocation(t.dom,0)}),(n=>{ue("caption")(t)&&Te("td",o).each((t=>e.selection.setCursorLocation(t.dom,0))),qe(n)})),ic(e,o.dom,dc)}))}))},mceTableSizingMode:(t,n)=>(t=>Qc(e).each((n=>{Vr(e)||$r(e)||Hr(e)||Kt(n,o).each((o=>{"relative"!==t||Oc(o)?"fixed"!==t||kc(o)?"responsive"!==t||Ec(o)||zc(o):_c(o):Bc(o),ts(o),ic(e,o.dom,dc)}))})))(n),mceTableCellType:g((e=>"th"===e?t.makeCellsHeader:t.unmakeCellsHeader)),mceTableColType:g((e=>"th"===e?t.makeColumnsHeader:t.unmakeColumnsHeader)),mceTableRowType:g((e=>{switch(e){case"header":return t.makeRowsHeader;case"footer":return t.makeRowsFooter;default:return t.makeRowsBody}}))},((t,o)=>e.addCommand(o,t))),e.addCommand("mceInsertTable",((t,o)=>{((e,t,o,n={})=>{const r=e=>u(e)&&e>0;if(r(t)&&r(o)){const r=n.headerRows||0,s=n.headerColumns||0;return Mc(e,o,t,s,r)}console.error("Invalid values for mceInsertTable - rows and columns values are required to insert a table.")})(e,o.rows,o.columns,o.options)})),e.addCommand("mceTableApplyCellStyle",((t,o)=>{const l=e=>"tablecell"+e.toLowerCase().replace("-","");if(!s(o))return;const a=_(Ps(e),ss);if(0===a.length)return;const c=((e,t)=>{const o={};return((e,t,o,n)=>{G(e,((e,r)=>{(t(e,r)?o:n)(e,r)}))})(e,t,(e=>(t,o)=>{e[o]=t})(o),f),o})(o,((t,o)=>e.formatter.has(l(o))&&r(t)));(e=>{for(const t in e)if(U.call(e,t))return!1;return!0})(c)||(G(c,((t,o)=>{const n=l(o);N(a,(o=>{""===t?e.formatter.remove(n,{value:null},o.dom,!0):e.formatter.apply(n,{value:t},o.dom)}))})),n(a[0]).each((t=>ic(e,t.dom,mc))))}))},Zc=Zl([{before:["element"]},{on:["element","offset"]},{after:["element"]}]),ei={before:Zc.before,on:Zc.on,after:Zc.after,cata:(e,t,o,n)=>e.fold(t,o,n),getStart:e=>e.fold(h,h,h)},ti=(e,t)=>({selection:e,kill:t}),oi=(e,t)=>{const o=e.document.createRange();return o.selectNode(t.dom),o},ni=(e,t)=>{const o=e.document.createRange();return ri(o,t),o},ri=(e,t)=>e.selectNodeContents(t.dom),si=(e,t,o)=>{const n=e.document.createRange();var r;return r=n,t.fold((e=>{r.setStartBefore(e.dom)}),((e,t)=>{r.setStart(e.dom,t)}),(e=>{r.setStartAfter(e.dom)})),((e,t)=>{t.fold((t=>{e.setEndBefore(t.dom)}),((t,o)=>{e.setEnd(t.dom,o)}),(t=>{e.setEndAfter(t.dom)}))})(n,o),n},li=(e,t,o,n,r)=>{const s=e.document.createRange();return s.setStart(t.dom,o),s.setEnd(n.dom,r),s},ai=e=>({left:e.left,top:e.top,right:e.right,bottom:e.bottom,width:e.width,height:e.height}),ci=Zl([{ltr:["start","soffset","finish","foffset"]},{rtl:["start","soffset","finish","foffset"]}]),ii=(e,t,o)=>t(xe.fromDom(o.startContainer),o.startOffset,xe.fromDom(o.endContainer),o.endOffset),mi=(e,t)=>{const o=((e,t)=>t.match({domRange:e=>({ltr:g(e),rtl:C.none}),relative:(t,o)=>({ltr:eo((()=>si(e,t,o))),rtl:eo((()=>C.some(si(e,o,t))))}),exact:(t,o,n,r)=>({ltr:eo((()=>li(e,t,o,n,r))),rtl:eo((()=>C.some(li(e,n,r,t,o))))})}))(e,t);return((e,t)=>{const o=t.ltr();return o.collapsed?t.rtl().filter((e=>!1===e.collapsed)).map((e=>ci.rtl(xe.fromDom(e.endContainer),e.endOffset,xe.fromDom(e.startContainer),e.startOffset))).getOrThunk((()=>ii(0,ci.ltr,o))):ii(0,ci.ltr,o)})(0,o)},di=(e,t)=>mi(e,t).match({ltr:(t,o,n,r)=>{const s=e.document.createRange();return s.setStart(t.dom,o),s.setEnd(n.dom,r),s},rtl:(t,o,n,r)=>{const s=e.document.createRange();return s.setStart(n.dom,r),s.setEnd(t.dom,o),s}});ci.ltr,ci.rtl;const ui=(e,t,o,n)=>({start:e,soffset:t,finish:o,foffset:n}),fi=(e,t,o,n)=>({start:ei.on(e,t),finish:ei.on(o,n)}),gi=(e,t)=>{const o=di(e,t);return ui(xe.fromDom(o.startContainer),o.startOffset,xe.fromDom(o.endContainer),o.endOffset)},hi=fi,pi=(e,t,o,n,r)=>Re(o,n)?C.none():xs(o,n,t).bind((t=>{const n=t.boxes.getOr([]);return n.length>1?(r(e,n,t.start,t.finish),C.some(ti(C.some(hi(o,0,o,br(o))),!0))):C.none()})),wi=(e,t)=>({item:e,mode:t}),bi=(e,t,o,n=vi)=>e.property().parent(t).map((e=>wi(e,n))),vi=(e,t,o,n=yi)=>o.sibling(e,t).map((e=>wi(e,n))),yi=(e,t,o,n=yi)=>{const r=e.property().children(t);return o.first(r).map((e=>wi(e,n)))},xi=[{current:bi,next:vi,fallback:C.none()},{current:vi,next:yi,fallback:C.some(bi)},{current:yi,next:yi,fallback:C.some(vi)}],Ci=(e,t,o,n,r=xi)=>L(r,(e=>e.current===o)).bind((o=>o.current(e,t,n,o.next).orThunk((()=>o.fallback.bind((o=>Ci(e,t,o,n))))))),Si=(e,t,o,n,r,s)=>Ci(e,t,n,r).bind((t=>s(t.item)?C.none():o(t.item)?C.some(t.item):Si(e,t.item,o,t.mode,r,s))),Ti=e=>t=>0===e.property().children(t).length,Ri=(e,t,o,n)=>Si(e,t,o,vi,{sibling:(e,t)=>e.query().prevSibling(t),first:e=>e.length>0?C.some(e[e.length-1]):C.none()},n),Di=(e,t,o,n)=>Si(e,t,o,vi,{sibling:(e,t)=>e.query().nextSibling(t),first:e=>e.length>0?C.some(e[0]):C.none()},n),Oi=hs(),ki=(e,t)=>((e,t,o)=>Ri(e,t,Ti(e),o))(Oi,e,t),Ei=(e,t)=>((e,t,o)=>Di(e,t,Ti(e),o))(Oi,e,t),Ni=Zl([{none:["message"]},{success:[]},{failedUp:["cell"]},{failedDown:["cell"]}]),Bi=e=>bt(e,"tr"),_i={...Ni,verify:(e,t,o,n,r,s,l)=>bt(n,"td,th",l).bind((o=>bt(t,"td,th",l).map((t=>Re(o,t)?Re(n,o)&&br(o)===r?s(t):Ni.none("in same cell"):vs(Bi,[o,t]).fold((()=>((e,t,o)=>{const n=e.getRect(t),r=e.getRect(o);return r.right>n.left&&r.lefts(t))))))).getOr(Ni.none("default")),cata:(e,t,o,n,r)=>e.fold(t,o,n,r)},zi=ue("br"),Ai=(e,t,o)=>t(e,o).bind((e=>ie(e)&&0===hr(e).trim().length?Ai(e,t,o):C.some(e))),Li=(e,t,o,n)=>((e,t)=>We(e,t).filter(zi).orThunk((()=>We(e,t-1).filter(zi))))(t,o).bind((t=>n.traverse(t).fold((()=>Ai(t,n.gather,e).map(n.relative)),(e=>(e=>Ne(e).bind((t=>{const o=Le(t);return((e,t)=>W(e,w(Re,t)))(o,e).map((n=>((e,t,o,n)=>({parent:e,children:t,element:o,index:n}))(t,o,e,n)))})))(e).map((e=>ei.on(e.parent,e.index))))))),Wi=(e,t)=>({left:e.left,top:e.top+t,right:e.right,bottom:e.bottom+t}),Mi=(e,t)=>({left:e.left,top:e.top-t,right:e.right,bottom:e.bottom-t}),ji=(e,t,o)=>({left:e.left+t,top:e.top+o,right:e.right+t,bottom:e.bottom+o}),Pi=e=>({left:e.left,top:e.top,right:e.right,bottom:e.bottom}),Ii=(e,t)=>C.some(e.getRect(t)),Fi=(e,t,o)=>ce(t)?Ii(e,t).map(Pi):ie(t)?((e,t,o)=>o>=0&&o0?e.getRangedRect(t,o-1,t,o):C.none())(e,t,o).map(Pi):C.none(),Hi=(e,t)=>ce(t)?Ii(e,t).map(Pi):ie(t)?e.getRangedRect(t,0,t,br(t)).map(Pi):C.none(),$i=Zl([{none:[]},{retry:["caret"]}]),Vi=(e,t,o)=>gt(t,pa).fold(y,(t=>Hi(e,t).exists((e=>((e,t)=>e.leftt.right)(o,e))))),qi={point:e=>e.bottom,adjuster:(e,t,o,n,r)=>{const s=Wi(r,5);return Math.abs(o.bottom-n.bottom)<1||o.top>r.bottom?$i.retry(s):o.top===r.bottom?$i.retry(Wi(r,1)):Vi(e,t,r)?$i.retry(ji(s,5,0)):$i.none()},move:Wi,gather:Ei},Ui=(e,t,o,n,r)=>0===r?C.some(n):((e,t,o)=>e.elementFromPoint(t,o).filter((e=>"table"===ne(e))).isSome())(e,n.left,t.point(n))?((e,t,o,n,r)=>Ui(e,t,o,t.move(n,5),r))(e,t,o,n,r-1):e.situsFromPoint(n.left,t.point(n)).bind((s=>s.start.fold(C.none,(s=>Hi(e,s).bind((l=>t.adjuster(e,s,l,o,n).fold(C.none,(n=>Ui(e,t,o,n,r-1))))).orThunk((()=>C.some(n)))),C.none))),Gi=(e,t,o)=>{const n=e.move(o,5),r=Ui(t,e,o,n,100).getOr(n);return((e,t,o)=>e.point(t)>o.getInnerHeight()?C.some(e.point(t)-o.getInnerHeight()):e.point(t)<0?C.some(-e.point(t)):C.none())(e,r,t).fold((()=>t.situsFromPoint(r.left,e.point(r))),(o=>(t.scrollBy(0,o),t.situsFromPoint(r.left,e.point(r)-o))))},Ki={tryUp:w(Gi,{point:e=>e.top,adjuster:(e,t,o,n,r)=>{const s=Mi(r,5);return Math.abs(o.top-n.top)<1||o.bottome.getSelection().bind((n=>((e,t,o,n)=>{const r=zi(t)?((e,t,o)=>o.traverse(t).orThunk((()=>Ai(t,o.gather,e))).map(o.relative))(e,t,n):Li(e,t,o,n);return r.map((e=>({start:e,finish:e})))})(t,n.finish,n.foffset,o).fold((()=>C.some(Fs(n.finish,n.foffset))),(r=>{const s=e.fromSitus(r);return l=_i.verify(e,n.finish,n.foffset,s.finish,s.foffset,o.failure,t),_i.cata(l,(e=>C.none()),(()=>C.none()),(e=>C.some(Fs(e,0))),(e=>C.some(Fs(e,br(e)))));var l})))),Ji=(e,t,o,n,r,s)=>0===s?C.none():Zi(e,t,o,n,r).bind((l=>{const a=e.fromSitus(l),c=_i.verify(e,o,n,a.finish,a.foffset,r.failure,t);return _i.cata(c,(()=>C.none()),(()=>C.some(l)),(l=>Re(o,l)&&0===n?Qi(e,o,n,Mi,r):Ji(e,t,l,0,r,s-1)),(l=>Re(o,l)&&n===br(l)?Qi(e,o,n,Wi,r):Ji(e,t,l,br(l),r,s-1)))})),Qi=(e,t,o,n,r)=>Fi(e,t,o).bind((t=>Xi(e,r,n(t,Ki.getJumpSize())))),Xi=(e,t,o)=>{const n=Bo().browser;return n.isChromium()||n.isSafari()||n.isFirefox()?t.retry(e,o):C.none()},Zi=(e,t,o,n,r)=>Fi(e,o,n).bind((t=>Xi(e,r,t))),em=(e,t,o,n,r)=>bt(n,"td,th",t).bind((n=>bt(n,"table",t).bind((s=>((e,t)=>ft(e,(e=>Ne(e).exists((e=>Re(e,t)))),void 0).isSome())(r,s)?((e,t,o)=>Yi(e,t,o).bind((n=>Ji(e,t,n.element,n.offset,o,20).map(e.fromSitus))))(e,t,o).bind((e=>bt(e.finish,"td,th",t).map((t=>({start:n,finish:t,range:e}))))):C.none())))),tm=(e,t,o,n,r,s)=>s(n,t).orThunk((()=>em(e,t,o,n,r).map((e=>{const t=e.range;return ti(C.some(hi(t.start,t.soffset,t.finish,t.foffset)),!0)})))),om=(e,t)=>bt(e,"tr",t).bind((e=>bt(e,"table",t).bind((o=>{const n=dt(o,"tr");return Re(e,n[0])?((e,t,o)=>Ri(Oi,e,(e=>Cr(e).isSome()),o))(o,0,t).map((e=>{const t=br(e);return ti(C.some(hi(e,t,e,t)),!0)})):C.none()})))),nm=(e,t)=>bt(e,"tr",t).bind((e=>bt(e,"table",t).bind((o=>{const n=dt(o,"tr");return Re(e,n[n.length-1])?((e,t,o)=>Di(Oi,e,(e=>xr(e).isSome()),o))(o,0,t).map((e=>ti(C.some(hi(e,0,e,0)),!0))):C.none()})))),rm=(e,t,o,n,r,s,l)=>em(e,o,n,r,s).bind((e=>pi(t,o,e.start,e.finish,l))),sm=e=>{let t=e;return{get:()=>t,set:e=>{t=e}}},lm=()=>{const e=(e=>{const t=sm(C.none()),o=()=>t.get().each(e);return{clear:()=>{o(),t.set(C.none())},isSet:()=>t.get().isSome(),get:()=>t.get(),set:e=>{o(),t.set(C.some(e))}}})(f);return{...e,on:t=>e.get().each(t)}},am=(e,t)=>bt(e,"td,th",t),cm=e=>Be(e).exists(Qr),im={traverse:Ae,gather:Ei,relative:ei.before,retry:Ki.tryDown,failure:_i.failedDown},mm={traverse:ze,gather:ki,relative:ei.before,retry:Ki.tryUp,failure:_i.failedUp},dm=e=>t=>t===e,um=dm(38),fm=dm(40),gm=e=>e>=37&&e<=40,hm={isBackward:dm(37),isForward:dm(39)},pm={isBackward:dm(39),isForward:dm(37)},wm=Zl([{domRange:["rng"]},{relative:["startSitu","finishSitu"]},{exact:["start","soffset","finish","foffset"]}]),bm={domRange:wm.domRange,relative:wm.relative,exact:wm.exact,exactFromRange:e=>wm.exact(e.start,e.soffset,e.finish,e.foffset),getWin:e=>{const t=(e=>e.match({domRange:e=>xe.fromDom(e.startContainer),relative:(e,t)=>ei.getStart(e),exact:(e,t,o,n)=>e}))(e);return xe.fromDom(Ee(t).dom.defaultView)},range:ui},vm=document.caretPositionFromPoint?(e,t,o)=>{var n,r;return C.from(null===(r=(n=e.dom).caretPositionFromPoint)||void 0===r?void 0:r.call(n,t,o)).bind((t=>{if(null===t.offsetNode)return C.none();const o=e.dom.createRange();return o.setStart(t.offsetNode,t.offset),o.collapse(),C.some(o)}))}:document.caretRangeFromPoint?(e,t,o)=>{var n,r;return C.from(null===(r=(n=e.dom).caretRangeFromPoint)||void 0===r?void 0:r.call(n,t,o))}:C.none,ym=(e,t)=>{const o=ne(e);return"input"===o?ei.after(e):D(["br","img"],o)?0===t?ei.before(e):ei.after(e):ei.on(e,t)},xm=e=>C.from(e.getSelection()),Cm=(e,t)=>{xm(e).each((e=>{e.removeAllRanges(),e.addRange(t)}))},Sm=(e,t,o,n,r)=>{const s=li(e,t,o,n,r);Cm(e,s)},Tm=(e,t)=>mi(e,t).match({ltr:(t,o,n,r)=>{Sm(e,t,o,n,r)},rtl:(t,o,n,r)=>{xm(e).each((s=>{if(s.setBaseAndExtent)s.setBaseAndExtent(t.dom,o,n.dom,r);else if(s.extend)try{((e,t,o,n,r,s)=>{t.collapse(o.dom,n),t.extend(r.dom,s)})(0,s,t,o,n,r)}catch(s){Sm(e,n,r,t,o)}else Sm(e,n,r,t,o)}))}}),Rm=(e,t,o,n,r)=>{const s=((e,t,o,n)=>{const r=ym(e,t),s=ym(o,n);return bm.relative(r,s)})(t,o,n,r);Tm(e,s)},Dm=(e,t,o)=>{const n=((e,t)=>{const o=e.fold(ei.before,ym,ei.after),n=t.fold(ei.before,ym,ei.after);return bm.relative(o,n)})(t,o);Tm(e,n)},Om=e=>{if(e.rangeCount>0){const t=e.getRangeAt(0),o=e.getRangeAt(e.rangeCount-1);return C.some(ui(xe.fromDom(t.startContainer),t.startOffset,xe.fromDom(o.endContainer),o.endOffset))}return C.none()},km=e=>{if(null===e.anchorNode||null===e.focusNode)return Om(e);{const t=xe.fromDom(e.anchorNode),o=xe.fromDom(e.focusNode);return((e,t,o,n)=>{const r=((e,t,o,n)=>{const r=ke(e).dom.createRange();return r.setStart(e.dom,t),r.setEnd(o.dom,n),r})(e,t,o,n),s=Re(e,o)&&t===n;return r.collapsed&&!s})(t,e.anchorOffset,o,e.focusOffset)?C.some(ui(t,e.anchorOffset,o,e.focusOffset)):Om(e)}},Em=(e,t,o=!0)=>{const n=(o?ni:oi)(e,t);Cm(e,n)},Nm=e=>(e=>xm(e).filter((e=>e.rangeCount>0)).bind(km))(e).map((e=>bm.exact(e.start,e.soffset,e.finish,e.foffset))),Bm=e=>({elementFromPoint:(t,o)=>xe.fromPoint(xe.fromDom(e.document),t,o),getRect:e=>e.dom.getBoundingClientRect(),getRangedRect:(t,o,n,r)=>{const s=bm.exact(t,o,n,r);return((e,t)=>(e=>{const t=e.getClientRects(),o=t.length>0?t[0]:e.getBoundingClientRect();return o.width>0||o.height>0?C.some(o).map(ai):C.none()})(di(e,t)))(e,s)},getSelection:()=>Nm(e).map((t=>gi(e,t))),fromSitus:t=>{const o=bm.relative(t.start,t.finish);return gi(e,o)},situsFromPoint:(t,o)=>((e,t,o)=>((e,t,o)=>{const n=xe.fromDom(e.document);return vm(n,t,o).map((e=>ui(xe.fromDom(e.startContainer),e.startOffset,xe.fromDom(e.endContainer),e.endOffset)))})(e,t,o))(e,t,o).map((e=>fi(e.start,e.soffset,e.finish,e.foffset))),clearSelection:()=>{(e=>{xm(e).each((e=>e.removeAllRanges()))})(e)},collapseSelection:(t=!1)=>{Nm(e).each((o=>o.fold((e=>e.collapse(t)),((o,n)=>{const r=t?o:n;Dm(e,r,r)}),((o,n,r,s)=>{const l=t?o:r,a=t?n:s;Rm(e,l,a,l,a)}))))},setSelection:t=>{Rm(e,t.start,t.soffset,t.finish,t.foffset)},setRelativeSelection:(t,o)=>{Dm(e,t,o)},selectNode:t=>{Em(e,t,!1)},selectContents:t=>{Em(e,t)},getInnerHeight:()=>e.innerHeight,getScrollY:()=>(e=>{const t=void 0!==e?e.dom:document,o=t.body.scrollLeft||t.documentElement.scrollLeft,n=t.body.scrollTop||t.documentElement.scrollTop;return bn(o,n)})(xe.fromDom(e.document)).top,scrollBy:(t,o)=>{((e,t,o)=>{const n=(void 0!==o?o.dom:document).defaultView;n&&n.scrollBy(e,t)})(t,o,xe.fromDom(e.document))}}),_m=(e,t)=>({rows:e,cols:t}),zm=e=>gt(e,ae).exists(Qr),Am=(e,t)=>zm(e)||zm(t),Lm=e=>void 0!==e.dom.classList,Wm=(e,t)=>((e,t,o)=>{const n=((e,t)=>{const o=pe(e,t);return void 0===o||""===o?[]:o.split(" ")})(e,t).concat([o]);return ge(e,t,n.join(" ")),!0})(e,"class",t),Mm=(e,t)=>{Lm(e)?e.dom.classList.add(t):Wm(e,t)},jm=(e,t)=>Lm(e)&&e.dom.classList.contains(t),Pm=()=>({tag:"none"}),Im=e=>({tag:"multiple",elements:e}),Fm=e=>({tag:"single",element:e}),Hm=e=>{const t=xe.fromDom((e=>{if(nt()&&m(e.target)){const t=xe.fromDom(e.target);if(ce(t)&&m(t.dom.shadowRoot)&&e.composed&&e.composedPath){const t=e.composedPath();if(t)return H(t)}}return C.from(e.target)})(e).getOr(e.target)),o=()=>e.stopPropagation(),n=()=>e.preventDefault(),r=(s=n,l=o,(...e)=>s(l.apply(null,e)));var s,l;return((e,t,o,n,r,s,l)=>({target:e,x:t,y:o,stop:n,prevent:r,kill:s,raw:l}))(t,e.clientX,e.clientY,o,n,r,e)},$m=(e,t,o,n)=>{e.dom.removeEventListener(t,o,n)},Vm=x,qm=(e,t,o)=>((e,t,o,n)=>((e,t,o,n,r)=>{const s=((e,t)=>o=>{e(o)&&t(Hm(o))})(o,n);return e.dom.addEventListener(t,s,r),{unbind:w($m,e,t,s,r)}})(e,t,o,n,!1))(e,t,Vm,o),Um=Hm,Gm=e=>!jm(xe.fromDom(e.target),"ephox-snooker-resizer-bar"),Km=(e,t)=>{const o=(r=As.selectedSelector,{get:()=>Rs(xe.fromDom(e.getBody()),r).fold((()=>js(os(e),es(e)).fold(Pm,Fm)),Im)}),n=((e,t,o)=>{const n=t=>{be(t,e.selected),be(t,e.firstSelected),be(t,e.lastSelected)},r=t=>{ge(t,e.selected,"1")},s=e=>{l(e),o()},l=t=>{const o=dt(t,`${e.selectedSelector},${e.firstSelectedSelector},${e.lastSelectedSelector}`);N(o,n)};return{clearBeforeUpdate:l,clear:s,selectRange:(o,n,l,a)=>{s(o),N(n,r),ge(l,e.firstSelected,"1"),ge(a,e.lastSelected,"1"),t(n,l,a)},selectedSelector:e.selectedSelector,firstSelectedSelector:e.firstSelectedSelector,lastSelectedSelector:e.lastSelectedSelector}})(As,((t,o,n)=>{Kt(o).each((r=>{const s=Wr(e),l=Br(f,xe.fromDom(e.getDoc()),s),a=((e,t,o)=>{const n=Zo(e);return Ol(n,t).map((e=>{const t=xl(n,o,!1),{rows:r}=qo(t),s=((e,t)=>{const o=e.slice(0,t[t.length-1].row+1),n=Cl(o);return j(n,(e=>{const o=e.cells.slice(0,t[t.length-1].column+1);return E(o,(e=>e.element))}))})(r,e),l=((e,t)=>{const o=e.slice(t[0].row+t[0].rowspan-1,e.length),n=Cl(o);return j(n,(e=>{const o=e.cells.slice(t[0].column+t[0].colspan-1,e.cells.length);return E(o,(e=>e.element))}))})(r,e);return{upOrLeftCells:s,downOrRightCells:l}}))})(r,{selection:Ps(e)},l);((e,t,o,n,r)=>{e.dispatch("TableSelectionChange",{cells:t,start:o,finish:n,otherCells:r})})(e,t,o,n,a)}))}),(()=>(e=>{e.dispatch("TableSelectionClear")})(e)));var r;return e.on("init",(o=>{const r=e.getWin(),s=Zr(e),l=es(e),a=((e,t,o,n)=>{const r=((e,t,o,n)=>{const r=lm(),s=r.clear,l=s=>{r.on((r=>{n.clearBeforeUpdate(t),am(s.target,o).each((l=>{xs(r,l,o).each((o=>{const r=o.boxes.getOr([]);if(1===r.length){const o=r[0],l="false"===Xr(o),a=vt(Jr(s.target),o,Re);l&&a&&(n.selectRange(t,r,o,o),e.selectContents(o))}else r.length>1&&(n.selectRange(t,r,o.start,o.finish),e.selectContents(l))}))}))}))};return{clearstate:s,mousedown:e=>{n.clear(t),am(e.target,o).filter(cm).each(r.set)},mouseover:e=>{l(e)},mouseup:e=>{l(e),s()}}})(Bm(e),t,o,n);return{clearstate:r.clearstate,mousedown:r.mousedown,mouseover:r.mouseover,mouseup:r.mouseup}})(r,s,l,n),c=((e,t,o,n)=>{const r=Bm(e),s=()=>(n.clear(t),C.none());return{keydown:(e,l,a,c,i,m)=>{const d=e.raw,u=d.which,f=!0===d.shiftKey,g=Cs(t,n.selectedSelector).fold((()=>(gm(u)&&!f&&n.clearBeforeUpdate(t),gm(u)&&f&&!Am(l,c)?C.none:fm(u)&&f?w(rm,r,t,o,im,c,l,n.selectRange):um(u)&&f?w(rm,r,t,o,mm,c,l,n.selectRange):fm(u)?w(tm,r,o,im,c,l,nm):um(u)?w(tm,r,o,mm,c,l,om):C.none)),(e=>{const o=o=>()=>{const s=V(o,(o=>((e,t,o,n,r)=>Ts(n,e,t,r.firstSelectedSelector,r.lastSelectedSelector).map((e=>(r.clearBeforeUpdate(o),r.selectRange(o,e.boxes,e.start,e.finish),e.boxes))))(o.rows,o.cols,t,e,n)));return s.fold((()=>Ss(t,n.firstSelectedSelector,n.lastSelectedSelector).map((e=>{const o=fm(u)||m.isForward(u)?ei.after:ei.before;return r.setRelativeSelection(ei.on(e.first,0),o(e.table)),n.clear(t),ti(C.none(),!0)}))),(e=>C.some(ti(C.none(),!0))))};return gm(u)&&f&&!Am(l,c)?C.none:fm(u)&&f?o([_m(1,0)]):um(u)&&f?o([_m(-1,0)]):m.isBackward(u)&&f?o([_m(0,-1),_m(-1,0)]):m.isForward(u)&&f?o([_m(0,1),_m(1,0)]):gm(u)&&!f?s:C.none}));return g()},keyup:(e,r,s,l,a)=>Cs(t,n.selectedSelector).fold((()=>{const c=e.raw,i=c.which;return!0===c.shiftKey&&gm(i)&&Am(r,l)?((e,t,o,n,r,s,l)=>Re(o,r)&&n===s?C.none():bt(o,"td,th",t).bind((o=>bt(r,"td,th",t).bind((n=>pi(e,t,o,n,l))))))(t,o,r,s,l,a,n.selectRange):C.none()}),C.none)}})(r,s,l,n),i=((e,t,o,n)=>{const r=Bm(e);return(e,s)=>{n.clearBeforeUpdate(t),xs(e,s,o).each((e=>{const o=e.boxes.getOr([]);n.selectRange(t,o,e.start,e.finish),r.selectContents(s),r.collapseSelection()}))}})(r,s,l,n);e.on("TableSelectorChange",(e=>i(e.start,e.finish)));const m=(t,o)=>{(e=>!0===e.raw.shiftKey)(t)&&(o.kill&&t.kill(),o.selection.each((t=>{const o=bm.relative(t.start,t.finish),n=di(r,o);e.selection.setRng(n)})))},d=e=>0===e.button,u=(()=>{const e=sm(xe.fromDom(s)),t=sm(0);return{touchEnd:o=>{const n=xe.fromDom(o.target);if(ue("td")(n)||ue("th")(n)){const r=e.get(),s=t.get();Re(r,n)&&o.timeStamp-s<300&&(o.preventDefault(),i(n,n))}e.set(n),t.set(o.timeStamp)}}})();e.on("dragstart",(e=>{a.clearstate()})),e.on("mousedown",(e=>{d(e)&&Gm(e)&&a.mousedown(Um(e))})),e.on("mouseover",(e=>{var t;void 0!==(t=e).buttons&&0==(1&t.buttons)||!Gm(e)||a.mouseover(Um(e))})),e.on("mouseup",(e=>{d(e)&&Gm(e)&&a.mouseup(Um(e))})),e.on("touchend",u.touchEnd),e.on("keyup",(t=>{const o=Um(t);if(o.raw.shiftKey&&gm(o.raw.which)){const t=e.selection.getRng(),n=xe.fromDom(t.startContainer),r=xe.fromDom(t.endContainer);c.keyup(o,n,t.startOffset,r,t.endOffset).each((e=>{m(o,e)}))}})),e.on("keydown",(o=>{const n=Um(o);t.hide();const r=e.selection.getRng(),s=xe.fromDom(r.startContainer),l=xe.fromDom(r.endContainer),a=un(hm,pm)(xe.fromDom(e.selection.getStart()));c.keydown(n,s,r.startOffset,l,r.endOffset,a).each((e=>{m(n,e)})),t.show()})),e.on("NodeChange",(()=>{const t=e.selection,o=xe.fromDom(t.getStart()),r=xe.fromDom(t.getEnd());vs(Kt,[o,r]).fold((()=>n.clear(s)),f)}))})),e.on("PreInit",(()=>{e.serializer.addTempAttr(As.firstSelected),e.serializer.addTempAttr(As.lastSelected)})),{getSelectedCells:()=>((e,t,o,n)=>{switch(e.tag){case"none":return t();case"single":return(e=>[e.dom])(e.element);case"multiple":return(e=>E(e,(e=>e.dom)))(e.elements)}})(o.get(),g([])),clearSelectedCells:e=>n.clear(xe.fromDom(e))}},Ym=e=>{let t=[];return{bind:e=>{if(void 0===e)throw new Error("Event bind error: undefined handler");t.push(e)},unbind:e=>{t=_(t,(t=>t!==e))},trigger:(...o)=>{const n={};N(e,((e,t)=>{n[e]=o[t]})),N(t,(e=>{e(n)}))}}},Jm=e=>({registry:K(e,(e=>({bind:e.bind,unbind:e.unbind}))),trigger:K(e,(e=>e.trigger))}),Qm=e=>e.slice(0).sort(),Xm=(e,t)=>{const o=_(t,(t=>!D(e,t)));o.length>0&&(e=>{throw new Error("Unsupported keys for object: "+Qm(e).join(", "))})(o)},Zm=e=>((e,t)=>((e,t,o)=>{if(0===t.length)throw new Error("You must specify at least one required field.");return((e,t)=>{if(!l(t))throw new Error("The "+e+" fields must be an array. Was: "+t+".");N(t,(t=>{if(!r(t))throw new Error("The value "+t+" in the "+e+" fields was not a string.")}))})("required",t),(e=>{const t=Qm(e);L(t,((e,o)=>o{throw new Error("The field: "+e+" occurs more than once in the combined fields: ["+t.join(", ")+"].")}))})(t),n=>{const r=q(n);P(t,(e=>D(r,e)))||((e,t)=>{throw new Error("All required keys ("+Qm(e).join(", ")+") were not specified. Specified keys were: "+Qm(t).join(", ")+".")})(t,r),e(t,r);const s=_(t,(e=>!o.validate(n[e],e)));return s.length>0&&((e,t)=>{throw new Error("All values need to be of type: "+t+". Keys ("+Qm(e).join(", ")+") were not.")})(s,o.label),n}})(e,t,{validate:d,label:"function"}))(Xm,e),ed=Zm(["compare","extract","mutate","sink"]),td=Zm(["element","start","stop","destroy"]),od=Zm(["forceDrop","drop","move","delayDrop"]),nd=()=>{const e=(()=>{const e=Jm({move:Ym(["info"])});return{onEvent:f,reset:f,events:e.registry}})(),t=(()=>{let e=C.none();const t=Jm({move:Ym(["info"])});return{onEvent:(o,n)=>{n.extract(o).each((o=>{const r=((t,o)=>{const n=e.map((e=>t.compare(e,o)));return e=C.some(o),n})(n,o);r.each((e=>{t.trigger.move(e)}))}))},reset:()=>{e=C.none()},events:t.registry}})();let o=e;return{on:()=>{o.reset(),o=t},off:()=>{o.reset(),o=e},isOn:()=>o===t,onEvent:(e,t)=>{o.onEvent(e,t)},events:t.events}},rd=e=>{const t=e.replace(/\./g,"-");return{resolve:e=>t+"-"+e}},sd=rd("ephox-dragster").resolve;var ld=ed({compare:(e,t)=>bn(t.left-e.left,t.top-e.top),extract:e=>C.some(bn(e.x,e.y)),sink:(e,t)=>{const o=(e=>{const t={layerClass:sd("blocker"),...e},o=xe.fromTag("div");return ge(o,"role","presentation"),Bt(o,{position:"fixed",left:"0px",top:"0px",width:"100%",height:"100%"}),Mm(o,sd("blocker")),Mm(o,t.layerClass),{element:g(o),destroy:()=>{qe(o)}}})(t),n=qm(o.element(),"mousedown",e.forceDrop),r=qm(o.element(),"mouseup",e.drop),s=qm(o.element(),"mousemove",e.move),l=qm(o.element(),"mouseout",e.delayDrop);return td({element:o.element,start:e=>{Ie(e,o.element())},stop:()=>{qe(o.element())},destroy:()=>{o.destroy(),r.unbind(),s.unbind(),l.unbind(),n.unbind()}})},mutate:(e,t)=>{e.mutate(t.left,t.top)}});const ad=rd("ephox-snooker").resolve,cd=ad("resizer-bar"),id=ad("resizer-rows"),md=ad("resizer-cols"),dd=e=>{const t=dt(e.parent(),"."+cd);N(t,qe)},ud=(e,t,o)=>{const n=e.origin();N(t,(t=>{t.each((t=>{const r=o(n,t);Mm(r,cd),Ie(e.parent(),r)}))}))},fd=(e,t,o,n,r)=>{const s=yn(o),l=t.isResizable,a=n.length>0?_n.positions(n,o):[],c=a.length>0?((e,t)=>j(e.all,((e,o)=>t(e.element)?[o]:[])))(e,l):[];((e,t,o,n)=>{ud(e,t,((e,t)=>{const r=((e,t,o,n,r)=>{const s=xe.fromTag("div");return Bt(s,{position:"absolute",left:t+"px",top:o-3.5+"px",height:"7px",width:n+"px"}),he(s,{"data-row":e,role:"presentation"}),s})(t.row,o.left-e.left,t.y-e.top,n);return Mm(r,id),r}))})(t,_(a,((e,t)=>O(c,(e=>t===e)))),s,Wo(o));const i=r.length>0?An.positions(r,o):[],m=i.length>0?((e,t)=>{const o=[];return k(e.grid.columns,(n=>{an(e,n).map((e=>e.element)).forall(t)&&o.push(n)})),_(o,(o=>{const n=nn(e,(e=>e.column===o));return P(n,(e=>t(e.element)))}))})(e,l):[];((e,t,o,n)=>{ud(e,t,((e,t)=>{const r=((e,t,o,n,r)=>{const s=xe.fromTag("div");return Bt(s,{position:"absolute",left:t-3.5+"px",top:o+"px",height:r+"px",width:"7px"}),he(s,{"data-column":e,role:"presentation"}),s})(t.col,t.x-e.left,o.top-e.top,0,n);return Mm(r,md),r}))})(t,_(i,((e,t)=>O(m,(e=>t===e)))),s,pn(o))},gd=(e,t)=>{if(dd(e),e.isResizable(t)){const o=Zo(t),n=dn(o),r=cn(o);fd(o,e,t,n,r)}},hd=(e,t)=>{const o=dt(e.parent(),"."+cd);N(o,t)},pd=e=>{hd(e,(e=>{Nt(e,"display","none")}))},wd=e=>{hd(e,(e=>{Nt(e,"display","block")}))},bd=ad("resizer-bar-dragging"),vd=e=>{const t=(()=>{const e=Jm({drag:Ym(["xDelta","yDelta","target"])});let t=C.none();const o=(()=>{const e=Jm({drag:Ym(["xDelta","yDelta"])});return{mutate:(t,o)=>{e.trigger.drag(t,o)},events:e.registry}})();return o.events.drag.bind((o=>{t.each((t=>{e.trigger.drag(o.xDelta,o.yDelta,t)}))})),{assign:e=>{t=C.some(e)},get:()=>t,mutate:o.mutate,events:e.registry}})(),o=((e,t={})=>{var o;return((e,t,o)=>{let n=!1;const r=Jm({start:Ym([]),stop:Ym([])}),s=nd(),l=()=>{m.stop(),s.isOn()&&(s.off(),r.trigger.stop())},c=((e,t)=>{let o=null;const n=()=>{a(o)||(clearTimeout(o),o=null)};return{cancel:n,throttle:(...t)=>{n(),o=setTimeout((()=>{o=null,e.apply(null,t)}),200)}}})(l);s.events.move.bind((o=>{t.mutate(e,o.info)}));const i=e=>(...t)=>{n&&e.apply(null,t)},m=t.sink(od({forceDrop:l,drop:i(l),move:i((e=>{c.cancel(),s.onEvent(e,t)})),delayDrop:i(c.throttle)}),o);return{element:m.element,go:e=>{m.start(e),s.on(),r.trigger.start()},on:()=>{n=!0},off:()=>{n=!1},isActive:()=>n,destroy:()=>{m.destroy()},events:r.registry}})(e,null!==(o=t.mode)&&void 0!==o?o:ld,t)})(t,{});let n=C.none();const r=(e,t)=>C.from(pe(e,t));t.events.drag.bind((e=>{r(e.target,"data-row").each((t=>{const o=It(e.target,"top");Nt(e.target,"top",o+e.yDelta+"px")})),r(e.target,"data-column").each((t=>{const o=It(e.target,"left");Nt(e.target,"left",o+e.xDelta+"px")}))}));const s=(e,t)=>It(e,t)-Wt(e,"data-initial-"+t,0);o.events.stop.bind((()=>{t.get().each((t=>{n.each((o=>{r(t,"data-row").each((e=>{const n=s(t,"top");be(t,"data-initial-top"),d.trigger.adjustHeight(o,n,parseInt(e,10))})),r(t,"data-column").each((e=>{const n=s(t,"left");be(t,"data-initial-left"),d.trigger.adjustWidth(o,n,parseInt(e,10))})),gd(e,o)}))}))}));const l=(n,r)=>{d.trigger.startAdjust(),t.assign(n),ge(n,"data-initial-"+r,It(n,r)),Mm(n,bd),Nt(n,"opacity","0.2"),o.go(e.parent())},c=qm(e.parent(),"mousedown",(e=>{var t;t=e.target,jm(t,id)&&l(e.target,"top"),(e=>jm(e,md))(e.target)&&l(e.target,"left")})),i=t=>Re(t,e.view()),m=qm(e.view(),"mouseover",(t=>{var r;(r=t.target,bt(r,"table",i).filter(Qr)).fold((()=>{lt(t.target)&&dd(e)}),(t=>{o.isActive()&&(n=C.some(t),gd(e,t))}))})),d=Jm({adjustHeight:Ym(["table","delta","row"]),adjustWidth:Ym(["table","delta","column"]),startAdjust:Ym([])});return{destroy:()=>{c.unbind(),m.unbind(),o.destroy(),dd(e)},refresh:t=>{gd(e,t)},on:o.on,off:o.off,hideBars:w(pd,e),showBars:w(wd,e),events:d.registry}},yd=(e,t,o)=>{const n=_n,r=An,s=vd(e),l=Jm({beforeResize:Ym(["table","type"]),afterResize:Ym(["table","type"]),startDrag:Ym([])});return s.events.adjustHeight.bind((e=>{const t=e.table;l.trigger.beforeResize(t,"row");((e,t,o,n)=>{const r=Zo(e),s=((e,t,o)=>lr(e,t,o,Yn,(e=>e.getOrThunk(Ht))))(r,e,n),l=E(s,((e,n)=>o===n?Math.max(t+e,Ht()):e)),a=oa(r,l),c=((e,t)=>E(e.all,((e,o)=>({element:e.element,height:t[o]}))))(r,l);N(c,(e=>{$n(e.element,e.height)})),N(a,(e=>{$n(e.element,e.height)}));const i=z(l,((e,t)=>e+t),0);$n(e,i)})(t,n.delta(e.delta,t),e.row,n),l.trigger.afterResize(t,"row")})),s.events.startAdjust.bind((e=>{l.trigger.startDrag()})),s.events.adjustWidth.bind((e=>{const n=e.table;l.trigger.beforeResize(n,"col");const s=r.delta(e.delta,n),a=o(n);ra(n,s,e.column,t,a),l.trigger.afterResize(n,"col")})),{on:s.on,off:s.off,refreshBars:s.refresh,hideBars:s.hideBars,showBars:s.showBars,destroy:s.destroy,events:l.registry}},xd=e=>m(e)&&"TABLE"===e.nodeName,Cd="bar-",Sd=e=>"false"!==pe(e,"data-mce-resize"),Td=e=>{const t=lm(),o=lm(),n=lm();let r,s;const l=t=>fc(e,t),a=()=>Pr(e)?el():Zs();return e.on("init",(()=>{const r=((e,t)=>e.inline?((e,t,o)=>({parent:g(t),view:g(e),origin:g(bn(0,0)),isResizable:o}))(xe.fromDom(e.getBody()),(()=>{const e=xe.fromTag("div");return Bt(e,{position:"static",height:"0",width:"0",padding:"0",margin:"0",border:"0"}),Ie(at(xe.fromDom(document)),e),e})(),t):((e,t)=>{const o=me(e)?(e=>xe.fromDom(Ee(e).dom.documentElement))(e):e;return{parent:g(o),view:g(e),origin:g(bn(0,0)),isResizable:t}})(xe.fromDom(e.getDoc()),t))(e,Sd);if(n.set(r),(e=>{const t=e.options.get("object_resizing");return D(t.split(","),"table")})(e)&&qr(e)){const n=a(),s=yd(r,n,l);s.on(),s.events.startDrag.bind((o=>{t.set(e.selection.getRng())})),s.events.beforeResize.bind((t=>{const o=t.table.dom;((e,t,o,n,r)=>{e.dispatch("ObjectResizeStart",{target:t,width:o,height:n,origin:r})})(e,o,ns(o),rs(o),Cd+t.type)})),s.events.afterResize.bind((o=>{const n=o.table,r=n.dom;ts(n),t.on((t=>{e.selection.setRng(t),e.focus()})),((e,t,o,n,r)=>{e.dispatch("ObjectResized",{target:t,width:o,height:n,origin:r})})(e,r,ns(r),rs(r),Cd+o.type),e.undoManager.add()})),o.set(s)}})),e.on("ObjectResizeStart",(t=>{const o=t.target;if(xd(o)){const n=xe.fromDom(o);N(e.dom.select(".mce-clonedresizable"),(t=>{e.dom.addClass(t,"mce-"+jr(e)+"-columns")})),!kc(n)&&$r(e)?_c(n):!Oc(n)&&Hr(e)&&Bc(n),Ec(n)&&Tt(t.origin,Cd)&&Bc(n),r=t.width,s=Vr(e)?"":((e,t)=>{const o=e.dom.getStyle(t,"width")||e.dom.getAttrib(t,"width");return C.from(o).filter(Ot)})(e,o).getOr("")}})),e.on("ObjectResized",(t=>{const o=t.target;if(xd(o)){const n=xe.fromDom(o),c=t.origin;Tt(c,"corner-")&&((t,o,n)=>{const c=Rt(o,"e");if(""===s&&Bc(t),n!==r&&""!==s){Nt(t,"width",s);const o=a(),i=l(t),m=Pr(e)||c?(e=>tl(e).columns)(t)-1:0;ra(t,n-r,m,o,i)}else if((e=>/^(\d+(\.\d+)?)%$/.test(e))(s)){const e=parseFloat(s.replace("%",""));Nt(t,"width",n*e/r+"%")}(e=>/^(\d+(\.\d+)?)px$/.test(e))(s)&&(e=>{const t=Zo(e);ln(t)||N(Ut(e),(e=>{const t=_t(e,"width");Nt(e,"width",t),be(e,"width")}))})(t)})(n,c,t.width),ts(n),ic(e,n.dom,mc)}})),e.on("SwitchMode",(()=>{o.on((t=>{e.mode.isReadOnly()?t.hideBars():t.showBars()}))})),e.on("dragstart dragend",(e=>{o.on((t=>{"dragstart"===e.type?(t.hideBars(),t.off()):(t.on(),t.showBars())}))})),e.on("remove",(()=>{o.on((e=>{e.destroy()})),n.on((t=>{((e,t)=>{e.inline&&qe(t.parent())})(e,t)}))})),{refresh:e=>{o.on((t=>t.refreshBars(xe.fromDom(e))))},hide:()=>{o.on((e=>e.hideBars()))},show:()=>{o.on((e=>e.showBars()))}}},Rd=e=>{(e=>{const t=e.options.register;t("table_clone_elements",{processor:"string[]"}),t("table_use_colgroups",{processor:"boolean",default:!0}),t("table_header_type",{processor:e=>{const t=D(["section","cells","sectionCells","auto"],e);return t?{value:e,valid:t}:{valid:!1,message:"Must be one of: section, cells, sectionCells or auto."}},default:"section"}),t("table_sizing_mode",{processor:"string",default:"auto"}),t("table_default_attributes",{processor:"object",default:{border:"1"}}),t("table_default_styles",{processor:"object",default:{"border-collapse":"collapse"}}),t("table_column_resizing",{processor:e=>{const t=D(["preservetable","resizetable"],e);return t?{value:e,valid:t}:{valid:!1,message:"Must be preservetable, or resizetable."}},default:"preservetable"}),t("table_resize_bars",{processor:"boolean",default:!0}),t("table_style_by_css",{processor:"boolean",default:!0}),t("table_merge_content_on_paste",{processor:"boolean",default:!0})})(e);const t=Td(e),o=Km(e,t),n=gc(e,t,o);return Xc(e,n),((e,t)=>{const o=es(e),n=t=>js(os(e)).bind((n=>Kt(n,o).map((o=>{const r=Ls(Ps(e),o,n);return t(o,r)})))).getOr("");G({mceTableRowType:()=>n(t.getTableRowType),mceTableCellType:()=>n(t.getTableCellType),mceTableColType:()=>n(t.getTableColType)},((t,o)=>e.addQueryValueHandler(o,t)))})(e,n),Is(e,n),{getSelectedCells:o.getSelectedCells,clearSelectedCells:o.clearSelectedCells}};e.add("dom",(e=>({table:Rd(e)})))}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/advlist/plugin.min.js b/public/libs/tinymce/plugins/advlist/plugin.min.js index c14d6635c..244b01974 100644 --- a/public/libs/tinymce/plugins/advlist/plugin.min.js +++ b/public/libs/tinymce/plugins/advlist/plugin.min.js @@ -1,4 +1,4 @@ /** - * TinyMCE version 6.5.1 (2023-06-19) + * TinyMCE version 6.7.2 (2023-10-25) */ !function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=(t,e,s)=>{const r="UL"===e?"InsertUnorderedList":"InsertOrderedList";t.execCommand(r,!1,!1===s?null:{"list-style-type":s})},s=t=>e=>e.options.get(t),r=s("advlist_number_styles"),n=s("advlist_bullet_styles"),i=t=>null==t,l=t=>!i(t);var o=tinymce.util.Tools.resolve("tinymce.util.Tools");class a{constructor(t,e){this.tag=t,this.value=e}static some(t){return new a(!0,t)}static none(){return a.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?a.some(t(this.value)):a.none()}bind(t){return this.tag?t(this.value):a.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:a.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return l(t)?a.some(t):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const u=t=>e=>l(e)&&t.test(e.nodeName),d=u(/^(OL|UL|DL)$/),g=u(/^(TH|TD)$/),c=t=>i(t)||"default"===t?"":t,h=(t,e)=>s=>((t,e)=>{const s=t.selection.getNode();return e({parents:t.dom.getParents(s),element:s}),t.on("NodeChange",e),()=>t.off("NodeChange",e)})(t,(r=>((t,r)=>{const n=t.selection.getStart(!0);s.setActive(((t,e,s)=>((t,e,s)=>{for(let e=0,n=t.length;ee.nodeName===s&&((t,e)=>t.dom.isChildOf(e,t.getBody()))(t,e))))(t,r,e)),s.setEnabled(!((t,e)=>{const s=t.dom.getParent(e,"ol,ul,dl");return((t,e)=>null!==e&&!t.dom.isEditable(e))(t,s)&&t.selection.isEditable()})(t,n)&&t.selection.isEditable())})(t,r.parents))),m=(t,s,r,n,i,l)=>{l.length>1?((t,s,r,n,i,l)=>{t.ui.registry.addSplitButton(s,{tooltip:r,icon:"OL"===i?"ordered-list":"unordered-list",presets:"listpreview",columns:3,fetch:t=>{t(o.map(l,(t=>{const e="OL"===i?"num":"bull",s="disc"===t||"decimal"===t?"default":t,r=c(t),n=(t=>t.replace(/\-/g," ").replace(/\b\w/g,(t=>t.toUpperCase())))(t);return{type:"choiceitem",value:r,icon:"list-"+e+"-"+s,text:n}})))},onAction:()=>t.execCommand(n),onItemAction:(s,r)=>{e(t,i,r)},select:e=>{const s=(t=>{const e=t.dom.getParent(t.selection.getNode(),"ol,ul"),s=t.dom.getStyle(e,"listStyleType");return a.from(s)})(t);return s.map((t=>e===t)).getOr(!1)},onSetup:h(t,i)})})(t,s,r,n,i,l):((t,s,r,n,i,l)=>{t.ui.registry.addToggleButton(s,{active:!1,tooltip:r,icon:"OL"===i?"ordered-list":"unordered-list",onSetup:h(t,i),onAction:()=>t.queryCommandState(n)||""===l?t.execCommand(n):e(t,i,l)})})(t,s,r,n,i,c(l[0]))};t.add("advlist",(t=>{t.hasPlugin("lists")?((t=>{const e=t.options.register;e("advlist_number_styles",{processor:"string[]",default:"default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman".split(",")}),e("advlist_bullet_styles",{processor:"string[]",default:"default,circle,square".split(",")})})(t),(t=>{m(t,"numlist","Numbered list","InsertOrderedList","OL",r(t)),m(t,"bullist","Bullet list","InsertUnorderedList","UL",n(t))})(t),(t=>{t.addCommand("ApplyUnorderedListStyle",((s,r)=>{e(t,"UL",r["list-style-type"])})),t.addCommand("ApplyOrderedListStyle",((s,r)=>{e(t,"OL",r["list-style-type"])}))})(t)):console.error("Please use the Lists plugin together with the Advanced List plugin.")}))}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/anchor/plugin.min.js b/public/libs/tinymce/plugins/anchor/plugin.min.js index 075af45c3..e1c650ff1 100644 --- a/public/libs/tinymce/plugins/anchor/plugin.min.js +++ b/public/libs/tinymce/plugins/anchor/plugin.min.js @@ -1,4 +1,4 @@ /** - * TinyMCE version 6.5.1 (2023-06-19) + * TinyMCE version 6.7.2 (2023-10-25) */ !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.dom.RangeUtils"),o=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=("allow_html_in_named_anchor",e=>e.options.get("allow_html_in_named_anchor"));const a="a:not([href])",r=e=>!e,i=e=>e.getAttribute("id")||e.getAttribute("name")||"",l=e=>(e=>"a"===e.nodeName.toLowerCase())(e)&&!e.getAttribute("href")&&""!==i(e),s=e=>e.dom.getParent(e.selection.getStart(),a),d=(e,a)=>{const r=s(e);r?((e,t,o)=>{o.removeAttribute("name"),o.id=t,e.addVisual(),e.undoManager.add()})(e,a,r):((e,a)=>{e.undoManager.transact((()=>{n(e)||e.selection.collapse(!0),e.selection.isCollapsed()?e.insertContent(e.dom.createHTML("a",{id:a})):((e=>{const n=e.dom;t(n).walk(e.selection.getRng(),(e=>{o.each(e,(e=>{var t;l(t=e)&&!t.firstChild&&n.remove(e,!1)}))}))})(e),e.formatter.remove("namedAnchor",void 0,void 0,!0),e.formatter.apply("namedAnchor",{value:a}),e.addVisual())}))})(e,a),e.focus()},c=e=>(e=>r(e.attr("href"))&&!r(e.attr("id")||e.attr("name")))(e)&&!e.firstChild,m=e=>t=>{for(let o=0;ot=>{const o=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",o),o(),()=>{e.off("NodeChange",o)}};e.add("anchor",(e=>{(e=>{(0,e.options.register)("allow_html_in_named_anchor",{processor:"boolean",default:!1})})(e),(e=>{e.on("PreInit",(()=>{e.parser.addNodeFilter("a",m("false")),e.serializer.addNodeFilter("a",m(null))}))})(e),(e=>{e.addCommand("mceAnchor",(()=>{(e=>{const t=(e=>{const t=s(e);return t?i(t):""})(e);e.windowManager.open({title:"Anchor",size:"normal",body:{type:"panel",items:[{name:"id",type:"input",label:"ID",placeholder:"example"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{id:t},onSubmit:t=>{((e,t)=>/^[A-Za-z][A-Za-z0-9\-:._]*$/.test(t)?(d(e,t),!0):(e.windowManager.alert("ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores."),!1))(e,t.getData().id)&&t.close()}})})(e)}))})(e),(e=>{const t=()=>e.execCommand("mceAnchor");e.ui.registry.addToggleButton("anchor",{icon:"bookmark",tooltip:"Anchor",onAction:t,onSetup:t=>{const o=e.selection.selectorChangedWithUnbind("a:not([href])",t.setActive).unbind,n=u(e)(t);return()=>{o(),n()}}}),e.ui.registry.addMenuItem("anchor",{icon:"bookmark",text:"Anchor...",onAction:t,onSetup:u(e)})})(e),e.on("PreInit",(()=>{(e=>{e.formatter.register("namedAnchor",{inline:"a",selector:a,remove:"all",split:!0,deep:!0,attributes:{id:"%value"},onmatch:(e,t,o)=>l(e)})})(e)}))}))}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/autolink/plugin.min.js b/public/libs/tinymce/plugins/autolink/plugin.min.js index bd176be4f..220664d5a 100644 --- a/public/libs/tinymce/plugins/autolink/plugin.min.js +++ b/public/libs/tinymce/plugins/autolink/plugin.min.js @@ -1,4 +1,4 @@ /** - * TinyMCE version 6.5.1 (2023-06-19) + * TinyMCE version 6.7.2 (2023-10-25) */ !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>t.options.get(e),n=t("autolink_pattern"),o=t("link_default_target"),r=t("link_default_protocol"),a=t("allow_unsafe_link_target"),s=("string",e=>"string"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=o=e,(r=String).prototype.isPrototypeOf(n)||(null===(a=o.constructor)||void 0===a?void 0:a.name)===r.name)?"string":t;var n,o,r,a})(e));const l=(void 0,e=>undefined===e);const i=e=>!(e=>null==e)(e),c=Object.hasOwnProperty,d=e=>"\ufeff"===e;var u=tinymce.util.Tools.resolve("tinymce.dom.TextSeeker");const f=e=>/^[(\[{ \u00a0]$/.test(e),g=(e,t,n)=>{for(let o=t-1;o>=0;o--){const t=e.charAt(o);if(!d(t)&&n(t))return o}return-1},m=(e,t)=>{var o;const a=e.schema.getVoidElements(),s=n(e),{dom:i,selection:d}=e;if(null!==i.getParent(d.getNode(),"a[href]"))return null;const m=d.getRng(),k=u(i,(e=>{return i.isBlock(e)||(t=a,n=e.nodeName.toLowerCase(),c.call(t,n))||"false"===i.getContentEditable(e);var t,n})),{container:p,offset:y}=((e,t)=>{let n=e,o=t;for(;1===n.nodeType&&n.childNodes[o];)n=n.childNodes[o],o=3===n.nodeType?n.data.length:n.childNodes.length;return{container:n,offset:o}})(m.endContainer,m.endOffset),w=null!==(o=i.getParent(p,i.isBlock))&&void 0!==o?o:i.getRoot(),h=k.backwards(p,y+t,((e,t)=>{const n=e.data,o=g(n,t,(r=f,e=>!r(e)));var r,a;return-1===o||(a=n[o],/[?!,.;:]/.test(a))?o:o+1}),w);if(!h)return null;let v=h.container;const _=k.backwards(h.container,h.offset,((e,t)=>{v=e;const n=g(e.data,t,f);return-1===n?n:n+1}),w),A=i.createRng();_?A.setStart(_.container,_.offset):A.setStart(v,0),A.setEnd(h.container,h.offset);const C=A.toString().replace(/\uFEFF/g,"").match(s);if(C){let t=C[0];return $="www.",(b=t).length>=4&&b.substr(0,4)===$?t=r(e)+"://"+t:((e,t,n=0,o)=>{const r=e.indexOf(t,n);return-1!==r&&(!!l(o)||r+t.length<=o)})(t,"@")&&!(e=>/^([A-Za-z][A-Za-z\d.+-]*:\/\/)|mailto:/.test(e))(t)&&(t="mailto:"+t),{rng:A,url:t}}var b,$;return null},k=(e,t)=>{const{dom:n,selection:r}=e,{rng:l,url:i}=t,c=r.getBookmark();r.setRng(l);const d="createlink",u={command:d,ui:!1,value:i};if(!e.dispatch("BeforeExecCommand",u).isDefaultPrevented()){e.getDoc().execCommand(d,!1,i),e.dispatch("ExecCommand",u);const t=o(e);if(s(t)){const o=r.getNode();n.setAttrib(o,"target",t),"_blank"!==t||a(e)||n.setAttrib(o,"rel","noopener")}}r.moveToBookmark(c),e.nodeChanged()},p=e=>{const t=m(e,-1);i(t)&&k(e,t)},y=p;e.add("autolink",(e=>{(e=>{const t=e.options.register;t("autolink_pattern",{processor:"regexp",default:new RegExp("^"+/(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)[A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*(?::\d+)?(?:\/(?:[-.~*+=!;:'%@$(),\/\w]*[-~*+=%@$()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?/g.source+"$","i")}),t("link_default_target",{processor:"string"}),t("link_default_protocol",{processor:"string",default:"https"})})(e),(e=>{e.on("keydown",(t=>{13!==t.keyCode||t.isDefaultPrevented()||(e=>{const t=m(e,0);i(t)&&k(e,t)})(e)})),e.on("keyup",(t=>{32===t.keyCode?p(e):(48===t.keyCode&&t.shiftKey||221===t.keyCode)&&y(e)}))})(e)}))}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/autoresize/plugin.min.js b/public/libs/tinymce/plugins/autoresize/plugin.min.js index c5e5ca891..0432684a4 100644 --- a/public/libs/tinymce/plugins/autoresize/plugin.min.js +++ b/public/libs/tinymce/plugins/autoresize/plugin.min.js @@ -1,4 +1,4 @@ /** - * TinyMCE version 6.5.1 (2023-06-19) + * TinyMCE version 6.7.2 (2023-10-25) */ !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.Env");const o=e=>t=>t.options.get(e),s=o("min_height"),i=o("max_height"),n=o("autoresize_overflow_padding"),r=o("autoresize_bottom_margin"),l=(e,t)=>{const o=e.getBody();o&&(o.style.overflowY=t?"":"hidden",t||(o.scrollTop=0))},g=(e,t,o,s)=>{var i;const n=parseInt(null!==(i=e.getStyle(t,o,s))&&void 0!==i?i:"",10);return isNaN(n)?0:n},a=(e,o,r,c)=>{var d;const f=e.dom,u=e.getDoc();if(!u)return;if((e=>e.plugins.fullscreen&&e.plugins.fullscreen.isFullscreen())(e))return void l(e,!0);const m=u.documentElement,h=c?c():n(e),p=null!==(d=s(e))&&void 0!==d?d:e.getElement().offsetHeight;let y=p;const S=g(f,m,"margin-top",!0),v=g(f,m,"margin-bottom",!0);let C=m.offsetHeight+S+v+h;C<0&&(C=0);const b=e.getContainer().offsetHeight-e.getContentAreaContainer().offsetHeight;C+b>p&&(y=C+b);const w=i(e);if(w&&y>w?(y=w,l(e,!0)):l(e,!1),y!==o.get()){const s=y-o.get();if(f.setStyle(e.getContainer(),"height",y+"px"),o.set(y),(e=>{e.dispatch("ResizeEditor")})(e),t.browser.isSafari()&&(t.os.isMacOS()||t.os.isiOS())){const t=e.getWin();t.scrollTo(t.pageXOffset,t.pageYOffset)}e.hasFocus()&&(e=>{if("setcontent"===(null==e?void 0:e.type.toLowerCase())){const t=e;return!0===t.selection||!0===t.paste}return!1})(r)&&e.selection.scrollIntoView(),(t.browser.isSafari()||t.browser.isChromium())&&s<0&&a(e,o,r,c)}};e.add("autoresize",(e=>{if((e=>{const t=e.options.register;t("autoresize_overflow_padding",{processor:"number",default:1}),t("autoresize_bottom_margin",{processor:"number",default:50})})(e),e.options.isSet("resize")||e.options.set("resize",!1),!e.inline){const o=(e=>{let t=0;return{get:()=>t,set:e=>{t=e}}})();((e,t)=>{e.addCommand("mceAutoResize",(()=>{a(e,t)}))})(e,o),((e,o)=>{let s,i,l=()=>r(e);e.on("init",(i=>{s=0;const r=n(e),g=e.dom;g.setStyles(e.getDoc().documentElement,{height:"auto"}),t.browser.isEdge()||t.browser.isIE()?g.setStyles(e.getBody(),{paddingLeft:r,paddingRight:r,"min-height":0}):g.setStyles(e.getBody(),{paddingLeft:r,paddingRight:r}),a(e,o,i,l),s+=1})),e.on("NodeChange SetContent keyup FullscreenStateChanged ResizeContent",(t=>{if(1===s)i=e.getContainer().offsetHeight,a(e,o,t,l),s+=1;else if(2===s){const t=i0):l,s+=1}else a(e,o,t,l)}))})(e,o)}}))}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/autosave/plugin.min.js b/public/libs/tinymce/plugins/autosave/plugin.min.js index 6acfa5e8a..362325ff7 100644 --- a/public/libs/tinymce/plugins/autosave/plugin.min.js +++ b/public/libs/tinymce/plugins/autosave/plugin.min.js @@ -1,4 +1,4 @@ /** - * TinyMCE version 6.5.1 (2023-06-19) + * TinyMCE version 6.7.2 (2023-10-25) */ !function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=("string",t=>"string"===(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(r=o=t,(a=String).prototype.isPrototypeOf(r)||(null===(s=o.constructor)||void 0===s?void 0:s.name)===a.name)?"string":e;var r,o,a,s})(t));const r=(void 0,t=>undefined===t);var o=tinymce.util.Tools.resolve("tinymce.util.Delay"),a=tinymce.util.Tools.resolve("tinymce.util.LocalStorage"),s=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=t=>{const e=/^(\d+)([ms]?)$/.exec(t);return(e&&e[2]?{s:1e3,m:6e4}[e[2]]:1)*parseInt(t,10)},i=t=>e=>e.options.get(t),u=i("autosave_ask_before_unload"),l=i("autosave_restore_when_empty"),c=i("autosave_interval"),d=i("autosave_retention"),m=t=>{const e=document.location;return t.options.get("autosave_prefix").replace(/{path}/g,e.pathname).replace(/{query}/g,e.search).replace(/{hash}/g,e.hash).replace(/{id}/g,t.id)},v=(t,e)=>{if(r(e))return t.dom.isEmpty(t.getBody());{const r=s.trim(e);if(""===r)return!0;{const e=(new DOMParser).parseFromString(r,"text/html");return t.dom.isEmpty(e)}}},f=t=>{var e;const r=parseInt(null!==(e=a.getItem(m(t)+"time"))&&void 0!==e?e:"0",10)||0;return!((new Date).getTime()-r>d(t)&&(p(t,!1),1))},p=(t,e)=>{const r=m(t);a.removeItem(r+"draft"),a.removeItem(r+"time"),!1!==e&&(t=>{t.dispatch("RemoveDraft")})(t)},g=t=>{const e=m(t);!v(t)&&t.isDirty()&&(a.setItem(e+"draft",t.getContent({format:"raw",no_events:!0})),a.setItem(e+"time",(new Date).getTime().toString()),(t=>{t.dispatch("StoreDraft")})(t))},y=t=>{var e;const r=m(t);f(t)&&(t.setContent(null!==(e=a.getItem(r+"draft"))&&void 0!==e?e:"",{format:"raw"}),(t=>{t.dispatch("RestoreDraft")})(t))};var D=tinymce.util.Tools.resolve("tinymce.EditorManager");const h=t=>e=>{e.setEnabled(f(t));const r=()=>e.setEnabled(f(t));return t.on("StoreDraft RestoreDraft RemoveDraft",r),()=>t.off("StoreDraft RestoreDraft RemoveDraft",r)};t.add("autosave",(t=>((t=>{const r=t.options.register,o=t=>{const r=e(t);return r?{value:n(t),valid:r}:{valid:!1,message:"Must be a string."}};r("autosave_ask_before_unload",{processor:"boolean",default:!0}),r("autosave_prefix",{processor:"string",default:"tinymce-autosave-{path}{query}{hash}-{id}-"}),r("autosave_restore_when_empty",{processor:"boolean",default:!1}),r("autosave_interval",{processor:o,default:"30s"}),r("autosave_retention",{processor:o,default:"20m"})})(t),(t=>{t.editorManager.on("BeforeUnload",(t=>{let e;s.each(D.get(),(t=>{t.plugins.autosave&&t.plugins.autosave.storeDraft(),!e&&t.isDirty()&&u(t)&&(e=t.translate("You have unsaved changes are you sure you want to navigate away?"))})),e&&(t.preventDefault(),t.returnValue=e)}))})(t),(t=>{(t=>{const e=c(t);o.setEditorInterval(t,(()=>{g(t)}),e)})(t);const e=()=>{(t=>{t.undoManager.transact((()=>{y(t),p(t)})),t.focus()})(t)};t.ui.registry.addButton("restoredraft",{tooltip:"Restore last draft",icon:"restore-draft",onAction:e,onSetup:h(t)}),t.ui.registry.addMenuItem("restoredraft",{text:"Restore last draft",icon:"restore-draft",onAction:e,onSetup:h(t)})})(t),t.on("init",(()=>{l(t)&&t.dom.isEmpty(t.getBody())&&y(t)})),(t=>({hasDraft:()=>f(t),storeDraft:()=>g(t),restoreDraft:()=>y(t),removeDraft:e=>p(t,e),isEmpty:e=>v(t,e)}))(t))))}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/charmap/plugin.min.js b/public/libs/tinymce/plugins/charmap/plugin.min.js index 520b1e817..9660ebd9e 100644 --- a/public/libs/tinymce/plugins/charmap/plugin.min.js +++ b/public/libs/tinymce/plugins/charmap/plugin.min.js @@ -1,4 +1,4 @@ /** - * TinyMCE version 6.5.1 (2023-06-19) + * TinyMCE version 6.7.2 (2023-10-25) */ !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=(e,t)=>{const r=((e,t)=>e.dispatch("insertCustomChar",{chr:t}))(e,t).chr;e.execCommand("mceInsertContent",!1,r)},r=e=>t=>e===t,a=("array",e=>"array"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(r=a=e,(n=String).prototype.isPrototypeOf(r)||(null===(i=a.constructor)||void 0===i?void 0:i.name)===n.name)?"string":t;var r,a,n,i})(e));const n=r(null),i=r(void 0),o=e=>"function"==typeof e,s=(!1,()=>false);class l{constructor(e,t){this.tag=e,this.value=t}static some(e){return new l(!0,e)}static none(){return l.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?l.some(e(this.value)):l.none()}bind(e){return this.tag?e(this.value):l.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:l.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return null==e?l.none():l.some(e)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}l.singletonNone=new l(!1);const c=Array.prototype.push,u=(e,t)=>{const r=e.length,a=new Array(r);for(let n=0;nt=>t.options.get(e),m=h("charmap"),p=h("charmap_append"),d=g.isArray,f="User Defined",y=e=>{return d(e)?(t=e,g.grep(t,(e=>d(e)&&2===e.length))):"function"==typeof e?e():[];var t},b=e=>{const t=((e,t)=>{const r=m(e);r&&(t=[{name:f,characters:y(r)}]);const a=p(e);if(a){const e=g.grep(t,(e=>e.name===f));return e.length?(e[0].characters=[...e[0].characters,...y(a)],t):t.concat({name:f,characters:y(a)})}return t})(e,[{name:"Currency",characters:[[36,"dollar sign"],[162,"cent sign"],[8364,"euro sign"],[163,"pound sign"],[165,"yen sign"],[164,"currency sign"],[8352,"euro-currency sign"],[8353,"colon sign"],[8354,"cruzeiro sign"],[8355,"french franc sign"],[8356,"lira sign"],[8357,"mill sign"],[8358,"naira sign"],[8359,"peseta sign"],[8360,"rupee sign"],[8361,"won sign"],[8362,"new sheqel sign"],[8363,"dong sign"],[8365,"kip sign"],[8366,"tugrik sign"],[8367,"drachma sign"],[8368,"german penny symbol"],[8369,"peso sign"],[8370,"guarani sign"],[8371,"austral sign"],[8372,"hryvnia sign"],[8373,"cedi sign"],[8374,"livre tournois sign"],[8375,"spesmilo sign"],[8376,"tenge sign"],[8377,"indian rupee sign"],[8378,"turkish lira sign"],[8379,"nordic mark sign"],[8380,"manat sign"],[8381,"ruble sign"],[20870,"yen character"],[20803,"yuan character"],[22291,"yuan character, in hong kong and taiwan"],[22278,"yen/yuan character variant one"]]},{name:"Text",characters:[[169,"copyright sign"],[174,"registered sign"],[8482,"trade mark sign"],[8240,"per mille sign"],[181,"micro sign"],[183,"middle dot"],[8226,"bullet"],[8230,"three dot leader"],[8242,"minutes / feet"],[8243,"seconds / inches"],[167,"section sign"],[182,"paragraph sign"],[223,"sharp s / ess-zed"]]},{name:"Quotations",characters:[[8249,"single left-pointing angle quotation mark"],[8250,"single right-pointing angle quotation mark"],[171,"left pointing guillemet"],[187,"right pointing guillemet"],[8216,"left single quotation mark"],[8217,"right single quotation mark"],[8220,"left double quotation mark"],[8221,"right double quotation mark"],[8218,"single low-9 quotation mark"],[8222,"double low-9 quotation mark"],[60,"less-than sign"],[62,"greater-than sign"],[8804,"less-than or equal to"],[8805,"greater-than or equal to"],[8211,"en dash"],[8212,"em dash"],[175,"macron"],[8254,"overline"],[164,"currency sign"],[166,"broken bar"],[168,"diaeresis"],[161,"inverted exclamation mark"],[191,"turned question mark"],[710,"circumflex accent"],[732,"small tilde"],[176,"degree sign"],[8722,"minus sign"],[177,"plus-minus sign"],[247,"division sign"],[8260,"fraction slash"],[215,"multiplication sign"],[185,"superscript one"],[178,"superscript two"],[179,"superscript three"],[188,"fraction one quarter"],[189,"fraction one half"],[190,"fraction three quarters"]]},{name:"Mathematical",characters:[[402,"function / florin"],[8747,"integral"],[8721,"n-ary sumation"],[8734,"infinity"],[8730,"square root"],[8764,"similar to"],[8773,"approximately equal to"],[8776,"almost equal to"],[8800,"not equal to"],[8801,"identical to"],[8712,"element of"],[8713,"not an element of"],[8715,"contains as member"],[8719,"n-ary product"],[8743,"logical and"],[8744,"logical or"],[172,"not sign"],[8745,"intersection"],[8746,"union"],[8706,"partial differential"],[8704,"for all"],[8707,"there exists"],[8709,"diameter"],[8711,"backward difference"],[8727,"asterisk operator"],[8733,"proportional to"],[8736,"angle"]]},{name:"Extended Latin",characters:[[192,"A - grave"],[193,"A - acute"],[194,"A - circumflex"],[195,"A - tilde"],[196,"A - diaeresis"],[197,"A - ring above"],[256,"A - macron"],[198,"ligature AE"],[199,"C - cedilla"],[200,"E - grave"],[201,"E - acute"],[202,"E - circumflex"],[203,"E - diaeresis"],[274,"E - macron"],[204,"I - grave"],[205,"I - acute"],[206,"I - circumflex"],[207,"I - diaeresis"],[298,"I - macron"],[208,"ETH"],[209,"N - tilde"],[210,"O - grave"],[211,"O - acute"],[212,"O - circumflex"],[213,"O - tilde"],[214,"O - diaeresis"],[216,"O - slash"],[332,"O - macron"],[338,"ligature OE"],[352,"S - caron"],[217,"U - grave"],[218,"U - acute"],[219,"U - circumflex"],[220,"U - diaeresis"],[362,"U - macron"],[221,"Y - acute"],[376,"Y - diaeresis"],[562,"Y - macron"],[222,"THORN"],[224,"a - grave"],[225,"a - acute"],[226,"a - circumflex"],[227,"a - tilde"],[228,"a - diaeresis"],[229,"a - ring above"],[257,"a - macron"],[230,"ligature ae"],[231,"c - cedilla"],[232,"e - grave"],[233,"e - acute"],[234,"e - circumflex"],[235,"e - diaeresis"],[275,"e - macron"],[236,"i - grave"],[237,"i - acute"],[238,"i - circumflex"],[239,"i - diaeresis"],[299,"i - macron"],[240,"eth"],[241,"n - tilde"],[242,"o - grave"],[243,"o - acute"],[244,"o - circumflex"],[245,"o - tilde"],[246,"o - diaeresis"],[248,"o slash"],[333,"o macron"],[339,"ligature oe"],[353,"s - caron"],[249,"u - grave"],[250,"u - acute"],[251,"u - circumflex"],[252,"u - diaeresis"],[363,"u - macron"],[253,"y - acute"],[254,"thorn"],[255,"y - diaeresis"],[563,"y - macron"],[913,"Alpha"],[914,"Beta"],[915,"Gamma"],[916,"Delta"],[917,"Epsilon"],[918,"Zeta"],[919,"Eta"],[920,"Theta"],[921,"Iota"],[922,"Kappa"],[923,"Lambda"],[924,"Mu"],[925,"Nu"],[926,"Xi"],[927,"Omicron"],[928,"Pi"],[929,"Rho"],[931,"Sigma"],[932,"Tau"],[933,"Upsilon"],[934,"Phi"],[935,"Chi"],[936,"Psi"],[937,"Omega"],[945,"alpha"],[946,"beta"],[947,"gamma"],[948,"delta"],[949,"epsilon"],[950,"zeta"],[951,"eta"],[952,"theta"],[953,"iota"],[954,"kappa"],[955,"lambda"],[956,"mu"],[957,"nu"],[958,"xi"],[959,"omicron"],[960,"pi"],[961,"rho"],[962,"final sigma"],[963,"sigma"],[964,"tau"],[965,"upsilon"],[966,"phi"],[967,"chi"],[968,"psi"],[969,"omega"]]},{name:"Symbols",characters:[[8501,"alef symbol"],[982,"pi symbol"],[8476,"real part symbol"],[978,"upsilon - hook symbol"],[8472,"Weierstrass p"],[8465,"imaginary part"]]},{name:"Arrows",characters:[[8592,"leftwards arrow"],[8593,"upwards arrow"],[8594,"rightwards arrow"],[8595,"downwards arrow"],[8596,"left right arrow"],[8629,"carriage return"],[8656,"leftwards double arrow"],[8657,"upwards double arrow"],[8658,"rightwards double arrow"],[8659,"downwards double arrow"],[8660,"left right double arrow"],[8756,"therefore"],[8834,"subset of"],[8835,"superset of"],[8836,"not a subset of"],[8838,"subset of or equal to"],[8839,"superset of or equal to"],[8853,"circled plus"],[8855,"circled times"],[8869,"perpendicular"],[8901,"dot operator"],[8968,"left ceiling"],[8969,"right ceiling"],[8970,"left floor"],[8971,"right floor"],[9001,"left-pointing angle bracket"],[9002,"right-pointing angle bracket"],[9674,"lozenge"],[9824,"black spade suit"],[9827,"black club suit"],[9829,"black heart suit"],[9830,"black diamond suit"],[8194,"en space"],[8195,"em space"],[8201,"thin space"],[8204,"zero width non-joiner"],[8205,"zero width joiner"],[8206,"left-to-right mark"],[8207,"right-to-left mark"]]}]);return t.length>1?[{name:"All",characters:(r=t,n=e=>e.characters,(e=>{const t=[];for(let r=0,n=e.length;r{let t=e;return{get:()=>t,set:e=>{t=e}}},v=(e,t,r=0,a)=>{const n=e.indexOf(t,r);return-1!==n&&(!!i(a)||n+t.length<=a)},k=String.fromCodePoint,C=(e,t)=>{const r=[],a=t.toLowerCase();return((e,t)=>{for(let t=0,i=e.length;t!!v(k(e).toLowerCase(),r)||v(t.toLowerCase(),r)||v(t.toLowerCase().replace(/\s+/g,""),r))((n=e[t])[0],n[1],a)&&r.push(n);var n})(e.characters),u(r,(e=>({text:e[1],value:k(e[0]),icon:k(e[0])})))},x="pattern",A=(e,r)=>{const a=()=>[{label:"Search",type:"input",name:x},{type:"collection",name:"results"}],i=1===r.length?w(f):w("All"),o=((e,t)=>{let r=null;const a=()=>{n(r)||(clearTimeout(r),r=null)};return{cancel:a,throttle:(...t)=>{a(),r=setTimeout((()=>{r=null,e.apply(null,t)}),40)}}})((e=>{const t=e.getData().pattern;((e,t)=>{var a,n;(a=r,n=e=>e.name===i.get(),((e,t,r)=>{for(let a=0,n=e.length;a{const a=C(r,t);e.setData({results:a})}))})(e,t)})),c={title:"Special Character",size:"normal",body:1===r.length?{type:"panel",items:a()}:{type:"tabpanel",tabs:u(r,(e=>({title:e.name,name:e.name,items:a()})))},buttons:[{type:"cancel",name:"close",text:"Close",primary:!0}],initialData:{pattern:"",results:C(r[0],"")},onAction:(r,a)=>{"results"===a.name&&(t(e,a.value),r.close())},onTabChange:(e,t)=>{i.set(t.newTabName),o.throttle(e)},onChange:(e,t)=>{t.name===x&&o.throttle(e)}};e.windowManager.open(c).focus(x)},q=e=>t=>{const r=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",r),r(),()=>{e.off("NodeChange",r)}};e.add("charmap",(e=>{(e=>{const t=e.options.register,r=e=>o(e)||a(e);t("charmap",{processor:r}),t("charmap_append",{processor:r})})(e);const r=b(e);return((e,t)=>{e.addCommand("mceShowCharmap",(()=>{A(e,t)}))})(e,r),(e=>{const t=()=>e.execCommand("mceShowCharmap");e.ui.registry.addButton("charmap",{icon:"insert-character",tooltip:"Special character",onAction:t,onSetup:q(e)}),e.ui.registry.addMenuItem("charmap",{icon:"insert-character",text:"Special character...",onAction:t,onSetup:q(e)})})(e),((e,t)=>{e.ui.registry.addAutocompleter("charmap",{trigger:":",columns:"auto",minChars:2,fetch:(e,r)=>new Promise(((r,a)=>{r(C(t,e))})),onAction:(t,r,a)=>{e.selection.setRng(r),e.insertContent(a),t.hide()}})})(e,r[0]),(e=>({getCharMap:()=>b(e),insertChar:r=>{t(e,r)}}))(e)}))}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/code/plugin.min.js b/public/libs/tinymce/plugins/code/plugin.min.js index edee77ec1..644eee54c 100644 --- a/public/libs/tinymce/plugins/code/plugin.min.js +++ b/public/libs/tinymce/plugins/code/plugin.min.js @@ -1,4 +1,4 @@ /** - * TinyMCE version 6.5.1 (2023-06-19) + * TinyMCE version 6.7.2 (2023-10-25) */ !function(){"use strict";tinymce.util.Tools.resolve("tinymce.PluginManager").add("code",(e=>((e=>{e.addCommand("mceCodeEditor",(()=>{(e=>{const o=(e=>e.getContent({source_view:!0}))(e);e.windowManager.open({title:"Source Code",size:"large",body:{type:"panel",items:[{type:"textarea",name:"code"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{code:o},onSubmit:o=>{((e,o)=>{e.focus(),e.undoManager.transact((()=>{e.setContent(o)})),e.selection.setCursorLocation(),e.nodeChanged()})(e,o.getData().code),o.close()}})})(e)}))})(e),(e=>{const o=()=>e.execCommand("mceCodeEditor");e.ui.registry.addButton("code",{icon:"sourcecode",tooltip:"Source code",onAction:o}),e.ui.registry.addMenuItem("code",{icon:"sourcecode",text:"Source code",onAction:o})})(e),{})))}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/codesample/plugin.min.js b/public/libs/tinymce/plugins/codesample/plugin.min.js index d89494717..71d3e4f26 100644 --- a/public/libs/tinymce/plugins/codesample/plugin.min.js +++ b/public/libs/tinymce/plugins/codesample/plugin.min.js @@ -1,4 +1,4 @@ /** - * TinyMCE version 6.5.1 (2023-06-19) + * TinyMCE version 6.7.2 (2023-10-25) */ !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>!(e=>null==e)(e),n=()=>{};class a{constructor(e,t){this.tag=e,this.value=t}static some(e){return new a(!0,e)}static none(){return a.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?a.some(e(this.value)):a.none()}bind(e){return this.tag?e(this.value):a.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:a.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return t(e)?a.some(e):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);var s=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils");const r="undefined"!=typeof window?window:Function("return this;")(),i=function(e,t,n){const a=window.Prism;window.Prism={manual:!0};var s=function(e){var t=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,n=0,a={},s={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(t){return t instanceof r?new r(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/=d.reach);x+=_.value.length,_=_.next){var F=_.value;if(t.length>e.length)return;if(!(F instanceof r)){var A,S=1;if(y){if(!(A=i(v,x,e,m))||A.index>=e.length)break;var $=A.index,z=A.index+A[0].length,E=x;for(E+=_.value.length;$>=E;)E+=(_=_.next).value.length;if(x=E-=_.value.length,_.value instanceof r)continue;for(var C=_;C!==t.tail&&(Ed.reach&&(d.reach=O);var P=_.prev;if(B&&(P=u(t,P,B),x+=B.length),c(t,P,S),_=u(t,P,new r(g,f?s.tokenize(j,f):j,w,j)),T&&u(t,_,T),S>1){var N={cause:g+","+b,reach:O};o(e,t,n,_.prev,x,N),d&&N.reach>d.reach&&(d.reach=N.reach)}}}}}}function l(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function u(e,t,n){var a=t.next,s={value:n,prev:t,next:a};return t.next=s,a.prev=s,e.length++,s}function c(e,t,n){for(var a=t.next,s=0;s"+r.content+""},!e.document)return e.addEventListener?(s.disableWorkerMessageHandler||e.addEventListener("message",(function(t){var n=JSON.parse(t.data),a=n.language,r=n.code,i=n.immediateClose;e.postMessage(s.highlight(r,s.languages[a],a)),i&&e.close()}),!1),s):s;var d=s.util.currentScript();function g(){s.manual||s.highlightAll()}if(d&&(s.filename=d.src,d.hasAttribute("data-manual")&&(s.manual=!0)),!s.manual){var p=document.readyState;"loading"===p||"interactive"===p&&d&&d.defer?document.addEventListener("DOMContentLoaded",g):window.requestAnimationFrame?window.requestAnimationFrame(g):window.setTimeout(g,16)}return s}("undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{});return s.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,a,s,r){if(n.language===a){var i=n.tokenStack=[];n.code=n.code.replace(s,(function(e){if("function"==typeof r&&!r(e))return e;for(var s,o=i.length;-1!==n.code.indexOf(s=t(a,o));)++o;return i[o]=e,s})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,a){if(n.language===a&&n.tokenStack){n.grammar=e.languages[a];var s=0,r=Object.keys(n.tokenStack);!function i(o){for(var l=0;l=r.length);l++){var u=o[l];if("string"==typeof u||u.content&&"string"==typeof u.content){var c=r[s],d=n.tokenStack[c],g="string"==typeof u?u:u.content,p=t(a,c),b=g.indexOf(p);if(b>-1){++s;var h=g.substring(0,b),f=new e.Token(a,e.tokenize(d,n.grammar),"language-"+a,d),m=g.substring(b+p.length),y=[];h&&y.push.apply(y,i([h])),y.push(f),m&&y.push.apply(y,i([m])),"string"==typeof u?o.splice.apply(o,[l,1].concat(y)):u.content=y}}else u.content&&i(u.content)}return o}(n.tokens)}}}})}(s),s.languages.c=s.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),s.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),s.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},s.languages.c.string],char:s.languages.c.char,comment:s.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:s.languages.c}}}}),s.languages.insertBefore("c","function",{constant:/\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/}),delete s.languages.c.boolean,function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n=/\b(?!)\w+(?:\s*\.\s*\w+)*\b/.source.replace(//g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!)\w+/.source.replace(//g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/(?:\s*:\s*)?|:\s*/.source.replace(//g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(s),function(e){function t(e,t){return e.replace(/<<(\d+)>>/g,(function(e,n){return"(?:"+t[+n]+")"}))}function n(e,n,a){return RegExp(t(e,n),a||"")}function a(e,t){for(var n=0;n>/g,(function(){return"(?:"+e+")"}));return e.replace(/<>/g,"[^\\s\\S]")}var s="bool byte char decimal double dynamic float int long object sbyte short string uint ulong ushort var void",r="class enum interface record struct",i="add alias and ascending async await by descending from(?=\\s*(?:\\w|$)) get global group into init(?=\\s*;) join let nameof not notnull on or orderby partial remove select set unmanaged value when where with(?=\\s*{)",o="abstract as base break case catch checked const continue default delegate do else event explicit extern finally fixed for foreach goto if implicit in internal is lock namespace new null operator out override params private protected public readonly ref return sealed sizeof stackalloc static switch this throw try typeof unchecked unsafe using virtual volatile while yield";function l(e){return"\\b(?:"+e.trim().replace(/ /g,"|")+")\\b"}var u=l(r),c=RegExp(l(s+" "+r+" "+i+" "+o)),d=l(r+" "+i+" "+o),g=l(s+" "+r+" "+o),p=a(/<(?:[^<>;=+\-*/%&|^]|<>)*>/.source,2),b=a(/\((?:[^()]|<>)*\)/.source,2),h=/@?\b[A-Za-z_]\w*\b/.source,f=t(/<<0>>(?:\s*<<1>>)?/.source,[h,p]),m=t(/(?!<<0>>)<<1>>(?:\s*\.\s*<<1>>)*/.source,[d,f]),y=/\[\s*(?:,\s*)*\]/.source,w=t(/<<0>>(?:\s*(?:\?\s*)?<<1>>)*(?:\s*\?)?/.source,[m,y]),k=t(/[^,()<>[\];=+\-*/%&|^]|<<0>>|<<1>>|<<2>>/.source,[p,b,y]),v=t(/\(<<0>>+(?:,<<0>>+)+\)/.source,[k]),_=t(/(?:<<0>>|<<1>>)(?:\s*(?:\?\s*)?<<2>>)*(?:\s*\?)?/.source,[v,m,y]),x={keyword:c,punctuation:/[<>()?,.:[\]]/},F=/'(?:[^\r\n'\\]|\\.|\\[Uux][\da-fA-F]{1,8})'/.source,A=/"(?:\\.|[^\\"\r\n])*"/.source,S=/@"(?:""|\\[\s\S]|[^\\"])*"(?!")/.source;e.languages.csharp=e.languages.extend("clike",{string:[{pattern:n(/(^|[^$\\])<<0>>/.source,[S]),lookbehind:!0,greedy:!0},{pattern:n(/(^|[^@$\\])<<0>>/.source,[A]),lookbehind:!0,greedy:!0}],"class-name":[{pattern:n(/(\busing\s+static\s+)<<0>>(?=\s*;)/.source,[m]),lookbehind:!0,inside:x},{pattern:n(/(\busing\s+<<0>>\s*=\s*)<<1>>(?=\s*;)/.source,[h,_]),lookbehind:!0,inside:x},{pattern:n(/(\busing\s+)<<0>>(?=\s*=)/.source,[h]),lookbehind:!0},{pattern:n(/(\b<<0>>\s+)<<1>>/.source,[u,f]),lookbehind:!0,inside:x},{pattern:n(/(\bcatch\s*\(\s*)<<0>>/.source,[m]),lookbehind:!0,inside:x},{pattern:n(/(\bwhere\s+)<<0>>/.source,[h]),lookbehind:!0},{pattern:n(/(\b(?:is(?:\s+not)?|as)\s+)<<0>>/.source,[w]),lookbehind:!0,inside:x},{pattern:n(/\b<<0>>(?=\s+(?!<<1>>|with\s*\{)<<2>>(?:\s*[=,;:{)\]]|\s+(?:in|when)\b))/.source,[_,g,h]),inside:x}],keyword:c,number:/(?:\b0(?:x[\da-f_]*[\da-f]|b[01_]*[01])|(?:\B\.\d+(?:_+\d+)*|\b\d+(?:_+\d+)*(?:\.\d+(?:_+\d+)*)?)(?:e[-+]?\d+(?:_+\d+)*)?)(?:[dflmu]|lu|ul)?\b/i,operator:/>>=?|<<=?|[-=]>|([-+&|])\1|~|\?\?=?|[-+*/%&|^!=<>]=?/,punctuation:/\?\.?|::|[{}[\];(),.:]/}),e.languages.insertBefore("csharp","number",{range:{pattern:/\.\./,alias:"operator"}}),e.languages.insertBefore("csharp","punctuation",{"named-parameter":{pattern:n(/([(,]\s*)<<0>>(?=\s*:)/.source,[h]),lookbehind:!0,alias:"punctuation"}}),e.languages.insertBefore("csharp","class-name",{namespace:{pattern:n(/(\b(?:namespace|using)\s+)<<0>>(?:\s*\.\s*<<0>>)*(?=\s*[;{])/.source,[h]),lookbehind:!0,inside:{punctuation:/\./}},"type-expression":{pattern:n(/(\b(?:default|sizeof|typeof)\s*\(\s*(?!\s))(?:[^()\s]|\s(?!\s)|<<0>>)*(?=\s*\))/.source,[b]),lookbehind:!0,alias:"class-name",inside:x},"return-type":{pattern:n(/<<0>>(?=\s+(?:<<1>>\s*(?:=>|[({]|\.\s*this\s*\[)|this\s*\[))/.source,[_,m]),inside:x,alias:"class-name"},"constructor-invocation":{pattern:n(/(\bnew\s+)<<0>>(?=\s*[[({])/.source,[_]),lookbehind:!0,inside:x,alias:"class-name"},"generic-method":{pattern:n(/<<0>>\s*<<1>>(?=\s*\()/.source,[h,p]),inside:{function:n(/^<<0>>/.source,[h]),generic:{pattern:RegExp(p),alias:"class-name",inside:x}}},"type-list":{pattern:n(/\b((?:<<0>>\s+<<1>>|record\s+<<1>>\s*<<5>>|where\s+<<2>>)\s*:\s*)(?:<<3>>|<<4>>|<<1>>\s*<<5>>|<<6>>)(?:\s*,\s*(?:<<3>>|<<4>>|<<6>>))*(?=\s*(?:where|[{;]|=>|$))/.source,[u,f,h,_,c.source,b,/\bnew\s*\(\s*\)/.source]),lookbehind:!0,inside:{"record-arguments":{pattern:n(/(^(?!new\s*\()<<0>>\s*)<<1>>/.source,[f,b]),lookbehind:!0,greedy:!0,inside:e.languages.csharp},keyword:c,"class-name":{pattern:RegExp(_),greedy:!0,inside:x},punctuation:/[,()]/}},preprocessor:{pattern:/(^[\t ]*)#.*/m,lookbehind:!0,alias:"property",inside:{directive:{pattern:/(#)\b(?:define|elif|else|endif|endregion|error|if|line|nullable|pragma|region|undef|warning)\b/,lookbehind:!0,alias:"keyword"}}}});var $=A+"|"+F,z=t(/\/(?![*/])|\/\/[^\r\n]*[\r\n]|\/\*(?:[^*]|\*(?!\/))*\*\/|<<0>>/.source,[$]),E=a(t(/[^"'/()]|<<0>>|\(<>*\)/.source,[z]),2),C=/\b(?:assembly|event|field|method|module|param|property|return|type)\b/.source,j=t(/<<0>>(?:\s*\(<<1>>*\))?/.source,[m,E]);e.languages.insertBefore("csharp","class-name",{attribute:{pattern:n(/((?:^|[^\s\w>)?])\s*\[\s*)(?:<<0>>\s*:\s*)?<<1>>(?:\s*,\s*<<1>>)*(?=\s*\])/.source,[C,j]),lookbehind:!0,greedy:!0,inside:{target:{pattern:n(/^<<0>>(?=\s*:)/.source,[C]),alias:"keyword"},"attribute-arguments":{pattern:n(/\(<<0>>*\)/.source,[E]),inside:e.languages.csharp},"class-name":{pattern:RegExp(m),inside:{punctuation:/\./}},punctuation:/[:,]/}}});var B=/:[^}\r\n]+/.source,T=a(t(/[^"'/()]|<<0>>|\(<>*\)/.source,[z]),2),O=t(/\{(?!\{)(?:(?![}:])<<0>>)*<<1>>?\}/.source,[T,B]),P=a(t(/[^"'/()]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|<<0>>|\(<>*\)/.source,[$]),2),N=t(/\{(?!\{)(?:(?![}:])<<0>>)*<<1>>?\}/.source,[P,B]);function R(t,a){return{interpolation:{pattern:n(/((?:^|[^{])(?:\{\{)*)<<0>>/.source,[t]),lookbehind:!0,inside:{"format-string":{pattern:n(/(^\{(?:(?![}:])<<0>>)*)<<1>>(?=\}$)/.source,[a,B]),lookbehind:!0,inside:{punctuation:/^:/}},punctuation:/^\{|\}$/,expression:{pattern:/[\s\S]+/,alias:"language-csharp",inside:e.languages.csharp}}},string:/[\s\S]+/}}e.languages.insertBefore("csharp","string",{"interpolation-string":[{pattern:n(/(^|[^\\])(?:\$@|@\$)"(?:""|\\[\s\S]|\{\{|<<0>>|[^\\{"])*"/.source,[O]),lookbehind:!0,greedy:!0,inside:R(O,T)},{pattern:n(/(^|[^@\\])\$"(?:\\.|\{\{|<<0>>|[^\\"{])*"/.source,[N]),lookbehind:!0,greedy:!0,inside:R(N,P)}],char:{pattern:RegExp(F),greedy:!0}}),e.languages.dotnet=e.languages.cs=e.languages.csharp}(s),function(e){var t=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:RegExp("@[\\w-](?:"+/[^;{\s"']|\s+(?!\s)/.source+"|"+t.source+")*?"+/(?:;|(?=\s*\{))/.source),inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+t.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:t,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var n=e.languages.markup;n&&(n.tag.addInlined("style","css"),n.tag.addAttribute("style","css"))}(s),function(e){var t=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record(?!\s*[(){}[\]<>=%~.:,;?+\-*/&|^])|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,n=/(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source,a={pattern:RegExp(/(^|[^\w.])/.source+n+/[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,inside:{punctuation:/\./}},punctuation:/\./}};e.languages.java=e.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"/,lookbehind:!0,greedy:!0},"class-name":[a,{pattern:RegExp(/(^|[^\w.])/.source+n+/[A-Z]\w*(?=\s+\w+\s*[;,=()]|\s*(?:\[[\s,]*\]\s*)?::\s*new\b)/.source),lookbehind:!0,inside:a.inside},{pattern:RegExp(/(\b(?:class|enum|extends|implements|instanceof|interface|new|record|throws)\s+)/.source+n+/[A-Z]\w*\b/.source),lookbehind:!0,inside:a.inside}],keyword:t,function:[e.languages.clike.function,{pattern:/(::\s*)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0},constant:/\b[A-Z][A-Z_\d]+\b/}),e.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"},char:{pattern:/'(?:\\.|[^'\\\r\n]){1,6}'/,greedy:!0}}),e.languages.insertBefore("java","class-name",{annotation:{pattern:/(^|[^.])@\w+(?:\s*\.\s*\w+)*/,lookbehind:!0,alias:"punctuation"},generics:{pattern:/<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,inside:{"class-name":a,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}},import:[{pattern:RegExp(/(\bimport\s+)/.source+n+/(?:[A-Z]\w*|\*)(?=\s*;)/.source),lookbehind:!0,inside:{namespace:a.inside.namespace,punctuation:/\./,operator:/\*/,"class-name":/\w+/}},{pattern:RegExp(/(\bimport\s+static\s+)/.source+n+/(?:\w+|\*)(?=\s*;)/.source),lookbehind:!0,alias:"static",inside:{namespace:a.inside.namespace,static:/\b\w+$/,punctuation:/\./,operator:/\*/,"class-name":/\w+/}}],namespace:{pattern:RegExp(/(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!)[a-z]\w*(?:\.[a-z]\w*)*\.?/.source.replace(//g,(function(){return t.source}))),lookbehind:!0,inside:{punctuation:/\./}}})}(s),s.languages.javascript=s.languages.extend("clike",{"class-name":[s.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),s.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,s.languages.insertBefore("javascript","keyword",{regex:{pattern:RegExp(/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source+/\//.source+"(?:"+/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source+"|"+/(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source+")"+/(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source),lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:s.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:s.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:s.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:s.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:s.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),s.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:s.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),s.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),s.languages.markup&&(s.languages.markup.tag.addInlined("script","javascript"),s.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),s.languages.js=s.languages.javascript,s.languages.markup={comment:{pattern://,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern://i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},s.languages.markup.tag.inside["attr-value"].inside.entity=s.languages.markup.entity,s.languages.markup.doctype.inside["internal-subset"].inside=s.languages.markup,s.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(s.languages.markup.tag,"addInlined",{value:function(e,t){var n={};n["language-"+t]={pattern:/(^$)/i,lookbehind:!0,inside:s.languages[t]},n.cdata=/^$/i;var a={"included-cdata":{pattern://i,inside:n}};a["language-"+t]={pattern:/[\s\S]+/,inside:s.languages[t]};var r={};r[e]={pattern:RegExp(/(<__[^>]*>)(?:))*\]\]>|(?!)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:a},s.languages.insertBefore("markup","cdata",r)}}),Object.defineProperty(s.languages.markup.tag,"addAttribute",{value:function(e,t){s.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[t,"language-"+t],inside:s.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),s.languages.html=s.languages.markup,s.languages.mathml=s.languages.markup,s.languages.svg=s.languages.markup,s.languages.xml=s.languages.extend("markup",{}),s.languages.ssml=s.languages.xml,s.languages.atom=s.languages.xml,s.languages.rss=s.languages.xml,function(e){var t=/\/\*[\s\S]*?\*\/|\/\/.*|#(?!\[).*/,n=[{pattern:/\b(?:false|true)\b/i,alias:"boolean"},{pattern:/(::\s*)\b[a-z_]\w*\b(?!\s*\()/i,greedy:!0,lookbehind:!0},{pattern:/(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i,greedy:!0,lookbehind:!0},/\b(?:null)\b/i,/\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/],a=/\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i,s=/|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/,r=/[{}\[\](),:;]/;e.languages.php={delimiter:{pattern:/\?>$|^<\?(?:php(?=\s)|=)?/i,alias:"important"},comment:t,variable:/\$+(?:\w+\b|(?=\{))/,package:{pattern:/(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,lookbehind:!0,inside:{punctuation:/\\/}},"class-name-definition":{pattern:/(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i,lookbehind:!0,alias:"class-name"},"function-definition":{pattern:/(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,lookbehind:!0,alias:"function"},keyword:[{pattern:/(\(\s*)\b(?:array|bool|boolean|float|int|integer|object|string)\b(?=\s*\))/i,alias:"type-casting",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string)\b(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|never|object|self|static|string|void)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/\b(?:array(?!\s*\()|bool|float|int|iterable|mixed|object|string|void)\b/i,alias:"type-declaration",greedy:!0},{pattern:/(\|\s*)(?:false|null)\b|\b(?:false|null)(?=\s*\|)/i,alias:"type-declaration",greedy:!0,lookbehind:!0},{pattern:/\b(?:parent|self|static)(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(\byield\s+)from\b/i,lookbehind:!0},/\bclass\b/i,{pattern:/((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|match|namespace|never|new|or|parent|print|private|protected|public|readonly|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield|__halt_compiler)\b/i,lookbehind:!0}],"argument-name":{pattern:/([(,]\s*)\b[a-z_]\w*(?=\s*:(?!:))/i,lookbehind:!0},"class-name":[{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/(\|\s*)\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i,greedy:!0},{pattern:/(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i,alias:"class-name-fully-qualified",greedy:!0,inside:{punctuation:/\\/}},{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*\$)/i,alias:"type-declaration",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-declaration"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*::)/i,alias:["class-name-fully-qualified","static-context"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/([(,?]\s*)[a-z_]\w*(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-hint"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:["class-name-fully-qualified","return-type"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:n,function:{pattern:/(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,lookbehind:!0,inside:{punctuation:/\\/}},property:{pattern:/(->\s*)\w+/,lookbehind:!0},number:a,operator:s,punctuation:r};var i={pattern:/\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,lookbehind:!0,inside:e.languages.php},o=[{pattern:/<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/,alias:"nowdoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<'?|[';]$/}}}},{pattern:/<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<"?|[";]$/}},interpolation:i}},{pattern:/`(?:\\[\s\S]|[^\\`])*`/,alias:"backtick-quoted-string",greedy:!0},{pattern:/'(?:\\[\s\S]|[^\\'])*'/,alias:"single-quoted-string",greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,alias:"double-quoted-string",greedy:!0,inside:{interpolation:i}}];e.languages.insertBefore("php","variable",{string:o,attribute:{pattern:/#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im,greedy:!0,inside:{"attribute-content":{pattern:/^(#\[)[\s\S]+(?=\]$)/,lookbehind:!0,inside:{comment:t,string:o,"attribute-class-name":[{pattern:/([^:]|^)\b[a-z_]\w*(?!\\)\b/i,alias:"class-name",greedy:!0,lookbehind:!0},{pattern:/([^:]|^)(?:\\?\b[a-z_]\w*)+/i,alias:["class-name","class-name-fully-qualified"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:n,number:a,operator:s,punctuation:r}},delimiter:{pattern:/^#\[|\]$/,alias:"punctuation"}}}}),e.hooks.add("before-tokenize",(function(t){/<\?/.test(t.code)&&e.languages["markup-templating"].buildPlaceholders(t,"php",/<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/g)})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"php")}))}(s),s.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},s.languages.python["string-interpolation"].inside.interpolation.inside.rest=s.languages.python,s.languages.py=s.languages.python,function(e){e.languages.ruby=e.languages.extend("clike",{comment:{pattern:/#.*|^=begin\s[\s\S]*?^=end/m,greedy:!0},"class-name":{pattern:/(\b(?:class|module)\s+|\bcatch\s+\()[\w.\\]+|\b[A-Z_]\w*(?=\s*\.\s*new\b)/,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:BEGIN|END|alias|and|begin|break|case|class|def|define_method|defined|do|each|else|elsif|end|ensure|extend|for|if|in|include|module|new|next|nil|not|or|prepend|private|protected|public|raise|redo|require|rescue|retry|return|self|super|then|throw|undef|unless|until|when|while|yield)\b/,operator:/\.{2,3}|&\.|===||[!=]?~|(?:&&|\|\||<<|>>|\*\*|[+\-*/%<>!^&|=])=?|[?:]/,punctuation:/[(){}[\].,;]/}),e.languages.insertBefore("ruby","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}});var t={pattern:/((?:^|[^\\])(?:\\{2})*)#\{(?:[^{}]|\{[^{}]*\})*\}/,lookbehind:!0,inside:{content:{pattern:/^(#\{)[\s\S]+(?=\}$)/,lookbehind:!0,inside:e.languages.ruby},delimiter:{pattern:/^#\{|\}$/,alias:"punctuation"}}};delete e.languages.ruby.function;var n="(?:"+[/([^a-zA-Z0-9\s{(\[<=])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source,/\((?:[^()\\]|\\[\s\S]|\((?:[^()\\]|\\[\s\S])*\))*\)/.source,/\{(?:[^{}\\]|\\[\s\S]|\{(?:[^{}\\]|\\[\s\S])*\})*\}/.source,/\[(?:[^\[\]\\]|\\[\s\S]|\[(?:[^\[\]\\]|\\[\s\S])*\])*\]/.source,/<(?:[^<>\\]|\\[\s\S]|<(?:[^<>\\]|\\[\s\S])*>)*>/.source].join("|")+")",a=/(?:"(?:\\.|[^"\\\r\n])*"|(?:\b[a-zA-Z_]\w*|[^\s\0-\x7F]+)[?!]?|\$.)/.source;e.languages.insertBefore("ruby","keyword",{"regex-literal":[{pattern:RegExp(/%r/.source+n+/[egimnosux]{0,6}/.source),greedy:!0,inside:{interpolation:t,regex:/[\s\S]+/}},{pattern:/(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[egimnosux]{0,6}(?=\s*(?:$|[\r\n,.;})#]))/,lookbehind:!0,greedy:!0,inside:{interpolation:t,regex:/[\s\S]+/}}],variable:/[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/,symbol:[{pattern:RegExp(/(^|[^:]):/.source+a),lookbehind:!0,greedy:!0},{pattern:RegExp(/([\r\n{(,][ \t]*)/.source+a+/(?=:(?!:))/.source),lookbehind:!0,greedy:!0}],"method-definition":{pattern:/(\bdef\s+)\w+(?:\s*\.\s*\w+)?/,lookbehind:!0,inside:{function:/\b\w+$/,keyword:/^self\b/,"class-name":/^\w+/,punctuation:/\./}}}),e.languages.insertBefore("ruby","string",{"string-literal":[{pattern:RegExp(/%[qQiIwWs]?/.source+n),greedy:!0,inside:{interpolation:t,string:/[\s\S]+/}},{pattern:/("|')(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|(?!\1)[^\\#\r\n])*\1/,greedy:!0,inside:{interpolation:t,string:/[\s\S]+/}},{pattern:/<<[-~]?([a-z_]\w*)[\r\n](?:.*[\r\n])*?[\t ]*\1/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<[-~]?[a-z_]\w*|\b[a-z_]\w*$/i,inside:{symbol:/\b\w+/,punctuation:/^<<[-~]?/}},interpolation:t,string:/[\s\S]+/}},{pattern:/<<[-~]?'([a-z_]\w*)'[\r\n](?:.*[\r\n])*?[\t ]*\1/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<[-~]?'[a-z_]\w*'|\b[a-z_]\w*$/i,inside:{symbol:/\b\w+/,punctuation:/^<<[-~]?'|'$/}},string:/[\s\S]+/}}],"command-literal":[{pattern:RegExp(/%x/.source+n),greedy:!0,inside:{interpolation:t,command:{pattern:/[\s\S]+/,alias:"string"}}},{pattern:/`(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|[^\\`#\r\n])*`/,greedy:!0,inside:{interpolation:t,command:{pattern:/[\s\S]+/,alias:"string"}}}]}),delete e.languages.ruby.string,e.languages.insertBefore("ruby","number",{builtin:/\b(?:Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Fixnum|Float|Hash|IO|Integer|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|Stat|String|Struct|Symbol|TMS|Thread|ThreadGroup|Time|TrueClass)\b/,constant:/\b[A-Z][A-Z0-9_]*(?:[?!]|\b)/}),e.languages.rb=e.languages.ruby}(s),window.Prism=a,s}(),o=e=>t=>t.options.get(e),l=o("codesample_languages"),u=o("codesample_global_prismjs"),c=e=>r.Prism&&u(e)?r.Prism:i,d=e=>t(e)&&"PRE"===e.nodeName&&-1!==e.className.indexOf("language-"),g=e=>{const t=e.selection?e.selection.getNode():null;return d(t)?a.some(t):a.none()},p=e=>{const t=(e=>l(e)||[{text:"HTML/XML",value:"markup"},{text:"JavaScript",value:"javascript"},{text:"CSS",value:"css"},{text:"PHP",value:"php"},{text:"Ruby",value:"ruby"},{text:"Python",value:"python"},{text:"Java",value:"java"},{text:"C",value:"c"},{text:"C#",value:"csharp"},{text:"C++",value:"cpp"}])(e),n=(r=t,((e,t)=>0""),(e=>e.value));var r;const i=((e,t)=>g(e).fold((()=>t),(e=>{const n=e.className.match(/language-(\w+)/);return n?n[1]:t})))(e,n),o=(e=>g(e).bind((e=>a.from(e.textContent))).getOr(""))(e);e.windowManager.open({title:"Insert/Edit Code Sample",size:"large",body:{type:"panel",items:[{type:"listbox",name:"language",label:"Language",items:t},{type:"textarea",name:"code",label:"Code view"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{language:i,code:o},onSubmit:t=>{const n=t.getData();((e,t,n)=>{const a=e.dom;e.undoManager.transact((()=>{const r=g(e);return n=s.DOM.encode(n),r.fold((()=>{e.insertContent('

'+n+"
");const s=a.select("#__new")[0];a.setAttrib(s,"id",null),e.selection.select(s)}),(s=>{a.setAttrib(s,"class","language-"+t),s.innerHTML=n,c(e).highlightElement(s),e.selection.select(s)}))}))})(e,n.language,n.code),t.close()}})},b=(h=/^\s+|\s+$/g,e=>e.replace(h,""));var h,f=tinymce.util.Tools.resolve("tinymce.util.Tools");const m=(e,t=n)=>n=>{const a=()=>{n.setEnabled(e.selection.isEditable()),t(n)};return e.on("NodeChange",a),a(),()=>{e.off("NodeChange",a)}};e.add("codesample",(e=>{(e=>{const t=e.options.register;t("codesample_languages",{processor:"object[]"}),t("codesample_global_prismjs",{processor:"boolean",default:!1})})(e),(e=>{e.on("PreProcess",(t=>{const n=e.dom,a=n.select("pre[contenteditable=false]",t.node);f.each(f.grep(a,d),(e=>{const t=e.textContent;let a;for(n.setAttrib(e,"class",b(n.getAttrib(e,"class"))),n.setAttrib(e,"contentEditable",null),n.setAttrib(e,"data-mce-highlighted",null);a=e.firstChild;)e.removeChild(a);n.add(e,"code").textContent=t}))})),e.on("SetContent",(()=>{const t=e.dom,n=f.grep(t.select("pre"),(e=>d(e)&&"true"!==t.getAttrib(e,"data-mce-highlighted")));n.length&&e.undoManager.transact((()=>{f.each(n,(n=>{var a;f.each(t.select("br",n),(n=>{t.replace(e.getDoc().createTextNode("\n"),n)})),n.innerHTML=t.encode(null!==(a=n.textContent)&&void 0!==a?a:""),c(e).highlightElement(n),t.setAttrib(n,"data-mce-highlighted",!0),n.className=b(n.className)}))}))})),e.on("PreInit",(()=>{e.parser.addNodeFilter("pre",(e=>{var t;for(let n=0,a=e.length;n{const t=()=>e.execCommand("codesample");e.ui.registry.addToggleButton("codesample",{icon:"code-sample",tooltip:"Insert/edit code sample",onAction:t,onSetup:m(e,(t=>{t.setActive((e=>{const t=e.selection.getStart();return e.dom.is(t,'pre[class*="language-"]')})(e))}))}),e.ui.registry.addMenuItem("codesample",{text:"Code sample...",icon:"code-sample",onAction:t,onSetup:m(e)})})(e),(e=>{e.addCommand("codesample",(()=>{const t=e.selection.getNode();e.selection.isCollapsed()||d(t)?p(e):e.formatter.toggle("code")}))})(e),e.on("dblclick",(t=>{d(t.target)&&p(e)}))}))}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/directionality/plugin.min.js b/public/libs/tinymce/plugins/directionality/plugin.min.js index 19dee3a51..d6a2eacef 100644 --- a/public/libs/tinymce/plugins/directionality/plugin.min.js +++ b/public/libs/tinymce/plugins/directionality/plugin.min.js @@ -1,4 +1,4 @@ /** - * TinyMCE version 6.5.1 (2023-06-19) + * TinyMCE version 6.7.2 (2023-10-25) */ !function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=t=>e=>typeof e===t,o=t=>"string"===(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(o=r=t,(n=String).prototype.isPrototypeOf(o)||(null===(i=r.constructor)||void 0===i?void 0:i.name)===n.name)?"string":e;var o,r,n,i})(t),r=e("boolean"),n=t=>!(t=>null==t)(t),i=e("function"),s=e("number"),l=(!1,()=>false);class a{constructor(t,e){this.tag=t,this.value=e}static some(t){return new a(!0,t)}static none(){return a.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?a.some(t(this.value)):a.none()}bind(t){return this.tag?t(this.value):a.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:a.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return n(t)?a.some(t):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const u=(t,e)=>{for(let o=0,r=t.length;o{if(null==t)throw new Error("Node cannot be null or undefined");return{dom:t}},d=c,h=(t,e)=>{const o=t.dom;if(1!==o.nodeType)return!1;{const t=o;if(void 0!==t.matches)return t.matches(e);if(void 0!==t.msMatchesSelector)return t.msMatchesSelector(e);if(void 0!==t.webkitMatchesSelector)return t.webkitMatchesSelector(e);if(void 0!==t.mozMatchesSelector)return t.mozMatchesSelector(e);throw new Error("Browser lacks native selectors")}};"undefined"!=typeof window?window:Function("return this;")();const m=t=>e=>(t=>t.dom.nodeType)(e)===t,g=m(1),f=m(3),v=m(9),y=m(11),p=(t,e)=>{t.dom.removeAttribute(e)},w=i(Element.prototype.attachShadow)&&i(Node.prototype.getRootNode)?t=>d(t.dom.getRootNode()):t=>v(t)?t:d(t.dom.ownerDocument),b=t=>d(t.dom.host),N=t=>{const e=f(t)?t.dom.parentNode:t.dom;if(null==e||null===e.ownerDocument)return!1;const o=e.ownerDocument;return(t=>{const e=w(t);return y(o=e)&&n(o.dom.host)?a.some(e):a.none();var o})(d(e)).fold((()=>o.body.contains(e)),(r=N,i=b,t=>r(i(t))));var r,i},S=t=>"rtl"===((t,e)=>{const o=t.dom,r=window.getComputedStyle(o).getPropertyValue(e);return""!==r||N(t)?r:((t,e)=>(t=>void 0!==t.style&&i(t.style.getPropertyValue))(t)?t.style.getPropertyValue(e):"")(o,e)})(t,"direction")?"rtl":"ltr",A=(t,e)=>((t,o)=>((t,e)=>{const o=[];for(let r=0,n=t.length;r{const o=t.length,r=new Array(o);for(let n=0;nh(t,e))))(t),E=("li",t=>g(t)&&"li"===t.dom.nodeName.toLowerCase());const T=(t,e,n)=>{u(e,(e=>{const c=d(e),m=E(c),f=((t,e)=>{return(e?(o=t,r="ol,ul",((t,e,o)=>{let n=t.dom;const s=i(o)?o:l;for(;n.parentNode;){n=n.parentNode;const t=d(n);if(h(t,r))return a.some(t);if(s(t))break}return a.none()})(o,0,n)):a.some(t)).getOr(t);var o,r,n})(c,m);var v;(v=f,(t=>a.from(t.dom.parentNode).map(d))(v).filter(g)).each((e=>{if(t.setStyle(f.dom,"direction",null),S(e)===n?p(f,"dir"):((t,e,n)=>{((t,e,n)=>{if(!(o(n)||r(n)||s(n)))throw console.error("Invalid call to Attribute.set. Key ",e,":: Value ",n,":: Element ",t),new Error("Attribute value was not simple");t.setAttribute(e,n+"")})(t.dom,e,n)})(f,"dir",n),S(f)!==n&&t.setStyle(f.dom,"direction",n),m){const e=A(f,"li[dir],li[style]");u(e,(e=>{p(e,"dir"),t.setStyle(e.dom,"direction",null)}))}}))}))},C=(t,e)=>{t.selection.isEditable()&&(T(t.dom,t.selection.getSelectedBlocks(),e),t.nodeChanged())},D=(t,e)=>o=>{const r=r=>{const n=d(r.element);o.setActive(S(n)===e),o.setEnabled(t.selection.isEditable())};return t.on("NodeChange",r),o.setEnabled(t.selection.isEditable()),()=>t.off("NodeChange",r)};t.add("directionality",(t=>{(t=>{t.addCommand("mceDirectionLTR",(()=>{C(t,"ltr")})),t.addCommand("mceDirectionRTL",(()=>{C(t,"rtl")}))})(t),(t=>{t.ui.registry.addToggleButton("ltr",{tooltip:"Left to right",icon:"ltr",onAction:()=>t.execCommand("mceDirectionLTR"),onSetup:D(t,"ltr")}),t.ui.registry.addToggleButton("rtl",{tooltip:"Right to left",icon:"rtl",onAction:()=>t.execCommand("mceDirectionRTL"),onSetup:D(t,"rtl")})})(t)}))}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/fullscreen/plugin.min.js b/public/libs/tinymce/plugins/fullscreen/plugin.min.js index e127e5097..f9cdcf986 100644 --- a/public/libs/tinymce/plugins/fullscreen/plugin.min.js +++ b/public/libs/tinymce/plugins/fullscreen/plugin.min.js @@ -1,4 +1,4 @@ /** - * TinyMCE version 6.5.1 (2023-06-19) + * TinyMCE version 6.7.2 (2023-10-25) */ !function(){"use strict";const e=e=>{let t=e;return{get:()=>t,set:e=>{t=e}}};var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const n=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=r=e,(o=String).prototype.isPrototypeOf(n)||(null===(s=r.constructor)||void 0===s?void 0:s.name)===o.name)?"string":t;var n,r,o,s})(t)===e,r=e=>t=>typeof t===e,o=e=>t=>e===t,s=n("string"),i=n("array"),l=o(null),a=r("boolean"),c=o(void 0),u=e=>!(e=>null==e)(e),d=r("function"),m=r("number"),h=()=>{},g=e=>()=>e;function p(e,...t){return(...n)=>{const r=t.concat(n);return e.apply(null,r)}}const f=g(!1),v=g(!0);class w{constructor(e,t){this.tag=e,this.value=t}static some(e){return new w(!0,e)}static none(){return w.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?w.some(e(this.value)):w.none()}bind(e){return this.tag?e(this.value):w.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:w.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return u(e)?w.some(e):w.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}w.singletonNone=new w(!1);const y=t=>{const n=e(w.none()),r=()=>n.get().each(t);return{clear:()=>{r(),n.set(w.none())},isSet:()=>n.get().isSome(),get:()=>n.get(),set:e=>{r(),n.set(w.some(e))}}},b=()=>y((e=>e.unbind())),S=Array.prototype.push,x=(e,t)=>{const n=e.length,r=new Array(n);for(let o=0;o{for(let n=0,r=e.length;n{const n=[];for(let r=0,o=e.length;r((e,t,n)=>{for(let r=0,o=e.length;r{const o=e.indexOf(t,n);return-1!==o&&(!!c(r)||o+t.length<=r)},C=e=>void 0!==e.style&&d(e.style.getPropertyValue),A=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},R=A;"undefined"!=typeof window?window:Function("return this;")();const L=e=>t=>(e=>e.dom.nodeType)(t)===e,M=L(1),N=L(3),P=L(9),D=L(11),W=(e,t)=>{const n=e.dom;if(1!==n.nodeType)return!1;{const e=n;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},q=e=>R(e.dom.ownerDocument),H=e=>x(e.dom.childNodes,R),I=d(Element.prototype.attachShadow)&&d(Node.prototype.getRootNode),B=g(I),V=I?e=>R(e.dom.getRootNode()):e=>P(e)?e:q(e),_=e=>{const t=V(e);return D(n=t)&&u(n.dom.host)?w.some(t):w.none();var n},j=e=>R(e.dom.host),z=e=>{const t=N(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const n=t.ownerDocument;return _(R(t)).fold((()=>n.body.contains(t)),(r=z,o=j,e=>r(o(e))));var r,o},$=(e,t)=>{const n=e.dom.getAttribute(t);return null===n?void 0:n},U=(e,t)=>{e.dom.removeAttribute(t)},K=(e,t)=>{const n=e.dom;((e,t)=>{const n=T(e);for(let r=0,o=n.length;r{((e,t,n)=>{if(!s(n))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",n,":: Element ",e),new Error("CSS value must be a string: "+n);C(e)&&e.style.setProperty(t,n)})(n,t,e)}))},X=e=>{const t=R((e=>{if(B()&&u(e.target)){const t=R(e.target);if(M(t)&&u(t.dom.shadowRoot)&&e.composed&&e.composedPath){const t=e.composedPath();if(t)return((e,t)=>0e.stopPropagation(),r=()=>e.preventDefault(),o=(s=r,i=n,(...e)=>s(i.apply(null,e)));var s,i;return((e,t,n,r,o,s,i)=>({target:e,x:t,y:n,stop:r,prevent:o,kill:s,raw:i}))(t,e.clientX,e.clientY,n,r,o,e)},Y=(e,t,n,r)=>{e.dom.removeEventListener(t,n,r)},G=v,J=(e,t,n)=>((e,t,n,r)=>((e,t,n,r,o)=>{const s=((e,t)=>n=>{e(n)&&t(X(n))})(n,r);return e.dom.addEventListener(t,s,o),{unbind:p(Y,e,t,s,o)}})(e,t,n,r,!1))(e,t,G,n),Q=()=>Z(0,0),Z=(e,t)=>({major:e,minor:t}),ee={nu:Z,detect:(e,t)=>{const n=String(t).toLowerCase();return 0===e.length?Q():((e,t)=>{const n=((e,t)=>{for(let n=0;nNumber(t.replace(n,"$"+e));return Z(r(1),r(2))})(e,n)},unknown:Q},te=(e,t)=>{const n=String(t).toLowerCase();return O(e,(e=>e.search(n)))},ne=/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,re=e=>t=>k(t,e),oe=[{name:"Edge",versionRegexes:[/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],search:e=>k(e,"edge/")&&k(e,"chrome")&&k(e,"safari")&&k(e,"applewebkit")},{name:"Chromium",brand:"Chromium",versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/,ne],search:e=>k(e,"chrome")&&!k(e,"chromeframe")},{name:"IE",versionRegexes:[/.*?msie\ ?([0-9]+)\.([0-9]+).*/,/.*?rv:([0-9]+)\.([0-9]+).*/],search:e=>k(e,"msie")||k(e,"trident")},{name:"Opera",versionRegexes:[ne,/.*?opera\/([0-9]+)\.([0-9]+).*/],search:re("opera")},{name:"Firefox",versionRegexes:[/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],search:re("firefox")},{name:"Safari",versionRegexes:[ne,/.*?cpu os ([0-9]+)_([0-9]+).*/],search:e=>(k(e,"safari")||k(e,"mobile/"))&&k(e,"applewebkit")}],se=[{name:"Windows",search:re("win"),versionRegexes:[/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]},{name:"iOS",search:e=>k(e,"iphone")||k(e,"ipad"),versionRegexes:[/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,/.*cpu os ([0-9]+)_([0-9]+).*/,/.*cpu iphone os ([0-9]+)_([0-9]+).*/]},{name:"Android",search:re("android"),versionRegexes:[/.*?android\ ?([0-9]+)\.([0-9]+).*/]},{name:"macOS",search:re("mac os x"),versionRegexes:[/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]},{name:"Linux",search:re("linux"),versionRegexes:[]},{name:"Solaris",search:re("sunos"),versionRegexes:[]},{name:"FreeBSD",search:re("freebsd"),versionRegexes:[]},{name:"ChromeOS",search:re("cros"),versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/]}],ie={browsers:g(oe),oses:g(se)},le="Edge",ae="Chromium",ce="Opera",ue="Firefox",de="Safari",me=e=>{const t=e.current,n=e.version,r=e=>()=>t===e;return{current:t,version:n,isEdge:r(le),isChromium:r(ae),isIE:r("IE"),isOpera:r(ce),isFirefox:r(ue),isSafari:r(de)}},he=()=>me({current:void 0,version:ee.unknown()}),ge=me,pe=(g(le),g(ae),g("IE"),g(ce),g(ue),g(de),"Windows"),fe="Android",ve="Linux",we="macOS",ye="Solaris",be="FreeBSD",Se="ChromeOS",xe=e=>{const t=e.current,n=e.version,r=e=>()=>t===e;return{current:t,version:n,isWindows:r(pe),isiOS:r("iOS"),isAndroid:r(fe),isMacOS:r(we),isLinux:r(ve),isSolaris:r(ye),isFreeBSD:r(be),isChromeOS:r(Se)}},Ee=()=>xe({current:void 0,version:ee.unknown()}),Fe=xe,Oe=(g(pe),g("iOS"),g(fe),g(ve),g(we),g(ye),g(be),g(Se),(e,t,n)=>{const r=ie.browsers(),o=ie.oses(),s=t.bind((e=>((e,t)=>((e,t)=>{for(let n=0;n{const n=t.brand.toLowerCase();return O(e,(e=>{var t;return n===(null===(t=e.brand)||void 0===t?void 0:t.toLowerCase())})).map((e=>({current:e.name,version:ee.nu(parseInt(t.version,10),0)})))})))(r,e))).orThunk((()=>((e,t)=>te(e,t).map((e=>{const n=ee.detect(e.versionRegexes,t);return{current:e.name,version:n}})))(r,e))).fold(he,ge),i=((e,t)=>te(e,t).map((e=>{const n=ee.detect(e.versionRegexes,t);return{current:e.name,version:n}})))(o,e).fold(Ee,Fe),l=((e,t,n,r)=>{const o=e.isiOS()&&!0===/ipad/i.test(n),s=e.isiOS()&&!o,i=e.isiOS()||e.isAndroid(),l=i||r("(pointer:coarse)"),a=o||!s&&i&&r("(min-device-width:768px)"),c=s||i&&!a,u=t.isSafari()&&e.isiOS()&&!1===/safari/i.test(n),d=!c&&!a&&!u;return{isiPad:g(o),isiPhone:g(s),isTablet:g(a),isPhone:g(c),isTouch:g(l),isAndroid:e.isAndroid,isiOS:e.isiOS,isWebView:g(u),isDesktop:g(d)}})(i,s,e,n);return{browser:s,os:i,deviceType:l}}),Te=e=>window.matchMedia(e).matches;let ke=(e=>{let t,n=!1;return(...r)=>(n||(n=!0,t=e.apply(null,r)),t)})((()=>Oe(navigator.userAgent,w.from(navigator.userAgentData),Te)));const Ce=(e,t)=>({left:e,top:t,translate:(n,r)=>Ce(e+n,t+r)}),Ae=Ce,Re=e=>{const t=void 0===e?window:e;return ke().browser.isFirefox()?w.none():w.from(t.visualViewport)},Le=(e,t,n,r)=>({x:e,y:t,width:n,height:r,right:e+n,bottom:t+r}),Me=e=>{const t=void 0===e?window:e,n=t.document,r=(e=>{const t=void 0!==e?e.dom:document,n=t.body.scrollLeft||t.documentElement.scrollLeft,r=t.body.scrollTop||t.documentElement.scrollTop;return Ae(n,r)})(R(n));return Re(t).fold((()=>{const e=t.document.documentElement,n=e.clientWidth,o=e.clientHeight;return Le(r.left,r.top,n,o)}),(e=>Le(Math.max(e.pageLeft,r.left),Math.max(e.pageTop,r.top),e.width,e.height)))},Ne=(e,t,n)=>Re(n).map((n=>{const r=e=>t(X(e));return n.addEventListener(e,r),{unbind:()=>n.removeEventListener(e,r)}})).getOrThunk((()=>({unbind:h})));var Pe=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),De=tinymce.util.Tools.resolve("tinymce.Env");const We=(e,t)=>{e.dispatch("FullscreenStateChanged",{state:t}),e.dispatch("ResizeEditor")},qe=("fullscreen_native",e=>e.options.get("fullscreen_native"));const He=e=>{return e.dom===(void 0!==(t=q(e).dom).fullscreenElement?t.fullscreenElement:void 0!==t.msFullscreenElement?t.msFullscreenElement:void 0!==t.webkitFullscreenElement?t.webkitFullscreenElement:null);var t},Ie=(e,t,n)=>((e,t,n)=>F(((e,t)=>{const n=d(t)?t:f;let r=e.dom;const o=[];for(;null!==r.parentNode&&void 0!==r.parentNode;){const e=r.parentNode,t=R(e);if(o.push(t),!0===n(t))break;r=e}return o})(e,n),t))(e,(e=>W(e,t)),n),Be=(e,t)=>((e,n)=>{return F((e=>w.from(e.dom.parentNode).map(R))(r=e).map(H).map((e=>F(e,(e=>{return t=e,!(r.dom===t.dom);var t})))).getOr([]),(e=>W(e,t)));var r})(e),Ve="data-ephox-mobile-fullscreen-style",_e="position:absolute!important;",je="top:0!important;left:0!important;margin:0!important;padding:0!important;width:100%!important;height:100%!important;overflow:visible!important;",ze=De.os.isAndroid(),$e=e=>{const t=((e,t)=>{const n=e.dom,r=window.getComputedStyle(n).getPropertyValue(t);return""!==r||z(e)?r:((e,t)=>C(e)?e.style.getPropertyValue(t):"")(n,t)})(e,"background-color");return void 0!==t&&""!==t?"background-color:"+t+"!important":"background-color:rgb(255,255,255)!important;"},Ue=Pe.DOM,Ke=Re().fold((()=>({bind:h,unbind:h})),(e=>{const t=(()=>{const e=y(h);return{...e,on:t=>e.get().each(t)}})(),n=b(),r=b(),o=((e,t)=>{let n=null;return{cancel:()=>{l(n)||(clearTimeout(n),n=null)},throttle:(...t)=>{l(n)&&(n=setTimeout((()=>{n=null,e.apply(null,t)}),50))}}})((()=>{document.body.scrollTop=0,document.documentElement.scrollTop=0,window.requestAnimationFrame((()=>{t.on((t=>K(t,{top:e.offsetTop+"px",left:e.offsetLeft+"px",height:e.height+"px",width:e.width+"px"})))}))}));return{bind:e=>{t.set(e),o.throttle(),n.set(Ne("resize",o.throttle)),r.set(Ne("scroll",o.throttle))},unbind:()=>{t.on((()=>{n.clear(),r.clear()})),t.clear()}}})),Xe=(e,t)=>{const n=document.body,r=document.documentElement,o=e.getContainer(),l=R(o),c=(e=>{const t=R(e.getElement());return _(t).map(j).getOrThunk((()=>(e=>{const t=e.dom.body;if(null==t)throw new Error("Body is not available yet");return R(t)})(q(t))))})(e),u=t.get(),d=R(e.getBody()),h=De.deviceType.isTouch(),g=o.style,p=e.iframeElement,f=null==p?void 0:p.style,v=e=>{e(n,"tox-fullscreen"),e(r,"tox-fullscreen"),e(o,"tox-fullscreen"),_(l).map((e=>j(e).dom)).each((t=>{e(t,"tox-fullscreen"),e(t,"tox-shadowhost")}))},y=()=>{h&&(e=>{const t=((e,t)=>{const n=document;return 1!==(r=n).nodeType&&9!==r.nodeType&&11!==r.nodeType||0===r.childElementCount?[]:x(n.querySelectorAll(e),R);var r})("["+Ve+"]");E(t,(t=>{const n=$(t,Ve);n&&"no-styles"!==n?K(t,e.parseStyle(n)):U(t,"style"),U(t,Ve)}))})(e.dom),v(Ue.removeClass),Ke.unbind(),w.from(t.get()).each((e=>e.fullscreenChangeHandler.unbind()))};if(u)u.fullscreenChangeHandler.unbind(),qe(e)&&He(c)&&(e=>{const t=e.dom;t.exitFullscreen?t.exitFullscreen():t.msExitFullscreen?t.msExitFullscreen():t.webkitCancelFullScreen&&t.webkitCancelFullScreen()})(q(c)),f.width=u.iframeWidth,f.height=u.iframeHeight,g.width=u.containerWidth,g.height=u.containerHeight,g.top=u.containerTop,g.left=u.containerLeft,y(),b=u.scrollPos,window.scrollTo(b.x,b.y),t.set(null),We(e,!1),e.off("remove",y);else{const n=J(q(c),void 0!==document.fullscreenElement?"fullscreenchange":void 0!==document.msFullscreenElement?"MSFullscreenChange":void 0!==document.webkitFullscreenElement?"webkitfullscreenchange":"fullscreenchange",(n=>{qe(e)&&(He(c)||null===t.get()||Xe(e,t))})),r={scrollPos:Me(window),containerWidth:g.width,containerHeight:g.height,containerTop:g.top,containerLeft:g.left,iframeWidth:f.width,iframeHeight:f.height,fullscreenChangeHandler:n};h&&((e,t,n)=>{const r=t=>n=>{const r=$(n,"style"),o=void 0===r?"no-styles":r.trim();o!==t&&(((e,t,n)=>{((e,t,n)=>{if(!(s(n)||a(n)||m(n)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",n,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,n+"")})(e.dom,t,n)})(n,Ve,o),K(n,e.parseStyle(t)))},o=Ie(t,"*"),l=(e=>{const t=[];for(let n=0,r=e.length;nBe(e,"*:not(.tox-silver-sink)")))),c=$e(n);E(l,r("display:none!important;")),E(o,r(_e+je+c)),r((!0===ze?"":_e)+je+c)(t)})(e.dom,l,d),f.width=f.height="100%",g.width=g.height="",v(Ue.addClass),Ke.bind(l),e.on("remove",y),t.set(r),qe(e)&&(e=>{const t=e.dom;t.requestFullscreen?t.requestFullscreen():t.msRequestFullscreen?t.msRequestFullscreen():t.webkitRequestFullScreen&&t.webkitRequestFullScreen()})(c),We(e,!0)}var b},Ye=(e,t)=>n=>{n.setActive(null!==t.get());const r=e=>n.setActive(e.state);return e.on("FullscreenStateChanged",r),()=>e.off("FullscreenStateChanged",r)};t.add("fullscreen",(t=>{const n=e(null);return t.inline||((e=>{(0,e.options.register)("fullscreen_native",{processor:"boolean",default:!1})})(t),((e,t)=>{e.addCommand("mceFullScreen",(()=>{Xe(e,t)}))})(t,n),((e,t)=>{const n=()=>e.execCommand("mceFullScreen");e.ui.registry.addToggleMenuItem("fullscreen",{text:"Fullscreen",icon:"fullscreen",shortcut:"Meta+Shift+F",onAction:n,onSetup:Ye(e,t)}),e.ui.registry.addToggleButton("fullscreen",{tooltip:"Fullscreen",icon:"fullscreen",onAction:n,onSetup:Ye(e,t)})})(t,n),t.addShortcut("Meta+Shift+F","","mceFullScreen")),(e=>({isFullscreen:()=>null!==e.get()}))(n)}))}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/help/plugin.min.js b/public/libs/tinymce/plugins/help/plugin.min.js deleted file mode 100644 index 1460eab37..000000000 --- a/public/libs/tinymce/plugins/help/plugin.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/** - * TinyMCE version 6.5.1 (2023-06-19) - */ -!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");let t=0;const n=e=>{const n=(new Date).getTime(),a=Math.floor(1e9*Math.random());return t++,e+"_"+a+t+String(n)},a=e=>t=>t.options.get(e),r=a("help_tabs"),o=a("forced_plugins"),i=("string",e=>"string"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=a=e,(r=String).prototype.isPrototypeOf(n)||(null===(o=a.constructor)||void 0===o?void 0:o.name)===r.name)?"string":t;var n,a,r,o})(e));const s=(void 0,e=>undefined===e);const c=e=>"function"==typeof e,l=(!1,()=>false);class m{constructor(e,t){this.tag=e,this.value=t}static some(e){return new m(!0,e)}static none(){return m.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?m.some(e(this.value)):m.none()}bind(e){return this.tag?e(this.value):m.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:m.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return null==e?m.none():m.some(e)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}m.singletonNone=new m(!1);const u=Array.prototype.slice,p=Array.prototype.indexOf,y=(e,t)=>{const n=e.length,a=new Array(n);for(let r=0;r{const n=[];for(let a=0,r=e.length;a{const n=u.call(e,0);return n.sort(t),n},g=Object.keys,k=Object.hasOwnProperty,v=(e,t)=>k.call(e,t);var b=tinymce.util.Tools.resolve("tinymce.Resource"),f=tinymce.util.Tools.resolve("tinymce.util.I18n");const A=(e,t)=>b.load(`tinymce.html-i18n.help-keynav.${t}`,`${e}/js/i18n/keynav/${t}.js`),C=e=>A(e,f.getCode()).catch((()=>A(e,"en")));var w=tinymce.util.Tools.resolve("tinymce.Env");const S=e=>{const t=w.os.isMacOS()||w.os.isiOS(),n=t?{alt:"⌥",ctrl:"⌃",shift:"⇧",meta:"⌘",access:"⌃⌥"}:{meta:"Ctrl ",access:"Shift + Alt "},a=e.split("+"),r=y(a,(e=>{const t=e.toLowerCase().trim();return v(n,t)?n[t]:e}));return t?r.join("").replace(/\s/,""):r.join("+")},M=[{shortcuts:["Meta + B"],action:"Bold"},{shortcuts:["Meta + I"],action:"Italic"},{shortcuts:["Meta + U"],action:"Underline"},{shortcuts:["Meta + A"],action:"Select all"},{shortcuts:["Meta + Y","Meta + Shift + Z"],action:"Redo"},{shortcuts:["Meta + Z"],action:"Undo"},{shortcuts:["Access + 1"],action:"Heading 1"},{shortcuts:["Access + 2"],action:"Heading 2"},{shortcuts:["Access + 3"],action:"Heading 3"},{shortcuts:["Access + 4"],action:"Heading 4"},{shortcuts:["Access + 5"],action:"Heading 5"},{shortcuts:["Access + 6"],action:"Heading 6"},{shortcuts:["Access + 7"],action:"Paragraph"},{shortcuts:["Access + 8"],action:"Div"},{shortcuts:["Access + 9"],action:"Address"},{shortcuts:["Alt + 0"],action:"Open help dialog"},{shortcuts:["Alt + F9"],action:"Focus to menubar"},{shortcuts:["Alt + F10"],action:"Focus to toolbar"},{shortcuts:["Alt + F11"],action:"Focus to element path"},{shortcuts:["Ctrl + F9"],action:"Focus to contextual toolbar"},{shortcuts:["Shift + Enter"],action:"Open popup menu for split buttons"},{shortcuts:["Meta + K"],action:"Insert link (if link plugin activated)"},{shortcuts:["Meta + S"],action:"Save (if save plugin activated)"},{shortcuts:["Meta + F"],action:"Find (if searchreplace plugin activated)"},{shortcuts:["Meta + Shift + F"],action:"Switch to or from fullscreen mode"}],T=()=>({name:"shortcuts",title:"Handy Shortcuts",items:[{type:"table",header:["Action","Shortcut"],cells:y(M,(e=>{const t=y(e.shortcuts,S).join(" or ");return[e.action,t]}))}]}),x=y([{key:"accordion",name:"Accordion"},{key:"advlist",name:"Advanced List"},{key:"anchor",name:"Anchor"},{key:"autolink",name:"Autolink"},{key:"autoresize",name:"Autoresize"},{key:"autosave",name:"Autosave"},{key:"charmap",name:"Character Map"},{key:"code",name:"Code"},{key:"codesample",name:"Code Sample"},{key:"colorpicker",name:"Color Picker"},{key:"directionality",name:"Directionality"},{key:"emoticons",name:"Emoticons"},{key:"fullscreen",name:"Full Screen"},{key:"help",name:"Help"},{key:"image",name:"Image"},{key:"importcss",name:"Import CSS"},{key:"insertdatetime",name:"Insert Date/Time"},{key:"link",name:"Link"},{key:"lists",name:"Lists"},{key:"media",name:"Media"},{key:"nonbreaking",name:"Nonbreaking"},{key:"pagebreak",name:"Page Break"},{key:"preview",name:"Preview"},{key:"quickbars",name:"Quick Toolbars"},{key:"save",name:"Save"},{key:"searchreplace",name:"Search and Replace"},{key:"table",name:"Table"},{key:"template",name:"Template"},{key:"textcolor",name:"Text Color"},{key:"visualblocks",name:"Visual Blocks"},{key:"visualchars",name:"Visual Characters"},{key:"wordcount",name:"Word Count"},{key:"a11ychecker",name:"Accessibility Checker",type:"premium"},{key:"advcode",name:"Advanced Code Editor",type:"premium"},{key:"advtable",name:"Advanced Tables",type:"premium"},{key:"advtemplate",name:"Advanced Templates",type:"premium",slug:"advanced-templates"},{key:"casechange",name:"Case Change",type:"premium"},{key:"checklist",name:"Checklist",type:"premium"},{key:"editimage",name:"Enhanced Image Editing",type:"premium"},{key:"footnotes",name:"Footnotes",type:"premium"},{key:"typography",name:"Advanced Typography",type:"premium",slug:"advanced-typography"},{key:"mediaembed",name:"Enhanced Media Embed",type:"premium",slug:"introduction-to-mediaembed"},{key:"export",name:"Export",type:"premium"},{key:"formatpainter",name:"Format Painter",type:"premium"},{key:"inlinecss",name:"Inline CSS",type:"premium",slug:"inline-css"},{key:"linkchecker",name:"Link Checker",type:"premium"},{key:"mentions",name:"Mentions",type:"premium"},{key:"mergetags",name:"Merge Tags",type:"premium"},{key:"pageembed",name:"Page Embed",type:"premium"},{key:"permanentpen",name:"Permanent Pen",type:"premium"},{key:"powerpaste",name:"PowerPaste",type:"premium",slug:"introduction-to-powerpaste"},{key:"rtc",name:"Real-Time Collaboration",type:"premium",slug:"rtc-introduction"},{key:"tinymcespellchecker",name:"Spell Checker Pro",type:"premium",slug:"introduction-to-tiny-spellchecker"},{key:"autocorrect",name:"Spelling Autocorrect",type:"premium"},{key:"tableofcontents",name:"Table of Contents",type:"premium"},{key:"tinycomments",name:"Tiny Comments",type:"premium",slug:"introduction-to-tiny-comments"},{key:"tinydrive",name:"Tiny Drive",type:"premium",slug:"tinydrive-introduction"}],(e=>({...e,type:e.type||"opensource",slug:e.slug||e.key}))),_=e=>{const t=e=>`${e.name}`,n=(e,n)=>{return(a=x,r=e=>e.key===n,((e,t,n)=>{for(let a=0,r=e.length;a((e,n)=>{const a=e.plugins[n].getMetadata;if(c(a)){const e=a();return{name:e.name,html:t(e)}}return{name:n,html:n}})(e,n)),(e=>{const n="premium"===e.type?`${e.name}*`:e.name;return{name:n,html:t({name:n,url:`https://www.tiny.cloud/docs/tinymce/6/${e.slug}/`})}}));var a,r},a=e=>{const t=(e=>{const t=g(e.plugins),n=o(e);return s(n)?t:h(t,(e=>!(((e,t)=>p.call(e,t))(n,e)>-1)))})(e),a=d(y(t,(t=>n(e,t))),((e,t)=>e.name.localeCompare(t.name))),r=y(a,(e=>"
  • "+e.html+"
  • ")),i=r.length,c=r.join("");return"

    "+f.translate(["Plugins installed ({0}):",i])+"

      "+c+"
    "},r={type:"htmlpanel",presets:"document",html:[(e=>null==e?"":'
    '+a(e)+"
    ")(e),(()=>{const e=h(x,(({type:e})=>"premium"===e)),t=d(y(e,(e=>e.name)),((e,t)=>e.localeCompare(t))),n=y(t,(e=>`
  • ${e}
  • `)).join("");return'

    '+f.translate("Premium plugins:")+"

    "})()].join("")};return{name:"plugins",title:"Plugins",items:[r]}};var O=tinymce.util.Tools.resolve("tinymce.EditorManager");const P=(e,t,a)=>()=>{(async(e,t,a)=>{const o=T(),s=await(async e=>({name:"keyboardnav",title:"Keyboard Navigation",items:[{type:"htmlpanel",presets:"document",html:await C(e)}]}))(a),c=_(e),l=(()=>{var e,t;const n='TinyMCE '+(e=O.majorVersion,t=O.minorVersion,(0===e.indexOf("@")?"X.X.X":e+"."+t)+"");return{name:"versions",title:"Version",items:[{type:"htmlpanel",html:"

    "+f.translate(["You are using {0}",n])+"

    ",presets:"document"}]}})(),u={[o.name]:o,[s.name]:s,[c.name]:c,[l.name]:l,...t.get()};return m.from(r(e)).fold((()=>(e=>{const t=g(e),n=t.indexOf("versions");return-1!==n&&(t.splice(n,1),t.push("versions")),{tabs:e,names:t}})(u)),(e=>((e,t)=>{const a={},r=y(e,(e=>{var r;if(i(e))return v(t,e)&&(a[e]=t[e]),e;{const t=null!==(r=e.name)&&void 0!==r?r:n("tab-name");return a[t]=e,t}}));return{tabs:a,names:r}})(e,u)))})(e,t,a).then((({tabs:t,names:n})=>{const a={type:"tabpanel",tabs:(e=>{const t=[],n=e=>{t.push(e)};for(let t=0;t{return v(n=t,a=e)?m.from(n[a]):m.none();var n,a})))};e.windowManager.open({title:"Help",size:"medium",body:a,buttons:[{type:"cancel",name:"close",text:"Close",primary:!0}],initialData:{}})}))};e.add("help",((e,t)=>{const a=(e=>{let t={};return{get:()=>t,set:e=>{t=e}}})(),r=(e=>({addTab:t=>{var a;const r=null!==(a=t.name)&&void 0!==a?a:n("tab-name"),o=e.get();o[r]=t,e.set(o)}}))(a);(e=>{(0,e.options.register)("help_tabs",{processor:"array"})})(e);const o=P(e,a,t);return((e,t)=>{e.ui.registry.addButton("help",{icon:"help",tooltip:"Help",onAction:t}),e.ui.registry.addMenuItem("help",{text:"Help",icon:"help",shortcut:"Alt+0",onAction:t})})(e,o),((e,t)=>{e.addCommand("mceHelp",t)})(e,o),e.shortcuts.add("Alt+0","Open help dialog","mceHelp"),((e,t)=>{e.on("init",(()=>{C(t)}))})(e,t),r}))}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/image/plugin.min.js b/public/libs/tinymce/plugins/image/plugin.min.js index aa8947304..905b47535 100644 --- a/public/libs/tinymce/plugins/image/plugin.min.js +++ b/public/libs/tinymce/plugins/image/plugin.min.js @@ -1,4 +1,4 @@ /** - * TinyMCE version 6.5.1 (2023-06-19) + * TinyMCE version 6.7.2 (2023-10-25) */ -!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=Object.getPrototypeOf,a=(e,t,a)=>{var i;return!!a(e,t.prototype)||(null===(i=e.constructor)||void 0===i?void 0:i.name)===t.name},i=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&a(e,String,((e,t)=>t.isPrototypeOf(e)))?"string":t})(t)===e,s=e=>t=>typeof t===e,r=i("string"),o=i("object"),n=e=>((e,i)=>o(e)&&a(e,i,((e,a)=>t(e)===a)))(e,Object),l=i("array"),c=(null,e=>null===e);const m=s("boolean"),d=e=>!(e=>null==e)(e),g=s("function"),u=s("number"),p=()=>{};class h{constructor(e,t){this.tag=e,this.value=t}static some(e){return new h(!0,e)}static none(){return h.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?h.some(e(this.value)):h.none()}bind(e){return this.tag?e(this.value):h.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:h.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return d(e)?h.some(e):h.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}h.singletonNone=new h(!1);const b=Object.keys,v=Object.hasOwnProperty,y=(e,t)=>v.call(e,t),f=Array.prototype.push,w=e=>{const t=[];for(let a=0,i=e.length;a{((e,t,a)=>{if(!(r(a)||m(a)||u(a)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",a,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,a+"")})(e.dom,t,a)},D=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},_=D;var C=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),I=tinymce.util.Tools.resolve("tinymce.util.URI");const U=e=>e.length>0,S=e=>t=>t.options.get(e),x=S("image_dimensions"),N=S("image_advtab"),T=S("image_uploadtab"),O=S("image_prepend_url"),E=S("image_class_list"),L=S("image_description"),j=S("image_title"),M=S("image_caption"),R=S("image_list"),k=S("a11y_advanced_options"),z=S("automatic_uploads"),P=(e,t)=>Math.max(parseInt(e,10),parseInt(t,10)),B=e=>(e&&(e=e.replace(/px$/,"")),e),F=e=>(e.length>0&&/^[0-9]+$/.test(e)&&(e+="px"),e),H=e=>"IMG"===e.nodeName&&(e.hasAttribute("data-mce-object")||e.hasAttribute("data-mce-placeholder")),G=(e,t)=>{const a=e.options.get;return I.isDomSafe(t,"img",{allow_html_data_urls:a("allow_html_data_urls"),allow_script_urls:a("allow_script_urls"),allow_svg_data_urls:a("allow_svg_data_urls")})},W=C.DOM,$=e=>e.style.marginLeft&&e.style.marginRight&&e.style.marginLeft===e.style.marginRight?B(e.style.marginLeft):"",V=e=>e.style.marginTop&&e.style.marginBottom&&e.style.marginTop===e.style.marginBottom?B(e.style.marginTop):"",K=e=>e.style.borderWidth?B(e.style.borderWidth):"",Z=(e,t)=>{var a;return e.hasAttribute(t)&&null!==(a=e.getAttribute(t))&&void 0!==a?a:""},q=e=>null!==e.parentNode&&"FIGURE"===e.parentNode.nodeName,J=(e,t,a)=>{""===a||null===a?e.removeAttribute(t):e.setAttribute(t,a)},Q=(e,t)=>{const a=e.getAttribute("style"),i=t(null!==a?a:"");i.length>0?(e.setAttribute("style",i),e.setAttribute("data-mce-style",i)):e.removeAttribute("style")},X=(e,t)=>(e,a,i)=>{const s=e.style;s[a]?(s[a]=F(i),Q(e,t)):J(e,a,i)},Y=(e,t)=>e.style[t]?B(e.style[t]):Z(e,t),ee=(e,t)=>{const a=F(t);e.style.marginLeft=a,e.style.marginRight=a},te=(e,t)=>{const a=F(t);e.style.marginTop=a,e.style.marginBottom=a},ae=(e,t)=>{const a=F(t);e.style.borderWidth=a},ie=(e,t)=>{e.style.borderStyle=t},se=e=>{var t;return null!==(t=e.style.borderStyle)&&void 0!==t?t:""},re=e=>d(e)&&"FIGURE"===e.nodeName,oe=e=>0===W.getAttrib(e,"alt").length&&"presentation"===W.getAttrib(e,"role"),ne=e=>oe(e)?"":Z(e,"alt"),le=(e,t)=>{var a;const i=document.createElement("img");return J(i,"style",t.style),($(i)||""!==t.hspace)&&ee(i,t.hspace),(V(i)||""!==t.vspace)&&te(i,t.vspace),(K(i)||""!==t.border)&&ae(i,t.border),(se(i)||""!==t.borderStyle)&&ie(i,t.borderStyle),e(null!==(a=i.getAttribute("style"))&&void 0!==a?a:"")},ce=(e,t)=>({src:Z(t,"src"),alt:ne(t),title:Z(t,"title"),width:Y(t,"width"),height:Y(t,"height"),class:Z(t,"class"),style:e(Z(t,"style")),caption:q(t),hspace:$(t),vspace:V(t),border:K(t),borderStyle:se(t),isDecorative:oe(t)}),me=(e,t,a,i,s)=>{a[i]!==t[i]&&s(e,i,String(a[i]))},de=(e,t,a)=>{if(a){W.setAttrib(e,"role","presentation");const t=_(e);A(t,"alt","")}else{if(c(t)){"alt",_(e).dom.removeAttribute("alt")}else{const a=_(e);A(a,"alt",t)}"presentation"===W.getAttrib(e,"role")&&W.setAttrib(e,"role","")}},ge=(e,t)=>(a,i,s)=>{e(a,s),Q(a,t)},ue=(e,t,a)=>{const i=ce(e,a);me(a,i,t,"caption",((e,t,a)=>(e=>{q(e)?(e=>{const t=e.parentNode;d(t)&&(W.insertAfter(e,t),W.remove(t))})(e):(e=>{const t=W.create("figure",{class:"image"});W.insertAfter(t,e),t.appendChild(e),t.appendChild(W.create("figcaption",{contentEditable:"true"},"Caption")),t.contentEditable="false"})(e)})(e))),me(a,i,t,"src",J),me(a,i,t,"title",J),me(a,i,t,"width",X(0,e)),me(a,i,t,"height",X(0,e)),me(a,i,t,"class",J),me(a,i,t,"style",ge(((e,t)=>J(e,"style",t)),e)),me(a,i,t,"hspace",ge(ee,e)),me(a,i,t,"vspace",ge(te,e)),me(a,i,t,"border",ge(ae,e)),me(a,i,t,"borderStyle",ge(ie,e)),((e,t,a)=>{a.alt===t.alt&&a.isDecorative===t.isDecorative||de(e,a.alt,a.isDecorative)})(a,i,t)},pe=(e,t)=>{const a=(e=>{if(e.margin){const t=String(e.margin).split(" ");switch(t.length){case 1:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[0],e["margin-bottom"]=e["margin-bottom"]||t[0],e["margin-left"]=e["margin-left"]||t[0];break;case 2:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[0],e["margin-left"]=e["margin-left"]||t[1];break;case 3:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[2],e["margin-left"]=e["margin-left"]||t[1];break;case 4:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[2],e["margin-left"]=e["margin-left"]||t[3]}delete e.margin}return e})(e.dom.styles.parse(t)),i=e.dom.styles.parse(e.dom.styles.serialize(a));return e.dom.styles.serialize(i)},he=e=>{const t=e.selection.getNode(),a=e.dom.getParent(t,"figure.image");return a?e.dom.select("img",a)[0]:t&&("IMG"!==t.nodeName||H(t))?null:t},be=(e,t)=>{var a;const i=e.dom,s=((t,a)=>{const i={};var s;return((e,t,a,i)=>{((e,t)=>{const a=b(e);for(let i=0,s=a.length;i{(t(e,s)?a:i)(e,s)}))})(t,((t,a)=>!e.schema.isValidChild(a,"figure")),(s=i,(e,t)=>{s[t]=e}),p),i})(e.schema.getTextBlockElements()),r=i.getParent(t.parentNode,(e=>{return t=s,a=e.nodeName,y(t,a)&&void 0!==t[a]&&null!==t[a];var t,a}),e.getBody());return r&&null!==(a=i.split(r,t))&&void 0!==a?a:t},ve=(e,t)=>{const a=((t,a)=>{const i=document.createElement("img");if(ue((t=>pe(e,t)),{...a,caption:!1},i),de(i,a.alt,a.isDecorative),a.caption){const e=W.create("figure",{class:"image"});return e.appendChild(i),e.appendChild(W.create("figcaption",{contentEditable:"true"},"Caption")),e.contentEditable="false",e}return i})(0,t);e.dom.setAttrib(a,"data-mce-id","__mcenew"),e.focus(),e.selection.setContent(a.outerHTML);const i=e.dom.select('*[data-mce-id="__mcenew"]')[0];if(e.dom.setAttrib(i,"data-mce-id",null),re(i)){const t=be(e,i);e.selection.select(t)}else e.selection.select(i)},ye=(e,t)=>{const a=he(e);if(a){const i={...ce((t=>pe(e,t)),a),...t},s=((e,t)=>{const a=t.src;return{...t,src:G(e,a)?a:""}})(e,i);i.src?((e,t)=>{const a=he(e);if(a)if(ue((t=>pe(e,t)),t,a),((e,t)=>{e.dom.setAttrib(t,"src",t.getAttribute("src"))})(e,a),re(a.parentNode)){const t=a.parentNode;be(e,t),e.selection.select(a.parentNode)}else e.selection.select(a),((e,t,a)=>{const i=()=>{a.onload=a.onerror=null,e.selection&&(e.selection.select(a),e.nodeChanged())};a.onload=()=>{t.width||t.height||!x(e)||e.dom.setAttribs(a,{width:String(a.clientWidth),height:String(a.clientHeight)}),i()},a.onerror=i})(e,t,a)})(e,s):((e,t)=>{if(t){const a=e.dom.is(t.parentNode,"figure.image")?t.parentNode:t;e.dom.remove(a),e.focus(),e.nodeChanged(),e.dom.isEmpty(e.getBody())&&(e.setContent(""),e.selection.setCursorLocation())}})(e,a)}else t.src&&ve(e,{src:"",alt:"",title:"",width:"",height:"",class:"",style:"",caption:!1,hspace:"",vspace:"",border:"",borderStyle:"",isDecorative:!1,...t})},fe=(we=(e,t)=>n(e)&&n(t)?fe(e,t):t,(...e)=>{if(0===e.length)throw new Error("Can't merge zero objects");const t={};for(let a=0;ar(e.value)?e.value:"",Ce=(e,t)=>{const a=[];return De.each(e,(e=>{const i=(e=>r(e.text)?e.text:r(e.title)?e.title:"")(e);if(void 0!==e.menu){const s=Ce(e.menu,t);a.push({text:i,items:s})}else{const s=t(e);a.push({text:i,value:s})}})),a},Ie=(e=_e)=>t=>t?h.from(t).map((t=>Ce(t,e))):h.none(),Ue=(e,t)=>((e,a)=>{for(let a=0;ay(e,"items"))(i=e[a])?Ue(i.items,t):i.value===t?h.some(i):h.none();if(s.isSome())return s}var i;return h.none()})(e),Se=Ie,xe=(e,t)=>e.bind((e=>Ue(e,t))),Ne=e=>{const t=Se((t=>e.convertURL(t.value||t.url||"","src"))),a=new Promise((a=>{((e,t)=>{const a=R(e);r(a)?fetch(a).then((e=>{e.ok&&e.json().then(t)})):g(a)?a(t):t(a)})(e,(e=>{a(t(e).map((e=>w([[{text:"None",value:""}],e]))))}))})),i=(A=E(e),Ie(_e)(A)),s=N(e),o=T(e),n=(e=>U(e.options.get("images_upload_url")))(e),l=(e=>d(e.options.get("images_upload_handler")))(e),c=(e=>{const t=he(e);return t?ce((t=>pe(e,t)),t):{src:"",alt:"",title:"",width:"",height:"",class:"",style:"",caption:!1,hspace:"",vspace:"",border:"",borderStyle:"",isDecorative:!1}})(e),m=L(e),u=j(e),p=x(e),b=M(e),v=k(e),y=z(e),f=h.some(O(e)).filter((e=>r(e)&&e.length>0));var A;return a.then((e=>({image:c,imageList:e,classList:i,hasAdvTab:s,hasUploadTab:o,hasUploadUrl:n,hasUploadHandler:l,hasDescription:m,hasImageTitle:u,hasDimensions:p,hasImageCaption:b,prependURL:f,hasAccessibilityOptions:v,automaticUploads:y})))},Te=e=>{const t=e.imageList.map((e=>({name:"images",type:"listbox",label:"Image list",items:e}))),a={name:"alt",type:"input",label:"Alternative description",enabled:!(e.hasAccessibilityOptions&&e.image.isDecorative)},i=e.classList.map((e=>({name:"classes",type:"listbox",label:"Class",items:e})));return w([[{name:"src",type:"urlinput",filetype:"image",label:"Source"}],t.toArray(),e.hasAccessibilityOptions&&e.hasDescription?[{type:"label",label:"Accessibility",items:[{name:"isDecorative",type:"checkbox",label:"Image is decorative"}]}]:[],e.hasDescription?[a]:[],e.hasImageTitle?[{name:"title",type:"input",label:"Image title"}]:[],e.hasDimensions?[{name:"dimensions",type:"sizeinput"}]:[],[{...(s=e.classList.isSome()&&e.hasImageCaption,s?{type:"grid",columns:2}:{type:"panel"}),items:w([i.toArray(),e.hasImageCaption?[{type:"label",label:"Caption",items:[{type:"checkbox",name:"caption",label:"Show caption"}]}]:[]])}]]);var s},Oe=e=>({title:"General",name:"general",items:Te(e)}),Ee=Te,Le=e=>({src:{value:e.src,meta:{}},images:e.src,alt:e.alt,title:e.title,dimensions:{width:e.width,height:e.height},classes:e.class,caption:e.caption,style:e.style,vspace:e.vspace,border:e.border,hspace:e.hspace,borderstyle:e.borderStyle,fileinput:[],isDecorative:e.isDecorative}),je=(e,t)=>({src:e.src.value,alt:null!==e.alt&&0!==e.alt.length||!t?e.alt:null,title:e.title,width:e.dimensions.width,height:e.dimensions.height,class:e.classes,style:e.style,caption:e.caption,hspace:e.hspace,vspace:e.vspace,border:e.border,borderStyle:e.borderstyle,isDecorative:e.isDecorative}),Me=(e,t,a,i)=>{((e,t)=>{const a=t.getData();((e,t)=>/^(?:[a-zA-Z]+:)?\/\//.test(t)?h.none():e.prependURL.bind((e=>t.substring(0,e.length)!==e?h.some(e+t):h.none())))(e,a.src.value).each((e=>{t.setData({src:{value:e,meta:a.src.meta}})}))})(t,i),((e,t)=>{const a=t.getData(),i=a.src.meta;if(void 0!==i){const s=fe({},a);((e,t,a)=>{e.hasDescription&&r(a.alt)&&(t.alt=a.alt),e.hasAccessibilityOptions&&(t.isDecorative=a.isDecorative||t.isDecorative||!1),e.hasImageTitle&&r(a.title)&&(t.title=a.title),e.hasDimensions&&(r(a.width)&&(t.dimensions.width=a.width),r(a.height)&&(t.dimensions.height=a.height)),r(a.class)&&xe(e.classList,a.class).each((e=>{t.classes=e.value})),e.hasImageCaption&&m(a.caption)&&(t.caption=a.caption),e.hasAdvTab&&(r(a.style)&&(t.style=a.style),r(a.vspace)&&(t.vspace=a.vspace),r(a.border)&&(t.border=a.border),r(a.hspace)&&(t.hspace=a.hspace),r(a.borderstyle)&&(t.borderstyle=a.borderstyle))})(e,s,i),t.setData(s)}})(t,i),((e,t,a,i)=>{const s=i.getData(),r=s.src.value,o=s.src.meta||{};o.width||o.height||!t.hasDimensions||(U(r)?e.imageSize(r).then((e=>{a.open&&i.setData({dimensions:e})})).catch((e=>console.error(e))):i.setData({dimensions:{width:"",height:""}}))})(e,t,a,i),((e,t,a)=>{const i=a.getData(),s=xe(e.imageList,i.src.value);t.prevImage=s,a.setData({images:s.map((e=>e.value)).getOr("")})})(t,a,i)},Re=(e,t,a,i)=>{const s=i.getData();var r;i.block("Uploading image"),(r=s.fileinput,((e,t)=>0{i.unblock()}),(s=>{const r=URL.createObjectURL(s),o=()=>{i.unblock(),URL.revokeObjectURL(r)},n=s=>{i.setData({src:{value:s,meta:{}}}),i.showTab("general"),Me(e,t,a,i)};var l;(l=s,new Promise(((e,t)=>{const a=new FileReader;a.onload=()=>{e(a.result)},a.onerror=()=>{var e;t(null===(e=a.error)||void 0===e?void 0:e.message)},a.readAsDataURL(l)}))).then((a=>{const l=e.createBlobCache(s,r,a);t.automaticUploads?e.uploadImage(l).then((e=>{n(e.url),o()})).catch((t=>{o(),e.alertErr(t)})):(e.addToBlobCache(l),n(l.blobUri()),i.unblock())}))}))},ke=(e,t,a)=>(i,s)=>{"src"===s.name?Me(e,t,a,i):"images"===s.name?((e,t,a,i)=>{const s=i.getData(),r=xe(t.imageList,s.images);r.each((e=>{const t=""===s.alt||a.prevImage.map((e=>e.text===s.alt)).getOr(!1);t?""===e.value?i.setData({src:e,alt:a.prevAlt}):i.setData({src:e,alt:e.text}):i.setData({src:e})})),a.prevImage=r,Me(e,t,a,i)})(e,t,a,i):"alt"===s.name?a.prevAlt=i.getData().alt:"fileinput"===s.name?Re(e,t,a,i):"isDecorative"===s.name&&i.setEnabled("alt",!i.getData().isDecorative)},ze=e=>()=>{e.open=!1},Pe=e=>e.hasAdvTab||e.hasUploadUrl||e.hasUploadHandler?{type:"tabpanel",tabs:w([[Oe(e)],e.hasAdvTab?[{title:"Advanced",name:"advanced",items:[{type:"grid",columns:2,items:[{type:"input",label:"Vertical space",name:"vspace",inputMode:"numeric"},{type:"input",label:"Horizontal space",name:"hspace",inputMode:"numeric"},{type:"input",label:"Border width",name:"border",inputMode:"numeric"},{type:"listbox",name:"borderstyle",label:"Border style",items:[{text:"Select...",value:""},{text:"Solid",value:"solid"},{text:"Dotted",value:"dotted"},{text:"Dashed",value:"dashed"},{text:"Double",value:"double"},{text:"Groove",value:"groove"},{text:"Ridge",value:"ridge"},{text:"Inset",value:"inset"},{text:"Outset",value:"outset"},{text:"None",value:"none"},{text:"Hidden",value:"hidden"}]}]}]}]:[],e.hasUploadTab&&(e.hasUploadUrl||e.hasUploadHandler)?[{title:"Upload",name:"upload",items:[{type:"dropzone",name:"fileinput"}]}]:[]])}:{type:"panel",items:Ee(e)},Be=(e,t,a)=>i=>{const s=fe(Le(t.image),i.getData()),r={...s,style:le(a.normalizeCss,je(s,!1))};e.execCommand("mceUpdateImage",!1,je(r,t.hasAccessibilityOptions)),e.editorUpload.uploadImagesAuto(),i.close()},Fe=e=>t=>G(e,t)?(e=>new Promise((t=>{const a=document.createElement("img"),i=e=>{a.onload=a.onerror=null,a.parentNode&&a.parentNode.removeChild(a),t(e)};a.onload=()=>{const e={width:P(a.width,a.clientWidth),height:P(a.height,a.clientHeight)};i(Promise.resolve(e))},a.onerror=()=>{i(Promise.reject(`Failed to get image dimensions for: ${e}`))};const s=a.style;s.visibility="hidden",s.position="fixed",s.bottom=s.left="0px",s.width=s.height="auto",document.body.appendChild(a),a.src=e})))(e.documentBaseURI.toAbsolute(t)).then((e=>({width:String(e.width),height:String(e.height)}))):Promise.resolve({width:"",height:""}),He=e=>(t,a,i)=>{var s;return e.editorUpload.blobCache.create({blob:t,blobUri:a,name:null===(s=t.name)||void 0===s?void 0:s.replace(/\.[^\.]+$/,""),filename:t.name,base64:i.split(",")[1]})},Ge=e=>t=>{e.editorUpload.blobCache.add(t)},We=e=>t=>{e.windowManager.alert(t)},$e=e=>t=>pe(e,t),Ve=e=>t=>e.dom.parseStyle(t),Ke=e=>(t,a)=>e.dom.serializeStyle(t,a),Ze=e=>t=>Ae(e).upload([t],!1).then((e=>{var t;return 0===e.length?Promise.reject("Failed to upload image"):!1===e[0].status?Promise.reject(null===(t=e[0].error)||void 0===t?void 0:t.message):e[0]})),qe=e=>{const t={imageSize:Fe(e),addToBlobCache:Ge(e),createBlobCache:He(e),alertErr:We(e),normalizeCss:$e(e),parseStyle:Ve(e),serializeStyle:Ke(e),uploadImage:Ze(e)};return{open:()=>{Ne(e).then((a=>{const i=(e=>({prevImage:xe(e.imageList,e.image.src),prevAlt:e.image.alt,open:!0}))(a);return{title:"Insert/Edit Image",size:"normal",body:Pe(a),buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:Le(a.image),onSubmit:Be(e,a,t),onChange:ke(t,a,i),onClose:ze(i)}})).then(e.windowManager.open)}}},Je=e=>{const t=e.attr("class");return d(t)&&/\bimage\b/.test(t)},Qe=e=>t=>{let a=t.length;const i=t=>{t.attr("contenteditable",e?"true":null)};for(;a--;){const s=t[a];Je(s)&&(s.attr("contenteditable",e?"false":null),De.each(s.getAll("figcaption"),i))}},Xe=e=>t=>{const a=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",a),a(),()=>{e.off("NodeChange",a)}};e.add("image",(e=>{(e=>{const t=e.options.register;t("image_dimensions",{processor:"boolean",default:!0}),t("image_advtab",{processor:"boolean",default:!1}),t("image_uploadtab",{processor:"boolean",default:!0}),t("image_prepend_url",{processor:"string",default:""}),t("image_class_list",{processor:"object[]"}),t("image_description",{processor:"boolean",default:!0}),t("image_title",{processor:"boolean",default:!1}),t("image_caption",{processor:"boolean",default:!1}),t("image_list",{processor:e=>{const t=!1===e||r(e)||((e,t)=>{if(l(e)){for(let a=0,i=e.length;a{e.on("PreInit",(()=>{e.parser.addNodeFilter("figure",Qe(!0)),e.serializer.addNodeFilter("figure",Qe(!1))}))})(e),(e=>{e.ui.registry.addToggleButton("image",{icon:"image",tooltip:"Insert/edit image",onAction:qe(e).open,onSetup:t=>{t.setActive(d(he(e)));const a=e.selection.selectorChangedWithUnbind("img:not([data-mce-object]):not([data-mce-placeholder]),figure.image",t.setActive).unbind,i=Xe(e)(t);return()=>{a(),i()}}}),e.ui.registry.addMenuItem("image",{icon:"image",text:"Image...",onAction:qe(e).open,onSetup:Xe(e)}),e.ui.registry.addContextMenu("image",{update:e=>re(e)||"IMG"===e.nodeName&&!H(e)?["image"]:[]})})(e),(e=>{e.addCommand("mceImage",qe(e).open),e.addCommand("mceUpdateImage",((t,a)=>{e.undoManager.transact((()=>ye(e,a)))}))})(e)}))}(); \ No newline at end of file +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=Object.getPrototypeOf,a=(e,t,a)=>{var i;return!!a(e,t.prototype)||(null===(i=e.constructor)||void 0===i?void 0:i.name)===t.name},i=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&a(e,String,((e,t)=>t.isPrototypeOf(e)))?"string":t})(t)===e,s=e=>t=>typeof t===e,r=i("string"),o=i("object"),n=e=>((e,i)=>o(e)&&a(e,i,((e,a)=>t(e)===a)))(e,Object),l=i("array"),c=(null,e=>null===e);const m=s("boolean"),d=e=>!(e=>null==e)(e),g=s("function"),u=s("number"),p=()=>{};class h{constructor(e,t){this.tag=e,this.value=t}static some(e){return new h(!0,e)}static none(){return h.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?h.some(e(this.value)):h.none()}bind(e){return this.tag?e(this.value):h.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:h.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return d(e)?h.some(e):h.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}h.singletonNone=new h(!1);const b=Object.keys,v=Object.hasOwnProperty,y=(e,t)=>v.call(e,t),f=Array.prototype.push,w=e=>{const t=[];for(let a=0,i=e.length;a{((e,t,a)=>{if(!(r(a)||m(a)||u(a)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",a,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,a+"")})(e.dom,t,a)},D=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},_=D;var C=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),I=tinymce.util.Tools.resolve("tinymce.util.URI");const U=e=>e.length>0,S=e=>t=>t.options.get(e),x=S("image_dimensions"),N=S("image_advtab"),T=S("image_uploadtab"),O=S("image_prepend_url"),E=S("image_class_list"),L=S("image_description"),j=S("image_title"),M=S("image_caption"),R=S("image_list"),k=S("a11y_advanced_options"),z=S("automatic_uploads"),P=(e,t)=>Math.max(parseInt(e,10),parseInt(t,10)),B=e=>(e&&(e=e.replace(/px$/,"")),e),F=e=>(e.length>0&&/^[0-9]+$/.test(e)&&(e+="px"),e),H=e=>"IMG"===e.nodeName&&(e.hasAttribute("data-mce-object")||e.hasAttribute("data-mce-placeholder")),G=(e,t)=>{const a=e.options.get;return I.isDomSafe(t,"img",{allow_html_data_urls:a("allow_html_data_urls"),allow_script_urls:a("allow_script_urls"),allow_svg_data_urls:a("allow_svg_data_urls")})},W=C.DOM,$=e=>e.style.marginLeft&&e.style.marginRight&&e.style.marginLeft===e.style.marginRight?B(e.style.marginLeft):"",V=e=>e.style.marginTop&&e.style.marginBottom&&e.style.marginTop===e.style.marginBottom?B(e.style.marginTop):"",K=e=>e.style.borderWidth?B(e.style.borderWidth):"",Z=(e,t)=>{var a;return e.hasAttribute(t)&&null!==(a=e.getAttribute(t))&&void 0!==a?a:""},q=e=>null!==e.parentNode&&"FIGURE"===e.parentNode.nodeName,J=(e,t,a)=>{""===a||null===a?e.removeAttribute(t):e.setAttribute(t,a)},Q=(e,t)=>{const a=e.getAttribute("style"),i=t(null!==a?a:"");i.length>0?(e.setAttribute("style",i),e.setAttribute("data-mce-style",i)):e.removeAttribute("style")},X=(e,t)=>(e,a,i)=>{const s=e.style;s[a]?(s[a]=F(i),Q(e,t)):J(e,a,i)},Y=(e,t)=>e.style[t]?B(e.style[t]):Z(e,t),ee=(e,t)=>{const a=F(t);e.style.marginLeft=a,e.style.marginRight=a},te=(e,t)=>{const a=F(t);e.style.marginTop=a,e.style.marginBottom=a},ae=(e,t)=>{const a=F(t);e.style.borderWidth=a},ie=(e,t)=>{e.style.borderStyle=t},se=e=>{var t;return null!==(t=e.style.borderStyle)&&void 0!==t?t:""},re=e=>d(e)&&"FIGURE"===e.nodeName,oe=e=>0===W.getAttrib(e,"alt").length&&"presentation"===W.getAttrib(e,"role"),ne=e=>oe(e)?"":Z(e,"alt"),le=(e,t)=>{var a;const i=document.createElement("img");return J(i,"style",t.style),($(i)||""!==t.hspace)&&ee(i,t.hspace),(V(i)||""!==t.vspace)&&te(i,t.vspace),(K(i)||""!==t.border)&&ae(i,t.border),(se(i)||""!==t.borderStyle)&&ie(i,t.borderStyle),e(null!==(a=i.getAttribute("style"))&&void 0!==a?a:"")},ce=(e,t)=>({src:Z(t,"src"),alt:ne(t),title:Z(t,"title"),width:Y(t,"width"),height:Y(t,"height"),class:Z(t,"class"),style:e(Z(t,"style")),caption:q(t),hspace:$(t),vspace:V(t),border:K(t),borderStyle:se(t),isDecorative:oe(t)}),me=(e,t,a,i,s)=>{a[i]!==t[i]&&s(e,i,String(a[i]))},de=(e,t,a)=>{if(a){W.setAttrib(e,"role","presentation");const t=_(e);A(t,"alt","")}else{if(c(t)){"alt",_(e).dom.removeAttribute("alt")}else{const a=_(e);A(a,"alt",t)}"presentation"===W.getAttrib(e,"role")&&W.setAttrib(e,"role","")}},ge=(e,t)=>(a,i,s)=>{e(a,s),Q(a,t)},ue=(e,t,a)=>{const i=ce(e,a);me(a,i,t,"caption",((e,t,a)=>(e=>{q(e)?(e=>{const t=e.parentNode;d(t)&&(W.insertAfter(e,t),W.remove(t))})(e):(e=>{const t=W.create("figure",{class:"image"});W.insertAfter(t,e),t.appendChild(e),t.appendChild(W.create("figcaption",{contentEditable:"true"},"Caption")),t.contentEditable="false"})(e)})(e))),me(a,i,t,"src",J),me(a,i,t,"title",J),me(a,i,t,"width",X(0,e)),me(a,i,t,"height",X(0,e)),me(a,i,t,"class",J),me(a,i,t,"style",ge(((e,t)=>J(e,"style",t)),e)),me(a,i,t,"hspace",ge(ee,e)),me(a,i,t,"vspace",ge(te,e)),me(a,i,t,"border",ge(ae,e)),me(a,i,t,"borderStyle",ge(ie,e)),((e,t,a)=>{a.alt===t.alt&&a.isDecorative===t.isDecorative||de(e,a.alt,a.isDecorative)})(a,i,t)},pe=(e,t)=>{const a=(e=>{if(e.margin){const t=String(e.margin).split(" ");switch(t.length){case 1:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[0],e["margin-bottom"]=e["margin-bottom"]||t[0],e["margin-left"]=e["margin-left"]||t[0];break;case 2:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[0],e["margin-left"]=e["margin-left"]||t[1];break;case 3:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[2],e["margin-left"]=e["margin-left"]||t[1];break;case 4:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[2],e["margin-left"]=e["margin-left"]||t[3]}delete e.margin}return e})(e.dom.styles.parse(t)),i=e.dom.styles.parse(e.dom.styles.serialize(a));return e.dom.styles.serialize(i)},he=e=>{const t=e.selection.getNode(),a=e.dom.getParent(t,"figure.image");return a?e.dom.select("img",a)[0]:t&&("IMG"!==t.nodeName||H(t))?null:t},be=(e,t)=>{var a;const i=e.dom,s=((t,a)=>{const i={};var s;return((e,t,a,i)=>{((e,t)=>{const a=b(e);for(let i=0,s=a.length;i{(t(e,s)?a:i)(e,s)}))})(t,((t,a)=>!e.schema.isValidChild(a,"figure")),(s=i,(e,t)=>{s[t]=e}),p),i})(e.schema.getTextBlockElements()),r=i.getParent(t.parentNode,(e=>{return t=s,a=e.nodeName,y(t,a)&&void 0!==t[a]&&null!==t[a];var t,a}),e.getBody());return r&&null!==(a=i.split(r,t))&&void 0!==a?a:t},ve=(e,t)=>{const a=((t,a)=>{const i=document.createElement("img");if(ue((t=>pe(e,t)),{...a,caption:!1},i),de(i,a.alt,a.isDecorative),a.caption){const e=W.create("figure",{class:"image"});return e.appendChild(i),e.appendChild(W.create("figcaption",{contentEditable:"true"},"Caption")),e.contentEditable="false",e}return i})(0,t);e.dom.setAttrib(a,"data-mce-id","__mcenew"),e.focus(),e.selection.setContent(a.outerHTML);const i=e.dom.select('*[data-mce-id="__mcenew"]')[0];if(e.dom.setAttrib(i,"data-mce-id",null),re(i)){const t=be(e,i);e.selection.select(t)}else e.selection.select(i)},ye=(e,t)=>{const a=he(e);if(a){const i={...ce((t=>pe(e,t)),a),...t},s=((e,t)=>{const a=t.src;return{...t,src:G(e,a)?a:""}})(e,i);i.src?((e,t)=>{const a=he(e);if(a)if(ue((t=>pe(e,t)),t,a),((e,t)=>{e.dom.setAttrib(t,"src",t.getAttribute("src"))})(e,a),re(a.parentNode)){const t=a.parentNode;be(e,t),e.selection.select(a.parentNode)}else e.selection.select(a),((e,t,a)=>{const i=()=>{a.onload=a.onerror=null,e.selection&&(e.selection.select(a),e.nodeChanged())};a.onload=()=>{t.width||t.height||!x(e)||e.dom.setAttribs(a,{width:String(a.clientWidth),height:String(a.clientHeight)}),i()},a.onerror=i})(e,t,a)})(e,s):((e,t)=>{if(t){const a=e.dom.is(t.parentNode,"figure.image")?t.parentNode:t;e.dom.remove(a),e.focus(),e.nodeChanged(),e.dom.isEmpty(e.getBody())&&(e.setContent(""),e.selection.setCursorLocation())}})(e,a)}else t.src&&ve(e,{src:"",alt:"",title:"",width:"",height:"",class:"",style:"",caption:!1,hspace:"",vspace:"",border:"",borderStyle:"",isDecorative:!1,...t})},fe=(we=(e,t)=>n(e)&&n(t)?fe(e,t):t,(...e)=>{if(0===e.length)throw new Error("Can't merge zero objects");const t={};for(let a=0;ar(e.value)?e.value:"",Ce=(e,t)=>{const a=[];return De.each(e,(e=>{const i=(e=>r(e.text)?e.text:r(e.title)?e.title:"")(e);if(void 0!==e.menu){const s=Ce(e.menu,t);a.push({text:i,items:s})}else{const s=t(e);a.push({text:i,value:s})}})),a},Ie=(e=_e)=>t=>t?h.from(t).map((t=>Ce(t,e))):h.none(),Ue=(e,t)=>((e,a)=>{for(let a=0;ay(e,"items"))(i=e[a])?Ue(i.items,t):i.value===t?h.some(i):h.none();if(s.isSome())return s}var i;return h.none()})(e),Se=Ie,xe=(e,t)=>e.bind((e=>Ue(e,t))),Ne=e=>{const t=Se((t=>e.convertURL(t.value||t.url||"","src"))),a=new Promise((a=>{((e,t)=>{const a=R(e);r(a)?fetch(a).then((e=>{e.ok&&e.json().then(t)})):g(a)?a(t):t(a)})(e,(e=>{a(t(e).map((e=>w([[{text:"None",value:""}],e]))))}))})),i=(A=E(e),Ie(_e)(A)),s=N(e),o=T(e),n=(e=>U(e.options.get("images_upload_url")))(e),l=(e=>d(e.options.get("images_upload_handler")))(e),c=(e=>{const t=he(e);return t?ce((t=>pe(e,t)),t):{src:"",alt:"",title:"",width:"",height:"",class:"",style:"",caption:!1,hspace:"",vspace:"",border:"",borderStyle:"",isDecorative:!1}})(e),m=L(e),u=j(e),p=x(e),b=M(e),v=k(e),y=z(e),f=h.some(O(e)).filter((e=>r(e)&&e.length>0));var A;return a.then((e=>({image:c,imageList:e,classList:i,hasAdvTab:s,hasUploadTab:o,hasUploadUrl:n,hasUploadHandler:l,hasDescription:m,hasImageTitle:u,hasDimensions:p,hasImageCaption:b,prependURL:f,hasAccessibilityOptions:v,automaticUploads:y})))},Te=e=>{const t=e.imageList.map((e=>({name:"images",type:"listbox",label:"Image list",items:e}))),a={name:"alt",type:"input",label:"Alternative description",enabled:!(e.hasAccessibilityOptions&&e.image.isDecorative)},i=e.classList.map((e=>({name:"classes",type:"listbox",label:"Class",items:e})));return w([[{name:"src",type:"urlinput",filetype:"image",label:"Source"}],t.toArray(),e.hasAccessibilityOptions&&e.hasDescription?[{type:"label",label:"Accessibility",items:[{name:"isDecorative",type:"checkbox",label:"Image is decorative"}]}]:[],e.hasDescription?[a]:[],e.hasImageTitle?[{name:"title",type:"input",label:"Image title"}]:[],e.hasDimensions?[{name:"dimensions",type:"sizeinput"}]:[],[{...(s=e.classList.isSome()&&e.hasImageCaption,s?{type:"grid",columns:2}:{type:"panel"}),items:w([i.toArray(),e.hasImageCaption?[{type:"label",label:"Caption",items:[{type:"checkbox",name:"caption",label:"Show caption"}]}]:[]])}]]);var s},Oe=e=>({title:"General",name:"general",items:Te(e)}),Ee=Te,Le=e=>({src:{value:e.src,meta:{}},images:e.src,alt:e.alt,title:e.title,dimensions:{width:e.width,height:e.height},classes:e.class,caption:e.caption,style:e.style,vspace:e.vspace,border:e.border,hspace:e.hspace,borderstyle:e.borderStyle,fileinput:[],isDecorative:e.isDecorative}),je=(e,t)=>({src:e.src.value,alt:null!==e.alt&&0!==e.alt.length||!t?e.alt:null,title:e.title,width:e.dimensions.width,height:e.dimensions.height,class:e.classes,style:e.style,caption:e.caption,hspace:e.hspace,vspace:e.vspace,border:e.border,borderStyle:e.borderstyle,isDecorative:e.isDecorative}),Me=(e,t,a,i)=>{((e,t)=>{const a=t.getData();((e,t)=>/^(?:[a-zA-Z]+:)?\/\//.test(t)?h.none():e.prependURL.bind((e=>t.substring(0,e.length)!==e?h.some(e+t):h.none())))(e,a.src.value).each((e=>{t.setData({src:{value:e,meta:a.src.meta}})}))})(t,i),((e,t)=>{const a=t.getData(),i=a.src.meta;if(void 0!==i){const s=fe({},a);((e,t,a)=>{e.hasDescription&&r(a.alt)&&(t.alt=a.alt),e.hasAccessibilityOptions&&(t.isDecorative=a.isDecorative||t.isDecorative||!1),e.hasImageTitle&&r(a.title)&&(t.title=a.title),e.hasDimensions&&(r(a.width)&&(t.dimensions.width=a.width),r(a.height)&&(t.dimensions.height=a.height)),r(a.class)&&xe(e.classList,a.class).each((e=>{t.classes=e.value})),e.hasImageCaption&&m(a.caption)&&(t.caption=a.caption),e.hasAdvTab&&(r(a.style)&&(t.style=a.style),r(a.vspace)&&(t.vspace=a.vspace),r(a.border)&&(t.border=a.border),r(a.hspace)&&(t.hspace=a.hspace),r(a.borderstyle)&&(t.borderstyle=a.borderstyle))})(e,s,i),t.setData(s)}})(t,i),((e,t,a,i)=>{const s=i.getData(),r=s.src.value,o=s.src.meta||{};o.width||o.height||!t.hasDimensions||(U(r)?e.imageSize(r).then((e=>{a.open&&i.setData({dimensions:e})})).catch((e=>console.error(e))):i.setData({dimensions:{width:"",height:""}}))})(e,t,a,i),((e,t,a)=>{const i=a.getData(),s=xe(e.imageList,i.src.value);t.prevImage=s,a.setData({images:s.map((e=>e.value)).getOr("")})})(t,a,i)},Re=(e,t,a,i)=>{const s=i.getData();var r;i.block("Uploading image"),(r=s.fileinput,((e,t)=>0{i.unblock()}),(s=>{const r=URL.createObjectURL(s),o=()=>{i.unblock(),URL.revokeObjectURL(r)},n=s=>{i.setData({src:{value:s,meta:{}}}),i.showTab("general"),Me(e,t,a,i)};var l;(l=s,new Promise(((e,t)=>{const a=new FileReader;a.onload=()=>{e(a.result)},a.onerror=()=>{var e;t(null===(e=a.error)||void 0===e?void 0:e.message)},a.readAsDataURL(l)}))).then((a=>{const l=e.createBlobCache(s,r,a);t.automaticUploads?e.uploadImage(l).then((e=>{n(e.url),o()})).catch((t=>{o(),e.alertErr(t)})):(e.addToBlobCache(l),n(l.blobUri()),i.unblock())}))}))},ke=(e,t,a)=>(i,s)=>{"src"===s.name?Me(e,t,a,i):"images"===s.name?((e,t,a,i)=>{const s=i.getData(),r=xe(t.imageList,s.images);r.each((e=>{const t=""===s.alt||a.prevImage.map((e=>e.text===s.alt)).getOr(!1);t?""===e.value?i.setData({src:e,alt:a.prevAlt}):i.setData({src:e,alt:e.text}):i.setData({src:e})})),a.prevImage=r,Me(e,t,a,i)})(e,t,a,i):"alt"===s.name?a.prevAlt=i.getData().alt:"fileinput"===s.name?Re(e,t,a,i):"isDecorative"===s.name&&i.setEnabled("alt",!i.getData().isDecorative)},ze=e=>()=>{e.open=!1},Pe=e=>e.hasAdvTab||e.hasUploadUrl||e.hasUploadHandler?{type:"tabpanel",tabs:w([[Oe(e)],e.hasAdvTab?[{title:"Advanced",name:"advanced",items:[{type:"grid",columns:2,items:[{type:"input",label:"Vertical space",name:"vspace",inputMode:"numeric"},{type:"input",label:"Horizontal space",name:"hspace",inputMode:"numeric"},{type:"input",label:"Border width",name:"border",inputMode:"numeric"},{type:"listbox",name:"borderstyle",label:"Border style",items:[{text:"Select...",value:""},{text:"Solid",value:"solid"},{text:"Dotted",value:"dotted"},{text:"Dashed",value:"dashed"},{text:"Double",value:"double"},{text:"Groove",value:"groove"},{text:"Ridge",value:"ridge"},{text:"Inset",value:"inset"},{text:"Outset",value:"outset"},{text:"None",value:"none"},{text:"Hidden",value:"hidden"}]}]}]}]:[],e.hasUploadTab&&(e.hasUploadUrl||e.hasUploadHandler)?[{title:"Upload",name:"upload",items:[{type:"dropzone",name:"fileinput"}]}]:[]])}:{type:"panel",items:Ee(e)},Be=(e,t,a)=>i=>{const s=fe(Le(t.image),i.getData()),r={...s,style:le(a.normalizeCss,je(s,!1))};e.execCommand("mceUpdateImage",!1,je(r,t.hasAccessibilityOptions)),e.editorUpload.uploadImagesAuto(),i.close()},Fe=e=>t=>G(e,t)?(e=>new Promise((t=>{const a=document.createElement("img"),i=e=>{a.onload=a.onerror=null,a.parentNode&&a.parentNode.removeChild(a),t(e)};a.onload=()=>{const e={width:P(a.width,a.clientWidth),height:P(a.height,a.clientHeight)};i(Promise.resolve(e))},a.onerror=()=>{i(Promise.reject(`Failed to get image dimensions for: ${e}`))};const s=a.style;s.visibility="hidden",s.position="fixed",s.bottom=s.left="0px",s.width=s.height="auto",document.body.appendChild(a),a.src=e})))(e.documentBaseURI.toAbsolute(t)).then((e=>({width:String(e.width),height:String(e.height)}))):Promise.resolve({width:"",height:""}),He=e=>(t,a,i)=>{var s;return e.editorUpload.blobCache.create({blob:t,blobUri:a,name:null===(s=t.name)||void 0===s?void 0:s.replace(/\.[^\.]+$/,""),filename:t.name,base64:i.split(",")[1]})},Ge=e=>t=>{e.editorUpload.blobCache.add(t)},We=e=>t=>{e.windowManager.alert(t)},$e=e=>t=>pe(e,t),Ve=e=>t=>e.dom.parseStyle(t),Ke=e=>(t,a)=>e.dom.serializeStyle(t,a),Ze=e=>t=>Ae(e).upload([t],!1).then((e=>{var t;return 0===e.length?Promise.reject("Failed to upload image"):!1===e[0].status?Promise.reject(null===(t=e[0].error)||void 0===t?void 0:t.message):e[0]})),qe=e=>{const t={imageSize:Fe(e),addToBlobCache:Ge(e),createBlobCache:He(e),alertErr:We(e),normalizeCss:$e(e),parseStyle:Ve(e),serializeStyle:Ke(e),uploadImage:Ze(e)};return{open:()=>{Ne(e).then((a=>{const i=(e=>({prevImage:xe(e.imageList,e.image.src),prevAlt:e.image.alt,open:!0}))(a);return{title:"Insert/Edit Image",size:"normal",body:Pe(a),buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:Le(a.image),onSubmit:Be(e,a,t),onChange:ke(t,a,i),onClose:ze(i)}})).then(e.windowManager.open)}}},Je=e=>{const t=e.attr("class");return d(t)&&/\bimage\b/.test(t)},Qe=e=>t=>{let a=t.length;const i=t=>{t.attr("contenteditable",e?"true":null)};for(;a--;){const s=t[a];Je(s)&&(s.attr("contenteditable",e?"false":null),De.each(s.getAll("figcaption"),i))}},Xe=e=>t=>{const a=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",a),a(),()=>{e.off("NodeChange",a)}};e.add("image",(e=>{(e=>{const t=e.options.register;t("image_dimensions",{processor:"boolean",default:!0}),t("image_advtab",{processor:"boolean",default:!1}),t("image_uploadtab",{processor:"boolean",default:!0}),t("image_prepend_url",{processor:"string",default:""}),t("image_class_list",{processor:"object[]"}),t("image_description",{processor:"boolean",default:!0}),t("image_title",{processor:"boolean",default:!1}),t("image_caption",{processor:"boolean",default:!1}),t("image_list",{processor:e=>{const t=!1===e||r(e)||((e,t)=>{if(l(e)){for(let a=0,i=e.length;a{e.on("PreInit",(()=>{e.parser.addNodeFilter("figure",Qe(!0)),e.serializer.addNodeFilter("figure",Qe(!1))}))})(e),(e=>{e.ui.registry.addToggleButton("image",{icon:"image",tooltip:"Insert/edit image",onAction:qe(e).open,onSetup:t=>{t.setActive(d(he(e)));const a=e.selection.selectorChangedWithUnbind("img:not([data-mce-object]):not([data-mce-placeholder]),figure.image",t.setActive).unbind,i=Xe(e)(t);return()=>{a(),i()}}}),e.ui.registry.addMenuItem("image",{icon:"image",text:"Image...",onAction:qe(e).open,onSetup:Xe(e)}),e.ui.registry.addContextMenu("image",{update:t=>e.selection.isEditable()&&(re(t)||"IMG"===t.nodeName&&!H(t))?["image"]:[]})})(e),(e=>{e.addCommand("mceImage",qe(e).open),e.addCommand("mceUpdateImage",((t,a)=>{e.undoManager.transact((()=>ye(e,a)))}))})(e)}))}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/importcss/plugin.min.js b/public/libs/tinymce/plugins/importcss/plugin.min.js index bfb8a1d90..9afd216c8 100644 --- a/public/libs/tinymce/plugins/importcss/plugin.min.js +++ b/public/libs/tinymce/plugins/importcss/plugin.min.js @@ -1,4 +1,4 @@ /** - * TinyMCE version 6.5.1 (2023-06-19) + * TinyMCE version 6.7.2 (2023-10-25) */ !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(s=r=e,(o=String).prototype.isPrototypeOf(s)||(null===(n=r.constructor)||void 0===n?void 0:n.name)===o.name)?"string":t;var s,r,o,n})(t)===e,s=t("string"),r=t("object"),o=t("array"),n=("function",e=>"function"==typeof e);var c=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),i=tinymce.util.Tools.resolve("tinymce.EditorManager"),l=tinymce.util.Tools.resolve("tinymce.Env"),a=tinymce.util.Tools.resolve("tinymce.util.Tools");const p=e=>t=>t.options.get(e),u=p("importcss_merge_classes"),m=p("importcss_exclusive"),f=p("importcss_selector_converter"),y=p("importcss_selector_filter"),d=p("importcss_groups"),h=p("importcss_append"),_=p("importcss_file_filter"),g=p("skin"),v=p("skin_url"),b=Array.prototype.push,x=/^\.(?:ephox|tiny-pageembed|mce)(?:[.-]+\w+)+$/,T=e=>s(e)?t=>-1!==t.indexOf(e):e instanceof RegExp?t=>e.test(t):e,S=(e,t)=>{let s={};const r=/^(?:([a-z0-9\-_]+))?(\.[a-z0-9_\-\.]+)$/i.exec(t);if(!r)return;const o=r[1],n=r[2].substr(1).split(".").join(" "),c=a.makeMap("a,img");return r[1]?(s={title:t},e.schema.getTextBlockElements()[o]?s.block=o:e.schema.getBlockElements()[o]||c[o.toLowerCase()]?s.selector=o:s.inline=o):r[2]&&(s={inline:"span",title:t.substr(1),classes:n}),u(e)?s.classes=n:s.attributes={class:n},s},k=(e,t)=>null===t||m(e),w=e=>{e.on("init",(()=>{const t=(()=>{const e=[],t=[],s={};return{addItemToGroup:(e,r)=>{s[e]?s[e].push(r):(t.push(e),s[e]=[r])},addItem:t=>{e.push(t)},toFormats:()=>{return(r=t,n=e=>{const t=s[e];return 0===t.length?[]:[{title:e,items:t}]},(e=>{const t=[];for(let s=0,r=e.length;s{const s=e.length,r=new Array(s);for(let o=0;oa.map(e,(e=>a.extend({},e,{original:e,selectors:{},filter:T(e.filter)}))))(d(e)),u=(t,s)=>{if(((e,t,s,r)=>!(k(e,s)?t in r:t in s.selectors))(e,t,s,r)){((e,t,s,r)=>{k(e,s)?r[t]=!0:s.selectors[t]=!0})(e,t,s,r);const o=((e,t,s,r)=>{let o;const n=f(e);return o=r&&r.selector_converter?r.selector_converter:n||(()=>S(e,s)),o.call(t,s,r)})(e,e.plugins.importcss,t,s);if(o){const t=o.name||c.DOM.uniqueId();return e.formatter.register(t,o),{title:o.title,format:t}}}return null};a.each(((e,t,r)=>{const o=[],n={},c=(t,n)=>{let p,u=t.href;if(u=(e=>{const t=l.cacheSuffix;return s(e)&&(e=e.replace("?"+t,"").replace("&"+t,"")),e})(u),u&&(!r||r(u,n))&&!((e,t)=>{const s=g(e);if(s){const r=v(e),o=r?e.documentBaseURI.toAbsolute(r):i.baseURL+"/skins/ui/"+s,n=i.baseURL+"/skins/content/";return t===o+"/content"+(e.inline?".inline":"")+".min.css"||-1!==t.indexOf(n)}return!1})(e,u)){a.each(t.imports,(e=>{c(e,!0)}));try{p=t.cssRules||t.rules}catch(e){}a.each(p,(e=>{e.styleSheet?c(e.styleSheet,!0):e.selectorText&&a.each(e.selectorText.split(","),(e=>{o.push(a.trim(e))}))}))}};a.each(e.contentCSS,(e=>{n[e]=!0})),r||(r=(e,t)=>t||n[e]);try{a.each(t.styleSheets,(e=>{c(e)}))}catch(e){}return o})(e,e.getDoc(),T(_(e))),(e=>{if(!x.test(e)&&(!n||n(e))){const s=((e,t)=>a.grep(e,(e=>!e.filter||e.filter(t))))(p,e);if(s.length>0)a.each(s,(s=>{const r=u(e,s);r&&t.addItemToGroup(s.title,r)}));else{const s=u(e,null);s&&t.addItem(s)}}}));const m=t.toFormats();e.dispatch("addStyleModifications",{items:m,replace:!h(e)})}))};e.add("importcss",(e=>((e=>{const t=e.options.register,o=e=>s(e)||n(e)||r(e);t("importcss_merge_classes",{processor:"boolean",default:!0}),t("importcss_exclusive",{processor:"boolean",default:!0}),t("importcss_selector_converter",{processor:"function"}),t("importcss_selector_filter",{processor:o}),t("importcss_file_filter",{processor:o}),t("importcss_groups",{processor:"object[]"}),t("importcss_append",{processor:"boolean",default:!1})})(e),w(e),(e=>({convertSelectorToFormat:t=>S(e,t)}))(e))))}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/insertdatetime/plugin.min.js b/public/libs/tinymce/plugins/insertdatetime/plugin.min.js index 73348f8e1..e0c4d38c6 100644 --- a/public/libs/tinymce/plugins/insertdatetime/plugin.min.js +++ b/public/libs/tinymce/plugins/insertdatetime/plugin.min.js @@ -1,4 +1,4 @@ /** - * TinyMCE version 6.5.1 (2023-06-19) + * TinyMCE version 6.7.2 (2023-10-25) */ !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>t.options.get(e),a=t("insertdatetime_dateformat"),n=t("insertdatetime_timeformat"),r=t("insertdatetime_formats"),s=t("insertdatetime_element"),i="Sun Mon Tue Wed Thu Fri Sat Sun".split(" "),o="Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday".split(" "),l="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),m="January February March April May June July August September October November December".split(" "),c=(e,t)=>{if((e=""+e).length(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=t.replace("%D","%m/%d/%Y")).replace("%r","%I:%M:%S %p")).replace("%Y",""+a.getFullYear())).replace("%y",""+a.getYear())).replace("%m",c(a.getMonth()+1,2))).replace("%d",c(a.getDate(),2))).replace("%H",""+c(a.getHours(),2))).replace("%M",""+c(a.getMinutes(),2))).replace("%S",""+c(a.getSeconds(),2))).replace("%I",""+((a.getHours()+11)%12+1))).replace("%p",a.getHours()<12?"AM":"PM")).replace("%B",""+e.translate(m[a.getMonth()]))).replace("%b",""+e.translate(l[a.getMonth()]))).replace("%A",""+e.translate(o[a.getDay()]))).replace("%a",""+e.translate(i[a.getDay()]))).replace("%%","%"),u=(e,t)=>{if(s(e)){const a=d(e,t);let n;n=/%[HMSIp]/.test(t)?d(e,"%Y-%m-%dT%H:%M"):d(e,"%Y-%m-%d");const r=e.dom.getParent(e.selection.getStart(),"time");r?((e,t,a,n)=>{const r=e.dom.create("time",{datetime:a},n);e.dom.replace(r,t),e.selection.select(r,!0),e.selection.collapse(!1)})(e,r,n,a):e.insertContent('")}else e.insertContent(d(e,t))};var p=tinymce.util.Tools.resolve("tinymce.util.Tools");const g=e=>t=>{const a=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",a),a(),()=>{e.off("NodeChange",a)}};e.add("insertdatetime",(e=>{(e=>{const t=e.options.register;t("insertdatetime_dateformat",{processor:"string",default:e.translate("%Y-%m-%d")}),t("insertdatetime_timeformat",{processor:"string",default:e.translate("%H:%M:%S")}),t("insertdatetime_formats",{processor:"string[]",default:["%H:%M:%S","%Y-%m-%d","%I:%M:%S %p","%D"]}),t("insertdatetime_element",{processor:"boolean",default:!1})})(e),(e=>{e.addCommand("mceInsertDate",((t,n)=>{u(e,null!=n?n:a(e))})),e.addCommand("mceInsertTime",((t,a)=>{u(e,null!=a?a:n(e))}))})(e),(e=>{const t=r(e),a=(e=>{let t=e;return{get:()=>t,set:e=>{t=e}}})((e=>{const t=r(e);return t.length>0?t[0]:n(e)})(e)),s=t=>e.execCommand("mceInsertDate",!1,t);e.ui.registry.addSplitButton("insertdatetime",{icon:"insert-time",tooltip:"Insert date/time",select:e=>e===a.get(),fetch:a=>{a(p.map(t,(t=>({type:"choiceitem",text:d(e,t),value:t}))))},onAction:e=>{s(a.get())},onItemAction:(e,t)=>{a.set(t),s(t)},onSetup:g(e)});const i=e=>()=>{a.set(e),s(e)};e.ui.registry.addNestedMenuItem("insertdatetime",{icon:"insert-time",text:"Date/time",getSubmenuItems:()=>p.map(t,(t=>({type:"menuitem",text:d(e,t),onAction:i(t)}))),onSetup:g(e)})})(e)}))}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/link/plugin.min.js b/public/libs/tinymce/plugins/link/plugin.min.js index 57e8a8342..fa1f87339 100644 --- a/public/libs/tinymce/plugins/link/plugin.min.js +++ b/public/libs/tinymce/plugins/link/plugin.min.js @@ -1,4 +1,4 @@ /** - * TinyMCE version 6.5.1 (2023-06-19) + * TinyMCE version 6.7.2 (2023-10-25) */ !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=o=e,(r=String).prototype.isPrototypeOf(n)||(null===(l=o.constructor)||void 0===l?void 0:l.name)===r.name)?"string":t;var n,o,r,l})(t)===e,n=e=>t=>typeof t===e,o=t("string"),r=t("object"),l=t("array"),a=(null,e=>null===e);const i=n("boolean"),s=e=>!(e=>null==e)(e),c=n("function"),u=(e,t)=>{if(l(e)){for(let n=0,o=e.length;n{},d=(e,t)=>e===t;class m{constructor(e,t){this.tag=e,this.value=t}static some(e){return new m(!0,e)}static none(){return m.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?m.some(e(this.value)):m.none()}bind(e){return this.tag?e(this.value):m.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:m.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return s(e)?m.some(e):m.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}m.singletonNone=new m(!1);const h=Array.prototype.indexOf,f=Array.prototype.push,p=e=>{const t=[];for(let n=0,o=e.length;n{for(let n=0;ne.exists((e=>n(e,t))),y=e=>{const t=[],n=e=>{t.push(e)};for(let t=0;te?m.some(t):m.none(),b=e=>t=>t.options.get(e),_=b("link_assume_external_targets"),w=b("link_context_toolbar"),C=b("link_list"),O=b("link_default_target"),N=b("link_default_protocol"),A=b("link_target_list"),S=b("link_rel_list"),E=b("link_class_list"),T=b("link_title"),R=b("allow_unsafe_link_target"),P=b("link_quicklink");var L=tinymce.util.Tools.resolve("tinymce.util.Tools");const M=e=>o(e.value)?e.value:"",D=(e,t)=>{const n=[];return L.each(e,(e=>{const r=(e=>o(e.text)?e.text:o(e.title)?e.title:"")(e);if(void 0!==e.menu){const o=D(e.menu,t);n.push({text:r,items:o})}else{const o=t(e);n.push({text:r,value:o})}})),n},B=(e=M)=>t=>m.from(t).map((t=>D(t,e))),I=e=>B(M)(e),j=B,K=(e,t)=>n=>({name:e,type:"listbox",label:t,items:n}),U=M,q=Object.keys,F=Object.hasOwnProperty,V=(e,t)=>F.call(e,t);var $=tinymce.util.Tools.resolve("tinymce.dom.TreeWalker"),z=tinymce.util.Tools.resolve("tinymce.util.URI");const G=e=>s(e)&&"a"===e.nodeName.toLowerCase(),H=e=>G(e)&&!!Q(e),J=(e,t)=>{if(e.collapsed)return[];{const n=e.cloneContents(),o=n.firstChild,r=new $(o,n),l=[];let a=o;do{t(a)&&l.push(a)}while(a=r.next());return l}},W=e=>/^\w+:/i.test(e),Q=e=>{var t,n;return null!==(n=null!==(t=e.getAttribute("data-mce-href"))&&void 0!==t?t:e.getAttribute("href"))&&void 0!==n?n:""},X=(e,t)=>{const n=["noopener"],o=e?e.split(/\s+/):[],r=e=>e.filter((e=>-1===L.inArray(n,e))),l=t?(e=>(e=r(e)).length>0?e.concat(n):n)(o):r(o);return l.length>0?(e=>L.trim(e.sort().join(" ")))(l):""},Y=(e,t)=>(t=t||te(e.selection.getRng())[0]||e.selection.getNode(),le(t)?m.from(e.dom.select("a[href]",t)[0]):m.from(e.dom.getParent(t,"a[href]"))),Z=(e,t)=>Y(e,t).isSome(),ee=(e,t)=>t.fold((()=>e.getContent({format:"text"})),(e=>e.innerText||e.textContent||"")).replace(/\uFEFF/g,""),te=e=>J(e,H),ne=e=>L.grep(e,H),oe=e=>ne(e).length>0,re=e=>{const t=e.schema.getTextInlineElements();if(Y(e).exists((e=>e.hasAttribute("data-mce-block"))))return!1;const n=e.selection.getRng();return!!n.collapsed||0===J(n,(e=>1===e.nodeType&&!G(e)&&!V(t,e.nodeName.toLowerCase()))).length},le=e=>s(e)&&"FIGURE"===e.nodeName&&/\bimage\b/i.test(e.className),ae=(e,t,n)=>{const o=e.selection.getNode(),r=Y(e,o),l=((e,t)=>{const n={...t};if(0===S(e).length&&!R(e)){const e=X(n.rel,"_blank"===n.target);n.rel=e||null}return m.from(n.target).isNone()&&!1===A(e)&&(n.target=O(e)),n.href=((e,t)=>"http"!==t&&"https"!==t||W(e)?e:t+"://"+e)(n.href,_(e)),n})(e,(e=>{return t=["title","rel","class","target"],n=(t,n)=>(e[n].each((e=>{t[n]=e.length>0?e:null})),t),o={href:e.href},((e,t)=>{for(let n=0,o=e.length;n{o=n(o,e)})),o;var t,n,o})(n));e.undoManager.transact((()=>{n.href===t.href&&t.attach(),r.fold((()=>{((e,t,n,o)=>{const r=e.dom;le(t)?ge(r,t,o):n.fold((()=>{e.execCommand("mceInsertLink",!1,o)}),(t=>{e.insertContent(r.createHTML("a",o,r.encode(t)))}))})(e,o,n.text,l)}),(t=>{e.focus(),((e,t,n,o)=>{n.each((e=>{V(t,"innerText")?t.innerText=e:t.textContent=e})),e.dom.setAttribs(t,o),e.selection.select(t)})(e,t,n.text,l)}))}))},ie=e=>{const{class:t,href:n,rel:o,target:r,text:l,title:i}=e;return((e,t)=>{const n={};var o;return((e,t,n,o)=>{((e,t)=>{const n=q(e);for(let o=0,r=n.length;o{(t(e,r)?n:o)(e,r)}))})(e,((e,t)=>!1===a(e)),(o=n,(e,t)=>{o[t]=e}),g),n})({class:t.getOrNull(),href:n,rel:o.getOrNull(),target:r.getOrNull(),text:l.getOrNull(),title:i.getOrNull()})},se=(e,t,n)=>{const o=((e,t)=>{const n=e.options.get,o={allow_html_data_urls:n("allow_html_data_urls"),allow_script_urls:n("allow_script_urls"),allow_svg_data_urls:n("allow_svg_data_urls")},r=t.href;return{...t,href:z.isDomSafe(r,"a",o)?r:""}})(e,n);e.hasPlugin("rtc",!0)?e.execCommand("createlink",!1,ie(o)):ae(e,t,o)},ce=e=>{e.hasPlugin("rtc",!0)?e.execCommand("unlink"):(e=>{e.undoManager.transact((()=>{const t=e.selection.getNode();le(t)?ue(e,t):(e=>{const t=e.dom,n=e.selection,o=n.getBookmark(),r=n.getRng().cloneRange(),l=t.getParent(r.startContainer,"a[href]",e.getBody()),a=t.getParent(r.endContainer,"a[href]",e.getBody());l&&r.setStartBefore(l),a&&r.setEndAfter(a),n.setRng(r),e.execCommand("unlink"),n.moveToBookmark(o)})(e),e.focus()}))})(e)},ue=(e,t)=>{var n;const o=e.dom.select("img",t)[0];if(o){const r=e.dom.getParents(o,"a[href]",t)[0];r&&(null===(n=r.parentNode)||void 0===n||n.insertBefore(o,r),e.dom.remove(r))}},ge=(e,t,n)=>{var o;const r=e.select("img",t)[0];if(r){const t=e.create("a",n);null===(o=r.parentNode)||void 0===o||o.insertBefore(t,r),t.appendChild(r)}},de=(e,t)=>k(t,(t=>(e=>{return V(t=e,n="items")&&void 0!==t[n]&&null!==t[n];var t,n})(t)?de(e,t.items):x(t.value===e,t))),me=(e,t)=>{const n={text:e.text,title:e.title},o=(e,o)=>{const r=(l=t,a=o,"link"===a?l.link:"anchor"===a?l.anchor:m.none()).getOr([]);var l,a;return((e,t,n,o)=>{const r=o[t],l=e.length>0;return void 0!==r?de(r,n).map((t=>({url:{value:t.value,meta:{text:l?e:t.text,attach:g}},text:l?e:t.text}))):m.none()})(n.text,o,r,e)};return{onChange:(e,t)=>{const r=t.name;return"url"===r?(e=>{const t=(o=e.url,x(n.text.length<=0,m.from(null===(r=o.meta)||void 0===r?void 0:r.text).getOr(o.value)));var o,r;const l=(e=>{var t;return x(n.title.length<=0,m.from(null===(t=e.meta)||void 0===t?void 0:t.title).getOr(""))})(e.url);return t.isSome()||l.isSome()?m.some({...t.map((e=>({text:e}))).getOr({}),...l.map((e=>({title:e}))).getOr({})}):m.none()})(e()):((e,t)=>h.call(e,t))(["anchor","link"],r)>-1?o(e(),r):"text"===r||"title"===r?(n[r]=e()[r],m.none()):m.none()}}};var he=tinymce.util.Tools.resolve("tinymce.util.Delay");const fe=e=>{const t=e.href;return t.indexOf("@")>0&&-1===t.indexOf("/")&&-1===t.indexOf("mailto:")?m.some({message:"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?",preprocess:e=>({...e,href:"mailto:"+t})}):m.none()},pe=(e,t)=>n=>{const o=n.href;return 1===e&&!W(o)||0===e&&/^\s*www(\.|\d\.)/i.test(o)?m.some({message:`The URL you entered seems to be an external link. Do you want to add the required ${t}:// prefix?`,preprocess:e=>({...e,href:t+"://"+o})}):m.none()},ke=e=>{const t=e.dom.select("a:not([href])"),n=p(((e,t)=>{const n=e.length,o=new Array(n);for(let r=0;r{const t=e.name||e.id;return t?[{text:t,value:"#"+t}]:[]})));return n.length>0?m.some([{text:"None",value:""}].concat(n)):m.none()},ve=e=>{const t=E(e);return t.length>0?I(t):m.none()},ye=e=>{try{return m.some(JSON.parse(e))}catch(e){return m.none()}},xe=(e,t)=>{const n=S(e);if(n.length>0){const o=v(t,"_blank"),r=e=>X(U(e),o);return(!1===R(e)?j(r):I)(n)}return m.none()},be=[{text:"Current window",value:""},{text:"New window",value:"_blank"}],_e=e=>{const t=A(e);return l(t)?I(t).orThunk((()=>m.some(be))):!1===t?m.none():m.some(be)},we=(e,t,n)=>{const o=e.getAttrib(t,n);return null!==o&&o.length>0?m.some(o):m.none()},Ce=(e,t)=>(e=>{const t=t=>e.convertURL(t.value||t.url||"","href"),n=C(e);return new Promise((e=>{o(n)?fetch(n).then((e=>e.ok?e.text().then(ye):Promise.reject())).then(e,(()=>e(m.none()))):c(n)?n((t=>e(m.some(t)))):e(m.from(n))})).then((e=>e.bind(j(t)).map((e=>e.length>0?[{text:"None",value:""}].concat(e):e))))})(e).then((n=>{const o=((e,t)=>{const n=e.dom,o=re(e)?m.some(ee(e.selection,t)):m.none(),r=t.bind((e=>m.from(n.getAttrib(e,"href")))),l=t.bind((e=>m.from(n.getAttrib(e,"target")))),a=t.bind((e=>we(n,e,"rel"))),i=t.bind((e=>we(n,e,"class")));return{url:r,text:o,title:t.bind((e=>we(n,e,"title"))),target:l,rel:a,linkClass:i}})(e,t);return{anchor:o,catalogs:{targets:_e(e),rels:xe(e,o.target),classes:ve(e),anchor:ke(e),link:n},optNode:t,flags:{titleEnabled:T(e)}}})),Oe=e=>{const t=(e=>{const t=Y(e);return Ce(e,t)})(e);t.then((t=>{const n=((e,t)=>n=>{const o=n.getData();if(!o.url.value)return ce(e),void n.close();const r=e=>m.from(o[e]).filter((n=>!v(t.anchor[e],n))),l={href:o.url.value,text:r("text"),target:r("target"),rel:r("rel"),class:r("linkClass"),title:r("title")},a={href:o.url.value,attach:void 0!==o.url.meta&&o.url.meta.attach?o.url.meta.attach:g};((e,t)=>k([fe,pe(_(e),N(e))],(e=>e(t))).fold((()=>Promise.resolve(t)),(n=>new Promise((o=>{((e,t,n)=>{const o=e.selection.getRng();he.setEditorTimeout(e,(()=>{e.windowManager.confirm(t,(t=>{e.selection.setRng(o),n(t)}))}))})(e,n.message,(e=>{o(e?n.preprocess(t):t)}))})))))(e,l).then((t=>{se(e,a,t)})),n.close()})(e,t);return((e,t,n)=>{const o=e.anchor.text.map((()=>({name:"text",type:"input",label:"Text to display"}))).toArray(),r=e.flags.titleEnabled?[{name:"title",type:"input",label:"Title"}]:[],l=((e,t)=>{const n=e.anchor,o=n.url.getOr("");return{url:{value:o,meta:{original:{value:o}}},text:n.text.getOr(""),title:n.title.getOr(""),anchor:o,link:o,rel:n.rel.getOr(""),target:n.target.or(t).getOr(""),linkClass:n.linkClass.getOr("")}})(e,m.from(O(n))),a=e.catalogs,i=me(l,a);return{title:"Insert/Edit Link",size:"normal",body:{type:"panel",items:p([[{name:"url",type:"urlinput",filetype:"file",label:"URL"}],o,r,y([a.anchor.map(K("anchor","Anchors")),a.rels.map(K("rel","Rel")),a.targets.map(K("target","Open link in...")),a.link.map(K("link","Link list")),a.classes.map(K("linkClass","Class"))])])},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:l,onChange:(e,{name:t})=>{i.onChange(e.getData,{name:t}).each((t=>{e.setData(t)}))},onSubmit:t}})(t,n,e)})).then((t=>{e.windowManager.open(t)}))};var Ne=tinymce.util.Tools.resolve("tinymce.util.VK");const Ae=(e,t)=>e.dom.getParent(t,"a[href]"),Se=e=>Ae(e,e.selection.getStart()),Ee=(e,t)=>{if(t){const n=Q(t);if(/^#/.test(n)){const t=e.dom.select(n);t.length&&e.selection.scrollIntoView(t[0],!0)}else(e=>{const t=document.createElement("a");t.target="_blank",t.href=e,t.rel="noreferrer noopener";const n=document.createEvent("MouseEvents");n.initMouseEvent("click",!0,!0,window,0,0,0,0,0,!1,!1,!1,!1,0,null),((e,t)=>{document.body.appendChild(e),e.dispatchEvent(t),document.body.removeChild(e)})(t,n)})(t.href)}},Te=e=>()=>{e.execCommand("mceLink",!1,{dialog:!0})},Re=e=>()=>{Ee(e,Se(e))},Pe=(e,t)=>(e.on("NodeChange",t),()=>e.off("NodeChange",t)),Le=e=>t=>{const n=()=>{t.setActive(!e.mode.isReadOnly()&&Z(e,e.selection.getNode())),t.setEnabled(e.selection.isEditable())};return n(),Pe(e,n)},Me=e=>t=>{const n=()=>{t.setEnabled(e.selection.isEditable())};return n(),Pe(e,n)},De=e=>t=>{const n=()=>t.setEnabled((e=>1===(e.selection.isCollapsed()?ne(e.dom.getParents(e.selection.getStart())):te(e.selection.getRng())).length)(e));return n(),Pe(e,n)},Be=e=>t=>{const n=e.dom.getParents(e.selection.getStart()),o=n=>{t.setEnabled((t=>{return oe(t)||(n=e.selection.getRng(),te(n).length>0);var n})(n)&&e.selection.isEditable())};return o(n),Pe(e,(e=>o(e.parents)))};e.add("link",(e=>{(e=>{const t=e.options.register;t("link_assume_external_targets",{processor:e=>{const t=o(e)||i(e);return t?!0===e?{value:1,valid:t}:"http"===e||"https"===e?{value:e,valid:t}:{value:0,valid:t}:{valid:!1,message:"Must be a string or a boolean."}},default:!1}),t("link_context_toolbar",{processor:"boolean",default:!1}),t("link_list",{processor:e=>o(e)||c(e)||u(e,r)}),t("link_default_target",{processor:"string"}),t("link_default_protocol",{processor:"string",default:"https"}),t("link_target_list",{processor:e=>i(e)||u(e,r),default:!0}),t("link_rel_list",{processor:"object[]",default:[]}),t("link_class_list",{processor:"object[]",default:[]}),t("link_title",{processor:"boolean",default:!0}),t("allow_unsafe_link_target",{processor:"boolean",default:!1}),t("link_quicklink",{processor:"boolean",default:!1})})(e),(e=>{e.ui.registry.addToggleButton("link",{icon:"link",tooltip:"Insert/edit link",onAction:Te(e),onSetup:Le(e)}),e.ui.registry.addButton("openlink",{icon:"new-tab",tooltip:"Open link",onAction:Re(e),onSetup:De(e)}),e.ui.registry.addButton("unlink",{icon:"unlink",tooltip:"Remove link",onAction:()=>ce(e),onSetup:Be(e)})})(e),(e=>{e.ui.registry.addMenuItem("openlink",{text:"Open link",icon:"new-tab",onAction:Re(e),onSetup:De(e)}),e.ui.registry.addMenuItem("link",{icon:"link",text:"Link...",shortcut:"Meta+K",onSetup:Me(e),onAction:Te(e)}),e.ui.registry.addMenuItem("unlink",{icon:"unlink",text:"Remove link",onAction:()=>ce(e),onSetup:Be(e)})})(e),(e=>{e.ui.registry.addContextMenu("link",{update:t=>e.dom.isEditable(t)?oe(e.dom.getParents(t,"a"))?"link unlink openlink":"link":""})})(e),(e=>{const t=t=>{const n=e.selection.getNode();return t.setEnabled(Z(e,n)),g};e.ui.registry.addContextForm("quicklink",{launch:{type:"contextformtogglebutton",icon:"link",tooltip:"Link",onSetup:Le(e)},label:"Link",predicate:t=>w(e)&&Z(e,t),initValue:()=>Y(e).fold((()=>""),Q),commands:[{type:"contextformtogglebutton",icon:"link",tooltip:"Link",primary:!0,onSetup:t=>{const n=e.selection.getNode();return t.setActive(Z(e,n)),Le(e)(t)},onAction:t=>{const n=t.getValue(),o=(t=>{const n=Y(e),o=re(e);if(n.isNone()&&o){const o=ee(e.selection,n);return x(0===o.length,t)}return m.none()})(n);se(e,{href:n,attach:g},{href:n,text:o,title:m.none(),rel:m.none(),target:m.none(),class:m.none()}),(e=>{e.selection.collapse(!1)})(e),t.hide()}},{type:"contextformbutton",icon:"unlink",tooltip:"Remove link",onSetup:t,onAction:t=>{ce(e),t.hide()}},{type:"contextformbutton",icon:"new-tab",tooltip:"Open link",onSetup:t,onAction:t=>{Re(e)(),t.hide()}}]})})(e),(e=>{e.on("click",(t=>{const n=Ae(e,t.target);n&&Ne.metaKeyPressed(t)&&(t.preventDefault(),Ee(e,n))})),e.on("keydown",(t=>{if(!t.isDefaultPrevented()&&13===t.keyCode&&(e=>!0===e.altKey&&!1===e.shiftKey&&!1===e.ctrlKey&&!1===e.metaKey)(t)){const n=Se(e);n&&(t.preventDefault(),Ee(e,n))}}))})(e),(e=>{e.addCommand("mceLink",((t,n)=>{!0!==(null==n?void 0:n.dialog)&&P(e)?e.dispatch("contexttoolbar-show",{toolbarKey:"quicklink"}):Oe(e)}))})(e),(e=>{e.addShortcut("Meta+K","",(()=>{e.execCommand("mceLink")}))})(e)}))}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/lists/plugin.min.js b/public/libs/tinymce/plugins/lists/plugin.min.js index 2dc22048d..e72e1336b 100644 --- a/public/libs/tinymce/plugins/lists/plugin.min.js +++ b/public/libs/tinymce/plugins/lists/plugin.min.js @@ -1,4 +1,4 @@ /** - * TinyMCE version 6.5.1 (2023-06-19) + * TinyMCE version 6.7.2 (2023-10-25) */ -!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=r=e,(o=String).prototype.isPrototypeOf(n)||(null===(s=r.constructor)||void 0===s?void 0:s.name)===o.name)?"string":t;var n,r,o,s})(t)===e,n=e=>t=>typeof t===e,r=t("string"),o=t("object"),s=t("array"),i=n("boolean"),l=e=>!(e=>null==e)(e),a=n("function"),d=n("number"),c=()=>{},u=(e,t)=>e===t,m=e=>t=>!e(t),p=(!1,()=>false);class g{constructor(e,t){this.tag=e,this.value=t}static some(e){return new g(!0,e)}static none(){return g.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?g.some(e(this.value)):g.none()}bind(e){return this.tag?e(this.value):g.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:g.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return l(e)?g.some(e):g.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}g.singletonNone=new g(!1);const h=Array.prototype.slice,f=Array.prototype.indexOf,y=Array.prototype.push,v=(e,t)=>{return n=e,r=t,f.call(n,r)>-1;var n,r},b=(e,t)=>{for(let n=0,r=e.length;n{const n=e.length,r=new Array(n);for(let o=0;o{for(let n=0,r=e.length;n{const n=[];for(let r=0,o=e.length;r(S(e,((e,r)=>{n=t(n,e,r)})),n),O=(e,t,n)=>{for(let r=0,o=e.length;rO(e,t,p),T=(e,t)=>(e=>{const t=[];for(let n=0,r=e.length;n{const t=h.call(e,0);return t.reverse(),t},x=(e,t)=>t>=0&&tx(e,0),w=e=>x(e,e.length-1),D=(e,t)=>{const n=[],r=a(t)?e=>b(n,(n=>t(n,e))):e=>v(n,e);for(let t=0,o=e.length;te.exists((e=>n(e,t))),I=(e,t,n)=>e.isSome()&&t.isSome()?g.some(n(e.getOrDie(),t.getOrDie())):g.none(),P=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},M=(e,t)=>{const n=(t||document).createElement(e);return P(n)},R=P,U=(e,t)=>e.dom===t.dom;"undefined"!=typeof window?window:Function("return this;")();const $=e=>e.dom.nodeName.toLowerCase(),_=(1,e=>1===(e=>e.dom.nodeType)(e));const F=e=>t=>_(t)&&$(t)===e,H=e=>g.from(e.dom.parentNode).map(R),V=e=>C(e.dom.childNodes,R),j=(e,t)=>{const n=e.dom.childNodes;return g.from(n[t]).map(R)},K=e=>j(e,0),z=e=>j(e,e.dom.childNodes.length-1),Q=(e,t,n)=>{let r=e.dom;const o=a(n)?n:p;for(;r.parentNode;){r=r.parentNode;const e=R(r);if(t(e))return g.some(e);if(o(e))break}return g.none()},q=(e,t,n)=>((e,t,n,r,o)=>r(n)?g.some(n):a(o)&&o(n)?g.none():t(n,r,o))(0,Q,e,t,n),W=(e,t)=>{H(e).each((n=>{n.dom.insertBefore(t.dom,e.dom)}))},Z=(e,t)=>{e.dom.appendChild(t.dom)},G=(e,t)=>{S(t,(t=>{Z(e,t)}))},J=e=>{e.dom.textContent="",S(V(e),(e=>{X(e)}))},X=e=>{const t=e.dom;null!==t.parentNode&&t.parentNode.removeChild(t)};var Y=tinymce.util.Tools.resolve("tinymce.dom.RangeUtils"),ee=tinymce.util.Tools.resolve("tinymce.dom.TreeWalker"),te=tinymce.util.Tools.resolve("tinymce.util.VK");const ne=e=>C(e,R),re=Object.keys,oe=(e,t)=>{const n=re(e);for(let r=0,o=n.length;r{const n=e.dom;oe(t,((e,t)=>{((e,t,n)=>{if(!(r(n)||i(n)||d(n)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",n,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,n+"")})(n,t,e)}))},ie=e=>L(e.dom.attributes,((e,t)=>(e[t.name]=t.value,e)),{}),le=e=>((e,t)=>R(e.dom.cloneNode(!0)))(e),ae=(e,t)=>{const n=((e,t)=>{const n=M(t),r=ie(e);return se(n,r),n})(e,t);var r,o;o=n,(e=>g.from(e.dom.nextSibling).map(R))(r=e).fold((()=>{H(r).each((e=>{Z(e,o)}))}),(e=>{W(e,o)}));const s=V(e);return G(n,s),X(e),n};var de=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),ce=tinymce.util.Tools.resolve("tinymce.util.Tools");const ue=e=>t=>l(t)&&t.nodeName.toLowerCase()===e,me=e=>t=>l(t)&&e.test(t.nodeName),pe=e=>l(e)&&3===e.nodeType,ge=e=>l(e)&&1===e.nodeType,he=me(/^(OL|UL|DL)$/),fe=me(/^(OL|UL)$/),ye=ue("ol"),ve=me(/^(LI|DT|DD)$/),be=me(/^(DT|DD)$/),Ce=me(/^(TH|TD)$/),Se=ue("br"),Ne=(e,t)=>l(t)&&t.nodeName in e.schema.getTextBlockElements(),Le=(e,t)=>l(e)&&e.nodeName in t,Oe=(e,t)=>l(t)&&t.nodeName in e.schema.getVoidElements(),ke=(e,t,n)=>{const r=e.isEmpty(t);return!(n&&e.select("span[data-mce-type=bookmark]",t).length>0)&&r},Te=(e,t)=>e.isChildOf(t,e.getRoot()),Ae=e=>t=>t.options.get(e),xe=Ae("lists_indent_on_tab"),Ee=Ae("forced_root_block"),we=Ae("forced_root_block_attrs"),De=(e,t)=>{const n=e.dom,r=e.schema.getBlockElements(),o=n.createFragment(),s=Ee(e),i=we(e);let l,a,d=!1;for(a=n.create(s,i),Le(t.firstChild,r)||o.appendChild(a);l=t.firstChild;){const e=l.nodeName;d||"SPAN"===e&&"bookmark"===l.getAttribute("data-mce-type")||(d=!0),Le(l,r)?(o.appendChild(l),a=null):(a||(a=n.create(s,i),o.appendChild(a)),a.appendChild(l))}return!d&&a&&a.appendChild(n.create("br",{"data-mce-bogus":"1"})),o},Be=de.DOM,Ie=F("dd"),Pe=F("dt"),Me=(e,t)=>{var n;Ie(t)?ae(t,"dt"):Pe(t)&&(n=t,g.from(n.dom.parentElement).map(R)).each((n=>((e,t,n)=>{const r=Be.select('span[data-mce-type="bookmark"]',t),o=De(e,n),s=Be.createRng();s.setStartAfter(n),s.setEndAfter(t);const i=s.extractContents();for(let t=i.firstChild;t;t=t.firstChild)if("LI"===t.nodeName&&e.dom.isEmpty(t)){Be.remove(t);break}e.dom.isEmpty(i)||Be.insertAfter(i,t),Be.insertAfter(o,t);const l=n.parentElement;l&&ke(e.dom,l)&&(e=>{const t=e.parentNode;t&&ce.each(r,(e=>{t.insertBefore(e,n.parentNode)})),Be.remove(e)})(l),Be.remove(n),ke(e.dom,t)&&Be.remove(t)})(e,n.dom,t.dom)))},Re=e=>{Pe(e)&&ae(e,"dd")},Ue=(e,t)=>{if(pe(e))return{container:e,offset:t};const n=Y.getNode(e,t);return pe(n)?{container:n,offset:t>=e.childNodes.length?n.data.length:0}:n.previousSibling&&pe(n.previousSibling)?{container:n.previousSibling,offset:n.previousSibling.data.length}:n.nextSibling&&pe(n.nextSibling)?{container:n.nextSibling,offset:0}:{container:e,offset:t}},$e=e=>{const t=e.cloneRange(),n=Ue(e.startContainer,e.startOffset);t.setStart(n.container,n.offset);const r=Ue(e.endContainer,e.endOffset);return t.setEnd(r.container,r.offset),t},_e=["OL","UL","DL"],Fe=_e.join(","),He=(e,t)=>{const n=t||e.selection.getStart(!0);return e.dom.getParent(n,Fe,Ke(e,n))},Ve=e=>{const t=e.selection.getSelectedBlocks();return N(((e,t)=>{const n=ce.map(t,(t=>e.dom.getParent(t,"li,dd,dt",Ke(e,t))||t));return D(n)})(e,t),ve)},je=(e,t)=>{const n=e.dom.getParents(t,"TD,TH");return n.length>0?n[0]:e.getBody()},Ke=(e,t)=>{const n=e.dom.getParents(t,e.dom.isBlock),r=k(n,(t=>{return n=e.schema,!he(r=t)&&!ve(r)&&b(_e,(e=>n.isValidChild(r.nodeName,e)));var n,r}));return r.getOr(e.getBody())},ze=(e,t)=>{const n=e.dom.getParents(t,"ol,ul",Ke(e,t));return w(n)},Qe=(e,t)=>{const n=C(t,(t=>ze(e,t).getOr(t)));return D(n)},qe=e=>/\btox\-/.test(e.className),We=(e,t)=>O(e,he,Ce).exists((e=>e.nodeName===t&&!qe(e))),Ze=(e,t)=>null!==t&&!e.dom.isEditable(t),Ge=(e,t)=>{const n=e.dom.getParent(t,"ol,ul,dl");return Ze(e,n)},Je=(e,t)=>{const n=e.selection.getNode();return t({parents:e.dom.getParents(n),element:n}),e.on("NodeChange",t),()=>e.off("NodeChange",t)},Xe=(e,t,n)=>e.dispatch("ListMutation",{action:t,element:n}),Ye=(et=/^\s+|\s+$/g,e=>e.replace(et,""));var et;const tt=(e,t,n)=>{((e,t,n)=>{if(!r(n))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",n,":: Element ",e),new Error("CSS value must be a string: "+n);(e=>void 0!==e.style&&a(e.style.getPropertyValue))(e)&&e.style.setProperty(t,n)})(e.dom,t,n)},nt=(e,t)=>{Z(e.item,t.list)},rt=(e,t)=>{const n={list:M(t,e),item:M("li",e)};return Z(n.list,n.item),n},ot=e=>((e,t)=>{const n=e.dom;if(1!==n.nodeType)return!1;{const e=n;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}})(e,"OL,UL"),st=e=>K(e).exists(ot),it=e=>e.depth>0,lt=e=>e.isSelected,at=e=>{const t=V(e),n=z(e).exists(ot)?t.slice(0,-1):t;return C(n,le)},dt=e=>(S(e,((t,n)=>{((e,t)=>{const n=e[t].depth,r=e=>e.depth===n&&!e.dirty,o=e=>e.depthO(e.slice(t+1),r,o)))})(e,n).fold((()=>{t.dirty&&(e=>{e.listAttributes=((e,t)=>{const n={};var r;return((e,t,n,r)=>{oe(e,((e,o)=>{(t(e,o)?n:r)(e,o)}))})(e,t,(r=n,(e,t)=>{r[t]=e}),c),n})(e.listAttributes,((e,t)=>"start"!==t))})(t)}),(e=>{return r=e,(n=t).listType=r.listType,void(n.listAttributes={...r.listAttributes});var n,r}))})),e),ct=(e,t,n,r)=>K(r).filter(ot).fold((()=>{t.each((e=>{U(e.start,r)&&n.set(!0)}));const o=((e,t,n)=>H(e).filter(_).map((r=>({depth:t,dirty:!1,isSelected:n,content:at(e),itemAttributes:ie(e),listAttributes:ie(r),listType:$(r)}))))(r,e,n.get());t.each((e=>{U(e.end,r)&&n.set(!1)}));const s=z(r).filter(ot).map((r=>ut(e,t,n,r))).getOr([]);return o.toArray().concat(s)}),(r=>ut(e,t,n,r))),ut=(e,t,n,r)=>T(V(r),(r=>(ot(r)?ut:ct)(e+1,t,n,r))),mt=(e,t)=>{const n=dt(t);return((e,t)=>{const n=L(t,((t,n)=>n.depth>t.length?((e,t,n)=>{const r=((e,t,n)=>{const r=[];for(let o=0;o{for(let t=1;t{for(let t=0;t{se(e.list,t.listAttributes),se(e.item,t.itemAttributes),G(e.item,t.content)}))})(r,n),o=r,I(w(t),E(o),nt),t.concat(r)})(e,t,n):((e,t,n)=>{const r=t.slice(0,n.depth);return w(r).each((t=>{const r=((e,t,n)=>{const r=M("li",e);return se(r,t),G(r,n),r})(e,n.itemAttributes,n.content);((e,t)=>{Z(e.list,t),e.item=t})(t,r),((e,t)=>{$(e.list)!==t.listType&&(e.list=ae(e.list,t.listType)),se(e.list,t.listAttributes)})(t,n)})),r})(e,t,n)),[]);return E(n).map((e=>e.list))})(e.contentDocument,n).toArray()},pt=(e,t,n)=>{const r=((e,t)=>{const n=(e=>{let t=!1;return{get:()=>t,set:e=>{t=e}}})();return C(e,(e=>({sourceList:e,entries:ut(0,t,n,e)})))})(t,(e=>{const t=C(Ve(e),R);return I(k(t,m(st)),k(A(t),m(st)),((e,t)=>({start:e,end:t})))})(e));S(r,(t=>{((e,t)=>{S(N(e,lt),(e=>((e,t)=>{switch(e){case"Indent":t.depth++;break;case"Outdent":t.depth--;break;case"Flatten":t.depth=0}t.dirty=!0})(t,e)))})(t.entries,n);const r=((e,t)=>T(((e,t)=>{if(0===e.length)return[];{let n=t(e[0]);const r=[];let o=[];for(let s=0,i=e.length;sE(t).exists(it)?mt(e,t):((e,t)=>{const n=dt(t);return C(n,(t=>{const n=((e,t)=>{const n=document.createDocumentFragment();return S(e,(e=>{n.appendChild(e.dom)})),R(n)})(t.content);return R(De(e,n.dom))}))})(e,t))))(e,t.entries);var o;S(r,(t=>{Xe(e,"Indent"===n?"IndentList":"OutdentList",t.dom)})),o=t.sourceList,S(r,(e=>{W(o,e)})),X(t.sourceList)}))},gt=(e,t)=>{const n=ne((e=>{const t=(e=>{const t=ze(e,e.selection.getStart()),n=N(e.selection.getSelectedBlocks(),fe);return t.toArray().concat(n)})(e);return Qe(e,t)})(e)),r=ne((e=>N(Ve(e),be))(e));let o=!1;if(n.length||r.length){const s=e.selection.getBookmark();pt(e,n,t),((e,t,n)=>{S(n,"Indent"===t?Re:t=>Me(e,t))})(e,t,r),e.selection.moveToBookmark(s),e.selection.setRng($e(e.selection.getRng())),e.nodeChanged(),o=!0}return o},ht=(e,t)=>!(e=>{const t=He(e);return Ze(e,t)})(e)&>(e,t),ft=e=>ht(e,"Indent"),yt=e=>ht(e,"Outdent"),vt=e=>ht(e,"Flatten"),bt=e=>"\ufeff"===e;var Ct=tinymce.util.Tools.resolve("tinymce.dom.BookmarkManager");const St=de.DOM,Nt=e=>{const t={},n=n=>{let r=e[n?"startContainer":"endContainer"],o=e[n?"startOffset":"endOffset"];if(ge(r)){const e=St.create("span",{"data-mce-type":"bookmark"});r.hasChildNodes()?(o=Math.min(o,r.childNodes.length-1),n?r.insertBefore(e,r.childNodes[o]):St.insertAfter(e,r.childNodes[o])):r.appendChild(e),r=e,o=0}t[n?"startContainer":"endContainer"]=r,t[n?"startOffset":"endOffset"]=o};return n(!0),e.collapsed||n(),t},Lt=e=>{const t=t=>{let n=e[t?"startContainer":"endContainer"],r=e[t?"startOffset":"endOffset"];if(n){if(ge(n)&&n.parentNode){const e=n;r=(e=>{var t;let n=null===(t=e.parentNode)||void 0===t?void 0:t.firstChild,r=0;for(;n;){if(n===e)return r;ge(n)&&"bookmark"===n.getAttribute("data-mce-type")||r++,n=n.nextSibling}return-1})(n),n=n.parentNode,St.remove(e),!n.hasChildNodes()&&St.isBlock(n)&&n.appendChild(St.create("br"))}e[t?"startContainer":"endContainer"]=n,e[t?"startOffset":"endOffset"]=r}};t(!0),t();const n=St.createRng();return n.setStart(e.startContainer,e.startOffset),e.endContainer&&n.setEnd(e.endContainer,e.endOffset),$e(n)},Ot=e=>{switch(e){case"UL":return"ToggleUlList";case"OL":return"ToggleOlList";case"DL":return"ToggleDLList"}},kt=(e,t)=>{ce.each(t,((t,n)=>{e.setAttribute(n,t)}))},Tt=(e,t,n)=>{((e,t,n)=>{const r=n["list-style-type"]?n["list-style-type"]:null;e.setStyle(t,"list-style-type",r)})(e,t,n),((e,t,n)=>{kt(t,n["list-attributes"]),ce.each(e.select("li",t),(e=>{kt(e,n["list-item-attributes"])}))})(e,t,n)},At=(e,t)=>l(t)&&!Le(t,e.schema.getBlockElements()),xt=(e,t,n,r)=>{let o=t[n?"startContainer":"endContainer"];const s=t[n?"startOffset":"endOffset"];ge(o)&&(o=o.childNodes[Math.min(s,o.childNodes.length-1)]||o),!n&&Se(o.nextSibling)&&(o=o.nextSibling);const i=(t,n)=>{var o;const s=new ee(t,r),i=n?"next":"prev";let l;for(;l=s[i]();)if(!Oe(e,l)&&!bt(l.textContent)&&0!==(null===(o=l.textContent)||void 0===o?void 0:o.length))return g.some(l);return g.none()};if(n&&pe(o))if(bt(o.textContent))o=i(o,!1).getOr(o);else for(null!==o.parentNode&&At(e,o.parentNode)&&(o=o.parentNode);null!==o.previousSibling&&(At(e,o.previousSibling)||pe(o.previousSibling));)o=o.previousSibling;if(!n&&pe(o))if(bt(o.textContent))o=i(o,!0).getOr(o);else for(null!==o.parentNode&&At(e,o.parentNode)&&(o=o.parentNode);null!==o.nextSibling&&(At(e,o.nextSibling)||pe(o.nextSibling));)o=o.nextSibling;for(;o.parentNode!==r;){const t=o.parentNode;if(Ne(e,o))return o;if(/^(TD|TH)$/.test(t.nodeName))return o;o=t}return o},Et=(e,t,n)=>{const r=e.selection.getRng();let o="LI";const s=Ke(e,e.selection.getStart(!0)),i=e.dom;if("false"===i.getContentEditable(e.selection.getNode()))return;"DL"===(t=t.toUpperCase())&&(o="DT");const l=Nt(r),a=N(((e,t,n)=>{const r=[],o=e.dom,s=xt(e,t,!0,n),i=xt(e,t,!1,n);let l;const a=[];for(let e=s;e&&(a.push(e),e!==i);e=e.nextSibling);return ce.each(a,(t=>{var s;if(Ne(e,t))return r.push(t),void(l=null);if(o.isBlock(t)||Se(t))return Se(t)&&o.remove(t),void(l=null);const i=t.nextSibling;Ct.isBookmarkNode(t)&&(he(i)||Ne(e,i)||!i&&t.parentNode===n)?l=null:(l||(l=o.create("p"),null===(s=t.parentNode)||void 0===s||s.insertBefore(l,t),r.push(l)),l.appendChild(t))})),r})(e,r,s),e.dom.isEditable);ce.each(a,(r=>{let s;const l=r.previousSibling,a=r.parentNode;ve(a)||(l&&he(l)&&l.nodeName===t&&((e,t,n)=>{const r=e.getStyle(t,"list-style-type");let o=n?n["list-style-type"]:"";return o=null===o?"":o,r===o})(i,l,n)?(s=l,r=i.rename(r,o),l.appendChild(r)):(s=i.create(t),a.insertBefore(s,r),s.appendChild(r),r=i.rename(r,o)),((e,t,n)=>{ce.each(["margin","margin-right","margin-bottom","margin-left","margin-top","padding","padding-right","padding-bottom","padding-left","padding-top"],(n=>e.setStyle(t,n,"")))})(i,r),Tt(i,s,n),Dt(e.dom,s))})),e.selection.setRng(Lt(l))},wt=(e,t,n)=>{return((e,t)=>he(e)&&e.nodeName===(null==t?void 0:t.nodeName))(t,n)&&((e,t,n)=>e.getStyle(t,"list-style-type",!0)===e.getStyle(n,"list-style-type",!0))(e,t,n)&&(r=n,t.className===r.className);var r},Dt=(e,t)=>{let n,r=t.nextSibling;if(wt(e,t,r)){const o=r;for(;n=o.firstChild;)t.appendChild(n);e.remove(o)}if(r=t.previousSibling,wt(e,t,r)){const o=r;for(;n=o.lastChild;)t.insertBefore(n,t.firstChild);e.remove(o)}},Bt=e=>"list-style-type"in e,It=(e,t,n)=>{const r=He(e);if(Ge(e,r)||!e.hasEditableRoot())return;const s=(e=>{const t=He(e),n=e.selection.getSelectedBlocks();return((e,t)=>l(e)&&1===t.length&&t[0]===e)(t,n)?(e=>N(e.querySelectorAll(Fe),he))(t):N(n,(e=>he(e)&&t!==e))})(e),i=o(n)?n:{};s.length>0?((e,t,n,r,o)=>{const s=he(t);if(s&&t.nodeName===r&&!Bt(o))vt(e);else{Et(e,r,o);const i=Nt(e.selection.getRng()),l=s?[t,...n]:n;ce.each(l,(t=>{((e,t,n,r)=>{if(t.nodeName!==n){const o=e.dom.rename(t,n);Tt(e.dom,o,r),Xe(e,Ot(n),o)}else Tt(e.dom,t,r),Xe(e,Ot(n),t)})(e,t,r,o)})),e.selection.setRng(Lt(i))}})(e,r,s,t,i):((e,t,n,r)=>{if(t!==e.getBody())if(t)if(t.nodeName!==n||Bt(r)||qe(t)){const o=Nt(e.selection.getRng());Tt(e.dom,t,r);const s=e.dom.rename(t,n);Dt(e.dom,s),e.selection.setRng(Lt(o)),Et(e,n,r),Xe(e,Ot(n),s)}else vt(e);else Et(e,n,r),Xe(e,Ot(n),t)})(e,r,t,i)},Pt=de.DOM,Mt=(e,t)=>{const n=ce.grep(e.select("ol,ul",t));ce.each(n,(t=>{((e,t)=>{const n=t.parentElement;if(n&&"LI"===n.nodeName&&n.firstChild===t){const r=n.previousSibling;r&&"LI"===r.nodeName?(r.appendChild(t),ke(e,n)&&Pt.remove(n)):Pt.setStyle(n,"listStyleType","none")}if(he(n)){const e=n.previousSibling;e&&"LI"===e.nodeName&&e.appendChild(t)}})(e,t)}))},Rt=(e,t,n,r)=>{let o=t.startContainer;const s=t.startOffset;if(pe(o)&&(n?s0))return o;const i=e.schema.getNonEmptyElements();ge(o)&&(o=Y.getNode(o,s));const l=new ee(o,r);n&&((e,t)=>!!Se(t)&&e.isBlock(t.nextSibling)&&!Se(t.previousSibling))(e.dom,o)&&l.next();const a=n?l.next.bind(l):l.prev2.bind(l);for(;o=a();){if("LI"===o.nodeName&&!o.hasChildNodes())return o;if(i[o.nodeName])return o;if(pe(o)&&o.data.length>0)return o}return null},Ut=(e,t)=>{const n=t.childNodes;return 1===n.length&&!he(n[0])&&e.isBlock(n[0])},$t=(e,t,n)=>{let r;const o=t.parentNode;if(!Te(e,t)||!Te(e,n))return;he(n.lastChild)&&(r=n.lastChild),o===n.lastChild&&Se(o.previousSibling)&&e.remove(o.previousSibling);const s=n.lastChild;s&&Se(s)&&t.hasChildNodes()&&e.remove(s),ke(e,n,!0)&&J(R(n)),((e,t,n)=>{let r;const o=Ut(e,n)?n.firstChild:n;if(((e,t)=>{Ut(e,t)&&e.remove(t.firstChild,!0)})(e,t),!ke(e,t,!0))for(;r=t.firstChild;)o.appendChild(r)})(e,t,n),r&&n.appendChild(r);const i=((e,t)=>{const n=e.dom,r=t.dom;return n!==r&&n.contains(r)})(R(n),R(t))?e.getParents(t,he,n):[];e.remove(t),S(i,(t=>{ke(e,t)&&t!==e.getRoot()&&e.remove(t)}))},_t=(e,t)=>{const n=e.dom,r=e.selection,o=r.getStart(),s=je(e,o),i=n.getParent(r.getStart(),"LI",s);if(i){const o=i.parentElement;if(o===e.getBody()&&ke(n,o))return!0;const l=$e(r.getRng()),a=n.getParent(Rt(e,l,t,s),"LI",s);if(a&&a!==i)return e.undoManager.transact((()=>{var n,r;t?((e,t,n,r)=>{const o=e.dom;if(o.isEmpty(r))((e,t,n)=>{J(R(n)),$t(e.dom,t,n),e.selection.setCursorLocation(n,0)})(e,n,r);else{const s=Nt(t);$t(o,n,r),e.selection.setRng(Lt(s))}})(e,l,a,i):(null===(r=(n=i).parentNode)||void 0===r?void 0:r.firstChild)===n?yt(e):((e,t,n,r)=>{const o=Nt(t);$t(e.dom,n,r);const s=Lt(o);e.selection.setRng(s)})(e,l,i,a)})),!0;if(!a&&!t&&0===l.startOffset&&0===l.endOffset)return e.undoManager.transact((()=>{vt(e)})),!0}return!1},Ft=e=>{const t=e.selection.getStart(),n=je(e,t);return e.dom.getParent(t,"LI,DT,DD",n)||Ve(e).length>0},Ht=(e,t)=>{const n=e.selection;return!Ge(e,n.getNode())&&(n.isCollapsed()?((e,t)=>_t(e,t)||((e,t)=>{const n=e.dom,r=e.selection.getStart(),o=je(e,r),s=n.getParent(r,n.isBlock,o);if(s&&n.isEmpty(s)){const r=$e(e.selection.getRng()),i=n.getParent(Rt(e,r,t,o),"LI",o);if(i){const l=e=>v(["td","th","caption"],$(e)),a=e=>e.dom===o;return!!((e,t,n=u)=>I(e,t,n).getOr(e.isNone()&&t.isNone()))(q(R(i),l,a),q(R(r.startContainer),l,a),U)&&(e.undoManager.transact((()=>{((e,t,n)=>{const r=e.getParent(t.parentNode,e.isBlock,n);e.remove(t),r&&e.isEmpty(r)&&e.remove(r)})(n,s,o),Dt(n,i.parentNode),e.selection.select(i,!0),e.selection.collapse(t)})),!0)}}return!1})(e,t))(e,t):(e=>!!Ft(e)&&(e.undoManager.transact((()=>{e.execCommand("Delete"),Mt(e.dom,e.getBody())})),!0))(e))},Vt=e=>{const t=A(Ye(e).split("")),n=C(t,((e,t)=>{const n=e.toUpperCase().charCodeAt(0)-"A".charCodeAt(0)+1;return Math.pow(26,t)*n}));return L(n,((e,t)=>e+t),0)},jt=e=>{if(--e<0)return"";{const t=e%26,n=Math.floor(e/26);return jt(n)+String.fromCharCode("A".charCodeAt(0)+t)}},Kt=e=>{const t=parseInt(e.start,10);return B(e.listStyleType,"upper-alpha")?jt(t):B(e.listStyleType,"lower-alpha")?jt(t).toLowerCase():e.start},zt=(e,t)=>()=>{const n=He(e);return l(n)&&n.nodeName===t},Qt=e=>{e.addCommand("mceListProps",(()=>{(e=>{const t=He(e);ye(t)&&!Ge(e,t)&&e.windowManager.open({title:"List Properties",body:{type:"panel",items:[{type:"input",name:"start",label:"Start list at number",inputMode:"numeric"}]},initialData:{start:Kt({start:e.dom.getAttrib(t,"start","1"),listStyleType:g.from(e.dom.getStyle(t,"list-style-type"))})},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],onSubmit:t=>{(e=>{switch((e=>/^[0-9]+$/.test(e)?2:/^[A-Z]+$/.test(e)?0:/^[a-z]+$/.test(e)?1:e.length>0?4:3)(e)){case 2:return g.some({listStyleType:g.none(),start:e});case 0:return g.some({listStyleType:g.some("upper-alpha"),start:Vt(e).toString()});case 1:return g.some({listStyleType:g.some("lower-alpha"),start:Vt(e).toString()});case 3:return g.some({listStyleType:g.none(),start:""});case 4:return g.none()}})(t.getData().start).each((t=>{e.execCommand("mceListUpdate",!1,{attrs:{start:"1"===t.start?"":t.start},styles:{"list-style-type":t.listStyleType.getOr("")}})})),t.close()}})})(e)}))};var qt=tinymce.util.Tools.resolve("tinymce.html.Node");const Wt=e=>3===e.type,Zt=e=>0===e.length,Gt=e=>{const t=(t,n)=>{const r=qt.create("li");S(t,(e=>r.append(e))),n?e.insert(r,n,!0):e.append(r)},n=L(e.children(),((e,n)=>Wt(n)?[...e,n]:Zt(e)||Wt(n)?e:(t(e,n),[])),[]);Zt(n)||t(n)},Jt=(e,t)=>n=>(n.setEnabled(e.selection.isEditable()),Je(e,(r=>{n.setActive(We(r.parents,t)),n.setEnabled(!Ge(e,r.element)&&e.selection.isEditable())}))),Xt=(e,t)=>n=>Je(e,(r=>n.setEnabled(We(r.parents,t)&&!Ge(e,r.element))));e.add("lists",(e=>((e=>{(0,e.options.register)("lists_indent_on_tab",{processor:"boolean",default:!0})})(e),(e=>{e.on("PreInit",(()=>{const{parser:t}=e;t.addNodeFilter("ul,ol",(e=>S(e,Gt)))}))})(e),e.hasPlugin("rtc",!0)?Qt(e):((e=>{xe(e)&&(e=>{e.on("keydown",(t=>{t.keyCode!==te.TAB||te.metaKeyPressed(t)||e.undoManager.transact((()=>{(t.shiftKey?yt(e):ft(e))&&t.preventDefault()}))}))})(e),(e=>{e.on("ExecCommand",(t=>{const n=t.command.toLowerCase();"delete"!==n&&"forwarddelete"!==n||!Ft(e)||Mt(e.dom,e.getBody())})),e.on("keydown",(t=>{t.keyCode===te.BACKSPACE?Ht(e,!1)&&t.preventDefault():t.keyCode===te.DELETE&&Ht(e,!0)&&t.preventDefault()}))})(e)})(e),(e=>{e.on("BeforeExecCommand",(t=>{const n=t.command.toLowerCase();"indent"===n?ft(e):"outdent"===n&&yt(e)})),e.addCommand("InsertUnorderedList",((t,n)=>{It(e,"UL",n)})),e.addCommand("InsertOrderedList",((t,n)=>{It(e,"OL",n)})),e.addCommand("InsertDefinitionList",((t,n)=>{It(e,"DL",n)})),e.addCommand("RemoveList",(()=>{vt(e)})),Qt(e),e.addCommand("mceListUpdate",((t,n)=>{o(n)&&((e,t)=>{const n=He(e);null===n||Ge(e,n)||e.undoManager.transact((()=>{o(t.styles)&&e.dom.setStyles(n,t.styles),o(t.attrs)&&oe(t.attrs,((t,r)=>e.dom.setAttrib(n,r,t)))}))})(e,n)})),e.addQueryStateHandler("InsertUnorderedList",zt(e,"UL")),e.addQueryStateHandler("InsertOrderedList",zt(e,"OL")),e.addQueryStateHandler("InsertDefinitionList",zt(e,"DL"))})(e)),(e=>{const t=t=>()=>e.execCommand(t);e.hasPlugin("advlist")||(e.ui.registry.addToggleButton("numlist",{icon:"ordered-list",active:!1,tooltip:"Numbered list",onAction:t("InsertOrderedList"),onSetup:Jt(e,"OL")}),e.ui.registry.addToggleButton("bullist",{icon:"unordered-list",active:!1,tooltip:"Bullet list",onAction:t("InsertUnorderedList"),onSetup:Jt(e,"UL")}))})(e),(e=>{const t={text:"List properties...",icon:"ordered-list",onAction:()=>e.execCommand("mceListProps"),onSetup:Xt(e,"OL")};e.ui.registry.addMenuItem("listprops",t),e.ui.registry.addContextMenu("lists",{update:t=>{const n=He(e,t);return ye(n)?["listprops"]:[]}})})(e),(e=>({backspaceDelete:t=>{Ht(e,t)}}))(e))))}(); \ No newline at end of file +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=o=e,(r=String).prototype.isPrototypeOf(n)||(null===(s=o.constructor)||void 0===s?void 0:s.name)===r.name)?"string":t;var n,o,r,s})(t)===e,n=e=>t=>typeof t===e,o=t("string"),r=t("object"),s=t("array"),i=n("boolean"),l=e=>!(e=>null==e)(e),a=n("function"),d=n("number"),c=()=>{},m=(e,t)=>e===t,u=e=>t=>!e(t),p=(!1,()=>false);class g{constructor(e,t){this.tag=e,this.value=t}static some(e){return new g(!0,e)}static none(){return g.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?g.some(e(this.value)):g.none()}bind(e){return this.tag?e(this.value):g.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:g.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return l(e)?g.some(e):g.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}g.singletonNone=new g(!1);const h=Array.prototype.slice,f=Array.prototype.indexOf,y=Array.prototype.push,v=(e,t)=>{return n=e,o=t,f.call(n,o)>-1;var n,o},C=(e,t)=>{for(let n=0,o=e.length;n{const n=e.length,o=new Array(n);for(let r=0;r{for(let n=0,o=e.length;n{const n=[];for(let o=0,r=e.length;o(S(e,((e,o)=>{n=t(n,e,o)})),n),O=(e,t,n)=>{for(let o=0,r=e.length;oO(e,t,p),x=(e,t)=>(e=>{const t=[];for(let n=0,o=e.length;n{const t=h.call(e,0);return t.reverse(),t},T=(e,t)=>t>=0&&tT(e,0),w=e=>T(e,e.length-1),D=(e,t)=>{const n=[],o=a(t)?e=>C(n,(n=>t(n,e))):e=>v(n,e);for(let t=0,r=e.length;te.exists((e=>n(e,t))),I=(e,t,n)=>e.isSome()&&t.isSome()?g.some(n(e.getOrDie(),t.getOrDie())):g.none(),P=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},M=(e,t)=>{const n=(t||document).createElement("div");if(n.innerHTML=e,!n.hasChildNodes()||n.childNodes.length>1){const t="HTML does not have a single root node";throw console.error(t,e),new Error(t)}return P(n.childNodes[0])},R=(e,t)=>{const n=(t||document).createElement(e);return P(n)},U=P,$=(e,t)=>e.dom===t.dom;"undefined"!=typeof window?window:Function("return this;")();const _=e=>e.dom.nodeName.toLowerCase(),H=e=>e.dom.nodeType,V=(1,e=>1===H(e));const F=e=>t=>V(t)&&_(t)===e,j=e=>g.from(e.dom.parentNode).map(U),K=e=>b(e.dom.childNodes,U),z=(e,t)=>{const n=e.dom.childNodes;return g.from(n[t]).map(U)},Q=e=>z(e,0),W=e=>z(e,e.dom.childNodes.length-1),q=(e,t,n)=>{let o=e.dom;const r=a(n)?n:p;for(;o.parentNode;){o=o.parentNode;const e=U(o);if(t(e))return g.some(e);if(r(e))break}return g.none()},Z=(e,t,n)=>((e,t,n,o,r)=>o(n)?g.some(n):a(r)&&r(n)?g.none():t(n,o,r))(0,q,e,t,n),G=(e,t)=>{j(e).each((n=>{n.dom.insertBefore(t.dom,e.dom)}))},J=(e,t)=>{e.dom.appendChild(t.dom)},X=(e,t)=>{S(t,(t=>{J(e,t)}))},Y=e=>{e.dom.textContent="",S(K(e),(e=>{ee(e)}))},ee=e=>{const t=e.dom;null!==t.parentNode&&t.parentNode.removeChild(t)};var te=tinymce.util.Tools.resolve("tinymce.dom.RangeUtils"),ne=tinymce.util.Tools.resolve("tinymce.dom.TreeWalker"),oe=tinymce.util.Tools.resolve("tinymce.util.VK");const re=e=>b(e,U),se=Object.keys,ie=(e,t)=>{const n=se(e);for(let o=0,r=n.length;o{const n=e.dom;ie(t,((e,t)=>{((e,t,n)=>{if(!(o(n)||i(n)||d(n)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",n,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,n+"")})(n,t,e)}))},ae=e=>L(e.dom.attributes,((e,t)=>(e[t.name]=t.value,e)),{}),de=e=>((e,t)=>U(e.dom.cloneNode(!0)))(e),ce=(e,t)=>{const n=((e,t)=>{const n=R(t),o=ae(e);return le(n,o),n})(e,t);var o,r;r=n,(e=>g.from(e.dom.nextSibling).map(U))(o=e).fold((()=>{j(o).each((e=>{J(e,r)}))}),(e=>{G(e,r)}));const s=K(e);return X(n,s),ee(e),n};var me=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),ue=tinymce.util.Tools.resolve("tinymce.util.Tools");const pe=e=>t=>l(t)&&t.nodeName.toLowerCase()===e,ge=e=>t=>l(t)&&e.test(t.nodeName),he=e=>l(e)&&3===e.nodeType,fe=e=>l(e)&&1===e.nodeType,ye=ge(/^(OL|UL|DL)$/),ve=ge(/^(OL|UL)$/),Ce=pe("ol"),be=ge(/^(LI|DT|DD)$/),Se=ge(/^(DT|DD)$/),Ne=ge(/^(TH|TD)$/),Le=pe("br"),Oe=(e,t)=>l(t)&&t.nodeName in e.schema.getTextBlockElements(),Ae=(e,t)=>l(e)&&e.nodeName in t,xe=(e,t)=>l(t)&&t.nodeName in e.schema.getVoidElements(),ke=(e,t,n)=>{const o=e.isEmpty(t);return!(n&&e.select("span[data-mce-type=bookmark]",t).length>0)&&o},Te=(e,t)=>e.isChildOf(t,e.getRoot()),Ee=e=>t=>t.options.get(e),we=Ee("lists_indent_on_tab"),De=Ee("forced_root_block"),Be=Ee("forced_root_block_attrs"),Ie=(e,t)=>{const n=e.dom,o=e.schema.getBlockElements(),r=n.createFragment(),s=De(e),i=Be(e);let l,a,d=!1;for(a=n.create(s,i),Ae(t.firstChild,o)||r.appendChild(a);l=t.firstChild;){const e=l.nodeName;d||"SPAN"===e&&"bookmark"===l.getAttribute("data-mce-type")||(d=!0),Ae(l,o)?(r.appendChild(l),a=null):(a||(a=n.create(s,i),r.appendChild(a)),a.appendChild(l))}return!d&&a&&a.appendChild(n.create("br",{"data-mce-bogus":"1"})),r},Pe=me.DOM,Me=F("dd"),Re=F("dt"),Ue=(e,t)=>{var n;Me(t)?ce(t,"dt"):Re(t)&&(n=t,g.from(n.dom.parentElement).map(U)).each((n=>((e,t,n)=>{const o=Pe.select('span[data-mce-type="bookmark"]',t),r=Ie(e,n),s=Pe.createRng();s.setStartAfter(n),s.setEndAfter(t);const i=s.extractContents();for(let t=i.firstChild;t;t=t.firstChild)if("LI"===t.nodeName&&e.dom.isEmpty(t)){Pe.remove(t);break}e.dom.isEmpty(i)||Pe.insertAfter(i,t),Pe.insertAfter(r,t);const l=n.parentElement;l&&ke(e.dom,l)&&(e=>{const t=e.parentNode;t&&ue.each(o,(e=>{t.insertBefore(e,n.parentNode)})),Pe.remove(e)})(l),Pe.remove(n),ke(e.dom,t)&&Pe.remove(t)})(e,n.dom,t.dom)))},$e=e=>{Re(e)&&ce(e,"dd")},_e=(e,t)=>{if(he(e))return{container:e,offset:t};const n=te.getNode(e,t);return he(n)?{container:n,offset:t>=e.childNodes.length?n.data.length:0}:n.previousSibling&&he(n.previousSibling)?{container:n.previousSibling,offset:n.previousSibling.data.length}:n.nextSibling&&he(n.nextSibling)?{container:n.nextSibling,offset:0}:{container:e,offset:t}},He=e=>{const t=e.cloneRange(),n=_e(e.startContainer,e.startOffset);t.setStart(n.container,n.offset);const o=_e(e.endContainer,e.endOffset);return t.setEnd(o.container,o.offset),t},Ve=["OL","UL","DL"],Fe=Ve.join(","),je=(e,t)=>{const n=t||e.selection.getStart(!0);return e.dom.getParent(n,Fe,Qe(e,n))},Ke=e=>{const t=e.selection.getSelectedBlocks();return N(((e,t)=>{const n=ue.map(t,(t=>e.dom.getParent(t,"li,dd,dt",Qe(e,t))||t));return D(n)})(e,t),be)},ze=(e,t)=>{const n=e.dom.getParents(t,"TD,TH");return n.length>0?n[0]:e.getBody()},Qe=(e,t)=>{const n=e.dom.getParents(t,e.dom.isBlock),o=A(n,(t=>{return n=e.schema,!ye(o=t)&&!be(o)&&C(Ve,(e=>n.isValidChild(o.nodeName,e)));var n,o}));return o.getOr(e.getBody())},We=(e,t)=>{const n=e.dom.getParents(t,"ol,ul",Qe(e,t));return w(n)},qe=(e,t)=>{const n=b(t,(t=>We(e,t).getOr(t)));return D(n)},Ze=e=>/\btox\-/.test(e.className),Ge=(e,t)=>O(e,ye,Ne).exists((e=>e.nodeName===t&&!Ze(e))),Je=(e,t)=>null!==t&&!e.dom.isEditable(t),Xe=(e,t)=>{const n=e.dom.getParent(t,"ol,ul,dl");return Je(e,n)},Ye=(e,t)=>{const n=e.selection.getNode();return t({parents:e.dom.getParents(n),element:n}),e.on("NodeChange",t),()=>e.off("NodeChange",t)},et=(e,t)=>{const n=(t||document).createDocumentFragment();return S(e,(e=>{n.appendChild(e.dom)})),U(n)},tt=(e,t,n)=>e.dispatch("ListMutation",{action:t,element:n}),nt=(ot=/^\s+|\s+$/g,e=>e.replace(ot,""));var ot;const rt=(e,t,n)=>{((e,t,n)=>{if(!o(n))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",n,":: Element ",e),new Error("CSS value must be a string: "+n);(e=>void 0!==e.style&&a(e.style.getPropertyValue))(e)&&e.style.setProperty(t,n)})(e.dom,t,n)},st=e=>((e,t)=>{const n=e.dom;if(1!==n.nodeType)return!1;{const e=n;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}})(e,"OL,UL"),it=e=>Q(e).exists(st),lt=e=>"listAttributes"in e,at=e=>"isComment"in e,dt=e=>e.depth>0,ct=e=>e.isSelected,mt=e=>{const t=K(e),n=W(e).exists(st)?t.slice(0,-1):t;return b(n,de)},ut=(e,t)=>{J(e.item,t.list)},pt=(e,t)=>{const n={list:R(t,e),item:R("li",e)};return J(n.list,n.item),n},gt=(e,t,n)=>{const o=t.slice(0,n.depth);return w(o).each((t=>{if(lt(n)){const o=((e,t,n)=>{const o=R("li",e);return le(o,t),X(o,n),o})(e,n.itemAttributes,n.content);((e,t)=>{J(e.list,t),e.item=t})(t,o),((e,t)=>{_(e.list)!==t.listType&&(e.list=ce(e.list,t.listType)),le(e.list,t.listAttributes)})(t,n)}else if((e=>"isInPreviousLi"in e)(n)){if(n.isInPreviousLi){const o=((e,t,n,o)=>{const r=R(o,e);return le(r,t),X(r,n),r})(e,n.attributes,n.content,n.type);J(t.item,o)}}else{const e=M(`\x3c!--${n.content}--\x3e`);J(t.list,e)}})),o},ht=(e,t)=>{let n=g.none();const o=L(t,((t,o,r)=>lt(o)?o.depth>t.length?((e,t,n)=>{const o=((e,t,n)=>{const o=[];for(let r=0;r{for(let t=1;t{for(let t=0;t{le(e.list,t.listAttributes),le(e.item,t.itemAttributes),X(e.item,t.content)}))})(o,n),r=o,I(w(t),E(r),ut),t.concat(o)})(e,t,o):gt(e,t,o):0===r&&at(o)?(n=g.some(o),t):gt(e,t,o)),[]);return n.each((e=>{const t=M(`\x3c!--${e.content}--\x3e`);E(o).each((e=>{((e,t)=>{Q(e).fold((()=>{J(e,t)}),(n=>{e.dom.insertBefore(t.dom,n.dom)}))})(e.list,t)}))})),E(o).map((e=>e.list))},ft=e=>(S(e,((t,n)=>{((e,t)=>{const n=e[t].depth,o=e=>e.depth===n&&!e.dirty,r=e=>e.depthO(e.slice(t+1),o,r)))})(e,n).fold((()=>{t.dirty&<(t)&&(e=>{e.listAttributes=((e,t)=>{const n={};var o;return((e,t,n,o)=>{ie(e,((e,r)=>{(t(e,r)?n:o)(e,r)}))})(e,t,(o=n,(e,t)=>{o[t]=e}),c),n})(e.listAttributes,((e,t)=>"start"!==t))})(t)}),(e=>{return o=e,void(lt(n=t)&<(o)&&(n.listType=o.listType,n.listAttributes={...o.listAttributes}));var n,o}))})),e),yt=(e,t,n,o)=>{var r,s;if(8===H(s=o)||"#comment"===_(s))return[{depth:e+1,content:null!==(r=o.dom.nodeValue)&&void 0!==r?r:"",dirty:!1,isSelected:!1,isComment:!0}];t.each((e=>{$(e.start,o)&&n.set(!0)}));const i=((e,t,n)=>j(e).filter(V).map((o=>({depth:t,dirty:!1,isSelected:n,content:mt(e),itemAttributes:ae(e),listAttributes:ae(o),listType:_(o),isInPreviousLi:!1}))))(o,e,n.get());t.each((e=>{$(e.end,o)&&n.set(!1)}));const l=W(o).filter(st).map((o=>Ct(e,t,n,o))).getOr([]);return i.toArray().concat(l)},vt=(e,t,n,o)=>Q(o).filter(st).fold((()=>yt(e,t,n,o)),(r=>{const s=L(K(o),((o,r,s)=>{if(0===s)return o;{const s=yt(e,t,n,r).map((e=>((e,t,n)=>lt(e)?{depth:e.depth,dirty:e.dirty,content:e.content,isSelected:e.isSelected,type:t,attributes:e.itemAttributes,isInPreviousLi:!0}:e)(e,r.dom.nodeName.toLowerCase())));return o.concat(s)}}),[]);return Ct(e,t,n,r).concat(s)})),Ct=(e,t,n,o)=>x(K(o),(o=>(st(o)?Ct:vt)(e+1,t,n,o))),bt=(e,t,n)=>{const o=((e,t)=>{const n=(e=>{let t=!1;return{get:()=>t,set:e=>{t=e}}})();return b(e,(e=>({sourceList:e,entries:Ct(0,t,n,e)})))})(t,(e=>{const t=b(Ke(e),U);return I(A(t,u(it)),A(k(t),u(it)),((e,t)=>({start:e,end:t})))})(e));S(o,(t=>{((e,t)=>{S(N(e,ct),(e=>((e,t)=>{switch(e){case"Indent":t.depth++;break;case"Outdent":t.depth--;break;case"Flatten":t.depth=0}t.dirty=!0})(t,e)))})(t.entries,n);const o=((e,t)=>x(((e,t)=>{if(0===e.length)return[];{let n=t(e[0]);const o=[];let r=[];for(let s=0,i=e.length;sE(t).exists(dt)?((e,t)=>{const n=ft(t);return ht(e.contentDocument,n).toArray()})(e,t):((e,t)=>{const n=ft(t);return b(n,(t=>{const n=at(t)?et([M(`\x3c!--${t.content}--\x3e`)]):et(t.content);return U(Ie(e,n.dom))}))})(e,t))))(e,t.entries);var r;S(o,(t=>{tt(e,"Indent"===n?"IndentList":"OutdentList",t.dom)})),r=t.sourceList,S(o,(e=>{G(r,e)})),ee(t.sourceList)}))},St=(e,t)=>{const n=re((e=>{const t=(e=>{const t=We(e,e.selection.getStart()),n=N(e.selection.getSelectedBlocks(),ve);return t.toArray().concat(n)})(e),n=(e=>{const t=e.selection.getStart();return e.dom.getParents(t,"ol,ul",Qe(e,t))})(e);return A(n,(e=>{return t=U(e),j(t).exists((e=>be(e.dom)&&Q(e).exists((e=>!ye(e.dom)))&&W(e).exists((e=>!ye(e.dom)))));var t})).fold((()=>qe(e,t)),(e=>[e]))})(e)),o=re((e=>N(Ke(e),Se))(e));let r=!1;if(n.length||o.length){const s=e.selection.getBookmark();bt(e,n,t),((e,t,n)=>{S(n,"Indent"===t?$e:t=>Ue(e,t))})(e,t,o),e.selection.moveToBookmark(s),e.selection.setRng(He(e.selection.getRng())),e.nodeChanged(),r=!0}return r},Nt=(e,t)=>!(e=>{const t=je(e);return Je(e,t)})(e)&&St(e,t),Lt=e=>Nt(e,"Indent"),Ot=e=>Nt(e,"Outdent"),At=e=>Nt(e,"Flatten"),xt=e=>"\ufeff"===e;var kt=tinymce.util.Tools.resolve("tinymce.dom.BookmarkManager");const Tt=me.DOM,Et=e=>{const t={},n=n=>{let o=e[n?"startContainer":"endContainer"],r=e[n?"startOffset":"endOffset"];if(fe(o)){const e=Tt.create("span",{"data-mce-type":"bookmark"});o.hasChildNodes()?(r=Math.min(r,o.childNodes.length-1),n?o.insertBefore(e,o.childNodes[r]):Tt.insertAfter(e,o.childNodes[r])):o.appendChild(e),o=e,r=0}t[n?"startContainer":"endContainer"]=o,t[n?"startOffset":"endOffset"]=r};return n(!0),e.collapsed||n(),t},wt=e=>{const t=t=>{let n=e[t?"startContainer":"endContainer"],o=e[t?"startOffset":"endOffset"];if(n){if(fe(n)&&n.parentNode){const e=n;o=(e=>{var t;let n=null===(t=e.parentNode)||void 0===t?void 0:t.firstChild,o=0;for(;n;){if(n===e)return o;fe(n)&&"bookmark"===n.getAttribute("data-mce-type")||o++,n=n.nextSibling}return-1})(n),n=n.parentNode,Tt.remove(e),!n.hasChildNodes()&&Tt.isBlock(n)&&n.appendChild(Tt.create("br"))}e[t?"startContainer":"endContainer"]=n,e[t?"startOffset":"endOffset"]=o}};t(!0),t();const n=Tt.createRng();return n.setStart(e.startContainer,e.startOffset),e.endContainer&&n.setEnd(e.endContainer,e.endOffset),He(n)},Dt=e=>{switch(e){case"UL":return"ToggleUlList";case"OL":return"ToggleOlList";case"DL":return"ToggleDLList"}},Bt=(e,t)=>{ue.each(t,((t,n)=>{e.setAttribute(n,t)}))},It=(e,t,n)=>{((e,t,n)=>{const o=n["list-style-type"]?n["list-style-type"]:null;e.setStyle(t,"list-style-type",o)})(e,t,n),((e,t,n)=>{Bt(t,n["list-attributes"]),ue.each(e.select("li",t),(e=>{Bt(e,n["list-item-attributes"])}))})(e,t,n)},Pt=(e,t)=>l(t)&&!Ae(t,e.schema.getBlockElements()),Mt=(e,t,n,o)=>{let r=t[n?"startContainer":"endContainer"];const s=t[n?"startOffset":"endOffset"];fe(r)&&(r=r.childNodes[Math.min(s,r.childNodes.length-1)]||r),!n&&Le(r.nextSibling)&&(r=r.nextSibling);const i=(t,n)=>{var r;const s=new ne(t,(t=>{for(;!e.dom.isBlock(t)&&t.parentNode&&o!==t;)t=t.parentNode;return t})(t)),i=n?"next":"prev";let l;for(;l=s[i]();)if(!xe(e,l)&&!xt(l.textContent)&&0!==(null===(r=l.textContent)||void 0===r?void 0:r.length))return g.some(l);return g.none()};if(n&&he(r))if(xt(r.textContent))r=i(r,!1).getOr(r);else for(null!==r.parentNode&&Pt(e,r.parentNode)&&(r=r.parentNode);null!==r.previousSibling&&(Pt(e,r.previousSibling)||he(r.previousSibling));)r=r.previousSibling;if(!n&&he(r))if(xt(r.textContent))r=i(r,!0).getOr(r);else for(null!==r.parentNode&&Pt(e,r.parentNode)&&(r=r.parentNode);null!==r.nextSibling&&(Pt(e,r.nextSibling)||he(r.nextSibling));)r=r.nextSibling;for(;r.parentNode!==o;){const t=r.parentNode;if(Oe(e,r))return r;if(/^(TD|TH)$/.test(t.nodeName))return r;r=t}return r},Rt=(e,t,n)=>{const o=e.selection.getRng();let r="LI";const s=Qe(e,((e,t)=>{const n=e.selection.getStart(!0),o=Mt(e,t,!0,e.getBody());return r=U(o),s=U(t.commonAncestorContainer),i=r,l=function(e,...t){return(...n)=>{const o=t.concat(n);return e.apply(null,o)}}($,s),q(i,l,void 0).isSome()?t.commonAncestorContainer:n;var r,s,i,l})(e,o)),i=e.dom;if("false"===i.getContentEditable(e.selection.getNode()))return;"DL"===(t=t.toUpperCase())&&(r="DT");const l=Et(o),a=N(((e,t,n)=>{const o=[],r=e.dom,s=Mt(e,t,!0,n),i=Mt(e,t,!1,n);let l;const a=[];for(let e=s;e&&(a.push(e),e!==i);e=e.nextSibling);return ue.each(a,(t=>{var s;if(Oe(e,t))return o.push(t),void(l=null);if(r.isBlock(t)||Le(t))return Le(t)&&r.remove(t),void(l=null);const i=t.nextSibling;kt.isBookmarkNode(t)&&(ye(i)||Oe(e,i)||!i&&t.parentNode===n)?l=null:(l||(l=r.create("p"),null===(s=t.parentNode)||void 0===s||s.insertBefore(l,t),o.push(l)),l.appendChild(t))})),o})(e,o,s),e.dom.isEditable);ue.each(a,(o=>{let s;const l=o.previousSibling,a=o.parentNode;be(a)||(l&&ye(l)&&l.nodeName===t&&((e,t,n)=>{const o=e.getStyle(t,"list-style-type");let r=n?n["list-style-type"]:"";return r=null===r?"":r,o===r})(i,l,n)?(s=l,o=i.rename(o,r),l.appendChild(o)):(s=i.create(t),a.insertBefore(s,o),s.appendChild(o),o=i.rename(o,r)),((e,t,n)=>{ue.each(["margin","margin-right","margin-bottom","margin-left","margin-top","padding","padding-right","padding-bottom","padding-left","padding-top"],(n=>e.setStyle(t,n,"")))})(i,o),It(i,s,n),$t(e.dom,s))})),e.selection.setRng(wt(l))},Ut=(e,t,n)=>{return((e,t)=>ye(e)&&e.nodeName===(null==t?void 0:t.nodeName))(t,n)&&((e,t,n)=>e.getStyle(t,"list-style-type",!0)===e.getStyle(n,"list-style-type",!0))(e,t,n)&&(o=n,t.className===o.className);var o},$t=(e,t)=>{let n,o=t.nextSibling;if(Ut(e,t,o)){const r=o;for(;n=r.firstChild;)t.appendChild(n);e.remove(r)}if(o=t.previousSibling,Ut(e,t,o)){const r=o;for(;n=r.lastChild;)t.insertBefore(n,t.firstChild);e.remove(r)}},_t=(e,t,n,o)=>{if(t.nodeName!==n){const r=e.dom.rename(t,n);It(e.dom,r,o),tt(e,Dt(n),r)}else It(e.dom,t,o),tt(e,Dt(n),t)},Ht=(e,t,n,o)=>{if(t.classList.forEach(((e,n,o)=>{e.startsWith("tox-")&&(o.remove(e),0===o.length&&t.removeAttribute("class"))})),t.nodeName!==n){const r=e.dom.rename(t,n);It(e.dom,r,o),tt(e,Dt(n),r)}else It(e.dom,t,o),tt(e,Dt(n),t)},Vt=e=>"list-style-type"in e,Ft=(e,t,n)=>{const o=je(e);if(Xe(e,o))return;const s=(e=>{const t=je(e),n=e.selection.getSelectedBlocks();return((e,t)=>l(e)&&1===t.length&&t[0]===e)(t,n)?(e=>N(e.querySelectorAll(Fe),ye))(t):N(n,(e=>ye(e)&&t!==e))})(e),i=r(n)?n:{};s.length>0?((e,t,n,o,r)=>{const s=ye(t);if(!s||t.nodeName!==o||Vt(r)||Ze(t)){Rt(e,o,r);const i=Et(e.selection.getRng()),l=s?[t,...n]:n,a=s&&Ze(t)?Ht:_t;ue.each(l,(t=>{a(e,t,o,r)})),e.selection.setRng(wt(i))}else At(e)})(e,o,s,t,i):((e,t,n,o)=>{if(t!==e.getBody())if(t)if(t.nodeName!==n||Vt(o)||Ze(t)){const r=Et(e.selection.getRng());Ze(t)&&t.classList.forEach(((e,n,o)=>{e.startsWith("tox-")&&(o.remove(e),0===o.length&&t.removeAttribute("class"))})),It(e.dom,t,o);const s=e.dom.rename(t,n);$t(e.dom,s),e.selection.setRng(wt(r)),Rt(e,n,o),tt(e,Dt(n),s)}else At(e);else Rt(e,n,o),tt(e,Dt(n),t)})(e,o,t,i)},jt=me.DOM,Kt=(e,t)=>{const n=ue.grep(e.select("ol,ul",t));ue.each(n,(t=>{((e,t)=>{const n=t.parentElement;if(n&&"LI"===n.nodeName&&n.firstChild===t){const o=n.previousSibling;o&&"LI"===o.nodeName?(o.appendChild(t),ke(e,n)&&jt.remove(n)):jt.setStyle(n,"listStyleType","none")}if(ye(n)){const e=n.previousSibling;e&&"LI"===e.nodeName&&e.appendChild(t)}})(e,t)}))},zt=(e,t,n,o)=>{let r=t.startContainer;const s=t.startOffset;if(he(r)&&(n?s0))return r;const i=e.schema.getNonEmptyElements();fe(r)&&(r=te.getNode(r,s));const l=new ne(r,o);n&&((e,t)=>!!Le(t)&&e.isBlock(t.nextSibling)&&!Le(t.previousSibling))(e.dom,r)&&l.next();const a=n?l.next.bind(l):l.prev2.bind(l);for(;r=a();){if("LI"===r.nodeName&&!r.hasChildNodes())return r;if(i[r.nodeName])return r;if(he(r)&&r.data.length>0)return r}return null},Qt=(e,t)=>{const n=t.childNodes;return 1===n.length&&!ye(n[0])&&e.isBlock(n[0])},Wt=(e,t,n)=>{let o;const r=t.parentNode;if(!Te(e,t)||!Te(e,n))return;ye(n.lastChild)&&(o=n.lastChild),r===n.lastChild&&Le(r.previousSibling)&&e.remove(r.previousSibling);const s=n.lastChild;s&&Le(s)&&t.hasChildNodes()&&e.remove(s),ke(e,n,!0)&&Y(U(n)),((e,t,n)=>{let o;const r=Qt(e,n)?n.firstChild:n;if(((e,t)=>{Qt(e,t)&&e.remove(t.firstChild,!0)})(e,t),!ke(e,t,!0))for(;o=t.firstChild;)r.appendChild(o)})(e,t,n),o&&n.appendChild(o);const i=((e,t)=>{const n=e.dom,o=t.dom;return n!==o&&n.contains(o)})(U(n),U(t))?e.getParents(t,ye,n):[];e.remove(t),S(i,(t=>{ke(e,t)&&t!==e.getRoot()&&e.remove(t)}))},qt=(e,t)=>{const n=e.dom,o=e.selection,r=o.getStart(),s=ze(e,r),i=n.getParent(o.getStart(),"LI",s);if(i){const r=i.parentElement;if(r===e.getBody()&&ke(n,r))return!0;const l=He(o.getRng()),a=n.getParent(zt(e,l,t,s),"LI",s);if(a&&a!==i)return e.undoManager.transact((()=>{var n,o;t?((e,t,n,o)=>{const r=e.dom;if(r.isEmpty(o))((e,t,n)=>{Y(U(n)),Wt(e.dom,t,n),e.selection.setCursorLocation(n,0)})(e,n,o);else{const s=Et(t);Wt(r,n,o),e.selection.setRng(wt(s))}})(e,l,a,i):(null===(o=(n=i).parentNode)||void 0===o?void 0:o.firstChild)===n?Ot(e):((e,t,n,o)=>{const r=Et(t);Wt(e.dom,n,o);const s=wt(r);e.selection.setRng(s)})(e,l,i,a)})),!0;if(!a&&!t&&0===l.startOffset&&0===l.endOffset)return e.undoManager.transact((()=>{At(e)})),!0}return!1},Zt=e=>{const t=e.selection.getStart(),n=ze(e,t);return e.dom.getParent(t,"LI,DT,DD",n)||Ke(e).length>0},Gt=(e,t)=>{const n=e.selection;return!Xe(e,n.getNode())&&(n.isCollapsed()?((e,t)=>qt(e,t)||((e,t)=>{const n=e.dom,o=e.selection.getStart(),r=ze(e,o),s=n.getParent(o,n.isBlock,r);if(s&&n.isEmpty(s)){const o=He(e.selection.getRng()),i=n.getParent(zt(e,o,t,r),"LI",r);if(i){const l=e=>v(["td","th","caption"],_(e)),a=e=>e.dom===r;return!!((e,t,n=m)=>I(e,t,n).getOr(e.isNone()&&t.isNone()))(Z(U(i),l,a),Z(U(o.startContainer),l,a),$)&&(e.undoManager.transact((()=>{const o=i.parentNode;((e,t,n)=>{const o=e.getParent(t.parentNode,e.isBlock,n);e.remove(t),o&&e.isEmpty(o)&&e.remove(o)})(n,s,r),$t(n,o),e.selection.select(i,!0),e.selection.collapse(t)})),!0)}}return!1})(e,t))(e,t):(e=>!!Zt(e)&&(e.undoManager.transact((()=>{e.execCommand("Delete"),Kt(e.dom,e.getBody())})),!0))(e))},Jt=e=>{const t=k(nt(e).split("")),n=b(t,((e,t)=>{const n=e.toUpperCase().charCodeAt(0)-"A".charCodeAt(0)+1;return Math.pow(26,t)*n}));return L(n,((e,t)=>e+t),0)},Xt=e=>{if(--e<0)return"";{const t=e%26,n=Math.floor(e/26);return Xt(n)+String.fromCharCode("A".charCodeAt(0)+t)}},Yt=e=>{const t=parseInt(e.start,10);return B(e.listStyleType,"upper-alpha")?Xt(t):B(e.listStyleType,"lower-alpha")?Xt(t).toLowerCase():e.start},en=(e,t)=>()=>{const n=je(e);return l(n)&&n.nodeName===t},tn=e=>{e.addCommand("mceListProps",(()=>{(e=>{const t=je(e);Ce(t)&&!Xe(e,t)&&e.windowManager.open({title:"List Properties",body:{type:"panel",items:[{type:"input",name:"start",label:"Start list at number",inputMode:"numeric"}]},initialData:{start:Yt({start:e.dom.getAttrib(t,"start","1"),listStyleType:g.from(e.dom.getStyle(t,"list-style-type"))})},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],onSubmit:t=>{(e=>{switch((e=>/^[0-9]+$/.test(e)?2:/^[A-Z]+$/.test(e)?0:/^[a-z]+$/.test(e)?1:e.length>0?4:3)(e)){case 2:return g.some({listStyleType:g.none(),start:e});case 0:return g.some({listStyleType:g.some("upper-alpha"),start:Jt(e).toString()});case 1:return g.some({listStyleType:g.some("lower-alpha"),start:Jt(e).toString()});case 3:return g.some({listStyleType:g.none(),start:""});case 4:return g.none()}})(t.getData().start).each((t=>{e.execCommand("mceListUpdate",!1,{attrs:{start:"1"===t.start?"":t.start},styles:{"list-style-type":t.listStyleType.getOr("")}})})),t.close()}})})(e)}))};var nn=tinymce.util.Tools.resolve("tinymce.html.Node");const on=e=>3===e.type,rn=e=>0===e.length,sn=e=>{const t=(t,n)=>{const o=nn.create("li");S(t,(e=>o.append(e))),n?e.insert(o,n,!0):e.append(o)},n=L(e.children(),((e,n)=>on(n)?[...e,n]:rn(e)||on(n)?e:(t(e,n),[])),[]);rn(n)||t(n)},ln=(e,t)=>n=>(n.setEnabled(e.selection.isEditable()),Ye(e,(o=>{n.setActive(Ge(o.parents,t)),n.setEnabled(!Xe(e,o.element)&&e.selection.isEditable())}))),an=(e,t)=>n=>Ye(e,(o=>n.setEnabled(Ge(o.parents,t)&&!Xe(e,o.element))));e.add("lists",(e=>((e=>{(0,e.options.register)("lists_indent_on_tab",{processor:"boolean",default:!0})})(e),(e=>{e.on("PreInit",(()=>{const{parser:t}=e;t.addNodeFilter("ul,ol",(e=>S(e,sn)))}))})(e),e.hasPlugin("rtc",!0)?tn(e):((e=>{we(e)&&(e=>{e.on("keydown",(t=>{t.keyCode!==oe.TAB||oe.metaKeyPressed(t)||e.undoManager.transact((()=>{(t.shiftKey?Ot(e):Lt(e))&&t.preventDefault()}))}))})(e),(e=>{e.on("ExecCommand",(t=>{const n=t.command.toLowerCase();"delete"!==n&&"forwarddelete"!==n||!Zt(e)||Kt(e.dom,e.getBody())})),e.on("keydown",(t=>{t.keyCode===oe.BACKSPACE?Gt(e,!1)&&t.preventDefault():t.keyCode===oe.DELETE&&Gt(e,!0)&&t.preventDefault()}))})(e)})(e),(e=>{e.on("BeforeExecCommand",(t=>{const n=t.command.toLowerCase();"indent"===n?Lt(e):"outdent"===n&&Ot(e)})),e.addCommand("InsertUnorderedList",((t,n)=>{Ft(e,"UL",n)})),e.addCommand("InsertOrderedList",((t,n)=>{Ft(e,"OL",n)})),e.addCommand("InsertDefinitionList",((t,n)=>{Ft(e,"DL",n)})),e.addCommand("RemoveList",(()=>{At(e)})),tn(e),e.addCommand("mceListUpdate",((t,n)=>{r(n)&&((e,t)=>{const n=je(e);null===n||Xe(e,n)||e.undoManager.transact((()=>{r(t.styles)&&e.dom.setStyles(n,t.styles),r(t.attrs)&&ie(t.attrs,((t,o)=>e.dom.setAttrib(n,o,t)))}))})(e,n)})),e.addQueryStateHandler("InsertUnorderedList",en(e,"UL")),e.addQueryStateHandler("InsertOrderedList",en(e,"OL")),e.addQueryStateHandler("InsertDefinitionList",en(e,"DL"))})(e)),(e=>{const t=t=>()=>e.execCommand(t);e.hasPlugin("advlist")||(e.ui.registry.addToggleButton("numlist",{icon:"ordered-list",active:!1,tooltip:"Numbered list",onAction:t("InsertOrderedList"),onSetup:ln(e,"OL")}),e.ui.registry.addToggleButton("bullist",{icon:"unordered-list",active:!1,tooltip:"Bullet list",onAction:t("InsertUnorderedList"),onSetup:ln(e,"UL")}))})(e),(e=>{const t={text:"List properties...",icon:"ordered-list",onAction:()=>e.execCommand("mceListProps"),onSetup:an(e,"OL")};e.ui.registry.addMenuItem("listprops",t),e.ui.registry.addContextMenu("lists",{update:t=>{const n=je(e,t);return Ce(n)?["listprops"]:[]}})})(e),(e=>({backspaceDelete:t=>{Gt(e,t)}}))(e))))}(); \ No newline at end of file diff --git a/public/libs/tinymce/plugins/media/plugin.min.js b/public/libs/tinymce/plugins/media/plugin.min.js index 7229267d3..f9b72e957 100644 --- a/public/libs/tinymce/plugins/media/plugin.min.js +++ b/public/libs/tinymce/plugins/media/plugin.min.js @@ -1,4 +1,4 @@ /** - * TinyMCE version 6.5.1 (2023-06-19) + * TinyMCE version 6.7.2 (2023-10-25) */ -!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(r=o=e,(a=String).prototype.isPrototypeOf(r)||(null===(s=o.constructor)||void 0===s?void 0:s.name)===a.name)?"string":t;var r,o,a,s})(t)===e,r=t("string"),o=t("object"),a=t("array"),s=e=>!(e=>null==e)(e);class i{constructor(e,t){this.tag=e,this.value=t}static some(e){return new i(!0,e)}static none(){return i.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?i.some(e(this.value)):i.none()}bind(e){return this.tag?e(this.value):i.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:i.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return s(e)?i.some(e):i.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}i.singletonNone=new i(!1);const n=Array.prototype.push,c=(e,t)=>{for(let r=0,o=e.length;r{const t=[];for(let r=0,o=e.length;rh(e,t)?i.from(e[t]):i.none(),h=(e,t)=>u.call(e,t),p=e=>t=>t.options.get(e),g=p("audio_template_callback"),b=p("video_template_callback"),w=p("iframe_template_callback"),v=p("media_live_embeds"),y=p("media_filter_html"),f=p("media_url_resolver"),x=p("media_alt_source"),_=p("media_poster"),j=p("media_dimensions");var k=tinymce.util.Tools.resolve("tinymce.util.Tools"),O=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),A=tinymce.util.Tools.resolve("tinymce.html.DomParser");const S=O.DOM,$=e=>e.replace(/px$/,""),C=e=>{const t=e.attr("style"),r=t?S.parseStyle(t):{};return{type:"ephox-embed-iri",source:e.attr("data-ephox-embed-iri"),altsource:"",poster:"",width:d(r,"max-width").map($).getOr(""),height:d(r,"max-height").map($).getOr("")}},D=(e,t)=>{let r={};for(let o=A({validate:!1,forced_root_block:!1},t).parse(e);o;o=o.walk())if(1===o.type){const e=o.name;if(o.attr("data-ephox-embed-iri")){r=C(o);break}r.source||"param"!==e||(r.source=o.attr("movie")),"iframe"!==e&&"object"!==e&&"embed"!==e&&"video"!==e&&"audio"!==e||(r.type||(r.type=e),r=k.extend(o.attributes.map,r)),"script"===e&&(r={type:"script",source:o.attr("src")}),"source"===e&&(r.source?r.altsource||(r.altsource=o.attr("src")):r.source=o.attr("src")),"img"!==e||r.poster||(r.poster=o.attr("src"))}return r.source=r.source||r.src||"",r.altsource=r.altsource||"",r.poster=r.poster||"",r},T=e=>{var t;const r=null!==(t=e.toLowerCase().split(".").pop())&&void 0!==t?t:"";return d({mp3:"audio/mpeg",m4a:"audio/x-m4a",wav:"audio/wav",mp4:"video/mp4",webm:"video/webm",ogg:"video/ogg",swf:"application/x-shockwave-flash"},r).getOr("")};var z=tinymce.util.Tools.resolve("tinymce.html.Node"),F=tinymce.util.Tools.resolve("tinymce.html.Serializer");const M=(e,t={})=>A({forced_root_block:!1,validate:!1,allow_conditional_comments:!0,...t},e),N=O.DOM,R=e=>/^[0-9.]+$/.test(e)?e+"px":e,E=(e,t)=>{const r=t.attr("style"),o=r?N.parseStyle(r):{};s(e.width)&&(o["max-width"]=R(e.width)),s(e.height)&&(o["max-height"]=R(e.height)),t.attr("style",N.serializeStyle(o))},U=["source","altsource"],P=(e,t,r,o)=>{let a=0,s=0;const i=M(o);i.addNodeFilter("source",(e=>a=e.length));const n=i.parse(e);for(let e=n;e;e=e.walk())if(1===e.type){const o=e.name;if(e.attr("data-ephox-embed-iri")){E(t,e);break}switch(o){case"video":case"object":case"embed":case"img":case"iframe":void 0!==t.height&&void 0!==t.width&&(e.attr("width",t.width),e.attr("height",t.height))}if(r)switch(o){case"video":e.attr("poster",t.poster),e.attr("src",null);for(let r=a;r<2;r++)if(t[U[r]]){const o=new z("source",1);o.attr("src",t[U[r]]),o.attr("type",t[U[r]+"mime"]||null),e.append(o)}break;case"iframe":e.attr("src",t.source);break;case"object":const r=e.getAll("img").length>0;if(t.poster&&!r){e.attr("src",t.poster);const r=new z("img",1);r.attr("src",t.poster),r.attr("width",t.width),r.attr("height",t.height),e.append(r)}break;case"source":if(s<2&&(e.attr("src",t[U[s]]),e.attr("type",t[U[s]+"mime"]||null),!t[U[s]])){e.remove();continue}s++;break;case"img":t.poster||e.remove()}}return F({},o).serialize(n)},L=[{regex:/youtu\.be\/([\w\-_\?&=.]+)/i,type:"iframe",w:560,h:314,url:"www.youtube.com/embed/$1",allowFullscreen:!0},{regex:/youtube\.com(.+)v=([^&]+)(&([a-z0-9&=\-_]+))?/i,type:"iframe",w:560,h:314,url:"www.youtube.com/embed/$2?$4",allowFullscreen:!0},{regex:/youtube.com\/embed\/([a-z0-9\?&=\-_]+)/i,type:"iframe",w:560,h:314,url:"www.youtube.com/embed/$1",allowFullscreen:!0},{regex:/vimeo\.com\/([0-9]+)\?h=(\w+)/,type:"iframe",w:425,h:350,url:"player.vimeo.com/video/$1?h=$2&title=0&byline=0&portrait=0&color=8dc7dc",allowFullscreen:!0},{regex:/vimeo\.com\/(.*)\/([0-9]+)\?h=(\w+)/,type:"iframe",w:425,h:350,url:"player.vimeo.com/video/$2?h=$3&title=0&byline=0",allowFullscreen:!0},{regex:/vimeo\.com\/([0-9]+)/,type:"iframe",w:425,h:350,url:"player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc",allowFullscreen:!0},{regex:/vimeo\.com\/(.*)\/([0-9]+)/,type:"iframe",w:425,h:350,url:"player.vimeo.com/video/$2?title=0&byline=0",allowFullscreen:!0},{regex:/maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/,type:"iframe",w:425,h:350,url:'maps.google.com/maps/ms?msid=$2&output=embed"',allowFullscreen:!1},{regex:/dailymotion\.com\/video\/([^_]+)/,type:"iframe",w:480,h:270,url:"www.dailymotion.com/embed/video/$1",allowFullscreen:!0},{regex:/dai\.ly\/([^_]+)/,type:"iframe",w:480,h:270,url:"www.dailymotion.com/embed/video/$1",allowFullscreen:!0}],I=(e,t)=>{const r=(e=>{const t=e.match(/^(https?:\/\/|www\.)(.+)$/i);return t&&t.length>1?"www."===t[1]?"https://":t[1]:"https://"})(t),o=e.regex.exec(t);let a=r+e.url;if(s(o))for(let e=0;eo[e]?o[e]:""));return a.replace(/\?$/,"")},B=e=>{const t=L.filter((t=>t.regex.test(e)));return t.length>0?k.extend({},t[0],{url:I(t[0],e)}):null},G=(e,t)=>{var r;const o=k.extend({},t);if(!o.source&&(k.extend(o,D(null!==(r=o.embed)&&void 0!==r?r:"",e.schema)),!o.source))return"";o.altsource||(o.altsource=""),o.poster||(o.poster=""),o.source=e.convertURL(o.source,"source"),o.altsource=e.convertURL(o.altsource,"source"),o.sourcemime=T(o.source),o.altsourcemime=T(o.altsource),o.poster=e.convertURL(o.poster,"poster");const a=B(o.source);if(a&&(o.source=a.url,o.type=a.type,o.allowfullscreen=a.allowFullscreen,o.width=o.width||String(a.w),o.height=o.height||String(a.h)),o.embed)return P(o.embed,o,!0,e.schema);{const t=g(e),r=b(e),a=w(e);return o.width=o.width||"300",o.height=o.height||"150",k.each(o,((t,r)=>{o[r]=e.dom.encode(""+t)})),"iframe"===o.type?((e,t)=>{if(t)return t(e);{const t=e.allowfullscreen?' allowFullscreen="1"':"";return'"}})(o,a):"application/x-shockwave-flash"===o.sourcemime?(e=>{let t='';return e.poster&&(t+=''),t+="",t})(o):-1!==o.sourcemime.indexOf("audio")?((e,t)=>t?t(e):'")(o,t):"script"===o.type?(e=>' +@endpush {{ csrf_field() }}
    @@ -6,8 +9,8 @@
    - - @include('form.textarea', ['name' => 'description']) + + @include('form.description-html-input')
    @@ -35,7 +38,33 @@
    +
    + +
    +
    +

    + {{ trans('entities.books_default_template_explain') }} +

    + +
    + @include('form.page-picker', [ + 'name' => 'default_template_id', + 'placeholder' => trans('entities.books_default_template_select'), + 'value' => $book->default_template_id ?? null, + 'selectorEndpoint' => '/search/entity-selector-templates', + ]) +
    +
    + +
    +
    +
    {{ trans('common.cancel') }} -
    \ No newline at end of file + + +@include('entities.selector-popup') +@include('form.editor-translations') \ No newline at end of file diff --git a/resources/views/books/show.blade.php b/resources/views/books/show.blade.php index 8f7c3f6cf..dbb09fc9e 100644 --- a/resources/views/books/show.blade.php +++ b/resources/views/books/show.blade.php @@ -26,7 +26,7 @@

    {{$book->name}}

    -

    {!! nl2br(e($book->description)) !!}

    +
    {!! $book->descriptionHtml() !!}
    @if(count($bookChildren) > 0)
    @foreach($bookChildren as $childElement) diff --git a/resources/views/chapters/parts/form.blade.php b/resources/views/chapters/parts/form.blade.php index 8abcebe13..c6052c93a 100644 --- a/resources/views/chapters/parts/form.blade.php +++ b/resources/views/chapters/parts/form.blade.php @@ -1,14 +1,16 @@ +@push('head') + +@endpush -{!! csrf_field() !!} - +{{ csrf_field() }}
    @include('form.text', ['name' => 'name', 'autofocus' => true])
    - - @include('form.textarea', ['name' => 'description']) + + @include('form.description-html-input')
    @@ -24,3 +26,6 @@ {{ trans('common.cancel') }}
    + +@include('entities.selector-popup') +@include('form.editor-translations') \ No newline at end of file diff --git a/resources/views/chapters/show.blade.php b/resources/views/chapters/show.blade.php index 0e5224d54..45e43ad96 100644 --- a/resources/views/chapters/show.blade.php +++ b/resources/views/chapters/show.blade.php @@ -24,7 +24,7 @@

    {{ $chapter->name }}

    -

    {!! nl2br(e($chapter->description)) !!}

    +
    {!! $chapter->descriptionHtml() !!}
    @if(count($pages) > 0)
    @foreach($pages as $page) diff --git a/resources/views/common/dark-mode-toggle.blade.php b/resources/views/common/dark-mode-toggle.blade.php index d6ecbc4d6..531755109 100644 --- a/resources/views/common/dark-mode-toggle.blade.php +++ b/resources/views/common/dark-mode-toggle.blade.php @@ -1,6 +1,7 @@
    {{ csrf_field() }} {{ method_field('patch') }} + @if(setting()->getForCurrentUser('dark-mode-enabled')) @else diff --git a/resources/views/common/sort.blade.php b/resources/views/common/sort.blade.php index 29dfa60a1..e5336d3a2 100644 --- a/resources/views/common/sort.blade.php +++ b/resources/views/common/sort.blade.php @@ -13,6 +13,7 @@ method="post" @endif > + @if($useQuery ?? false) @foreach(array_filter(request()->except(['sort', 'order'])) as $key => $value) diff --git a/resources/views/entities/meta.blade.php b/resources/views/entities/meta.blade.php index 2298be8bb..9d3c4b956 100644 --- a/resources/views/entities/meta.blade.php +++ b/resources/views/entities/meta.blade.php @@ -64,7 +64,7 @@ @icon('reference')
    - {!! trans_choice('entities.meta_reference_page_count', $referenceCount, ['count' => $referenceCount]) !!} + {{ trans_choice('entities.meta_reference_count', $referenceCount, ['count' => $referenceCount]) }}
    @endif diff --git a/resources/views/entities/selector-popup.blade.php b/resources/views/entities/selector-popup.blade.php index c896b50b5..ac91725d6 100644 --- a/resources/views/entities/selector-popup.blade.php +++ b/resources/views/entities/selector-popup.blade.php @@ -5,9 +5,9 @@
    - @include('entities.selector', ['name' => 'entity-selector']) + @include('entities.selector', ['name' => 'entity-selector', 'selectorEndpoint' => ''])
    diff --git a/resources/views/entities/selector.blade.php b/resources/views/entities/selector.blade.php index a9f5b932c..c1280cfb2 100644 --- a/resources/views/entities/selector.blade.php +++ b/resources/views/entities/selector.blade.php @@ -3,7 +3,8 @@ refs="entity-selector-popup@selector" class="entity-selector {{$selectorSize ?? ''}}" option:entity-selector:entity-types="{{ $entityTypes ?? 'book,chapter,page' }}" - option:entity-selector:entity-permission="{{ $entityPermission ?? 'view' }}"> + option:entity-selector:entity-permission="{{ $entityPermission ?? 'view' }}" + option:entity-selector:search-endpoint="{{ $selectorEndpoint ?? '/search/entity-selector' }}">
    @include('common.loading-icon')
    diff --git a/resources/views/entities/view-toggle.blade.php b/resources/views/entities/view-toggle.blade.php index 7546e230f..9d64e09c3 100644 --- a/resources/views/entities/view-toggle.blade.php +++ b/resources/views/entities/view-toggle.blade.php @@ -1,7 +1,8 @@
    - {!! csrf_field() !!} - {!! method_field('PATCH') !!} + {{ csrf_field() }} + {{ method_field('patch') }} + @if ($view === 'list') @else @endif diff --git a/resources/views/exports/book.blade.php b/resources/views/exports/book.blade.php index 42e03ea01..9de7b8eba 100644 --- a/resources/views/exports/book.blade.php +++ b/resources/views/exports/book.blade.php @@ -5,7 +5,7 @@ @section('content')

    {{$book->name}}

    -

    {{ $book->description }}

    +
    {!! $book->descriptionHtml() !!}
    @include('exports.parts.book-contents-menu', ['children' => $bookChildren]) diff --git a/resources/views/exports/chapter.blade.php b/resources/views/exports/chapter.blade.php index ae49fa918..515366d60 100644 --- a/resources/views/exports/chapter.blade.php +++ b/resources/views/exports/chapter.blade.php @@ -5,7 +5,7 @@ @section('content')

    {{$chapter->name}}

    -

    {{ $chapter->description }}

    +
    {!! $chapter->descriptionHtml() !!}
    @include('exports.parts.chapter-contents-menu', ['pages' => $pages]) diff --git a/resources/views/exports/parts/chapter-item.blade.php b/resources/views/exports/parts/chapter-item.blade.php index f58068b5e..fa0b1f228 100644 --- a/resources/views/exports/parts/chapter-item.blade.php +++ b/resources/views/exports/parts/chapter-item.blade.php @@ -1,7 +1,7 @@

    {{ $chapter->name }}

    -

    {{ $chapter->description }}

    +
    {!! $chapter->descriptionHtml() !!}
    @if(count($chapter->visible_pages) > 0) @foreach($chapter->visible_pages as $page) diff --git a/resources/views/form/description-html-input.blade.php b/resources/views/form/description-html-input.blade.php new file mode 100644 index 000000000..3cf726ba4 --- /dev/null +++ b/resources/views/form/description-html-input.blade.php @@ -0,0 +1,8 @@ + +@if($errors->has('description_html')) +
    {{ $errors->first('description_html') }}
    +@endif \ No newline at end of file diff --git a/resources/views/pages/parts/editor-translations.blade.php b/resources/views/form/editor-translations.blade.php similarity index 100% rename from resources/views/pages/parts/editor-translations.blade.php rename to resources/views/form/editor-translations.blade.php diff --git a/resources/views/form/page-picker.blade.php b/resources/views/form/page-picker.blade.php new file mode 100644 index 000000000..ad0a9d516 --- /dev/null +++ b/resources/views/form/page-picker.blade.php @@ -0,0 +1,14 @@ + +{{--Depends on entity selector popup--}} +
    + +
    + + + + +
    \ No newline at end of file diff --git a/resources/views/layouts/export.blade.php b/resources/views/layouts/export.blade.php index eb2397a75..4a55e034c 100644 --- a/resources/views/layouts/export.blade.php +++ b/resources/views/layouts/export.blade.php @@ -13,7 +13,7 @@ @include('layouts.parts.export-body-start') -
    +
    @yield('content')
    @include('layouts.parts.export-body-end') diff --git a/resources/views/layouts/parts/header-user-menu.blade.php b/resources/views/layouts/parts/header-user-menu.blade.php index 0440e43d0..db4820a4d 100644 --- a/resources/views/layouts/parts/header-user-menu.blade.php +++ b/resources/views/layouts/parts/header-user-menu.blade.php @@ -29,8 +29,14 @@

  • - + @php + $logoutPath = match (config('auth.method')) { + 'saml2' => '/saml2/logout', + 'oidc' => '/oidc/logout', + default => '/logout', + } + @endphp + {{ csrf_field() }} - +
  • diff --git a/resources/views/pages/parts/wysiwyg-editor.blade.php b/resources/views/pages/parts/wysiwyg-editor.blade.php index ca6b6da8a..84a267b68 100644 --- a/resources/views/pages/parts/wysiwyg-editor.blade.php +++ b/resources/views/pages/parts/wysiwyg-editor.blade.php @@ -18,4 +18,4 @@
    {{ $errors->first('html') }}
    @endif -@include('pages.parts.editor-translations') \ No newline at end of file +@include('form.editor-translations') \ No newline at end of file diff --git a/resources/views/settings/customization.blade.php b/resources/views/settings/customization.blade.php index be99cc254..4845e2055 100644 --- a/resources/views/settings/customization.blade.php +++ b/resources/views/settings/customization.blade.php @@ -3,7 +3,7 @@ @section('card')

    {{ trans('settings.app_customization') }}

    - {!! csrf_field() !!} + {{ csrf_field() }}
    @@ -133,7 +133,12 @@
    @@ -168,5 +173,5 @@ @endsection @section('after-content') - @include('entities.selector-popup', ['entityTypes' => 'page']) + @include('entities.selector-popup') @endsection diff --git a/resources/views/settings/parts/page-picker.blade.php b/resources/views/settings/parts/page-picker.blade.php deleted file mode 100644 index d599a19ab..000000000 --- a/resources/views/settings/parts/page-picker.blade.php +++ /dev/null @@ -1,13 +0,0 @@ - -{{--Depends on entity selector popup--}} -
    - -
    - - - - -
    \ No newline at end of file diff --git a/resources/views/shelves/parts/form.blade.php b/resources/views/shelves/parts/form.blade.php index ad67cb85c..a75dd6ac1 100644 --- a/resources/views/shelves/parts/form.blade.php +++ b/resources/views/shelves/parts/form.blade.php @@ -1,13 +1,16 @@ -{{ csrf_field() }} +@push('head') + +@endpush +{{ csrf_field() }}
    @include('form.text', ['name' => 'name', 'autofocus' => true])
    - - @include('form.textarea', ['name' => 'description']) + + @include('form.description-html-input')
    @@ -84,4 +87,7 @@
    {{ trans('common.cancel') }} -
    \ No newline at end of file +
    + +@include('entities.selector-popup') +@include('form.editor-translations') \ No newline at end of file diff --git a/resources/views/shelves/show.blade.php b/resources/views/shelves/show.blade.php index 58fe1cd86..11baccaf4 100644 --- a/resources/views/shelves/show.blade.php +++ b/resources/views/shelves/show.blade.php @@ -28,7 +28,7 @@
    -

    {!! nl2br(e($shelf->description)) !!}

    +
    {!! $shelf->descriptionHtml() !!}
    @if(count($sortedVisibleShelfBooks) > 0) @if($view === 'list')
    diff --git a/routes/web.php b/routes/web.php index c86509c68..4620cd08b 100644 --- a/routes/web.php +++ b/routes/web.php @@ -182,6 +182,7 @@ Route::middleware('auth')->group(function () { Route::get('/search/chapter/{bookId}', [SearchController::class, 'searchChapter']); Route::get('/search/entity/siblings', [SearchController::class, 'searchSiblings']); Route::get('/search/entity-selector', [SearchController::class, 'searchForSelector']); + Route::get('/search/entity-selector-templates', [SearchController::class, 'templatesForSelector']); Route::get('/search/suggest', [SearchController::class, 'searchSuggestions']); // User Search @@ -332,6 +333,7 @@ Route::get('/saml2/acs', [AccessControllers\Saml2Controller::class, 'processAcs' // OIDC routes Route::post('/oidc/login', [AccessControllers\OidcController::class, 'login']); 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']); diff --git a/tests/Activity/WatchTest.php b/tests/Activity/WatchTest.php index 63e51c92e..38935bbf5 100644 --- a/tests/Activity/WatchTest.php +++ b/tests/Activity/WatchTest.php @@ -12,7 +12,6 @@ use BookStack\Activity\Tools\ActivityLogger; use BookStack\Activity\Tools\UserEntityWatchOptions; use BookStack\Activity\WatchLevels; use BookStack\Entities\Models\Entity; -use BookStack\Entities\Tools\TrashCan; use BookStack\Settings\UserNotificationPreferences; use Illuminate\Support\Facades\Notification; use Tests\TestCase; @@ -64,8 +63,7 @@ class WatchTest extends TestCase $editor = $this->users->editor(); $book = $this->entities->book(); - $this->actingAs($editor)->get($book->getUrl()); - $resp = $this->put('/watching/update', [ + $resp = $this->actingAs($editor)->put('/watching/update', [ 'type' => $book->getMorphClass(), 'id' => $book->id, 'level' => 'comments' @@ -268,6 +266,7 @@ class WatchTest extends TestCase return $mail->subject === 'New comment on page: ' . $entities['page']->getShortName() && str_contains($mailContent, 'View Comment') && str_contains($mailContent, 'Page Name: ' . $entities['page']->name) + && str_contains($mailContent, 'Page Path: ' . $entities['book']->getShortName(24) . ' > ' . $entities['chapter']->getShortName(24)) && str_contains($mailContent, 'Commenter: ' . $admin->name) && str_contains($mailContent, 'Comment: My new comment response'); }); @@ -285,12 +284,13 @@ class WatchTest extends TestCase $this->actingAs($admin); $this->entities->updatePage($entities['page'], ['name' => 'Updated page', 'html' => 'new page content']); - $notifications->assertSentTo($editor, function (PageUpdateNotification $notification) use ($editor, $admin) { + $notifications->assertSentTo($editor, function (PageUpdateNotification $notification) use ($editor, $admin, $entities) { $mail = $notification->toMail($editor); $mailContent = html_entity_decode(strip_tags($mail->render()), ENT_QUOTES); return $mail->subject === 'Updated page: Updated page' && str_contains($mailContent, 'View Page') && str_contains($mailContent, 'Page Name: Updated page') + && str_contains($mailContent, 'Page Path: ' . $entities['book']->getShortName(24) . ' > ' . $entities['chapter']->getShortName(24)) && str_contains($mailContent, 'Updated By: ' . $admin->name) && str_contains($mailContent, 'you won\'t be sent notifications for further edits to this page by the same editor'); }); @@ -314,12 +314,13 @@ class WatchTest extends TestCase $page = $entities['chapter']->pages()->where('draft', '=', true)->first(); $this->post($page->getUrl(), ['name' => 'My new page', 'html' => 'My new page content']); - $notifications->assertSentTo($editor, function (PageCreationNotification $notification) use ($editor, $admin) { + $notifications->assertSentTo($editor, function (PageCreationNotification $notification) use ($editor, $admin, $entities) { $mail = $notification->toMail($editor); $mailContent = html_entity_decode(strip_tags($mail->render()), ENT_QUOTES); return $mail->subject === 'New page: My new page' && str_contains($mailContent, 'View Page') && str_contains($mailContent, 'Page Name: My new page') + && str_contains($mailContent, 'Page Path: ' . $entities['book']->getShortName(24) . ' > ' . $entities['chapter']->getShortName(24)) && str_contains($mailContent, 'Created By: ' . $admin->name); }); } @@ -408,4 +409,32 @@ class WatchTest extends TestCase $this->assertDatabaseMissing('watches', ['watchable_type' => 'page', 'watchable_id' => $page->id]); } + + public function test_page_path_in_notifications_limited_by_permissions() + { + $chapter = $this->entities->chapterHasPages(); + $page = $chapter->pages()->first(); + $book = $chapter->book; + $notification = new PageCreationNotification($page, $this->users->editor()); + + $viewer = $this->users->viewer(); + $viewerRole = $viewer->roles()->first(); + + $content = html_entity_decode(strip_tags($notification->toMail($viewer)->render()), ENT_QUOTES); + $this->assertStringContainsString('Page Path: ' . $book->getShortName(24) . ' > ' . $chapter->getShortName(24), $content); + + $this->permissions->setEntityPermissions($page, ['view'], [$viewerRole]); + $this->permissions->setEntityPermissions($chapter, [], [$viewerRole]); + + $content = html_entity_decode(strip_tags($notification->toMail($viewer)->render()), ENT_QUOTES); + $this->assertStringContainsString('Page Path: ' . $book->getShortName(24), $content); + $this->assertStringNotContainsString(' > ' . $chapter->getShortName(24), $content); + + $this->permissions->setEntityPermissions($book, [], [$viewerRole]); + + $content = html_entity_decode(strip_tags($notification->toMail($viewer)->render()), ENT_QUOTES); + $this->assertStringNotContainsString('Page Path:', $content); + $this->assertStringNotContainsString($book->getShortName(24), $content); + $this->assertStringNotContainsString($chapter->getShortName(24), $content); + } } diff --git a/tests/Api/BooksApiTest.php b/tests/Api/BooksApiTest.php index 326304d6f..b31bd7d37 100644 --- a/tests/Api/BooksApiTest.php +++ b/tests/Api/BooksApiTest.php @@ -31,18 +31,46 @@ class BooksApiTest extends TestCase public function test_create_endpoint() { $this->actingAsApiEditor(); + $templatePage = $this->entities->templatePage(); $details = [ - 'name' => 'My API book', - 'description' => 'A book created via the API', + 'name' => 'My API book', + 'description' => 'A book created via the API', + 'default_template_id' => $templatePage->id, ]; $resp = $this->postJson($this->baseEndpoint, $details); $resp->assertStatus(200); + $newItem = Book::query()->orderByDesc('id')->where('name', '=', $details['name'])->first(); - $resp->assertJson(array_merge($details, ['id' => $newItem->id, 'slug' => $newItem->slug])); + $resp->assertJson(array_merge($details, [ + 'id' => $newItem->id, + 'slug' => $newItem->slug, + 'description_html' => '

    A book created via the API

    ', + ])); $this->assertActivityExists('book_create', $newItem); } + public function test_create_endpoint_with_html() + { + $this->actingAsApiEditor(); + $details = [ + 'name' => 'My API book', + 'description_html' => '

    A book created via the API

    ', + ]; + + $resp = $this->postJson($this->baseEndpoint, $details); + $resp->assertStatus(200); + + $newItem = Book::query()->orderByDesc('id')->where('name', '=', $details['name'])->first(); + $expectedDetails = array_merge($details, [ + 'id' => $newItem->id, + 'description' => 'A book created via the API', + ]); + + $resp->assertJson($expectedDetails); + $this->assertDatabaseHas('books', $expectedDetails); + } + public function test_book_name_needed_to_create() { $this->actingAsApiEditor(); @@ -58,7 +86,7 @@ class BooksApiTest extends TestCase 'validation' => [ 'name' => ['The name field is required.'], ], - 'code' => 422, + 'code' => 422, ], ]); } @@ -83,6 +111,7 @@ class BooksApiTest extends TestCase 'owned_by' => [ 'name' => $book->ownedBy->name, ], + 'default_template_id' => null, ]); } @@ -121,19 +150,40 @@ class BooksApiTest extends TestCase { $this->actingAsApiEditor(); $book = $this->entities->book(); + $templatePage = $this->entities->templatePage(); $details = [ 'name' => 'My updated API book', - 'description' => 'A book created via the API', + 'description' => 'A book updated via the API', + 'default_template_id' => $templatePage->id, ]; $resp = $this->putJson($this->baseEndpoint . "/{$book->id}", $details); $book->refresh(); $resp->assertStatus(200); - $resp->assertJson(array_merge($details, ['id' => $book->id, 'slug' => $book->slug])); + $resp->assertJson(array_merge($details, [ + 'id' => $book->id, + 'slug' => $book->slug, + 'description_html' => '

    A book updated via the API

    ', + ])); $this->assertActivityExists('book_update', $book); } + public function test_update_endpoint_with_html() + { + $this->actingAsApiEditor(); + $book = $this->entities->book(); + $details = [ + 'name' => 'My updated API book', + 'description_html' => '

    A book updated via the API

    ', + ]; + + $resp = $this->putJson($this->baseEndpoint . "/{$book->id}", $details); + $resp->assertStatus(200); + + $this->assertDatabaseHas('books', array_merge($details, ['id' => $book->id, 'description' => 'A book updated via the API'])); + } + public function test_update_increments_updated_date_if_only_tags_are_sent() { $this->actingAsApiEditor(); diff --git a/tests/Api/ChaptersApiTest.php b/tests/Api/ChaptersApiTest.php index 0629f3aed..81a918877 100644 --- a/tests/Api/ChaptersApiTest.php +++ b/tests/Api/ChaptersApiTest.php @@ -51,7 +51,11 @@ class ChaptersApiTest extends TestCase $resp = $this->postJson($this->baseEndpoint, $details); $resp->assertStatus(200); $newItem = Chapter::query()->orderByDesc('id')->where('name', '=', $details['name'])->first(); - $resp->assertJson(array_merge($details, ['id' => $newItem->id, 'slug' => $newItem->slug])); + $resp->assertJson(array_merge($details, [ + 'id' => $newItem->id, + 'slug' => $newItem->slug, + 'description_html' => '

    A chapter created via the API

    ', + ])); $this->assertDatabaseHas('tags', [ 'entity_id' => $newItem->id, 'entity_type' => $newItem->getMorphClass(), @@ -62,6 +66,28 @@ class ChaptersApiTest extends TestCase $this->assertActivityExists('chapter_create', $newItem); } + public function test_create_endpoint_with_html() + { + $this->actingAsApiEditor(); + $book = $this->entities->book(); + $details = [ + 'name' => 'My API chapter', + 'description_html' => '

    A chapter created via the API

    ', + 'book_id' => $book->id, + ]; + + $resp = $this->postJson($this->baseEndpoint, $details); + $resp->assertStatus(200); + $newItem = Chapter::query()->orderByDesc('id')->where('name', '=', $details['name'])->first(); + + $expectedDetails = array_merge($details, [ + 'id' => $newItem->id, + 'description' => 'A chapter created via the API', + ]); + $resp->assertJson($expectedDetails); + $this->assertDatabaseHas('chapters', $expectedDetails); + } + public function test_chapter_name_needed_to_create() { $this->actingAsApiEditor(); @@ -131,7 +157,7 @@ class ChaptersApiTest extends TestCase $chapter = $this->entities->chapter(); $details = [ 'name' => 'My updated API chapter', - 'description' => 'A chapter created via the API', + 'description' => 'A chapter updated via the API', 'tags' => [ [ 'name' => 'freshtag', @@ -146,11 +172,31 @@ class ChaptersApiTest extends TestCase $resp->assertStatus(200); $resp->assertJson(array_merge($details, [ - 'id' => $chapter->id, 'slug' => $chapter->slug, 'book_id' => $chapter->book_id, + 'id' => $chapter->id, + 'slug' => $chapter->slug, + 'book_id' => $chapter->book_id, + 'description_html' => '

    A chapter updated via the API

    ', ])); $this->assertActivityExists('chapter_update', $chapter); } + public function test_update_endpoint_with_html() + { + $this->actingAsApiEditor(); + $chapter = $this->entities->chapter(); + $details = [ + 'name' => 'My updated API chapter', + 'description_html' => '

    A chapter updated via the API

    ', + ]; + + $resp = $this->putJson($this->baseEndpoint . "/{$chapter->id}", $details); + $resp->assertStatus(200); + + $this->assertDatabaseHas('chapters', array_merge($details, [ + 'id' => $chapter->id, 'description' => 'A chapter updated via the API' + ])); + } + public function test_update_increments_updated_date_if_only_tags_are_sent() { $this->actingAsApiEditor(); diff --git a/tests/Api/SearchApiTest.php b/tests/Api/SearchApiTest.php index cdc954ec3..2a186e8d6 100644 --- a/tests/Api/SearchApiTest.php +++ b/tests/Api/SearchApiTest.php @@ -52,7 +52,7 @@ class SearchApiTest extends TestCase public function test_all_endpoint_returns_items_with_preview_html() { $book = $this->entities->book(); - $book->update(['name' => 'name with superuniquevalue within', 'description' => 'Description with superuniquevalue within']); + $book->forceFill(['name' => 'name with superuniquevalue within', 'description' => 'Description with superuniquevalue within'])->save(); $book->indexForSearch(); $resp = $this->actingAsApiAdmin()->getJson($this->baseEndpoint . '?query=superuniquevalue'); diff --git a/tests/Api/ShelvesApiTest.php b/tests/Api/ShelvesApiTest.php index fbfc17cb4..f1b8ed985 100644 --- a/tests/Api/ShelvesApiTest.php +++ b/tests/Api/ShelvesApiTest.php @@ -42,7 +42,11 @@ class ShelvesApiTest extends TestCase $resp = $this->postJson($this->baseEndpoint, array_merge($details, ['books' => [$books[0]->id, $books[1]->id]])); $resp->assertStatus(200); $newItem = Bookshelf::query()->orderByDesc('id')->where('name', '=', $details['name'])->first(); - $resp->assertJson(array_merge($details, ['id' => $newItem->id, 'slug' => $newItem->slug])); + $resp->assertJson(array_merge($details, [ + 'id' => $newItem->id, + 'slug' => $newItem->slug, + 'description_html' => '

    A shelf created via the API

    ', + ])); $this->assertActivityExists('bookshelf_create', $newItem); foreach ($books as $index => $book) { $this->assertDatabaseHas('bookshelves_books', [ @@ -53,6 +57,28 @@ class ShelvesApiTest extends TestCase } } + public function test_create_endpoint_with_html() + { + $this->actingAsApiEditor(); + + $details = [ + 'name' => 'My API shelf', + 'description_html' => '

    A shelf created via the API

    ', + ]; + + $resp = $this->postJson($this->baseEndpoint, $details); + $resp->assertStatus(200); + $newItem = Bookshelf::query()->orderByDesc('id')->where('name', '=', $details['name'])->first(); + + $expectedDetails = array_merge($details, [ + 'id' => $newItem->id, + 'description' => 'A shelf created via the API', + ]); + + $resp->assertJson($expectedDetails); + $this->assertDatabaseHas('bookshelves', $expectedDetails); + } + public function test_shelf_name_needed_to_create() { $this->actingAsApiEditor(); @@ -102,17 +128,36 @@ class ShelvesApiTest extends TestCase $shelf = Bookshelf::visible()->first(); $details = [ 'name' => 'My updated API shelf', - 'description' => 'A shelf created via the API', + 'description' => 'A shelf updated via the API', ]; $resp = $this->putJson($this->baseEndpoint . "/{$shelf->id}", $details); $shelf->refresh(); $resp->assertStatus(200); - $resp->assertJson(array_merge($details, ['id' => $shelf->id, 'slug' => $shelf->slug])); + $resp->assertJson(array_merge($details, [ + 'id' => $shelf->id, + 'slug' => $shelf->slug, + 'description_html' => '

    A shelf updated via the API

    ', + ])); $this->assertActivityExists('bookshelf_update', $shelf); } + public function test_update_endpoint_with_html() + { + $this->actingAsApiEditor(); + $shelf = Bookshelf::visible()->first(); + $details = [ + 'name' => 'My updated API shelf', + 'description_html' => '

    A shelf updated via the API

    ', + ]; + + $resp = $this->putJson($this->baseEndpoint . "/{$shelf->id}", $details); + $resp->assertStatus(200); + + $this->assertDatabaseHas('bookshelves', array_merge($details, ['id' => $shelf->id, 'description' => 'A shelf updated via the API'])); + } + public function test_update_increments_updated_date_if_only_tags_are_sent() { $this->actingAsApiEditor(); diff --git a/tests/Api/UsersApiTest.php b/tests/Api/UsersApiTest.php index 6ad727257..a0c67d0d2 100644 --- a/tests/Api/UsersApiTest.php +++ b/tests/Api/UsersApiTest.php @@ -143,6 +143,23 @@ class UsersApiTest extends TestCase Notification::assertSentTo($user, UserInviteNotification::class); } + public function test_create_with_send_invite_works_with_value_of_1() + { + $this->actingAsApiAdmin(); + Notification::fake(); + + $resp = $this->postJson($this->baseEndpoint, [ + 'name' => 'Benny Boris', + 'email' => 'bboris@example.com', + 'send_invite' => '1', // Submissions via x-www-form-urlencoded/form-data may use 1 instead of boolean + ]); + + $resp->assertStatus(200); + /** @var User $user */ + $user = User::query()->where('email', '=', 'bboris@example.com')->first(); + Notification::assertSentTo($user, UserInviteNotification::class); + } + public function test_create_name_and_email_validation() { $this->actingAsApiAdmin(); diff --git a/tests/Auth/OidcTest.php b/tests/Auth/OidcTest.php index 204a3bb5f..dbf26f1bd 100644 --- a/tests/Auth/OidcTest.php +++ b/tests/Auth/OidcTest.php @@ -44,6 +44,7 @@ class OidcTest extends TestCase 'oidc.groups_claim' => 'group', 'oidc.remove_from_groups' => false, 'oidc.external_id_claim' => 'sub', + 'oidc.end_session_endpoint' => false, ]); } @@ -478,6 +479,128 @@ class OidcTest extends TestCase $this->assertTrue($user->hasRole($roleA->id)); } + public function test_oidc_logout_form_active_when_oidc_active() + { + $this->runLogin(); + + $resp = $this->get('/'); + $this->withHtml($resp)->assertElementExists('header form[action$="/oidc/logout"] button'); + } + public function test_logout_with_autodiscovery_with_oidc_logout_enabled() + { + config()->set(['oidc.end_session_endpoint' => true]); + $this->withAutodiscovery(); + + $transactions = $this->mockHttpClient([ + $this->getAutoDiscoveryResponse(), + $this->getJwksResponse(), + ]); + + $resp = $this->asEditor()->post('/oidc/logout'); + $resp->assertRedirect('https://auth.example.com/oidc/logout?post_logout_redirect_uri=' . urlencode(url('/'))); + + $this->assertEquals(2, $transactions->requestCount()); + $this->assertFalse(auth()->check()); + } + + public function test_logout_with_autodiscovery_with_oidc_logout_disabled() + { + $this->withAutodiscovery(); + config()->set(['oidc.end_session_endpoint' => false]); + + $this->mockHttpClient([ + $this->getAutoDiscoveryResponse(), + $this->getJwksResponse(), + ]); + + $resp = $this->asEditor()->post('/oidc/logout'); + $resp->assertRedirect('/'); + $this->assertFalse(auth()->check()); + } + + public function test_logout_without_autodiscovery_but_with_endpoint_configured() + { + config()->set(['oidc.end_session_endpoint' => 'https://example.com/logout']); + + $resp = $this->asEditor()->post('/oidc/logout'); + $resp->assertRedirect('https://example.com/logout?post_logout_redirect_uri=' . urlencode(url('/'))); + $this->assertFalse(auth()->check()); + } + + public function test_logout_without_autodiscovery_with_configured_endpoint_adds_to_query_if_existing() + { + config()->set(['oidc.end_session_endpoint' => 'https://example.com/logout?a=b']); + + $resp = $this->asEditor()->post('/oidc/logout'); + $resp->assertRedirect('https://example.com/logout?a=b&post_logout_redirect_uri=' . urlencode(url('/'))); + $this->assertFalse(auth()->check()); + } + + public function test_logout_with_autodiscovery_and_auto_initiate_returns_to_auto_prevented_login() + { + $this->withAutodiscovery(); + config()->set([ + 'auth.auto_initiate' => true, + 'services.google.client_id' => false, + 'services.github.client_id' => false, + 'oidc.end_session_endpoint' => true, + ]); + + $this->mockHttpClient([ + $this->getAutoDiscoveryResponse(), + $this->getJwksResponse(), + ]); + + $resp = $this->asEditor()->post('/oidc/logout'); + + $redirectUrl = url('/login?prevent_auto_init=true'); + $resp->assertRedirect('https://auth.example.com/oidc/logout?post_logout_redirect_uri=' . urlencode($redirectUrl)); + $this->assertFalse(auth()->check()); + } + + public function test_logout_endpoint_url_overrides_autodiscovery_endpoint() + { + config()->set(['oidc.end_session_endpoint' => 'https://a.example.com']); + $this->withAutodiscovery(); + + $transactions = $this->mockHttpClient([ + $this->getAutoDiscoveryResponse(), + $this->getJwksResponse(), + ]); + + $resp = $this->asEditor()->post('/oidc/logout'); + $resp->assertRedirect('https://a.example.com?post_logout_redirect_uri=' . urlencode(url('/'))); + + $this->assertEquals(2, $transactions->requestCount()); + $this->assertFalse(auth()->check()); + } + + public function test_logout_with_autodiscovery_does_not_use_rp_logout_if_no_url_via_autodiscovery() + { + config()->set(['oidc.end_session_endpoint' => true]); + $this->withAutodiscovery(); + + $this->mockHttpClient([ + $this->getAutoDiscoveryResponse(['end_session_endpoint' => null]), + $this->getJwksResponse(), + ]); + + $resp = $this->asEditor()->post('/oidc/logout'); + $resp->assertRedirect('/'); + $this->assertFalse(auth()->check()); + } + + public function test_logout_redirect_contains_id_token_hint_if_existing() + { + config()->set(['oidc.end_session_endpoint' => 'https://example.com/logout']); + + $this->runLogin(); + + $resp = $this->asEditor()->post('/oidc/logout'); + $query = 'id_token_hint=' . urlencode(OidcJwtHelper::idToken()) . '&post_logout_redirect_uri=' . urlencode(url('/')); + $resp->assertRedirect('https://example.com/logout?' . $query); + } + public function test_oidc_id_token_pre_validate_theme_event_without_return() { $args = []; @@ -563,6 +686,7 @@ class OidcTest extends TestCase 'authorization_endpoint' => OidcJwtHelper::defaultIssuer() . '/oidc/authorize', 'jwks_uri' => OidcJwtHelper::defaultIssuer() . '/oidc/keys', 'issuer' => OidcJwtHelper::defaultIssuer(), + 'end_session_endpoint' => OidcJwtHelper::defaultIssuer() . '/oidc/logout', ], $responseOverrides))); } diff --git a/tests/Auth/Saml2Test.php b/tests/Auth/Saml2Test.php index 801682a00..3de6238ed 100644 --- a/tests/Auth/Saml2Test.php +++ b/tests/Auth/Saml2Test.php @@ -181,7 +181,7 @@ class Saml2Test extends TestCase ]); $handleLogoutResponse = function () { - $this->assertTrue($this->isAuthenticated()); + $this->assertFalse($this->isAuthenticated()); $req = $this->get('/saml2/sls'); $req->assertRedirect('/'); @@ -214,6 +214,55 @@ class Saml2Test extends TestCase $this->assertFalse($this->isAuthenticated()); } + public function test_logout_sls_flow_logs_user_out_before_redirect() + { + config()->set([ + 'saml2.onelogin.strict' => false, + ]); + + $this->followingRedirects()->post('/saml2/acs', ['SAMLResponse' => $this->acsPostData]); + $this->assertTrue($this->isAuthenticated()); + + $req = $this->post('/saml2/logout'); + $redirect = $req->headers->get('location'); + $this->assertStringStartsWith('http://saml.local/saml2/idp/SingleLogoutService.php', $redirect); + $this->assertFalse($this->isAuthenticated()); + } + + public function test_logout_sls_request_redirect_prevents_auto_login_when_enabled() + { + config()->set([ + 'saml2.onelogin.strict' => false, + 'auth.auto_initiate' => true, + 'services.google.client_id' => false, + 'services.github.client_id' => false, + ]); + + $this->followingRedirects()->post('/saml2/acs', ['SAMLResponse' => $this->acsPostData]); + + $req = $this->post('/saml2/logout'); + $redirect = $req->headers->get('location'); + $this->assertStringContainsString(urlencode(url('/login?prevent_auto_init=true')), $redirect); + } + + public function test_logout_sls_response_endpoint_redirect_prevents_auto_login_when_enabled() + { + config()->set([ + 'saml2.onelogin.strict' => false, + 'auth.auto_initiate' => true, + 'services.google.client_id' => false, + 'services.github.client_id' => false, + ]); + + $this->followingRedirects()->post('/saml2/acs', ['SAMLResponse' => $this->acsPostData]); + + $this->withGet(['SAMLResponse' => $this->sloResponseData], function () { + $req = $this->get('/saml2/sls'); + $redirect = $req->headers->get('location'); + $this->assertEquals(url('/login?prevent_auto_init=true'), $redirect); + }); + } + public function test_dump_user_details_option_works() { config()->set([ @@ -229,6 +278,22 @@ class Saml2Test extends TestCase ]); } + public function test_dump_user_details_response_contains_parsed_group_data_if_groups_enabled() + { + config()->set([ + 'saml2.onelogin.strict' => false, + 'saml2.dump_user_details' => true, + 'saml2.user_to_groups' => true, + ]); + + $acsPost = $this->followingRedirects()->post('/saml2/acs', ['SAMLResponse' => $this->acsPostData]); + $acsPost->assertJson([ + 'attrs_after_parsing' => [ + 'groups' => ['member', 'admin'], + ] + ]); + } + public function test_saml_routes_are_only_active_if_saml_enabled() { config()->set(['auth.method' => 'standard']); @@ -441,9 +506,9 @@ class Saml2Test extends TestCase * ] * ]. */ - protected $acsPostData = 'PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iIElEPSJfNGRkNDU2NGRjNzk0MDYxZWYxYmFhMDQ2N2Q3OTAyOGNlZDNjZTU0YmVlIiBWZXJzaW9uPSIyLjAiIElzc3VlSW5zdGFudD0iMjAxOS0xMS0xN1QxNzo1MzozOVoiIERlc3RpbmF0aW9uPSJodHRwOi8vYm9va3N0YWNrLmxvY2FsL3NhbWwyL2FjcyIgSW5SZXNwb25zZVRvPSJPTkVMT0dJTl82YTBmNGYzOTkzMDQwZjE5ODdmZDM3MDY4YjUyOTYyMjlhZDUzNjFjIj48c2FtbDpJc3N1ZXI+aHR0cDovL3NhbWwubG9jYWwvc2FtbDIvaWRwL21ldGFkYXRhLnBocDwvc2FtbDpJc3N1ZXI+PGRzOlNpZ25hdHVyZSB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyI+CiAgPGRzOlNpZ25lZEluZm8+PGRzOkNhbm9uaWNhbGl6YXRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz4KICAgIDxkczpTaWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNyc2Etc2hhMjU2Ii8+CiAgPGRzOlJlZmVyZW5jZSBVUkk9IiNfNGRkNDU2NGRjNzk0MDYxZWYxYmFhMDQ2N2Q3OTAyOGNlZDNjZTU0YmVlIj48ZHM6VHJhbnNmb3Jtcz48ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI2VudmVsb3BlZC1zaWduYXR1cmUiLz48ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PC9kczpUcmFuc2Zvcm1zPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNzaGEyNTYiLz48ZHM6RGlnZXN0VmFsdWU+dm1oL1M3NU5mK2crZWNESkN6QWJaV0tKVmx1ZzdCZnNDKzlhV05lSXJlUT08L2RzOkRpZ2VzdFZhbHVlPjwvZHM6UmVmZXJlbmNlPjwvZHM6U2lnbmVkSW5mbz48ZHM6U2lnbmF0dXJlVmFsdWU+dnJhZ0tKWHNjVm5UNjJFaEk3bGk4MERUWHNOTGJOc3lwNWZ2QnU4WjFYSEtFUVA3QWpPNkcxcVBwaGpWQ2dRMzd6TldVVTZvUytQeFA3UDlHeG5xL3hKejRUT3lHcHJ5N1RoK2pIcHc0YWVzQTdrTmp6VU51UmU2c1ltWTlrRXh2VjMvTmJRZjROMlM2Y2RhRHIzWFRodllVVDcxYzQwNVVHOFJpQjJaY3liWHIxZU1yWCtXUDBnU2Qrc0F2RExqTjBJc3pVWlVUNThadFpEVE1ya1ZGL0pIbFBFQ04vVW1sYVBBeitTcUJ4c25xTndZK1oxYUt3MnlqeFRlNnUxM09Kb29OOVN1REowNE0rK2F3RlY3NkI4cXEyTzMxa3FBbDJibm1wTGxtTWdRNFEraUlnL3dCc09abTV1clphOWJObDNLVEhtTVBXbFpkbWhsLzgvMy9IT1RxN2thWGs3cnlWRHRLcFlsZ3FUajNhRUpuL0dwM2o4SFp5MUVialRiOTRRT1ZQMG5IQzB1V2hCaE13TjdzVjFrUSsxU2NjUlpUZXJKSGlSVUQvR0srTVg3M0YrbzJVTFRIL1Z6Tm9SM2o4N2hOLzZ1UC9JeG5aM1RudGR1MFZPZS9ucEdVWjBSMG9SWFhwa2JTL2poNWk1ZjU0RXN4eXZ1VEM5NHdKaEM8L2RzOlNpZ25hdHVyZVZhbHVlPgo8ZHM6S2V5SW5mbz48ZHM6WDUwOURhdGE+PGRzOlg1MDlDZXJ0aWZpY2F0ZT5NSUlFYXpDQ0F0T2dBd0lCQWdJVWU3YTA4OENucjRpem1ybkJFbng1cTNIVE12WXdEUVlKS29aSWh2Y05BUUVMQlFBd1JURUxNQWtHQTFVRUJoTUNSMEl4RXpBUkJnTlZCQWdNQ2xOdmJXVXRVM1JoZEdVeElUQWZCZ05WQkFvTUdFbHVkR1Z5Ym1WMElGZHBaR2RwZEhNZ1VIUjVJRXgwWkRBZUZ3MHhPVEV4TVRZeE1qRTNNVFZhRncweU9URXhNVFV4TWpFM01UVmFNRVV4Q3pBSkJnTlZCQVlUQWtkQ01STXdFUVlEVlFRSURBcFRiMjFsTFZOMFlYUmxNU0V3SHdZRFZRUUtEQmhKYm5SbGNtNWxkQ0JYYVdSbmFYUnpJRkIwZVNCTWRHUXdnZ0dpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCandBd2dnR0tBb0lCZ1FEekxlOUZmZHlwbFR4SHA0U3VROWdRdFpUM3QrU0RmdkVMNzJwcENmRlp3NytCNXM1Qi9UNzNhWHBvUTNTNTNwR0kxUklXQ2dlMmlDVVEydHptMjdhU05IMGl1OWFKWWNVUVovUklUcWQwYXl5RGtzMU5BMlBUM1RXNnQzbTdLVjVyZTRQME5iK1lEZXV5SGRreitqY010cG44Q21Cb1QwSCtza2hhMGhpcUlOa2prUlBpSHZMSFZHcCt0SFVFQS9JNm1ONGFCL1VFeFNUTHM3OU5zTFVmdGVxcXhlOSt0dmRVYVRveURQcmhQRmpPTnMrOU5LQ2t6SUM2dmN2N0o2QXR1S0c2bkVUK3pCOXlPV2d0R1lRaWZYcVFBMnk1ZEw4MUJCMHE1dU1hQkxTMnBxM2FQUGp6VTJGMytFeXNqeVNXVG5Da2ZrN0M1U3NDWFJ1OFErVTk1dHVucE5md2Y1b2xFNldhczQ4Tk1NK1B3VjdpQ05NUGtOemxscTZQQ2lNK1A4RHJNU2N6elVaWlFVU3Y2ZFN3UENvK1lTVmltRU0wT2czWEpUaU5oUTVBTmxhSW42Nkt3NWdmb0JmdWlYbXlJS2lTRHlBaURZbUZhZjQzOTV3V3dMa1RSK2N3OFdmamFIc3dLWlRvbW4xTVIzT0pzWTJVSjBlUkJZTStZU3NDQXdFQUFhTlRNRkV3SFFZRFZSME9CQllFRkltcDJDWUNHZmNiN3c5MUgvY1NoVENrWHdSL01COEdBMVVkSXdRWU1CYUFGSW1wMkNZQ0dmY2I3dzkxSC9jU2hUQ2tYd1IvTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3RFFZSktvWklodmNOQVFFTEJRQURnZ0dCQUErZy9DN3VMOWxuK1crcUJrbkxXODFrb2pZZmxnUEsxSTFNSEl3bk12bC9aVEhYNGRSWEtEcms3S2NVcTFLanFhak5WNjZmMWNha3AwM0lpakJpTzBYaTFnWFVaWUxvQ2lOR1V5eXA5WGxvaUl5OVh3MlBpV25ydzAreVp5dlZzc2JlaFhYWUpsNFJpaEJqQld1bDlSNHdNWUxPVVNKRGUyV3hjVUJoSm54eU5ScytQMHhMU1FYNkIybjZueG9Ea280cDA3czhaS1hRa2VpWjJpd0ZkVHh6UmtHanRoTVV2NzA0bnpzVkdCVDBEQ1B0ZlNhTzVLSlpXMXJDczN5aU10aG5CeHE0cUVET1FKRklsKy9MRDcxS2JCOXZaY1c1SnVhdnpCRm1rS0dOcm8vNkcxSTdlbDQ2SVI0d2lqVHlORkNZVXVEOWR0aWduTm1wV3ROOE9XK3B0aUwvanRUeVNXdWtqeXMwcyt2TG44M0NWdmpCMGRKdFZBSVlPZ1hGZEl1aWk2Nmdjend3TS9MR2lPRXhKbjBkVE56c0ovSVlocHhMNEZCRXVQMHBza1kwbzBhVWxKMkxTMmord1NRVFJLc0JnTWp5clVyZWtsZTJPRFN0U3RuM2VhYmpJeDAvRkhscEZyMGpOSW0vb01QN2t3anRVWDR6YU5lNDdRSTRHZz09PC9kczpYNTA5Q2VydGlmaWNhdGU+PC9kczpYNTA5RGF0YT48L2RzOktleUluZm8+PC9kczpTaWduYXR1cmU+PHNhbWxwOlN0YXR1cz48c2FtbHA6U3RhdHVzQ29kZSBWYWx1ZT0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnN0YXR1czpTdWNjZXNzIi8+PC9zYW1scDpTdGF0dXM+PHNhbWw6QXNzZXJ0aW9uIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhtbG5zOnhzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgSUQ9Il82ODQyZGY5YzY1OWYxM2ZlNTE5NmNkOWVmNmMyZjAyODM2NGFlOTQzYjEiIFZlcnNpb249IjIuMCIgSXNzdWVJbnN0YW50PSIyMDE5LTExLTE3VDE3OjUzOjM5WiI+PHNhbWw6SXNzdWVyPmh0dHA6Ly9zYW1sLmxvY2FsL3NhbWwyL2lkcC9tZXRhZGF0YS5waHA8L3NhbWw6SXNzdWVyPjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPgogIDxkczpTaWduZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+CiAgICA8ZHM6U2lnbmF0dXJlTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxkc2lnLW1vcmUjcnNhLXNoYTI1NiIvPgogIDxkczpSZWZlcmVuY2UgVVJJPSIjXzY4NDJkZjljNjU5ZjEzZmU1MTk2Y2Q5ZWY2YzJmMDI4MzY0YWU5NDNiMSI+PGRzOlRyYW5zZm9ybXM+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0dXJlIi8+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjwvZHM6VHJhbnNmb3Jtcz48ZHM6RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjc2hhMjU2Ii8+PGRzOkRpZ2VzdFZhbHVlPmtyYjV3NlM4dG9YYy9lU3daUFVPQnZRem4zb3M0SkFDdXh4ckpreHBnRnc9PC9kczpEaWdlc3RWYWx1ZT48L2RzOlJlZmVyZW5jZT48L2RzOlNpZ25lZEluZm8+PGRzOlNpZ25hdHVyZVZhbHVlPjJxcW1Ba3hucXhOa3N5eXh5dnFTVDUxTDg5VS9ZdHpja2t1ekF4ci9hQ1JTK1NPRzg1YkFNWm8vU3puc3d0TVlBYlFRQ0VGb0R1amdNdlpzSFl3NlR2dmFHanlXWUpRNVZyYWhlemZaSWlCVUU0NHBtWGFrOCswV0l0WTVndnBGSXhxWFZaRmdFUkt2VExmZVFCMzhkMVZQc0ZVZ0RYdXQ4VS9Qdm43dXZwdXZjVXorMUUyOUVKR2FZL0dndnhUN0tyWU9SQTh3SitNdVRzUVZtanNlUnhveVJTejA4TmJ3ZTJIOGpXQnpFWWNxWWwyK0ZnK2hwNWd0S216VmhLRnBkNXZBNjdBSXo1NXN0QmNHNSswNHJVaWpFSzRzci9xa0x5QmtKQjdLdkwzanZKcG8zQjhxYkxYeXhLb1dSSmRnazhKNHMvTVp1QWk3QWUxUXNTTjl2Z3ZTdVRlc0VCUjVpSHJuS1lrbEpRWXNrbUQzbSsremE4U1NRbnBlM0UzYUZBY3p6cElUdUQ4YkFCWmRqcUk2TkhrSmFRQXBmb0hWNVQrZ244ejdUTWsrSStUU2JlQURubUxCS3lnMHRabW10L0ZKbDV6eWowVmxwc1dzTVM2OVE2bUZJVStqcEhSanpOb2FLMVM1dlQ3ZW1HbUhKSUp0cWlOdXJRN0tkQlBJPC9kczpTaWduYXR1cmVWYWx1ZT4KPGRzOktleUluZm8+PGRzOlg1MDlEYXRhPjxkczpYNTA5Q2VydGlmaWNhdGU+TUlJRWF6Q0NBdE9nQXdJQkFnSVVlN2EwODhDbnI0aXptcm5CRW54NXEzSFRNdll3RFFZSktvWklodmNOQVFFTEJRQXdSVEVMTUFrR0ExVUVCaE1DUjBJeEV6QVJCZ05WQkFnTUNsTnZiV1V0VTNSaGRHVXhJVEFmQmdOVkJBb01HRWx1ZEdWeWJtVjBJRmRwWkdkcGRITWdVSFI1SUV4MFpEQWVGdzB4T1RFeE1UWXhNakUzTVRWYUZ3MHlPVEV4TVRVeE1qRTNNVFZhTUVVeEN6QUpCZ05WQkFZVEFrZENNUk13RVFZRFZRUUlEQXBUYjIxbExWTjBZWFJsTVNFd0h3WURWUVFLREJoSmJuUmxjbTVsZENCWGFXUm5hWFJ6SUZCMGVTQk1kR1F3Z2dHaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQmp3QXdnZ0dLQW9JQmdRRHpMZTlGZmR5cGxUeEhwNFN1UTlnUXRaVDN0K1NEZnZFTDcycHBDZkZadzcrQjVzNUIvVDczYVhwb1EzUzUzcEdJMVJJV0NnZTJpQ1VRMnR6bTI3YVNOSDBpdTlhSlljVVFaL1JJVHFkMGF5eURrczFOQTJQVDNUVzZ0M203S1Y1cmU0UDBOYitZRGV1eUhka3oramNNdHBuOENtQm9UMEgrc2toYTBoaXFJTmtqa1JQaUh2TEhWR3ArdEhVRUEvSTZtTjRhQi9VRXhTVExzNzlOc0xVZnRlcXF4ZTkrdHZkVWFUb3lEUHJoUEZqT05zKzlOS0NreklDNnZjdjdKNkF0dUtHNm5FVCt6Qjl5T1dndEdZUWlmWHFRQTJ5NWRMODFCQjBxNXVNYUJMUzJwcTNhUFBqelUyRjMrRXlzanlTV1RuQ2tmazdDNVNzQ1hSdThRK1U5NXR1bnBOZndmNW9sRTZXYXM0OE5NTStQd1Y3aUNOTVBrTnpsbHE2UENpTStQOERyTVNjenpVWlpRVVN2NmRTd1BDbytZU1ZpbUVNME9nM1hKVGlOaFE1QU5sYUluNjZLdzVnZm9CZnVpWG15SUtpU0R5QWlEWW1GYWY0Mzk1d1d3TGtUUitjdzhXZmphSHN3S1pUb21uMU1SM09Kc1kyVUowZVJCWU0rWVNzQ0F3RUFBYU5UTUZFd0hRWURWUjBPQkJZRUZJbXAyQ1lDR2ZjYjd3OTFIL2NTaFRDa1h3Ui9NQjhHQTFVZEl3UVlNQmFBRkltcDJDWUNHZmNiN3c5MUgvY1NoVENrWHdSL01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dHQkFBK2cvQzd1TDlsbitXK3FCa25MVzgxa29qWWZsZ1BLMUkxTUhJd25NdmwvWlRIWDRkUlhLRHJrN0tjVXExS2pxYWpOVjY2ZjFjYWtwMDNJaWpCaU8wWGkxZ1hVWllMb0NpTkdVeXlwOVhsb2lJeTlYdzJQaVducncwK3laeXZWc3NiZWhYWFlKbDRSaWhCakJXdWw5UjR3TVlMT1VTSkRlMld4Y1VCaEpueHlOUnMrUDB4TFNRWDZCMm42bnhvRGtvNHAwN3M4WktYUWtlaVoyaXdGZFR4elJrR2p0aE1VdjcwNG56c1ZHQlQwRENQdGZTYU81S0paVzFyQ3MzeWlNdGhuQnhxNHFFRE9RSkZJbCsvTEQ3MUtiQjl2WmNXNUp1YXZ6QkZta0tHTnJvLzZHMUk3ZWw0NklSNHdpalR5TkZDWVV1RDlkdGlnbk5tcFd0TjhPVytwdGlML2p0VHlTV3VranlzMHMrdkxuODNDVnZqQjBkSnRWQUlZT2dYRmRJdWlpNjZnY3p3d00vTEdpT0V4Sm4wZFROenNKL0lZaHB4TDRGQkV1UDBwc2tZMG8wYVVsSjJMUzJqK3dTUVRSS3NCZ01qeXJVcmVrbGUyT0RTdFN0bjNlYWJqSXgwL0ZIbHBGcjBqTkltL29NUDdrd2p0VVg0emFOZTQ3UUk0R2c9PTwvZHM6WDUwOUNlcnRpZmljYXRlPjwvZHM6WDUwOURhdGE+PC9kczpLZXlJbmZvPjwvZHM6U2lnbmF0dXJlPjxzYW1sOlN1YmplY3Q+PHNhbWw6TmFtZUlEIFNQTmFtZVF1YWxpZmllcj0iaHR0cDovL2Jvb2tzdGFjay5sb2NhbC9zYW1sMi9tZXRhZGF0YSIgRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6bmFtZWlkLWZvcm1hdDp0cmFuc2llbnQiPl8yYzdhYjg2ZWI4ZjFkMTA2MzQ0M2YyMTljYzU4NjhmZjY2NzA4OTEyZTM8L3NhbWw6TmFtZUlEPjxzYW1sOlN1YmplY3RDb25maXJtYXRpb24gTWV0aG9kPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6Y206YmVhcmVyIj48c2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uRGF0YSBOb3RPbk9yQWZ0ZXI9IjIwMTktMTEtMTdUMTc6NTg6MzlaIiBSZWNpcGllbnQ9Imh0dHA6Ly9ib29rc3RhY2subG9jYWwvc2FtbDIvYWNzIiBJblJlc3BvbnNlVG89Ik9ORUxPR0lOXzZhMGY0ZjM5OTMwNDBmMTk4N2ZkMzcwNjhiNTI5NjIyOWFkNTM2MWMiLz48L3NhbWw6U3ViamVjdENvbmZpcm1hdGlvbj48L3NhbWw6U3ViamVjdD48c2FtbDpDb25kaXRpb25zIE5vdEJlZm9yZT0iMjAxOS0xMS0xN1QxNzo1MzowOVoiIE5vdE9uT3JBZnRlcj0iMjAxOS0xMS0xN1QxNzo1ODozOVoiPjxzYW1sOkF1ZGllbmNlUmVzdHJpY3Rpb24+PHNhbWw6QXVkaWVuY2U+aHR0cDovL2Jvb2tzdGFjay5sb2NhbC9zYW1sMi9tZXRhZGF0YTwvc2FtbDpBdWRpZW5jZT48L3NhbWw6QXVkaWVuY2VSZXN0cmljdGlvbj48L3NhbWw6Q29uZGl0aW9ucz48c2FtbDpBdXRoblN0YXRlbWVudCBBdXRobkluc3RhbnQ9IjIwMTktMTEtMTdUMTc6NTM6MzlaIiBTZXNzaW9uTm90T25PckFmdGVyPSIyMDE5LTExLTE4VDAxOjUzOjM5WiIgU2Vzc2lvbkluZGV4PSJfNGZlN2MwZDE1NzJkNjRiMjdmOTMwYWE2ZjIzNmE2ZjQyZTkzMDkwMWNjIj48c2FtbDpBdXRobkNvbnRleHQ+PHNhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFjOmNsYXNzZXM6UGFzc3dvcmQ8L3NhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+PC9zYW1sOkF1dGhuQ29udGV4dD48L3NhbWw6QXV0aG5TdGF0ZW1lbnQ+PHNhbWw6QXR0cmlidXRlU3RhdGVtZW50PjxzYW1sOkF0dHJpYnV0ZSBOYW1lPSJ1aWQiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6YmFzaWMiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlIHhzaTp0eXBlPSJ4czpzdHJpbmciPnVzZXI8L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgTmFtZT0iZmlyc3RfbmFtZSIgTmFtZUZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmF0dHJuYW1lLWZvcm1hdDpiYXNpYyI+PHNhbWw6QXR0cmlidXRlVmFsdWUgeHNpOnR5cGU9InhzOnN0cmluZyI+QmFycnk8L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgTmFtZT0ibGFzdF9uYW1lIiBOYW1lRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXR0cm5hbWUtZm9ybWF0OmJhc2ljIj48c2FtbDpBdHRyaWJ1dGVWYWx1ZSB4c2k6dHlwZT0ieHM6c3RyaW5nIj5TY290dDwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBOYW1lPSJlbWFpbCIgTmFtZUZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmF0dHJuYW1lLWZvcm1hdDpiYXNpYyI+PHNhbWw6QXR0cmlidXRlVmFsdWUgeHNpOnR5cGU9InhzOnN0cmluZyI+dXNlckBleGFtcGxlLmNvbTwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBOYW1lPSJ1c2VyX2dyb3VwcyIgTmFtZUZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmF0dHJuYW1lLWZvcm1hdDpiYXNpYyI+PHNhbWw6QXR0cmlidXRlVmFsdWUgeHNpOnR5cGU9InhzOnN0cmluZyI+bWVtYmVyPC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjxzYW1sOkF0dHJpYnV0ZVZhbHVlIHhzaTp0eXBlPSJ4czpzdHJpbmciPmFkbWluPC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU+PC9zYW1sOkF0dHJpYnV0ZVN0YXRlbWVudD48L3NhbWw6QXNzZXJ0aW9uPjwvc2FtbHA6UmVzcG9uc2U+'; + protected string $acsPostData = 'PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iIElEPSJfNGRkNDU2NGRjNzk0MDYxZWYxYmFhMDQ2N2Q3OTAyOGNlZDNjZTU0YmVlIiBWZXJzaW9uPSIyLjAiIElzc3VlSW5zdGFudD0iMjAxOS0xMS0xN1QxNzo1MzozOVoiIERlc3RpbmF0aW9uPSJodHRwOi8vYm9va3N0YWNrLmxvY2FsL3NhbWwyL2FjcyIgSW5SZXNwb25zZVRvPSJPTkVMT0dJTl82YTBmNGYzOTkzMDQwZjE5ODdmZDM3MDY4YjUyOTYyMjlhZDUzNjFjIj48c2FtbDpJc3N1ZXI+aHR0cDovL3NhbWwubG9jYWwvc2FtbDIvaWRwL21ldGFkYXRhLnBocDwvc2FtbDpJc3N1ZXI+PGRzOlNpZ25hdHVyZSB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyI+CiAgPGRzOlNpZ25lZEluZm8+PGRzOkNhbm9uaWNhbGl6YXRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz4KICAgIDxkczpTaWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNyc2Etc2hhMjU2Ii8+CiAgPGRzOlJlZmVyZW5jZSBVUkk9IiNfNGRkNDU2NGRjNzk0MDYxZWYxYmFhMDQ2N2Q3OTAyOGNlZDNjZTU0YmVlIj48ZHM6VHJhbnNmb3Jtcz48ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI2VudmVsb3BlZC1zaWduYXR1cmUiLz48ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PC9kczpUcmFuc2Zvcm1zPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNzaGEyNTYiLz48ZHM6RGlnZXN0VmFsdWU+dm1oL1M3NU5mK2crZWNESkN6QWJaV0tKVmx1ZzdCZnNDKzlhV05lSXJlUT08L2RzOkRpZ2VzdFZhbHVlPjwvZHM6UmVmZXJlbmNlPjwvZHM6U2lnbmVkSW5mbz48ZHM6U2lnbmF0dXJlVmFsdWU+dnJhZ0tKWHNjVm5UNjJFaEk3bGk4MERUWHNOTGJOc3lwNWZ2QnU4WjFYSEtFUVA3QWpPNkcxcVBwaGpWQ2dRMzd6TldVVTZvUytQeFA3UDlHeG5xL3hKejRUT3lHcHJ5N1RoK2pIcHc0YWVzQTdrTmp6VU51UmU2c1ltWTlrRXh2VjMvTmJRZjROMlM2Y2RhRHIzWFRodllVVDcxYzQwNVVHOFJpQjJaY3liWHIxZU1yWCtXUDBnU2Qrc0F2RExqTjBJc3pVWlVUNThadFpEVE1ya1ZGL0pIbFBFQ04vVW1sYVBBeitTcUJ4c25xTndZK1oxYUt3MnlqeFRlNnUxM09Kb29OOVN1REowNE0rK2F3RlY3NkI4cXEyTzMxa3FBbDJibm1wTGxtTWdRNFEraUlnL3dCc09abTV1clphOWJObDNLVEhtTVBXbFpkbWhsLzgvMy9IT1RxN2thWGs3cnlWRHRLcFlsZ3FUajNhRUpuL0dwM2o4SFp5MUVialRiOTRRT1ZQMG5IQzB1V2hCaE13TjdzVjFrUSsxU2NjUlpUZXJKSGlSVUQvR0srTVg3M0YrbzJVTFRIL1Z6Tm9SM2o4N2hOLzZ1UC9JeG5aM1RudGR1MFZPZS9ucEdVWjBSMG9SWFhwa2JTL2poNWk1ZjU0RXN4eXZ1VEM5NHdKaEM8L2RzOlNpZ25hdHVyZVZhbHVlPgo8ZHM6S2V5SW5mbz48ZHM6WDUwOURhdGE+PGRzOlg1MDlDZXJ0aWZpY2F0ZT5NSUlFYXpDQ0F0T2dBd0lCQWdJVWU3YTA4OENucjRpem1ybkJFbng1cTNIVE12WXdEUVlKS29aSWh2Y05BUUVMQlFBd1JURUxNQWtHQTFVRUJoTUNSMEl4RXpBUkJnTlZCQWdNQ2xOdmJXVXRVM1JoZEdVeElUQWZCZ05WQkFvTUdFbHVkR1Z5Ym1WMElGZHBaR2RwZEhNZ1VIUjVJRXgwWkRBZUZ3MHhPVEV4TVRZeE1qRTNNVFZhRncweU9URXhNVFV4TWpFM01UVmFNRVV4Q3pBSkJnTlZCQVlUQWtkQ01STXdFUVlEVlFRSURBcFRiMjFsTFZOMFlYUmxNU0V3SHdZRFZRUUtEQmhKYm5SbGNtNWxkQ0JYYVdSbmFYUnpJRkIwZVNCTWRHUXdnZ0dpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCandBd2dnR0tBb0lCZ1FEekxlOUZmZHlwbFR4SHA0U3VROWdRdFpUM3QrU0RmdkVMNzJwcENmRlp3NytCNXM1Qi9UNzNhWHBvUTNTNTNwR0kxUklXQ2dlMmlDVVEydHptMjdhU05IMGl1OWFKWWNVUVovUklUcWQwYXl5RGtzMU5BMlBUM1RXNnQzbTdLVjVyZTRQME5iK1lEZXV5SGRreitqY010cG44Q21Cb1QwSCtza2hhMGhpcUlOa2prUlBpSHZMSFZHcCt0SFVFQS9JNm1ONGFCL1VFeFNUTHM3OU5zTFVmdGVxcXhlOSt0dmRVYVRveURQcmhQRmpPTnMrOU5LQ2t6SUM2dmN2N0o2QXR1S0c2bkVUK3pCOXlPV2d0R1lRaWZYcVFBMnk1ZEw4MUJCMHE1dU1hQkxTMnBxM2FQUGp6VTJGMytFeXNqeVNXVG5Da2ZrN0M1U3NDWFJ1OFErVTk1dHVucE5md2Y1b2xFNldhczQ4Tk1NK1B3VjdpQ05NUGtOemxscTZQQ2lNK1A4RHJNU2N6elVaWlFVU3Y2ZFN3UENvK1lTVmltRU0wT2czWEpUaU5oUTVBTmxhSW42Nkt3NWdmb0JmdWlYbXlJS2lTRHlBaURZbUZhZjQzOTV3V3dMa1RSK2N3OFdmamFIc3dLWlRvbW4xTVIzT0pzWTJVSjBlUkJZTStZU3NDQXdFQUFhTlRNRkV3SFFZRFZSME9CQllFRkltcDJDWUNHZmNiN3c5MUgvY1NoVENrWHdSL01COEdBMVVkSXdRWU1CYUFGSW1wMkNZQ0dmY2I3dzkxSC9jU2hUQ2tYd1IvTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3RFFZSktvWklodmNOQVFFTEJRQURnZ0dCQUErZy9DN3VMOWxuK1crcUJrbkxXODFrb2pZZmxnUEsxSTFNSEl3bk12bC9aVEhYNGRSWEtEcms3S2NVcTFLanFhak5WNjZmMWNha3AwM0lpakJpTzBYaTFnWFVaWUxvQ2lOR1V5eXA5WGxvaUl5OVh3MlBpV25ydzAreVp5dlZzc2JlaFhYWUpsNFJpaEJqQld1bDlSNHdNWUxPVVNKRGUyV3hjVUJoSm54eU5ScytQMHhMU1FYNkIybjZueG9Ea280cDA3czhaS1hRa2VpWjJpd0ZkVHh6UmtHanRoTVV2NzA0bnpzVkdCVDBEQ1B0ZlNhTzVLSlpXMXJDczN5aU10aG5CeHE0cUVET1FKRklsKy9MRDcxS2JCOXZaY1c1SnVhdnpCRm1rS0dOcm8vNkcxSTdlbDQ2SVI0d2lqVHlORkNZVXVEOWR0aWduTm1wV3ROOE9XK3B0aUwvanRUeVNXdWtqeXMwcyt2TG44M0NWdmpCMGRKdFZBSVlPZ1hGZEl1aWk2Nmdjend3TS9MR2lPRXhKbjBkVE56c0ovSVlocHhMNEZCRXVQMHBza1kwbzBhVWxKMkxTMmord1NRVFJLc0JnTWp5clVyZWtsZTJPRFN0U3RuM2VhYmpJeDAvRkhscEZyMGpOSW0vb01QN2t3anRVWDR6YU5lNDdRSTRHZz09PC9kczpYNTA5Q2VydGlmaWNhdGU+PC9kczpYNTA5RGF0YT48L2RzOktleUluZm8+PC9kczpTaWduYXR1cmU+PHNhbWxwOlN0YXR1cz48c2FtbHA6U3RhdHVzQ29kZSBWYWx1ZT0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnN0YXR1czpTdWNjZXNzIi8+PC9zYW1scDpTdGF0dXM+PHNhbWw6QXNzZXJ0aW9uIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhtbG5zOnhzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgSUQ9Il82ODQyZGY5YzY1OWYxM2ZlNTE5NmNkOWVmNmMyZjAyODM2NGFlOTQzYjEiIFZlcnNpb249IjIuMCIgSXNzdWVJbnN0YW50PSIyMDE5LTExLTE3VDE3OjUzOjM5WiI+PHNhbWw6SXNzdWVyPmh0dHA6Ly9zYW1sLmxvY2FsL3NhbWwyL2lkcC9tZXRhZGF0YS5waHA8L3NhbWw6SXNzdWVyPjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPgogIDxkczpTaWduZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+CiAgICA8ZHM6U2lnbmF0dXJlTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxkc2lnLW1vcmUjcnNhLXNoYTI1NiIvPgogIDxkczpSZWZlcmVuY2UgVVJJPSIjXzY4NDJkZjljNjU5ZjEzZmU1MTk2Y2Q5ZWY2YzJmMDI4MzY0YWU5NDNiMSI+PGRzOlRyYW5zZm9ybXM+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0dXJlIi8+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjwvZHM6VHJhbnNmb3Jtcz48ZHM6RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjc2hhMjU2Ii8+PGRzOkRpZ2VzdFZhbHVlPmtyYjV3NlM4dG9YYy9lU3daUFVPQnZRem4zb3M0SkFDdXh4ckpreHBnRnc9PC9kczpEaWdlc3RWYWx1ZT48L2RzOlJlZmVyZW5jZT48L2RzOlNpZ25lZEluZm8+PGRzOlNpZ25hdHVyZVZhbHVlPjJxcW1Ba3hucXhOa3N5eXh5dnFTVDUxTDg5VS9ZdHpja2t1ekF4ci9hQ1JTK1NPRzg1YkFNWm8vU3puc3d0TVlBYlFRQ0VGb0R1amdNdlpzSFl3NlR2dmFHanlXWUpRNVZyYWhlemZaSWlCVUU0NHBtWGFrOCswV0l0WTVndnBGSXhxWFZaRmdFUkt2VExmZVFCMzhkMVZQc0ZVZ0RYdXQ4VS9Qdm43dXZwdXZjVXorMUUyOUVKR2FZL0dndnhUN0tyWU9SQTh3SitNdVRzUVZtanNlUnhveVJTejA4TmJ3ZTJIOGpXQnpFWWNxWWwyK0ZnK2hwNWd0S216VmhLRnBkNXZBNjdBSXo1NXN0QmNHNSswNHJVaWpFSzRzci9xa0x5QmtKQjdLdkwzanZKcG8zQjhxYkxYeXhLb1dSSmRnazhKNHMvTVp1QWk3QWUxUXNTTjl2Z3ZTdVRlc0VCUjVpSHJuS1lrbEpRWXNrbUQzbSsremE4U1NRbnBlM0UzYUZBY3p6cElUdUQ4YkFCWmRqcUk2TkhrSmFRQXBmb0hWNVQrZ244ejdUTWsrSStUU2JlQURubUxCS3lnMHRabW10L0ZKbDV6eWowVmxwc1dzTVM2OVE2bUZJVStqcEhSanpOb2FLMVM1dlQ3ZW1HbUhKSUp0cWlOdXJRN0tkQlBJPC9kczpTaWduYXR1cmVWYWx1ZT4KPGRzOktleUluZm8+PGRzOlg1MDlEYXRhPjxkczpYNTA5Q2VydGlmaWNhdGU+TUlJRWF6Q0NBdE9nQXdJQkFnSVVlN2EwODhDbnI0aXptcm5CRW54NXEzSFRNdll3RFFZSktvWklodmNOQVFFTEJRQXdSVEVMTUFrR0ExVUVCaE1DUjBJeEV6QVJCZ05WQkFnTUNsTnZiV1V0VTNSaGRHVXhJVEFmQmdOVkJBb01HRWx1ZEdWeWJtVjBJRmRwWkdkcGRITWdVSFI1SUV4MFpEQWVGdzB4T1RFeE1UWXhNakUzTVRWYUZ3MHlPVEV4TVRVeE1qRTNNVFZhTUVVeEN6QUpCZ05WQkFZVEFrZENNUk13RVFZRFZRUUlEQXBUYjIxbExWTjBZWFJsTVNFd0h3WURWUVFLREJoSmJuUmxjbTVsZENCWGFXUm5hWFJ6SUZCMGVTQk1kR1F3Z2dHaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQmp3QXdnZ0dLQW9JQmdRRHpMZTlGZmR5cGxUeEhwNFN1UTlnUXRaVDN0K1NEZnZFTDcycHBDZkZadzcrQjVzNUIvVDczYVhwb1EzUzUzcEdJMVJJV0NnZTJpQ1VRMnR6bTI3YVNOSDBpdTlhSlljVVFaL1JJVHFkMGF5eURrczFOQTJQVDNUVzZ0M203S1Y1cmU0UDBOYitZRGV1eUhka3oramNNdHBuOENtQm9UMEgrc2toYTBoaXFJTmtqa1JQaUh2TEhWR3ArdEhVRUEvSTZtTjRhQi9VRXhTVExzNzlOc0xVZnRlcXF4ZTkrdHZkVWFUb3lEUHJoUEZqT05zKzlOS0NreklDNnZjdjdKNkF0dUtHNm5FVCt6Qjl5T1dndEdZUWlmWHFRQTJ5NWRMODFCQjBxNXVNYUJMUzJwcTNhUFBqelUyRjMrRXlzanlTV1RuQ2tmazdDNVNzQ1hSdThRK1U5NXR1bnBOZndmNW9sRTZXYXM0OE5NTStQd1Y3aUNOTVBrTnpsbHE2UENpTStQOERyTVNjenpVWlpRVVN2NmRTd1BDbytZU1ZpbUVNME9nM1hKVGlOaFE1QU5sYUluNjZLdzVnZm9CZnVpWG15SUtpU0R5QWlEWW1GYWY0Mzk1d1d3TGtUUitjdzhXZmphSHN3S1pUb21uMU1SM09Kc1kyVUowZVJCWU0rWVNzQ0F3RUFBYU5UTUZFd0hRWURWUjBPQkJZRUZJbXAyQ1lDR2ZjYjd3OTFIL2NTaFRDa1h3Ui9NQjhHQTFVZEl3UVlNQmFBRkltcDJDWUNHZmNiN3c5MUgvY1NoVENrWHdSL01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dHQkFBK2cvQzd1TDlsbitXK3FCa25MVzgxa29qWWZsZ1BLMUkxTUhJd25NdmwvWlRIWDRkUlhLRHJrN0tjVXExS2pxYWpOVjY2ZjFjYWtwMDNJaWpCaU8wWGkxZ1hVWllMb0NpTkdVeXlwOVhsb2lJeTlYdzJQaVducncwK3laeXZWc3NiZWhYWFlKbDRSaWhCakJXdWw5UjR3TVlMT1VTSkRlMld4Y1VCaEpueHlOUnMrUDB4TFNRWDZCMm42bnhvRGtvNHAwN3M4WktYUWtlaVoyaXdGZFR4elJrR2p0aE1VdjcwNG56c1ZHQlQwRENQdGZTYU81S0paVzFyQ3MzeWlNdGhuQnhxNHFFRE9RSkZJbCsvTEQ3MUtiQjl2WmNXNUp1YXZ6QkZta0tHTnJvLzZHMUk3ZWw0NklSNHdpalR5TkZDWVV1RDlkdGlnbk5tcFd0TjhPVytwdGlML2p0VHlTV3VranlzMHMrdkxuODNDVnZqQjBkSnRWQUlZT2dYRmRJdWlpNjZnY3p3d00vTEdpT0V4Sm4wZFROenNKL0lZaHB4TDRGQkV1UDBwc2tZMG8wYVVsSjJMUzJqK3dTUVRSS3NCZ01qeXJVcmVrbGUyT0RTdFN0bjNlYWJqSXgwL0ZIbHBGcjBqTkltL29NUDdrd2p0VVg0emFOZTQ3UUk0R2c9PTwvZHM6WDUwOUNlcnRpZmljYXRlPjwvZHM6WDUwOURhdGE+PC9kczpLZXlJbmZvPjwvZHM6U2lnbmF0dXJlPjxzYW1sOlN1YmplY3Q+PHNhbWw6TmFtZUlEIFNQTmFtZVF1YWxpZmllcj0iaHR0cDovL2Jvb2tzdGFjay5sb2NhbC9zYW1sMi9tZXRhZGF0YSIgRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6bmFtZWlkLWZvcm1hdDp0cmFuc2llbnQiPl8yYzdhYjg2ZWI4ZjFkMTA2MzQ0M2YyMTljYzU4NjhmZjY2NzA4OTEyZTM8L3NhbWw6TmFtZUlEPjxzYW1sOlN1YmplY3RDb25maXJtYXRpb24gTWV0aG9kPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6Y206YmVhcmVyIj48c2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uRGF0YSBOb3RPbk9yQWZ0ZXI9IjIwMTktMTEtMTdUMTc6NTg6MzlaIiBSZWNpcGllbnQ9Imh0dHA6Ly9ib29rc3RhY2subG9jYWwvc2FtbDIvYWNzIiBJblJlc3BvbnNlVG89Ik9ORUxPR0lOXzZhMGY0ZjM5OTMwNDBmMTk4N2ZkMzcwNjhiNTI5NjIyOWFkNTM2MWMiLz48L3NhbWw6U3ViamVjdENvbmZpcm1hdGlvbj48L3NhbWw6U3ViamVjdD48c2FtbDpDb25kaXRpb25zIE5vdEJlZm9yZT0iMjAxOS0xMS0xN1QxNzo1MzowOVoiIE5vdE9uT3JBZnRlcj0iMjAxOS0xMS0xN1QxNzo1ODozOVoiPjxzYW1sOkF1ZGllbmNlUmVzdHJpY3Rpb24+PHNhbWw6QXVkaWVuY2U+aHR0cDovL2Jvb2tzdGFjay5sb2NhbC9zYW1sMi9tZXRhZGF0YTwvc2FtbDpBdWRpZW5jZT48L3NhbWw6QXVkaWVuY2VSZXN0cmljdGlvbj48L3NhbWw6Q29uZGl0aW9ucz48c2FtbDpBdXRoblN0YXRlbWVudCBBdXRobkluc3RhbnQ9IjIwMTktMTEtMTdUMTc6NTM6MzlaIiBTZXNzaW9uTm90T25PckFmdGVyPSIyMDE5LTExLTE4VDAxOjUzOjM5WiIgU2Vzc2lvbkluZGV4PSJfNGZlN2MwZDE1NzJkNjRiMjdmOTMwYWE2ZjIzNmE2ZjQyZTkzMDkwMWNjIj48c2FtbDpBdXRobkNvbnRleHQ+PHNhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFjOmNsYXNzZXM6UGFzc3dvcmQ8L3NhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+PC9zYW1sOkF1dGhuQ29udGV4dD48L3NhbWw6QXV0aG5TdGF0ZW1lbnQ+PHNhbWw6QXR0cmlidXRlU3RhdGVtZW50PjxzYW1sOkF0dHJpYnV0ZSBOYW1lPSJ1aWQiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6YmFzaWMiPjxzYW1sOkF0dHJpYnV0ZVZhbHVlIHhzaTp0eXBlPSJ4czpzdHJpbmciPnVzZXI8L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgTmFtZT0iZmlyc3RfbmFtZSIgTmFtZUZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmF0dHJuYW1lLWZvcm1hdDpiYXNpYyI+PHNhbWw6QXR0cmlidXRlVmFsdWUgeHNpOnR5cGU9InhzOnN0cmluZyI+QmFycnk8L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48c2FtbDpBdHRyaWJ1dGUgTmFtZT0ibGFzdF9uYW1lIiBOYW1lRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXR0cm5hbWUtZm9ybWF0OmJhc2ljIj48c2FtbDpBdHRyaWJ1dGVWYWx1ZSB4c2k6dHlwZT0ieHM6c3RyaW5nIj5TY290dDwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBOYW1lPSJlbWFpbCIgTmFtZUZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmF0dHJuYW1lLWZvcm1hdDpiYXNpYyI+PHNhbWw6QXR0cmlidXRlVmFsdWUgeHNpOnR5cGU9InhzOnN0cmluZyI+dXNlckBleGFtcGxlLmNvbTwvc2FtbDpBdHRyaWJ1dGVWYWx1ZT48L3NhbWw6QXR0cmlidXRlPjxzYW1sOkF0dHJpYnV0ZSBOYW1lPSJ1c2VyX2dyb3VwcyIgTmFtZUZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmF0dHJuYW1lLWZvcm1hdDpiYXNpYyI+PHNhbWw6QXR0cmlidXRlVmFsdWUgeHNpOnR5cGU9InhzOnN0cmluZyI+bWVtYmVyPC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjxzYW1sOkF0dHJpYnV0ZVZhbHVlIHhzaTp0eXBlPSJ4czpzdHJpbmciPmFkbWluPC9zYW1sOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDpBdHRyaWJ1dGU+PC9zYW1sOkF0dHJpYnV0ZVN0YXRlbWVudD48L3NhbWw6QXNzZXJ0aW9uPjwvc2FtbHA6UmVzcG9uc2U+'; - protected $sloResponseData = 'fZHRa8IwEMb/lZJ3bdJa04a2MOYYglOY4sNe5JKms9gmpZfC/vxF3ZjC8OXgLvl938ddjtC1vVjZTzu6d429NaiDr641KC5PBRkHIyxgg8JAp1E4JbZPbysRTanoB+ussi25QR4TgKgH11hDguWiIIeawTxOaK1iPYt5XcczHUlJeVRlMklBJjOuM1qDVCTY6wE9WRAv5HHEUS8NOjDOjyjLJoxNGN+xVESpSNgHCRYaXWPAXaijc70IQ2ntyUPqNG2tgjY8Z45CbNFLmt8V7GxBNuuX1eZ1uT7EcZJKAE4TJhXPaMxlVlFffPKKJnXE5ryusoiU+VlMXJIN5Y/feXRn1VR92GkHFTiY9sc+D2+p/HqRrQM34n33bCsd7KEd9eMd4+W32I5KaUQSlleHP9Hwv6uX3w=='; + protected string $sloResponseData = 'fZHRa8IwEMb/lZJ3bdJa04a2MOYYglOY4sNe5JKms9gmpZfC/vxF3ZjC8OXgLvl938ddjtC1vVjZTzu6d429NaiDr641KC5PBRkHIyxgg8JAp1E4JbZPbysRTanoB+ussi25QR4TgKgH11hDguWiIIeawTxOaK1iPYt5XcczHUlJeVRlMklBJjOuM1qDVCTY6wE9WRAv5HHEUS8NOjDOjyjLJoxNGN+xVESpSNgHCRYaXWPAXaijc70IQ2ntyUPqNG2tgjY8Z45CbNFLmt8V7GxBNuuX1eZ1uT7EcZJKAE4TJhXPaMxlVlFffPKKJnXE5ryusoiU+VlMXJIN5Y/feXRn1VR92GkHFTiY9sc+D2+p/HqRrQM34n33bCsd7KEd9eMd4+W32I5KaUQSlleHP9Hwv6uX3w=='; - protected $testCert = 'MIIEazCCAtOgAwIBAgIUe7a088Cnr4izmrnBEnx5q3HTMvYwDQYJKoZIhvcNAQELBQAwRTELMAkGA1UEBhMCR0IxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xOTExMTYxMjE3MTVaFw0yOTExMTUxMjE3MTVaMEUxCzAJBgNVBAYTAkdCMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDzLe9FfdyplTxHp4SuQ9gQtZT3t+SDfvEL72ppCfFZw7+B5s5B/T73aXpoQ3S53pGI1RIWCge2iCUQ2tzm27aSNH0iu9aJYcUQZ/RITqd0ayyDks1NA2PT3TW6t3m7KV5re4P0Nb+YDeuyHdkz+jcMtpn8CmBoT0H+skha0hiqINkjkRPiHvLHVGp+tHUEA/I6mN4aB/UExSTLs79NsLUfteqqxe9+tvdUaToyDPrhPFjONs+9NKCkzIC6vcv7J6AtuKG6nET+zB9yOWgtGYQifXqQA2y5dL81BB0q5uMaBLS2pq3aPPjzU2F3+EysjySWTnCkfk7C5SsCXRu8Q+U95tunpNfwf5olE6Was48NMM+PwV7iCNMPkNzllq6PCiM+P8DrMSczzUZZQUSv6dSwPCo+YSVimEM0Og3XJTiNhQ5ANlaIn66Kw5gfoBfuiXmyIKiSDyAiDYmFaf4395wWwLkTR+cw8WfjaHswKZTomn1MR3OJsY2UJ0eRBYM+YSsCAwEAAaNTMFEwHQYDVR0OBBYEFImp2CYCGfcb7w91H/cShTCkXwR/MB8GA1UdIwQYMBaAFImp2CYCGfcb7w91H/cShTCkXwR/MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggGBAA+g/C7uL9ln+W+qBknLW81kojYflgPK1I1MHIwnMvl/ZTHX4dRXKDrk7KcUq1KjqajNV66f1cakp03IijBiO0Xi1gXUZYLoCiNGUyyp9XloiIy9Xw2PiWnrw0+yZyvVssbehXXYJl4RihBjBWul9R4wMYLOUSJDe2WxcUBhJnxyNRs+P0xLSQX6B2n6nxoDko4p07s8ZKXQkeiZ2iwFdTxzRkGjthMUv704nzsVGBT0DCPtfSaO5KJZW1rCs3yiMthnBxq4qEDOQJFIl+/LD71KbB9vZcW5JuavzBFmkKGNro/6G1I7el46IR4wijTyNFCYUuD9dtignNmpWtN8OW+ptiL/jtTySWukjys0s+vLn83CVvjB0dJtVAIYOgXFdIuii66gczwwM/LGiOExJn0dTNzsJ/IYhpxL4FBEuP0pskY0o0aUlJ2LS2j+wSQTRKsBgMjyrUrekle2ODStStn3eabjIx0/FHlpFr0jNIm/oMP7kwjtUX4zaNe47QI4Gg=='; + protected string $testCert = 'MIIEazCCAtOgAwIBAgIUe7a088Cnr4izmrnBEnx5q3HTMvYwDQYJKoZIhvcNAQELBQAwRTELMAkGA1UEBhMCR0IxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xOTExMTYxMjE3MTVaFw0yOTExMTUxMjE3MTVaMEUxCzAJBgNVBAYTAkdCMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDzLe9FfdyplTxHp4SuQ9gQtZT3t+SDfvEL72ppCfFZw7+B5s5B/T73aXpoQ3S53pGI1RIWCge2iCUQ2tzm27aSNH0iu9aJYcUQZ/RITqd0ayyDks1NA2PT3TW6t3m7KV5re4P0Nb+YDeuyHdkz+jcMtpn8CmBoT0H+skha0hiqINkjkRPiHvLHVGp+tHUEA/I6mN4aB/UExSTLs79NsLUfteqqxe9+tvdUaToyDPrhPFjONs+9NKCkzIC6vcv7J6AtuKG6nET+zB9yOWgtGYQifXqQA2y5dL81BB0q5uMaBLS2pq3aPPjzU2F3+EysjySWTnCkfk7C5SsCXRu8Q+U95tunpNfwf5olE6Was48NMM+PwV7iCNMPkNzllq6PCiM+P8DrMSczzUZZQUSv6dSwPCo+YSVimEM0Og3XJTiNhQ5ANlaIn66Kw5gfoBfuiXmyIKiSDyAiDYmFaf4395wWwLkTR+cw8WfjaHswKZTomn1MR3OJsY2UJ0eRBYM+YSsCAwEAAaNTMFEwHQYDVR0OBBYEFImp2CYCGfcb7w91H/cShTCkXwR/MB8GA1UdIwQYMBaAFImp2CYCGfcb7w91H/cShTCkXwR/MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggGBAA+g/C7uL9ln+W+qBknLW81kojYflgPK1I1MHIwnMvl/ZTHX4dRXKDrk7KcUq1KjqajNV66f1cakp03IijBiO0Xi1gXUZYLoCiNGUyyp9XloiIy9Xw2PiWnrw0+yZyvVssbehXXYJl4RihBjBWul9R4wMYLOUSJDe2WxcUBhJnxyNRs+P0xLSQX6B2n6nxoDko4p07s8ZKXQkeiZ2iwFdTxzRkGjthMUv704nzsVGBT0DCPtfSaO5KJZW1rCs3yiMthnBxq4qEDOQJFIl+/LD71KbB9vZcW5JuavzBFmkKGNro/6G1I7el46IR4wijTyNFCYUuD9dtignNmpWtN8OW+ptiL/jtTySWukjys0s+vLn83CVvjB0dJtVAIYOgXFdIuii66gczwwM/LGiOExJn0dTNzsJ/IYhpxL4FBEuP0pskY0o0aUlJ2LS2j+wSQTRKsBgMjyrUrekle2ODStStn3eabjIx0/FHlpFr0jNIm/oMP7kwjtUX4zaNe47QI4Gg=='; } diff --git a/tests/Commands/UpdateUrlCommandTest.php b/tests/Commands/UpdateUrlCommandTest.php index 280c81feb..62c39c274 100644 --- a/tests/Commands/UpdateUrlCommandTest.php +++ b/tests/Commands/UpdateUrlCommandTest.php @@ -2,6 +2,7 @@ namespace Tests\Commands; +use BookStack\Entities\Models\Entity; use Illuminate\Support\Facades\Artisan; use Symfony\Component\Console\Exception\RuntimeException; use Tests\TestCase; @@ -24,6 +25,28 @@ class UpdateUrlCommandTest extends TestCase ]); } + public function test_command_updates_description_html() + { + /** @var Entity[] $models */ + $models = [$this->entities->book(), $this->entities->chapter(), $this->entities->shelf()]; + + foreach ($models as $model) { + $model->description_html = ''; + $model->save(); + } + + $this->artisan('bookstack:update-url https://example.com https://cats.example.com') + ->expectsQuestion("This will search for \"https://example.com\" in your database and replace it with \"https://cats.example.com\".\nAre you sure you want to proceed?", 'y') + ->expectsQuestion('This operation could cause issues if used incorrectly. Have you made a backup of your existing database?', 'y'); + + foreach ($models as $model) { + $this->assertDatabaseHas($model->getTable(), [ + 'id' => $model->id, + 'description_html' => '', + ]); + } + } + public function test_command_requires_valid_url() { $badUrlMessage = 'The given urls are expected to be full urls starting with http:// or https://'; diff --git a/tests/DebugViewTest.php b/tests/DebugViewTest.php index 43de9f175..34de6b802 100644 --- a/tests/DebugViewTest.php +++ b/tests/DebugViewTest.php @@ -2,7 +2,7 @@ namespace Tests; -use BookStack\Access\SocialAuthService; +use BookStack\Access\SocialDriverManager; use Illuminate\Testing\TestResponse; class DebugViewTest extends TestCase @@ -46,8 +46,8 @@ class DebugViewTest extends TestCase protected function getDebugViewForException(\Exception $exception): TestResponse { // Fake an error via social auth service used on login page - $mockService = $this->mock(SocialAuthService::class); - $mockService->shouldReceive('getActiveDrivers')->andThrow($exception); + $mockService = $this->mock(SocialDriverManager::class); + $mockService->shouldReceive('getActive')->andThrow($exception); return $this->get('/login'); } diff --git a/tests/Entity/BookDefaultTemplateTest.php b/tests/Entity/BookDefaultTemplateTest.php new file mode 100644 index 000000000..d4cd5b2c3 --- /dev/null +++ b/tests/Entity/BookDefaultTemplateTest.php @@ -0,0 +1,185 @@ +entities->templatePage(); + $details = [ + 'name' => 'My book with default template', + 'default_template_id' => $templatePage->id, + ]; + + $this->asEditor()->post('/books', $details); + $this->assertDatabaseHas('books', $details); + } + + public function test_updating_book_with_default_template() + { + $book = $this->entities->book(); + $templatePage = $this->entities->templatePage(); + + $this->asEditor()->put("/books/{$book->slug}", ['name' => $book->name, 'default_template_id' => strval($templatePage->id)]); + $this->assertDatabaseHas('books', ['id' => $book->id, 'default_template_id' => $templatePage->id]); + + $this->asEditor()->put("/books/{$book->slug}", ['name' => $book->name, 'default_template_id' => '']); + $this->assertDatabaseHas('books', ['id' => $book->id, 'default_template_id' => null]); + } + + public function test_default_template_cannot_be_set_if_not_a_template() + { + $book = $this->entities->book(); + $page = $this->entities->page(); + $this->assertFalse($page->template); + + $this->asEditor()->put("/books/{$book->slug}", ['name' => $book->name, 'default_template_id' => $page->id]); + $this->assertDatabaseHas('books', ['id' => $book->id, 'default_template_id' => null]); + } + + public function test_default_template_cannot_be_set_if_not_have_access() + { + $book = $this->entities->book(); + $templatePage = $this->entities->templatePage(); + $this->permissions->disableEntityInheritedPermissions($templatePage); + + $this->asEditor()->put("/books/{$book->slug}", ['name' => $book->name, 'default_template_id' => $templatePage->id]); + $this->assertDatabaseHas('books', ['id' => $book->id, 'default_template_id' => null]); + } + + public function test_inaccessible_default_template_can_be_set_if_unchanged() + { + $templatePage = $this->entities->templatePage(); + $book = $this->bookUsingDefaultTemplate($templatePage); + $this->permissions->disableEntityInheritedPermissions($templatePage); + + $this->asEditor()->put("/books/{$book->slug}", ['name' => $book->name, 'default_template_id' => $templatePage->id]); + $this->assertDatabaseHas('books', ['id' => $book->id, 'default_template_id' => $templatePage->id]); + } + + public function test_default_page_template_option_shows_on_book_form() + { + $templatePage = $this->entities->templatePage(); + $book = $this->bookUsingDefaultTemplate($templatePage); + + $resp = $this->asEditor()->get($book->getUrl('/edit')); + $this->withHtml($resp)->assertElementExists('input[name="default_template_id"][value="' . $templatePage->id . '"]'); + } + + public function test_default_page_template_option_only_shows_template_name_if_visible() + { + $templatePage = $this->entities->templatePage(); + $book = $this->bookUsingDefaultTemplate($templatePage); + + $resp = $this->asEditor()->get($book->getUrl('/edit')); + $this->withHtml($resp)->assertElementContains('#template-control a.text-page', "#{$templatePage->id}, {$templatePage->name}"); + + $this->permissions->disableEntityInheritedPermissions($templatePage); + + $resp = $this->asEditor()->get($book->getUrl('/edit')); + $this->withHtml($resp)->assertElementNotContains('#template-control a.text-page', "#{$templatePage->id}, {$templatePage->name}"); + $this->withHtml($resp)->assertElementContains('#template-control a.text-page', "#{$templatePage->id}"); + } + + public function test_creating_book_page_uses_default_template() + { + $templatePage = $this->entities->templatePage(); + $templatePage->forceFill(['html' => '

    My template page

    ', 'markdown' => '# My template page'])->save(); + $book = $this->bookUsingDefaultTemplate($templatePage); + + $this->asEditor()->get($book->getUrl('/create-page')); + $latestPage = $book->pages() + ->where('draft', '=', true) + ->where('template', '=', false) + ->latest()->first(); + + $this->assertEquals('

    My template page

    ', $latestPage->html); + $this->assertEquals('# My template page', $latestPage->markdown); + } + + public function test_creating_chapter_page_uses_default_template() + { + $templatePage = $this->entities->templatePage(); + $templatePage->forceFill(['html' => '

    My template page in chapter

    ', 'markdown' => '# My template page in chapter'])->save(); + $book = $this->bookUsingDefaultTemplate($templatePage); + $chapter = $book->chapters()->first(); + + $this->asEditor()->get($chapter->getUrl('/create-page')); + $latestPage = $chapter->pages() + ->where('draft', '=', true) + ->where('template', '=', false) + ->latest()->first(); + + $this->assertEquals('

    My template page in chapter

    ', $latestPage->html); + $this->assertEquals('# My template page in chapter', $latestPage->markdown); + } + + public function test_creating_book_page_as_guest_uses_default_template() + { + $templatePage = $this->entities->templatePage(); + $templatePage->forceFill(['html' => '

    My template page

    ', 'markdown' => '# My template page'])->save(); + $book = $this->bookUsingDefaultTemplate($templatePage); + $guest = $this->users->guest(); + + $this->permissions->makeAppPublic(); + $this->permissions->grantUserRolePermissions($guest, ['page-create-all', 'page-update-all']); + + $resp = $this->post($book->getUrl('/create-guest-page'), [ + 'name' => 'My guest page with template' + ]); + $latestPage = $book->pages() + ->where('draft', '=', false) + ->where('template', '=', false) + ->where('created_by', '=', $guest->id) + ->latest()->first(); + + $this->assertEquals('

    My template page

    ', $latestPage->html); + $this->assertEquals('# My template page', $latestPage->markdown); + } + + public function test_creating_book_page_does_not_use_template_if_not_visible() + { + $templatePage = $this->entities->templatePage(); + $templatePage->forceFill(['html' => '

    My template page

    ', 'markdown' => '# My template page'])->save(); + $book = $this->bookUsingDefaultTemplate($templatePage); + $this->permissions->disableEntityInheritedPermissions($templatePage); + + $this->asEditor()->get($book->getUrl('/create-page')); + $latestPage = $book->pages() + ->where('draft', '=', true) + ->where('template', '=', false) + ->latest()->first(); + + $this->assertEquals('', $latestPage->html); + $this->assertEquals('', $latestPage->markdown); + } + + public function test_template_page_delete_removes_book_template_usage() + { + $templatePage = $this->entities->templatePage(); + $book = $this->bookUsingDefaultTemplate($templatePage); + + $book->refresh(); + $this->assertEquals($templatePage->id, $book->default_template_id); + + $this->asEditor()->delete($templatePage->getUrl()); + $this->asAdmin()->post('/settings/recycle-bin/empty'); + + $book->refresh(); + $this->assertEquals(null, $book->default_template_id); + } + + protected function bookUsingDefaultTemplate(Page $page): Book + { + $book = $this->entities->book(); + $book->default_template_id = $page->id; + $book->save(); + + return $book; + } +} diff --git a/tests/Entity/BookShelfTest.php b/tests/Entity/BookShelfTest.php index c1842c175..fb9862931 100644 --- a/tests/Entity/BookShelfTest.php +++ b/tests/Entity/BookShelfTest.php @@ -77,8 +77,8 @@ class BookShelfTest extends TestCase { $booksToInclude = Book::take(2)->get(); $shelfInfo = [ - 'name' => 'My test book' . Str::random(4), - 'description' => 'Test book description ' . Str::random(10), + 'name' => 'My test shelf' . Str::random(4), + 'description_html' => '

    Test book description ' . Str::random(10) . '

    ', ]; $resp = $this->asEditor()->post('/shelves', array_merge($shelfInfo, [ 'books' => $booksToInclude->implode('id', ','), @@ -96,7 +96,7 @@ class BookShelfTest extends TestCase $shelf = Bookshelf::where('name', '=', $shelfInfo['name'])->first(); $shelfPage = $this->get($shelf->getUrl()); $shelfPage->assertSee($shelfInfo['name']); - $shelfPage->assertSee($shelfInfo['description']); + $shelfPage->assertSee($shelfInfo['description_html'], false); $this->withHtml($shelfPage)->assertElementContains('.tag-item', 'Test Category'); $this->withHtml($shelfPage)->assertElementContains('.tag-item', 'Test Tag Value'); @@ -107,8 +107,8 @@ class BookShelfTest extends TestCase public function test_shelves_create_sets_cover_image() { $shelfInfo = [ - 'name' => 'My test book' . Str::random(4), - 'description' => 'Test book description ' . Str::random(10), + 'name' => 'My test shelf' . Str::random(4), + 'description_html' => '

    Test book description ' . Str::random(10) . '

    ', ]; $imageFile = $this->files->uploadedImage('shelf-test.png'); @@ -174,7 +174,7 @@ class BookShelfTest extends TestCase // Set book ordering $this->asAdmin()->put($shelf->getUrl(), [ 'books' => $books->implode('id', ','), - 'tags' => [], 'description' => 'abc', 'name' => 'abc', + 'tags' => [], 'description_html' => 'abc', 'name' => 'abc', ]); $this->assertEquals(3, $shelf->books()->count()); $shelf->refresh(); @@ -207,7 +207,7 @@ class BookShelfTest extends TestCase // Set book ordering $this->asAdmin()->put($shelf->getUrl(), [ 'books' => $books->implode('id', ','), - 'tags' => [], 'description' => 'abc', 'name' => 'abc', + 'tags' => [], 'description_html' => 'abc', 'name' => 'abc', ]); $this->assertEquals(3, $shelf->books()->count()); $shelf->refresh(); @@ -229,8 +229,8 @@ class BookShelfTest extends TestCase $booksToInclude = Book::take(2)->get(); $shelfInfo = [ - 'name' => 'My test book' . Str::random(4), - 'description' => 'Test book description ' . Str::random(10), + 'name' => 'My test shelf' . Str::random(4), + 'description_html' => '

    Test book description ' . Str::random(10) . '

    ', ]; $resp = $this->asEditor()->put($shelf->getUrl(), array_merge($shelfInfo, [ @@ -251,7 +251,7 @@ class BookShelfTest extends TestCase $shelfPage = $this->get($shelf->getUrl()); $shelfPage->assertSee($shelfInfo['name']); - $shelfPage->assertSee($shelfInfo['description']); + $shelfPage->assertSee($shelfInfo['description_html'], false); $this->withHtml($shelfPage)->assertElementContains('.tag-item', 'Test Category'); $this->withHtml($shelfPage)->assertElementContains('.tag-item', 'Test Tag Value'); @@ -270,8 +270,8 @@ class BookShelfTest extends TestCase $testName = 'Test Book in Shelf Name'; $createBookResp = $this->asEditor()->post($shelf->getUrl('/create-book'), [ - 'name' => $testName, - 'description' => 'Book in shelf description', + 'name' => $testName, + 'description_html' => 'Book in shelf description', ]); $createBookResp->assertRedirect(); @@ -372,8 +372,8 @@ class BookShelfTest extends TestCase { // Create shelf $shelfInfo = [ - 'name' => 'My test shelf' . Str::random(4), - 'description' => 'Test shelf description ' . Str::random(10), + 'name' => 'My test shelf' . Str::random(4), + 'description_html' => '

    Test shelf description ' . Str::random(10) . '

    ', ]; $this->asEditor()->post('/shelves', $shelfInfo); @@ -381,8 +381,8 @@ class BookShelfTest extends TestCase // Create book and add to shelf $this->asEditor()->post($shelf->getUrl('/create-book'), [ - 'name' => 'Test book name', - 'description' => 'Book in shelf description', + 'name' => 'Test book name', + 'description_html' => '

    Book in shelf description

    ', ]); $newBook = Book::query()->orderBy('id', 'desc')->first(); @@ -403,4 +403,15 @@ class BookShelfTest extends TestCase $resp = $this->asEditor()->get($shelf->getUrl('/create-book')); $this->withHtml($resp)->assertElementContains('form a[href="' . $shelf->getUrl() . '"]', 'Cancel'); } + + public function test_show_view_displays_description_if_no_description_html_set() + { + $shelf = $this->entities->shelf(); + $shelf->description_html = ''; + $shelf->description = "My great\ndescription\n\nwith newlines"; + $shelf->save(); + + $resp = $this->asEditor()->get($shelf->getUrl()); + $resp->assertSee("

    My great
    \ndescription
    \n
    \nwith newlines

    ", false); + } } diff --git a/tests/Entity/BookTest.php b/tests/Entity/BookTest.php index 833cabaae..374089246 100644 --- a/tests/Entity/BookTest.php +++ b/tests/Entity/BookTest.php @@ -22,7 +22,7 @@ class BookTest extends TestCase $resp = $this->get('/create-book'); $this->withHtml($resp)->assertElementContains('form[action="' . url('/books') . '"][method="POST"]', 'Save Book'); - $resp = $this->post('/books', $book->only('name', 'description')); + $resp = $this->post('/books', $book->only('name', 'description_html')); $resp->assertRedirect('/books/my-first-book'); $resp = $this->get('/books/my-first-book'); @@ -36,8 +36,8 @@ class BookTest extends TestCase 'name' => 'My First Book', ]); - $this->asEditor()->post('/books', $book->only('name', 'description')); - $this->asEditor()->post('/books', $book->only('name', 'description')); + $this->asEditor()->post('/books', $book->only('name', 'description_html')); + $this->asEditor()->post('/books', $book->only('name', 'description_html')); $books = Book::query()->where('name', '=', $book->name) ->orderBy('id', 'desc') @@ -52,9 +52,9 @@ class BookTest extends TestCase { // Cheeky initial update to refresh slug $this->asEditor()->post('books', [ - 'name' => 'My book with tags', - 'description' => 'A book with tags', - 'tags' => [ + 'name' => 'My book with tags', + 'description_html' => '

    A book with tags

    ', + 'tags' => [ [ 'name' => 'Category', 'value' => 'Donkey Content', @@ -79,23 +79,23 @@ class BookTest extends TestCase { $book = $this->entities->book(); // Cheeky initial update to refresh slug - $this->asEditor()->put($book->getUrl(), ['name' => $book->name . '5', 'description' => $book->description]); + $this->asEditor()->put($book->getUrl(), ['name' => $book->name . '5', 'description_html' => $book->description_html]); $book->refresh(); $newName = $book->name . ' Updated'; - $newDesc = $book->description . ' with more content'; + $newDesc = $book->description_html . '

    with more content

    '; $resp = $this->get($book->getUrl('/edit')); $resp->assertSee($book->name); - $resp->assertSee($book->description); + $resp->assertSee($book->description_html); $this->withHtml($resp)->assertElementContains('form[action="' . $book->getUrl() . '"]', 'Save Book'); - $resp = $this->put($book->getUrl(), ['name' => $newName, 'description' => $newDesc]); + $resp = $this->put($book->getUrl(), ['name' => $newName, 'description_html' => $newDesc]); $resp->assertRedirect($book->getUrl() . '-updated'); $resp = $this->get($book->getUrl() . '-updated'); $resp->assertSee($newName); - $resp->assertSee($newDesc); + $resp->assertSee($newDesc, false); } public function test_update_sets_tags() @@ -184,7 +184,7 @@ class BookTest extends TestCase public function test_recently_viewed_books_updates_as_expected() { - $books = Book::all()->take(2); + $books = Book::take(2)->get(); $resp = $this->asAdmin()->get('/books'); $this->withHtml($resp)->assertElementNotContains('#recents', $books[0]->name) @@ -200,7 +200,7 @@ class BookTest extends TestCase public function test_popular_books_updates_upon_visits() { - $books = Book::all()->take(2); + $books = Book::take(2)->get(); $resp = $this->asAdmin()->get('/books'); $this->withHtml($resp)->assertElementNotContains('#popular', $books[0]->name) @@ -262,6 +262,33 @@ class BookTest extends TestCase $this->assertEquals('parta-partb-partc', $book->slug); } + public function test_description_limited_to_specific_html() + { + $book = $this->entities->book(); + + $input = '

    Test

    Contenta

    Hello

    '; + $expected = '

    Contenta

    '; + + $this->asEditor()->put($book->getUrl(), [ + 'name' => $book->name, + 'description_html' => $input + ]); + + $book->refresh(); + $this->assertEquals($expected, $book->description_html); + } + + public function test_show_view_displays_description_if_no_description_html_set() + { + $book = $this->entities->book(); + $book->description_html = ''; + $book->description = "My great\ndescription\n\nwith newlines"; + $book->save(); + + $resp = $this->asEditor()->get($book->getUrl()); + $resp->assertSee("

    My great
    \ndescription
    \n
    \nwith newlines

    ", false); + } + public function test_show_view_has_copy_button() { $book = $this->entities->book(); @@ -291,6 +318,8 @@ class BookTest extends TestCase $resp->assertRedirect($copy->getUrl()); $this->assertEquals($book->getDirectChildren()->count(), $copy->getDirectChildren()->count()); + + $this->get($copy->getUrl())->assertSee($book->description_html, false); } public function test_copy_does_not_copy_non_visible_content() diff --git a/tests/Entity/ChapterTest.php b/tests/Entity/ChapterTest.php index 7fa32c252..1577cee76 100644 --- a/tests/Entity/ChapterTest.php +++ b/tests/Entity/ChapterTest.php @@ -23,12 +23,23 @@ class ChapterTest extends TestCase $resp = $this->get($book->getUrl('/create-chapter')); $this->withHtml($resp)->assertElementContains('form[action="' . $book->getUrl('/create-chapter') . '"][method="POST"]', 'Save Chapter'); - $resp = $this->post($book->getUrl('/create-chapter'), $chapter->only('name', 'description')); + $resp = $this->post($book->getUrl('/create-chapter'), $chapter->only('name', 'description_html')); $resp->assertRedirect($book->getUrl('/chapter/my-first-chapter')); $resp = $this->get($book->getUrl('/chapter/my-first-chapter')); $resp->assertSee($chapter->name); - $resp->assertSee($chapter->description); + $resp->assertSee($chapter->description_html, false); + } + + public function test_show_view_displays_description_if_no_description_html_set() + { + $chapter = $this->entities->chapter(); + $chapter->description_html = ''; + $chapter->description = "My great\ndescription\n\nwith newlines"; + $chapter->save(); + + $resp = $this->asEditor()->get($chapter->getUrl()); + $resp->assertSee("

    My great
    \ndescription
    \n
    \nwith newlines

    ", false); } public function test_delete() diff --git a/tests/Entity/ConvertTest.php b/tests/Entity/ConvertTest.php index decda5224..d9b1ee466 100644 --- a/tests/Entity/ConvertTest.php +++ b/tests/Entity/ConvertTest.php @@ -42,6 +42,7 @@ class ConvertTest extends TestCase $this->assertEquals('Penguins', $newBook->tags->first()->value); $this->assertEquals($chapter->name, $newBook->name); $this->assertEquals($chapter->description, $newBook->description); + $this->assertEquals($chapter->description_html, $newBook->description_html); $this->assertActivityExists(ActivityType::BOOK_CREATE_FROM_CHAPTER, $newBook); } @@ -105,6 +106,7 @@ class ConvertTest extends TestCase $this->assertEquals('Ducks', $newShelf->tags->first()->value); $this->assertEquals($book->name, $newShelf->name); $this->assertEquals($book->description, $newShelf->description); + $this->assertEquals($book->description_html, $newShelf->description_html); $this->assertEquals($newShelf->books()->count(), $bookChapterCount + 1); $this->assertEquals($systemBookCount + $bookChapterCount, Book::query()->count()); $this->assertActivityExists(ActivityType::BOOKSHELF_CREATE_FROM_BOOK, $newShelf); diff --git a/tests/Entity/EntitySearchTest.php b/tests/Entity/EntitySearchTest.php index fbb47226e..9b77a32ab 100644 --- a/tests/Entity/EntitySearchTest.php +++ b/tests/Entity/EntitySearchTest.php @@ -252,6 +252,39 @@ class EntitySearchTest extends TestCase $this->withHtml($resp)->assertElementContains($baseSelector, "You don't have the required permissions to select this item"); } + public function test_entity_template_selector_search() + { + $templatePage = $this->entities->newPage(['name' => 'Template search test', 'html' => 'template test']); + $templatePage->template = true; + $templatePage->save(); + + $nonTemplatePage = $this->entities->newPage(['name' => 'Nontemplate page', 'html' => 'nontemplate', 'template' => false]); + + // Visit both to make popular + $this->asEditor()->get($templatePage->getUrl()); + $this->get($nonTemplatePage->getUrl()); + + $normalSearch = $this->get('/search/entity-selector-templates?term=test'); + $normalSearch->assertSee($templatePage->name); + $normalSearch->assertDontSee($nonTemplatePage->name); + + $normalSearch = $this->get('/search/entity-selector-templates?term=beans'); + $normalSearch->assertDontSee($templatePage->name); + $normalSearch->assertDontSee($nonTemplatePage->name); + + $defaultListTest = $this->get('/search/entity-selector-templates'); + $defaultListTest->assertSee($templatePage->name); + $defaultListTest->assertDontSee($nonTemplatePage->name); + + $this->permissions->disableEntityInheritedPermissions($templatePage); + + $normalSearch = $this->get('/search/entity-selector-templates?term=test'); + $normalSearch->assertDontSee($templatePage->name); + + $defaultListTest = $this->get('/search/entity-selector-templates'); + $defaultListTest->assertDontSee($templatePage->name); + } + public function test_sibling_search_for_pages() { $chapter = $this->entities->chapterHasPages(); diff --git a/tests/Entity/ExportTest.php b/tests/Entity/ExportTest.php index 08bf17d0a..eedcb672c 100644 --- a/tests/Entity/ExportTest.php +++ b/tests/Entity/ExportTest.php @@ -107,18 +107,18 @@ class ExportTest extends TestCase $resp->assertHeader('Content-Disposition', 'attachment; filename="' . $book->slug . '.html"'); } - public function test_book_html_export_shows_chapter_descriptions() + public function test_book_html_export_shows_html_descriptions() { - $chapterDesc = 'My custom test chapter description ' . Str::random(12); - $chapter = $this->entities->chapter(); - $chapter->description = $chapterDesc; + $book = $this->entities->bookHasChaptersAndPages(); + $chapter = $book->chapters()->first(); + $book->description_html = '

    A description with HTML within!

    '; + $chapter->description_html = '

    A chapter description with HTML within!

    '; + $book->save(); $chapter->save(); - $book = $chapter->book; - $this->asEditor(); - - $resp = $this->get($book->getUrl('/export/html')); - $resp->assertSee($chapterDesc); + $resp = $this->asEditor()->get($book->getUrl('/export/html')); + $resp->assertSee($book->description_html, false); + $resp->assertSee($chapter->description_html, false); } public function test_chapter_text_export() @@ -174,6 +174,16 @@ class ExportTest extends TestCase $resp->assertHeader('Content-Disposition', 'attachment; filename="' . $chapter->slug . '.html"'); } + public function test_chapter_html_export_shows_html_descriptions() + { + $chapter = $this->entities->chapter(); + $chapter->description_html = '

    A description with HTML within!

    '; + $chapter->save(); + + $resp = $this->asEditor()->get($chapter->getUrl('/export/html')); + $resp->assertSee($chapter->description_html, false); + } + public function test_page_html_export_contains_custom_head_if_set() { $page = $this->entities->page(); diff --git a/tests/Entity/PageContentTest.php b/tests/Entity/PageContentTest.php index 78b739512..28897c14d 100644 --- a/tests/Entity/PageContentTest.php +++ b/tests/Entity/PageContentTest.php @@ -57,38 +57,6 @@ class PageContentTest extends TestCase $this->assertEquals('', $page->text); } - public function test_page_includes_do_not_break_tables() - { - $page = $this->entities->page(); - $secondPage = $this->entities->page(); - - $content = '
    test
    '; - $secondPage->html = $content; - $secondPage->save(); - - $page->html = "{{@{$secondPage->id}#table}}"; - $page->save(); - - $pageResp = $this->asEditor()->get($page->getUrl()); - $pageResp->assertSee($content, false); - } - - public function test_page_includes_do_not_break_code() - { - $page = $this->entities->page(); - $secondPage = $this->entities->page(); - - $content = '
    var cat = null;
    '; - $secondPage->html = $content; - $secondPage->save(); - - $page->html = "{{@{$secondPage->id}#bkmrk-code}}"; - $page->save(); - - $pageResp = $this->asEditor()->get($page->getUrl()); - $pageResp->assertSee($content, false); - } - public function test_page_includes_rendered_on_book_export() { $page = $this->entities->page(); @@ -120,6 +88,19 @@ class PageContentTest extends TestCase $this->withHtml($pageResp)->assertElementNotContains('#bkmrk-test', 'Hello Barry Hello Barry Hello Barry Hello Barry Hello Barry ' . $tag); } + public function test_page_includes_to_nonexisting_pages_does_not_error() + { + $page = $this->entities->page(); + $missingId = Page::query()->max('id') + 1; + $tag = "{{@{$missingId}}}"; + $page->html = '

    Hello Barry ' . $tag . '

    '; + $page->save(); + + $pageResp = $this->asEditor()->get($page->getUrl()); + $pageResp->assertOk(); + $pageResp->assertSee('Hello Barry'); + } + public function test_page_content_scripts_removed_by_default() { $this->asEditor(); diff --git a/tests/FavouriteTest.php b/tests/FavouriteTest.php index 48048e284..11016af14 100644 --- a/tests/FavouriteTest.php +++ b/tests/FavouriteTest.php @@ -56,6 +56,23 @@ class FavouriteTest extends TestCase ]); } + public function test_add_and_remove_redirect_to_entity_without_history() + { + $page = $this->entities->page(); + + $resp = $this->asEditor()->post('/favourites/add', [ + 'type' => $page->getMorphClass(), + 'id' => $page->id, + ]); + $resp->assertRedirect($page->getUrl()); + + $resp = $this->asEditor()->post('/favourites/remove', [ + 'type' => $page->getMorphClass(), + 'id' => $page->id, + ]); + $resp->assertRedirect($page->getUrl()); + } + public function test_favourite_flow_with_own_permissions() { $book = $this->entities->book(); diff --git a/tests/Helpers/EntityProvider.php b/tests/Helpers/EntityProvider.php index 3cb8c44d3..982063421 100644 --- a/tests/Helpers/EntityProvider.php +++ b/tests/Helpers/EntityProvider.php @@ -53,6 +53,15 @@ class EntityProvider return $this->page(fn(Builder $query) => $query->where('chapter_id', '=', 0)); } + public function templatePage(): Page + { + $page = $this->page(); + $page->template = true; + $page->save(); + + return $page; + } + /** * Get an un-fetched chapter from the system. */ diff --git a/tests/Helpers/PermissionsProvider.php b/tests/Helpers/PermissionsProvider.php index 512f43fb6..cb036fe97 100644 --- a/tests/Helpers/PermissionsProvider.php +++ b/tests/Helpers/PermissionsProvider.php @@ -5,16 +5,21 @@ namespace Tests\Helpers; use BookStack\Entities\Models\Entity; use BookStack\Permissions\Models\EntityPermission; use BookStack\Permissions\Models\RolePermission; +use BookStack\Settings\SettingService; use BookStack\Users\Models\Role; use BookStack\Users\Models\User; class PermissionsProvider { - protected UserRoleProvider $userRoleProvider; + public function __construct( + protected UserRoleProvider $userRoleProvider + ) { + } - public function __construct(UserRoleProvider $userRoleProvider) + public function makeAppPublic(): void { - $this->userRoleProvider = $userRoleProvider; + $settings = app(SettingService::class); + $settings->put('app-public', 'true'); } /** diff --git a/tests/References/ReferencesTest.php b/tests/References/ReferencesTest.php index a19e1b901..715f71435 100644 --- a/tests/References/ReferencesTest.php +++ b/tests/References/ReferencesTest.php @@ -30,7 +30,30 @@ class ReferencesTest extends TestCase ]); } - public function test_references_deleted_on_entity_delete() + public function test_references_created_on_book_chapter_bookshelf_update() + { + $entities = [$this->entities->book(), $this->entities->chapter(), $this->entities->shelf()]; + $shelf = $this->entities->shelf(); + + foreach ($entities as $entity) { + $entity->refresh(); + $this->assertDatabaseMissing('references', ['from_id' => $entity->id, 'from_type' => $entity->getMorphClass()]); + + $this->asEditor()->put($entity->getUrl(), [ + 'name' => 'Reference test', + 'description_html' => 'Testing', + ]); + + $this->assertDatabaseHas('references', [ + 'from_id' => $entity->id, + 'from_type' => $entity->getMorphClass(), + 'to_id' => $shelf->id, + 'to_type' => $shelf->getMorphClass(), + ]); + } + } + + public function test_references_deleted_on_page_delete() { $pageA = $this->entities->page(); $pageB = $this->entities->page(); @@ -48,6 +71,25 @@ class ReferencesTest extends TestCase $this->assertDatabaseMissing('references', ['to_id' => $pageA->id, 'to_type' => $pageA->getMorphClass()]); } + public function test_references_from_deleted_on_book_chapter_shelf_delete() + { + $entities = [$this->entities->chapter(), $this->entities->book(), $this->entities->shelf()]; + $shelf = $this->entities->shelf(); + + foreach ($entities as $entity) { + $this->createReference($entity, $shelf); + $this->assertDatabaseHas('references', ['from_id' => $entity->id, 'from_type' => $entity->getMorphClass()]); + + $this->asEditor()->delete($entity->getUrl()); + app(TrashCan::class)->empty(); + + $this->assertDatabaseMissing('references', [ + 'from_id' => $entity->id, + 'from_type' => $entity->getMorphClass() + ]); + } + } + public function test_references_to_count_visible_on_entity_show_view() { $entities = $this->entities->all(); @@ -60,13 +102,13 @@ class ReferencesTest extends TestCase foreach ($entities as $entity) { $resp = $this->get($entity->getUrl()); - $resp->assertSee('Referenced on 1 page'); - $resp->assertDontSee('Referenced on 1 pages'); + $resp->assertSee('Referenced by 1 item'); + $resp->assertDontSee('Referenced by 1 items'); } $this->createReference($otherPage, $entities['page']); $resp = $this->get($entities['page']->getUrl()); - $resp->assertSee('Referenced on 2 pages'); + $resp->assertSee('Referenced by 2 items'); } public function test_references_to_visible_on_references_page() @@ -203,6 +245,32 @@ class ReferencesTest extends TestCase $this->assertEquals($expected, $page->markdown); } + public function test_description_links_from_book_chapter_shelf_updated_on_url_change() + { + $entities = [$this->entities->chapter(), $this->entities->book(), $this->entities->shelf()]; + $shelf = $this->entities->shelf(); + $this->asEditor(); + + foreach ($entities as $entity) { + $this->put($entity->getUrl(), [ + 'name' => 'Reference test', + 'description_html' => 'Testing', + ]); + } + + $oldUrl = $shelf->getUrl(); + $this->put($shelf->getUrl(), ['name' => 'My updated shelf link']); + $shelf->refresh(); + $this->assertNotEquals($oldUrl, $shelf->getUrl()); + + foreach ($entities as $entity) { + $oldHtml = $entity->description_html; + $entity->refresh(); + $this->assertNotEquals($oldHtml, $entity->description_html); + $this->assertStringContainsString($shelf->getUrl(), $entity->description_html); + } + } + protected function createReference(Model $from, Model $to) { (new Reference())->forceFill([ diff --git a/tests/Settings/RegenerateReferencesTest.php b/tests/Settings/RegenerateReferencesTest.php index 25832b03e..0511f2624 100644 --- a/tests/Settings/RegenerateReferencesTest.php +++ b/tests/Settings/RegenerateReferencesTest.php @@ -21,7 +21,7 @@ class RegenerateReferencesTest extends TestCase public function test_action_runs_reference_regen() { $this->mock(ReferenceStore::class) - ->shouldReceive('updateForAllPages') + ->shouldReceive('updateForAll') ->once(); $resp = $this->asAdmin()->post('/settings/maintenance/regenerate-references'); @@ -45,7 +45,7 @@ class RegenerateReferencesTest extends TestCase public function test_action_failed_shown_as_error_notification() { $this->mock(ReferenceStore::class) - ->shouldReceive('updateForAllPages') + ->shouldReceive('updateForAll') ->andThrow(\Exception::class, 'A badger stopped the task'); $resp = $this->asAdmin()->post('/settings/maintenance/regenerate-references'); diff --git a/tests/ThemeTest.php b/tests/ThemeTest.php index f6706595b..a7a46521a 100644 --- a/tests/ThemeTest.php +++ b/tests/ThemeTest.php @@ -256,6 +256,40 @@ class ThemeTest extends TestCase $this->assertEquals($otherPage->id, $args[3]->id); } + public function test_event_routes_register_web_and_web_auth() + { + $functionsContent = <<<'END' +get('/cat', fn () => 'cat')->name('say.cat'); +}); +Theme::listen(ThemeEvents::ROUTES_REGISTER_WEB_AUTH, function (Router $router) { + $router->get('/dog', fn () => 'dog')->name('say.dog'); +}); +END; + + $this->usingThemeFolder(function () use ($functionsContent) { + + $functionsFile = theme_path('functions.php'); + file_put_contents($functionsFile, $functionsContent); + + $app = $this->createApplication(); + /** @var \Illuminate\Routing\Router $router */ + $router = $app->get('router'); + + /** @var \Illuminate\Routing\Route $catRoute */ + $catRoute = $router->getRoutes()->getRoutesByName()['say.cat']; + $this->assertEquals(['web'], $catRoute->middleware()); + + /** @var \Illuminate\Routing\Route $dogRoute */ + $dogRoute = $router->getRoutes()->getRoutesByName()['say.dog']; + $this->assertEquals(['web', 'auth'], $dogRoute->middleware()); + }); + } + public function test_add_social_driver() { Theme::addSocialDriver('catnet', [ diff --git a/tests/Unit/PageIncludeParserTest.php b/tests/Unit/PageIncludeParserTest.php new file mode 100644 index 000000000..83fded436 --- /dev/null +++ b/tests/Unit/PageIncludeParserTest.php @@ -0,0 +1,240 @@ +runParserTest( + '

    {{@45#content}}

    ', + ['45' => '

    Testing

    '], + '

    Testing

    ', + ); + } + + public function test_simple_inline_text_with_existing_siblings() + { + $this->runParserTest( + '

    {{@45#content}} Hithere!

    ', + ['45' => '

    Testing

    '], + '

    Testing Hithere!

    ', + ); + } + + public function test_simple_inline_text_within_other_text() + { + $this->runParserTest( + '

    Hello {{@45#content}}there!

    ', + ['45' => '

    Testing

    '], + '

    Hello Testingthere!

    ', + ); + } + + public function test_complex_inline_text_within_other_text() + { + $this->runParserTest( + '

    Hello {{@45#content}}there!

    ', + ['45' => '

    Testing withsomeextratags

    '], + '

    Hello Testing withsomeextratagsthere!

    ', + ); + } + + public function test_block_content_types() + { + $inputs = [ + '
    Text
    ', + '
    • Item A
    ', + '
    1. Item A
    ', + '
    Code
    ', + ]; + + foreach ($inputs as $input) { + $this->runParserTest( + '

    A{{@45#content}}B

    ', + ['45' => $input], + '

    A

    ' . $input . '

    B

    ', + ); + } + } + + public function test_block_content_nested_origin_gets_placed_before() + { + $this->runParserTest( + '

    A {{@45#content}} there!

    ', + ['45' => '
    Testing
    '], + '
    Testing

    A there!

    ', + ); + } + + public function test_block_content_nested_origin_gets_placed_after() + { + $this->runParserTest( + '

    Some really good {{@45#content}} there!

    ', + ['45' => '
    Testing
    '], + '

    Some really good there!

    Testing
    ', + ); + } + + public function test_block_content_in_shallow_origin_gets_split() + { + $this->runParserTest( + '

    Some really good {{@45#content}} there!

    ', + ['45' => '
    doggos
    '], + '

    Some really good

    doggos

    there!

    ', + ); + } + + public function test_block_content_in_shallow_origin_split_does_not_duplicate_id() + { + $this->runParserTest( + '

    Some really good {{@45#content}} there!

    ', + ['45' => '
    doggos
    '], + '

    Some really good

    doggos

    there!

    ', + ); + } + + public function test_block_content_in_shallow_origin_does_not_leave_empty_nodes() + { + $this->runParserTest( + '

    {{@45#content}}

    ', + ['45' => '
    doggos
    '], + '
    doggos
    ', + ); + } + + public function test_block_content_in_allowable_parent_element() + { + $this->runParserTest( + '
    {{@45#content}}
    ', + ['45' => '
    doggos
    '], + '
    doggos
    ', + ); + } + + public function test_block_content_in_paragraph_origin_with_allowable_grandparent() + { + $this->runParserTest( + '

    {{@45#content}}

    ', + ['45' => '
    doggos
    '], + '
    doggos
    ', + ); + } + + public function test_block_content_in_paragraph_origin_with_allowable_grandparent_with_adjacent_content() + { + $this->runParserTest( + '

    Cute {{@45#content}} over there!

    ', + ['45' => '
    doggos
    '], + '

    Cute

    doggos

    over there!

    ', + ); + } + + public function test_block_content_in_child_within_paragraph_origin_with_allowable_grandparent_with_adjacent_content() + { + $this->runParserTest( + '

    Cute {{@45#content}} over there!

    ', + ['45' => '
    doggos
    '], + '
    doggos

    Cute over there!

    ', + ); + } + + public function test_block_content_in_paragraph_origin_within_details() + { + $this->runParserTest( + '

    {{@45#content}}

    ', + ['45' => '
    doggos
    '], + '
    doggos
    ', + ); + } + + public function test_simple_whole_document() + { + $this->runParserTest( + '

    {{@45}}

    ', + ['45' => '

    Testing

    '], + '

    Testing

    ', + ); + } + + public function test_multi_source_elem_whole_document() + { + $this->runParserTest( + '

    {{@45}}

    ', + ['45' => '

    Testing

    This
    '], + '

    Testing

    This
    ', + ); + } + + public function test_multi_source_elem_whole_document_with_shared_content_origin() + { + $this->runParserTest( + '

    This is {{@45}} some text

    ', + ['45' => '

    Testing

    This
    '], + '

    This is

    Testing

    This

    some text

    ', + ); + } + + public function test_multi_source_elem_whole_document_with_nested_content_origin() + { + $this->runParserTest( + '

    {{@45}}

    ', + ['45' => '

    Testing

    This
    '], + '

    Testing

    This
    ', + ); + } + + public function test_multiple_tags_in_same_origin_with_inline_content() + { + $this->runParserTest( + '

    This {{@45#content}}{{@45#content}} content is {{@45#content}}

    ', + ['45' => '

    inline

    '], + '

    This inlineinline content is inline

    ', + ); + } + + public function test_multiple_tags_in_same_origin_with_block_content() + { + $this->runParserTest( + '

    This {{@45#content}}{{@45#content}} content is {{@45#content}}

    ', + ['45' => '
    block
    '], + '

    This

    block
    block

    content is

    block
    ', + ); + } + + public function test_multiple_tags_in_differing_origin_levels_with_block_content() + { + $this->runParserTest( + '

    This {{@45#content}} content is {{@45#content}}

    {{@45#content}}
    ', + ['45' => '
    block
    '], + '
    block

    This content is

    block
    block
    ', + ); + } + + public function test_multiple_tags_in_shallow_origin_with_multi_block_content() + { + $this->runParserTest( + '

    {{@45}}C{{@45}}

    {{@45}}{{@45}}
    ', + ['45' => '

    A

    B

    '], + '

    A

    B

    C

    A

    B

    A

    B

    A

    B

    ', + ); + } + + protected function runParserTest(string $html, array $contentById, string $expected): void + { + $doc = new HtmlDocument($html); + $parser = new PageIncludeParser($doc, function (PageIncludeTag $tag) use ($contentById): PageIncludeContent { + $html = $contentById[strval($tag->getPageId())] ?? ''; + return PageIncludeContent::fromHtmlAndTag($html, $tag); + }); + + $parser->parse(); + $this->assertEquals($expected, $doc->getBodyInnerHtml()); + } +} diff --git a/tests/User/RoleManagementTest.php b/tests/User/RoleManagementTest.php index 5722a0b08..9e5cf78dd 100644 --- a/tests/User/RoleManagementTest.php +++ b/tests/User/RoleManagementTest.php @@ -235,7 +235,7 @@ class RoleManagementTest extends TestCase /** @var Role $publicRole */ $publicRole = Role::getSystemRole('public'); $resp = $this->asAdmin()->delete('/settings/roles/delete/' . $publicRole->id); - $resp->assertRedirect('/'); + $resp->assertRedirect('/settings/roles/delete/' . $publicRole->id); $this->get('/settings/roles/delete/' . $publicRole->id); $resp = $this->delete('/settings/roles/delete/' . $publicRole->id); diff --git a/tests/User/UserPreferencesTest.php b/tests/User/UserPreferencesTest.php index d78ac2ea7..ff3cb63ca 100644 --- a/tests/User/UserPreferencesTest.php +++ b/tests/User/UserPreferencesTest.php @@ -2,8 +2,6 @@ namespace Tests\User; -use BookStack\Activity\Tools\UserEntityWatchOptions; -use BookStack\Activity\WatchLevels; use Tests\TestCase; class UserPreferencesTest extends TestCase @@ -40,7 +38,7 @@ class UserPreferencesTest extends TestCase 'sort' => 'name', 'order' => 'asc', ]); - $updateRequest->assertStatus(500); + $updateRequest->assertRedirect(); $this->assertNotEmpty('name', setting()->getForCurrentUser('bookshelves_sort')); $this->assertNotEmpty('asc', setting()->getForCurrentUser('bookshelves_sort_order')); @@ -141,7 +139,10 @@ class UserPreferencesTest extends TestCase ->assertElementNotExists('.featured-image-container') ->assertElementExists('.content-wrap .entity-list-item'); - $req = $this->patch("/preferences/change-view/bookshelf", ['view' => 'grid']); + $req = $this->patch("/preferences/change-view/bookshelf", [ + 'view' => 'grid', + '_return' => $shelf->getUrl(), + ]); $req->assertRedirect($shelf->getUrl()); $resp = $this->actingAs($editor)->get($shelf->getUrl())