From c76d12d1ded72b5bf74a51fdb1647f87bb935edc Mon Sep 17 00:00:00 2001 From: "Luke T. Shumaker" Date: Fri, 15 Dec 2023 10:58:20 -0700 Subject: [PATCH 001/969] Oidc: Properly query the UserInfo Endpoint BooksStack's OIDC Client requests the 'profile' and 'email' scope values in order to have access to the 'name', 'email', and other claims. It looks for these claims in the ID Token that is returned along with the Access Token. However, the OIDC-core specification section 5.4 [1] only requires that the Provider include those claims in the ID Token *if* an Access Token is not also issued. If an Access Token is issued, the Provider can leave out those claims from the ID Token, and the Client is supposed to obtain them by submitting the Access Token to the UserInfo Endpoint. So I suppose it's just good luck that the OIDC Providers that BookStack has been tested with just so happen to also stick those claims in the ID Token even though they don't have to. But others (in particular: https://login.infomaniak.com) don't do so, and require fetching the UserInfo Endpoint.) A workaround is currently possible by having the user write a theme with a ThemeEvents::OIDC_ID_TOKEN_PRE_VALIDATE hook that fetches the UserInfo Endpoint. This workaround isn't great, for a few reasons: 1. Asking the user to implement core parts of the OIDC protocol is silly. 2. The user either needs to re-fetch the .well-known/openid-configuration file to discover the endpoint (adding yet another round-trip to each login) or hard-code the endpoint, which is fragile. 3. The hook doesn't receive the HTTP client configuration. So, have BookStack's OidcService fetch the UserInfo Endpoint and inject those claims into the ID Token, if a UserInfo Endpoint is defined. Two points about this: - Injecting them into the ID Token's claims is the most obvious approach given the current code structure; though I'm not sure it is the best approach, perhaps it should instead fetch the user info in processAuthorizationResponse() and pass that as an argument to processAccessTokenCallback() which would then need a bit of restructuring. But this made sense because it's also how the ThemeEvents::OIDC_ID_TOKEN_PRE_VALIDATE hook works. - OIDC *requires* that a UserInfo Endpoint exists, so why bother with that "if a UserInfo Endpoint is defined" bit? Simply out of an abundance of caution that there's an existing BookStack user that is relying on it not fetching the UserInfo Endpoint in order to work with a non-compliant OIDC Provider. [1]: https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims --- .env.example.complete | 1 + app/Access/Oidc/OidcProviderSettings.php | 7 ++++- app/Access/Oidc/OidcService.php | 12 ++++++++ app/Config/oidc.php | 1 + tests/Auth/OidcTest.php | 38 ++++++++++++++++++++++-- 5 files changed, 56 insertions(+), 3 deletions(-) diff --git a/.env.example.complete b/.env.example.complete index e8520a24cae..1242968182a 100644 --- a/.env.example.complete +++ b/.env.example.complete @@ -267,6 +267,7 @@ OIDC_ISSUER_DISCOVER=false OIDC_PUBLIC_KEY=null OIDC_AUTH_ENDPOINT=null OIDC_TOKEN_ENDPOINT=null +OIDC_USERINFO_ENDPOINT=null OIDC_ADDITIONAL_SCOPES=null OIDC_DUMP_USER_DETAILS=false OIDC_USER_TO_GROUPS=false diff --git a/app/Access/Oidc/OidcProviderSettings.php b/app/Access/Oidc/OidcProviderSettings.php index bea6a523e77..49ccab6f0de 100644 --- a/app/Access/Oidc/OidcProviderSettings.php +++ b/app/Access/Oidc/OidcProviderSettings.php @@ -22,6 +22,7 @@ class OidcProviderSettings public ?string $authorizationEndpoint; public ?string $tokenEndpoint; public ?string $endSessionEndpoint; + public ?string $userinfoEndpoint; /** * @var string[]|array[] @@ -128,6 +129,10 @@ protected function loadSettingsFromIssuerDiscovery(ClientInterface $httpClient): $discoveredSettings['tokenEndpoint'] = $result['token_endpoint']; } + if (!empty($result['userinfo_endpoint'])) { + $discoveredSettings['userinfoEndpoint'] = $result['userinfo_endpoint']; + } + if (!empty($result['jwks_uri'])) { $keys = $this->loadKeysFromUri($result['jwks_uri'], $httpClient); $discoveredSettings['keys'] = $this->filterKeys($keys); @@ -177,7 +182,7 @@ protected function loadKeysFromUri(string $uri, ClientInterface $httpClient): ar */ public function arrayForProvider(): array { - $settingKeys = ['clientId', 'clientSecret', 'redirectUri', 'authorizationEndpoint', 'tokenEndpoint']; + $settingKeys = ['clientId', 'clientSecret', 'redirectUri', 'authorizationEndpoint', 'tokenEndpoint', 'userinfoEndpoint']; $settings = []; foreach ($settingKeys as $setting) { $settings[$setting] = $this->$setting; diff --git a/app/Access/Oidc/OidcService.php b/app/Access/Oidc/OidcService.php index f1e5b25af14..24495799195 100644 --- a/app/Access/Oidc/OidcService.php +++ b/app/Access/Oidc/OidcService.php @@ -85,6 +85,7 @@ protected function getProviderSettings(): OidcProviderSettings 'authorizationEndpoint' => $config['authorization_endpoint'], 'tokenEndpoint' => $config['token_endpoint'], 'endSessionEndpoint' => is_string($config['end_session_endpoint']) ? $config['end_session_endpoint'] : null, + 'userinfoEndpoint' => $config['userinfo_endpoint'], ]); // Use keys if configured @@ -228,6 +229,17 @@ protected function processAccessTokenCallback(OidcAccessToken $accessToken, Oidc session()->put("oidc_id_token", $idTokenText); + if (!empty($settings->userinfoEndpoint)) { + $provider = $this->getProvider($settings); + $request = $provider->getAuthenticatedRequest('GET', $settings->userinfoEndpoint, $accessToken->getToken()); + $response = $provider->getParsedResponse($request); + $claims = $idToken->getAllClaims(); + foreach ($response as $key => $value) { + $claims[$key] = $value; + } + $idToken->replaceClaims($claims); + } + $returnClaims = Theme::dispatch(ThemeEvents::OIDC_ID_TOKEN_PRE_VALIDATE, $idToken->getAllClaims(), [ 'access_token' => $accessToken->getToken(), 'expires_in' => $accessToken->getExpires(), diff --git a/app/Config/oidc.php b/app/Config/oidc.php index 7f8f40d4190..8b5470931d0 100644 --- a/app/Config/oidc.php +++ b/app/Config/oidc.php @@ -35,6 +35,7 @@ // OAuth2 endpoints. 'authorization_endpoint' => env('OIDC_AUTH_ENDPOINT', null), 'token_endpoint' => env('OIDC_TOKEN_ENDPOINT', null), + 'userinfo_endpoint' => env('OIDC_USERINFO_ENDPOINT', null), // OIDC RP-Initiated Logout endpoint URL. // A false value force-disables RP-Initiated Logout. diff --git a/tests/Auth/OidcTest.php b/tests/Auth/OidcTest.php index dbf26f1bd30..f47a201005d 100644 --- a/tests/Auth/OidcTest.php +++ b/tests/Auth/OidcTest.php @@ -668,11 +668,44 @@ protected function withAutodiscovery() protected function runLogin($claimOverrides = []): TestResponse { + // These two variables should perhaps be arguments instead of + // assuming that they're tied to whether discovery is enabled, + // but that's how the tests are written for now. + $claimsInIdToken = !config('oidc.discover'); + $tokenEndpoint = config('oidc.discover') + ? OidcJwtHelper::defaultIssuer() . '/oidc/token' + : 'https://oidc.local/token'; + $this->post('/oidc/login'); $state = session()->get('oidc_state'); - $this->mockHttpClient([$this->getMockAuthorizationResponse($claimOverrides)]); - return $this->get('/oidc/callback?code=SplxlOBeZQQYbYS6WxSbIA&state=' . $state); + $providerResponses = [$this->getMockAuthorizationResponse($claimsInIdToken ? $claimOverrides : [])]; + if (!$claimsInIdToken) { + $providerResponses[] = new Response(200, [ + 'Content-Type' => 'application/json', + 'Cache-Control' => 'no-cache, no-store', + 'Pragma' => 'no-cache', + ], json_encode($claimOverrides)); + } + + $transactions = $this->mockHttpClient($providerResponses); + + $response = $this->get('/oidc/callback?code=SplxlOBeZQQYbYS6WxSbIA&state=' . $state); + + if (auth()->check()) { + $this->assertEquals($claimsInIdToken ? 1 : 2, $transactions->requestCount()); + $tokenRequest = $transactions->requestAt(0); + $this->assertEquals($tokenEndpoint, (string) $tokenRequest->getUri()); + $this->assertEquals('POST', $tokenRequest->getMethod()); + if (!$claimsInIdToken) { + $userinfoRequest = $transactions->requestAt(1); + $this->assertEquals(OidcJwtHelper::defaultIssuer() . '/oidc/userinfo', (string) $userinfoRequest->getUri()); + $this->assertEquals('GET', $userinfoRequest->getMethod()); + $this->assertEquals('Bearer abc123', $userinfoRequest->getHeader('Authorization')[0]); + } + } + + return $response; } protected function getAutoDiscoveryResponse($responseOverrides = []): Response @@ -684,6 +717,7 @@ protected function getAutoDiscoveryResponse($responseOverrides = []): Response ], json_encode(array_merge([ 'token_endpoint' => OidcJwtHelper::defaultIssuer() . '/oidc/token', 'authorization_endpoint' => OidcJwtHelper::defaultIssuer() . '/oidc/authorize', + 'userinfo_endpoint' => OidcJwtHelper::defaultIssuer() . '/oidc/userinfo', 'jwks_uri' => OidcJwtHelper::defaultIssuer() . '/oidc/keys', 'issuer' => OidcJwtHelper::defaultIssuer(), 'end_session_endpoint' => OidcJwtHelper::defaultIssuer() . '/oidc/logout', From 70bfebcd7c9396c9d17757ec57a584371dce2e9f Mon Sep 17 00:00:00 2001 From: Sascha Date: Mon, 1 Jan 2024 21:58:49 +0100 Subject: [PATCH 002/969] Added Default Templates for Chapters --- .../Controllers/ChapterController.php | 14 ++++---- app/Entities/Controllers/PageController.php | 9 +++-- app/Entities/Models/Chapter.php | 11 ++++++ app/Entities/Repos/ChapterRepo.php | 34 +++++++++++++++++++ app/Entities/Repos/PageRepo.php | 8 ++++- app/Entities/Tools/TrashCan.php | 6 ++++ ...04542_add_default_template_to_chapters.php | 32 +++++++++++++++++ lang/en/entities.php | 3 ++ resources/views/chapters/parts/form.blade.php | 23 +++++++++++++ 9 files changed, 131 insertions(+), 9 deletions(-) create mode 100644 database/migrations/2024_01_01_104542_add_default_template_to_chapters.php diff --git a/app/Entities/Controllers/ChapterController.php b/app/Entities/Controllers/ChapterController.php index 28ad35fa4b3..00616888a70 100644 --- a/app/Entities/Controllers/ChapterController.php +++ b/app/Entities/Controllers/ChapterController.php @@ -49,9 +49,10 @@ public function create(string $bookSlug) public function store(Request $request, string $bookSlug) { $validated = $this->validate($request, [ - 'name' => ['required', 'string', 'max:255'], - 'description_html' => ['string', 'max:2000'], - 'tags' => ['array'], + 'name' => ['required', 'string', 'max:255'], + 'description_html' => ['string', 'max:2000'], + 'tags' => ['array'], + 'default_template_id' => ['nullable', 'integer'], ]); $book = Book::visible()->where('slug', '=', $bookSlug)->firstOrFail(); @@ -111,9 +112,10 @@ public function edit(string $bookSlug, string $chapterSlug) 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'], + 'name' => ['required', 'string', 'max:255'], + 'description_html' => ['string', 'max:2000'], + 'tags' => ['array'], + 'default_template_id' => ['nullable', 'integer'], ]); $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); diff --git a/app/Entities/Controllers/PageController.php b/app/Entities/Controllers/PageController.php index adafcdc7bd9..74dd4f531b4 100644 --- a/app/Entities/Controllers/PageController.php +++ b/app/Entities/Controllers/PageController.php @@ -6,6 +6,7 @@ use BookStack\Activity\Tools\CommentTree; use BookStack\Activity\Tools\UserEntityWatchOptions; use BookStack\Entities\Models\Book; +use BookStack\Entities\Models\Chapter; use BookStack\Entities\Models\Page; use BookStack\Entities\Repos\PageRepo; use BookStack\Entities\Tools\BookContents; @@ -259,7 +260,9 @@ public function showDelete(string $bookSlug, string $pageSlug) $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; + $usedAsTemplate = + Book::query()->where('default_template_id', '=', $page->id)->count() > 0 || + Chapter::query()->where('default_template_id', '=', $page->id)->count() > 0; return view('pages.delete', [ 'book' => $page->book, @@ -279,7 +282,9 @@ public function showDeleteDraft(string $bookSlug, int $pageId) $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; + $usedAsTemplate = + Book::query()->where('default_template_id', '=', $page->id)->count() > 0 || + Chapter::query()->where('default_template_id', '=', $page->id)->count() > 0; return view('pages.delete', [ 'book' => $page->book, diff --git a/app/Entities/Models/Chapter.php b/app/Entities/Models/Chapter.php index f30d77b5c5c..d3a7101116b 100644 --- a/app/Entities/Models/Chapter.php +++ b/app/Entities/Models/Chapter.php @@ -2,6 +2,7 @@ namespace BookStack\Entities\Models; +use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Support\Collection; @@ -11,6 +12,8 @@ * * @property Collection $pages * @property string $description + * @property ?int $default_template_id + * @property ?Page $defaultTemplate */ class Chapter extends BookChild { @@ -48,6 +51,14 @@ public function getUrl(string $path = ''): string return url('/' . implode('/', $parts)); } + /** + * Get the Page that is used as default template for newly created pages within this Chapter. + */ + public function defaultTemplate(): BelongsTo + { + return $this->belongsTo(Page::class, 'default_template_id'); + } + /** * Get the visible pages in this chapter. */ diff --git a/app/Entities/Repos/ChapterRepo.php b/app/Entities/Repos/ChapterRepo.php index 977193d85bb..9534a406082 100644 --- a/app/Entities/Repos/ChapterRepo.php +++ b/app/Entities/Repos/ChapterRepo.php @@ -4,6 +4,7 @@ use BookStack\Activity\ActivityType; use BookStack\Entities\Models\Book; +use BookStack\Entities\Models\Page; use BookStack\Entities\Models\Chapter; use BookStack\Entities\Models\Entity; use BookStack\Entities\Tools\BookContents; @@ -46,6 +47,7 @@ public function create(array $input, Book $parentBook): Chapter $chapter->book_id = $parentBook->id; $chapter->priority = (new BookContents($parentBook))->getLastPriority() + 1; $this->baseRepo->create($chapter, $input); + $this->updateChapterDefaultTemplate($chapter, intval($input['default_template_id'] ?? null)); Activity::add(ActivityType::CHAPTER_CREATE, $chapter); return $chapter; @@ -57,6 +59,11 @@ public function create(array $input, Book $parentBook): Chapter public function update(Chapter $chapter, array $input): Chapter { $this->baseRepo->update($chapter, $input); + + if (array_key_exists('default_template_id', $input)) { + $this->updateChapterDefaultTemplate($chapter, intval($input['default_template_id'])); + } + Activity::add(ActivityType::CHAPTER_UPDATE, $chapter); return $chapter; @@ -101,6 +108,33 @@ public function move(Chapter $chapter, string $parentIdentifier): Book return $parent; } + /** + * Update the default page template used for this chapter. + * Checks that, if changing, the provided value is a valid template and the user + * has visibility of the provided page template id. + */ + protected function updateChapterDefaultTemplate(Chapter $chapter, int $templateId): void + { + $changing = $templateId !== intval($chapter->default_template_id); + if (!$changing) { + return; + } + + if ($templateId === 0) { + $chapter->default_template_id = null; + $chapter->save(); + return; + } + + $templateExists = Page::query()->visible() + ->where('template', '=', true) + ->where('id', '=', $templateId) + ->exists(); + + $chapter->default_template_id = $templateExists ? $templateId : null; + $chapter->save(); + } + /** * Find a page parent entity via an identifier string in the format: * {type}:{id} diff --git a/app/Entities/Repos/PageRepo.php b/app/Entities/Repos/PageRepo.php index 7b14ea7d278..67c4b222547 100644 --- a/app/Entities/Repos/PageRepo.php +++ b/app/Entities/Repos/PageRepo.php @@ -136,7 +136,13 @@ public function getNewDraftPage(Entity $parent) $page->book_id = $parent->id; } - $defaultTemplate = $page->book->defaultTemplate; + // check for chapter + if ($page->chapter_id) { + $defaultTemplate = $page->chapter->defaultTemplate; + } else { + $defaultTemplate = $page->book->defaultTemplate; + } + if ($defaultTemplate && userCan('view', $defaultTemplate)) { $page->forceFill([ 'html' => $defaultTemplate->html, diff --git a/app/Entities/Tools/TrashCan.php b/app/Entities/Tools/TrashCan.php index b2510398541..e5bcfe71ac2 100644 --- a/app/Entities/Tools/TrashCan.php +++ b/app/Entities/Tools/TrashCan.php @@ -208,6 +208,12 @@ protected function destroyPage(Page $page): int $page->forceDelete(); + // Remove chapter template usages + Chapter::query()->where('default_template_id', '=', $page->id) + ->update(['default_template_id' => null]); + + $page->forceDelete(); + return 1; } diff --git a/database/migrations/2024_01_01_104542_add_default_template_to_chapters.php b/database/migrations/2024_01_01_104542_add_default_template_to_chapters.php new file mode 100644 index 00000000000..5e9ea1de311 --- /dev/null +++ b/database/migrations/2024_01_01_104542_add_default_template_to_chapters.php @@ -0,0 +1,32 @@ +integer('default_template_id')->nullable()->default(null); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('chapters', function (Blueprint $table) { + $table->dropColumn('default_template_id'); + }); + } +} diff --git a/lang/en/entities.php b/lang/en/entities.php index f1f915544d1..4ab9de47dfb 100644 --- a/lang/en/entities.php +++ b/lang/en/entities.php @@ -192,6 +192,9 @@ 'chapters_permissions_success' => 'Chapter Permissions Updated', 'chapters_search_this' => 'Search this chapter', 'chapter_sort_book' => 'Sort Book', + 'chapter_default_template' => 'Default Page Template', + 'chapter_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this chapter. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'chapter_default_template_select' => 'Select a template page', // Pages 'page' => 'Page', diff --git a/resources/views/chapters/parts/form.blade.php b/resources/views/chapters/parts/form.blade.php index c6052c93af4..ea7f84bc839 100644 --- a/resources/views/chapters/parts/form.blade.php +++ b/resources/views/chapters/parts/form.blade.php @@ -22,6 +22,29 @@ +
+ +
+
+

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

+ +
+ @include('form.page-picker', [ + 'name' => 'default_template_id', + 'placeholder' => trans('entities.chapter_default_template_select'), + 'value' => $chapter->default_template_id ?? null, + 'selectorEndpoint' => '/search/entity-selector-templates', + ]) +
+
+ +
+
+
{{ trans('common.cancel') }} From b4d9029dc301f73f0e87026b8eff78cf2cda6164 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 7 Jan 2024 14:03:13 +0000 Subject: [PATCH 003/969] Range requests: Extracted stream output handling to new class --- app/Http/DownloadResponseFactory.php | 36 ++++-------- app/Http/RangeSupportedStream.php | 57 +++++++++++++++++++ app/Uploads/AttachmentService.php | 10 +++- .../Controllers/AttachmentController.php | 5 +- 4 files changed, 80 insertions(+), 28 deletions(-) create mode 100644 app/Http/RangeSupportedStream.php diff --git a/app/Http/DownloadResponseFactory.php b/app/Http/DownloadResponseFactory.php index 20032f52534..f8c10165c80 100644 --- a/app/Http/DownloadResponseFactory.php +++ b/app/Http/DownloadResponseFactory.php @@ -9,11 +9,9 @@ class DownloadResponseFactory { - protected Request $request; - - public function __construct(Request $request) - { - $this->request = $request; + public function __construct( + protected Request $request + ) { } /** @@ -27,19 +25,11 @@ public function directly(string $content, string $fileName): Response /** * Create a response that forces a download, from a given stream of content. */ - public function streamedDirectly($stream, string $fileName): StreamedResponse + public function streamedDirectly($stream, string $fileName, int $fileSize): StreamedResponse { - return response()->stream(function () use ($stream) { - - // End & flush the output buffer, if we're in one, otherwise we still use memory. - // Output buffer may or may not exist depending on PHP `output_buffering` setting. - // Ignore in testing since output buffers are used to gather a response. - if (!empty(ob_get_status()) && !app()->runningUnitTests()) { - ob_end_clean(); - } - - fpassthru($stream); - fclose($stream); + $rangeStream = new RangeSupportedStream($stream, $fileSize, $this->request->headers); + return response()->stream(function () use ($rangeStream) { + $rangeStream->outputAndClose(); }, 200, $this->getHeaders($fileName)); } @@ -48,15 +38,13 @@ public function streamedDirectly($stream, string $fileName): StreamedResponse * correct for the file, in a way so the browser can show the content in browser, * for a given content stream. */ - public function streamedInline($stream, string $fileName): StreamedResponse + public function streamedInline($stream, string $fileName, int $fileSize): StreamedResponse { - $sniffContent = fread($stream, 2000); - $mime = (new WebSafeMimeSniffer())->sniff($sniffContent); + $rangeStream = new RangeSupportedStream($stream, $fileSize, $this->request->headers); + $mime = $rangeStream->sniffMime(); - return response()->stream(function () use ($sniffContent, $stream) { - echo $sniffContent; - fpassthru($stream); - fclose($stream); + return response()->stream(function () use ($rangeStream) { + $rangeStream->outputAndClose(); }, 200, $this->getHeaders($fileName, $mime)); } diff --git a/app/Http/RangeSupportedStream.php b/app/Http/RangeSupportedStream.php new file mode 100644 index 00000000000..dc310503567 --- /dev/null +++ b/app/Http/RangeSupportedStream.php @@ -0,0 +1,57 @@ +fileSize); + $this->sniffContent = fread($this->stream, $offset); + + return (new WebSafeMimeSniffer())->sniff($this->sniffContent); + } + + /** + * Output the current stream to stdout before closing out the stream. + */ + public function outputAndClose(): void + { + // End & flush the output buffer, if we're in one, otherwise we still use memory. + // Output buffer may or may not exist depending on PHP `output_buffering` setting. + // Ignore in testing since output buffers are used to gather a response. + if (!empty(ob_get_status()) && !app()->runningUnitTests()) { + ob_end_clean(); + } + + $outStream = fopen('php://output', 'w'); + $offset = 0; + + if (!empty($this->sniffContent)) { + fwrite($outStream, $this->sniffContent); + $offset = strlen($this->sniffContent); + } + + $toWrite = $this->fileSize - $offset; + stream_copy_to_stream($this->stream, $outStream, $toWrite); + fpassthru($this->stream); + + fclose($this->stream); + fclose($outStream); + } +} diff --git a/app/Uploads/AttachmentService.php b/app/Uploads/AttachmentService.php index ddabec09f27..72f78e347bf 100644 --- a/app/Uploads/AttachmentService.php +++ b/app/Uploads/AttachmentService.php @@ -66,8 +66,6 @@ protected function adjustPathForStorageDisk(string $path): string /** * Stream an attachment from storage. * - * @throws FileNotFoundException - * * @return resource|null */ public function streamAttachmentFromStorage(Attachment $attachment) @@ -75,6 +73,14 @@ public function streamAttachmentFromStorage(Attachment $attachment) return $this->getStorageDisk()->readStream($this->adjustPathForStorageDisk($attachment->path)); } + /** + * Read the file size of an attachment from storage, in bytes. + */ + public function getAttachmentFileSize(Attachment $attachment): int + { + return $this->getStorageDisk()->size($this->adjustPathForStorageDisk($attachment->path)); + } + /** * Store a new attachment upon user upload. * diff --git a/app/Uploads/Controllers/AttachmentController.php b/app/Uploads/Controllers/AttachmentController.php index 92f23465d22..e61c1033884 100644 --- a/app/Uploads/Controllers/AttachmentController.php +++ b/app/Uploads/Controllers/AttachmentController.php @@ -226,12 +226,13 @@ public function get(Request $request, string $attachmentId) $fileName = $attachment->getFileName(); $attachmentStream = $this->attachmentService->streamAttachmentFromStorage($attachment); + $attachmentSize = $this->attachmentService->getAttachmentFileSize($attachment); if ($request->get('open') === 'true') { - return $this->download()->streamedInline($attachmentStream, $fileName); + return $this->download()->streamedInline($attachmentStream, $fileName, $attachmentSize); } - return $this->download()->streamedDirectly($attachmentStream, $fileName); + return $this->download()->streamedDirectly($attachmentStream, $fileName, $attachmentSize); } /** From d94762549a3ef364d4486a27f1585122f60c10ec Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 7 Jan 2024 20:34:03 +0000 Subject: [PATCH 004/969] Range requests: Added basic HTTP range support --- app/Http/DownloadResponseFactory.php | 28 ++++---- app/Http/RangeSupportedStream.php | 95 +++++++++++++++++++++++++--- 2 files changed, 103 insertions(+), 20 deletions(-) diff --git a/app/Http/DownloadResponseFactory.php b/app/Http/DownloadResponseFactory.php index f8c10165c80..f29aaa2e45a 100644 --- a/app/Http/DownloadResponseFactory.php +++ b/app/Http/DownloadResponseFactory.php @@ -2,7 +2,6 @@ namespace BookStack\Http; -use BookStack\Util\WebSafeMimeSniffer; use Illuminate\Http\Request; use Illuminate\Http\Response; use Symfony\Component\HttpFoundation\StreamedResponse; @@ -19,7 +18,7 @@ public function __construct( */ public function directly(string $content, string $fileName): Response { - return response()->make($content, 200, $this->getHeaders($fileName)); + return response()->make($content, 200, $this->getHeaders($fileName, strlen($content))); } /** @@ -27,10 +26,13 @@ public function directly(string $content, string $fileName): Response */ public function streamedDirectly($stream, string $fileName, int $fileSize): StreamedResponse { - $rangeStream = new RangeSupportedStream($stream, $fileSize, $this->request->headers); - return response()->stream(function () use ($rangeStream) { - $rangeStream->outputAndClose(); - }, 200, $this->getHeaders($fileName)); + $rangeStream = new RangeSupportedStream($stream, $fileSize, $this->request); + $headers = array_merge($this->getHeaders($fileName, $fileSize), $rangeStream->getResponseHeaders()); + return response()->stream( + fn() => $rangeStream->outputAndClose(), + $rangeStream->getResponseStatus(), + $headers, + ); } /** @@ -40,24 +42,28 @@ public function streamedDirectly($stream, string $fileName, int $fileSize): Stre */ public function streamedInline($stream, string $fileName, int $fileSize): StreamedResponse { - $rangeStream = new RangeSupportedStream($stream, $fileSize, $this->request->headers); + $rangeStream = new RangeSupportedStream($stream, $fileSize, $this->request); $mime = $rangeStream->sniffMime(); + $headers = array_merge($this->getHeaders($fileName, $fileSize, $mime), $rangeStream->getResponseHeaders()); - return response()->stream(function () use ($rangeStream) { - $rangeStream->outputAndClose(); - }, 200, $this->getHeaders($fileName, $mime)); + return response()->stream( + fn() => $rangeStream->outputAndClose(), + $rangeStream->getResponseStatus(), + $headers, + ); } /** * Get the common headers to provide for a download response. */ - protected function getHeaders(string $fileName, string $mime = 'application/octet-stream'): array + protected function getHeaders(string $fileName, int $fileSize, string $mime = 'application/octet-stream'): array { $disposition = ($mime === 'application/octet-stream') ? 'attachment' : 'inline'; $downloadName = str_replace('"', '', $fileName); return [ 'Content-Type' => $mime, + 'Content-Length' => $fileSize, 'Content-Disposition' => "{$disposition}; filename=\"{$downloadName}\"", 'X-Content-Type-Options' => 'nosniff', ]; diff --git a/app/Http/RangeSupportedStream.php b/app/Http/RangeSupportedStream.php index dc310503567..b51d4a5498f 100644 --- a/app/Http/RangeSupportedStream.php +++ b/app/Http/RangeSupportedStream.php @@ -3,17 +3,30 @@ namespace BookStack\Http; use BookStack\Util\WebSafeMimeSniffer; -use Symfony\Component\HttpFoundation\HeaderBag; +use Illuminate\Http\Request; +/** + * Helper wrapper for range-based stream response handling. + * Much of this used symfony/http-foundation as a reference during build. + * URL: https://github.com/symfony/http-foundation/blob/v6.0.20/BinaryFileResponse.php + * License: MIT license, Copyright (c) Fabien Potencier. + */ class RangeSupportedStream { protected string $sniffContent; + protected array $responseHeaders; + protected int $responseStatus = 200; + + protected int $responseLength = 0; + protected int $responseOffset = 0; public function __construct( protected $stream, protected int $fileSize, - protected HeaderBag $requestHeaders, + Request $request, ) { + $this->responseLength = $this->fileSize; + $this->parseRequest($request); } /** @@ -40,18 +53,82 @@ public function outputAndClose(): void } $outStream = fopen('php://output', 'w'); - $offset = 0; + $sniffOffset = strlen($this->sniffContent); - if (!empty($this->sniffContent)) { - fwrite($outStream, $this->sniffContent); - $offset = strlen($this->sniffContent); + if (!empty($this->sniffContent) && $this->responseOffset < $sniffOffset) { + $sniffOutput = substr($this->sniffContent, $this->responseOffset, min($sniffOffset, $this->responseLength)); + fwrite($outStream, $sniffOutput); + } else if ($this->responseOffset !== 0) { + fseek($this->stream, $this->responseOffset); } - $toWrite = $this->fileSize - $offset; - stream_copy_to_stream($this->stream, $outStream, $toWrite); - fpassthru($this->stream); + stream_copy_to_stream($this->stream, $outStream, $this->responseLength); fclose($this->stream); fclose($outStream); } + + public function getResponseHeaders(): array + { + return $this->responseHeaders; + } + + public function getResponseStatus(): int + { + return $this->responseStatus; + } + + protected function parseRequest(Request $request): void + { + $this->responseHeaders['Accept-Ranges'] = $request->isMethodSafe() ? 'bytes' : 'none'; + + $range = $this->getRangeFromRequest($request); + if ($range) { + [$start, $end] = $range; + if ($start < 0 || $start > $end) { + $this->responseStatus = 416; + $this->responseHeaders['Content-Range'] = sprintf('bytes */%s', $this->fileSize); + } elseif ($end - $start < $this->fileSize - 1) { + $this->responseLength = $end < $this->fileSize ? $end - $start + 1 : -1; + $this->responseOffset = $start; + $this->responseStatus = 206; + $this->responseHeaders['Content-Range'] = sprintf('bytes %s-%s/%s', $start, $end, $this->fileSize); + $this->responseHeaders['Content-Length'] = $end - $start + 1; + } + } + + if ($request->isMethod('HEAD')) { + $this->responseLength = 0; + } + } + + protected function getRangeFromRequest(Request $request): ?array + { + $range = $request->headers->get('Range'); + if (!$range || !$request->isMethod('GET') || !str_starts_with($range, 'bytes=')) { + return null; + } + + if ($request->headers->has('If-Range')) { + return null; + } + + [$start, $end] = explode('-', substr($range, 6), 2) + [0]; + + $end = ('' === $end) ? $this->fileSize - 1 : (int) $end; + + if ('' === $start) { + $start = $this->fileSize - $end; + $end = $this->fileSize - 1; + } else { + $start = (int) $start; + } + + if ($start > $end) { + return null; + } + + $end = min($end, $this->fileSize - 1); + return [$start, $end]; + } } From 91d8d6eaaa5ae42fc9872901d6fcbcae8e19236e Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 14 Jan 2024 15:50:00 +0000 Subject: [PATCH 005/969] Range requests: Added test cases to cover functionality Fixed some found issues in the process. --- app/Http/RangeSupportedStream.php | 20 +++--- tests/Uploads/AttachmentTest.php | 101 ++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 10 deletions(-) diff --git a/app/Http/RangeSupportedStream.php b/app/Http/RangeSupportedStream.php index b51d4a5498f..300f4488cf4 100644 --- a/app/Http/RangeSupportedStream.php +++ b/app/Http/RangeSupportedStream.php @@ -13,8 +13,8 @@ */ class RangeSupportedStream { - protected string $sniffContent; - protected array $responseHeaders; + protected string $sniffContent = ''; + protected array $responseHeaders = []; protected int $responseStatus = 200; protected int $responseLength = 0; @@ -53,16 +53,20 @@ public function outputAndClose(): void } $outStream = fopen('php://output', 'w'); - $sniffOffset = strlen($this->sniffContent); + $sniffLength = strlen($this->sniffContent); + $bytesToWrite = $this->responseLength; - if (!empty($this->sniffContent) && $this->responseOffset < $sniffOffset) { - $sniffOutput = substr($this->sniffContent, $this->responseOffset, min($sniffOffset, $this->responseLength)); + if ($sniffLength > 0 && $this->responseOffset < $sniffLength) { + $sniffEnd = min($sniffLength, $bytesToWrite + $this->responseOffset); + $sniffOutLength = $sniffEnd - $this->responseOffset; + $sniffOutput = substr($this->sniffContent, $this->responseOffset, $sniffOutLength); fwrite($outStream, $sniffOutput); + $bytesToWrite -= $sniffOutLength; } else if ($this->responseOffset !== 0) { fseek($this->stream, $this->responseOffset); } - stream_copy_to_stream($this->stream, $outStream, $this->responseLength); + stream_copy_to_stream($this->stream, $outStream, $bytesToWrite); fclose($this->stream); fclose($outStream); @@ -124,10 +128,6 @@ protected function getRangeFromRequest(Request $request): ?array $start = (int) $start; } - if ($start > $end) { - return null; - } - $end = min($end, $this->fileSize - 1); return [$start, $end]; } diff --git a/tests/Uploads/AttachmentTest.php b/tests/Uploads/AttachmentTest.php index bd03c339c43..2e1a7b3395a 100644 --- a/tests/Uploads/AttachmentTest.php +++ b/tests/Uploads/AttachmentTest.php @@ -316,4 +316,105 @@ public function test_file_upload_works_when_local_secure_restricted_is_in_use() $this->assertFileExists(storage_path($attachment->path)); $this->files->deleteAllAttachmentFiles(); } + + public function test_file_get_range_access() + { + $page = $this->entities->page(); + $this->asAdmin(); + $attachment = $this->files->uploadAttachmentDataToPage($this, $page, 'my_text.txt', 'abc123456', 'text/plain'); + + // Download access + $resp = $this->get($attachment->getUrl(), ['Range' => 'bytes=3-5']); + $resp->assertStatus(206); + $resp->assertStreamedContent('123'); + $resp->assertHeader('Content-Length', '3'); + $resp->assertHeader('Content-Range', 'bytes 3-5/9'); + + // Inline access + $resp = $this->get($attachment->getUrl(true), ['Range' => 'bytes=5-7']); + $resp->assertStatus(206); + $resp->assertStreamedContent('345'); + $resp->assertHeader('Content-Length', '3'); + $resp->assertHeader('Content-Range', 'bytes 5-7/9'); + + $this->files->deleteAllAttachmentFiles(); + } + + public function test_file_head_range_returns_no_content() + { + $page = $this->entities->page(); + $this->asAdmin(); + $attachment = $this->files->uploadAttachmentDataToPage($this, $page, 'my_text.txt', 'abc123456', 'text/plain'); + + $resp = $this->head($attachment->getUrl(), ['Range' => 'bytes=0-9']); + $resp->assertStreamedContent(''); + $resp->assertHeader('Content-Length', '9'); + $resp->assertStatus(200); + + $this->files->deleteAllAttachmentFiles(); + } + + public function test_file_head_range_edge_cases() + { + $page = $this->entities->page(); + $this->asAdmin(); + + // Mime-type "sniffing" happens on first 2k bytes, hence this content (2005 bytes) + $content = '01234' . str_repeat('a', 1990) . '0123456789'; + $attachment = $this->files->uploadAttachmentDataToPage($this, $page, 'my_text.txt', $content, 'text/plain'); + + // Test for both inline and download attachment serving + foreach ([true, false] as $isInline) { + // No end range + $resp = $this->get($attachment->getUrl($isInline), ['Range' => 'bytes=5-']); + $resp->assertStreamedContent(substr($content, 5)); + $resp->assertHeader('Content-Length', '2000'); + $resp->assertHeader('Content-Range', 'bytes 5-2004/2005'); + $resp->assertStatus(206); + + // End only range + $resp = $this->get($attachment->getUrl($isInline), ['Range' => 'bytes=-10']); + $resp->assertStreamedContent('0123456789'); + $resp->assertHeader('Content-Length', '10'); + $resp->assertHeader('Content-Range', 'bytes 1995-2004/2005'); + $resp->assertStatus(206); + + // Range across sniff point + $resp = $this->get($attachment->getUrl($isInline), ['Range' => 'bytes=1997-2002']); + $resp->assertStreamedContent('234567'); + $resp->assertHeader('Content-Length', '6'); + $resp->assertHeader('Content-Range', 'bytes 1997-2002/2005'); + $resp->assertStatus(206); + + // Range up to sniff point + $resp = $this->get($attachment->getUrl($isInline), ['Range' => 'bytes=0-1997']); + $resp->assertHeader('Content-Length', '1998'); + $resp->assertHeader('Content-Range', 'bytes 0-1997/2005'); + $resp->assertStreamedContent(substr($content, 0, 1998)); + $resp->assertStatus(206); + + // Range beyond sniff point + $resp = $this->get($attachment->getUrl($isInline), ['Range' => 'bytes=2001-2003']); + $resp->assertStreamedContent('678'); + $resp->assertHeader('Content-Length', '3'); + $resp->assertHeader('Content-Range', 'bytes 2001-2003/2005'); + $resp->assertStatus(206); + + // Range beyond content + $resp = $this->get($attachment->getUrl($isInline), ['Range' => 'bytes=0-2010']); + $resp->assertStreamedContent($content); + $resp->assertHeader('Content-Length', '2005'); + $resp->assertHeaderMissing('Content-Range'); + $resp->assertStatus(200); + + // Range start before end + $resp = $this->get($attachment->getUrl($isInline), ['Range' => 'bytes=50-10']); + $resp->assertStreamedContent($content); + $resp->assertHeader('Content-Length', '2005'); + $resp->assertHeader('Content-Range', 'bytes */2005'); + $resp->assertStatus(416); + } + + $this->files->deleteAllAttachmentFiles(); + } } From c1552fb799cda7fbb6de27ebcb01aa2580fd5330 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 15 Jan 2024 11:50:05 +0000 Subject: [PATCH 006/969] Attachments: Drag and drop video support Supports dragging and dropping video attahchments to embed them in the editor as HTML video tags. --- app/Uploads/Attachment.php | 19 +++++++++++++++++-- .../views/attachments/manager-list.blade.php | 2 +- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/app/Uploads/Attachment.php b/app/Uploads/Attachment.php index 4fd6d4cdcb7..57d7cb3346c 100644 --- a/app/Uploads/Attachment.php +++ b/app/Uploads/Attachment.php @@ -77,7 +77,22 @@ public function getUrl($openInline = false): string } /** - * Generate a HTML link to this attachment. + * Get the representation of this attachment in a format suitable for the page editors. + * Detects and adapts video content to use an inline video embed. + */ + public function editorContent(): array + { + $videoExtensions = ['mp4', 'webm', 'mkv', 'ogg', 'avi']; + if (in_array(strtolower($this->extension), $videoExtensions)) { + $html = ''; + return ['text/html' => $html, 'text/plain' => $html]; + } + + return ['text/html' => $this->htmlLink(), 'text/plain' => $this->markdownLink()]; + } + + /** + * Generate the HTML link to this attachment. */ public function htmlLink(): string { @@ -85,7 +100,7 @@ public function htmlLink(): string } /** - * Generate a markdown link to this attachment. + * Generate a MarkDown link to this attachment. */ public function markdownLink(): string { diff --git a/resources/views/attachments/manager-list.blade.php b/resources/views/attachments/manager-list.blade.php index 342b46dcad7..0e841a042f7 100644 --- a/resources/views/attachments/manager-list.blade.php +++ b/resources/views/attachments/manager-list.blade.php @@ -4,7 +4,7 @@
@icon('grip')
From 2dc454d206b518804aecd0551a71d338cf889c08 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 15 Jan 2024 13:36:04 +0000 Subject: [PATCH 007/969] Uploads: Explicitly disabled s3 streaming in config This was the default option anyway, just adding here for better visibility of this being set. Can't enable without issues as the app will attempt to seek which does not work for these streams. Also have not tested on non-s3, s3-like systems. --- app/Config/filesystems.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Config/filesystems.php b/app/Config/filesystems.php index e6ae0fed364..1319c8886f6 100644 --- a/app/Config/filesystems.php +++ b/app/Config/filesystems.php @@ -58,6 +58,7 @@ 'endpoint' => env('STORAGE_S3_ENDPOINT', null), 'use_path_style_endpoint' => env('STORAGE_S3_ENDPOINT', null) !== null, 'throw' => true, + 'stream_reads' => false, ], ], From adf1806feaa541f7ff627ba83278ea7dd2fd7a04 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Tue, 16 Jan 2024 12:06:13 +0000 Subject: [PATCH 008/969] Chapters API: Added missing book_slug field Was removed during previous changes, but reflected in response examples. This adds into all standard single chapter responses. For #4765 --- app/Entities/Controllers/ChapterApiController.php | 5 +++-- dev/api/responses/chapters-create.json | 1 + dev/api/responses/chapters-update.json | 1 + tests/Api/ChaptersApiTest.php | 13 ++++++++----- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/app/Entities/Controllers/ChapterApiController.php b/app/Entities/Controllers/ChapterApiController.php index c2132326200..85c81c2485c 100644 --- a/app/Entities/Controllers/ChapterApiController.php +++ b/app/Entities/Controllers/ChapterApiController.php @@ -134,8 +134,9 @@ protected function forJsonDisplay(Chapter $chapter): Chapter $chapter->unsetRelations()->refresh(); $chapter->load(['tags']); - $chapter->makeVisible('description_html') - ->setAttribute('description_html', $chapter->descriptionHtml()); + $chapter->makeVisible('description_html'); + $chapter->setAttribute('description_html', $chapter->descriptionHtml()); + $chapter->setAttribute('book_slug', $chapter->book()->first()->slug); return $chapter; } diff --git a/dev/api/responses/chapters-create.json b/dev/api/responses/chapters-create.json index 183186b0b42..2d404440587 100644 --- a/dev/api/responses/chapters-create.json +++ b/dev/api/responses/chapters-create.json @@ -11,6 +11,7 @@ "updated_by": 1, "owned_by": 1, "description_html": "

This is a great new chapter<\/strong> that I've created via the API<\/p>", + "book_slug": "example-book", "tags": [ { "name": "Category", diff --git a/dev/api/responses/chapters-update.json b/dev/api/responses/chapters-update.json index 5ac3c64c12f..3dad6aa0c12 100644 --- a/dev/api/responses/chapters-update.json +++ b/dev/api/responses/chapters-update.json @@ -11,6 +11,7 @@ "updated_by": 1, "owned_by": 1, "description_html": "

This is an updated chapter<\/strong> that I've altered via the API<\/p>", + "book_slug": "example-book", "tags": [ { "name": "Category", diff --git a/tests/Api/ChaptersApiTest.php b/tests/Api/ChaptersApiTest.php index 81a91887794..002046c3a3b 100644 --- a/tests/Api/ChaptersApiTest.php +++ b/tests/Api/ChaptersApiTest.php @@ -22,11 +22,12 @@ public function test_index_endpoint_returns_expected_chapter() $resp = $this->getJson($this->baseEndpoint . '?count=1&sort=+id'); $resp->assertJson(['data' => [ [ - 'id' => $firstChapter->id, - 'name' => $firstChapter->name, - 'slug' => $firstChapter->slug, - 'book_id' => $firstChapter->book->id, - 'priority' => $firstChapter->priority, + 'id' => $firstChapter->id, + 'name' => $firstChapter->name, + 'slug' => $firstChapter->slug, + 'book_id' => $firstChapter->book->id, + 'priority' => $firstChapter->priority, + 'book_slug' => $firstChapter->book->slug, ], ]]); } @@ -130,6 +131,7 @@ public function test_read_endpoint() $resp->assertJson([ 'id' => $chapter->id, 'slug' => $chapter->slug, + 'book_slug' => $chapter->book->slug, 'created_by' => [ 'name' => $chapter->createdBy->name, ], @@ -148,6 +150,7 @@ public function test_read_endpoint() ], ], ]); + $resp->assertJsonMissingPath('book'); $resp->assertJsonCount($chapter->pages()->count(), 'pages'); } From 57284bb869bcf8e1f9aced986a72c386fee5d086 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Tue, 16 Jan 2024 12:10:22 +0000 Subject: [PATCH 009/969] Updated translations with latest Crowdin changes (#4747) --- lang/ca/entities.php | 4 ++-- lang/cs/entities.php | 4 ++-- lang/da/notifications.php | 14 +++++++------- lang/de/entities.php | 4 ++-- lang/de_informal/entities.php | 4 ++-- lang/fa/notifications.php | 6 +++--- lang/fa/settings.php | 6 +++--- lang/ja/entities.php | 12 ++++++------ lang/ja/notifications.php | 2 +- lang/nn/editor.php | 28 ++++++++++++++-------------- lang/nn/entities.php | 12 ++++++------ lang/nn/notifications.php | 22 +++++++++++----------- lang/nn/pagination.php | 2 +- lang/zh_CN/entities.php | 4 ++-- lang/zh_TW/common.php | 6 +++--- lang/zh_TW/components.php | 14 +++++++------- lang/zh_TW/settings.php | 6 +++--- 17 files changed, 75 insertions(+), 75 deletions(-) diff --git a/lang/ca/entities.php b/lang/ca/entities.php index 9bffe493cb5..53b766b4259 100644 --- a/lang/ca/entities.php +++ b/lang/ca/entities.php @@ -23,7 +23,7 @@ 'meta_updated' => 'Actualitzat :timeLength', 'meta_updated_name' => 'Actualitzat :timeLength per :user', 'meta_owned_name' => 'Propietat de :user', - 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', + 'meta_reference_count' => 'Hi fa referència :count element|Hi fan referència :count elements', 'entity_select' => 'Selecciona una entitat', 'entity_select_lack_permission' => 'No teniu els permisos necessaris per a seleccionar aquest element', 'images' => 'Imatges', @@ -409,7 +409,7 @@ // References '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.', + 'references_to_desc' => 'A continuació es llisten tots els continguts coneguts del sistema que enllacen a aquest element.', // Watch Options 'watch' => 'Segueix', diff --git a/lang/cs/entities.php b/lang/cs/entities.php index 55b2e71de68..4471c4b3787 100644 --- a/lang/cs/entities.php +++ b/lang/cs/entities.php @@ -23,7 +23,7 @@ 'meta_updated' => 'Aktualizováno :timeLength', 'meta_updated_name' => 'Aktualizováno :timeLength uživatelem :user', 'meta_owned_name' => 'Vlastník :user', - 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', + 'meta_reference_count' => 'Odkazováno :count položkou|Odkazováno :count položkami', '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', @@ -409,7 +409,7 @@ // References 'references' => 'Odkazy', 'references_none' => 'Nebyly nalezeny žádné odkazy na tuto položku.', - 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', + 'references_to_desc' => 'Níže je uveden veškerý obsah o kterém systém ví, že odkazuje na tuto položku.', // Watch Options 'watch' => 'Sledovat', diff --git a/lang/da/notifications.php b/lang/da/notifications.php index 1afd23f1dc4..61a44f1f094 100644 --- a/lang/da/notifications.php +++ b/lang/da/notifications.php @@ -4,13 +4,13 @@ */ 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' => 'Ny kommentar på siden: :pageName', + 'new_comment_intro' => 'En bruger har kommenteret på en side i :appName:', + 'new_page_subject' => 'Ny side: :pageName', + 'new_page_intro' => 'En ny side er blevet oprettet i :appName:', + 'updated_page_subject' => 'Opdateret side: :pageName', + 'updated_page_intro' => 'En side er blevet opdateret i :appName:', + 'updated_page_debounce' => 'For at forhindre en masse af notifikationer, i et stykke tid vil du ikke blive sendt notifikationer for yderligere redigeringer til denne side af den samme editor.', 'detail_page_name' => 'Page Name:', 'detail_page_path' => 'Page Path:', diff --git a/lang/de/entities.php b/lang/de/entities.php index 21a0d3befd4..0b46b41f398 100644 --- a/lang/de/entities.php +++ b/lang/de/entities.php @@ -23,7 +23,7 @@ 'meta_updated' => 'Zuletzt aktualisiert: :timeLength', 'meta_updated_name' => 'Zuletzt aktualisiert: :timeLength von :user', 'meta_owned_name' => 'Im Besitz von :user', - 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', + 'meta_reference_count' => 'Referenziert von :count Element|Referenziert von :count Elementen', 'entity_select' => 'Eintrag auswählen', 'entity_select_lack_permission' => 'Sie haben nicht die benötigte Berechtigung, um dieses Element auszuwählen', 'images' => 'Bilder', @@ -409,7 +409,7 @@ // References 'references' => 'Verweise', 'references_none' => 'Es gibt keine nachverfolgten Referenzen zu diesem Element.', - 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', + 'references_to_desc' => 'Unten sind alle bekannten Inhalte im System aufgelistet, die auf diesen Eintrag verweisen.', // Watch Options 'watch' => 'Beobachten', diff --git a/lang/de_informal/entities.php b/lang/de_informal/entities.php index 2da655c1f31..43842a55d16 100644 --- a/lang/de_informal/entities.php +++ b/lang/de_informal/entities.php @@ -23,7 +23,7 @@ 'meta_updated' => 'Zuletzt aktualisiert: :timeLength', 'meta_updated_name' => 'Zuletzt aktualisiert: :timeLength von :user', 'meta_owned_name' => 'Im Besitz von :user', - 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', + 'meta_reference_count' => 'Referenziert von :count Element|Referenziert von :count Elementen', 'entity_select' => 'Eintrag auswählen', 'entity_select_lack_permission' => 'Du hast nicht die benötigte Berechtigung, um dieses Element auszuwählen', 'images' => 'Bilder', @@ -409,7 +409,7 @@ // References 'references' => 'Verweise', 'references_none' => 'Es gibt keine nachverfolgten Referenzen zu diesem Element.', - 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', + 'references_to_desc' => 'Unten sind alle bekannten Inhalte im System aufgelistet, die auf diesen Eintrag verweisen.', // Watch Options 'watch' => 'Beobachten', diff --git a/lang/fa/notifications.php b/lang/fa/notifications.php index 675eaa762b6..12f4230a13e 100644 --- a/lang/fa/notifications.php +++ b/lang/fa/notifications.php @@ -5,7 +5,7 @@ return [ 'new_comment_subject' => 'نظر جدید در صفحه: :pageName', - 'new_comment_intro' => 'یک کاربر در بر روی صفحه‌ای نظر ثبت کرده است :appName:', + 'new_comment_intro' => 'یک کاربر در صفحه نظر ارایه کرده است :appName:', 'new_page_subject' => 'صفحه جدید: :pageName', 'new_page_intro' => 'یک صفحه جدید ایجاد شده است در :appName:', 'updated_page_subject' => 'صفحه جدید: :pageName', @@ -13,14 +13,14 @@ 'updated_page_debounce' => 'برای جلوگیری از انبوه اعلان‌ها، برای مدتی اعلان‌ ویرایش‌هایی که توسط همان ویرایشگر در این صفحه انجام می‌شود، ارسال نخواهد شد.', 'detail_page_name' => 'نام صفحه:', - 'detail_page_path' => 'Page Path:', + 'detail_page_path' => 'نام میسر صفحه:', 'detail_commenter' => 'نظر دهنده:', 'detail_comment' => 'نظر:', 'detail_created_by' => 'ایجاد شده توسط:', 'detail_updated_by' => 'به روزرسانی شده توسط:', 'action_view_comment' => 'مشاهده نظر', - 'action_view_page' => 'View Page', + 'action_view_page' => 'مشاهده صفحه', 'footer_reason' => 'This notification was sent to you because :link cover this type of activity for this item.', 'footer_reason_link' => 'تنظیمات اطلاع‌رسانی شما', diff --git a/lang/fa/settings.php b/lang/fa/settings.php index 0659cde465a..c48f4d8e92b 100644 --- a/lang/fa/settings.php +++ b/lang/fa/settings.php @@ -194,7 +194,7 @@ 'users_send_invite_option' => 'ارسال ایمیل دعوت کاربر', 'users_external_auth_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_password_warning' => 'فقط در صورتی که مایل به تغییر رمز عبور این کاربر هستید، موارد زیر را پر کنید.', 'users_system_public' => 'این کاربر نماینده هر کاربر مهمانی است که از نمونه شما بازدید می کند. نمی توان از آن برای ورود استفاده کرد اما به طور خودکار اختصاص داده می شود.', 'users_delete' => 'حذف کاربر', 'users_delete_named' => 'حذف :userName', @@ -210,12 +210,12 @@ 'users_preferred_language' => 'زبان ترجیحی', 'users_preferred_language_desc' => 'این گزینه زبان مورد استفاده برای رابط کاربری برنامه را تغییر می دهد. این روی محتوای ایجاد شده توسط کاربر تأثیری نخواهد داشت.', 'users_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_desc' => 'مشاهده وضعیت حساب‌های اجتماعی متصل به این کاربر. حساب‌های اجتماعی می‌توانند به عنوان تکمیلی به سیستم اصلی احراز هویت برای دسترسی به سیستم استفاده شوند.', 'users_social_accounts_info' => 'در اینجا می‌توانید حساب‌های دیگر خود را برای ورود سریع‌تر و آسان‌تر متصل کنید. قطع ارتباط حساب در اینجا، دسترسی مجاز قبلی را لغو نمی کند. دسترسی را از تنظیمات نمایه خود در حساب اجتماعی متصل لغو کنید.', 'users_social_connect' => 'اتصال حساب کاربری', 'users_social_disconnect' => 'قطع حساب', 'users_social_status_connected' => 'Connected', - 'users_social_status_disconnected' => 'Disconnected', + 'users_social_status_disconnected' => 'قطع اتصال', 'users_social_connected' => 'حساب :socialAccount با موفقیت به نمایه شما پیوست شد.', 'users_social_disconnected' => 'حساب :socialAccount با موفقیت از نمایه شما قطع شد.', 'users_api_tokens' => 'توکن‌های API', diff --git a/lang/ja/entities.php b/lang/ja/entities.php index dd4c2746982..0b39c2c27e8 100644 --- a/lang/ja/entities.php +++ b/lang/ja/entities.php @@ -23,7 +23,7 @@ 'meta_updated' => '更新: :timeLength', 'meta_updated_name' => '更新: :timeLength (:user)', 'meta_owned_name' => '所有者: :user', - 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', + 'meta_reference_count' => ':count 項目から参照|:count 項目から参照', 'entity_select' => 'エンティティ選択', 'entity_select_lack_permission' => 'この項目を選択するために必要な権限がありません', 'images' => '画像', @@ -132,9 +132,9 @@ '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_default_template' => 'デフォルトページテンプレート', + 'books_default_template_explain' => 'このブックに新しいページを作成する際にデフォルトコンテンツとして使用されるページテンプレートを割り当てます。 これはページ作成者が選択したテンプレートページへのアクセス権を持つ場合にのみ使用されることに注意してください。', + 'books_default_template_select' => 'テンプレートページを選択', 'books_permissions' => 'ブックの権限', 'books_permissions_updated' => 'ブックの権限を更新しました', 'books_empty_contents' => 'まだページまたはチャプターが作成されていません。', @@ -207,7 +207,7 @@ '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_warning_template' => 'このページは現在ブックのデフォルトページテンプレートとして使用されています。 このページが削除されると、それらのブックでデフォルトのページテンプレートが割り当てられなくなります。', 'pages_delete_confirm' => 'このページを削除してもよろしいですか?', 'pages_delete_draft_confirm' => 'このページの下書きを削除してもよろしいですか?', 'pages_editing_named' => 'ページ :pageName を編集', @@ -410,7 +410,7 @@ // References 'references' => '参照', 'references_none' => 'この項目への追跡された参照はありません。', - 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', + 'references_to_desc' => 'この項目はシステム内の以下のコンテンツからリンクされています。', // Watch Options 'watch' => 'ウォッチ', diff --git a/lang/ja/notifications.php b/lang/ja/notifications.php index 364b4a3aa0c..6fc0321d353 100644 --- a/lang/ja/notifications.php +++ b/lang/ja/notifications.php @@ -13,7 +13,7 @@ 'updated_page_debounce' => '大量の通知を防ぐために、しばらくの間は同じユーザがこのページをさらに編集しても通知は送信されません。', 'detail_page_name' => 'ページ名:', - 'detail_page_path' => 'Page Path:', + 'detail_page_path' => 'ページパス:', 'detail_commenter' => 'コメントユーザ:', 'detail_comment' => 'コメント:', 'detail_created_by' => '作成ユーザ:', diff --git a/lang/nn/editor.php b/lang/nn/editor.php index 2f3b22d8bd2..4eef9d28aa8 100644 --- a/lang/nn/editor.php +++ b/lang/nn/editor.php @@ -14,24 +14,24 @@ 'save' => 'Lagre', 'close' => 'Lukk', 'undo' => 'Angre', - 'redo' => 'Gjør om', + 'redo' => 'Gjer om', 'left' => 'Venstre', 'center' => 'Sentrert', - 'right' => 'Høyre', + 'right' => 'Høgre', 'top' => 'Topp', 'middle' => 'Sentrert', - 'bottom' => 'Bunn', - 'width' => 'Bredde', - 'height' => 'Høyde', - 'More' => 'Mer', + 'bottom' => 'Botn', + 'width' => 'Breidde', + 'height' => 'Høgde', + 'More' => 'Meir', 'select' => 'Velg …', // Toolbar 'formats' => 'Formater', 'header_large' => 'Stor overskrift', 'header_medium' => 'Medium overskrift', - 'header_small' => 'Liten overskrift', - 'header_tiny' => 'Bitteliten overskrift', + 'header_small' => 'Lita overskrift', + 'header_tiny' => 'Bittelita overskrift', 'paragraph' => 'Avsnitt', 'blockquote' => 'Blokksitat', 'inline_code' => 'Kodesetning', @@ -40,24 +40,24 @@ 'callout_success' => 'Positiv', 'callout_warning' => 'Advarsel', 'callout_danger' => 'Negativ', - 'bold' => 'Fet', + 'bold' => 'Feit', 'italic' => 'Kursiv', 'underline' => 'Understrek', 'strikethrough' => 'Strek over', - 'superscript' => 'Hevet skrift', - 'subscript' => 'Senket skrift', + 'superscript' => 'Heva skrift', + 'subscript' => 'Senka skrift', 'text_color' => 'Tekstfarge', - 'custom_color' => 'Egenvalgt farge', + 'custom_color' => 'Eigenvalgt farge', 'remove_color' => 'Fjern farge', 'background_color' => 'Bakgrunnsfarge', 'align_left' => 'Venstrejustering', 'align_center' => 'Midtstilling', - 'align_right' => 'Høyrejustering', + 'align_right' => 'Høgrejustering', 'align_justify' => 'Blokkjustering', 'list_bullet' => 'Punktliste', 'list_numbered' => 'Nummerert liste', 'list_task' => 'Oppgaveliste', - 'indent_increase' => 'Øk innrykk', + 'indent_increase' => 'Auk innrykk', 'indent_decrease' => 'Redusér innrykk', 'table' => 'Tabell', 'insert_image' => 'Sett inn bilde', diff --git a/lang/nn/entities.php b/lang/nn/entities.php index f2ad696776c..21ab84310b2 100644 --- a/lang/nn/entities.php +++ b/lang/nn/entities.php @@ -23,7 +23,7 @@ 'meta_updated' => 'Oppdatert :timeLength', 'meta_updated_name' => 'Oppdatert :timeLength av :user', 'meta_owned_name' => 'Eigd av :user', - 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', + 'meta_reference_count' => 'Sitert på :count side|Sitert på :count sider', 'entity_select' => 'Velg entitet', 'entity_select_lack_permission' => 'Du har ikkje tilgang til å velge dette elementet', 'images' => 'Bilete', @@ -132,9 +132,9 @@ '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_default_template' => 'Standard sidemal', + 'books_default_template_explain' => 'Tildel ein sidemal som vil bli brukt som standardinnhold for alle nye sider i denne boka. Hugs at dette berre vil bli brukt om sideskaperen har tilgang til den valgte malsida.', + 'books_default_template_select' => 'Velg ei malside', 'books_permissions' => 'Boktilganger', 'books_permissions_updated' => 'Boktilganger oppdatert', 'books_empty_contents' => 'Ingen sider eller kapittel finst i denne boka.', @@ -207,7 +207,7 @@ 'pages_delete_draft' => 'Slett utkastet', 'pages_delete_success' => 'Siden er 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_warning_template' => 'Denne siden er i aktiv bruk som en standard sidemal for bok. Desse bøkene vil ikkje lenger ha ein standard sidemal som er tilordnet etter at denne sida vert sletta.', '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)', @@ -409,7 +409,7 @@ // References 'references' => 'Referanser', 'references_none' => 'Det er ingen sporede referanser til dette elementet.', - 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', + 'references_to_desc' => 'Nedanfor vises alle dei kjente sidene i systemet som lenker til denne oppføringa.', // Watch Options 'watch' => 'Overvåk', diff --git a/lang/nn/notifications.php b/lang/nn/notifications.php index 98c686e4414..247d8d10572 100644 --- a/lang/nn/notifications.php +++ b/lang/nn/notifications.php @@ -4,24 +4,24 @@ */ return [ - 'new_comment_subject' => 'Ny kommentar på siden: :pageName', - 'new_comment_intro' => 'En bruker har kommentert en side i :appName:', + 'new_comment_subject' => 'Ny kommentar på sida: :pageName', + 'new_comment_intro' => 'Ein brukar har kommentert ei side i :appName:', 'new_page_subject' => 'Ny side: :pageName', - 'new_page_intro' => 'En ny side er opprettet i :appName:', + 'new_page_intro' => 'Ei ny side vart oppretta i :appName:', 'updated_page_subject' => 'Oppdatert side: :pageName', - 'updated_page_intro' => 'En side er oppdatert i :appName:', - 'updated_page_debounce' => 'For å forhindre mange varslinger, vil du ikke få nye varslinger for endringer på denne siden fra samme forfatter.', + 'updated_page_intro' => 'Ei side vart oppdatert i :appName:', + 'updated_page_debounce' => 'For å forhindre mange varslingar, vil du ikkje få nye varslinger for endringar på denne siden frå same forfattar.', - 'detail_page_name' => 'Sidenavn:', + 'detail_page_name' => 'Sidenamn:', 'detail_page_path' => 'Sidenamn:', - 'detail_commenter' => 'Kommentar fra:', + 'detail_commenter' => 'Kommentar frå:', 'detail_comment' => 'Kommentar:', - 'detail_created_by' => 'Opprettet av:', + 'detail_created_by' => 'Oppretta av:', 'detail_updated_by' => 'Oppdatert av:', 'action_view_comment' => 'Vis kommentar', - 'action_view_page' => 'Se side', + 'action_view_page' => 'Sjå side', - 'footer_reason' => 'Denne meldingen ble sendt til deg fordi :link dekker denne typen aktivitet for dette elementet.', - 'footer_reason_link' => 'dine varslingsinnstillinger', + 'footer_reason' => 'Denne meldinga vart sendt til deg fordi :link dekker denne typen aktivitet for dette elementet.', + 'footer_reason_link' => 'dine varslingsinnstillingar', ]; diff --git a/lang/nn/pagination.php b/lang/nn/pagination.php index d910da124be..15529d12af8 100644 --- a/lang/nn/pagination.php +++ b/lang/nn/pagination.php @@ -6,7 +6,7 @@ */ return [ - 'previous' => '« Forrige', + 'previous' => '« Førre', 'next' => 'Neste »', ]; diff --git a/lang/zh_CN/entities.php b/lang/zh_CN/entities.php index a0c32fa4f4d..e12f6051afb 100644 --- a/lang/zh_CN/entities.php +++ b/lang/zh_CN/entities.php @@ -23,7 +23,7 @@ 'meta_updated' => '更新于 :timeLength', 'meta_updated_name' => '由 :user 更新于 :timeLength', 'meta_owned_name' => '拥有者 :user', - 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', + 'meta_reference_count' => '被 :count 个页面引用|被 :count 个页面引用', 'entity_select' => '选择项目', 'entity_select_lack_permission' => '您没有选择此项目所需的权限', 'images' => '图片', @@ -133,7 +133,7 @@ '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_explain' => '指定一个页面模板,该模板将用作本书中所有新页面的默认内容。请注意,仅当页面创建者具有对所选页面模板的查看访问权限时,此功能才会生效。', 'books_default_template_select' => '选择模板页面', 'books_permissions' => '图书权限', 'books_permissions_updated' => '图书权限已更新', diff --git a/lang/zh_TW/common.php b/lang/zh_TW/common.php index 22bde3f0872..53b2a531037 100644 --- a/lang/zh_TW/common.php +++ b/lang/zh_TW/common.php @@ -6,7 +6,7 @@ // Buttons 'cancel' => '取消', - 'close' => 'Close', + 'close' => '關閉', 'confirm' => '確認', 'back' => '返回', 'save' => '儲存', @@ -42,7 +42,7 @@ 'remove' => '移除', 'add' => '新增', 'configure' => '配置', - 'manage' => 'Manage', + 'manage' => '管理', 'fullscreen' => '全螢幕', 'favourite' => '最愛', 'unfavourite' => '取消最愛', @@ -52,7 +52,7 @@ 'filter_clear' => '清理過濾', 'download' => '下載', 'open_in_tab' => '在新分頁中開啟', - 'open' => 'Open', + 'open' => '開啟', // Sort Options 'sort_options' => '排序選項', diff --git a/lang/zh_TW/components.php b/lang/zh_TW/components.php index 36f2265d133..682a8ed4d8c 100644 --- a/lang/zh_TW/components.php +++ b/lang/zh_TW/components.php @@ -6,10 +6,10 @@ // 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_list' => '圖片列表', + 'image_details' => '圖片詳細資訊', + 'image_upload' => '上傳圖片', + 'image_intro' => '您可以在這裡選取和管理上傳到系統的圖片。', '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' => '全部', 'image_all_title' => '檢視所有圖片', @@ -26,14 +26,14 @@ '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_replace' => '替換圖片', + 'image_replace_success' => '圖片更新成功', 'image_rebuild_thumbs' => 'Regenerate Size Variations', 'image_rebuild_thumbs_success' => 'Image size variations successfully rebuilt!', diff --git a/lang/zh_TW/settings.php b/lang/zh_TW/settings.php index ee05b202467..c3c86177026 100644 --- a/lang/zh_TW/settings.php +++ b/lang/zh_TW/settings.php @@ -32,7 +32,7 @@ '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_logo_desc' => '這個設定會被使用在應用程式標題欄等區域;圖片的高度應為 86 像素,大型圖片將會按比例縮小。', 'app_icon' => '應用程式圖示', 'app_icon_desc' => 'This icon is used for browser tabs and shortcut icons. This should be a 256px square PNG image.', 'app_homepage' => '應用程式首頁', @@ -53,7 +53,7 @@ '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' => '主要顏色', '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.', + 'content_colors_desc' => '設定頁面層次結構中的元素顏色;為了提高可讀性,建議選擇亮度與預設顏色相似的顏色。', 'bookshelf_color' => '書架顔色', 'book_color' => '書本顔色', 'chapter_color' => '章節顔色', @@ -269,7 +269,7 @@ 'webhooks_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' => 'Webhook 格式範例', '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 狀態', 'webhooks_last_called' => 'Last Called:', From 496b4264d9df114a0bc4bde8fba2ff4bd9d4c266 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Tue, 16 Jan 2024 12:14:25 +0000 Subject: [PATCH 010/969] Updated translator attribution --- .github/translators.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/translators.txt b/.github/translators.txt index a27717f9421..ef16da25722 100644 --- a/.github/translators.txt +++ b/.github/translators.txt @@ -324,7 +324,7 @@ Robin Flikkema (RobinFlikkema) :: Dutch Michal Gurcik (mgurcik) :: Slovak Pooyan Arab (pooyanarab) :: Persian Ochi Darma Putra (troke12) :: Indonesian -H.-H. Peng (Hsins) :: Chinese Traditional +Hsin-Hsiang Peng (Hsins) :: Chinese Traditional Mosi Wang (mosiwang) :: Chinese Traditional 骆言 (LawssssCat) :: Chinese Simplified Stickers Gaming Shøw (StickerSGSHOW) :: French @@ -386,3 +386,5 @@ Y (cnsr) :: Ukrainian ZY ZV (vy0b0x) :: Chinese Simplified diegobenitez :: Spanish Marc Hagen (MarcHagen) :: Dutch +Kasper Alsøe (zeonos) :: Danish +sultani :: Persian From 655ae5ecaeba3eaea73bd20c970387f1fa993e6a Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Tue, 23 Jan 2024 12:31:44 +0000 Subject: [PATCH 011/969] Text: Tweaks to EN text for consistency/readability As suggested by Tim in discord chat. --- lang/en/activities.php | 6 +++--- lang/en/settings.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lang/en/activities.php b/lang/en/activities.php index d5b55c03dcb..092398ef0e1 100644 --- a/lang/en/activities.php +++ b/lang/en/activities.php @@ -93,11 +93,11 @@ 'user_delete_notification' => 'User successfully removed', // API Tokens - 'api_token_create' => 'created api token', + 'api_token_create' => 'created API token', 'api_token_create_notification' => 'API token successfully created', - 'api_token_update' => 'updated api token', + 'api_token_update' => 'updated API token', 'api_token_update_notification' => 'API token successfully updated', - 'api_token_delete' => 'deleted api token', + 'api_token_delete' => 'deleted API token', 'api_token_delete_notification' => 'API token successfully deleted', // Roles diff --git a/lang/en/settings.php b/lang/en/settings.php index 03e9bf462e2..7b7f5d2a2e3 100644 --- a/lang/en/settings.php +++ b/lang/en/settings.php @@ -109,7 +109,7 @@ '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_confirm' => 'This action will permanently delete this item from the system, along with any child elements listed below, and you will not be able to restore this content. Are you sure you want to permanently delete this item?', 'recycle_bin_destroy_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.', From 788327fffb044a03ccc490be0bcddd48e3551b01 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Tue, 23 Jan 2024 15:01:07 +0000 Subject: [PATCH 012/969] Attachment List: Fixed broken ctrl-click functionality Fixes #4782 --- resources/js/components/attachments-list.js | 8 ++++---- resources/views/attachments/list.blade.php | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/resources/js/components/attachments-list.js b/resources/js/components/attachments-list.js index 4db09977fec..665904f8616 100644 --- a/resources/js/components/attachments-list.js +++ b/resources/js/components/attachments-list.js @@ -9,6 +9,8 @@ export class AttachmentsList extends Component { setup() { this.container = this.$el; + this.fileLinks = this.$manyRefs.linkTypeFile; + this.setupListeners(); } @@ -27,8 +29,7 @@ export class AttachmentsList extends Component { } addOpenQueryToLinks() { - const links = this.container.querySelectorAll('a.attachment-file'); - for (const link of links) { + for (const link of this.fileLinks) { if (link.href.split('?')[1] !== 'open=true') { link.href += '?open=true'; link.setAttribute('target', '_blank'); @@ -37,8 +38,7 @@ export class AttachmentsList extends Component { } removeOpenQueryFromLinks() { - const links = this.container.querySelectorAll('a.attachment-file'); - for (const link of links) { + for (const link of this.fileLinks) { link.href = link.href.split('?')[0]; link.removeAttribute('target'); } diff --git a/resources/views/attachments/list.blade.php b/resources/views/attachments/list.blade.php index a6ffb709b4d..71197cc19c0 100644 --- a/resources/views/attachments/list.blade.php +++ b/resources/views/attachments/list.blade.php @@ -2,7 +2,9 @@ @foreach($attachments as $attachment)

- external) target="_blank" @endif> + external) target="_blank" @endif>
@icon($attachment->external ? 'export' : 'file')
{{ $attachment->name }}
From 69c8ff5c2d491d8674e2671a912a025cf16f86d3 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Tue, 23 Jan 2024 15:39:09 +0000 Subject: [PATCH 013/969] Entity selector: Fixed initial load overwriting initial search This changes how initial searches can be handled via config rather than specific action so they can be considered in how the initial data load is done, to prevent the default empty state loading and overwriting the search data if it lands later (which was commonly likely). For #4778 --- resources/js/components/entity-selector-popup.js | 7 +------ resources/js/components/entity-selector.js | 13 ++++++++----- resources/js/components/page-picker.js | 3 ++- resources/js/markdown/actions.js | 3 ++- resources/js/wysiwyg/config.js | 3 ++- resources/js/wysiwyg/shortcuts.js | 3 ++- 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/resources/js/components/entity-selector-popup.js b/resources/js/components/entity-selector-popup.js index 6fb46196885..29c06e90951 100644 --- a/resources/js/components/entity-selector-popup.js +++ b/resources/js/components/entity-selector-popup.js @@ -18,18 +18,13 @@ export class EntitySelectorPopup extends Component { /** * Show the selector popup. * @param {Function} callback - * @param {String} searchText * @param {EntitySelectorSearchOptions} searchOptions */ - show(callback, searchText = '', searchOptions = {}) { + show(callback, searchOptions = {}) { this.callback = callback; this.getSelector().configureSearchOptions(searchOptions); this.getPopup().show(); - if (searchText) { - this.getSelector().searchText(searchText); - } - this.getSelector().focusSearch(); } diff --git a/resources/js/components/entity-selector.js b/resources/js/components/entity-selector.js index 5ad9914378e..561370d7a34 100644 --- a/resources/js/components/entity-selector.js +++ b/resources/js/components/entity-selector.js @@ -6,6 +6,7 @@ import {Component} from './component'; * @property entityTypes string * @property entityPermission string * @property searchEndpoint string + * @property initialValue string */ /** @@ -25,6 +26,7 @@ export class EntitySelector extends Component { entityTypes: this.$opts.entityTypes || 'page,book,chapter', entityPermission: this.$opts.entityPermission || 'view', searchEndpoint: this.$opts.searchEndpoint || '', + initialValue: this.searchInput.value || '', }; this.search = ''; @@ -44,6 +46,7 @@ export class EntitySelector extends Component { configureSearchOptions(options) { Object.assign(this.searchOptions, options); this.reset(); + this.searchInput.value = this.searchOptions.initialValue; } setupListeners() { @@ -108,11 +111,6 @@ export class EntitySelector extends Component { this.searchInput.focus(); } - searchText(queryText) { - this.searchInput.value = queryText; - this.searchEntities(queryText); - } - showLoading() { this.loading.style.display = 'block'; this.resultsContainer.style.display = 'none'; @@ -128,6 +126,11 @@ export class EntitySelector extends Component { throw new Error('Search endpoint not set for entity-selector load'); } + if (this.searchOptions.initialValue) { + this.searchEntities(this.searchOptions.initialValue); + return; + } + window.$http.get(this.searchUrl()).then(resp => { this.resultsContainer.innerHTML = resp.data; this.hideLoading(); diff --git a/resources/js/components/page-picker.js b/resources/js/components/page-picker.js index 39af6722993..5ab51159570 100644 --- a/resources/js/components/page-picker.js +++ b/resources/js/components/page-picker.js @@ -35,7 +35,8 @@ export class PagePicker extends Component { const selectorPopup = window.$components.first('entity-selector-popup'); selectorPopup.show(entity => { this.setValue(entity.id, entity.name); - }, '', { + }, { + initialValue: '', searchEndpoint: this.selectorEndpoint, entityTypes: 'page', entityPermission: 'view', diff --git a/resources/js/markdown/actions.js b/resources/js/markdown/actions.js index 511f1ebdae6..73040a57b1e 100644 --- a/resources/js/markdown/actions.js +++ b/resources/js/markdown/actions.js @@ -73,7 +73,8 @@ export class Actions { const selectedText = selectionText || entity.name; const newText = `[${selectedText}](${entity.link})`; this.#replaceSelection(newText, newText.length, selectionRange); - }, selectionText, { + }, { + initialValue: selectionText, searchEndpoint: '/search/entity-selector', entityTypes: 'page,book,chapter,bookshelf', entityPermission: 'view', diff --git a/resources/js/wysiwyg/config.js b/resources/js/wysiwyg/config.js index 963e2970d34..6c96e47e9c3 100644 --- a/resources/js/wysiwyg/config.js +++ b/resources/js/wysiwyg/config.js @@ -85,7 +85,8 @@ function filePickerCallback(callback, value, meta) { text: entity.name, title: entity.name, }); - }, selectionText, { + }, { + initialValue: selectionText, searchEndpoint: '/search/entity-selector', entityTypes: 'page,book,chapter,bookshelf', entityPermission: 'view', diff --git a/resources/js/wysiwyg/shortcuts.js b/resources/js/wysiwyg/shortcuts.js index da9e0227099..dbc725b1dcd 100644 --- a/resources/js/wysiwyg/shortcuts.js +++ b/resources/js/wysiwyg/shortcuts.js @@ -58,7 +58,8 @@ export function register(editor) { editor.selection.collapse(false); editor.focus(); - }, selectionText, { + }, { + initialValue: selectionText, searchEndpoint: '/search/entity-selector', entityTypes: 'page,book,chapter,bookshelf', entityPermission: 'view', From 8c6b1164724fffd1766792fb3d6fef4972ba1b9e Mon Sep 17 00:00:00 2001 From: Sascha Date: Tue, 23 Jan 2024 21:37:00 +0100 Subject: [PATCH 014/969] Update TrashCan.php remove duplicate call of $page->forceDelete(); --- app/Entities/Tools/TrashCan.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/Entities/Tools/TrashCan.php b/app/Entities/Tools/TrashCan.php index e5bcfe71ac2..8e9f010df0f 100644 --- a/app/Entities/Tools/TrashCan.php +++ b/app/Entities/Tools/TrashCan.php @@ -206,8 +206,6 @@ protected function destroyPage(Page $page): int Book::query()->where('default_template_id', '=', $page->id) ->update(['default_template_id' => null]); - $page->forceDelete(); - // Remove chapter template usages Chapter::query()->where('default_template_id', '=', $page->id) ->update(['default_template_id' => null]); From 0fc02a2532fd33c443838de77f5700df220b79c9 Mon Sep 17 00:00:00 2001 From: Sascha Date: Tue, 23 Jan 2024 22:37:15 +0100 Subject: [PATCH 015/969] fixed error from phpcs --- app/Entities/Controllers/PageController.php | 4 ++-- app/Entities/Repos/PageRepo.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Entities/Controllers/PageController.php b/app/Entities/Controllers/PageController.php index 74dd4f531b4..eaad3c0b79d 100644 --- a/app/Entities/Controllers/PageController.php +++ b/app/Entities/Controllers/PageController.php @@ -260,7 +260,7 @@ public function showDelete(string $bookSlug, string $pageSlug) $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); $this->checkOwnablePermission('page-delete', $page); $this->setPageTitle(trans('entities.pages_delete_named', ['pageName' => $page->getShortName()])); - $usedAsTemplate = + $usedAsTemplate = Book::query()->where('default_template_id', '=', $page->id)->count() > 0 || Chapter::query()->where('default_template_id', '=', $page->id)->count() > 0; @@ -282,7 +282,7 @@ public function showDeleteDraft(string $bookSlug, int $pageId) $page = $this->pageRepo->getById($pageId); $this->checkOwnablePermission('page-update', $page); $this->setPageTitle(trans('entities.pages_delete_draft_named', ['pageName' => $page->getShortName()])); - $usedAsTemplate = + $usedAsTemplate = Book::query()->where('default_template_id', '=', $page->id)->count() > 0 || Chapter::query()->where('default_template_id', '=', $page->id)->count() > 0; diff --git a/app/Entities/Repos/PageRepo.php b/app/Entities/Repos/PageRepo.php index 67c4b222547..d9bda019892 100644 --- a/app/Entities/Repos/PageRepo.php +++ b/app/Entities/Repos/PageRepo.php @@ -142,7 +142,7 @@ public function getNewDraftPage(Entity $parent) } else { $defaultTemplate = $page->book->defaultTemplate; } - + if ($defaultTemplate && userCan('view', $defaultTemplate)) { $page->forceFill([ 'html' => $defaultTemplate->html, From 14ecb19b054e6b915f8f37104793fb98cd962b13 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Wed, 24 Jan 2024 10:22:13 +0000 Subject: [PATCH 016/969] Merged l10n_development into v23-12 Squash merge Closes #4779 --- lang/cy/activities.php | 62 ++++++------ lang/cy/auth.php | 22 ++--- lang/cy/common.php | 98 +++++++++--------- lang/cy/components.php | 16 +-- lang/cy/editor.php | 76 +++++++------- lang/cy/notifications.php | 20 ++-- lang/cy/pagination.php | 4 +- lang/fr/entities.php | 12 +-- lang/fr/notifications.php | 2 +- lang/he/common.php | 4 +- lang/he/notifications.php | 34 +++---- lang/ko/activities.php | 102 +++++++++---------- lang/ko/auth.php | 2 +- lang/ko/common.php | 8 +- lang/ko/components.php | 18 ++-- lang/ko/editor.php | 6 +- lang/ko/entities.php | 202 +++++++++++++++++++------------------- lang/ko/errors.php | 100 +++++++++---------- lang/ko/notifications.php | 34 +++---- lang/ko/preferences.php | 58 +++++------ lang/ko/settings.php | 62 ++++++------ lang/ko/validation.php | 2 +- lang/lv/activities.php | 52 +++++----- lang/lv/components.php | 18 ++-- lang/lv/entities.php | 24 ++--- lang/lv/errors.php | 10 +- lang/lv/preferences.php | 42 ++++---- lang/lv/settings.php | 16 +-- lang/nl/activities.php | 78 +++++++-------- lang/nl/auth.php | 14 +-- lang/nl/entities.php | 122 +++++++++++------------ lang/nl/errors.php | 6 +- lang/nl/settings.php | 14 +-- lang/sq/activities.php | 170 ++++++++++++++++---------------- lang/sq/auth.php | 48 ++++----- 35 files changed, 779 insertions(+), 779 deletions(-) diff --git a/lang/cy/activities.php b/lang/cy/activities.php index 2c474c673ba..b3301d757b8 100644 --- a/lang/cy/activities.php +++ b/lang/cy/activities.php @@ -6,26 +6,26 @@ return [ // Pages - 'page_create' => 'tudalen wedi\'i chreu', + 'page_create' => 'creodd dudalen', 'page_create_notification' => 'Tudalen wedi\'i chreu\'n llwyddiannus', - 'page_update' => 'tudalen wedi\'i diweddaru', + 'page_update' => 'diweddarodd dudalen', 'page_update_notification' => 'Tudalen wedi\'i diweddaru\'n llwyddiannus', - 'page_delete' => 'tudalen wedi\'i dileu', - 'page_delete_notification' => 'Cafodd y dudalen ei dileu yn llwyddiannus', - 'page_restore' => 'tudalen wedi\'i hadfer', - 'page_restore_notification' => 'Cafodd y dudalen ei hadfer yn llwyddiannus', - 'page_move' => 'symwyd tudalen', - 'page_move_notification' => 'Page successfully moved', + 'page_delete' => 'dileodd dudalen', + 'page_delete_notification' => 'Tudalen wedi\'i dileu\'n llwyddiannus', + 'page_restore' => 'adferodd dudalen', + 'page_restore_notification' => 'Tudalen wedi\'i hadfer yn llwyddiannus', + 'page_move' => 'symydodd dudalen', + 'page_move_notification' => 'Tudalen wedi\'i symud yn llwyddianus', // Chapters - 'chapter_create' => 'pennod creu', + 'chapter_create' => 'creodd bennod', 'chapter_create_notification' => 'Pennod wedi\'i chreu\'n llwyddiannus', 'chapter_update' => 'pennod wedi diweddaru', 'chapter_update_notification' => 'Pennod wedi\'i diweddaru\'n llwyddiannus', 'chapter_delete' => 'pennod wedi dileu', 'chapter_delete_notification' => 'Pennod wedi\'i dileu\'n llwyddiannus', 'chapter_move' => 'pennod wedi symud', - 'chapter_move_notification' => 'Chapter successfully moved', + 'chapter_move_notification' => 'Pennod wedi\'i symud yn llwyddianus', // Books 'book_create' => 'llyfr wedi creu', @@ -40,14 +40,14 @@ 'book_sort_notification' => 'Ail-archebwyd y llyfr yn llwyddiannus', // Bookshelves - 'bookshelf_create' => 'created shelf', - 'bookshelf_create_notification' => 'Shelf successfully created', + 'bookshelf_create' => 'creodd silff', + 'bookshelf_create_notification' => 'Silff wedi\'i chreu\'n llwyddiannus', '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_update' => 'diweddarodd silff', + 'bookshelf_update_notification' => 'Silff wedi\'i diweddaru\'n llwyddiannus', + 'bookshelf_delete' => 'dileodd silff', + 'bookshelf_delete_notification' => 'Silff wedi\'i dileu\'n llwyddiannus', // Revisions 'revision_restore' => 'restored revision', @@ -62,7 +62,7 @@ 'watch_update_level_notification' => 'Watch preferences successfully updated', // Auth - 'auth_login' => 'logged in', + 'auth_login' => 'wedi\'u mewngofnodi', 'auth_register' => 'registered as new user', 'auth_password_reset_request' => 'requested user password reset', 'auth_password_reset_update' => 'reset user password', @@ -85,20 +85,20 @@ 'webhook_delete_notification' => 'Webhook wedi\'i dileu\'n llwyddiannus', // Users - 'user_create' => 'created user', - 'user_create_notification' => 'User successfully created', - 'user_update' => 'updated user', + 'user_create' => 'creodd ddefnyddiwr', + 'user_create_notification' => 'Defnyddiwr wedi\'i greu\'n llwyddiannus', + 'user_update' => 'diweddarodd ddefnyddiwr', 'user_update_notification' => 'Diweddarwyd y defnyddiwr yn llwyddiannus', - 'user_delete' => 'deleted user', + 'user_delete' => 'dileodd ddefnyddiwr', 'user_delete_notification' => 'Tynnwyd y defnyddiwr yn llwyddiannus', // 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' => 'creodd tocyn api', + 'api_token_create_notification' => 'Tocyn API wedi\'i greu\'n llwyddiannus', + 'api_token_update' => 'diweddarodd docyn api', + 'api_token_update_notification' => 'Tocyn API wedi\'i ddiweddaru\'n llwyddiannus', + 'api_token_delete' => 'dileodd docyn api', + 'api_token_delete_notification' => 'Tocyn API wedi\'i ddileu\'n llwyddiannus', // Roles 'role_create' => 'created role', @@ -109,15 +109,15 @@ 'role_delete_notification' => 'Role successfully deleted', // Recycle Bin - 'recycle_bin_empty' => 'emptied recycle bin', + 'recycle_bin_empty' => 'gwagodd fin ailgylchu', 'recycle_bin_restore' => 'restored from recycle bin', 'recycle_bin_destroy' => 'removed from recycle bin', // Comments 'commented_on' => 'gwnaeth sylwadau ar', - 'comment_create' => 'added comment', - 'comment_update' => 'updated comment', - 'comment_delete' => 'deleted comment', + 'comment_create' => 'ychwanegodd sylw', + 'comment_update' => 'diweddarodd sylw', + 'comment_delete' => 'dileodd sylw', // Other 'permissions_update' => 'caniatadau wedi\'u diweddaru', diff --git a/lang/cy/auth.php b/lang/cy/auth.php index 6be96308076..94fc0b6b54b 100644 --- a/lang/cy/auth.php +++ b/lang/cy/auth.php @@ -54,30 +54,30 @@ 'email_reset_not_requested' => 'If you did not request a password reset, no further action is required.', // 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_subject' => 'Cadarnhewch eich e-bost chi a :appName', + 'email_confirm_greeting' => 'Diolch am ymuno â :appName!', + 'email_confirm_text' => 'Os gwelwch yn dda cadarnhewch eich e-bost chi gan clicio ar y botwm isod:', + 'email_confirm_action' => 'Cadarnhau E-bost', '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' => 'Diolch am gadarnhau!', '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_not_confirmed' => 'Email Address Not Confirmed', - 'email_not_confirmed_text' => 'Your email address has not yet been confirmed.', + 'email_not_confirmed' => 'Cyfeiriad E-bost heb ei Gadarnhau', + 'email_not_confirmed_text' => 'Dyw eich cyfeiriad e-bost chi ddim wedi cael ei gadarnhau eto.', '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', // 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_greeting' => 'Mae cyfrif wedi cae ei greu i chi ar :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_welcome' => 'Croeso i :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_page_confirm_button' => 'Cadarnhau cyfrinair', 'user_invite_success_login' => 'Password set, you should now be able to login using your set password to access :appName!', // Multi-factor Authentication @@ -88,7 +88,7 @@ '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_title' => 'Ap Ffôn Symudol', '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.', diff --git a/lang/cy/common.php b/lang/cy/common.php index 27037babec0..e359e8ba361 100644 --- a/lang/cy/common.php +++ b/lang/cy/common.php @@ -5,61 +5,61 @@ return [ // Buttons - 'cancel' => 'Cancel', - 'close' => 'Close', - 'confirm' => 'Confirm', - 'back' => 'Back', - 'save' => 'Save', - 'continue' => 'Continue', - 'select' => 'Select', + 'cancel' => 'Canslo', + 'close' => 'Cau', + 'confirm' => 'Cadarnhau', + 'back' => 'Yn ôl', + 'save' => 'Cadw', + 'continue' => 'Parhau', + 'select' => 'Dewis', 'toggle_all' => 'Toggle All', - 'more' => 'More', + 'more' => 'Mwy', // Form Labels - 'name' => 'Name', - 'description' => 'Description', + 'name' => 'Enw', + 'description' => 'Disgrifiad', 'role' => 'Role', 'cover_image' => 'Cover image', 'cover_image_description' => 'This image should be approx 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', + 'actions' => 'Gweithredoedd', + 'view' => 'Gweld', + 'view_all' => 'Gweld popeth', + 'new' => 'Newydd', + 'create' => 'Creu', + 'update' => 'Diweddaru', + 'edit' => 'Golygu', + 'sort' => 'Trefnu', + 'move' => 'Symud', + 'copy' => 'Copïo', + 'reply' => 'Ateb', + 'delete' => 'Dileu', + 'delete_confirm' => 'Cadarnhau\'r dilead', + 'search' => 'Chwilio', + 'search_clear' => 'Clirio\'r chwiliad', + 'reset' => 'Ailosod', + 'remove' => 'Diddymu', + 'add' => 'Ychwanegu', + 'configure' => 'Ffurfweddu', + 'manage' => 'Rheoli', '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', + 'next' => 'Nesa', + 'previous' => 'Cynt', + 'filter_active' => 'Hidl weithredol:', + 'filter_clear' => 'Clirio\'r hidl', + 'download' => 'Llwytho i lawr', + 'open_in_tab' => 'Agor mewn Tab', + 'open' => 'Agor', // Sort Options - 'sort_options' => 'Sort Options', + 'sort_options' => 'Trefnu\'r opsiynau', 'sort_direction_toggle' => 'Sort Direction Toggle', - 'sort_ascending' => 'Sort Ascending', - 'sort_descending' => 'Sort Descending', - 'sort_name' => 'Name', + 'sort_ascending' => 'Trefnu\'n esgynnol', + 'sort_descending' => 'Trefnu\'n ddisgynnol', + 'sort_name' => 'Enw', 'sort_default' => 'Default', 'sort_created_at' => 'Created Date', 'sort_updated_at' => 'Updated Date', @@ -67,8 +67,8 @@ // Misc 'deleted_user' => 'Deleted User', 'no_activity' => 'No activity to show', - 'no_items' => 'No items available', - 'back_to_top' => 'Back to top', + 'no_items' => 'Dim eitemau ar gael', + 'back_to_top' => 'Yn ôl i\'r brig', 'skip_to_main_content' => 'Skip to main content', 'toggle_details' => 'Toggle Details', 'toggle_thumbnails' => 'Toggle Thumbnails', @@ -78,10 +78,10 @@ 'default' => 'Default', 'breadcrumb' => 'Breadcrumb', 'status' => 'Status', - 'status_active' => 'Active', - 'status_inactive' => 'Inactive', - 'never' => 'Never', - 'none' => 'None', + 'status_active' => 'Gweithredol', + 'status_inactive' => 'Anweithredol', + 'never' => 'Byth', + 'none' => 'Dim un', // Header 'homepage' => 'Homepage', @@ -94,9 +94,9 @@ 'global_search' => 'Global Search', // Layout tabs - 'tab_info' => 'Info', + 'tab_info' => 'Gwybodaeth', 'tab_info_label' => 'Tab: Show Secondary Information', - 'tab_content' => 'Content', + 'tab_content' => 'Cynnwys', 'tab_content_label' => 'Tab: Show Primary Content', // Email Content diff --git a/lang/cy/components.php b/lang/cy/components.php index c33b1d0b791..9286c456346 100644 --- a/lang/cy/components.php +++ b/lang/cy/components.php @@ -6,28 +6,28 @@ // Image Manager 'image_select' => 'Image Select', - 'image_list' => 'Image List', - 'image_details' => 'Image Details', + 'image_list' => 'Rhestr o Ddelweddau', + 'image_details' => 'Manylion Delwedd', '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_all' => 'Popeth', + 'image_all_title' => 'Gweld holl ddelweddau', '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_search_hint' => 'Cwilio gan enw delwedd', '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_image_name' => 'Enw Delwedd', '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_delete_confirm_text' => 'Wyt ti\'n bendant eisiau dileu\'r ddelwedd hwn?', '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', + 'images_deleted' => 'Delweddau wedi\'u Dileu', 'image_preview' => 'Image Preview', 'image_upload_success' => 'Image uploaded successfully', 'image_update_success' => 'Image details successfully updated', diff --git a/lang/cy/editor.php b/lang/cy/editor.php index 670c1c5e1ac..5ad569a8ed4 100644 --- a/lang/cy/editor.php +++ b/lang/cy/editor.php @@ -9,47 +9,47 @@ // 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...', + 'none' => 'Dim un', + 'cancel' => 'Canslo', + 'save' => 'Cadw', + 'close' => 'Cau', + 'undo' => 'Dadwneud', + 'redo' => 'Ail-wneud', + 'left' => 'Chwith', + 'center' => 'Canol', + 'right' => 'Dde', + 'top' => 'Pen', + 'middle' => 'Canol', + 'bottom' => 'Gwaelod', + 'width' => 'Lled', + 'height' => 'Uchder', + 'More' => 'Mwy', + 'select' => 'Dewis...', // Toolbar - 'formats' => 'Formats', - 'header_large' => 'Large Header', - 'header_medium' => 'Medium Header', - 'header_small' => 'Small Header', - 'header_tiny' => 'Tiny Header', - 'paragraph' => 'Paragraph', + 'formats' => 'Fformatau', + 'header_large' => 'Pennyn Mawr', + 'header_medium' => 'Pennyn Canolig', + 'header_small' => 'Pennyn Bach', + 'header_tiny' => 'Pennyn Mân', + 'paragraph' => 'Paragraff', 'blockquote' => 'Blockquote', 'inline_code' => 'Inline code', 'callouts' => 'Callouts', - 'callout_information' => 'Information', - 'callout_success' => 'Success', - 'callout_warning' => 'Warning', - 'callout_danger' => 'Danger', - 'bold' => 'Bold', - 'italic' => 'Italic', + 'callout_information' => 'Gwybodaeth', + 'callout_success' => 'Llwyddiant', + 'callout_warning' => 'Rhybudd', + 'callout_danger' => 'Perygl', + 'bold' => 'Trwm', + 'italic' => 'Italig', 'underline' => 'Underline', 'strikethrough' => 'Strikethrough', 'superscript' => 'Superscript', 'subscript' => 'Subscript', - 'text_color' => 'Text color', - 'custom_color' => 'Custom color', + 'text_color' => 'Lliw testun', + 'custom_color' => 'Lliw addasu', 'remove_color' => 'Remove color', - 'background_color' => 'Background color', + 'background_color' => 'Lliw cefnder', 'align_left' => 'Align left', 'align_center' => 'Align center', 'align_right' => 'Align right', @@ -112,18 +112,18 @@ 'paste_row_before' => 'Paste row before', 'paste_row_after' => 'Paste row after', 'row_type' => 'Row type', - 'row_type_header' => 'Header', + 'row_type_header' => 'Pennyn', 'row_type_body' => 'Body', - 'row_type_footer' => 'Footer', - 'alignment' => 'Alignment', + 'row_type_footer' => 'Troedyn', + 'alignment' => 'Aliniad', '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', + 'caption' => 'Pennawd', + 'show_caption' => 'Dangos pennawd', 'constrain' => 'Constrain proportions', 'cell_border_solid' => 'Solid', 'cell_border_dotted' => 'Dotted', @@ -143,7 +143,7 @@ 'paste_embed' => 'Paste your embed code below:', 'url' => 'URL', 'text_to_display' => 'Text to display', - 'title' => 'Title', + 'title' => 'Teitl', 'open_link' => 'Open link', 'open_link_in' => 'Open link in...', 'open_link_current' => 'Current window', @@ -170,5 +170,5 @@ 'shortcuts_intro' => 'The following shortcuts are available in the editor:', 'windows_linux' => '(Windows/Linux)', 'mac' => '(Mac)', - 'description' => 'Description', + 'description' => 'Disgrifiad', ]; diff --git a/lang/cy/notifications.php b/lang/cy/notifications.php index 1afd23f1dc4..b9f58ac2576 100644 --- a/lang/cy/notifications.php +++ b/lang/cy/notifications.php @@ -4,23 +4,23 @@ */ 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:', + 'new_comment_subject' => 'Sylw newydd ar dudalen :pageName', + 'new_comment_intro' => 'Mae defnyddiwr wedi sylw ar dudalen yn :appName:', + 'new_page_subject' => 'Tudalen newydd :pageName', + 'new_page_intro' => 'Mae tudalen newydd wedi cael ei chreu yn :appName:', + 'updated_page_subject' => 'Tudalen wedi\'i diweddaru :pageName', + 'updated_page_intro' => 'Mae tudalen newydd wedi cael ei diweddaru yn :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.', - 'detail_page_name' => 'Page Name:', + 'detail_page_name' => 'Enw\'r dudalen:', 'detail_page_path' => 'Page Path:', 'detail_commenter' => 'Commenter:', - 'detail_comment' => 'Comment:', + 'detail_comment' => 'Sylw:', 'detail_created_by' => 'Created By:', 'detail_updated_by' => 'Updated By:', - 'action_view_comment' => 'View Comment', - 'action_view_page' => 'View Page', + 'action_view_comment' => 'Gweld y sylw', + 'action_view_page' => 'Gweld y dudalen', 'footer_reason' => 'This notification was sent to you because :link cover this type of activity for this item.', 'footer_reason_link' => 'your notification preferences', diff --git a/lang/cy/pagination.php b/lang/cy/pagination.php index 85bd12fc319..9cd781925e9 100644 --- a/lang/cy/pagination.php +++ b/lang/cy/pagination.php @@ -6,7 +6,7 @@ */ return [ - 'previous' => '« Previous', - 'next' => 'Next »', + 'previous' => '« Cynt', + 'next' => 'Nesa »', ]; diff --git a/lang/fr/entities.php b/lang/fr/entities.php index e890c278762..32351548b0c 100644 --- a/lang/fr/entities.php +++ b/lang/fr/entities.php @@ -23,7 +23,7 @@ 'meta_updated' => 'Mis à jour :timeLength', 'meta_updated_name' => 'Mis à jour :timeLength par :user', 'meta_owned_name' => 'Appartient à :user', - 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', + 'meta_reference_count' => 'Référencé sur :count élément|Référencé sur :count éléments', '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,9 +132,9 @@ '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_default_template' => 'Modèle de page par défaut', + 'books_default_template_explain' => 'Sélectionnez un modèle de page qui sera utilisé comme contenu par défaut pour les nouvelles pages créées dans ce livre. Gardez à l\'esprit que le modèle ne sera utilisé que si le créateur de la page a accès au modèle sélectionné.', + 'books_default_template_select' => 'Sélectionnez un modèle de 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.', @@ -207,7 +207,7 @@ '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_warning_template' => 'Cette page est utilisée comme modèle de page par défaut dans un livre. Ces livres n\'utiliseront plus ce modèle après la suppression de cette page.', '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', @@ -409,7 +409,7 @@ // References 'references' => 'Références', 'references_none' => 'Il n\'y a pas de références suivies à cet élément.', - 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', + 'references_to_desc' => 'Vous trouverez ci-dessous le contenu connu du système qui a un lien vers cet élément.', // Watch Options 'watch' => 'Suivre', diff --git a/lang/fr/notifications.php b/lang/fr/notifications.php index eb97ddfda31..5d7ae88f72b 100644 --- a/lang/fr/notifications.php +++ b/lang/fr/notifications.php @@ -13,7 +13,7 @@ '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_page_path' => 'Chemin de la page :', 'detail_commenter' => 'Commenta·teur·trice :', 'detail_comment' => 'Commentaire :', 'detail_created_by' => 'Créé par :', diff --git a/lang/he/common.php b/lang/he/common.php index 75dbd44936d..dafafe6ed18 100644 --- a/lang/he/common.php +++ b/lang/he/common.php @@ -6,7 +6,7 @@ // Buttons 'cancel' => 'ביטול', - 'close' => 'Close', + 'close' => 'סגור', 'confirm' => 'אישור', 'back' => 'אחורה', 'save' => 'שמור', @@ -42,7 +42,7 @@ 'remove' => 'הסר', 'add' => 'הוסף', 'configure' => 'הגדרות', - 'manage' => 'Manage', + 'manage' => 'נהל', 'fullscreen' => 'מסך מלא', 'favourite' => 'מועדף', 'unfavourite' => 'בטל מועדף', diff --git a/lang/he/notifications.php b/lang/he/notifications.php index 1afd23f1dc4..8385c0a6da3 100644 --- a/lang/he/notifications.php +++ b/lang/he/notifications.php @@ -4,24 +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_page_path' => 'Page Path:', - '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/ko/activities.php b/lang/ko/activities.php index f9002431bc2..4cb03f90cc9 100644 --- a/lang/ko/activities.php +++ b/lang/ko/activities.php @@ -6,75 +6,75 @@ return [ // Pages - 'page_create' => '문서 만들기', - 'page_create_notification' => '페이지를 생성했습니다', - 'page_update' => '문서 수정', - 'page_update_notification' => '페이지를 수정했습니다', - 'page_delete' => '삭제 된 페이지', - 'page_delete_notification' => '페이지를 삭제했습니다', - 'page_restore' => '문서 복원', - 'page_restore_notification' => '페이지가 복원되었습니다', - 'page_move' => '문서 이동', - 'page_move_notification' => 'Page successfully moved', + 'page_create' => '생성된 페이지', + 'page_create_notification' => '페이지가 성공적으로 생성되었습니다.', + 'page_update' => '페이지 업데이트됨', + 'page_update_notification' => '페이지가 성공적으로 업데이트되었습니다.', + 'page_delete' => '삭제된 페이지', + 'page_delete_notification' => '페이지가 성공적으로 삭제되었습니다.', + 'page_restore' => '복구된 페이지', + 'page_restore_notification' => '페이지가 성공적으로 복원되었습니다.', + 'page_move' => '이동된 페이지', + 'page_move_notification' => '페이지가 성공적으로 이동되었습니다.', // Chapters 'chapter_create' => '챕터 만들기', - 'chapter_create_notification' => '챕터 생성함', - 'chapter_update' => '챕터 수정', - 'chapter_update_notification' => '챕터 수정함', + 'chapter_create_notification' => '챕터가 성공적으로 생성되었습니다.', + 'chapter_update' => '업데이트된 챕터', + 'chapter_update_notification' => '챕터가 성공적으로 업데이트되었습니다.', 'chapter_delete' => '삭제된 챕터', - 'chapter_delete_notification' => '챕터 삭제함', - 'chapter_move' => '챕터 이동된', - 'chapter_move_notification' => 'Chapter successfully moved', + 'chapter_delete_notification' => '챕터가 성공적으로 삭제되었습니다.', + 'chapter_move' => '이동된 챕터', + 'chapter_move_notification' => '챕터를 성공적으로 이동했습니다.', // Books - 'book_create' => '책자 만들기', - 'book_create_notification' => '책 생성함', + 'book_create' => '생성된 책', + 'book_create_notification' => '책이 성공적으로 생성되었습니다.', 'book_create_from_chapter' => '챕터를 책으로 변환', - 'book_create_from_chapter_notification' => '챕터를 책으로 변환했습니다.', - 'book_update' => '책 수정', - 'book_update_notification' => '책 수정함', - 'book_delete' => '책 지우기', - 'book_delete_notification' => '책 삭제함', - 'book_sort' => '책자 정렬', - 'book_sort_notification' => '책 정렬 바꿈', + 'book_create_from_chapter_notification' => '챕터가 책으로 성공적으로 변환되었습니다.', + 'book_update' => '업데이트된 책', + 'book_update_notification' => '책이 성공적으로 업데이트되었습니다.', + 'book_delete' => '삭제된 책', + 'book_delete_notification' => '책이 성공적으로 삭제되었습니다.', + 'book_sort' => '정렬된 책', + 'book_sort_notification' => '책이 성공적으로 재정렬되었습니다.', // Bookshelves - 'bookshelf_create' => '책꽃이 만들기', - 'bookshelf_create_notification' => '책꽃이 생성 완료', - 'bookshelf_create_from_book' => '책을 책꽃이로 변환', - 'bookshelf_create_from_book_notification' => '책을 책꽂이로 변환했습니다.', - 'bookshelf_update' => '책꽃이 업데이트', - 'bookshelf_update_notification' => '책꽃이가 업데이트되었습니다', - 'bookshelf_delete' => '선반 삭제', - 'bookshelf_delete_notification' => '책꽃이가 삭제되었습니다.', + 'bookshelf_create' => '책장 만들기', + 'bookshelf_create_notification' => '책장을 성공적으로 생성했습니다.', + 'bookshelf_create_from_book' => '책을 책장으로 변환함', + 'bookshelf_create_from_book_notification' => '책을 성공적으로 책장으로 변환하였습니다.', + 'bookshelf_update' => '책장 업데이트됨', + 'bookshelf_update_notification' => '책장이 성공적으로 업데이트 되었습니다.', + 'bookshelf_delete' => '삭제된 책장', + 'bookshelf_delete_notification' => '책장이 성공적으로 삭제되었습니다.', // Revisions - 'revision_restore' => '버전 복원', - 'revision_delete' => '버전 삭제', - 'revision_delete_notification' => '버전 삭제 성공', + 'revision_restore' => '복구된 리비전', + 'revision_delete' => '삭제된 리비전', + 'revision_delete_notification' => '리비전을 성공적으로 삭제하였습니다.', // Favourites - 'favourite_add_notification' => '":name" 북마크에 추가함', - 'favourite_remove_notification' => '":name" 북마크에서 삭제함', + '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_login' => '로그인 됨', 'auth_register' => '신규 사용자 등록', 'auth_password_reset_request' => '사용자 비밀번호 초기화 요청', 'auth_password_reset_update' => '사용자 비밀번호 초기화', - 'mfa_setup_method' => 'configured MFA method', + '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' => '설정 변경', 'settings_update_notification' => '설졍 변경 성공', - 'maintenance_action_run' => 'ran maintenance action', + 'maintenance_action_run' => '유지 관리 작업 실행', // Webhooks 'webhook_create' => '웹 훅 만들기', @@ -94,11 +94,11 @@ // API Tokens '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', - 'api_token_delete' => 'deleted api token', - 'api_token_delete_notification' => 'API token successfully deleted', + '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' => '역활 생성', @@ -109,9 +109,9 @@ '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' => '댓글 쓰기', diff --git a/lang/ko/auth.php b/lang/ko/auth.php index 60a54dabd64..a29f9b9ad96 100644 --- a/lang/ko/auth.php +++ b/lang/ko/auth.php @@ -29,7 +29,7 @@ 'already_have_account' => '계정이 있나요?', 'dont_have_account' => '계정이 없나요?', 'social_login' => '소셜 로그인', - 'social_registration' => '소셜 가입', + 'social_registration' => '소셜 계정으로 가입', 'social_registration_text' => '소셜 계정으로 가입하고 로그인합니다.', 'register_thanks' => '가입해 주셔서 감사합니다!', diff --git a/lang/ko/common.php b/lang/ko/common.php index 89ae78bd389..794fdc6cd3c 100644 --- a/lang/ko/common.php +++ b/lang/ko/common.php @@ -6,7 +6,7 @@ // Buttons 'cancel' => '취소', - 'close' => 'Close', + 'close' => '닫기', 'confirm' => '확인', 'back' => '뒤로', 'save' => '저장', @@ -26,7 +26,7 @@ 'actions' => '활동', 'view' => '보기', 'view_all' => '모두 보기', - 'new' => 'New', + 'new' => '신규', 'create' => '만들기', 'update' => '바꾸기', 'edit' => '수정', @@ -42,7 +42,7 @@ 'remove' => '제거', 'add' => '추가', 'configure' => '설정', - 'manage' => 'Manage', + 'manage' => '관리', 'fullscreen' => '전체화면', 'favourite' => '즐겨찾기', 'unfavourite' => '즐겨찾기 해제', @@ -52,7 +52,7 @@ 'filter_clear' => '모든 필터 해제', 'download' => '내려받기', 'open_in_tab' => '탭에서 열기', - 'open' => 'Open', + 'open' => '열기 ', // Sort Options 'sort_options' => '정렬 기준', diff --git a/lang/ko/components.php b/lang/ko/components.php index 66e1bde18b1..c81497e0308 100644 --- a/lang/ko/components.php +++ b/lang/ko/components.php @@ -9,18 +9,18 @@ '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_intro' => '여기에서 이전에 시스템에 업로드한 이미지를 선택하고 관리할 수 있습니다.', + 'image_intro_upload' => '이미지 파일을 이 창으로 끌어다 놓거나 위의 \'이미지 업로드\' 버튼을 사용하여 새 이미지를 업로드합니다.', 'image_all' => '모든 이미지', 'image_all_title' => '모든 이미지', 'image_book_title' => '이 책에서 쓰고 있는 이미지', 'image_page_title' => '이 문서에서 쓰고 있는 이미지', 'image_search_hint' => '이미지 이름 검색', 'image_uploaded' => '올림 :uploadedDate', - 'image_uploaded_by' => '업로드:유저 닉네임', - 'image_uploaded_to' => '업로드:링크', - 'image_updated' => '갱신:갱신일', - 'image_load_more' => '더 로드하기', + 'image_uploaded_by' => '업로드 :userName', + 'image_uploaded_to' => ':pageLink 로 업로드됨', + 'image_updated' => '갱신일 :updateDate', + 'image_load_more' => '더 보기', 'image_image_name' => '이미지 이름', 'image_delete_used' => '이 이미지는 다음 문서들이 쓰고 있습니다.', 'image_delete_confirm_text' => '이 이미지를 지울 건가요?', @@ -33,9 +33,9 @@ 'image_update_success' => '이미지 정보 수정함', 'image_delete_success' => '이미지 삭제함', 'image_replace' => '이미지 교체', - 'image_replace_success' => 'Image file successfully updated', - 'image_rebuild_thumbs' => 'Regenerate Size Variations', - 'image_rebuild_thumbs_success' => 'Image size variations successfully rebuilt!', + 'image_replace_success' => '이미지 파일 업데이트 성공', + 'image_rebuild_thumbs' => '사이즈 변경 재생성하기', + 'image_rebuild_thumbs_success' => '이미지 크기 변경이 성공적으로 완료되었습니다!', // Code Editor 'code_editor' => '코드 수정', diff --git a/lang/ko/editor.php b/lang/ko/editor.php index 9764c7d356d..7959bc81dc0 100644 --- a/lang/ko/editor.php +++ b/lang/ko/editor.php @@ -150,7 +150,7 @@ 'open_link_new' => '새 창', 'remove_link' => '링크 제거', 'insert_collapsible' => '접을 수 있는 블록 삽입', - 'collapsible_unwrap' => 'Unwrap', + 'collapsible_unwrap' => '언래핑', 'edit_label' => '레이블 수정', 'toggle_open_closed' => '열림/닫힘 전환', 'collapsible_edit' => '접을 수 있는 블록 편집', @@ -163,8 +163,8 @@ 'editor_tiny_license' => '이 편집기는 MIT 라이선스에 따라 제공되는 :tinyLink를 사용하여 제작되었습니다.', 'editor_tiny_license_link' => 'TinyMCE의 저작권 및 라이선스 세부 정보는 여기에서 확인할 수 있습니다.', 'save_continue' => '저장하고 계속하기', - 'callouts_cycle' => '(Keep pressing to toggle through types)', - 'link_selector' => 'Link to content', + 'callouts_cycle' => '(계속 누르면 유형이 전환됩니다.)', + 'link_selector' => '콘텐츠에 연결', 'shortcuts' => '단축키', 'shortcut' => '단축키', 'shortcuts_intro' => '편집기에서 사용할 수 있는 바로 가기는 다음과 같습니다:', diff --git a/lang/ko/entities.php b/lang/ko/entities.php index cd56d3ed89f..934d7201e2b 100644 --- a/lang/ko/entities.php +++ b/lang/ko/entities.php @@ -11,7 +11,7 @@ 'recently_updated_pages' => '최근에 수정한 문서', 'recently_created_chapters' => '최근에 만든 챕터', 'recently_created_books' => '최근에 만든 책', - 'recently_created_shelves' => '최근에 만든 책꽂이', + 'recently_created_shelves' => '최근에 만든 책장', 'recently_update' => '최근에 수정함', 'recently_viewed' => '최근에 읽음', 'recent_activity' => '최근에 활동함', @@ -23,34 +23,34 @@ 'meta_updated' => '수정함 :timeLength', 'meta_updated_name' => '수정함 :timeLength, :user', 'meta_owned_name' => '소유함 :user', - 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', + 'meta_reference_count' => '참조 대상 :count item|참조 대상 :count items', 'entity_select' => '항목 선택', 'entity_select_lack_permission' => '이 항목을 선택하기 위해 필요한 권한이 없습니다', 'images' => '이미지', 'my_recent_drafts' => '내 최근의 초안 문서', 'my_recently_viewed' => '내가 읽은 문서', - 'my_most_viewed_favourites' => '많이 본 북마크', - 'my_favourites' => '북마크', - 'no_pages_viewed' => '문서 없음', - 'no_pages_recently_created' => '문서 없음', - 'no_pages_recently_updated' => '문서 없음', - 'export' => '파일로 받기', - 'export_html' => 'Contained Web(.html) 파일', + 'my_most_viewed_favourites' => '내가 가장 많이 본 즐겨찾기', + 'my_favourites' => '나의 즐겨찾기', + 'no_pages_viewed' => '본 페이지가 없습니다.', + 'no_pages_recently_created' => '최근에 생성된 페이지가 없습니다.', + 'no_pages_recently_updated' => '최근 업데이트된 페이지가 없습니다.', + 'export' => '내보내기', + 'export_html' => '포함된 웹 파일', 'export_pdf' => 'PDF 파일', - 'export_text' => 'Plain Text(.txt) 파일', - 'export_md' => 'Markdown(.md) 파일', + 'export_text' => '일반 텍스트 파일', + 'export_md' => '마크다운 파일', // Permissions and restrictions '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_desc' => '여기에서 권한을 설정하여 사용자 역할에서 제공하는 기본 권한을 재정의합니다.', + 'permissions_book_cascade' => '책에 설정된 권한은 자체 권한이 정의되어 있지 않은 한 하위 챕터와 페이지에 자동으로 계단식으로 적용됩니다.', + 'permissions_chapter_cascade' => '챕터에 설정된 권한은 하위 페이지에 자체 권한이 정의되어 있지 않는 한 자동으로 계단식으로 적용됩니다.', 'permissions_save' => '권한 저장', 'permissions_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_role_everyone_else' => '그 외 모든 사용자', + 'permissions_role_everyone_else_desc' => '특별히 재정의되지 않은 모든 역할에 대한 권한을 설정.', + 'permissions_role_override' => '역할에 대한 권한 재정의하기', + 'permissions_inherit_defaults' => '기본값 상속', // Search 'search_results' => '검색 결과', @@ -96,21 +96,21 @@ 'shelves_drag_books' => '책을 이 책장에 추가하려면 아래로 드래그하세요', 'shelves_empty_contents' => '이 책꽂이에 책이 없습니다.', 'shelves_edit_and_assign' => '책꽂이 바꾸기로 책을 추가하세요.', - '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' => '책꽂이 편집 :name', + 'shelves_edit' => '책꽂이 편집', + 'shelves_delete' => '책꽂이 삭제', + 'shelves_delete_named' => '책꽂이 삭제 :이름', + 'shelves_delete_explain' => "그러면 ':name'이라는 이름의 서가가 삭제됩니다. 포함된 책은 삭제되지 않습니다.", + 'shelves_delete_confirmation' => '이 책꽂이를 삭제하시겠습니까?', + 'shelves_permissions' => '책꽂이 권한', + 'shelves_permissions_updated' => '책꽂이 권한 업데이트됨', + 'shelves_permissions_active' => '책꽂이 권한 활성화', + 'shelves_permissions_cascade_warning' => '책꽂이에 대한 권한은 포함된 책에 자동으로 계단식으로 부여되지 않습니다. 한 권의 책이 여러 개의 책꽂이에 존재할 수 있기 때문입니다. 그러나 아래 옵션을 사용하여 권한을 하위 책으로 복사할 수 있습니다.', + 'shelves_permissions_create' => '책꽂이 만들기 권한은 아래 작업을 사용하여 하위 책에 대한 권한을 복사하는 데만 사용됩니다. 책을 만드는 기능은 제어하지 않습니다.', 'shelves_copy_permissions_to_books' => '권한 맞춤', 'shelves_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', + 'shelves_copy_permissions_explain' => '그러면 이 책꽂이의 현재 권한 설정이 이 책꽂이에 포함된 모든 책에 적용됩니다. 활성화하기 전에 이 책꽂이의 권한에 대한 변경 사항이 모두 저장되었는지 확인하세요.', + 'shelves_copy_permission_success' => '책꽂이 권한이 복사됨 :count books', // Books 'book' => '책', @@ -132,9 +132,9 @@ '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_default_template' => '기본 페이지 템플릿', + 'books_default_template_explain' => '이 책에 있는 모든 새 페이지의 기본 콘텐츠로 사용할 페이지 템플릿을 지정합니다. 페이지 작성자에게 선택한 템플릿 페이지에 대한 보기 액세스 권한이 있는 경우에만 이 템플릿이 사용된다는 점에 유의하세요.', + 'books_default_template_select' => '템플릿 페이지 선택', 'books_permissions' => '책 권한', 'books_permissions_updated' => '권한 저장함', 'books_empty_contents' => '이 책에 챕터나 문서가 없습니다.', @@ -145,7 +145,7 @@ 'books_search_this' => '이 책에서 검색', 'books_navigation' => '목차', 'books_sort' => '다른 책들', - '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' => '책 내에서 챕터와 페이지를 이동하여 내용을 재구성할 수 있습니다. 다른 책을 추가하여 책 간에 챕터와 페이지를 쉽게 이동할 수 있습니다.', 'books_sort_named' => ':bookName 정렬', 'books_sort_name' => '제목', 'books_sort_created' => '만든 날짜', @@ -154,17 +154,17 @@ 'books_sort_chapters_last' => '문서 우선', 'books_sort_show_other' => '다른 책들', 'books_sort_save' => '적용', - '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_sort_show_other_desc' => '여기에 다른 책을 추가하여 정렬 작업에 포함시키고 책 간 재구성을 쉽게 할 수 있습니다.', + 'books_sort_move_up' => '위로 이동', + 'books_sort_move_down' => '아래로 이동', + 'books_sort_move_prev_book' => '이전 책으로 이동', + 'books_sort_move_next_book' => '다음 책으로 이동', + 'books_sort_move_prev_chapter' => '이전 챕터로 이동', + 'books_sort_move_next_chapter' => '다음 챕터로 이동', + 'books_sort_move_book_start' => '책 시작 부분으로 이동', + 'books_sort_move_book_end' => '책의 끝으로 이동', + 'books_sort_move_before_chapter' => '이전 챕터로 이동', + 'books_sort_move_after_chapter' => '챕터 뒤로 이동', 'books_copy' => '책 복사하기', 'books_copy_success' => '책 복사함', @@ -207,7 +207,7 @@ '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_warning_template' => '이 페이지는 책의 기본 페이지 템플릿으로 사용 중입니다. 이 페이지가 삭제된 후에는 이러한 책에 더 이상 기본 페이지 템플릿이 할당되지 않습니다.', 'pages_delete_confirm' => '이 문서를 지울 건가요?', 'pages_delete_draft_confirm' => '이 초안을 지울 건가요?', 'pages_editing_named' => ':pageName 수정', @@ -218,7 +218,7 @@ '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' => '마크다운 편집기로 전환', 'pages_edit_switch_to_markdown_clean' => '(Clean Content)', @@ -230,9 +230,9 @@ 'pages_editor_switch_title' => '편집기 전환', 'pages_editor_switch_are_you_sure' => '이 페이지의 편집기를 변경하시겠어요?', 'pages_editor_switch_consider_following' => '편집기를 전환할 때에 다음 사항들을 고려하세요:', - '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_consideration_a' => '저장된 새 편집기 옵션은 편집기 유형을 직접 변경할 수 없는 편집자를 포함하여 향후 모든 편집자가 사용할 수 있습니다.', + 'pages_editor_switch_consideration_b' => '이로 인해 특정 상황에서는 디테일과 구문이 손실될 수 있습니다.', + 'pages_editor_switch_consideration_c' => '마지막 저장 이후 변경된 태그 또는 변경 로그 변경 사항은 이 변경 사항에서 유지되지 않습니다.', 'pages_save' => '저장', 'pages_title' => '문서 제목', 'pages_name' => '문서 이름', @@ -241,10 +241,10 @@ 'pages_md_insert_image' => '이미지 추가', 'pages_md_insert_link' => '내부 링크', 'pages_md_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_md_show_preview' => '미리보기 표시', + 'pages_md_sync_scroll' => '미리보기 스크롤 동기화', + 'pages_drawing_unsaved' => '저장되지 않은 드로잉 발견', + 'pages_drawing_unsaved_confirm' => '이전에 실패한 드로잉 저장 시도에서 저장되지 않은 드로잉 데이터가 발견되었습니다. 이 저장되지 않은 드로잉을 복원하고 계속 편집하시겠습니까?', 'pages_not_in_chapter' => '챕터에 있는 문서가 아닙니다.', 'pages_move' => '문서 이동하기', 'pages_copy' => '문서 복제', @@ -254,14 +254,14 @@ 'pages_permissions_success' => '문서 권한 바꿈', 'pages_revision' => '수정본', 'pages_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_desc' => '아래는 이 페이지의 모든 과거 개정 버전입니다. 권한이 허용하는 경우 이전 페이지 버전을 되돌아보고, 비교하고, 복원할 수 있습니다. 시스템 구성에 따라 이전 수정본이 자동으로 삭제될 수 있으므로 페이지의 전체 기록이 여기에 완전히 반영되지 않을 수 있습니다.', 'pages_revisions_named' => ':pageName 수정본', 'pages_revision_named' => ':pageName 수정본', 'pages_revision_restored_from' => '#:id; :summary에서 복구함', 'pages_revisions_created_by' => '만든 사용자', 'pages_revisions_date' => '수정한 날짜', 'pages_revisions_number' => 'No.', - 'pages_revisions_sort_number' => 'Revision Number', + 'pages_revisions_sort_number' => '수정 번호', 'pages_revisions_numbered' => '수정본 :id', 'pages_revisions_numbered_changes' => '수정본 :id에서 바꾼 부분', 'pages_revisions_editor' => '편집기 유형', @@ -272,16 +272,16 @@ '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' => 'System auto-update of internal links', + 'pages_references_update_revision' => '시스템에서 내부 링크 자동 업데이트', 'pages_initial_name' => '제목 없음', 'pages_editing_draft_notification' => ':timeDiff에 초안 문서입니다.', 'pages_draft_edited_notification' => '최근에 수정한 문서이기 때문에 초안 문서를 폐기하는 편이 좋습니다.', @@ -293,20 +293,20 @@ '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' => '책 꼬리표', 'shelf_tags' => '책꽂이 꼬리표', 'tag' => '꼬리표', '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.', + 'tags_index_desc' => '태그를 시스템 내의 콘텐츠에 적용하여 유연한 형태의 분류를 적용할 수 있습니다. 태그는 키와 값을 모두 가질 수 있으며 값은 선택 사항입니다. 태그가 적용되면 태그 이름과 값을 사용하여 콘텐츠를 쿼리할 수 있습니다.', 'tag_name' => '꼬리표 이름', 'tag_value' => '리스트 값 (선택 사항)', 'tags_explain' => "꼬리표로 문서를 분류하세요.", @@ -327,10 +327,10 @@ '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' => '링크 이름', @@ -373,13 +373,13 @@ 'comment_new' => '새로운 댓글', 'comment_created' => '댓글 등록함 :createDiff', 'comment_updated' => ':username(이)가 댓글 수정함 :updateDiff', - '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' => '이 수정본을 지울 건가요?', @@ -396,42 +396,42 @@ // Conversions '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_to_shelf_contents_desc' => '이 책을 동일한 내용의 새 서가로 변환할 수 있습니다. 이 책에 포함된 챕터는 새 책으로 변환됩니다. 이 책에 챕터에 포함되지 않은 페이지가 포함되어 있는 경우, 이 책의 이름이 변경되어 해당 페이지가 포함되며 이 책은 새 서가의 일부가 됩니다.', + 'convert_to_shelf_permissions_desc' => '이 책에 설정된 모든 권한은 새 서가 및 자체 권한이 적용되지 않은 모든 새 책에 복사됩니다. 책에 대한 권한은 책에 대한 권한처럼 그 안의 콘텐츠로 자동 캐스케이드되지 않는다는 점에 유의하세요.', 'convert_book' => '책 변환', 'convert_book_confirm' => '이 책을 변환하시겠어요?', 'convert_undo_warning' => '이 작업은 되돌리기 어렵습니다.', '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_to_book_desc' => '이 챕터를 동일한 내용의 새 책으로 변환할 수 있습니다. 이 장에 설정된 모든 권한은 새 책에 복사되지만 상위 책에서 상속된 권한은 복사되지 않으므로 액세스 제어가 변경될 수 있습니다.', 'convert_chapter' => '챕터 변환', 'convert_chapter_confirm' => '이 챕터를 변환하시겠어요?', // References - 'references' => 'References', - 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', + 'references' => '참조', + 'references_none' => '이 항목에 대한 추적된 참조가 없습니다.', + '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/ko/errors.php b/lang/ko/errors.php index a652cc697ef..0ab6789cc0c 100644 --- a/lang/ko/errors.php +++ b/lang/ko/errors.php @@ -5,68 +5,68 @@ return [ // Permissions - 'permission' => '권한이 없습니다.', - 'permissionJson' => '권한이 없습니다.', + 'permission' => '요청된 페이지에 액세스할 수 있는 권한이 없습니다.', + 'permissionJson' => '요청된 작업을 수행할 수 있는 권한이 없습니다.', // Auth - 'error_user_exists_different_creds' => ':email(을)를 가진 다른 사용자가 있습니다.', - 'email_already_confirmed' => '확인이 끝난 메일 주소입니다. 로그인하세요.', - 'email_confirmation_invalid' => '이 링크는 더 이상 유효하지 않습니다. 다시 가입하세요.', - 'email_confirmation_expired' => '이 링크는 더 이상 유효하지 않습니다. 메일을 다시 보냈습니다.', - 'email_confirmation_awaiting' => '사용 중인 계정의 이메일 주소를 확인해 주어야 합니다.', - 'ldap_fail_anonymous' => '익명 정보로 LDAP 서버에 접근할 수 없습니다.', - 'ldap_fail_authed' => '이 정보로 LDAP 서버에 접근할 수 없습니다.', - 'ldap_extension_not_installed' => 'PHP에 LDAP 확장 도구를 설치하세요.', - 'ldap_cannot_connect' => 'LDAP 서버에 연결할 수 없습니다.', - 'saml_already_logged_in' => '로그인 중입니다.', - 'saml_no_email_address' => '인증 시스템이 제공한 메일 주소가 없습니다.', - 'saml_invalid_response_id' => '인증 시스템이 요청을 받지 못했습니다. 인증 후 이전 페이지로 돌아갈 때 발생할 수 있는 현상입니다.', - 'saml_fail_authed' => ':system에 로그인할 수 없습니다.', - '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로 로그인하세요.', - 'social_account_email_in_use' => ':email(을)를 가진 사용자가 있습니다. 쓰고 있는 계정을 :socialAccount에 연결하세요.', - 'social_account_existing' => ':socialAccount(와)과 연결 상태입니다.', - 'social_account_already_used_existing' => ':socialAccount(와)과 연결한 다른 계정이 있습니다.', - 'social_account_not_used' => ':socialAccount(와)과 연결한 계정이 없습니다. 쓰고 있는 계정을 연결하세요.', - 'social_account_register_instructions' => '계정이 없어도 :socialAccount로 가입할 수 있습니다.', - 'social_driver_not_found' => '가입할 수 없습니다.', - 'social_driver_not_configured' => ':socialAccount가 유효하지 않습니다.', - 'invite_token_expired' => '이 링크는 더 이상 유효하지 않습니다. 패스워드를 바꾸세요.', + 'error_user_exists_different_creds' => '이메일 :email 이 이미 존재하지만 다른 자격 증명을 가진 사용자입니다.', + 'email_already_confirmed' => '이메일이 이미 확인되었으니 로그인해 보세요.', + 'email_confirmation_invalid' => '이 확인 토큰이 유효하지 않거나 이미 사용되었습니다. 다시 등록해 주세요.', + 'email_confirmation_expired' => '확인 토큰이 만료되었습니다. 새 확인 이메일이 전송되었습니다.', + 'email_confirmation_awaiting' => '사용 중인 계정의 이메일 주소를 확인해야 합니다.', + 'ldap_fail_anonymous' => '익명 바인딩을 사용하여 LDAP 액세스에 실패했습니다.', + 'ldap_fail_authed' => '주어진 dn 및 암호 세부 정보를 사용하여 LDAP 액세스에 실패했습니다.', + 'ldap_extension_not_installed' => 'LDAP PHP 확장이 설치되지 않았습니다.', + 'ldap_cannot_connect' => 'LDAP 서버에 연결할 수 없음, 초기 연결 실패', + 'saml_already_logged_in' => '이미 로그인했습니다.', + 'saml_no_email_address' => '외부 인증 시스템에서 제공한 데이터에서 이 사용자의 이메일 주소를 찾을 수 없습니다.', + 'saml_invalid_response_id' => '이 애플리케이션에서 시작한 프로세스에서 외부 인증 시스템의 요청을 인식하지 못합니다. 로그인 후 다시 이동하면 이 문제가 발생할 수 있습니다.', + 'saml_fail_authed' => ':system 을 사용하여 로그인, 시스템이 성공적인 인증을 제공하지 않음', + '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 옵션을 통해 로그인해 보세요.', + 'social_account_email_in_use' => '이메일 :email 은(는) 이미 사용 중입니다. 이미 계정이 있는 경우 프로필 설정에서 :socialAccount 계정을 연결할 수 있습니다.', + 'social_account_existing' => '이 :socialAccount 는 이미 프로필에 연결되어 있습니다.', + 'social_account_already_used_existing' => '이 :socialAccount 계정은 다른 사용자가 이미 사용하고 있습니다.', + 'social_account_not_used' => '이 :socialAccount 계정은 어떤 사용자와도 연결되어 있지 않습니다. 프로필 설정에서 첨부하세요. ', + 'social_account_register_instructions' => '아직 계정이 없는 경우 :socialAccount 옵션을 사용하여 계정을 등록할 수 있습니다.', + 'social_driver_not_found' => '소셜 드라이버를 찾을 수 없습니다.', + 'social_driver_not_configured' => '소셜 계정 :socialAccount 가(이) 올바르게 구성되지 않았습니다.', + 'invite_token_expired' => '이 초대 링크가 만료되었습니다. 대신 계정 비밀번호 재설정을 시도해 보세요.', // System - 'path_not_writable' => ':filePath에 쓰는 것을 서버에서 허용하지 않습니다.', - 'cannot_get_image_from_url' => ':url에서 이미지를 불러올 수 없습니다.', - 'cannot_create_thumbs' => '섬네일을 못 만들었습니다. PHP에 GD 확장 도구를 설치하세요.', - 'server_upload_limit' => '파일 크기가 서버에서 허용하는 수치를 넘습니다.', - 'server_post_limit' => 'The server cannot receive the provided amount of data. Try again with less data or a smaller file.', - 'uploaded' => '파일 크기가 서버에서 허용하는 수치를 넘습니다.', + 'path_not_writable' => '파일 경로 :filePath 에 업로드할 수 없습니다. 서버에 저장이 가능한지 확인하세요.', + 'cannot_get_image_from_url' => ':url 에서 이미지를 가져올 수 없습니다.', + 'cannot_create_thumbs' => '서버에서 썸네일을 만들 수 없습니다. GD PHP 확장이 설치되어 있는지 확인하세요.', + 'server_upload_limit' => '서버에서 이 크기의 업로드를 허용하지 않습니다. 더 작은 파일 크기를 시도해 보세요.', + '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_error' => '이미지를 업로드하는 동안 오류가 발생했습니다.', + 'image_upload_type_error' => '업로드 중인 이미지 유형이 유효하지 않습니다.', + '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_not_found' => '첨부 파일을 찾을 수 없습니다.', + 'attachment_upload_error' => '첨부 파일을 업로드하는 동안 오류가 발생했습니다.', // Pages - 'page_draft_autosave_fail' => '초안 문서를 유실했습니다. 인터넷 연결 상태를 확인하세요.', - 'page_draft_delete_fail' => 'Failed to delete page draft and fetch current page saved content', - 'page_custom_home_deletion' => '처음 페이지는 지울 수 없습니다.', + 'page_draft_autosave_fail' => '초안을 저장하지 못했습니다. 이 페이지를 저장하기 전에 인터넷에 연결되어 있는지 확인하세요.', + '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' => '챕터가 없습니다.', @@ -115,5 +115,5 @@ '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/ko/notifications.php b/lang/ko/notifications.php index 1afd23f1dc4..b337fa86de2 100644 --- a/lang/ko/notifications.php +++ b/lang/ko/notifications.php @@ -4,24 +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_page_path' => 'Page Path:', - '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/ko/preferences.php b/lang/ko/preferences.php index dec399112a5..ccc09e7a33f 100644 --- a/lang/ko/preferences.php +++ b/lang/ko/preferences.php @@ -5,10 +5,10 @@ */ return [ - 'my_account' => 'My Account', + 'my_account' => '내 계정', 'shortcuts' => '단축키', - 'shortcuts_interface' => 'UI Shortcut Preferences', + 'shortcuts_interface' => 'UI 바로 가기 환경설정', 'shortcuts_toggle_desc' => '여기에서 탐색과 행동에 사용될 수 있는 키보드 단축키를 활성화하거나 비활성화할 수 있습니다.', 'shortcuts_customize_desc' => '아래에서 각 단축키를 사용자 지정할 수 있습니다. 바로가기에 대한 입력을 선택한 후 원하는 키 조합을 누르기만 하면 됩니다.', 'shortcuts_toggle_label' => '키보드 단축키가 활성화되었습니다.', @@ -17,35 +17,35 @@ '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' => '이 이메일은 알림 및 활성 시스템 인증에 따라 시스템 액세스에 사용됩니다.', + 'profile_email_no_permission' => '안타깝게도 회원님에게는 이메일 주소를 변경할 수 있는 권한이 없습니다. 이메일 주소를 변경하려면 관리자에게 변경을 요청해야 합니다.', + 'profile_avatar_desc' => '시스템에서 다른 사람들에게 자신을 나타내는 데 사용할 이미지를 선택합니다. 이 이미지는 256 x 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/ko/settings.php b/lang/ko/settings.php index e60bb6646d9..fe6dd4c7e25 100644 --- a/lang/ko/settings.php +++ b/lang/ko/settings.php @@ -14,47 +14,47 @@ // App Settings 'app_customization' => '맞춤', - 'app_features_security' => '보안', - 'app_name' => '사이트 제목', - 'app_name_desc' => '메일을 보낼 때 이 제목을 씁니다.', - 'app_name_header' => '사이트 헤더 사용', + 'app_features_security' => '기능 및 보안', + 'app_name' => '애플리케이션 이름 (사이트 제목)', + 'app_name_desc' => '이 이름은 헤더와 시스템에서 보낸 모든 이메일에 표시됩니다.', + 'app_name_header' => '헤더에 이름 표시', 'app_public_access' => '사이트 공개', - 'app_public_access_desc' => '계정 없는 사용자가 문서를 볼 수 있습니다.', - 'app_public_access_desc_guest' => '이들의 권한은 사용자 이름이 Guest인 사용자로 관리할 수 있습니다.', - 'app_public_access_toggle' => '사이트 공개', - 'app_public_viewing' => '공개할 건가요?', - 'app_secure_images' => '이미지 주소 보호', - 'app_secure_images_toggle' => '이미지 주소 보호', - 'app_secure_images_desc' => '성능상의 문제로 이미지에 누구나 접근할 수 있기 때문에 이미지 주소를 무작위한 문자로 구성합니다. 폴더 색인을 끄세요.', + 'app_public_access_desc' => '이 옵션을 활성화하면 로그인하지 않은 방문자도 북스택 인스턴스의 콘텐츠에 액세스할 수 있습니다.', + 'app_public_access_desc_guest' => '일반 방문자의 액세스는 "Guest" 사용자를 통해 제어할 수 있습니다.', + 'app_public_access_toggle' => '공개 액세스 허용', + 'app_public_viewing' => '공개 열람을 허용할까요?', + 'app_secure_images' => '보안 강화된 이미지 업로드', + 'app_secure_images_toggle' => '보안 강화된 이미지 업로드 사용', + 'app_secure_images_desc' => '성능상의 이유로 모든 이미지는 공개됩니다. 이 옵션은 이미지 URL 앞에 추측하기 어려운 임의의 문자열을 추가합니다. 쉽게 액세스할 수 없도록 디렉토리 인덱스가 활성화되어 있지 않은지 확인하세요.', 'app_default_editor' => '기본 페이지 편집기', 'app_default_editor_desc' => '새 페이지를 편집할 때 기본으로 사용될 편집기를 선택합니다. 권한을 갖고 있다면 페이지마다 다르게 적용될 수 있습니다.', - 'app_custom_html' => '헤드 작성', - 'app_custom_html_desc' => '설정 페이지를 제외한 모든 페이지 head 태그 끝머리에 추가합니다.', - 'app_custom_html_disabled_notice' => '문제가 생겨도 설정 페이지에서 되돌릴 수 있어요.', - 'app_logo' => '사이트 로고', + 'app_custom_html' => '사용자 지정 HTML 헤드 콘텐츠', + 'app_custom_html_desc' => '여기에 추가된 모든 콘텐츠는 모든 페이지의 섹션 하단에 삽입됩니다. 스타일을 재정의하거나 분석 코드를 추가할 때 유용합니다.', + 'app_custom_html_disabled_notice' => '이 설정 페이지에서는 사용자 지정 HTML 헤드 콘텐츠가 비활성화되어 변경 사항을 되돌릴 수 있습니다.', + 'app_logo' => '애플리케이션 로고 (사이트 로고)', 'app_logo_desc' => '이 이미지는 애플리케이션 헤더 표시줄 등 여러 영역에서 사용됩니다. 이 이미지의 높이는 86픽셀이어야 합니다. 큰 이미지는 축소됩니다.', 'app_icon' => '애플리케이션 아이콘', 'app_icon_desc' => '이 아이콘은 브라우저 탭과 바로 가기 아이콘에 사용됩니다. 256픽셀의 정사각형 PNG 이미지여야 합니다.', - 'app_homepage' => '처음 페이지', - 'app_homepage_desc' => '고른 페이지에 설정한 권한은 무시합니다.', - 'app_homepage_select' => '문서 고르기', + 'app_homepage' => '애플리케이션 홈페이지', + 'app_homepage_desc' => '기본 보기 대신 홈페이지에 표시할 보기를 선택합니다. 선택한 페이지에 대한 페이지 권한은 무시됩니다.', + 'app_homepage_select' => '페이지를 선택하십시오', 'app_footer_links' => '바닥글 링크', - 'app_footer_links_desc' => '바닥글 링크는 로그인하지 않아도 보일 수 있습니다. "trans::" 레이블로 시스템에 있는 번역을 가져옵니다. trans::common.privacy_policy와 trans::common.terms_of_service를 쓸 수 있습니다.', + 'app_footer_links_desc' => '사이트 바닥글에 표시할 링크를 추가합니다. 이 링크는 로그인이 필요 없는 페이지를 포함하여 대부분의 페이지 하단에 표시됩니다. "trans::" 레이블을 사용하여 시스템 정의 번역을 사용할 수 있습니다. 예를 들면 다음과 같습니다: "trans::common.privacy_policy"를 사용하면 "개인정보처리방침"이라는 번역 텍스트가 제공되고 "trans::common.terms_of_service"를 사용하면 "서비스 약관"이라는 번역 텍스트가 제공됩니다.', 'app_footer_links_label' => '링크 레이블', 'app_footer_links_url' => '링크 URL', 'app_footer_links_add' => '바닥글 링크 추가', 'app_disable_comments' => '댓글 사용 안 함', 'app_disable_comments_toggle' => '댓글 사용 안 함', - 'app_disable_comments_desc' => '모든 페이지에서 댓글을 숨깁니다.', + 'app_disable_comments_desc' => '애플리케이션의 모든 페이지에서 코멘트를 비활성화합니다.
기존 댓글도 표시되지 않습니다.', // Color settings - 'color_scheme' => '애플리케이션 색상 스키마', - 'color_scheme_desc' => '애플리케이션 사용자 인터페이스에서 사용할 색상을 설정합니다. 테마에 가장 잘 맞으면서 가독성을 보장하기 위해 어두운 모드와 밝은 모드에 대해 색상을 개별적으로 구성할 수 있습니다.', + 'color_scheme' => '애플리케이션 색상 구성표', + 'color_scheme_desc' => '애플리케이션 사용자 인터페이스에서 사용할 색상을 설정합니다. 테마에 가장 잘 어울리고 가독성을 보장하기 위해 어두운 모드와 밝은 모드에 대해 색상을 별도로 구성할 수 있습니다.', 'ui_colors_desc' => '애플리케이션 기본 색상과 기본 링크 색상을 설정합니다. 기본 색상은 주로 헤더 배너, 버튼 및 인터페이스 장식에 사용됩니다. 기본 링크 색상은 작성된 콘텐츠와 애플리케이션 인터페이스 모두에서 텍스트 기반 링크 및 작업에 사용됩니다.', 'app_color' => '주 색상', 'link_color' => '기본 링크 색상', 'content_colors_desc' => '페이지 구성 계층 구조의 모든 요소에 대한 색상을 설정합니다. 가독성을 위해 기본 색상과 비슷한 밝기의 색상을 선택하는 것이 좋습니다.', - 'bookshelf_color' => '책꽂이 색상', + 'bookshelf_color' => '책장 색상', 'book_color' => '책 색상', 'chapter_color' => '챕터 색상', 'page_color' => '페이지 색상', @@ -62,7 +62,7 @@ // Registration Settings 'reg_settings' => '가입', - 'reg_enable' => '가입 받기', + 'reg_enable' => '가입 활성화', 'reg_enable_toggle' => '가입 받기', 'reg_enable_desc' => '가입한 사용자는 한 가지 권한을 가집니다.', 'reg_default_role' => '기본 권한', @@ -163,7 +163,7 @@ 'role_manage_settings' => '사이트 설정 관리', 'role_export_content' => '항목 내보내기', 'role_editor_change' => '페이지 편집기 변경', - 'role_notifications' => 'Receive & manage notifications', + 'role_notifications' => '알림 수신 및 관리', 'role_asset' => '권한 항목', 'roles_system_warning' => '위 세 권한은 자신의 권한이나 다른 유저의 권한을 바꿀 수 있습니다.', 'role_asset_desc' => '책, 챕터, 문서별 권한은 이 설정에 우선합니다.', @@ -193,8 +193,8 @@ 'users_send_invite_text' => '패스워드 설정을 권유하는 메일을 보내거나 내가 정할 수 있습니다.', 'users_send_invite_option' => '메일 보내기', 'users_external_auth_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' => '외부 인증 시스템(예: SAML2, OIDC 또는 LDAP)을 사용 중인 경우 이 BookStack 사용자를 인증 시스템 계정에 연결하는 ID입니다. 기본 이메일 기반 인증을 사용하는 경우 이 필드를 무시할 수 있습니다.', + 'users_password_warning' => '이 사용자의 비밀번호를 변경하려는 경우에만 아래 내용을 입력하세요.', 'users_system_public' => '계정 없는 모든 사용자에 할당한 사용자입니다. 이 사용자로 로그인할 수 없어요.', 'users_delete' => '사용자 삭제', 'users_delete_named' => ':userName 삭제', @@ -210,16 +210,16 @@ 'users_preferred_language' => '언어', 'users_preferred_language_desc' => '문서 내용에는 아무런 영향을 주지 않습니다.', 'users_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_desc' => '이 사용자에 대해 연결된 소셜 계정의 상태를 봅니다. 소셜 계정은 시스템 액세스를 위한 기본 인증 시스템과 함께 사용할 수 있습니다.', 'users_social_accounts_info' => '다른 계정으로 간단하게 로그인하세요. 여기에서 계정 연결을 끊는 것과 소셜 계정에서 접근 권한을 취소하는 것은 다릅니다.', 'users_social_connect' => '계정 연결', 'users_social_disconnect' => '계정 연결 끊기', - 'users_social_status_connected' => 'Connected', - 'users_social_status_disconnected' => 'Disconnected', + 'users_social_status_connected' => '연결됨', + 'users_social_status_disconnected' => '연결 해제됨', 'users_social_connected' => ':socialAccount(와)과 연결했습니다.', 'users_social_disconnected' => ':socialAccount(와)과의 연결을 끊었습니다.', 'users_api_tokens' => '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' => 'BookStack REST API로 인증하는 데 사용되는 액세스 토큰을 생성하고 관리합니다. API에 대한 권한은 토큰이 속한 사용자를 통해 관리됩니다.', 'users_api_tokens_none' => '이 사용자를 위해 생성된 API 토큰이 없습니다.', 'users_api_tokens_create' => '토큰 만들기', 'users_api_tokens_expires' => '만료', diff --git a/lang/ko/validation.php b/lang/ko/validation.php index 1a5de20f4c3..e533429ee1a 100644 --- a/lang/ko/validation.php +++ b/lang/ko/validation.php @@ -9,7 +9,7 @@ // Standard laravel validation lines 'accepted' => ':attribute(을)를 허용하세요.', - 'active_url' => ':attribute(을)를 유효한 주소로 구성하세요.', + 'active_url' => ':attribute이 유효한 URL이 아닙니다.', 'after' => ':attribute(을)를 :date 후로 설정하세요.', 'alpha' => ':attribute(을)를 문자로만 구성하세요.', 'alpha_dash' => ':attribute(을)를 문자, 숫자, -, _로만 구성하세요.', diff --git a/lang/lv/activities.php b/lang/lv/activities.php index 3441621547d..742288c98dc 100644 --- a/lang/lv/activities.php +++ b/lang/lv/activities.php @@ -64,17 +64,17 @@ // 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_password_reset_request' => 'pieprasīja lietotāja paroles atiestatīšanu', + 'auth_password_reset_update' => 'atiestatīja lietotāja paroli', + 'mfa_setup_method' => 'uzstādīja MFA metodi', 'mfa_setup_method_notification' => '2FA funkcija aktivizēta', - 'mfa_remove_method' => 'removed MFA method', + 'mfa_remove_method' => 'noņēma MFA metodi', 'mfa_remove_method_notification' => '2FA funkcija noņemta', // Settings - 'settings_update' => 'updated settings', - 'settings_update_notification' => 'Settings successfully updated', - 'maintenance_action_run' => 'ran maintenance action', + 'settings_update' => 'atjaunoja uzstādījumus', + 'settings_update_notification' => 'Uzstādījums veiksmīgi atjaunināts', + 'maintenance_action_run' => 'veica apkopes darbību', // Webhooks 'webhook_create' => 'izveidoja webhook', @@ -85,39 +85,39 @@ 'webhook_delete_notification' => 'Webhook veiksmīgi izdzēsts', // Users - 'user_create' => 'created user', - 'user_create_notification' => 'User successfully created', - 'user_update' => 'updated user', + 'user_create' => 'izveidoja lietotāju', + 'user_create_notification' => 'Lietotājs veiksmīgi izveidots', + 'user_update' => 'atjaunoja lietotāju', 'user_update_notification' => 'Lietotājs veiksmīgi atjaunināts', - 'user_delete' => 'deleted user', + 'user_delete' => 'dzēsa lietotāju', 'user_delete_notification' => 'Lietotājs veiksmīgi dzēsts', // 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' => 'izveidoja API žetonu', + 'api_token_create_notification' => 'API žetons veiksmīgi izveidots', + 'api_token_update' => 'atjaunoja API žetonu', + 'api_token_update_notification' => 'API žetons veiksmīgi atjaunināts', + 'api_token_delete' => 'dzēsa API žetonu', + 'api_token_delete_notification' => 'API žetons veiksmīgi dzēsts', // Roles - 'role_create' => 'created role', + 'role_create' => 'izveidoja lomu', 'role_create_notification' => 'Loma veiksmīgi izveidota', - 'role_update' => 'updated role', + 'role_update' => 'atjaunoja lomu', 'role_update_notification' => 'Loma veiksmīgi atjaunināta', - 'role_delete' => 'deleted role', + 'role_delete' => 'dzēsa lomu', 'role_delete_notification' => 'Loma veiksmīgi dzēsta', // 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' => 'iztukšoja atkritni', + 'recycle_bin_restore' => 'atjaunoja no atkritnes', + 'recycle_bin_destroy' => 'izdzēsa no atkritnes', // Comments 'commented_on' => 'komentēts', - 'comment_create' => 'added comment', - 'comment_update' => 'updated comment', - 'comment_delete' => 'deleted comment', + 'comment_create' => 'pievienoja komentāru', + 'comment_update' => 'atjaunoja komentārju', + 'comment_delete' => 'dzēsa komentāru', // Other 'permissions_update' => 'atjaunoja atļaujas', diff --git a/lang/lv/components.php b/lang/lv/components.php index 2b29b56253c..5a7197687cd 100644 --- a/lang/lv/components.php +++ b/lang/lv/components.php @@ -8,34 +8,34 @@ 'image_select' => 'Attēla izvēle', 'image_list' => 'Attēlu saraksts', 'image_details' => 'Attēla dati', - 'image_upload' => 'Augšuplādēt attēlu', + 'image_upload' => 'Augšupielādēt attēlu', 'image_intro' => 'Šeit jūs varat izvēlēties un pārvaldīt attēlus, kuri iepriekš tika aplugšupielādēti sistēmā.', - 'image_intro_upload' => 'Upload a new image by dragging an image file into this window, or by using the "Upload Image" button above.', + 'image_intro_upload' => 'Augšupielādējiet jaunu attēlu ievelkot attēla failu šajā logā vai izmantojot "Augšupielādēt attēlu" pogu augstāk.', 'image_all' => 'Visi', 'image_all_title' => 'Skatīt visus attēlus', 'image_book_title' => 'Apskatīt augšupielādētos attēlus šajā grāmatā', 'image_page_title' => 'Apskatīt augšupielādētos attēlus šajā lapā', 'image_search_hint' => 'Meklēt pēc attēla vārda', 'image_uploaded' => 'Augšupielādēts :uploadedDate', - 'image_uploaded_by' => 'Uploaded by :userName', - 'image_uploaded_to' => 'Uploaded to :pageLink', - 'image_updated' => 'Updated :updateDate', + 'image_uploaded_by' => 'Augšupielādēja :userName', + 'image_uploaded_to' => 'Augšupielādēja :pageLink', + 'image_updated' => 'Atjaunots :updateDate', 'image_load_more' => 'Ielādēt vairāk', 'image_image_name' => 'Attēla nosaukums', 'image_delete_used' => 'Šis attēls ir ievietots zemāk redzamajās lapās.', 'image_delete_confirm_text' => 'Vai tiešām vēlaties dzēst šo attēlu?', 'image_select_image' => 'Atlasīt attēlu', 'image_dropzone' => 'Ievilkt attēlu vai klikšķinat šeit, lai augšupielādētu', - 'image_dropzone_drop' => 'Drop images here to upload', + 'image_dropzone_drop' => 'Ievelciet attēlus šeit, lai augšupielādētu', 'images_deleted' => 'Dzēstie attēli', 'image_preview' => 'Attēla priekšskatījums', 'image_upload_success' => 'Attēls ir veiksmīgi augšupielādēts', 'image_update_success' => 'Attēlā informācija ir veiksmīgi atjunināta', 'image_delete_success' => 'Attēls veiksmīgi dzēsts', 'image_replace' => 'Nomainīt bildi', - 'image_replace_success' => 'Image file successfully updated', - 'image_rebuild_thumbs' => 'Regenerate Size Variations', - 'image_rebuild_thumbs_success' => 'Image size variations successfully rebuilt!', + 'image_replace_success' => 'Attēla fails veiksmīgi atjaunots', + 'image_rebuild_thumbs' => 'No jauna izveidot attēla dažādu izmēru variantus', + 'image_rebuild_thumbs_success' => 'Attēlu varianti veiksmīgi atjaunoti!', // Code Editor 'code_editor' => 'Rediģēt kodu', diff --git a/lang/lv/entities.php b/lang/lv/entities.php index 40115afff24..96d6b706a15 100644 --- a/lang/lv/entities.php +++ b/lang/lv/entities.php @@ -132,7 +132,7 @@ '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' => 'Noklusētā lapas sagatave', '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', @@ -272,11 +272,11 @@ 'pages_revisions_restore' => 'Atjaunot', 'pages_revisions_none' => 'Šai lapai nav revīziju', 'pages_copy_link' => 'Kopēt saiti', - 'pages_edit_content_link' => 'Jump to section in editor', + 'pages_edit_content_link' => 'Pārlekt uz sadaļu redaktorā', '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_label' => 'Lapas sadaļas uzstādījumi', + 'pages_pointer_permalink' => 'Lapas sadaļas saite', + 'pages_pointer_include_tag' => 'Lapas sadaļas iekļaušanas tags', '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' => 'Lapas atļaujas ir aktīvas', @@ -373,7 +373,7 @@ 'comment_new' => 'Jauns komentārs', 'comment_created' => 'komentējis :createDiff', 'comment_updated' => ':username atjauninājis pirms :updateDiff', - 'comment_updated_indicator' => 'Updated', + 'comment_updated_indicator' => 'Atjaunots', 'comment_deleted_success' => 'Komentārs ir dzēsts', 'comment_created_success' => 'Komentārs ir pievienots', 'comment_updated_success' => 'Komentārs ir atjaunināts', @@ -412,21 +412,21 @@ 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', // Watch Options - 'watch' => 'Watch', + 'watch' => 'Vērot', 'watch_title_default' => 'Default Preferences', 'watch_desc_default' => 'Revert watching to just your default notification preferences.', - 'watch_title_ignore' => 'Ignore', + 'watch_title_ignore' => 'Ignorēt', 'watch_desc_ignore' => 'Ignore all notifications, including those from user-level preferences.', - 'watch_title_new' => 'New Pages', + 'watch_title_new' => 'Jaunas lapas', 'watch_desc_new' => 'Notify when any new page is created within this item.', - 'watch_title_updates' => 'All Page Updates', + 'watch_title_updates' => 'Visi lapu atjauninājumi', '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_title_comments' => 'Visi lapu atjauninājumi un komentāri', '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_ignore' => 'Ignorēt paziņojumus', 'watch_detail_new' => 'Watching for new pages', 'watch_detail_updates' => 'Watching new pages and updates', 'watch_detail_comments' => 'Watching new pages, updates & comments', diff --git a/lang/lv/errors.php b/lang/lv/errors.php index 72abed6e62a..2a5777a0a7f 100644 --- a/lang/lv/errors.php +++ b/lang/lv/errors.php @@ -43,16 +43,16 @@ 'cannot_get_image_from_url' => 'Nevar iegūt bildi no :url', 'cannot_create_thumbs' => 'Serveris nevar izveidot samazinātus attēlus. Lūdzu pārbaudiet, vai ir uzstādīts PHP GD paplašinājums.', 'server_upload_limit' => 'Serveris neatļauj šāda izmēra failu ielādi. Lūdzu mēģiniet mazāka izmēra failu.', - 'server_post_limit' => 'The server cannot receive the provided amount of data. Try again with less data or a smaller file.', + 'server_post_limit' => 'Serveris nevar apstrādāt šāda izmēra datus. Lūdzu mēģiniet vēlreiz ar mazāku datu apjomu vai mazāku failu.', 'uploaded' => 'Serveris neatļauj šāda izmēra failu ielādi. Lūdzu mēģiniet mazāka izmēra failu.', // Drawing & Images 'image_upload_error' => 'Radās kļūda augšupielādējot attēlu', 'image_upload_type_error' => 'Ielādējamā attēla tips nav derīgs', 'image_upload_replace_type' => 'Aizvietojot attēlu tipiem ir jābūt vienādiem', - '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' => 'Neizdevās apstrādāt attēla ielādi vai izveidot attēlu variantus sistēmas resursu ierobežojumu dēļ.', + 'image_thumbnail_memory_limit' => 'Neizdevās izveidot attēla dažādu izmēru variantus sistēmas resursu ierobežojumu dēļ.', + 'image_gallery_thumbnail_memory_limit' => 'Neizdevās izveidot galerijas sīktēlus sistēmas resursu ierobežojumu dēļ.', 'drawing_data_not_found' => 'Attēla datus nevarēja ielādēt. Attēla fails, iespējams, vairs neeksistē, vai arī jums varētu nebūt piekļuves tiesības tam.', // Attachments @@ -115,5 +115,5 @@ 'maintenance_test_email_failure' => 'Radusies kļūda sūtot testa epastu:', // HTTP errors - 'http_ssr_url_no_match' => 'The URL does not match the configured allowed SSR hosts', + 'http_ssr_url_no_match' => 'Adrese (URL) nesakrīt ar atļautajām SSR adresēm', ]; diff --git a/lang/lv/preferences.php b/lang/lv/preferences.php index aea349b3b72..b45a063343b 100644 --- a/lang/lv/preferences.php +++ b/lang/lv/preferences.php @@ -5,47 +5,47 @@ */ return [ - 'my_account' => 'My Account', + 'my_account' => 'Mans konts', 'shortcuts' => 'Saīsnes', - 'shortcuts_interface' => 'UI Shortcut Preferences', + 'shortcuts_interface' => 'Saskarnes īsceļu iestatījumi', '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' => 'Klaviatūras saīsnes ieslēgtas', 'shortcuts_section_navigation' => 'Navigācija', - 'shortcuts_section_actions' => 'Common Actions', + 'shortcuts_section_actions' => 'Biežākās darbības', 'shortcuts_save' => 'Saglabāt saīsnes', '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' => 'Saīsņu uzstādījumi ir saglabāt!', 'shortcuts_overview_desc' => 'Manage keyboard shortcuts you can use to navigate the system user interface.', - 'notifications' => 'Notification Preferences', + 'notifications' => 'Paziņojumu iestatījumi', '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_opt_own_page_changes' => 'Paziņot par izmaiņām manās lapās', + 'notifications_opt_own_page_comments' => 'Paziņot par komentāriem manās lapās', + 'notifications_opt_comment_replies' => 'Paziņot par atbildēm uz maniem komentāriem', + 'notifications_save' => 'Saglabāt iestatījumus', + 'notifications_update_success' => 'Paziņojumu iestatījumi ir atjaunoti!', + 'notifications_watched' => 'Vērotie un ignorētie vienumi', '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' => 'Piekļuve un drošība', + 'auth_change_password' => 'Mainīt paroli', + 'auth_change_password_desc' => 'Mainīt paroli, ko izmantojat, lai piekļūtu aplikācijai. Tai jābūt vismaz 8 simbolus garai.', + 'auth_change_password_success' => 'Parole ir nomainīta!', - 'profile' => 'Profile Details', + 'profile' => 'Profila informācija', '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' => 'Skatīt publisko profilu', '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_email_desc' => 'Šis epasts tiks izmantots paziņojumiem un sistēmas piekļuvei, atkarībā no sistēmā uzstādītās autentifikācijas metodes.', + 'profile_email_no_permission' => 'Diemžēl jums nav tiesību mainīt savu epasta adresi. Ja vēlaties to mainīt, jums jāsazinās ar administratoru, lai tas nomaina šo adresi.', '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.', - 'delete_account' => 'Delete Account', - 'delete_my_account' => 'Delete My Account', + 'delete_account' => 'Dzēst kontu', + 'delete_my_account' => 'Izdzēst manu kontu', '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_my_account_warning' => 'Vai tiešām vēlaties dzēst savu kontu?', ]; diff --git a/lang/lv/settings.php b/lang/lv/settings.php index a443d497732..5c07cfc1d18 100644 --- a/lang/lv/settings.php +++ b/lang/lv/settings.php @@ -49,8 +49,8 @@ // Color settings 'color_scheme' => 'Lietotnes krāsu shēma', - '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.', + 'color_scheme_desc' => 'Uzstādiet krāsas, ko izmantot aplikācijas lietotātja saskarnē. Krāsas var uzstādīt atsevišķi gaišajam un tumšajam režīmam, lai labāk iederētos vizuālajā tēmā un nodrošinātu lasāmību.', + 'ui_colors_desc' => 'Uzstādiem aplikācijas primāro krāsu un noklusēto saišu krāsu. Primārā krāsa tiek izmantota galvenokārt lapas galvenē, uz pogām un saskarnes dekoratīvajos elementos. Noklusētā saišu krāsa tiek lietota teksta saitēm un darbībām gan izveidotajā saturā, gan aplikācijas saskarnē.', 'app_color' => 'Pamatkrāsa', 'link_color' => 'Noklusētā saišu krāsa', 'content_colors_desc' => 'Norādīt krāsas visiem lapas hierarhijas elementiem. Lasāmības labad ieteicams izvēlēties krāsas ar līdzīgu spilgtumu kā noklusētajām.', @@ -92,10 +92,10 @@ 'maint_send_test_email_mail_text' => 'Apsveicam! Tā kā jūs saņēmāt šo epasta paziņojumu, jūsu epasta uzstādījumi šķiet pareizi.', 'maint_recycle_bin_desc' => 'Dzēstie plaukti, grāmatas, nodaļas un lapas ir pārceltas uz miskasti, lai tos varētu atjaunot vai izdzēst pilnībā. Vecākas vienības miskastē var tikt automātiski dzēstas pēc kāda laika atkarībā no sistēmas uzstādījumiem.', 'maint_recycle_bin_open' => 'Atvērt miskasti', - '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' => 'Atjaunot atsauces', + 'maint_regen_references_desc' => 'Šī darbība no jauna izveidos atsauču indeksu datubāzē. Tas parasti notiek automātiski, taču šī darbība var palīdzēt, lai indeksētu vecāku saturu vai saturu, kas pievienots, izmantojot nestandarta metodes.', + 'maint_regen_references_success' => 'Atsauču indekss ir izveidots!', + 'maint_timeout_command_note' => 'Piezīme: Šī darbība var prasīt ilgāku laiku, kas var radīt pieprasījuma laika kļūmes (timeout) pie noteiktiem interneta vietnes uzstādījumiem. Alternatīva var būt veikt šo darbību, izmantojot termināla komandu.', // Recycle Bin 'recycle_bin' => 'Miskaste', @@ -214,8 +214,8 @@ 'users_social_accounts_info' => 'Te jūs varat pieslēgt citus kontus ātrākai un ērtākai piekļuvei. Konta atvienošana no šejienes neatceļ šai aplikācijai dotās tiesības šī konta piekļuvei. Atvienojtiet piekļuvi arī no jūsu profila uzstādījumiem pievienotajā sociālajā kontā.', 'users_social_connect' => 'Pievienot kontu', 'users_social_disconnect' => 'Atvienot kontu', - 'users_social_status_connected' => 'Connected', - 'users_social_status_disconnected' => 'Disconnected', + 'users_social_status_connected' => 'Savienots', + 'users_social_status_disconnected' => 'Atvienots', 'users_social_connected' => ':socialAccount konts veiksmīgi pieslēgts jūsu profilam.', 'users_social_disconnected' => ':socialAccount konts veiksmīgi atslēgts no jūsu profila.', 'users_api_tokens' => 'API žetoni', diff --git a/lang/nl/activities.php b/lang/nl/activities.php index 633ac888ebc..261583cc3a9 100644 --- a/lang/nl/activities.php +++ b/lang/nl/activities.php @@ -15,7 +15,7 @@ 'page_restore' => 'herstelde pagina', 'page_restore_notification' => 'Pagina succesvol hersteld', 'page_move' => 'verplaatste pagina', - 'page_move_notification' => 'Pagina met succes verplaatst', + 'page_move_notification' => 'Pagina succesvol verplaatst', // Chapters 'chapter_create' => 'maakte hoofdstuk', @@ -25,13 +25,13 @@ 'chapter_delete' => 'verwijderde hoofdstuk', 'chapter_delete_notification' => 'Hoofdstuk succesvol verwijderd', 'chapter_move' => 'verplaatste hoofdstuk', - 'chapter_move_notification' => 'Hoofdstuk met succes verplaatst', + 'chapter_move_notification' => 'Hoofdstuk succesvol verplaatst', // Books 'book_create' => 'maakte boek', 'book_create_notification' => 'Boek succesvol aangemaakt', - 'book_create_from_chapter' => 'heeft hoofdstuk geconverteerd naar boek', - 'book_create_from_chapter_notification' => 'Hoofdstuk is succesvol geconverteerd naar boekenplank', + 'book_create_from_chapter' => 'converteerde hoofdstuk naar boek', + 'book_create_from_chapter_notification' => 'Hoofdstuk succesvol geconverteerd naar een boek', 'book_update' => 'wijzigde boek', 'book_update_notification' => 'Boek succesvol bijgewerkt', 'book_delete' => 'verwijderde boek', @@ -40,14 +40,14 @@ 'book_sort_notification' => 'Boek succesvol opnieuw gesorteerd', // Bookshelves - 'bookshelf_create' => 'heeft boekenplank aangemaakt', - 'bookshelf_create_notification' => 'Boekenplank is succesvol aangemaakt', - 'bookshelf_create_from_book' => 'heeft boek geconverteerd naar boekenplank', - 'bookshelf_create_from_book_notification' => 'Boek is succesvol geconverteerd naar boekenplank', - 'bookshelf_update' => 'heeft boekenplank bijgewerkt', - 'bookshelf_update_notification' => 'Boekenplank is succesvol bijgewerkt', - 'bookshelf_delete' => 'heeft boekenplank verwijderd', - 'bookshelf_delete_notification' => 'Boekenplank is succesvol verwijderd', + 'bookshelf_create' => 'maakte boekenplank aan', + 'bookshelf_create_notification' => 'Boekenplank succesvol aangemaakt', + 'bookshelf_create_from_book' => 'converteerde boek naar boekenplank', + 'bookshelf_create_from_book_notification' => 'Boek succesvol geconverteerd naar boekenplank', + 'bookshelf_update' => 'werkte boekenplank bij', + 'bookshelf_update_notification' => 'Boekenplank succesvol bijgewerkt', + 'bookshelf_delete' => 'verwijderde boekenplank', + 'bookshelf_delete_notification' => 'Boekenplank succesvol verwijderd', // Revisions 'revision_restore' => 'herstelde revisie', @@ -62,50 +62,50 @@ 'watch_update_level_notification' => 'Volg voorkeuren succesvol aangepast', // Auth - 'auth_login' => 'heeft ingelogd', - 'auth_register' => 'geregistreerd als nieuwe gebruiker', - 'auth_password_reset_request' => 'heeft een nieuw gebruikerswachtwoord aangevraagd', - 'auth_password_reset_update' => 'heeft zijn gebruikerswachtwoord opnieuw ingesteld', - 'mfa_setup_method' => 'heeft zijn meervoudige verificatie methode ingesteld', - 'mfa_setup_method_notification' => 'Meervoudige verificatie methode is succesvol geconfigureerd', - 'mfa_remove_method' => 'heeft zijn meervoudige verificatie methode verwijderd', + 'auth_login' => 'logde in', + 'auth_register' => 'registreerde als nieuwe gebruiker', + 'auth_password_reset_request' => 'vraagde een nieuw gebruikerswachtwoord aan', + 'auth_password_reset_update' => 'stelde gebruikerswachtwoord opnieuw in', + 'mfa_setup_method' => 'stelde MFA-methode in', + 'mfa_setup_method_notification' => 'Meervoudige verificatie methode succesvol geconfigureerd', + 'mfa_remove_method' => 'verwijderde MFA-methode', 'mfa_remove_method_notification' => 'Meervoudige verificatie methode is succesvol verwijderd', // Settings - 'settings_update' => 'heeft de instellingen bijgewerkt', + 'settings_update' => 'werkte instellingen bij', 'settings_update_notification' => 'Instellingen met succes bijgewerkt', - 'maintenance_action_run' => 'heeft onderhoud uitgevoerd', + 'maintenance_action_run' => 'voerde onderhoudsactie uit', // Webhooks - 'webhook_create' => 'webhook aangemaakt', + 'webhook_create' => 'maakte webhook aan', 'webhook_create_notification' => 'Webhook succesvol aangemaakt', - 'webhook_update' => 'webhook bijgewerkt', + 'webhook_update' => 'werkte webhook bij', 'webhook_update_notification' => 'Webhook succesvol bijgewerkt', - 'webhook_delete' => 'webhook verwijderd', + 'webhook_delete' => 'verwijderde webhook', 'webhook_delete_notification' => 'Webhook succesvol verwijderd', // Users - 'user_create' => 'heeft gebruiker aangemaakt', + 'user_create' => 'maakte gebruiker aan', 'user_create_notification' => 'Gebruiker met succes aangemaakt', - 'user_update' => 'heeft gebruiker bijgewerkt', + 'user_update' => 'werkte gebruiker bij', 'user_update_notification' => 'Gebruiker succesvol bijgewerkt', - 'user_delete' => 'heeft gebruiker verwijderd', + 'user_delete' => 'verwijderde gebruiker', 'user_delete_notification' => 'Gebruiker succesvol verwijderd', // API Tokens - 'api_token_create' => 'heeft API token aangemaakt', - 'api_token_create_notification' => 'API token met succes aangemaakt', - 'api_token_update' => 'heeft API token bijgewerkt', - 'api_token_update_notification' => 'API token met succes bijgewerkt', - 'api_token_delete' => 'heeft API token verwijderd', - 'api_token_delete_notification' => 'API token met succes verwijderd', + 'api_token_create' => 'maakte api token aan', + 'api_token_create_notification' => 'API-token met succes aangemaakt', + 'api_token_update' => 'werkte api token bij', + 'api_token_update_notification' => 'API-token met succes bijgewerkt', + 'api_token_delete' => 'verwijderde api token', + 'api_token_delete_notification' => 'API-token met succes verwijderd', // Roles - 'role_create' => 'heeft rol aangemaakt', + 'role_create' => 'maakte rol aan', 'role_create_notification' => 'Rol succesvol aangemaakt', - 'role_update' => 'heeft rol bijgewerkt', + 'role_update' => 'werkte rol bij', 'role_update_notification' => 'Rol succesvol bijgewerkt', - 'role_delete' => 'heeft rol verwijderd', + 'role_delete' => 'verwijderde rol', 'role_delete_notification' => 'Rol succesvol verwijderd', // Recycle Bin @@ -115,9 +115,9 @@ // Comments 'commented_on' => 'reageerde op', - 'comment_create' => 'heeft opmerking toegevoegd', - 'comment_update' => 'heeft opmerking aangepast', - 'comment_delete' => 'heeft opmerking verwijderd', + 'comment_create' => 'voegde opmerking toe', + 'comment_update' => 'paste opmerking aan', + 'comment_delete' => 'verwijderde opmerking', // Other 'permissions_update' => 'wijzigde machtigingen', diff --git a/lang/nl/auth.php b/lang/nl/auth.php index dab15caca2a..1b974647ade 100644 --- a/lang/nl/auth.php +++ b/lang/nl/auth.php @@ -7,14 +7,14 @@ return [ 'failed' => 'Deze inloggegevens zijn niet bij ons bekend.', - 'throttle' => 'Te veel login pogingen! Probeer het opnieuw na :seconds seconden.', + 'throttle' => 'Te veel inlogpogingen! Probeer het opnieuw na :seconds seconden.', // Login & Register - 'sign_up' => 'Registreren', - 'log_in' => 'Inloggen', - 'log_in_with' => 'Login met :socialDriver', + 'sign_up' => 'Registreer', + 'log_in' => 'Log in', + 'log_in_with' => 'Log in met :socialDriver', 'sign_up_with' => 'Registreer met :socialDriver', - 'logout' => 'Uitloggen', + 'logout' => 'Log uit', 'name' => 'Naam', 'username' => 'Gebruikersnaam', @@ -23,7 +23,7 @@ 'password_confirm' => 'Wachtwoord Bevestigen', 'password_hint' => 'Moet uit minstens 8 tekens bestaan', 'forgot_password' => 'Wachtwoord vergeten?', - 'remember_me' => 'Mij onthouden', + 'remember_me' => 'Onthoud Mij', 'ldap_email_hint' => 'Geef een e-mailadres op voor dit account.', 'create_account' => 'Account aanmaken', 'already_have_account' => 'Heb je al een account?', @@ -87,7 +87,7 @@ 'mfa_setup_reconfigure' => 'Herconfigureren', 'mfa_setup_remove_confirmation' => 'Weet je zeker dat je deze multi-factor authenticatie methode wilt verwijderen?', 'mfa_setup_action' => 'Instellen', - 'mfa_backup_codes_usage_limit_warning' => 'U heeft minder dan 5 back-upcodes resterend. Genereer en sla een nieuwe set op voordat je geen codes meer hebt om te voorkomen dat je buiten je account wordt gesloten.', + 'mfa_backup_codes_usage_limit_warning' => 'U heeft minder dan 5 back-upcodes over. Genereer en sla een nieuwe set op voordat je geen codes meer hebt om te voorkomen dat je buiten je account wordt gesloten.', 'mfa_option_totp_title' => 'Mobiele app', 'mfa_option_totp_desc' => 'Om multi-factor authenticatie te gebruiken heeft u een mobiele applicatie nodig die TOTP ondersteunt, zoals Google Authenticator, Authy of Microsoft Authenticator.', 'mfa_option_backup_codes_title' => 'Back-up Codes', diff --git a/lang/nl/entities.php b/lang/nl/entities.php index 48625edd6a5..ee13185f697 100644 --- a/lang/nl/entities.php +++ b/lang/nl/entities.php @@ -6,24 +6,24 @@ return [ // Shared - 'recently_created' => 'Recent aangemaakt', - 'recently_created_pages' => 'Recent aangemaakte pagina\'s', + 'recently_created' => 'Recent gemaakt', + 'recently_created_pages' => 'Recent gemaakte pagina\'s', 'recently_updated_pages' => 'Recent bijgewerkte pagina\'s', - 'recently_created_chapters' => 'Recent aangemaakte hoofdstukken', - 'recently_created_books' => 'Recent aangemaakte boeken', - 'recently_created_shelves' => 'Recent aangemaakte boekenplanken', + 'recently_created_chapters' => 'Recent gemaakte hoofdstukken', + 'recently_created_books' => 'Recent gemaakte boeken', + 'recently_created_shelves' => 'Recent gemaakte boekenplanken', 'recently_update' => 'Recent bijgewerkt', 'recently_viewed' => 'Recent bekeken', 'recent_activity' => 'Recente activiteit', 'create_now' => 'Maak er nu één', 'revisions' => 'Revisies', 'meta_revision' => 'Revisie #:revisionCount', - 'meta_created' => 'Aangemaakt :timeLength', - 'meta_created_name' => 'Aangemaakt: :timeLength door :user', + 'meta_created' => 'Gemaakt op: :timeLength', + 'meta_created_name' => 'Gemaakt op :timeLength door :user', 'meta_updated' => 'Bijgewerkt: :timeLength', 'meta_updated_name' => 'Bijgewerkt: :timeLength door :user', 'meta_owned_name' => 'Eigendom van :user', - 'meta_reference_count' => 'Referenced by :count item|Referenced by :count items', + 'meta_reference_count' => 'Gerefereerd door :count item|Gerefereerd door :count items', 'entity_select' => 'Entiteit selecteren', 'entity_select_lack_permission' => 'Je hebt niet de vereiste machtiging om dit item te selecteren', 'images' => 'Afbeeldingen', @@ -32,7 +32,7 @@ 'my_most_viewed_favourites' => 'Mijn meest bekeken favorieten', 'my_favourites' => 'Mijn favorieten', 'no_pages_viewed' => 'Je hebt nog geen pagina\'s bekeken', - 'no_pages_recently_created' => 'Er zijn geen recent aangemaakte pagina\'s', + 'no_pages_recently_created' => 'Er zijn geen recent gemaakte pagina\'s', 'no_pages_recently_updated' => 'Er zijn geen pagina\'s recent bijgewerkt', 'export' => 'Exporteer', 'export_html' => 'Ingesloten webbestand', @@ -43,26 +43,26 @@ // Permissions and restrictions 'permissions' => 'Machtigingen', 'permissions_desc' => 'Stel hier machtigingen in om de standaardmachtigingen van gebruikersrollen te overschrijven.', - 'permissions_book_cascade' => 'Machtigingen voor boeken worden automatisch doorgegeven aan hoofdstukken en pagina\'s, tenzij deze hun eigen machtigingen hebben.', - 'permissions_chapter_cascade' => 'Machtigingen ingesteld op hoofdstukken zullen automatisch worden doorgegeven aan onderliggende pagina\'s, tenzij deze hun eigen machtigingen hebben.', + 'permissions_book_cascade' => 'Machtigingen voor boeken worden automatisch doorgegeven aan hoofdstukken en pagina\'s, behalve als deze hun eigen machtigingen hebben.', + 'permissions_chapter_cascade' => 'Machtigingen ingesteld op hoofdstukken zullen automatisch worden doorgegeven aan onderliggende pagina\'s, behalve als deze hun eigen machtigingen hebben.', 'permissions_save' => 'Machtigingen opslaan', 'permissions_owner' => 'Eigenaar', 'permissions_role_everyone_else' => 'De rest', - 'permissions_role_everyone_else_desc' => 'Stel machtigingen in voor alle rollen die niet specifiek overschreven worden.', + 'permissions_role_everyone_else_desc' => 'Stel machtigingen in voor alle rollen die niet specifiek overschreven zijn.', 'permissions_role_override' => 'Overschrijf machtigingen voor rol', 'permissions_inherit_defaults' => 'Standaardwaarden overnemen', // Search 'search_results' => 'Zoekresultaten', - 'search_total_results_found' => ':count resultaten gevonden|:count totaal aantal resultaten gevonden', + 'search_total_results_found' => ':count resultaten gevonden|totaal :count resultaten gevonden', 'search_clear' => 'Zoekopdracht wissen', - 'search_no_pages' => 'Er zijn geen pagina\'s gevonden', + 'search_no_pages' => 'Geen pagina\'s gevonden die overeenkomen met deze zoekopdracht', 'search_for_term' => 'Zoeken op :term', 'search_more' => 'Meer resultaten', 'search_advanced' => 'Uitgebreid zoeken', 'search_terms' => 'Zoektermen', 'search_content_type' => 'Inhoudstype', - 'search_exact_matches' => 'Exacte matches', + 'search_exact_matches' => 'Exacte overeenkomsten', 'search_tags' => 'Label Zoekopdrachten', 'search_options' => 'Opties', 'search_viewed_by_me' => 'Bekeken door mij', @@ -74,8 +74,8 @@ 'search_date_options' => 'Datum opties', 'search_updated_before' => 'Bijgewerkt voor', 'search_updated_after' => 'Bijgewerkt na', - 'search_created_before' => 'Aangemaakt voor', - 'search_created_after' => 'Aangemaakt na', + 'search_created_before' => 'Gemaakt voor', + 'search_created_after' => 'Gemaakt na', 'search_set_date' => 'Stel datum in', 'search_update' => 'Update zoekresultaten', @@ -83,13 +83,13 @@ 'shelf' => 'Boekenplank', 'shelves' => 'Boekenplanken', 'x_shelves' => ':count Boekenplank|:count Boekenplanken', - 'shelves_empty' => 'Er zijn geen boekenplanken aangemaakt', + 'shelves_empty' => 'Er zijn geen boekenplanken gemaakt', 'shelves_create' => 'Nieuwe boekenplank maken', 'shelves_popular' => 'Populaire boekenplanken', 'shelves_new' => 'Nieuwe boekenplanken', 'shelves_new_action' => 'Nieuwe boekenplank', 'shelves_popular_empty' => 'De meest populaire boekenplanken worden hier weergegeven.', - 'shelves_new_empty' => 'De meest recent aangemaakte boekenplanken worden hier weergeven.', + 'shelves_new_empty' => 'De meest recent gemaakte boekenplanken worden hier weergeven.', 'shelves_save' => 'Boekenplank opslaan', 'shelves_books' => 'Boeken op deze plank', 'shelves_add_books' => 'Voeg boeken toe aan deze plank', @@ -106,23 +106,23 @@ 'shelves_permissions_updated' => 'Boekenplank Machtigingen Bijgewerkt', 'shelves_permissions_active' => 'Machtigingen op Boekenplank Actief', 'shelves_permissions_cascade_warning' => 'De ingestelde machtigingen op deze boekenplank worden niet automatisch toegepast op de boeken van deze boekenplank. Dit is omdat een boek toegekend kan worden op meerdere boekenplanken. De machtigingen van deze boekenplank kunnen echter wel gekopieerd worden naar de boeken van deze boekenplank via de optie hieronder.', - 'shelves_permissions_create' => '\'Maak boekenplank\' machtigingen worden enkel gebruikt om machtigingen te kopiëren naar boeken binnenin een boekenplank door gebruik te maken van onderstaande actie. Deze machtigingen laten niet toe om een nieuw boek aan te maken.', + 'shelves_permissions_create' => '\'Maak boekenplank\' machtigingen worden enkel gebruikt om machtigingen te kopiëren naar boeken binnenin een boekenplank door gebruik te maken van onderstaande actie. Deze machtigingen beheren het maken van boeken niet.', 'shelves_copy_permissions_to_books' => 'Kopieer Machtigingen naar Boeken', 'shelves_copy_permissions' => 'Kopieer Machtigingen', - 'shelves_copy_permissions_explain' => 'Met deze actie worden de machtigingen van deze boekenplank gekopieërd naar alle boeken van deze boekenplank. Voor je deze actie uitvoert, moet je ervoor zorgen dat alle wijzigingen in de machtigingen van deze boekenplank zijn opgeslagen.', - 'shelves_copy_permission_success' => 'Boekenplank machtingen gekopieerd naar :count boeken', + 'shelves_copy_permissions_explain' => 'Met deze actie worden de machtigingen van deze boekenplank gekopieerd naar alle boeken van deze boekenplank. Voor je deze actie uitvoert, moet je ervoor zorgen dat alle wijzigingen in de machtigingen van deze boekenplank zijn opgeslagen.', + 'shelves_copy_permission_success' => 'Boekenplank machtigingen gekopieerd naar :count boeken', // Books 'book' => 'Boek', 'books' => 'Boeken', 'x_books' => ':count Boek|:count Boeken', - 'books_empty' => 'Er zijn geen boeken aangemaakt', + 'books_empty' => 'Geen boeken gemaakt', 'books_popular' => 'Populaire boeken', 'books_recent' => 'Recente boeken', 'books_new' => 'Nieuwe boeken', 'books_new_action' => 'Nieuw boek', 'books_popular_empty' => 'De meest populaire boeken worden hier weergegeven.', - 'books_new_empty' => 'De meest recent aangemaakte boeken verschijnen hier.', + 'books_new_empty' => 'De meest recent gemaakte boeken verschijnen hier.', 'books_create' => 'Nieuw boek maken', 'books_delete' => 'Boek verwijderen', 'books_delete_named' => 'Verwijder boek :bookName', @@ -132,9 +132,9 @@ '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_default_template' => 'Standaard Paginasjabloon', + 'books_default_template_explain' => 'Wijs een paginasjabloon toe die zal worden gebruikt als de standaardinhoud voor alle nieuwe pagina\'s in dit boek. Bedenk wel dat dit sjabloon alleen gebruikt wordt als de paginamaker machtiging heeft om die te bekijken.', + 'books_default_template_select' => 'Selecteer een sjabloonpagina', '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.', @@ -145,7 +145,7 @@ 'books_search_this' => 'Zoeken in dit boek', 'books_navigation' => 'Boek navigatie', 'books_sort' => 'Inhoud van het boek sorteren', - 'books_sort_desc' => 'Verplaats hoofdstukken en pagina\'s binnen een boek om de inhoud ervan te reorganiseren. Andere boeken kunnen worden toegevoegd, zodat hoofdstukken en pagina\'s gemakkelijk tussen boeken kunnen worden verplaatst.', + 'books_sort_desc' => 'Verplaats hoofdstukken en pagina\'s binnen een boek om ze te organiseren. Andere boeken kunnen worden toegevoegd, zodat hoofdstukken en pagina\'s gemakkelijk tussen boeken kunnen worden verplaatst.', 'books_sort_named' => 'Sorteer boek :bookName', 'books_sort_name' => 'Sorteren op naam', 'books_sort_created' => 'Sorteren op datum van aanmaken', @@ -177,7 +177,7 @@ 'chapters_create' => 'Nieuw hoofdstuk maken', 'chapters_delete' => 'Hoofdstuk verwijderen', 'chapters_delete_named' => 'Verwijder hoofdstuk :chapterName', - 'chapters_delete_explain' => 'Dit verwijdert het hoofdstuk met de naam \':chapterName\'. Alle pagina\'s die binnen dit hoofdstuk staan, worden ook verwijderd.', + 'chapters_delete_explain' => 'Dit verwijdert het hoofdstuk met de naam \':chapterName\'. Alle pagina\'s in dit hoofdstuk zullen ook worden verwijderd.', 'chapters_delete_confirm' => 'Weet je zeker dat je dit hoofdstuk wilt verwijderen?', 'chapters_edit' => 'Hoofdstuk aanpassen', 'chapters_edit_named' => 'Hoofdstuk :chapterName aanpassen', @@ -187,10 +187,10 @@ 'chapters_copy' => 'Kopieer Hoofdstuk', 'chapters_copy_success' => 'Hoofdstuk succesvol gekopieerd', 'chapters_permissions' => 'Hoofdstuk Machtigingen', - 'chapters_empty' => 'Er zijn geen pagina\'s in dit hoofdstuk aangemaakt.', + 'chapters_empty' => 'Dit hoofdstuk heeft op dit moment geen pagina\'s.', 'chapters_permissions_active' => 'Hoofdstuk Machtigingen Actief', 'chapters_permissions_success' => 'Hoofdstuk Machtigingen Bijgewerkt', - 'chapters_search_this' => 'Doorzoek dit hoofdstuk', + 'chapters_search_this' => 'Zoek in dit hoofdstuk', 'chapter_sort_book' => 'Sorteer Boek', // Pages @@ -202,15 +202,15 @@ 'pages_attachments' => 'Bijlages', 'pages_navigation' => 'Pagina navigatie', 'pages_delete' => 'Pagina verwijderen', - 'pages_delete_named' => 'Verwijderd pagina :pageName', + 'pages_delete_named' => 'Verwijder pagina :pageName', 'pages_delete_draft_named' => 'Verwijder concept pagina :pageName', '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_warning_template' => 'Deze pagina is actief in gebruik als standaard paginasjabloon. Deze boeken zullen geen standaard paginasjabloon meer hebben als deze pagina verwijderd is.', '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', + 'pages_editing_named' => 'Pagina :pageName aan het bewerken', 'pages_edit_draft_options' => 'Concept opties', 'pages_edit_save_draft' => 'Concept opslaan', 'pages_edit_draft' => 'Paginaconcept bewerken', @@ -220,36 +220,36 @@ 'pages_edit_delete_draft' => 'Concept verwijderen', 'pages_edit_delete_draft_confirm' => 'Weet je zeker dat je de wijzigingen in je concept wilt verwijderen? Al je wijzigingen sinds de laatste succesvolle bewaring gaan verloren en de editor wordt bijgewerkt met de meest recente niet-concept versie van de pagina.', 'pages_edit_discard_draft' => 'Concept verwijderen', - 'pages_edit_switch_to_markdown' => 'Verander naar Markdown Bewerker', - 'pages_edit_switch_to_markdown_clean' => '(Schoongemaakte Inhoud)', + 'pages_edit_switch_to_markdown' => 'Schakel naar de Markdown Bewerker', + 'pages_edit_switch_to_markdown_clean' => '(Opgeschoonde Inhoud)', 'pages_edit_switch_to_markdown_stable' => '(Stabiele Inhoud)', - 'pages_edit_switch_to_wysiwyg' => 'Verander naar WYSIWYG Bewerker', - 'pages_edit_set_changelog' => 'Wijzigingslogboek instellen', + 'pages_edit_switch_to_wysiwyg' => 'Schakel naar de WYSIWYG Bewerker', + 'pages_edit_set_changelog' => 'Logboek instellen', 'pages_edit_enter_changelog_desc' => 'Geef een korte omschrijving van de wijzigingen die je gemaakt hebt', - 'pages_edit_enter_changelog' => 'Voeg toe aan wijzigingslogboek', - 'pages_editor_switch_title' => 'Wijzig Bewerker', + 'pages_edit_enter_changelog' => 'Voeg toe aan logboek', + 'pages_editor_switch_title' => 'Schakel Bewerker', 'pages_editor_switch_are_you_sure' => 'Weet u zeker dat u de bewerker voor deze pagina wilt wijzigen?', 'pages_editor_switch_consider_following' => 'Houd rekening met het volgende als u van bewerker verandert:', 'pages_editor_switch_consideration_a' => 'Eenmaal opgeslagen, zal de nieuwe bewerker keuze gebruikt worden door alle toekomstige gebruikers, ook diegene die zelf niet van bewerker type kunnen veranderen.', - 'pages_editor_switch_consideration_b' => 'Dit kan mogelijks tot een verlies van detail en syntax leiden in bepaalde omstandigheden.', - 'pages_editor_switch_consideration_c' => 'De veranderingen aan Labels of aan het wijzigingslogboek, sinds de laatste keer opslaan, zullen niet behouden blijven met deze wijziging.', + 'pages_editor_switch_consideration_b' => 'Dit kan mogelijk tot een verlies van detail en syntaxis leiden in bepaalde omstandigheden.', + 'pages_editor_switch_consideration_c' => 'De veranderingen aan Labels of aan het logboek, sinds de laatste keer opslaan, zullen niet behouden blijven met deze wijziging.', 'pages_save' => 'Pagina opslaan', 'pages_title' => 'Pagina titel', 'pages_name' => 'Pagina naam', 'pages_md_editor' => 'Bewerker', 'pages_md_preview' => 'Voorbeeld', 'pages_md_insert_image' => 'Afbeelding invoegen', - 'pages_md_insert_link' => 'Entity link invoegen', + 'pages_md_insert_link' => 'Entiteit link invoegen', 'pages_md_insert_drawing' => 'Tekening invoegen', - 'pages_md_show_preview' => 'Toon preview', - 'pages_md_sync_scroll' => 'Synchroniseer preview scroll', + 'pages_md_show_preview' => 'Toon voorbeeld', + 'pages_md_sync_scroll' => 'Synchroniseer scrollen van voorbeeld', 'pages_drawing_unsaved' => 'Niet-opgeslagen Tekening Gevonden', 'pages_drawing_unsaved_confirm' => 'Er zijn niet-opgeslagen tekeninggegevens gevonden van een eerdere mislukte poging om de tekening op te slaan. Wilt u deze niet-opgeslagen tekening herstellen en verder bewerken?', - 'pages_not_in_chapter' => 'Deze pagina staat niet in een hoofdstuk', + 'pages_not_in_chapter' => 'Pagina is niet in een hoofdstuk', 'pages_move' => 'Pagina verplaatsten', 'pages_copy' => 'Pagina kopiëren', 'pages_copy_desination' => 'Kopieër bestemming', - 'pages_copy_success' => 'Pagina succesvol gekopieërd', + 'pages_copy_success' => 'Pagina succesvol gekopieerd', 'pages_permissions' => 'Pagina Machtigingen', 'pages_permissions_success' => 'Pagina machtigingen bijgewerkt', 'pages_revision' => 'Revisie', @@ -258,21 +258,21 @@ 'pages_revisions_named' => 'Pagina revisies voor :pageName', 'pages_revision_named' => 'Pagina revisie voor :pageName', 'pages_revision_restored_from' => 'Hersteld van #:id; :samenvatting', - 'pages_revisions_created_by' => 'Aangemaakt door', + 'pages_revisions_created_by' => 'Gemaakt door', 'pages_revisions_date' => 'Revisiedatum', 'pages_revisions_number' => '#', 'pages_revisions_sort_number' => 'Versie Nummer', 'pages_revisions_numbered' => 'Revisie #:id', 'pages_revisions_numbered_changes' => 'Revisie #:id wijzigingen', 'pages_revisions_editor' => 'Bewerker Type', - 'pages_revisions_changelog' => 'Wijzigingsoverzicht', + 'pages_revisions_changelog' => 'Logboek', 'pages_revisions_changes' => 'Wijzigingen', 'pages_revisions_current' => 'Huidige versie', 'pages_revisions_preview' => 'Voorbeeld', 'pages_revisions_restore' => 'Herstellen', 'pages_revisions_none' => 'Deze pagina heeft geen revisies', 'pages_copy_link' => 'Link kopiëren', - 'pages_edit_content_link' => 'Spring naar sectie in editor', + 'pages_edit_content_link' => 'Ga naar sectie in bewerker', 'pages_pointer_enter_mode' => 'Open selectiemodus per onderdeel', 'pages_pointer_label' => 'Pagina Onderdeel Opties', 'pages_pointer_permalink' => 'Pagina Onderdeel Permalink', @@ -285,16 +285,16 @@ 'pages_initial_name' => 'Nieuwe pagina', 'pages_editing_draft_notification' => 'U bewerkt momenteel een concept dat voor het laatst is opgeslagen op :timeDiff.', 'pages_draft_edited_notification' => 'Deze pagina is sindsdien bijgewerkt. Het wordt aanbevolen dat u dit concept verwijderd.', - 'pages_draft_page_changed_since_creation' => 'Deze pagina is bijgewerkt sinds het aanmaken van dit concept. Het wordt aanbevolen dat u dit ontwerp verwijdert of ervoor zorgt dat u wijzigingen op de pagina niet overschrijft.', + 'pages_draft_page_changed_since_creation' => 'Deze pagina is bijgewerkt sinds het aanmaken van dit concept. Het wordt aanbevolen dat u dit concept verwijdert of ervoor zorgt dat u wijzigingen op de pagina niet overschrijft.', 'pages_draft_edit_active' => [ 'start_a' => ':count gebruikers zijn begonnen deze pagina te bewerken', 'start_b' => ':userName is begonnen met het bewerken van deze pagina', - 'time_a' => 'since the pages was last updated', + 'time_a' => 'sinds de laatste pagina-update', 'time_b' => 'in de laatste :minCount minuten', 'message' => ':start :time. Let op om elkaars updates niet te overschrijven!', ], - 'pages_draft_discarded' => 'Concept verwporpen! De editor is bijgewerkt met de huidige inhoud van de pagina', - 'pages_draft_deleted' => 'Concept verwijderd! De editor is bijgewerkt met de huidige inhoud van de pagina', + 'pages_draft_discarded' => 'Concept verworpen! De bewerker is bijgewerkt met de huidige inhoud van de pagina', + 'pages_draft_deleted' => 'Concept verwijderd! De bewerker is bijgewerkt met de huidige inhoud van de pagina', 'pages_specific' => 'Specifieke pagina', 'pages_is_template' => 'Paginasjabloon', @@ -312,7 +312,7 @@ 'tags_explain' => "Voeg enkele labels toe om uw inhoud beter te categoriseren. \nJe kunt een waarde aan een label toekennen voor een meer gedetailleerde organisatie.", 'tags_add' => 'Voeg nog een label toe', 'tags_remove' => 'Verwijder deze label', - 'tags_usages' => 'Totaal aantal gebruikte labels', + 'tags_usages' => 'Totaal aantal label-toepassingen', 'tags_assigned_pages' => 'Toegewezen aan pagina\'s', 'tags_assigned_chapters' => 'Toegewezen aan hoofdstukken', 'tags_assigned_books' => 'Toegewezen aan boeken', @@ -327,7 +327,7 @@ 'attachments_explain_instant_save' => 'Wijzigingen worden meteen opgeslagen.', 'attachments_upload' => 'Bestand uploaden', 'attachments_link' => 'Link toevoegen', - 'attachments_upload_drop' => 'Of je kan een bestand hiernaartoe slepen om het als bijlage te uploaden.', + 'attachments_upload_drop' => 'Je kan ook een bestand hiernaartoe slepen om het als bijlage to uploaden.', 'attachments_set_link' => 'Zet link', 'attachments_delete' => 'Weet u zeker dat u deze bijlage wilt verwijderen?', 'attachments_dropzone' => 'Sleep hier de bestanden naar toe', @@ -357,11 +357,11 @@ // Profile View 'profile_user_for_x' => 'Lid sinds :time', - 'profile_created_content' => 'Aangemaakte Inhoud', + 'profile_created_content' => 'Gemaakte Inhoud', 'profile_not_created_pages' => ':userName heeft geen pagina\'s gemaakt', 'profile_not_created_chapters' => ':userName heeft geen hoofdstukken gemaakt', 'profile_not_created_books' => ':userName heeft geen boeken gemaakt', - 'profile_not_created_shelves' => ':userName heeft nog geen boekenplanken gemaakt', + 'profile_not_created_shelves' => ':userName heeft geen boekenplanken gemaakt', // Comments 'comment' => 'Reactie', @@ -392,7 +392,7 @@ 'copy_consider_owner' => 'Je wordt de eigenaar van alle gekopieerde inhoud.', 'copy_consider_images' => 'Afbeeldingsbestanden worden niet gedupliceerd & de originele afbeeldingen behouden hun koppeling met de pagina waarop ze oorspronkelijk werden geüpload.', 'copy_consider_attachments' => 'Pagina bijlagen worden niet gekopieerd.', - 'copy_consider_access' => 'Een verandering van locatie, eigenaar of machtigingen kan ertoe leiden dat deze inhoud toegankelijk wordt voor personen die er voordien geen toegang tot hadden.', + 'copy_consider_access' => 'Een verandering van locatie, eigenaar of machtigingen kan ertoe leiden dat deze inhoud toegankelijk wordt voor personen die eerder geen toegang hadden.', // Conversions 'convert_to_shelf' => 'Converteer naar Boekenplank', @@ -408,8 +408,8 @@ // References 'references' => 'Verwijzingen', - 'references_none' => 'Er zijn geen verwijzingen naar dit artikel bijgehouden.', - 'references_to_desc' => 'Listed below is all the known content in the system that links to this item.', + 'references_none' => 'Er zijn geen verwijzingen naar dit item bijgehouden.', + 'references_to_desc' => 'Hieronder is alle inhoud in het systeem dat naar dit item linkt vermeld.', // Watch Options 'watch' => 'Volg', diff --git a/lang/nl/errors.php b/lang/nl/errors.php index 7a026615a16..3fa1d94f7e1 100644 --- a/lang/nl/errors.php +++ b/lang/nl/errors.php @@ -106,9 +106,9 @@ // API errors 'api_no_authorization_found' => 'Geen autorisatie token gevonden', 'api_bad_authorization_format' => 'Een autorisatie token is gevonden, maar het formaat schijnt onjuist te zijn', - 'api_user_token_not_found' => 'Er is geen overeenkomende API token gevonden voor de opgegeven autorisatie token', - 'api_incorrect_token_secret' => 'Het opgegeven geheim voor de API token is onjuist', - 'api_user_no_api_permission' => 'De eigenaar van de gebruikte API token heeft geen machtiging om API calls te maken', + 'api_user_token_not_found' => 'Er is geen overeenkomende API-token gevonden voor de opgegeven autorisatie token', + 'api_incorrect_token_secret' => 'Het opgegeven geheim voor de API-token is onjuist', + 'api_user_no_api_permission' => 'De eigenaar van de gebruikte API-token heeft geen machtiging om API calls te maken', 'api_user_token_expired' => 'De gebruikte autorisatie token is verlopen', // Settings & Maintenance diff --git a/lang/nl/settings.php b/lang/nl/settings.php index c6e2ad2aed5..014153e536c 100644 --- a/lang/nl/settings.php +++ b/lang/nl/settings.php @@ -109,7 +109,7 @@ 'recycle_bin_contents_empty' => 'De prullenbak is momenteel leeg', 'recycle_bin_empty' => 'Prullenbak legen', 'recycle_bin_empty_confirm' => 'Dit zal permanent alle items in de prullenbak vernietigen, inclusief de inhoud die in elk item zit. Weet u zeker dat u de prullenbak wilt legen?', - 'recycle_bin_destroy_confirm' => 'Deze actie zal dit item permanent verwijderen, samen met alle onderliggende elementen hieronder vanuit het systeem en u kunt deze inhoud niet herstellen. Weet u zeker dat u dit item permanent wilt verwijderen?', + 'recycle_bin_destroy_confirm' => 'Deze actie zal dit item permanent uit het systeem verwijderen, samen met alle onderliggende elementen, en u kunt deze inhoud niet herstellen. Weet u zeker dat u dit item permanent wil verwijderen?', 'recycle_bin_destroy_list' => 'Te vernietigen items', 'recycle_bin_restore_list' => 'Items te herstellen', 'recycle_bin_restore_confirm' => 'Deze actie herstelt het verwijderde item, inclusief alle onderliggende elementen, op hun oorspronkelijke locatie. Als de oorspronkelijke locatie sindsdien is verwijderd en zich nu in de prullenbak bevindt, zal ook het bovenliggende item moeten worden hersteld.', @@ -216,14 +216,14 @@ 'users_social_disconnect' => 'Account Ontkoppelen', 'users_social_status_connected' => 'Verbonden', 'users_social_status_disconnected' => 'Verbroken', - 'users_social_connected' => ':socialAccount account is succesvol aan je profiel gekoppeld.', - 'users_social_disconnected' => ':socialAccount account is succesvol ontkoppeld van je profiel.', - 'users_api_tokens' => 'API Tokens', + 'users_social_connected' => ':socialAccount account succesvol aan je profiel gekoppeld.', + 'users_social_disconnected' => ':socialAccount account succesvol ontkoppeld van je profiel.', + 'users_api_tokens' => 'API-Tokens', 'users_api_tokens_desc' => 'Creëer en beheer de toegangstokens die gebruikt worden om te authenticeren met de BookStack REST API. Machtigingen voor de API worden beheerd via de gebruiker waartoe het token behoort.', 'users_api_tokens_none' => 'Er zijn geen API-tokens gemaakt voor deze gebruiker', 'users_api_tokens_create' => 'Token aanmaken', 'users_api_tokens_expires' => 'Verloopt', - 'users_api_tokens_docs' => 'API Documentatie', + 'users_api_tokens_docs' => 'API-Documentatie', 'users_mfa' => 'Meervoudige Verificatie', 'users_mfa_desc' => 'Stel meervoudige verificatie in als extra beveiligingslaag voor uw gebruikersaccount.', 'users_mfa_x_methods' => ':count methode geconfigureerd|:count methoden geconfigureerd', @@ -236,11 +236,11 @@ 'user_api_token_expiry' => 'Vervaldatum', 'user_api_token_expiry_desc' => 'Stel een datum in waarop deze token verloopt. Na deze datum zullen aanvragen die met deze token zijn ingediend niet langer werken. Als dit veld leeg blijft, wordt een vervaldatum van 100 jaar in de toekomst ingesteld.', 'user_api_token_create_secret_message' => 'Onmiddellijk na het aanmaken van dit token zal een "Token ID" en "Token Geheim" worden gegenereerd en weergegeven. Het geheim zal slechts één keer getoond worden. Kopieer de waarde dus eerst op een veilige plaats voordat u doorgaat.', - 'user_api_token' => 'API Token', + 'user_api_token' => 'API-Token', 'user_api_token_id' => 'Token ID', 'user_api_token_id_desc' => 'Dit is een niet-wijzigbare, door het systeem gegenereerde identificatiecode voor dit token, die in API-verzoeken moet worden verstrekt.', 'user_api_token_secret' => 'Geheime token sleutel', - 'user_api_token_secret_desc' => 'Dit is een door het systeem gegenereerd geheim voor dit token dat in API verzoeken zal moeten worden verstrekt. Dit zal slechts één keer worden weergegeven, dus kopieer deze waarde naar een veilige plaats.', + 'user_api_token_secret_desc' => 'Dit is een door het systeem gegenereerd geheim voor dit token dat in API-verzoeken zal moeten worden verstrekt. Dit zal slechts één keer worden weergegeven, dus kopieer deze waarde naar een veilige plaats.', 'user_api_token_created' => 'Token :timeAgo geleden aangemaakt', 'user_api_token_updated' => 'Token :timeAgo geleden bijgewerkt', 'user_api_token_delete' => 'Token Verwijderen', diff --git a/lang/sq/activities.php b/lang/sq/activities.php index d5b55c03dcb..1c7a10310c1 100644 --- a/lang/sq/activities.php +++ b/lang/sq/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' => 'krijoi faqe', + 'page_create_notification' => 'Faqja u krijua me sukses', + 'page_update' => 'përditësoi faqe', + 'page_update_notification' => 'Faqja u përditësua me sukses', + 'page_delete' => 'fshiu faqe', + 'page_delete_notification' => 'Faqja u fshi me sukses', + 'page_restore' => 'riktheu faqe', + 'page_restore_notification' => 'Faqja u rikthye me sukses', + 'page_move' => 'zhvendosi faqe', + 'page_move_notification' => 'Faqja u zhvendos me sukses', // 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' => 'krijoi kapitull', + 'chapter_create_notification' => 'Kapitulli u krijua me sukses', + 'chapter_update' => 'përditësoi kapitull', + 'chapter_update_notification' => 'Kapitulli u përditësua me sukses', + 'chapter_delete' => 'fshiu kapitull', + 'chapter_delete_notification' => 'Kapitulli u fshi me sukses', + 'chapter_move' => 'zhvendosi kapitull', + 'chapter_move_notification' => 'Kapitulli u zhvendos me sukses', // 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' => 'krijoi libër', + 'book_create_notification' => 'Libri u krijua me sukses', + 'book_create_from_chapter' => 'konvertoi kapitullin në libër', + 'book_create_from_chapter_notification' => 'Kapitulli u konvertua në libër me sukses', + 'book_update' => 'përditësoi libër', + 'book_update_notification' => 'Libri u përditësua me sukses', + 'book_delete' => 'fshiu libër', + 'book_delete_notification' => 'Libri u fshi me sukses', + 'book_sort' => 'renditi libër', + 'book_sort_notification' => 'Libri u rendit me sukses', // 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' => 'krijoi raft', + 'bookshelf_create_notification' => 'Rafti u krijua me sukses', + 'bookshelf_create_from_book' => 'konvertoi librin në raft', + 'bookshelf_create_from_book_notification' => 'Libri u konvertua ne raft me sukses', + 'bookshelf_update' => 'përditësoi raftin', + 'bookshelf_update_notification' => 'Rafti u përditësua me sukses', + 'bookshelf_delete' => 'fshiu raftin', + 'bookshelf_delete_notification' => 'Rafti u fshi me sukses', // Revisions - 'revision_restore' => 'restored revision', - 'revision_delete' => 'deleted revision', - 'revision_delete_notification' => 'Revision successfully deleted', + 'revision_restore' => 'riktheu rishikimin', + 'revision_delete' => 'fshiu rishikimin', + 'revision_delete_notification' => 'Rishikimi u fshi me sukses', // Favourites - 'favourite_add_notification' => '":name" has been added to your favourites', - 'favourite_remove_notification' => '":name" has been removed from your favourites', + 'favourite_add_notification' => '":emri" është shtuar në listën tuaj të të preferuarve', + 'favourite_remove_notification' => '":emri" është hequr nga lista juaj e të preferuarve', // Watching - 'watch_update_level_notification' => 'Watch preferences successfully updated', + 'watch_update_level_notification' => 'Preferencat e orës u përditësuan me sukses', // 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' => 'loguar', + 'auth_register' => 'regjistruar si përdorues i ri', + 'auth_password_reset_request' => 'kërkoi rivendosjen e fjalëkalimit të përdoruesit', + 'auth_password_reset_update' => 'rivendos fjalëkalimin e përdoruesit', + 'mfa_setup_method' => 'konfiguroi metodën MFA', + 'mfa_setup_method_notification' => 'Metoda Multi-factor u konfigurua me sukses', + 'mfa_remove_method' => 'hoqi metodën MFA', + 'mfa_remove_method_notification' => 'Metoda Multi-factor u hoq me sukses', // Settings - 'settings_update' => 'updated settings', - 'settings_update_notification' => 'Settings successfully updated', - 'maintenance_action_run' => 'ran maintenance action', + 'settings_update' => 'përditësoi cilësimet', + 'settings_update_notification' => 'Cilësimet u përditësuan me sukses', + 'maintenance_action_run' => 'u zhvillua veprim i mirëmbajtjes', // 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' => 'u krijua uebhook', + 'webhook_create_notification' => 'Uebhook-u u krijua me sukses', + 'webhook_update' => 'përditësoi uebhook', + 'webhook_update_notification' => 'Uebhook-u u përditësua me sukses', + 'webhook_delete' => 'fshiu uebhook', + 'webhook_delete_notification' => 'Uebhook-u u fshi me sukses', // 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' => 'krijoi përdorues', + 'user_create_notification' => 'Përdoruesi u krijua me sukses', + 'user_update' => 'përditësoi përdorues', + 'user_update_notification' => 'Përdoruesi u përditësua me sukses', + 'user_delete' => 'fshi përdorues', + 'user_delete_notification' => 'Përdoruesi u fshi me sukses', // 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' => 'krijoi token api', + 'api_token_create_notification' => 'Token API u krijua me sukses', + 'api_token_update' => 'përditësoi token api', + 'api_token_update_notification' => 'Token API u përditësua me sukses', + 'api_token_delete' => 'fshiu token api', + 'api_token_delete_notification' => 'Token API u fshi me sukses', // 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' => 'krijoi rol', + 'role_create_notification' => 'Roli u krijua me sukses', + 'role_update' => 'përditësoi rol', + 'role_update_notification' => 'Roli u përditësua me sukses', + 'role_delete' => 'fshiu rol', + 'role_delete_notification' => 'Roli u fshi me sukses', // 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' => 'boshatisi koshin e riciklimit', + 'recycle_bin_restore' => 'riktheu nga koshi i riciklimit', + 'recycle_bin_destroy' => 'fshiu nga koshi i riciklimit', // Comments - 'commented_on' => 'commented on', - 'comment_create' => 'added comment', - 'comment_update' => 'updated comment', - 'comment_delete' => 'deleted comment', + 'commented_on' => 'komentoi në', + 'comment_create' => 'shtoi koment', + 'comment_update' => 'përditësoi koment', + 'comment_delete' => 'fshiu koment', // Other - 'permissions_update' => 'updated permissions', + 'permissions_update' => 'përditësoi lejet', ]; diff --git a/lang/sq/auth.php b/lang/sq/auth.php index dc4b242a09e..08af155e88f 100644 --- a/lang/sq/auth.php +++ b/lang/sq/auth.php @@ -6,37 +6,37 @@ */ return [ - 'failed' => 'These credentials do not match our records.', - 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', + 'failed' => 'Këto kredenciale nuk përputhen me të dhënat tona.', + 'throttle' => 'Shumë përpjekje për hyrje. Ju lutemi provoni përsëri në :seconds sekonda.', // 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' => 'Regjistrohu', + 'log_in' => 'Logohu', + 'log_in_with' => 'Logohu me :socialDriver', + 'sign_up_with' => 'Regjistrohu me :socialDriver', + 'logout' => 'Shkyçu', - 'name' => 'Name', - 'username' => 'Username', + 'name' => 'Emri', + 'username' => 'Emri i përdoruesit', '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?', + 'password' => 'Fjalkalimi', + 'password_confirm' => 'Konfirmo fjalëkalimin', + 'password_hint' => 'Duhet të jetë të paktën 8 karaktere', + 'forgot_password' => 'Keni harruar fjalëkalimin?', + 'remember_me' => 'Më mbaj mend', + 'ldap_email_hint' => 'Ju lutem fusni një email që do përdorni për këtë llogari.', + 'create_account' => 'Krijo një llogari', + 'already_have_account' => 'Keni një llogari?', + 'dont_have_account' => 'Nuk keni akoma llogari?', 'social_login' => 'Social Login', 'social_registration' => 'Social Registration', - 'social_registration_text' => 'Register and sign in using another service.', + 'social_registration_text' => 'Regjistrohu dhe logohu duhet përdorur një shërbim tjetër.', - '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' => 'Faleminderit që u regjistruat!', + 'register_confirm' => 'Ju lutem kontrolloni emai-in tuaj dhe klikoni te butoni i konfirmimit për të aksesuar :appName.', + 'registrations_disabled' => 'Regjistrimet janë të mbyllura', + 'registration_email_domain_invalid' => 'Ky domain email-i nuk ka akses te ky aplikacion', + 'register_success' => 'Faleminderit që u regjistruar! Ju tani jeni të regjistruar dhe të loguar.', // Login auto-initiation 'auto_init_starting' => 'Attempting Login', From eff7aa0f73a08c495f39c4eb4dc151201fa0cef2 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Wed, 24 Jan 2024 10:25:24 +0000 Subject: [PATCH 017/969] Updated translator attribution before v23.12.2 release --- .github/translators.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/translators.txt b/.github/translators.txt index ef16da25722..950c9d69598 100644 --- a/.github/translators.txt +++ b/.github/translators.txt @@ -388,3 +388,8 @@ diegobenitez :: Spanish Marc Hagen (MarcHagen) :: Dutch Kasper Alsøe (zeonos) :: Danish sultani :: Persian +renge :: Korean +TheGatesDev (thegatesdev) :: Dutch +Irdi (irdiOL) :: Albanian +KateBarber :: Welsh +Twister (theuncles75) :: Hebrew From 8fb9d9d4c2c2916430cd4ed7fa14840c4cc897cc Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Wed, 24 Jan 2024 10:27:09 +0000 Subject: [PATCH 018/969] Dependancies: Updated PHP deps via composer --- composer.lock | 268 ++++++++++++++++++++++++-------------------------- 1 file changed, 131 insertions(+), 137 deletions(-) diff --git a/composer.lock b/composer.lock index 56d33e78ebf..3bea1a66a26 100644 --- a/composer.lock +++ b/composer.lock @@ -62,16 +62,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.294.5", + "version": "3.296.8", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "2e34d45e970c77775e4c298e08732d64b647c41c" + "reference": "f84fe470709e5ab9515649a1a0891e279693d1b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/2e34d45e970c77775e4c298e08732d64b647c41c", - "reference": "2e34d45e970c77775e4c298e08732d64b647c41c", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/f84fe470709e5ab9515649a1a0891e279693d1b3", + "reference": "f84fe470709e5ab9515649a1a0891e279693d1b3", "shasum": "" }, "require": { @@ -151,9 +151,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.294.5" + "source": "https://github.com/aws/aws-sdk-php/tree/3.296.8" }, - "time": "2023-12-21T19:10:21+00:00" + "time": "2024-01-23T20:32:59+00:00" }, { "name": "bacon/bacon-qr-code", @@ -708,16 +708,16 @@ }, { "name": "doctrine/dbal", - "version": "3.7.2", + "version": "3.7.3", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "0ac3c270590e54910715e9a1a044cc368df282b2" + "reference": "ce594cbc39a4866c544f1a970d285ff0548221ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/0ac3c270590e54910715e9a1a044cc368df282b2", - "reference": "0ac3c270590e54910715e9a1a044cc368df282b2", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/ce594cbc39a4866c544f1a970d285ff0548221ad", + "reference": "ce594cbc39a4866c544f1a970d285ff0548221ad", "shasum": "" }, "require": { @@ -733,14 +733,14 @@ "doctrine/coding-standard": "12.0.0", "fig/log-test": "^1", "jetbrains/phpstorm-stubs": "2023.1", - "phpstan/phpstan": "1.10.42", + "phpstan/phpstan": "1.10.56", "phpstan/phpstan-strict-rules": "^1.5", - "phpunit/phpunit": "9.6.13", + "phpunit/phpunit": "9.6.15", "psalm/plugin-phpunit": "0.18.4", "slevomat/coding-standard": "8.13.1", - "squizlabs/php_codesniffer": "3.7.2", - "symfony/cache": "^5.4|^6.0", - "symfony/console": "^4.4|^5.4|^6.0", + "squizlabs/php_codesniffer": "3.8.1", + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/console": "^4.4|^5.4|^6.0|^7.0", "vimeo/psalm": "4.30.0" }, "suggest": { @@ -801,7 +801,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.7.2" + "source": "https://github.com/doctrine/dbal/tree/3.7.3" }, "funding": [ { @@ -817,7 +817,7 @@ "type": "tidelift" } ], - "time": "2023-11-19T08:06:58+00:00" + "time": "2024-01-21T07:53:09+00:00" }, { "name": "doctrine/deprecations", @@ -960,16 +960,16 @@ }, { "name": "doctrine/inflector", - "version": "2.0.8", + "version": "2.0.9", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "f9301a5b2fb1216b2b08f02ba04dc45423db6bff" + "reference": "2930cd5ef353871c821d5c43ed030d39ac8cfe65" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/f9301a5b2fb1216b2b08f02ba04dc45423db6bff", - "reference": "f9301a5b2fb1216b2b08f02ba04dc45423db6bff", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/2930cd5ef353871c821d5c43ed030d39ac8cfe65", + "reference": "2930cd5ef353871c821d5c43ed030d39ac8cfe65", "shasum": "" }, "require": { @@ -1031,7 +1031,7 @@ ], "support": { "issues": "https://github.com/doctrine/inflector/issues", - "source": "https://github.com/doctrine/inflector/tree/2.0.8" + "source": "https://github.com/doctrine/inflector/tree/2.0.9" }, "funding": [ { @@ -1047,7 +1047,7 @@ "type": "tidelift" } ], - "time": "2023-06-16T13:40:37+00:00" + "time": "2024-01-15T18:05:13+00:00" }, { "name": "doctrine/lexer", @@ -2349,25 +2349,25 @@ }, { "name": "laravel/tinker", - "version": "v2.8.2", + "version": "v2.9.0", "source": { "type": "git", "url": "https://github.com/laravel/tinker.git", - "reference": "b936d415b252b499e8c3b1f795cd4fc20f57e1f3" + "reference": "502e0fe3f0415d06d5db1f83a472f0f3b754bafe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/tinker/zipball/b936d415b252b499e8c3b1f795cd4fc20f57e1f3", - "reference": "b936d415b252b499e8c3b1f795cd4fc20f57e1f3", + "url": "https://api.github.com/repos/laravel/tinker/zipball/502e0fe3f0415d06d5db1f83a472f0f3b754bafe", + "reference": "502e0fe3f0415d06d5db1f83a472f0f3b754bafe", "shasum": "" }, "require": { - "illuminate/console": "^6.0|^7.0|^8.0|^9.0|^10.0", - "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0", - "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0", + "illuminate/console": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", + "illuminate/contracts": "^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", "php": "^7.2.5|^8.0", - "psy/psysh": "^0.10.4|^0.11.1", - "symfony/var-dumper": "^4.3.4|^5.0|^6.0" + "psy/psysh": "^0.11.1|^0.12.0", + "symfony/var-dumper": "^4.3.4|^5.0|^6.0|^7.0" }, "require-dev": { "mockery/mockery": "~1.3.3|^1.4.2", @@ -2375,13 +2375,10 @@ "phpunit/phpunit": "^8.5.8|^9.3.3" }, "suggest": { - "illuminate/database": "The Illuminate Database package (^6.0|^7.0|^8.0|^9.0|^10.0)." + "illuminate/database": "The Illuminate Database package (^6.0|^7.0|^8.0|^9.0|^10.0|^11.0)." }, "type": "library", "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - }, "laravel": { "providers": [ "Laravel\\Tinker\\TinkerServiceProvider" @@ -2412,9 +2409,9 @@ ], "support": { "issues": "https://github.com/laravel/tinker/issues", - "source": "https://github.com/laravel/tinker/tree/v2.8.2" + "source": "https://github.com/laravel/tinker/tree/v2.9.0" }, - "time": "2023-08-15T14:27:00+00:00" + "time": "2024-01-04T16:10:04+00:00" }, { "name": "league/commonmark", @@ -3348,16 +3345,16 @@ }, { "name": "nesbot/carbon", - "version": "2.72.1", + "version": "2.72.2", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "2b3b3db0a2d0556a177392ff1a3bf5608fa09f78" + "reference": "3e7edc41b58d65509baeb0d4a14c8fa41d627130" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/2b3b3db0a2d0556a177392ff1a3bf5608fa09f78", - "reference": "2b3b3db0a2d0556a177392ff1a3bf5608fa09f78", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/3e7edc41b58d65509baeb0d4a14c8fa41d627130", + "reference": "3e7edc41b58d65509baeb0d4a14c8fa41d627130", "shasum": "" }, "require": { @@ -3451,7 +3448,7 @@ "type": "tidelift" } ], - "time": "2023-12-08T23:47:49+00:00" + "time": "2024-01-19T00:21:53+00:00" }, { "name": "nette/schema", @@ -3517,16 +3514,16 @@ }, { "name": "nette/utils", - "version": "v4.0.3", + "version": "v4.0.4", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "a9d127dd6a203ce6d255b2e2db49759f7506e015" + "reference": "d3ad0aa3b9f934602cb3e3902ebccf10be34d218" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/a9d127dd6a203ce6d255b2e2db49759f7506e015", - "reference": "a9d127dd6a203ce6d255b2e2db49759f7506e015", + "url": "https://api.github.com/repos/nette/utils/zipball/d3ad0aa3b9f934602cb3e3902ebccf10be34d218", + "reference": "d3ad0aa3b9f934602cb3e3902ebccf10be34d218", "shasum": "" }, "require": { @@ -3597,31 +3594,33 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.0.3" + "source": "https://github.com/nette/utils/tree/v4.0.4" }, - "time": "2023-10-29T21:02:13+00:00" + "time": "2024-01-17T16:50:36+00:00" }, { "name": "nikic/php-parser", - "version": "v4.18.0", + "version": "v5.0.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" + "reference": "4a21235f7e56e713259a6f76bf4b5ea08502b9dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4a21235f7e56e713259a6f76bf4b5ea08502b9dc", + "reference": "4a21235f7e56e713259a6f76bf4b5ea08502b9dc", "shasum": "" }, "require": { + "ext-ctype": "*", + "ext-json": "*", "ext-tokenizer": "*", - "php": ">=7.0" + "php": ">=7.4" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "bin": [ "bin/php-parse" @@ -3629,7 +3628,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.9-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -3653,9 +3652,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.0" }, - "time": "2023-12-10T21:03:43+00:00" + "time": "2024-01-07T17:17:35+00:00" }, { "name": "nunomaduro/termwind", @@ -3918,23 +3917,23 @@ }, { "name": "phenx/php-font-lib", - "version": "0.5.4", + "version": "0.5.5", "source": { "type": "git", "url": "https://github.com/dompdf/php-font-lib.git", - "reference": "dd448ad1ce34c63d09baccd05415e361300c35b4" + "reference": "671df0f3516252011aa94f9e8e3b3b66199339f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/dd448ad1ce34c63d09baccd05415e361300c35b4", - "reference": "dd448ad1ce34c63d09baccd05415e361300c35b4", + "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/671df0f3516252011aa94f9e8e3b3b66199339f8", + "reference": "671df0f3516252011aa94f9e8e3b3b66199339f8", "shasum": "" }, "require": { "ext-mbstring": "*" }, "require-dev": { - "symfony/phpunit-bridge": "^3 || ^4 || ^5" + "symfony/phpunit-bridge": "^3 || ^4 || ^5 || ^6" }, "type": "library", "autoload": { @@ -3944,7 +3943,7 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "LGPL-3.0" + "LGPL-2.1-or-later" ], "authors": [ { @@ -3956,9 +3955,9 @@ "homepage": "https://github.com/PhenX/php-font-lib", "support": { "issues": "https://github.com/dompdf/php-font-lib/issues", - "source": "https://github.com/dompdf/php-font-lib/tree/0.5.4" + "source": "https://github.com/dompdf/php-font-lib/tree/0.5.5" }, - "time": "2021-12-17T19:44:54+00:00" + "time": "2024-01-07T18:13:29+00:00" }, { "name": "phenx/php-svg-lib", @@ -4083,16 +4082,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.34", + "version": "3.0.35", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "56c79f16a6ae17e42089c06a2144467acc35348a" + "reference": "4b1827beabce71953ca479485c0ae9c51287f2fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/56c79f16a6ae17e42089c06a2144467acc35348a", - "reference": "56c79f16a6ae17e42089c06a2144467acc35348a", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/4b1827beabce71953ca479485c0ae9c51287f2fe", + "reference": "4b1827beabce71953ca479485c0ae9c51287f2fe", "shasum": "" }, "require": { @@ -4173,7 +4172,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.34" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.35" }, "funding": [ { @@ -4189,7 +4188,7 @@ "type": "tidelift" } ], - "time": "2023-11-27T11:13:31+00:00" + "time": "2023-12-29T01:59:53+00:00" }, { "name": "pragmarx/google2fa", @@ -4767,25 +4766,25 @@ }, { "name": "psy/psysh", - "version": "v0.11.22", + "version": "v0.12.0", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "128fa1b608be651999ed9789c95e6e2a31b5802b" + "reference": "750bf031a48fd07c673dbe3f11f72362ea306d0d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/128fa1b608be651999ed9789c95e6e2a31b5802b", - "reference": "128fa1b608be651999ed9789c95e6e2a31b5802b", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/750bf031a48fd07c673dbe3f11f72362ea306d0d", + "reference": "750bf031a48fd07c673dbe3f11f72362ea306d0d", "shasum": "" }, "require": { "ext-json": "*", "ext-tokenizer": "*", - "nikic/php-parser": "^4.0 || ^3.1", - "php": "^8.0 || ^7.0.8", - "symfony/console": "^6.0 || ^5.0 || ^4.0 || ^3.4", - "symfony/var-dumper": "^6.0 || ^5.0 || ^4.0 || ^3.4" + "nikic/php-parser": "^5.0 || ^4.0", + "php": "^8.0 || ^7.4", + "symfony/console": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4", + "symfony/var-dumper": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4" }, "conflict": { "symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4" @@ -4796,8 +4795,7 @@ "suggest": { "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", "ext-pdo-sqlite": "The doc command requires SQLite to work.", - "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.", - "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history." + "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well." }, "bin": [ "bin/psysh" @@ -4805,7 +4803,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-0.11": "0.11.x-dev" + "dev-main": "0.12.x-dev" }, "bamarni-bin": { "bin-links": false, @@ -4841,9 +4839,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.11.22" + "source": "https://github.com/bobthecow/psysh/tree/v0.12.0" }, - "time": "2023-10-14T21:56:36+00:00" + "time": "2023-12-20T15:28:09+00:00" }, { "name": "ralouphie/getallheaders", @@ -8112,16 +8110,16 @@ }, { "name": "fakerphp/faker", - "version": "v1.23.0", + "version": "v1.23.1", "source": { "type": "git", "url": "https://github.com/FakerPHP/Faker.git", - "reference": "e3daa170d00fde61ea7719ef47bb09bb8f1d9b01" + "reference": "bfb4fe148adbf78eff521199619b93a52ae3554b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/e3daa170d00fde61ea7719ef47bb09bb8f1d9b01", - "reference": "e3daa170d00fde61ea7719ef47bb09bb8f1d9b01", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/bfb4fe148adbf78eff521199619b93a52ae3554b", + "reference": "bfb4fe148adbf78eff521199619b93a52ae3554b", "shasum": "" }, "require": { @@ -8147,11 +8145,6 @@ "ext-mbstring": "Required for multibyte Unicode string functionality." }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "v1.21-dev" - } - }, "autoload": { "psr-4": { "Faker\\": "src/Faker/" @@ -8174,9 +8167,9 @@ ], "support": { "issues": "https://github.com/FakerPHP/Faker/issues", - "source": "https://github.com/FakerPHP/Faker/tree/v1.23.0" + "source": "https://github.com/FakerPHP/Faker/tree/v1.23.1" }, - "time": "2023-06-12T08:44:38+00:00" + "time": "2024-01-02T13:46:09+00:00" }, { "name": "filp/whoops", @@ -8370,36 +8363,36 @@ }, { "name": "larastan/larastan", - "version": "v2.7.0", + "version": "v2.8.1", "source": { "type": "git", "url": "https://github.com/larastan/larastan.git", - "reference": "a2610d46b9999cf558d9900ccb641962d1442f55" + "reference": "b7cc6a29c457a7d4f3de90466392ae9ad3e17022" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/larastan/larastan/zipball/a2610d46b9999cf558d9900ccb641962d1442f55", - "reference": "a2610d46b9999cf558d9900ccb641962d1442f55", + "url": "https://api.github.com/repos/larastan/larastan/zipball/b7cc6a29c457a7d4f3de90466392ae9ad3e17022", + "reference": "b7cc6a29c457a7d4f3de90466392ae9ad3e17022", "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", + "illuminate/console": "^9.52.16 || ^10.28.0 || ^11.0", + "illuminate/container": "^9.52.16 || ^10.28.0 || ^11.0", + "illuminate/contracts": "^9.52.16 || ^10.28.0 || ^11.0", + "illuminate/database": "^9.52.16 || ^10.28.0 || ^11.0", + "illuminate/http": "^9.52.16 || ^10.28.0 || ^11.0", + "illuminate/pipeline": "^9.52.16 || ^10.28.0 || ^11.0", + "illuminate/support": "^9.52.16 || ^10.28.0 || ^11.0", "php": "^8.0.2", "phpmyadmin/sql-parser": "^5.8.2", - "phpstan/phpstan": "^1.10.41" + "phpstan/phpstan": "^1.10.50" }, "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" + "orchestra/canvas": "^7.11.1 || ^8.11.0 || ^9.0.0", + "orchestra/testbench": "^7.33.0 || ^8.13.0 || ^9.0.0", + "phpunit/phpunit": "^9.6.13 || ^10.5" }, "suggest": { "orchestra/testbench": "Using Larastan for analysing a package needs Testbench" @@ -8447,7 +8440,7 @@ ], "support": { "issues": "https://github.com/larastan/larastan/issues", - "source": "https://github.com/larastan/larastan/tree/v2.7.0" + "source": "https://github.com/larastan/larastan/tree/v2.8.1" }, "funding": [ { @@ -8467,7 +8460,7 @@ "type": "patreon" } ], - "time": "2023-12-04T19:21:38+00:00" + "time": "2024-01-08T09:11:17+00:00" }, { "name": "mockery/mockery", @@ -8812,16 +8805,16 @@ }, { "name": "phpmyadmin/sql-parser", - "version": "5.8.2", + "version": "5.9.0", "source": { "type": "git", "url": "https://github.com/phpmyadmin/sql-parser.git", - "reference": "f1720ae19abe6294cb5599594a8a57bc3c8cc287" + "reference": "011fa18a4e55591fac6545a821921dd1d61c6984" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpmyadmin/sql-parser/zipball/f1720ae19abe6294cb5599594a8a57bc3c8cc287", - "reference": "f1720ae19abe6294cb5599594a8a57bc3c8cc287", + "url": "https://api.github.com/repos/phpmyadmin/sql-parser/zipball/011fa18a4e55591fac6545a821921dd1d61c6984", + "reference": "011fa18a4e55591fac6545a821921dd1d61c6984", "shasum": "" }, "require": { @@ -8852,6 +8845,7 @@ "bin": [ "bin/highlight-query", "bin/lint-query", + "bin/sql-parser", "bin/tokenize-query" ], "type": "library", @@ -8895,20 +8889,20 @@ "type": "other" } ], - "time": "2023-09-19T12:34:29+00:00" + "time": "2024-01-20T20:34:02+00:00" }, { "name": "phpstan/phpstan", - "version": "1.10.50", + "version": "1.10.56", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4" + "reference": "27816a01aea996191ee14d010f325434c0ee76fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/06a98513ac72c03e8366b5a0cb00750b487032e4", - "reference": "06a98513ac72c03e8366b5a0cb00750b487032e4", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/27816a01aea996191ee14d010f325434c0ee76fa", + "reference": "27816a01aea996191ee14d010f325434c0ee76fa", "shasum": "" }, "require": { @@ -8957,7 +8951,7 @@ "type": "tidelift" } ], - "time": "2023-12-13T10:59:42+00:00" + "time": "2024-01-15T10:43:00+00:00" }, { "name": "phpunit/php-code-coverage", @@ -9280,16 +9274,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.15", + "version": "9.6.16", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1" + "reference": "3767b2c56ce02d01e3491046f33466a1ae60a37f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/05017b80304e0eb3f31d90194a563fd53a6021f1", - "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3767b2c56ce02d01e3491046f33466a1ae60a37f", + "reference": "3767b2c56ce02d01e3491046f33466a1ae60a37f", "shasum": "" }, "require": { @@ -9363,7 +9357,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.15" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.16" }, "funding": [ { @@ -9379,7 +9373,7 @@ "type": "tidelift" } ], - "time": "2023-12-01T16:55:19+00:00" + "time": "2024-01-19T07:03:14+00:00" }, { "name": "sebastian/cli-parser", @@ -10347,16 +10341,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.8.0", + "version": "3.8.1", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "5805f7a4e4958dbb5e944ef1e6edae0a303765e7" + "reference": "14f5fff1e64118595db5408e946f3a22c75807f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5805f7a4e4958dbb5e944ef1e6edae0a303765e7", - "reference": "5805f7a4e4958dbb5e944ef1e6edae0a303765e7", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/14f5fff1e64118595db5408e946f3a22c75807f7", + "reference": "14f5fff1e64118595db5408e946f3a22c75807f7", "shasum": "" }, "require": { @@ -10366,11 +10360,11 @@ "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" }, "bin": [ - "bin/phpcs", - "bin/phpcbf" + "bin/phpcbf", + "bin/phpcs" ], "type": "library", "extra": { @@ -10423,7 +10417,7 @@ "type": "open_collective" } ], - "time": "2023-12-08T12:32:31+00:00" + "time": "2024-01-11T20:47:48+00:00" }, { "name": "ssddanbrown/asserthtml", From 3e9e196cdada5a6c515d5bbab971c80a90d333ab Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Thu, 25 Jan 2024 14:24:46 +0000 Subject: [PATCH 019/969] OIDC: Added PKCE functionality Related to #4734. Uses core logic from League AbstractProvider. --- app/Access/Oidc/OidcOAuthProvider.php | 31 +++++++++++---------------- app/Access/Oidc/OidcService.php | 12 ++++++++++- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/app/Access/Oidc/OidcOAuthProvider.php b/app/Access/Oidc/OidcOAuthProvider.php index d2dc829b729..371bfcecb54 100644 --- a/app/Access/Oidc/OidcOAuthProvider.php +++ b/app/Access/Oidc/OidcOAuthProvider.php @@ -83,15 +83,9 @@ protected function getScopeSeparator(): string /** * Checks a provider response for errors. - * - * @param ResponseInterface $response - * @param array|string $data Parsed response data - * * @throws IdentityProviderException - * - * @return void */ - protected function checkResponse(ResponseInterface $response, $data) + protected function checkResponse(ResponseInterface $response, $data): void { if ($response->getStatusCode() >= 400 || isset($data['error'])) { throw new IdentityProviderException( @@ -105,13 +99,8 @@ protected function checkResponse(ResponseInterface $response, $data) /** * Generates a resource owner object from a successful resource owner * details request. - * - * @param array $response - * @param AccessToken $token - * - * @return ResourceOwnerInterface */ - protected function createResourceOwner(array $response, AccessToken $token) + protected function createResourceOwner(array $response, AccessToken $token): ResourceOwnerInterface { return new GenericResourceOwner($response, ''); } @@ -121,14 +110,18 @@ protected function createResourceOwner(array $response, AccessToken $token) * * The grant that was used to fetch the response can be used to provide * additional context. - * - * @param array $response - * @param AbstractGrant $grant - * - * @return OidcAccessToken */ - protected function createAccessToken(array $response, AbstractGrant $grant) + protected function createAccessToken(array $response, AbstractGrant $grant): OidcAccessToken { return new OidcAccessToken($response); } + + /** + * Get the method used for PKCE code verifier hashing, which is passed + * in the "code_challenge_method" parameter in the authorization request. + */ + protected function getPkceMethod(): string + { + return static::PKCE_METHOD_S256; + } } diff --git a/app/Access/Oidc/OidcService.php b/app/Access/Oidc/OidcService.php index f1e5b25af14..036c9fc47ef 100644 --- a/app/Access/Oidc/OidcService.php +++ b/app/Access/Oidc/OidcService.php @@ -33,6 +33,8 @@ public function __construct( /** * Initiate an authorization flow. + * Provides back an authorize redirect URL, in addition to other + * details which may be required for the auth flow. * * @throws OidcException * @@ -42,8 +44,12 @@ public function login(): array { $settings = $this->getProviderSettings(); $provider = $this->getProvider($settings); + + $url = $provider->getAuthorizationUrl(); + session()->put('oidc_pkce_code', $provider->getPkceCode() ?? ''); + return [ - 'url' => $provider->getAuthorizationUrl(), + 'url' => $url, 'state' => $provider->getState(), ]; } @@ -63,6 +69,10 @@ public function processAuthorizeResponse(?string $authorizationCode): User $settings = $this->getProviderSettings(); $provider = $this->getProvider($settings); + // Set PKCE code flashed at login + $pkceCode = session()->pull('oidc_pkce_code', ''); + $provider->setPkceCode($pkceCode); + // Try to exchange authorization code for access token $accessToken = $provider->getAccessToken('authorization_code', [ 'code' => $authorizationCode, From 1dc094ffafc216e15c8355b400b21524137de5e4 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 27 Jan 2024 16:41:15 +0000 Subject: [PATCH 020/969] OIDC: Added testing of PKCE flow Also compared full flow to RFC spec during this process --- tests/Auth/OidcTest.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/Auth/OidcTest.php b/tests/Auth/OidcTest.php index dbf26f1bd30..345d1dc780b 100644 --- a/tests/Auth/OidcTest.php +++ b/tests/Auth/OidcTest.php @@ -655,6 +655,34 @@ public function test_oidc_id_token_pre_validate_theme_event_with_return() ]); } + public function test_pkce_used_on_authorize_and_access() + { + // Start auth + $resp = $this->post('/oidc/login'); + $state = session()->get('oidc_state'); + + $pkceCode = session()->get('oidc_pkce_code'); + $this->assertGreaterThan(30, strlen($pkceCode)); + + $expectedCodeChallenge = trim(strtr(base64_encode(hash('sha256', $pkceCode, true)), '+/', '-_'), '='); + $redirect = $resp->headers->get('Location'); + $redirectParams = []; + parse_str(parse_url($redirect, PHP_URL_QUERY), $redirectParams); + $this->assertEquals($expectedCodeChallenge, $redirectParams['code_challenge']); + $this->assertEquals('S256', $redirectParams['code_challenge_method']); + + $transactions = $this->mockHttpClient([$this->getMockAuthorizationResponse([ + 'email' => 'benny@example.com', + 'sub' => 'benny1010101', + ])]); + + $this->get('/oidc/callback?code=SplxlOBeZQQYbYS6WxSbIA&state=' . $state); + $tokenRequest = $transactions->latestRequest(); + $bodyParams = []; + parse_str($tokenRequest->getBody(), $bodyParams); + $this->assertEquals($pkceCode, $bodyParams['code_verifier']); + } + protected function withAutodiscovery() { config()->set([ From 2a849894bee6ac7846261938c9606fb18a4a1761 Mon Sep 17 00:00:00 2001 From: Sascha Date: Mon, 29 Jan 2024 19:37:59 +0100 Subject: [PATCH 021/969] Update entities.php changed text of `pages_delete_warning_template` to include chapters --- lang/en/entities.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/en/entities.php b/lang/en/entities.php index 4ab9de47dfb..21ef93fed3c 100644 --- a/lang/en/entities.php +++ b/lang/en/entities.php @@ -210,7 +210,7 @@ '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_warning_template' => 'This page is in active use as a book or chapter default page template. These books or chapters 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', From 64c783c6f8efb351dd73a1cfb4b5f214a731bd57 Mon Sep 17 00:00:00 2001 From: Sascha Date: Mon, 29 Jan 2024 19:55:39 +0100 Subject: [PATCH 022/969] extraded template form to own file and changed translations --- lang/en/entities.php | 9 +++------ resources/views/books/parts/form.blade.php | 18 ++---------------- resources/views/chapters/parts/form.blade.php | 18 ++---------------- .../views/entities/template-selector.blade.php | 14 ++++++++++++++ 4 files changed, 21 insertions(+), 38 deletions(-) create mode 100644 resources/views/entities/template-selector.blade.php diff --git a/lang/en/entities.php b/lang/en/entities.php index 21ef93fed3c..8860e243e77 100644 --- a/lang/en/entities.php +++ b/lang/en/entities.php @@ -39,6 +39,9 @@ 'export_pdf' => 'PDF File', 'export_text' => 'Plain Text File', 'export_md' => 'Markdown File', + 'default_template' => 'Default Page Template', + 'default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this book/chapter. Keep in mind this will only be used if the page creator has view access to those chosen template page.', + 'default_template_select' => 'Select a template page', // Permissions and restrictions 'permissions' => 'Permissions', @@ -132,9 +135,6 @@ '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.', @@ -192,9 +192,6 @@ 'chapters_permissions_success' => 'Chapter Permissions Updated', 'chapters_search_this' => 'Search this chapter', 'chapter_sort_book' => 'Sort Book', - 'chapter_default_template' => 'Default Page Template', - 'chapter_default_template_explain' => 'Assign a page template that will be used as the default content for all new pages in this chapter. Keep in mind this will only be used if the page creator has view access to those chosen template page.', - 'chapter_default_template_select' => 'Select a template page', // Pages 'page' => 'Page', diff --git a/resources/views/books/parts/form.blade.php b/resources/views/books/parts/form.blade.php index fa8f16e52f4..ee261e72d4a 100644 --- a/resources/views/books/parts/form.blade.php +++ b/resources/views/books/parts/form.blade.php @@ -40,24 +40,10 @@
-
-

- {{ 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', - ]) -
-
- + @include('entities.template-selector', ['entity' => $book ?? null])
diff --git a/resources/views/chapters/parts/form.blade.php b/resources/views/chapters/parts/form.blade.php index ea7f84bc839..602693916ea 100644 --- a/resources/views/chapters/parts/form.blade.php +++ b/resources/views/chapters/parts/form.blade.php @@ -24,24 +24,10 @@
-
-

- {{ trans('entities.chapter_default_template_explain') }} -

- -
- @include('form.page-picker', [ - 'name' => 'default_template_id', - 'placeholder' => trans('entities.chapter_default_template_select'), - 'value' => $chapter->default_template_id ?? null, - 'selectorEndpoint' => '/search/entity-selector-templates', - ]) -
-
- + @include('entities.template-selector', ['entity' => $chapter ?? null])
diff --git a/resources/views/entities/template-selector.blade.php b/resources/views/entities/template-selector.blade.php new file mode 100644 index 00000000000..80b2f49b2b9 --- /dev/null +++ b/resources/views/entities/template-selector.blade.php @@ -0,0 +1,14 @@ +
+

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

+ +
+ @include('form.page-picker', [ + 'name' => 'default_template_id', + 'placeholder' => trans('entities.default_template_select'), + 'value' => $entity->default_template_id ?? null, + 'selectorEndpoint' => '/search/entity-selector-templates', + ]) +
+
\ No newline at end of file From 4a8f70240fd01f28980dfd4031c7df2b1db4949a Mon Sep 17 00:00:00 2001 From: Sascha Date: Mon, 29 Jan 2024 19:59:03 +0100 Subject: [PATCH 023/969] added template to chapter API controller --- .../Controllers/ChapterApiController.php | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/app/Entities/Controllers/ChapterApiController.php b/app/Entities/Controllers/ChapterApiController.php index c2132326200..27b8206592d 100644 --- a/app/Entities/Controllers/ChapterApiController.php +++ b/app/Entities/Controllers/ChapterApiController.php @@ -15,20 +15,22 @@ class ChapterApiController extends ApiController { protected $rules = [ 'create' => [ - 'book_id' => ['required', 'integer'], - 'name' => ['required', 'string', 'max:255'], - 'description' => ['string', 'max:1900'], - 'description_html' => ['string', 'max:2000'], - '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'], + 'default_template_id' => ['nullable', 'integer'], ], 'update' => [ - 'book_id' => ['integer'], - 'name' => ['string', 'min:1', 'max:255'], - 'description' => ['string', 'max:1900'], - 'description_html' => ['string', 'max:2000'], - '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'], + 'default_template_id' => ['nullable', 'integer'], ], ]; From 24e6dc4b37f857ffe6f8eab85ca177ed290bb38a Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Tue, 30 Jan 2024 11:38:47 +0000 Subject: [PATCH 024/969] WYSIWYG: Altered how custom head added to editors Updated to parse and add as DOM nodes instead of innerHTML to avoid triggering an update of all head content, which would throw warnings in chromium in regard to setting the base URI. For #4814 --- resources/js/wysiwyg/config.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/resources/js/wysiwyg/config.js b/resources/js/wysiwyg/config.js index 6c96e47e9c3..36d78b32515 100644 --- a/resources/js/wysiwyg/config.js +++ b/resources/js/wysiwyg/config.js @@ -143,16 +143,23 @@ function gatherPlugins(options) { } /** - * Fetch custom HTML head content from the parent page head into the editor. + * Fetch custom HTML head content nodes from the outer page head + * and add them to the given editor document. + * @param {Document} editorDoc */ -function fetchCustomHeadContent() { +function addCustomHeadContent(editorDoc) { const headContentLines = document.head.innerHTML.split('\n'); const startLineIndex = headContentLines.findIndex(line => line.trim() === ''); const endLineIndex = headContentLines.findIndex(line => line.trim() === ''); if (startLineIndex === -1 || endLineIndex === -1) { - return ''; + return; } - return headContentLines.slice(startLineIndex + 1, endLineIndex).join('\n'); + + const customHeadHtml = headContentLines.slice(startLineIndex + 1, endLineIndex).join('\n'); + const el = editorDoc.createElement('div'); + el.innerHTML = customHeadHtml; + + editorDoc.head.append(...el.children); } /** @@ -284,8 +291,7 @@ export function buildForEditor(options) { } }, init_instance_callback(editor) { - const head = editor.getDoc().querySelector('head'); - head.innerHTML += fetchCustomHeadContent(); + addCustomHeadContent(editor.getDoc()); }, setup(editor) { registerCustomIcons(editor); @@ -335,8 +341,7 @@ export function buildForInput(options) { file_picker_types: 'file', file_picker_callback: filePickerCallback, init_instance_callback(editor) { - const head = editor.getDoc().querySelector('head'); - head.innerHTML += fetchCustomHeadContent(); + addCustomHeadContent(editor.getDoc()); editor.contentDocument.documentElement.classList.toggle('dark-mode', options.darkMode); }, From 5c92b72fdd419ccb6f77bfdf0a1cb1358c51a9d8 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Tue, 30 Jan 2024 14:27:09 +0000 Subject: [PATCH 025/969] Comments: Added input wysiwyg for creating/updating comments Not supporting old content, existing HTML or updating yet. --- app/Activity/Tools/CommentTree.php | 11 ++++++++ resources/js/components/page-comment.js | 27 ++++++++++++++++--- resources/js/components/page-comments.js | 30 ++++++++++++++++++--- resources/js/components/wysiwyg-input.js | 7 ++--- resources/sass/_tinymce.scss | 7 +++++ resources/views/comments/comment.blade.php | 2 ++ resources/views/comments/comments.blade.php | 10 ++++++- resources/views/layouts/base.blade.php | 3 +++ 8 files changed, 85 insertions(+), 12 deletions(-) diff --git a/app/Activity/Tools/CommentTree.php b/app/Activity/Tools/CommentTree.php index 3303add39b8..16f6804ea42 100644 --- a/app/Activity/Tools/CommentTree.php +++ b/app/Activity/Tools/CommentTree.php @@ -41,6 +41,17 @@ public function get(): array return $this->tree; } + public function canUpdateAny(): bool + { + foreach ($this->comments as $comment) { + if (userCan('comment-update', $comment)) { + return true; + } + } + + return false; + } + /** * @param Comment[] $comments */ diff --git a/resources/js/components/page-comment.js b/resources/js/components/page-comment.js index 8284d7f20d8..dc6ca826425 100644 --- a/resources/js/components/page-comment.js +++ b/resources/js/components/page-comment.js @@ -1,5 +1,6 @@ import {Component} from './component'; import {getLoading, htmlToDom} from '../services/dom'; +import {buildForInput} from "../wysiwyg/config"; export class PageComment extends Component { @@ -11,7 +12,12 @@ export class PageComment extends Component { this.deletedText = this.$opts.deletedText; this.updatedText = this.$opts.updatedText; - // Element References + // Editor reference and text options + this.wysiwygEditor = null; + this.wysiwygLanguage = this.$opts.wysiwygLanguage; + this.wysiwygTextDirection = this.$opts.wysiwygTextDirection; + + // Element references this.container = this.$el; this.contentContainer = this.$refs.contentContainer; this.form = this.$refs.form; @@ -50,8 +56,23 @@ export class PageComment extends Component { startEdit() { this.toggleEditMode(true); - const lineCount = this.$refs.input.value.split('\n').length; - this.$refs.input.style.height = `${(lineCount * 20) + 40}px`; + + if (this.wysiwygEditor) { + return; + } + + const config = buildForInput({ + language: this.wysiwygLanguage, + containerElement: this.input, + darkMode: document.documentElement.classList.contains('dark-mode'), + textDirection: this.wysiwygTextDirection, + translations: {}, + translationMap: window.editor_translations, + }); + + window.tinymce.init(config).then(editors => { + this.wysiwygEditor = editors[0]; + }); } async update(event) { diff --git a/resources/js/components/page-comments.js b/resources/js/components/page-comments.js index e2911afc6a0..ebcc95f07f4 100644 --- a/resources/js/components/page-comments.js +++ b/resources/js/components/page-comments.js @@ -1,5 +1,6 @@ import {Component} from './component'; import {getLoading, htmlToDom} from '../services/dom'; +import {buildForInput} from "../wysiwyg/config"; export class PageComments extends Component { @@ -21,6 +22,11 @@ export class PageComments extends Component { this.hideFormButton = this.$refs.hideFormButton; this.removeReplyToButton = this.$refs.removeReplyToButton; + // WYSIWYG options + this.wysiwygLanguage = this.$opts.wysiwygLanguage; + this.wysiwygTextDirection = this.$opts.wysiwygTextDirection; + this.wysiwygEditor = null; + // Translations this.createdText = this.$opts.createdText; this.countText = this.$opts.countText; @@ -96,9 +102,7 @@ export class PageComments extends Component { this.formContainer.toggleAttribute('hidden', false); this.addButtonContainer.toggleAttribute('hidden', true); this.formContainer.scrollIntoView({behavior: 'smooth', block: 'nearest'}); - setTimeout(() => { - this.formInput.focus(); - }, 100); + this.loadEditor(); } hideForm() { @@ -112,6 +116,26 @@ export class PageComments extends Component { this.addButtonContainer.toggleAttribute('hidden', false); } + loadEditor() { + if (this.wysiwygEditor) { + return; + } + + const config = buildForInput({ + language: this.wysiwygLanguage, + containerElement: this.formInput, + darkMode: document.documentElement.classList.contains('dark-mode'), + textDirection: this.wysiwygTextDirection, + translations: {}, + translationMap: window.editor_translations, + }); + + window.tinymce.init(config).then(editors => { + this.wysiwygEditor = editors[0]; + this.wysiwygEditor.focus(); + }); + } + getCommentCount() { return this.container.querySelectorAll('[component="page-comment"]').length; } diff --git a/resources/js/components/wysiwyg-input.js b/resources/js/components/wysiwyg-input.js index 88c06a334c6..ad964aed2c4 100644 --- a/resources/js/components/wysiwyg-input.js +++ b/resources/js/components/wysiwyg-input.js @@ -10,11 +10,8 @@ export class WysiwygInput extends Component { language: this.$opts.language, containerElement: this.elem, darkMode: document.documentElement.classList.contains('dark-mode'), - textDirection: this.textDirection, - translations: { - imageUploadErrorText: this.$opts.imageUploadErrorText, - serverUploadLimitText: this.$opts.serverUploadLimitText, - }, + textDirection: this.$opts.textDirection, + translations: {}, translationMap: window.editor_translations, }); diff --git a/resources/sass/_tinymce.scss b/resources/sass/_tinymce.scss index c4336da7cb7..fb5ea7e6ffe 100644 --- a/resources/sass/_tinymce.scss +++ b/resources/sass/_tinymce.scss @@ -30,6 +30,13 @@ display: block; } +.wysiwyg-input.mce-content-body:before { + padding: 1rem; + top: 4px; + font-style: italic; + color: rgba(34,47,62,.5) +} + // Default styles for our custom root nodes .page-content.mce-content-body doc-root { display: block; diff --git a/resources/views/comments/comment.blade.php b/resources/views/comments/comment.blade.php index 1cb70916087..4340cfdf5c4 100644 --- a/resources/views/comments/comment.blade.php +++ b/resources/views/comments/comment.blade.php @@ -4,6 +4,8 @@ option:page-comment:comment-parent-id="{{ $comment->parent_id }}" option:page-comment:updated-text="{{ trans('entities.comment_updated_success') }}" option:page-comment:deleted-text="{{ trans('entities.comment_deleted_success') }}" + option:page-comment:wysiwyg-language="{{ $locale->htmlLang() }}" + option:page-comment:wysiwyg-text-direction="{{ $locale->htmlDirection() }}" id="comment{{$comment->local_id}}" class="comment-box">
diff --git a/resources/views/comments/comments.blade.php b/resources/views/comments/comments.blade.php index 26d286290c2..2c314864bc2 100644 --- a/resources/views/comments/comments.blade.php +++ b/resources/views/comments/comments.blade.php @@ -2,6 +2,8 @@ option:page-comments:page-id="{{ $page->id }}" option:page-comments:created-text="{{ trans('entities.comment_created_success') }}" option:page-comments:count-text="{{ trans('entities.comment_count') }}" + option:page-comments:wysiwyg-language="{{ $locale->htmlLang() }}" + option:page-comments:wysiwyg-text-direction="{{ $locale->htmlDirection() }}" class="comments-list" aria-label="{{ trans('entities.comments') }}"> @@ -24,7 +26,6 @@ class="button outline">{{ trans('entities.comment_add') }} @if(userCan('comment-create-all')) @include('comments.create') - @if (!$commentTree->empty())
@endif @endif + @if(userCan('comment-create-all') || $commentTree->canUpdateAny()) + @push('post-app-scripts') + + @include('form.editor-translations') + @endpush + @endif + \ No newline at end of file diff --git a/resources/views/layouts/base.blade.php b/resources/views/layouts/base.blade.php index cf15e5426b8..43cca6b14c5 100644 --- a/resources/views/layouts/base.blade.php +++ b/resources/views/layouts/base.blade.php @@ -68,10 +68,13 @@ class="@stack('body-class')">
@yield('bottom') + + @if($cspNonce ?? false) @endif @yield('scripts') + @stack('post-app-scripts') @include('layouts.parts.base-body-end') From adf0baebb9ffc61cc944c0572ec6dbb12a5b41a0 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Tue, 30 Jan 2024 15:16:58 +0000 Subject: [PATCH 026/969] Comments: Added back-end HTML support, fixed editor focus Also fixed handling of editors when moved in DOM, to properly remove then re-init before & after move to avoid issues. --- app/Activity/CommentRepo.php | 26 ++++--------------- .../Controllers/CommentController.php | 17 +++++++----- resources/js/components/page-comment.js | 6 +++-- resources/js/components/page-comments.js | 17 +++++++++--- resources/views/comments/comment.blade.php | 2 +- resources/views/comments/create.blade.php | 2 +- 6 files changed, 34 insertions(+), 36 deletions(-) diff --git a/app/Activity/CommentRepo.php b/app/Activity/CommentRepo.php index ce2950e4d79..3336e17e988 100644 --- a/app/Activity/CommentRepo.php +++ b/app/Activity/CommentRepo.php @@ -5,7 +5,7 @@ use BookStack\Activity\Models\Comment; use BookStack\Entities\Models\Entity; use BookStack\Facades\Activity as ActivityService; -use League\CommonMark\CommonMarkConverter; +use BookStack\Util\HtmlDescriptionFilter; class CommentRepo { @@ -20,13 +20,12 @@ public function getById(int $id): Comment /** * Create a new comment on an entity. */ - public function create(Entity $entity, string $text, ?int $parent_id): Comment + public function create(Entity $entity, string $html, ?int $parent_id): Comment { $userId = user()->id; $comment = new Comment(); - $comment->text = $text; - $comment->html = $this->commentToHtml($text); + $comment->html = HtmlDescriptionFilter::filterFromString($html); $comment->created_by = $userId; $comment->updated_by = $userId; $comment->local_id = $this->getNextLocalId($entity); @@ -42,11 +41,10 @@ public function create(Entity $entity, string $text, ?int $parent_id): Comment /** * Update an existing comment. */ - public function update(Comment $comment, string $text): Comment + public function update(Comment $comment, string $html): Comment { $comment->updated_by = user()->id; - $comment->text = $text; - $comment->html = $this->commentToHtml($text); + $comment->html = HtmlDescriptionFilter::filterFromString($html); $comment->save(); ActivityService::add(ActivityType::COMMENT_UPDATE, $comment); @@ -64,20 +62,6 @@ public function delete(Comment $comment): void ActivityService::add(ActivityType::COMMENT_DELETE, $comment); } - /** - * Convert the given comment Markdown to HTML. - */ - public function commentToHtml(string $commentText): string - { - $converter = new CommonMarkConverter([ - 'html_input' => 'strip', - 'max_nesting_level' => 10, - 'allow_unsafe_links' => false, - ]); - - return $converter->convert($commentText); - } - /** * Get the next local ID relative to the linked entity. */ diff --git a/app/Activity/Controllers/CommentController.php b/app/Activity/Controllers/CommentController.php index 516bcac759a..340524cd069 100644 --- a/app/Activity/Controllers/CommentController.php +++ b/app/Activity/Controllers/CommentController.php @@ -22,8 +22,8 @@ public function __construct( */ public function savePageComment(Request $request, int $pageId) { - $this->validate($request, [ - 'text' => ['required', 'string'], + $input = $this->validate($request, [ + 'html' => ['required', 'string'], 'parent_id' => ['nullable', 'integer'], ]); @@ -39,7 +39,7 @@ public function savePageComment(Request $request, int $pageId) // Create a new comment. $this->checkPermission('comment-create-all'); - $comment = $this->commentRepo->create($page, $request->get('text'), $request->get('parent_id')); + $comment = $this->commentRepo->create($page, $input['html'], $input['parent_id'] ?? null); return view('comments.comment-branch', [ 'readOnly' => false, @@ -57,17 +57,20 @@ public function savePageComment(Request $request, int $pageId) */ public function update(Request $request, int $commentId) { - $this->validate($request, [ - 'text' => ['required', 'string'], + $input = $this->validate($request, [ + 'html' => ['required', 'string'], ]); $comment = $this->commentRepo->getById($commentId); $this->checkOwnablePermission('page-view', $comment->entity); $this->checkOwnablePermission('comment-update', $comment); - $comment = $this->commentRepo->update($comment, $request->get('text')); + $comment = $this->commentRepo->update($comment, $input['html']); - return view('comments.comment', ['comment' => $comment, 'readOnly' => false]); + return view('comments.comment', [ + 'comment' => $comment, + 'readOnly' => false, + ]); } /** diff --git a/resources/js/components/page-comment.js b/resources/js/components/page-comment.js index dc6ca826425..79c9d3c2c67 100644 --- a/resources/js/components/page-comment.js +++ b/resources/js/components/page-comment.js @@ -1,6 +1,6 @@ import {Component} from './component'; import {getLoading, htmlToDom} from '../services/dom'; -import {buildForInput} from "../wysiwyg/config"; +import {buildForInput} from '../wysiwyg/config'; export class PageComment extends Component { @@ -58,6 +58,7 @@ export class PageComment extends Component { this.toggleEditMode(true); if (this.wysiwygEditor) { + this.wysiwygEditor.focus(); return; } @@ -72,6 +73,7 @@ export class PageComment extends Component { window.tinymce.init(config).then(editors => { this.wysiwygEditor = editors[0]; + setTimeout(() => this.wysiwygEditor.focus(), 50); }); } @@ -81,7 +83,7 @@ export class PageComment extends Component { this.form.toggleAttribute('hidden', true); const reqData = { - text: this.input.value, + html: this.wysiwygEditor.getContent(), parent_id: this.parentId || null, }; diff --git a/resources/js/components/page-comments.js b/resources/js/components/page-comments.js index ebcc95f07f4..cfb0634a904 100644 --- a/resources/js/components/page-comments.js +++ b/resources/js/components/page-comments.js @@ -1,6 +1,6 @@ import {Component} from './component'; import {getLoading, htmlToDom} from '../services/dom'; -import {buildForInput} from "../wysiwyg/config"; +import {buildForInput} from '../wysiwyg/config'; export class PageComments extends Component { @@ -65,9 +65,8 @@ export class PageComments extends Component { this.form.after(loading); this.form.toggleAttribute('hidden', true); - const text = this.formInput.value; const reqData = { - text, + html: this.wysiwygEditor.getContent(), parent_id: this.parentId || null, }; @@ -92,6 +91,7 @@ export class PageComments extends Component { } resetForm() { + this.removeEditor(); this.formInput.value = ''; this.parentId = null; this.replyToRow.toggleAttribute('hidden', true); @@ -99,6 +99,7 @@ export class PageComments extends Component { } showForm() { + this.removeEditor(); this.formContainer.toggleAttribute('hidden', false); this.addButtonContainer.toggleAttribute('hidden', true); this.formContainer.scrollIntoView({behavior: 'smooth', block: 'nearest'}); @@ -118,6 +119,7 @@ export class PageComments extends Component { loadEditor() { if (this.wysiwygEditor) { + this.wysiwygEditor.focus(); return; } @@ -132,10 +134,17 @@ export class PageComments extends Component { window.tinymce.init(config).then(editors => { this.wysiwygEditor = editors[0]; - this.wysiwygEditor.focus(); + setTimeout(() => this.wysiwygEditor.focus(), 50); }); } + removeEditor() { + if (this.wysiwygEditor) { + this.wysiwygEditor.remove(); + this.wysiwygEditor = null; + } + } + getCommentCount() { return this.container.querySelectorAll('[component="page-comment"]').length; } diff --git a/resources/views/comments/comment.blade.php b/resources/views/comments/comment.blade.php index 4340cfdf5c4..e00307f0fbc 100644 --- a/resources/views/comments/comment.blade.php +++ b/resources/views/comments/comment.blade.php @@ -77,7 +77,7 @@ class="comment-box"> @if(!$readOnly && userCan('comment-update', $comment))