From 831f441879d20ac99645c242e81ae3d25bc96559 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 9 Jan 2021 19:04:23 +0000 Subject: [PATCH 1/6] Added in table + tasklist markdown rendering For parity with markdown-it renderer. Added tests to cover. For #2452 --- app/Entities/Tools/PageContent.php | 8 +++++- tests/Entity/PageContentTest.php | 41 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/app/Entities/Tools/PageContent.php b/app/Entities/Tools/PageContent.php index f60971b8b..91de94211 100644 --- a/app/Entities/Tools/PageContent.php +++ b/app/Entities/Tools/PageContent.php @@ -5,6 +5,9 @@ use DOMDocument; use DOMNodeList; use DOMXPath; use League\CommonMark\CommonMarkConverter; +use League\CommonMark\Environment; +use League\CommonMark\Extension\Table\TableExtension; +use League\CommonMark\Extension\TaskList\TaskListExtension; class PageContent { @@ -45,7 +48,10 @@ class PageContent */ protected function markdownToHtml(string $markdown): string { - $converter = new CommonMarkConverter(); + $environment = Environment::createCommonMarkEnvironment(); + $environment->addExtension(new TableExtension()); + $environment->addExtension(new TaskListExtension()); + $converter = new CommonMarkConverter([], $environment); return $converter->convertToHtml($markdown); } diff --git a/tests/Entity/PageContentTest.php b/tests/Entity/PageContentTest.php index 51a8568bf..857645823 100644 --- a/tests/Entity/PageContentTest.php +++ b/tests/Entity/PageContentTest.php @@ -420,4 +420,45 @@ class PageContentTest extends TestCase $page->refresh(); $this->assertEquals('"Hello & welcome"', $page->text); } + + public function test_page_markdown_table_rendering() + { + $this->asEditor(); + $page = Page::query()->first(); + + $content = '| Syntax | Description | +| ----------- | ----------- | +| Header | Title | +| Paragraph | Text |'; + $this->put($page->getUrl(), [ + 'name' => $page->name, 'markdown' => $content, + 'html' => '', 'summary' => '' + ]); + + $page->refresh(); + $this->assertStringContainsString('', $page->html); + + $pageView = $this->get($page->getUrl()); + $pageView->assertElementExists('.page-content table tbody td'); + } + + public function test_page_markdown_task_list_rendering() + { + $this->asEditor(); + $page = Page::query()->first(); + + $content = '- [ ] Item a +- [x] Item b'; + $this->put($page->getUrl(), [ + 'name' => $page->name, 'markdown' => $content, + 'html' => '', 'summary' => '' + ]); + + $page->refresh(); + $this->assertStringContainsString('input', $page->html); + $this->assertStringContainsString('type="checkbox"', $page->html); + + $pageView = $this->get($page->getUrl()); + $pageView->assertElementExists('.page-content input[type=checkbox]'); + } } From 526be33ab2a88609e0178187e013e22081263ee3 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 9 Jan 2021 19:39:09 +0000 Subject: [PATCH 2/6] Fixed page copying not retaining content Was when there was no markdown content. Added tests to cover both HTML and markdown scenarios. Also removed old console.log Related to #2463 --- app/Entities/Repos/PageRepo.php | 2 +- resources/js/components/page-editor.js | 1 - tests/Entity/PageTest.php | 91 ++++++++++++++++++++++++++ tests/Entity/SortTest.php | 69 ------------------- 4 files changed, 92 insertions(+), 71 deletions(-) diff --git a/app/Entities/Repos/PageRepo.php b/app/Entities/Repos/PageRepo.php index 9ca254f1e..4c59db468 100644 --- a/app/Entities/Repos/PageRepo.php +++ b/app/Entities/Repos/PageRepo.php @@ -210,7 +210,7 @@ class PageRepo } $pageContent = new PageContent($page); - if (isset($input['markdown'])) { + if (!empty($input['markdown'] ?? '')) { $pageContent->setNewMarkdown($input['markdown']); } else { $pageContent->setNewHTML($input['html']); diff --git a/resources/js/components/page-editor.js b/resources/js/components/page-editor.js index a0d8d38b1..f66e23b19 100644 --- a/resources/js/components/page-editor.js +++ b/resources/js/components/page-editor.js @@ -74,7 +74,6 @@ class PageEditor { } setInitialFocus() { - console.log({'HAS': this.hasDefaultTitle}); if (this.hasDefaultTitle) { return this.titleElem.select(); } diff --git a/tests/Entity/PageTest.php b/tests/Entity/PageTest.php index a49c8af20..4fc6b9c16 100644 --- a/tests/Entity/PageTest.php +++ b/tests/Entity/PageTest.php @@ -54,4 +54,95 @@ class PageTest extends TestCase $redirectReq = $this->get($deleteReq->baseResponse->headers->get('location')); $redirectReq->assertNotificationContains('Page Successfully Deleted'); } + + public function test_page_copy() + { + $page = Page::first(); + $page->html = '

This is some test content

'; + $page->save(); + + $currentBook = $page->book; + $newBook = Book::where('id', '!=', $currentBook->id)->first(); + + $resp = $this->asEditor()->get($page->getUrl('/copy')); + $resp->assertSee('Copy Page'); + + $movePageResp = $this->post($page->getUrl('/copy'), [ + 'entity_selection' => 'book:' . $newBook->id, + 'name' => 'My copied test page' + ]); + $pageCopy = Page::where('name', '=', 'My copied test page')->first(); + + $movePageResp->assertRedirect($pageCopy->getUrl()); + $this->assertTrue($pageCopy->book->id == $newBook->id, 'Page was copied to correct book'); + $this->assertStringContainsString('This is some test content', $pageCopy->html); + } + + public function test_page_copy_with_markdown_has_both_html_and_markdown() + { + $page = Page::first(); + $page->html = '

This is some test content

'; + $page->markdown = '# This is some test content'; + $page->save(); + $newBook = Book::where('id', '!=', $page->book->id)->first(); + + $this->asEditor()->post($page->getUrl('/copy'), [ + 'entity_selection' => 'book:' . $newBook->id, + 'name' => 'My copied test page' + ]); + $pageCopy = Page::where('name', '=', 'My copied test page')->first(); + + $this->assertStringContainsString('This is some test content', $pageCopy->html); + $this->assertEquals('# This is some test content', $pageCopy->markdown); + } + + public function test_page_copy_with_no_destination() + { + $page = Page::first(); + $currentBook = $page->book; + + $resp = $this->asEditor()->get($page->getUrl('/copy')); + $resp->assertSee('Copy Page'); + + $movePageResp = $this->post($page->getUrl('/copy'), [ + 'name' => 'My copied test page' + ]); + + $pageCopy = Page::where('name', '=', 'My copied test page')->first(); + + $movePageResp->assertRedirect($pageCopy->getUrl()); + $this->assertTrue($pageCopy->book->id == $currentBook->id, 'Page was copied to correct book'); + $this->assertTrue($pageCopy->id !== $page->id, 'Page copy is not the same instance'); + } + + public function test_page_can_be_copied_without_edit_permission() + { + $page = Page::first(); + $currentBook = $page->book; + $newBook = Book::where('id', '!=', $currentBook->id)->first(); + $viewer = $this->getViewer(); + + $resp = $this->actingAs($viewer)->get($page->getUrl()); + $resp->assertDontSee($page->getUrl('/copy')); + + $newBook->owned_by = $viewer->id; + $newBook->save(); + $this->giveUserPermissions($viewer, ['page-create-own']); + $this->regenEntityPermissions($newBook); + + $resp = $this->actingAs($viewer)->get($page->getUrl()); + $resp->assertSee($page->getUrl('/copy')); + + $movePageResp = $this->post($page->getUrl('/copy'), [ + 'entity_selection' => 'book:' . $newBook->id, + 'name' => 'My copied test page' + ]); + $movePageResp->assertRedirect(); + + $this->assertDatabaseHas('pages', [ + 'name' => 'My copied test page', + 'created_by' => $viewer->id, + 'book_id' => $newBook->id, + ]); + } } \ No newline at end of file diff --git a/tests/Entity/SortTest.php b/tests/Entity/SortTest.php index 01f764b7b..d75a134ea 100644 --- a/tests/Entity/SortTest.php +++ b/tests/Entity/SortTest.php @@ -239,73 +239,4 @@ class SortTest extends TestCase $checkResp->assertSee($newBook->name); } - public function test_page_copy() - { - $page = Page::first(); - $currentBook = $page->book; - $newBook = Book::where('id', '!=', $currentBook->id)->first(); - - $resp = $this->asEditor()->get($page->getUrl('/copy')); - $resp->assertSee('Copy Page'); - - $movePageResp = $this->post($page->getUrl('/copy'), [ - 'entity_selection' => 'book:' . $newBook->id, - 'name' => 'My copied test page' - ]); - $pageCopy = Page::where('name', '=', 'My copied test page')->first(); - - $movePageResp->assertRedirect($pageCopy->getUrl()); - $this->assertTrue($pageCopy->book->id == $newBook->id, 'Page was copied to correct book'); - } - - public function test_page_copy_with_no_destination() - { - $page = Page::first(); - $currentBook = $page->book; - - $resp = $this->asEditor()->get($page->getUrl('/copy')); - $resp->assertSee('Copy Page'); - - $movePageResp = $this->post($page->getUrl('/copy'), [ - 'name' => 'My copied test page' - ]); - - $pageCopy = Page::where('name', '=', 'My copied test page')->first(); - - $movePageResp->assertRedirect($pageCopy->getUrl()); - $this->assertTrue($pageCopy->book->id == $currentBook->id, 'Page was copied to correct book'); - $this->assertTrue($pageCopy->id !== $page->id, 'Page copy is not the same instance'); - } - - public function test_page_can_be_copied_without_edit_permission() - { - $page = Page::first(); - $currentBook = $page->book; - $newBook = Book::where('id', '!=', $currentBook->id)->first(); - $viewer = $this->getViewer(); - - $resp = $this->actingAs($viewer)->get($page->getUrl()); - $resp->assertDontSee($page->getUrl('/copy')); - - $newBook->owned_by = $viewer->id; - $newBook->save(); - $this->giveUserPermissions($viewer, ['page-create-own']); - $this->regenEntityPermissions($newBook); - - $resp = $this->actingAs($viewer)->get($page->getUrl()); - $resp->assertSee($page->getUrl('/copy')); - - $movePageResp = $this->post($page->getUrl('/copy'), [ - 'entity_selection' => 'book:' . $newBook->id, - 'name' => 'My copied test page' - ]); - $movePageResp->assertRedirect(); - - $this->assertDatabaseHas('pages', [ - 'name' => 'My copied test page', - 'created_by' => $viewer->id, - 'book_id' => $newBook->id, - ]); - } - } \ No newline at end of file From e5a96b0cb0788f44b331afa83f1279314a7bafd1 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 10 Jan 2021 13:29:13 +0000 Subject: [PATCH 3/6] Added test case for avatar failed fetch Fixed non-imported log issue while there. For #2449 --- app/Uploads/UserAvatars.php | 1 + tests/Uploads/AvatarTest.php | 27 ++++++++++++++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/app/Uploads/UserAvatars.php b/app/Uploads/UserAvatars.php index 92b06bc8a..b3b9d5951 100644 --- a/app/Uploads/UserAvatars.php +++ b/app/Uploads/UserAvatars.php @@ -3,6 +3,7 @@ use BookStack\Auth\User; use BookStack\Exceptions\HttpFetchException; use Exception; +use Illuminate\Support\Facades\Log; class UserAvatars { diff --git a/tests/Uploads/AvatarTest.php b/tests/Uploads/AvatarTest.php index ecf7037a9..efaa016dd 100644 --- a/tests/Uploads/AvatarTest.php +++ b/tests/Uploads/AvatarTest.php @@ -1,7 +1,9 @@ asAdmin()->post('/settings/users/create', [ + $this->asAdmin()->post('/settings/users/create', [ 'name' => $user->name, 'email' => $user->email, 'password' => 'testing', @@ -22,8 +24,7 @@ class AvatarTest extends TestCase protected function assertImageFetchFrom(string $url) { - $http = \Mockery::mock(HttpFetcher::class); - $this->app->instance(HttpFetcher::class, $http); + $http = $this->mock(HttpFetcher::class); $http->shouldReceive('fetch') ->once()->with($url) @@ -55,6 +56,7 @@ class AvatarTest extends TestCase public function test_custom_url_used_if_set() { config()->set([ + 'services.disable_services' => false, 'services.avatar_url' => 'https://example.com/${email}/${hash}/${size}', ]); @@ -74,11 +76,26 @@ class AvatarTest extends TestCase $user = factory(User::class)->make(); - $http = \Mockery::mock(HttpFetcher::class); - $this->app->instance(HttpFetcher::class, $http); + $http = $this->mock(HttpFetcher::class); $http->shouldNotReceive('fetch'); $this->createUserRequest($user); } + public function test_no_failure_but_error_logged_on_failed_avatar_fetch() + { + config()->set([ + 'services.disable_services' => false, + ]); + + $http = $this->mock(HttpFetcher::class); + $http->shouldReceive('fetch')->andThrow(new HttpFetchException()); + + $logger = $this->withTestLogger(); + + $user = factory(User::class)->make(); + $this->createUserRequest($user); + $this->assertTrue($logger->hasError('Failed to save user avatar image')); + } + } From 18f86fbf9b29460192d5e19341e81a954b9c1ac9 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 10 Jan 2021 13:36:46 +0000 Subject: [PATCH 4/6] Made recycle-bin settings navbar full width For #2468 --- resources/views/settings/recycle-bin/destroy.blade.php | 6 ++---- resources/views/settings/recycle-bin/index.blade.php | 6 ++---- resources/views/settings/recycle-bin/restore.blade.php | 6 ++---- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/resources/views/settings/recycle-bin/destroy.blade.php b/resources/views/settings/recycle-bin/destroy.blade.php index d027199b2..bd5ef79f0 100644 --- a/resources/views/settings/recycle-bin/destroy.blade.php +++ b/resources/views/settings/recycle-bin/destroy.blade.php @@ -3,10 +3,8 @@ @section('body')
-
-
- @include('settings.navbar', ['selected' => 'maintenance']) -
+
+ @include('settings.navbar', ['selected' => 'maintenance'])
diff --git a/resources/views/settings/recycle-bin/index.blade.php b/resources/views/settings/recycle-bin/index.blade.php index 7713945f0..b5de84efa 100644 --- a/resources/views/settings/recycle-bin/index.blade.php +++ b/resources/views/settings/recycle-bin/index.blade.php @@ -3,10 +3,8 @@ @section('body')
-
-
- @include('settings.navbar', ['selected' => 'maintenance']) -
+
+ @include('settings.navbar', ['selected' => 'maintenance'])
diff --git a/resources/views/settings/recycle-bin/restore.blade.php b/resources/views/settings/recycle-bin/restore.blade.php index 62a31e5cc..c888aa8e5 100644 --- a/resources/views/settings/recycle-bin/restore.blade.php +++ b/resources/views/settings/recycle-bin/restore.blade.php @@ -3,10 +3,8 @@ @section('body')
-
-
- @include('settings.navbar', ['selected' => 'maintenance']) -
+
+ @include('settings.navbar', ['selected' => 'maintenance'])
From 91efa601be03133e185dd544f03c2f9da2af9a02 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 10 Jan 2021 13:44:29 +0000 Subject: [PATCH 5/6] New Crowdin updates (#2464) * New translations entities.php (Chinese Traditional) * New translations entities.php (Chinese Traditional) * New translations settings.php (Italian) * New translations settings.php (Italian) * New translations settings.php (Russian) * New translations settings.php (Russian) * New translations entities.php (Russian) * New translations settings.php (Russian) * New translations activities.php (Russian) --- resources/lang/it/settings.php | 22 ++++++------ resources/lang/ru/activities.php | 2 +- resources/lang/ru/entities.php | 8 ++--- resources/lang/ru/settings.php | 56 +++++++++++++++---------------- resources/lang/zh_TW/entities.php | 6 ++-- 5 files changed, 47 insertions(+), 47 deletions(-) diff --git a/resources/lang/it/settings.php b/resources/lang/it/settings.php index 046a8f73f..f925de962 100755 --- a/resources/lang/it/settings.php +++ b/resources/lang/it/settings.php @@ -81,18 +81,18 @@ return [ 'maint_send_test_email_mail_greeting' => 'L\'invio delle email sembra funzionare!', 'maint_send_test_email_mail_text' => 'Congratulazioni! Siccome hai ricevuto questa notifica email, le tue impostazioni sembrano essere configurate correttamente.', 'maint_recycle_bin_desc' => 'Deleted shelves, books, chapters & pages are sent to the recycle bin so they can be restored or permanently deleted. Older items in the recycle bin may be automatically removed after a while depending on system configuration.', - 'maint_recycle_bin_open' => 'Open Recycle Bin', + 'maint_recycle_bin_open' => 'Apri il Cestino', // Recycle Bin - 'recycle_bin' => 'Recycle Bin', + 'recycle_bin' => 'Cestino', 'recycle_bin_desc' => 'Here you can restore items that have been deleted or choose to permanently remove them from the system. This list is unfiltered unlike similar activity lists in the system where permission filters are applied.', 'recycle_bin_deleted_item' => 'Deleted Item', - 'recycle_bin_deleted_by' => 'Deleted By', - 'recycle_bin_deleted_at' => 'Deletion Time', - 'recycle_bin_permanently_delete' => 'Permanently Delete', - 'recycle_bin_restore' => 'Restore', + 'recycle_bin_deleted_by' => 'Cancellato da', + 'recycle_bin_deleted_at' => 'Orario Cancellazione', + 'recycle_bin_permanently_delete' => 'Elimina Definitivamente', + 'recycle_bin_restore' => 'Ripristina', 'recycle_bin_contents_empty' => 'The recycle bin is currently empty', - 'recycle_bin_empty' => 'Empty Recycle Bin', + 'recycle_bin_empty' => 'Svuota Cestino', 'recycle_bin_empty_confirm' => 'This will permanently destroy all items in the recycle bin including content contained within each item. Are you sure you want to empty the recycle bin?', 'recycle_bin_destroy_confirm' => 'This action will permanently delete this item, along with any child elements listed below, from the system and you will not be able to restore this content. Are you sure you want to permanently delete this item?', 'recycle_bin_destroy_list' => 'Items to be Destroyed', @@ -109,8 +109,8 @@ return [ 'audit_event_filter_no_filter' => 'No Filter', 'audit_deleted_item' => 'Deleted Item', 'audit_deleted_item_name' => 'Name: :name', - 'audit_table_user' => 'User', - 'audit_table_event' => 'Event', + 'audit_table_user' => 'Utente', + 'audit_table_event' => 'Evento', 'audit_table_related' => 'Related Item or Detail', 'audit_table_date' => 'Activity Date', 'audit_date_from' => 'Date Range From', @@ -177,8 +177,8 @@ return [ 'users_delete_confirm' => 'Sei sicuro di voler eliminare questo utente?', 'users_migrate_ownership' => 'Migrate Ownership', 'users_migrate_ownership_desc' => 'Select a user here if you want another user to become the owner of all items currently owned by this user.', - 'users_none_selected' => 'No user selected', - 'users_delete_success' => 'User successfully removed', + 'users_none_selected' => 'Nessun utente selezionato', + 'users_delete_success' => 'Utente rimosso con successo', 'users_edit' => 'Modifica Utente', 'users_edit_profile' => 'Modifica Profilo', 'users_edit_success' => 'Utente aggiornato correttamente', diff --git a/resources/lang/ru/activities.php b/resources/lang/ru/activities.php index c33a01d9f..af5a7af1d 100644 --- a/resources/lang/ru/activities.php +++ b/resources/lang/ru/activities.php @@ -45,5 +45,5 @@ return [ // Other 'commented_on' => 'прокомментировал', - 'permissions_update' => 'updated permissions', + 'permissions_update' => 'обновил разрешения', ]; diff --git a/resources/lang/ru/entities.php b/resources/lang/ru/entities.php index 6563a4581..e78ffde65 100644 --- a/resources/lang/ru/entities.php +++ b/resources/lang/ru/entities.php @@ -22,7 +22,7 @@ return [ 'meta_created_name' => ':user создал :timeLength', 'meta_updated' => 'Обновлено :timeLength', 'meta_updated_name' => ':user обновил :timeLength', - 'meta_owned_name' => 'Owned by :user', + 'meta_owned_name' => 'Владелец :user', 'entity_select' => 'Выбор объекта', 'images' => 'Изображения', 'my_recent_drafts' => 'Мои последние черновики', @@ -40,7 +40,7 @@ return [ 'permissions_intro' => 'После включения опции эти разрешения будут иметь приоритет над любыми установленными разрешениями роли.', 'permissions_enable' => 'Включение пользовательских разрешений', 'permissions_save' => 'Сохранить разрешения', - 'permissions_owner' => 'Owner', + 'permissions_owner' => 'Владелец', // Search 'search_results' => 'Результаты поиска', @@ -148,7 +148,7 @@ return [ 'chapters_create' => 'Создать новую главу', 'chapters_delete' => 'Удалить главу', 'chapters_delete_named' => 'Удалить главу :chapterName', - 'chapters_delete_explain' => 'This will delete the chapter with the name \':chapterName\'. All pages that exist within this chapter will also be deleted.', + 'chapters_delete_explain' => 'Это действие удалит главу с названием \':chapterName\'. Все страницы, которые существуют в этой главе, также будут удалены.', 'chapters_delete_confirm' => 'Вы действительно хотите удалить эту главу?', 'chapters_edit' => 'Редактировать главу', 'chapters_edit_named' => 'Редактировать главу :chapterName', @@ -210,7 +210,7 @@ return [ 'pages_revisions' => 'Версии страницы', 'pages_revisions_named' => 'Версии страницы для :pageName', 'pages_revision_named' => 'Версия страницы для :pageName', - 'pages_revision_restored_from' => 'Restored from #:id; :summary', + 'pages_revision_restored_from' => 'Восстановлено из #:id; :summary', 'pages_revisions_created_by' => 'Создана', 'pages_revisions_date' => 'Дата версии', 'pages_revisions_number' => '#', diff --git a/resources/lang/ru/settings.php b/resources/lang/ru/settings.php index 0c51381d3..472973ca2 100755 --- a/resources/lang/ru/settings.php +++ b/resources/lang/ru/settings.php @@ -68,7 +68,7 @@ return [ 'maint' => 'Обслуживание', 'maint_image_cleanup' => 'Очистка изображений', 'maint_image_cleanup_desc' => "Сканирует содержимое страниц и предыдущих версий и определяет изображения, которые не используются. Убедитесь, что у вас есть резервная копия базы данных и папки изображений перед запуском этой функции.", - 'maint_delete_images_only_in_revisions' => 'Also delete images that only exist in old page revisions', + 'maint_delete_images_only_in_revisions' => 'Также удалять изображения, которые существуют только в старой версии страницы', 'maint_image_cleanup_run' => 'Выполнить очистку', 'maint_image_cleanup_warning' => 'Найдено :count возможно бесполезных изображений. Вы уверены, что хотите удалить эти изображения?', 'maint_image_cleanup_success' => ':count возможно бесполезных изображений было найдено и удалено!', @@ -80,38 +80,38 @@ return [ 'maint_send_test_email_mail_subject' => 'Проверка электронной почты', 'maint_send_test_email_mail_greeting' => 'Доставка электронной почты работает!', 'maint_send_test_email_mail_text' => 'Поздравляем! Поскольку вы получили это письмо, электронная почта настроена правильно.', - 'maint_recycle_bin_desc' => 'Deleted shelves, books, chapters & pages are sent to the recycle bin so they can be restored or permanently deleted. Older items in the recycle bin may be automatically removed after a while depending on system configuration.', - 'maint_recycle_bin_open' => 'Open Recycle Bin', + 'maint_recycle_bin_desc' => 'Удаленные полки, книги, главы и страницы отправляются в корзину, чтобы они могли быть восстановлены или удалены навсегда. Более старые элементы в корзине могут быть автоматически удалены через некоторое время в зависимости от системной конфигурации.', + 'maint_recycle_bin_open' => 'Открыть корзину', // Recycle Bin - 'recycle_bin' => 'Recycle Bin', - 'recycle_bin_desc' => 'Here you can restore items that have been deleted or choose to permanently remove them from the system. This list is unfiltered unlike similar activity lists in the system where permission filters are applied.', - 'recycle_bin_deleted_item' => 'Deleted Item', - 'recycle_bin_deleted_by' => 'Deleted By', - 'recycle_bin_deleted_at' => 'Deletion Time', - 'recycle_bin_permanently_delete' => 'Permanently Delete', - 'recycle_bin_restore' => 'Restore', - 'recycle_bin_contents_empty' => 'The recycle bin is currently empty', - 'recycle_bin_empty' => 'Empty Recycle Bin', - 'recycle_bin_empty_confirm' => 'This will permanently destroy all items in the recycle bin including content contained within each item. Are you sure you want to empty the recycle bin?', - 'recycle_bin_destroy_confirm' => 'This action will permanently delete this item, along with any child elements listed below, from the system and you will not be able to restore this content. Are you sure you want to permanently delete this item?', - 'recycle_bin_destroy_list' => 'Items to be Destroyed', - 'recycle_bin_restore_list' => 'Items to be Restored', - 'recycle_bin_restore_confirm' => 'This action will restore the deleted item, including any child elements, to their original location. If the original location has since been deleted, and is now in the recycle bin, the parent item will also need to be restored.', - 'recycle_bin_restore_deleted_parent' => 'The parent of this item has also been deleted. These will remain deleted until that parent is also restored.', - 'recycle_bin_destroy_notification' => 'Deleted :count total items from the recycle bin.', - 'recycle_bin_restore_notification' => 'Restored :count total items from the recycle bin.', + 'recycle_bin' => 'Корзина', + 'recycle_bin_desc' => 'Здесь вы можете восстановить удаленные элементы или навсегда удалить их из системы. Этот список не отфильтрован в отличие от аналогичных списков действий в системе, где применяются фильтры.', + 'recycle_bin_deleted_item' => 'Удаленный элемент', + 'recycle_bin_deleted_by' => 'Удалён', + 'recycle_bin_deleted_at' => 'Время удаления', + 'recycle_bin_permanently_delete' => 'Удалить навсегда', + 'recycle_bin_restore' => 'Восстановить', + 'recycle_bin_contents_empty' => 'На данный момент корзина пуста', + 'recycle_bin_empty' => 'Очистить корзину', + 'recycle_bin_empty_confirm' => 'Это действие навсегда уничтожит все элементы в корзине, включая содержимое, содержащееся в каждом элементе. Вы уверены, что хотите очистить корзину?', + 'recycle_bin_destroy_confirm' => 'Это действие удалит этот элемент навсегда вместе с любыми дочерними элементами, перечисленными ниже, и вы не сможете восстановить этот контент. Вы уверены, что хотите навсегда удалить этот элемент?', + 'recycle_bin_destroy_list' => 'Элементы для удаления', + 'recycle_bin_restore_list' => 'Элементы для восстановления', + 'recycle_bin_restore_confirm' => 'Это действие восстановит удаленный элемент, включая дочерние, в исходное место. Если исходное место было удалено и теперь находится в корзине, родительский элемент также необходимо будет восстановить.', + 'recycle_bin_restore_deleted_parent' => 'Родитель этого элемента также был удален. Элементы будут удалены до тех пор, пока этот родитель не будет восстановлен.', + 'recycle_bin_destroy_notification' => 'Удалено :count элементов из корзины.', + 'recycle_bin_restore_notification' => 'Восстановлено :count элементов из корзины', // Audit Log 'audit' => 'Журнал аудита', - 'audit_desc' => 'Этот журнал аудита отображает список действий, отслеживаемых в системе. Этот список не отфильтрован в отличие от аналогичных списков действий в системе, где применяются фильтры разрешений.', + 'audit_desc' => 'Этот журнал аудита отображает список действий, отслеживаемых в системе. Этот список не отфильтрован в отличие от аналогичных списков действий в системе, где применяются фильтры.', 'audit_event_filter' => 'Фильтр событий', 'audit_event_filter_no_filter' => 'Без фильтра', 'audit_deleted_item' => 'Удаленный элемент', 'audit_deleted_item_name' => 'Имя: :name', 'audit_table_user' => 'Пользователь', 'audit_table_event' => 'Событие', - 'audit_table_related' => 'Related Item or Detail', + 'audit_table_related' => 'Связанный элемент', 'audit_table_date' => 'Дата действия', 'audit_date_from' => 'Диапазон даты от', 'audit_date_to' => 'Диапазон даты до', @@ -157,7 +157,7 @@ return [ 'user_profile' => 'Профиль пользователя', 'users_add_new' => 'Добавить пользователя', 'users_search' => 'Поиск пользователей', - 'users_latest_activity' => 'Latest Activity', + 'users_latest_activity' => 'Последние действия', 'users_details' => 'Данные пользователя', 'users_details_desc' => 'Укажите имя и адрес электронной почты для этого пользователя. Адрес электронной почты будет использоваться для входа в приложение.', 'users_details_desc_no_email' => 'Задайте имя для этого пользователя, чтобы другие могли его узнать.', @@ -173,12 +173,12 @@ return [ 'users_system_public' => 'Этот пользователь представляет любых гостевых пользователей, которые посещают ваше приложение. Он не может использоваться для входа в систему и назначается автоматически.', 'users_delete' => 'Удалить пользователя', 'users_delete_named' => 'Удалить пользователя :userName', - 'users_delete_warning' => 'Это полностью удалит пользователя с именем \':userName\' из системы.', + 'users_delete_warning' => 'Это полностью удалит пользователя \':userName\' из системы.', 'users_delete_confirm' => 'Вы уверены что хотите удалить этого пользователя?', - 'users_migrate_ownership' => 'Migrate Ownership', - 'users_migrate_ownership_desc' => 'Select a user here if you want another user to become the owner of all items currently owned by this user.', - 'users_none_selected' => 'No user selected', - 'users_delete_success' => 'User successfully removed', + 'users_migrate_ownership' => 'Наследник контента', + 'users_migrate_ownership_desc' => 'Выберите пользователя, если вы хотите, чтобы он стал владельцем всех элементов, в настоящее время принадлежащих удаляемому пользователю.', + 'users_none_selected' => 'Пользователь не выбран', + 'users_delete_success' => 'Пользователь успешно удален', 'users_edit' => 'Редактировать пользователя', 'users_edit_profile' => 'Редактировать профиль', 'users_edit_success' => 'Пользователь успешно обновлен', diff --git a/resources/lang/zh_TW/entities.php b/resources/lang/zh_TW/entities.php index 124292c00..7f06a5460 100644 --- a/resources/lang/zh_TW/entities.php +++ b/resources/lang/zh_TW/entities.php @@ -22,7 +22,7 @@ return [ 'meta_created_name' => '由 :user 建立於 :timeLength', 'meta_updated' => '更新於 :timeLength', 'meta_updated_name' => '由 :user 更新於 :timeLength', - 'meta_owned_name' => 'Owned by :user', + 'meta_owned_name' => ':user 所擁有', 'entity_select' => '選擇項目', 'images' => '圖片', 'my_recent_drafts' => '我最近的草稿', @@ -40,7 +40,7 @@ return [ 'permissions_intro' => '本設定優先權高於每個使用者角色本身所具有的權限。', 'permissions_enable' => '啟用自訂權限', 'permissions_save' => '儲存權限', - 'permissions_owner' => 'Owner', + 'permissions_owner' => '擁有者', // Search 'search_results' => '搜尋結果', @@ -217,7 +217,7 @@ return [ 'pages_revisions_numbered' => '修訂編號:id', 'pages_revisions_numbered_changes' => '修訂編號:id 更改', 'pages_revisions_changelog' => '更新說明', - 'pages_revisions_changes' => '說明', + 'pages_revisions_changes' => '更新紀錄', 'pages_revisions_current' => '目前版本', 'pages_revisions_preview' => '預覽', 'pages_revisions_restore' => '恢複', From 44315233d7465f734ef833cc84bc322fc0438070 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 10 Jan 2021 14:04:38 +0000 Subject: [PATCH 6/6] Updated translator attribution before release v0.31.2 --- .github/translators.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/translators.txt b/.github/translators.txt index 901a34826..cd303d022 100644 --- a/.github/translators.txt +++ b/.github/translators.txt @@ -132,3 +132,4 @@ Kauê Sena (kaue.sena.ks) :: Portuguese, Brazilian MatthieuParis :: French Douradinho :: Portuguese, Brazilian Gaku Yaguchi (tama11) :: Japanese +johnroyer :: Chinese Traditional