Merge branch 'development' into release

This commit is contained in:
Dan Brown 2022-06-24 11:45:29 +01:00
commit 3ca15ad68a
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
313 changed files with 5477 additions and 1945 deletions

View File

@ -143,6 +143,10 @@ STORAGE_URL=false
# Can be 'standard', 'ldap', 'saml2' or 'oidc' # Can be 'standard', 'ldap', 'saml2' or 'oidc'
AUTH_METHOD=standard AUTH_METHOD=standard
# Automatically initiate login via external auth system if it's the only auth method.
# Works with saml2 or oidc auth methods.
AUTH_AUTO_INITIATE=false
# Social authentication configuration # Social authentication configuration
# All disabled by default. # All disabled by default.
# Refer to https://www.bookstackapp.com/docs/admin/third-party-auth/ # Refer to https://www.bookstackapp.com/docs/admin/third-party-auth/

1
.github/FUNDING.yml vendored
View File

@ -1,3 +1,4 @@
# These are supported funding model platforms # These are supported funding model platforms
github: [ssddanbrown] github: [ssddanbrown]
ko_fi: ssddanbrown

View File

@ -1,5 +1,5 @@
name: Language Request name: Language Request
description: Request a new language to be added to CrowdIn for you to translate description: Request a new language to be added to Crowdin for you to translate
labels: [":earth_africa: Translations"] labels: [":earth_africa: Translations"]
assignees: assignees:
- ssddanbrown - ssddanbrown
@ -23,7 +23,7 @@ body:
This issue template is to request a new language be added to our [Crowdin translation management project](https://crowdin.com/project/bookstack). This issue template is to request a new language be added to our [Crowdin translation management project](https://crowdin.com/project/bookstack).
Please don't use this template to request a new language that you are not prepared to provide translations for. Please don't use this template to request a new language that you are not prepared to provide translations for.
options: options:
- label: I confirm I'm offering to help translate for this new language via CrowdIn. - label: I confirm I'm offering to help translate for this new language via Crowdin.
required: true required: true
- type: markdown - type: markdown
attributes: attributes:

View File

@ -243,3 +243,18 @@ Shukrullo (vodiylik) :: Uzbek
William W. (Nevnt) :: Chinese Traditional William W. (Nevnt) :: Chinese Traditional
eamaro :: Portuguese eamaro :: Portuguese
Ypsilon-dev :: Arabic Ypsilon-dev :: Arabic
Hieu Vuong Trung (vuongtrunghieu) :: Vietnamese
David Clubb (davidoclubb) :: Welsh
welles freire (wellesximenes) :: Portuguese, Brazilian
Magnus Jensen (MagnusHJensen) :: Danish
Hesley Magno (hesleymagno) :: Portuguese, Brazilian
Éric Gaspar (erga) :: French
Fr3shlama :: German
DSR :: Spanish, Argentina
Andrii Bodnar (andrii-bodnar) :: Ukrainian
Younes el Anjri (younesea28) :: Dutch
Guclu Ozturk (gucluoz) :: Turkish
Atmis :: French
redjack666 :: Chinese Traditional
Ashita007 :: Russian
lihaorr :: Chinese Simplified

View File

@ -16,11 +16,13 @@ class ActivityType
const CHAPTER_MOVE = 'chapter_move'; const CHAPTER_MOVE = 'chapter_move';
const BOOK_CREATE = 'book_create'; const BOOK_CREATE = 'book_create';
const BOOK_CREATE_FROM_CHAPTER = 'book_create_from_chapter';
const BOOK_UPDATE = 'book_update'; const BOOK_UPDATE = 'book_update';
const BOOK_DELETE = 'book_delete'; const BOOK_DELETE = 'book_delete';
const BOOK_SORT = 'book_sort'; const BOOK_SORT = 'book_sort';
const BOOKSHELF_CREATE = 'bookshelf_create'; const BOOKSHELF_CREATE = 'bookshelf_create';
const BOOKSHELF_CREATE_FROM_BOOK = 'bookshelf_create_from_book';
const BOOKSHELF_UPDATE = 'bookshelf_update'; const BOOKSHELF_UPDATE = 'bookshelf_update';
const BOOKSHELF_DELETE = 'bookshelf_delete'; const BOOKSHELF_DELETE = 'bookshelf_delete';

View File

@ -28,10 +28,10 @@ class TagRepo
'name', 'name',
($searchTerm || $nameFilter) ? 'value' : DB::raw('COUNT(distinct value) as `values`'), ($searchTerm || $nameFilter) ? 'value' : DB::raw('COUNT(distinct value) as `values`'),
DB::raw('COUNT(id) as usages'), DB::raw('COUNT(id) as usages'),
DB::raw('SUM(IF(entity_type = \'BookStack\\\\Page\', 1, 0)) as page_count'), DB::raw('SUM(IF(entity_type = \'page\', 1, 0)) as page_count'),
DB::raw('SUM(IF(entity_type = \'BookStack\\\\Chapter\', 1, 0)) as chapter_count'), DB::raw('SUM(IF(entity_type = \'chapter\', 1, 0)) as chapter_count'),
DB::raw('SUM(IF(entity_type = \'BookStack\\\\Book\', 1, 0)) as book_count'), DB::raw('SUM(IF(entity_type = \'book\', 1, 0)) as book_count'),
DB::raw('SUM(IF(entity_type = \'BookStack\\\\BookShelf\', 1, 0)) as shelf_count'), DB::raw('SUM(IF(entity_type = \'bookshelf\', 1, 0)) as shelf_count'),
]) ])
->orderBy($nameFilter ? 'value' : 'name'); ->orderBy($nameFilter ? 'value' : 'name');

View File

@ -28,10 +28,8 @@ class GroupSyncService
*/ */
protected function externalIdMatchesGroupNames(string $externalId, array $groupNames): bool protected function externalIdMatchesGroupNames(string $externalId, array $groupNames): bool
{ {
$externalAuthIds = explode(',', strtolower($externalId)); foreach ($this->parseRoleExternalAuthId($externalId) as $externalAuthId) {
if (in_array($externalAuthId, $groupNames)) {
foreach ($externalAuthIds as $externalAuthId) {
if (in_array(trim($externalAuthId), $groupNames)) {
return true; return true;
} }
} }
@ -39,6 +37,18 @@ class GroupSyncService
return false; return false;
} }
protected function parseRoleExternalAuthId(string $externalId): array
{
$inputIds = preg_split('/(?<!\\\),/', $externalId);
$cleanIds = [];
foreach ($inputIds as $inputId) {
$cleanIds[] = str_replace('\,', ',', trim($inputId));
}
return $cleanIds;
}
/** /**
* Match an array of group names to BookStack system roles. * Match an array of group names to BookStack system roles.
* Formats group names to be lower-case and hyphenated. * Formats group names to be lower-case and hyphenated.

View File

@ -71,7 +71,7 @@ return [
'locale' => env('APP_LANG', 'en'), 'locale' => env('APP_LANG', 'en'),
// Locales available // Locales available
'locales' => ['en', 'ar', 'bg', 'bs', 'ca', 'cs', 'da', 'de', 'de_informal', 'es', 'es_AR', 'et', 'eu', 'fa', 'fr', 'he', 'hr', 'hu', 'id', 'it', 'ja', 'ko', 'lt', 'lv', 'nl', 'nb', 'pt', 'pt_BR', 'sk', 'sl', 'sv', 'pl', 'ru', 'th', 'tr', 'uk', 'uz', 'vi', 'zh_CN', 'zh_TW'], 'locales' => ['en', 'ar', 'bg', 'bs', 'ca', 'cs', 'cy', 'da', 'de', 'de_informal', 'es', 'es_AR', 'et', 'eu', 'fa', 'fr', 'he', 'hr', 'hu', 'id', 'it', 'ja', 'ko', 'lt', 'lv', 'nl', 'nb', 'pt', 'pt_BR', 'sk', 'sl', 'sv', 'pl', 'ru', 'th', 'tr', 'uk', 'uz', 'vi', 'zh_CN', 'zh_TW'],
// Application Fallback Locale // Application Fallback Locale
'fallback_locale' => 'en', 'fallback_locale' => 'en',

View File

@ -13,6 +13,10 @@ return [
// Options: standard, ldap, saml2, oidc // Options: standard, ldap, saml2, oidc
'method' => env('AUTH_METHOD', 'standard'), 'method' => env('AUTH_METHOD', 'standard'),
// Automatically initiate login via external auth system if it's the sole auth method.
// Works with saml2 or oidc auth methods.
'auto_initiate' => env('AUTH_AUTO_INITIATE', false),
// Authentication Defaults // Authentication Defaults
// This option controls the default authentication "guard" and password // This option controls the default authentication "guard" and password
// reset options for your application. // reset options for your application.

View File

@ -72,7 +72,7 @@ return [
// to the server if the browser has a HTTPS connection. This will keep // to the server if the browser has a HTTPS connection. This will keep
// the cookie from being sent to you if it can not be done securely. // the cookie from being sent to you if it can not be done securely.
'secure' => env('SESSION_SECURE_COOKIE', null) 'secure' => env('SESSION_SECURE_COOKIE', null)
?? Str::startsWith(env('APP_URL'), 'https:'), ?? Str::startsWith(env('APP_URL', ''), 'https:'),
// HTTP Access Only // HTTP Access Only
// Setting this value to true will prevent JavaScript from accessing the // Setting this value to true will prevent JavaScript from accessing the

View File

@ -91,6 +91,7 @@ class BookRepo
{ {
$book = new Book(); $book = new Book();
$this->baseRepo->create($book, $input); $this->baseRepo->create($book, $input);
$this->baseRepo->updateCoverImage($book, $input['image'] ?? null);
Activity::add(ActivityType::BOOK_CREATE, $book); Activity::add(ActivityType::BOOK_CREATE, $book);
return $book; return $book;
@ -102,6 +103,11 @@ class BookRepo
public function update(Book $book, array $input): Book public function update(Book $book, array $input): Book
{ {
$this->baseRepo->update($book, $input); $this->baseRepo->update($book, $input);
if (array_key_exists('image', $input)) {
$this->baseRepo->updateCoverImage($book, $input['image'], $input['image'] === null);
}
Activity::add(ActivityType::BOOK_UPDATE, $book); Activity::add(ActivityType::BOOK_UPDATE, $book);
return $book; return $book;

View File

@ -6,12 +6,10 @@ use BookStack\Actions\ActivityType;
use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Bookshelf; use BookStack\Entities\Models\Bookshelf;
use BookStack\Entities\Tools\TrashCan; use BookStack\Entities\Tools\TrashCan;
use BookStack\Exceptions\ImageUploadException;
use BookStack\Exceptions\NotFoundException; use BookStack\Exceptions\NotFoundException;
use BookStack\Facades\Activity; use BookStack\Facades\Activity;
use Exception; use Exception;
use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
class BookshelfRepo class BookshelfRepo
@ -89,6 +87,7 @@ class BookshelfRepo
{ {
$shelf = new Bookshelf(); $shelf = new Bookshelf();
$this->baseRepo->create($shelf, $input); $this->baseRepo->create($shelf, $input);
$this->baseRepo->updateCoverImage($shelf, $input['image'] ?? null);
$this->updateBooks($shelf, $bookIds); $this->updateBooks($shelf, $bookIds);
Activity::add(ActivityType::BOOKSHELF_CREATE, $shelf); Activity::add(ActivityType::BOOKSHELF_CREATE, $shelf);
@ -106,14 +105,17 @@ class BookshelfRepo
$this->updateBooks($shelf, $bookIds); $this->updateBooks($shelf, $bookIds);
} }
if (array_key_exists('image', $input)) {
$this->baseRepo->updateCoverImage($shelf, $input['image'], $input['image'] === null);
}
Activity::add(ActivityType::BOOKSHELF_UPDATE, $shelf); Activity::add(ActivityType::BOOKSHELF_UPDATE, $shelf);
return $shelf; return $shelf;
} }
/** /**
* Update which books are assigned to this shelf by * Update which books are assigned to this shelf by syncing the given book ids.
* syncing the given book ids.
* Function ensures the books are visible to the current user and existing. * Function ensures the books are visible to the current user and existing.
*/ */
protected function updateBooks(Bookshelf $shelf, array $bookIds) protected function updateBooks(Bookshelf $shelf, array $bookIds)
@ -132,17 +134,6 @@ class BookshelfRepo
$shelf->books()->sync($syncData); $shelf->books()->sync($syncData);
} }
/**
* Update the given shelf cover image, or clear it.
*
* @throws ImageUploadException
* @throws Exception
*/
public function updateCoverImage(Bookshelf $shelf, ?UploadedFile $coverImage, bool $removeImage = false)
{
$this->baseRepo->updateCoverImage($shelf, $coverImage, $removeImage);
}
/** /**
* Copy down the permissions of the given shelf to all child books. * Copy down the permissions of the given shelf to all child books.
*/ */

View File

@ -392,23 +392,6 @@ class PageRepo
return $parentClass::visible()->where('id', '=', $entityId)->first(); return $parentClass::visible()->where('id', '=', $entityId)->first();
} }
/**
* Change the page's parent to the given entity.
*/
protected function changeParent(Page $page, Entity $parent)
{
$book = ($parent instanceof Chapter) ? $parent->book : $parent;
$page->chapter_id = ($parent instanceof Chapter) ? $parent->id : 0;
$page->save();
if ($page->book->id !== $book->id) {
$page->changeBook($book->id);
}
$page->load('book');
$book->rebuildPermissions();
}
/** /**
* Get a page revision to update for the given page. * Get a page revision to update for the given page.
* Checks for an existing revisions before providing a fresh one. * Checks for an existing revisions before providing a fresh one.

View File

@ -16,25 +16,10 @@ use Illuminate\Http\UploadedFile;
class Cloner class Cloner
{ {
/** protected PageRepo $pageRepo;
* @var PageRepo protected ChapterRepo $chapterRepo;
*/ protected BookRepo $bookRepo;
protected $pageRepo; protected ImageService $imageService;
/**
* @var ChapterRepo
*/
protected $chapterRepo;
/**
* @var BookRepo
*/
protected $bookRepo;
/**
* @var ImageService
*/
protected $imageService;
public function __construct(PageRepo $pageRepo, ChapterRepo $chapterRepo, BookRepo $bookRepo, ImageService $imageService) public function __construct(PageRepo $pageRepo, ChapterRepo $chapterRepo, BookRepo $bookRepo, ImageService $imageService)
{ {
@ -50,11 +35,8 @@ class Cloner
public function clonePage(Page $original, Entity $parent, string $newName): Page public function clonePage(Page $original, Entity $parent, string $newName): Page
{ {
$copyPage = $this->pageRepo->getNewDraftPage($parent); $copyPage = $this->pageRepo->getNewDraftPage($parent);
$pageData = $original->getAttributes(); $pageData = $this->entityToInputData($original);
// Update name & tags
$pageData['name'] = $newName; $pageData['name'] = $newName;
$pageData['tags'] = $this->entityTagsToInputArray($original);
return $this->pageRepo->publishDraft($copyPage, $pageData); return $this->pageRepo->publishDraft($copyPage, $pageData);
} }
@ -65,9 +47,8 @@ class Cloner
*/ */
public function cloneChapter(Chapter $original, Book $parent, string $newName): Chapter public function cloneChapter(Chapter $original, Book $parent, string $newName): Chapter
{ {
$chapterDetails = $original->getAttributes(); $chapterDetails = $this->entityToInputData($original);
$chapterDetails['name'] = $newName; $chapterDetails['name'] = $newName;
$chapterDetails['tags'] = $this->entityTagsToInputArray($original);
$copyChapter = $this->chapterRepo->create($chapterDetails, $parent); $copyChapter = $this->chapterRepo->create($chapterDetails, $parent);
@ -87,9 +68,8 @@ class Cloner
*/ */
public function cloneBook(Book $original, string $newName): Book public function cloneBook(Book $original, string $newName): Book
{ {
$bookDetails = $original->getAttributes(); $bookDetails = $this->entityToInputData($original);
$bookDetails['name'] = $newName; $bookDetails['name'] = $newName;
$bookDetails['tags'] = $this->entityTagsToInputArray($original);
$copyBook = $this->bookRepo->create($bookDetails); $copyBook = $this->bookRepo->create($bookDetails);
@ -104,26 +84,48 @@ class Cloner
} }
} }
if ($original->cover) { return $copyBook;
try {
$tmpImgFile = tmpfile();
$uploadedFile = $this->imageToUploadedFile($original->cover, $tmpImgFile);
$this->bookRepo->updateCoverImage($copyBook, $uploadedFile, false);
} catch (\Exception $exception) {
}
} }
return $copyBook; /**
* Convert an entity to a raw data array of input data.
*
* @return array<string, mixed>
*/
public function entityToInputData(Entity $entity): array
{
$inputData = $entity->getAttributes();
$inputData['tags'] = $this->entityTagsToInputArray($entity);
// Add a cover to the data if existing on the original entity
if ($entity->cover instanceof Image) {
$uploadedFile = $this->imageToUploadedFile($entity->cover);
$inputData['image'] = $uploadedFile;
}
return $inputData;
}
/**
* Copy the permission settings from the source entity to the target entity.
*/
public function copyEntityPermissions(Entity $sourceEntity, Entity $targetEntity): void
{
$targetEntity->restricted = $sourceEntity->restricted;
$permissions = $sourceEntity->permissions()->get(['role_id', 'action'])->toArray();
$targetEntity->permissions()->delete();
$targetEntity->permissions()->createMany($permissions);
$targetEntity->rebuildPermissions();
} }
/** /**
* Convert an image instance to an UploadedFile instance to mimic * Convert an image instance to an UploadedFile instance to mimic
* a file being uploaded. * a file being uploaded.
*/ */
protected function imageToUploadedFile(Image $image, &$tmpFile): ?UploadedFile protected function imageToUploadedFile(Image $image): ?UploadedFile
{ {
$imgData = $this->imageService->getImageData($image); $imgData = $this->imageService->getImageData($image);
$tmpImgFilePath = stream_get_meta_data($tmpFile)['uri']; $tmpImgFilePath = tempnam(sys_get_temp_dir(), 'bs_cover_clone_');
file_put_contents($tmpImgFilePath, $imgData); file_put_contents($tmpImgFilePath, $imgData);
return new UploadedFile($tmpImgFilePath, basename($image->path)); return new UploadedFile($tmpImgFilePath, basename($image->path));

View File

@ -39,7 +39,7 @@ class ExportFormatter
public function pageToContainedHtml(Page $page) public function pageToContainedHtml(Page $page)
{ {
$page->html = (new PageContent($page))->render(); $page->html = (new PageContent($page))->render();
$pageHtml = view('pages.export', [ $pageHtml = view('exports.page', [
'page' => $page, 'page' => $page,
'format' => 'html', 'format' => 'html',
'cspContent' => $this->cspService->getCspMetaTagValue(), 'cspContent' => $this->cspService->getCspMetaTagValue(),
@ -59,7 +59,7 @@ class ExportFormatter
$pages->each(function ($page) { $pages->each(function ($page) {
$page->html = (new PageContent($page))->render(); $page->html = (new PageContent($page))->render();
}); });
$html = view('chapters.export', [ $html = view('exports.chapter', [
'chapter' => $chapter, 'chapter' => $chapter,
'pages' => $pages, 'pages' => $pages,
'format' => 'html', 'format' => 'html',
@ -77,7 +77,7 @@ class ExportFormatter
public function bookToContainedHtml(Book $book) public function bookToContainedHtml(Book $book)
{ {
$bookTree = (new BookContents($book))->getTree(false, true); $bookTree = (new BookContents($book))->getTree(false, true);
$html = view('books.export', [ $html = view('exports.book', [
'book' => $book, 'book' => $book,
'bookChildren' => $bookTree, 'bookChildren' => $bookTree,
'format' => 'html', 'format' => 'html',
@ -95,7 +95,7 @@ class ExportFormatter
public function pageToPdf(Page $page) public function pageToPdf(Page $page)
{ {
$page->html = (new PageContent($page))->render(); $page->html = (new PageContent($page))->render();
$html = view('pages.export', [ $html = view('exports.page', [
'page' => $page, 'page' => $page,
'format' => 'pdf', 'format' => 'pdf',
'engine' => $this->pdfGenerator->getActiveEngine(), 'engine' => $this->pdfGenerator->getActiveEngine(),
@ -116,7 +116,7 @@ class ExportFormatter
$page->html = (new PageContent($page))->render(); $page->html = (new PageContent($page))->render();
}); });
$html = view('chapters.export', [ $html = view('exports.chapter', [
'chapter' => $chapter, 'chapter' => $chapter,
'pages' => $pages, 'pages' => $pages,
'format' => 'pdf', 'format' => 'pdf',
@ -134,7 +134,7 @@ class ExportFormatter
public function bookToPdf(Book $book) public function bookToPdf(Book $book)
{ {
$bookTree = (new BookContents($book))->getTree(false, true); $bookTree = (new BookContents($book))->getTree(false, true);
$html = view('books.export', [ $html = view('exports.book', [
'book' => $book, 'book' => $book,
'bookChildren' => $bookTree, 'bookChildren' => $bookTree,
'format' => 'pdf', 'format' => 'pdf',

View File

@ -0,0 +1,87 @@
<?php
namespace BookStack\Entities\Tools;
use BookStack\Actions\ActivityType;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Bookshelf;
use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Page;
use BookStack\Entities\Repos\BookRepo;
use BookStack\Entities\Repos\BookshelfRepo;
use BookStack\Facades\Activity;
class HierarchyTransformer
{
protected BookRepo $bookRepo;
protected BookshelfRepo $shelfRepo;
protected Cloner $cloner;
protected TrashCan $trashCan;
public function __construct(BookRepo $bookRepo, BookshelfRepo $shelfRepo, Cloner $cloner, TrashCan $trashCan)
{
$this->bookRepo = $bookRepo;
$this->shelfRepo = $shelfRepo;
$this->cloner = $cloner;
$this->trashCan = $trashCan;
}
/**
* Transform a chapter into a book.
* Does not check permissions, check before calling.
*/
public function transformChapterToBook(Chapter $chapter): Book
{
$inputData = $this->cloner->entityToInputData($chapter);
$book = $this->bookRepo->create($inputData);
$this->cloner->copyEntityPermissions($chapter, $book);
/** @var Page $page */
foreach ($chapter->pages as $page) {
$page->chapter_id = 0;
$page->changeBook($book->id);
}
$this->trashCan->destroyEntity($chapter);
Activity::add(ActivityType::BOOK_CREATE_FROM_CHAPTER, $book);
return $book;
}
/**
* Transform a book into a shelf.
* Does not check permissions, check before calling.
*/
public function transformBookToShelf(Book $book): Bookshelf
{
$inputData = $this->cloner->entityToInputData($book);
$shelf = $this->shelfRepo->create($inputData, []);
$this->cloner->copyEntityPermissions($book, $shelf);
$shelfBookSyncData = [];
/** @var Chapter $chapter */
foreach ($book->chapters as $index => $chapter) {
$newBook = $this->transformChapterToBook($chapter);
$shelfBookSyncData[$newBook->id] = ['order' => $index];
if (!$newBook->restricted) {
$this->cloner->copyEntityPermissions($shelf, $newBook);
}
}
if ($book->directPages->count() > 0) {
$book->name .= ' ' . trans('entities.pages');
$shelfBookSyncData[$book->id] = ['order' => count($shelfBookSyncData) + 1];
$book->save();
} else {
$this->trashCan->destroyEntity($book);
}
$shelf->books()->sync($shelfBookSyncData);
Activity::add(ActivityType::BOOKSHELF_CREATE_FROM_BOOK, $shelf);
return $shelf;
}
}

View File

@ -147,6 +147,8 @@ class SearchIndex
]; ];
$html = '<body>' . $html . '</body>'; $html = '<body>' . $html . '</body>';
$html = str_ireplace(['<br>', '<br />', '<br/>'], "\n", $html);
libxml_use_internal_errors(true); libxml_use_internal_errors(true);
$doc = new DOMDocument(); $doc = new DOMDocument();
$doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8')); $doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));

View File

@ -344,7 +344,7 @@ class TrashCan
* *
* @throws Exception * @throws Exception
*/ */
protected function destroyEntity(Entity $entity): int public function destroyEntity(Entity $entity): int
{ {
if ($entity instanceof Page) { if ($entity instanceof Page) {
return $this->destroyPage($entity); return $this->destroyPage($entity);

View File

@ -21,6 +21,7 @@ class Handler extends ExceptionHandler
*/ */
protected $dontReport = [ protected $dontReport = [
NotFoundException::class, NotFoundException::class,
StoppedAuthenticationException::class,
]; ];
/** /**

View File

@ -11,19 +11,6 @@ class BookApiController extends ApiController
{ {
protected $bookRepo; protected $bookRepo;
protected $rules = [
'create' => [
'name' => ['required', 'string', 'max:255'],
'description' => ['string', 'max:1000'],
'tags' => ['array'],
],
'update' => [
'name' => ['string', 'min:1', 'max:255'],
'description' => ['string', 'max:1000'],
'tags' => ['array'],
],
];
public function __construct(BookRepo $bookRepo) public function __construct(BookRepo $bookRepo)
{ {
$this->bookRepo = $bookRepo; $this->bookRepo = $bookRepo;
@ -37,19 +24,21 @@ class BookApiController extends ApiController
$books = Book::visible(); $books = Book::visible();
return $this->apiListingResponse($books, [ return $this->apiListingResponse($books, [
'id', 'name', 'slug', 'description', 'created_at', 'updated_at', 'created_by', 'updated_by', 'owned_by', 'image_id', 'id', 'name', 'slug', 'description', 'created_at', 'updated_at', 'created_by', 'updated_by', 'owned_by',
]); ]);
} }
/** /**
* Create a new book in the system. * Create a new book in the system.
* The cover image of a book can be set by sending a file via an 'image' property within a 'multipart/form-data' request.
* If the 'image' property is null then the book cover image will be removed.
* *
* @throws ValidationException * @throws ValidationException
*/ */
public function create(Request $request) public function create(Request $request)
{ {
$this->checkPermission('book-create-all'); $this->checkPermission('book-create-all');
$requestData = $this->validate($request, $this->rules['create']); $requestData = $this->validate($request, $this->rules()['create']);
$book = $this->bookRepo->create($requestData); $book = $this->bookRepo->create($requestData);
@ -68,6 +57,8 @@ class BookApiController extends ApiController
/** /**
* Update the details of a single book. * Update the details of a single book.
* The cover image of a book can be set by sending a file via an 'image' property within a 'multipart/form-data' request.
* If the 'image' property is null then the book cover image will be removed.
* *
* @throws ValidationException * @throws ValidationException
*/ */
@ -76,7 +67,7 @@ class BookApiController extends ApiController
$book = Book::visible()->findOrFail($id); $book = Book::visible()->findOrFail($id);
$this->checkOwnablePermission('book-update', $book); $this->checkOwnablePermission('book-update', $book);
$requestData = $this->validate($request, $this->rules['update']); $requestData = $this->validate($request, $this->rules()['update']);
$book = $this->bookRepo->update($book, $requestData); $book = $this->bookRepo->update($book, $requestData);
return response()->json($book); return response()->json($book);
@ -97,4 +88,22 @@ class BookApiController extends ApiController
return response('', 204); return response('', 204);
} }
protected function rules(): array
{
return [
'create' => [
'name' => ['required', 'string', 'max:255'],
'description' => ['string', 'max:1000'],
'tags' => ['array'],
'image' => array_merge(['nullable'], $this->getImageValidationRules()),
],
'update' => [
'name' => ['string', 'min:1', 'max:255'],
'description' => ['string', 'max:1000'],
'tags' => ['array'],
'image' => array_merge(['nullable'], $this->getImageValidationRules()),
],
];
}
} }

View File

@ -26,7 +26,7 @@ class BookExportApiController extends ApiController
$book = Book::visible()->findOrFail($id); $book = Book::visible()->findOrFail($id);
$pdfContent = $this->exportFormatter->bookToPdf($book); $pdfContent = $this->exportFormatter->bookToPdf($book);
return $this->downloadResponse($pdfContent, $book->slug . '.pdf'); return $this->download()->directly($pdfContent, $book->slug . '.pdf');
} }
/** /**
@ -39,7 +39,7 @@ class BookExportApiController extends ApiController
$book = Book::visible()->findOrFail($id); $book = Book::visible()->findOrFail($id);
$htmlContent = $this->exportFormatter->bookToContainedHtml($book); $htmlContent = $this->exportFormatter->bookToContainedHtml($book);
return $this->downloadResponse($htmlContent, $book->slug . '.html'); return $this->download()->directly($htmlContent, $book->slug . '.html');
} }
/** /**
@ -50,7 +50,7 @@ class BookExportApiController extends ApiController
$book = Book::visible()->findOrFail($id); $book = Book::visible()->findOrFail($id);
$textContent = $this->exportFormatter->bookToPlainText($book); $textContent = $this->exportFormatter->bookToPlainText($book);
return $this->downloadResponse($textContent, $book->slug . '.txt'); return $this->download()->directly($textContent, $book->slug . '.txt');
} }
/** /**
@ -61,6 +61,6 @@ class BookExportApiController extends ApiController
$book = Book::visible()->findOrFail($id); $book = Book::visible()->findOrFail($id);
$markdown = $this->exportFormatter->bookToMarkdown($book); $markdown = $this->exportFormatter->bookToMarkdown($book);
return $this->downloadResponse($markdown, $book->slug . '.md'); return $this->download()->directly($markdown, $book->slug . '.md');
} }
} }

View File

@ -13,21 +13,6 @@ class BookshelfApiController extends ApiController
{ {
protected BookshelfRepo $bookshelfRepo; protected BookshelfRepo $bookshelfRepo;
protected $rules = [
'create' => [
'name' => ['required', 'string', 'max:255'],
'description' => ['string', 'max:1000'],
'books' => ['array'],
'tags' => ['array'],
],
'update' => [
'name' => ['string', 'min:1', 'max:255'],
'description' => ['string', 'max:1000'],
'books' => ['array'],
'tags' => ['array'],
],
];
/** /**
* BookshelfApiController constructor. * BookshelfApiController constructor.
*/ */
@ -44,7 +29,7 @@ class BookshelfApiController extends ApiController
$shelves = Bookshelf::visible(); $shelves = Bookshelf::visible();
return $this->apiListingResponse($shelves, [ return $this->apiListingResponse($shelves, [
'id', 'name', 'slug', 'description', 'created_at', 'updated_at', 'created_by', 'updated_by', 'owned_by', 'image_id', 'id', 'name', 'slug', 'description', 'created_at', 'updated_at', 'created_by', 'updated_by', 'owned_by',
]); ]);
} }
@ -52,13 +37,15 @@ class BookshelfApiController extends ApiController
* Create a new shelf in the system. * Create a new shelf in the system.
* An array of books IDs can be provided in the request. These * An array of books IDs can be provided in the request. These
* will be added to the shelf in the same order as provided. * will be added to the shelf in the same order as provided.
* The cover image of a shelf can be set by sending a file via an 'image' property within a 'multipart/form-data' request.
* If the 'image' property is null then the shelf cover image will be removed.
* *
* @throws ValidationException * @throws ValidationException
*/ */
public function create(Request $request) public function create(Request $request)
{ {
$this->checkPermission('bookshelf-create-all'); $this->checkPermission('bookshelf-create-all');
$requestData = $this->validate($request, $this->rules['create']); $requestData = $this->validate($request, $this->rules()['create']);
$bookIds = $request->get('books', []); $bookIds = $request->get('books', []);
$shelf = $this->bookshelfRepo->create($requestData, $bookIds); $shelf = $this->bookshelfRepo->create($requestData, $bookIds);
@ -86,6 +73,8 @@ class BookshelfApiController extends ApiController
* An array of books IDs can be provided in the request. These * An array of books IDs can be provided in the request. These
* will be added to the shelf in the same order as provided and overwrite * will be added to the shelf in the same order as provided and overwrite
* any existing book assignments. * any existing book assignments.
* The cover image of a shelf can be set by sending a file via an 'image' property within a 'multipart/form-data' request.
* If the 'image' property is null then the shelf cover image will be removed.
* *
* @throws ValidationException * @throws ValidationException
*/ */
@ -94,7 +83,7 @@ class BookshelfApiController extends ApiController
$shelf = Bookshelf::visible()->findOrFail($id); $shelf = Bookshelf::visible()->findOrFail($id);
$this->checkOwnablePermission('bookshelf-update', $shelf); $this->checkOwnablePermission('bookshelf-update', $shelf);
$requestData = $this->validate($request, $this->rules['update']); $requestData = $this->validate($request, $this->rules()['update']);
$bookIds = $request->get('books', null); $bookIds = $request->get('books', null);
$shelf = $this->bookshelfRepo->update($shelf, $requestData, $bookIds); $shelf = $this->bookshelfRepo->update($shelf, $requestData, $bookIds);
@ -117,4 +106,24 @@ class BookshelfApiController extends ApiController
return response('', 204); return response('', 204);
} }
protected function rules(): array
{
return [
'create' => [
'name' => ['required', 'string', 'max:255'],
'description' => ['string', 'max:1000'],
'books' => ['array'],
'tags' => ['array'],
'image' => array_merge(['nullable'], $this->getImageValidationRules()),
],
'update' => [
'name' => ['string', 'min:1', 'max:255'],
'description' => ['string', 'max:1000'],
'books' => ['array'],
'tags' => ['array'],
'image' => array_merge(['nullable'], $this->getImageValidationRules()),
],
];
}
} }

View File

@ -29,7 +29,7 @@ class ChapterExportApiController extends ApiController
$chapter = Chapter::visible()->findOrFail($id); $chapter = Chapter::visible()->findOrFail($id);
$pdfContent = $this->exportFormatter->chapterToPdf($chapter); $pdfContent = $this->exportFormatter->chapterToPdf($chapter);
return $this->downloadResponse($pdfContent, $chapter->slug . '.pdf'); return $this->download()->directly($pdfContent, $chapter->slug . '.pdf');
} }
/** /**
@ -42,7 +42,7 @@ class ChapterExportApiController extends ApiController
$chapter = Chapter::visible()->findOrFail($id); $chapter = Chapter::visible()->findOrFail($id);
$htmlContent = $this->exportFormatter->chapterToContainedHtml($chapter); $htmlContent = $this->exportFormatter->chapterToContainedHtml($chapter);
return $this->downloadResponse($htmlContent, $chapter->slug . '.html'); return $this->download()->directly($htmlContent, $chapter->slug . '.html');
} }
/** /**
@ -53,7 +53,7 @@ class ChapterExportApiController extends ApiController
$chapter = Chapter::visible()->findOrFail($id); $chapter = Chapter::visible()->findOrFail($id);
$textContent = $this->exportFormatter->chapterToPlainText($chapter); $textContent = $this->exportFormatter->chapterToPlainText($chapter);
return $this->downloadResponse($textContent, $chapter->slug . '.txt'); return $this->download()->directly($textContent, $chapter->slug . '.txt');
} }
/** /**
@ -64,6 +64,6 @@ class ChapterExportApiController extends ApiController
$chapter = Chapter::visible()->findOrFail($id); $chapter = Chapter::visible()->findOrFail($id);
$markdown = $this->exportFormatter->chapterToMarkdown($chapter); $markdown = $this->exportFormatter->chapterToMarkdown($chapter);
return $this->downloadResponse($markdown, $chapter->slug . '.md'); return $this->download()->directly($markdown, $chapter->slug . '.md');
} }
} }

View File

@ -26,7 +26,7 @@ class PageExportApiController extends ApiController
$page = Page::visible()->findOrFail($id); $page = Page::visible()->findOrFail($id);
$pdfContent = $this->exportFormatter->pageToPdf($page); $pdfContent = $this->exportFormatter->pageToPdf($page);
return $this->downloadResponse($pdfContent, $page->slug . '.pdf'); return $this->download()->directly($pdfContent, $page->slug . '.pdf');
} }
/** /**
@ -39,7 +39,7 @@ class PageExportApiController extends ApiController
$page = Page::visible()->findOrFail($id); $page = Page::visible()->findOrFail($id);
$htmlContent = $this->exportFormatter->pageToContainedHtml($page); $htmlContent = $this->exportFormatter->pageToContainedHtml($page);
return $this->downloadResponse($htmlContent, $page->slug . '.html'); return $this->download()->directly($htmlContent, $page->slug . '.html');
} }
/** /**
@ -50,7 +50,7 @@ class PageExportApiController extends ApiController
$page = Page::visible()->findOrFail($id); $page = Page::visible()->findOrFail($id);
$textContent = $this->exportFormatter->pageToPlainText($page); $textContent = $this->exportFormatter->pageToPlainText($page);
return $this->downloadResponse($textContent, $page->slug . '.txt'); return $this->download()->directly($textContent, $page->slug . '.txt');
} }
/** /**
@ -61,6 +61,6 @@ class PageExportApiController extends ApiController
$page = Page::visible()->findOrFail($id); $page = Page::visible()->findOrFail($id);
$markdown = $this->exportFormatter->pageToMarkdown($page); $markdown = $this->exportFormatter->pageToMarkdown($page);
return $this->downloadResponse($markdown, $page->slug . '.md'); return $this->download()->directly($markdown, $page->slug . '.md');
} }
} }

View File

@ -233,10 +233,10 @@ class AttachmentController extends Controller
$attachmentStream = $this->attachmentService->streamAttachmentFromStorage($attachment); $attachmentStream = $this->attachmentService->streamAttachmentFromStorage($attachment);
if ($request->get('open') === 'true') { if ($request->get('open') === 'true') {
return $this->streamedInlineDownloadResponse($attachmentStream, $fileName); return $this->download()->streamedInline($attachmentStream, $fileName);
} }
return $this->streamedDownloadResponse($attachmentStream, $fileName); return $this->download()->streamedDirectly($attachmentStream, $fileName);
} }
/** /**

View File

@ -25,17 +25,16 @@ class LoginController extends Controller
| |
*/ */
use AuthenticatesUsers; use AuthenticatesUsers { logout as traitLogout; }
/** /**
* Redirection paths. * Redirection paths.
*/ */
protected $redirectTo = '/'; protected $redirectTo = '/';
protected $redirectPath = '/'; protected $redirectPath = '/';
protected $redirectAfterLogout = '/login';
protected $socialAuthService; protected SocialAuthService $socialAuthService;
protected $loginService; protected LoginService $loginService;
/** /**
* Create a new controller instance. * Create a new controller instance.
@ -50,7 +49,6 @@ class LoginController extends Controller
$this->loginService = $loginService; $this->loginService = $loginService;
$this->redirectPath = url('/'); $this->redirectPath = url('/');
$this->redirectAfterLogout = url('/login');
} }
public function username() public function username()
@ -73,6 +71,7 @@ class LoginController extends Controller
{ {
$socialDrivers = $this->socialAuthService->getActiveDrivers(); $socialDrivers = $this->socialAuthService->getActiveDrivers();
$authMethod = config('auth.method'); $authMethod = config('auth.method');
$preventInitiation = $request->get('prevent_auto_init') === 'true';
if ($request->has('email')) { if ($request->has('email')) {
session()->flashInput([ session()->flashInput([
@ -84,6 +83,12 @@ class LoginController extends Controller
// Store the previous location for redirect after login // Store the previous location for redirect after login
$this->updateIntendedFromPrevious(); $this->updateIntendedFromPrevious();
if (!$preventInitiation && $this->shouldAutoInitiate()) {
return view('auth.login-initiate', [
'authMethod' => $authMethod,
]);
}
return view('auth.login', [ return view('auth.login', [
'socialDrivers' => $socialDrivers, 'socialDrivers' => $socialDrivers,
'authMethod' => $authMethod, 'authMethod' => $authMethod,
@ -251,4 +256,32 @@ class LoginController extends Controller
redirect()->setIntendedUrl($previous); redirect()->setIntendedUrl($previous);
} }
/**
* Check if login auto-initiate should be valid based upon authentication config.
*/
protected function shouldAutoInitiate(): bool
{
$socialDrivers = $this->socialAuthService->getActiveDrivers();
$authMethod = config('auth.method');
$autoRedirect = config('auth.auto_initiate');
return $autoRedirect && count($socialDrivers) === 0 && in_array($authMethod, ['oidc', 'saml2']);
}
/**
* Logout user and perform subsequent redirect.
*
* @param \Illuminate\Http\Request $request
*
* @return mixed
*/
public function logout(Request $request)
{
$this->traitLogout($request);
$redirectUri = $this->shouldAutoInitiate() ? '/login?prevent_auto_init=true' : '/';
return redirect($redirectUri);
}
} }

View File

@ -9,6 +9,7 @@ use BookStack\Entities\Models\Bookshelf;
use BookStack\Entities\Repos\BookRepo; use BookStack\Entities\Repos\BookRepo;
use BookStack\Entities\Tools\BookContents; use BookStack\Entities\Tools\BookContents;
use BookStack\Entities\Tools\Cloner; use BookStack\Entities\Tools\Cloner;
use BookStack\Entities\Tools\HierarchyTransformer;
use BookStack\Entities\Tools\PermissionsUpdater; use BookStack\Entities\Tools\PermissionsUpdater;
use BookStack\Entities\Tools\ShelfContext; use BookStack\Entities\Tools\ShelfContext;
use BookStack\Exceptions\ImageUploadException; use BookStack\Exceptions\ImageUploadException;
@ -100,7 +101,6 @@ class BookController extends Controller
} }
$book = $this->bookRepo->create($request->all()); $book = $this->bookRepo->create($request->all());
$this->bookRepo->updateCoverImage($book, $request->file('image', null));
if ($bookshelf) { if ($bookshelf) {
$bookshelf->appendBook($book); $bookshelf->appendBook($book);
@ -158,15 +158,20 @@ class BookController extends Controller
{ {
$book = $this->bookRepo->getBySlug($slug); $book = $this->bookRepo->getBySlug($slug);
$this->checkOwnablePermission('book-update', $book); $this->checkOwnablePermission('book-update', $book);
$this->validate($request, [
$validated = $this->validate($request, [
'name' => ['required', 'string', 'max:255'], 'name' => ['required', 'string', 'max:255'],
'description' => ['string', 'max:1000'], 'description' => ['string', 'max:1000'],
'image' => array_merge(['nullable'], $this->getImageValidationRules()), 'image' => array_merge(['nullable'], $this->getImageValidationRules()),
]); ]);
$book = $this->bookRepo->update($book, $request->all()); if ($request->has('image_reset')) {
$resetCover = $request->has('image_reset'); $validated['image'] = null;
$this->bookRepo->updateCoverImage($book, $request->file('image', null), $resetCover); } elseif (array_key_exists('image', $validated) && is_null($validated['image'])) {
unset($validated['image']);
}
$book = $this->bookRepo->update($book, $validated);
return redirect($book->getUrl()); return redirect($book->getUrl());
} }
@ -262,4 +267,20 @@ class BookController extends Controller
return redirect($bookCopy->getUrl()); return redirect($bookCopy->getUrl());
} }
/**
* Convert the chapter to a book.
*/
public function convertToShelf(HierarchyTransformer $transformer, string $bookSlug)
{
$book = $this->bookRepo->getBySlug($bookSlug);
$this->checkOwnablePermission('book-update', $book);
$this->checkOwnablePermission('book-delete', $book);
$this->checkPermission('bookshelf-create-all');
$this->checkPermission('book-create-all');
$shelf = $transformer->transformBookToShelf($book);
return redirect($shelf->getUrl());
}
} }

View File

@ -31,7 +31,7 @@ class BookExportController extends Controller
$book = $this->bookRepo->getBySlug($bookSlug); $book = $this->bookRepo->getBySlug($bookSlug);
$pdfContent = $this->exportFormatter->bookToPdf($book); $pdfContent = $this->exportFormatter->bookToPdf($book);
return $this->downloadResponse($pdfContent, $bookSlug . '.pdf'); return $this->download()->directly($pdfContent, $bookSlug . '.pdf');
} }
/** /**
@ -44,7 +44,7 @@ class BookExportController extends Controller
$book = $this->bookRepo->getBySlug($bookSlug); $book = $this->bookRepo->getBySlug($bookSlug);
$htmlContent = $this->exportFormatter->bookToContainedHtml($book); $htmlContent = $this->exportFormatter->bookToContainedHtml($book);
return $this->downloadResponse($htmlContent, $bookSlug . '.html'); return $this->download()->directly($htmlContent, $bookSlug . '.html');
} }
/** /**
@ -55,7 +55,7 @@ class BookExportController extends Controller
$book = $this->bookRepo->getBySlug($bookSlug); $book = $this->bookRepo->getBySlug($bookSlug);
$textContent = $this->exportFormatter->bookToPlainText($book); $textContent = $this->exportFormatter->bookToPlainText($book);
return $this->downloadResponse($textContent, $bookSlug . '.txt'); return $this->download()->directly($textContent, $bookSlug . '.txt');
} }
/** /**
@ -66,6 +66,6 @@ class BookExportController extends Controller
$book = $this->bookRepo->getBySlug($bookSlug); $book = $this->bookRepo->getBySlug($bookSlug);
$textContent = $this->exportFormatter->bookToMarkdown($book); $textContent = $this->exportFormatter->bookToMarkdown($book);
return $this->downloadResponse($textContent, $bookSlug . '.md'); return $this->download()->directly($textContent, $bookSlug . '.md');
} }
} }

View File

@ -83,15 +83,15 @@ class BookshelfController extends Controller
public function store(Request $request) public function store(Request $request)
{ {
$this->checkPermission('bookshelf-create-all'); $this->checkPermission('bookshelf-create-all');
$this->validate($request, [ $validated = $this->validate($request, [
'name' => ['required', 'string', 'max:255'], 'name' => ['required', 'string', 'max:255'],
'description' => ['string', 'max:1000'], 'description' => ['string', 'max:1000'],
'image' => array_merge(['nullable'], $this->getImageValidationRules()), 'image' => array_merge(['nullable'], $this->getImageValidationRules()),
'tags' => ['array'],
]); ]);
$bookIds = explode(',', $request->get('books', '')); $bookIds = explode(',', $request->get('books', ''));
$shelf = $this->bookshelfRepo->create($request->all(), $bookIds); $shelf = $this->bookshelfRepo->create($validated, $bookIds);
$this->bookshelfRepo->updateCoverImage($shelf, $request->file('image', null));
return redirect($shelf->getUrl()); return redirect($shelf->getUrl());
} }
@ -160,16 +160,21 @@ class BookshelfController extends Controller
{ {
$shelf = $this->bookshelfRepo->getBySlug($slug); $shelf = $this->bookshelfRepo->getBySlug($slug);
$this->checkOwnablePermission('bookshelf-update', $shelf); $this->checkOwnablePermission('bookshelf-update', $shelf);
$this->validate($request, [ $validated = $this->validate($request, [
'name' => ['required', 'string', 'max:255'], 'name' => ['required', 'string', 'max:255'],
'description' => ['string', 'max:1000'], 'description' => ['string', 'max:1000'],
'image' => array_merge(['nullable'], $this->getImageValidationRules()), 'image' => array_merge(['nullable'], $this->getImageValidationRules()),
'tags' => ['array'],
]); ]);
if ($request->has('image_reset')) {
$validated['image'] = null;
} elseif (array_key_exists('image', $validated) && is_null($validated['image'])) {
unset($validated['image']);
}
$bookIds = explode(',', $request->get('books', '')); $bookIds = explode(',', $request->get('books', ''));
$shelf = $this->bookshelfRepo->update($shelf, $request->all(), $bookIds); $shelf = $this->bookshelfRepo->update($shelf, $validated, $bookIds);
$resetCover = $request->has('image_reset');
$this->bookshelfRepo->updateCoverImage($shelf, $request->file('image', null), $resetCover);
return redirect($shelf->getUrl()); return redirect($shelf->getUrl());
} }

View File

@ -7,6 +7,7 @@ use BookStack\Entities\Models\Book;
use BookStack\Entities\Repos\ChapterRepo; use BookStack\Entities\Repos\ChapterRepo;
use BookStack\Entities\Tools\BookContents; use BookStack\Entities\Tools\BookContents;
use BookStack\Entities\Tools\Cloner; use BookStack\Entities\Tools\Cloner;
use BookStack\Entities\Tools\HierarchyTransformer;
use BookStack\Entities\Tools\NextPreviousContentLocator; use BookStack\Entities\Tools\NextPreviousContentLocator;
use BookStack\Entities\Tools\PermissionsUpdater; use BookStack\Entities\Tools\PermissionsUpdater;
use BookStack\Exceptions\MoveOperationException; use BookStack\Exceptions\MoveOperationException;
@ -272,4 +273,19 @@ class ChapterController extends Controller
return redirect($chapter->getUrl()); return redirect($chapter->getUrl());
} }
/**
* Convert the chapter to a book.
*/
public function convertToBook(HierarchyTransformer $transformer, string $bookSlug, string $chapterSlug)
{
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
$this->checkOwnablePermission('chapter-update', $chapter);
$this->checkOwnablePermission('chapter-delete', $chapter);
$this->checkPermission('book-create-all');
$book = $transformer->transformChapterToBook($chapter);
return redirect($book->getUrl());
}
} }

View File

@ -33,7 +33,7 @@ class ChapterExportController extends Controller
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
$pdfContent = $this->exportFormatter->chapterToPdf($chapter); $pdfContent = $this->exportFormatter->chapterToPdf($chapter);
return $this->downloadResponse($pdfContent, $chapterSlug . '.pdf'); return $this->download()->directly($pdfContent, $chapterSlug . '.pdf');
} }
/** /**
@ -47,7 +47,7 @@ class ChapterExportController extends Controller
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
$containedHtml = $this->exportFormatter->chapterToContainedHtml($chapter); $containedHtml = $this->exportFormatter->chapterToContainedHtml($chapter);
return $this->downloadResponse($containedHtml, $chapterSlug . '.html'); return $this->download()->directly($containedHtml, $chapterSlug . '.html');
} }
/** /**
@ -60,7 +60,7 @@ class ChapterExportController extends Controller
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
$chapterText = $this->exportFormatter->chapterToPlainText($chapter); $chapterText = $this->exportFormatter->chapterToPlainText($chapter);
return $this->downloadResponse($chapterText, $chapterSlug . '.txt'); return $this->download()->directly($chapterText, $chapterSlug . '.txt');
} }
/** /**
@ -70,10 +70,9 @@ class ChapterExportController extends Controller
*/ */
public function markdown(string $bookSlug, string $chapterSlug) public function markdown(string $bookSlug, string $chapterSlug)
{ {
// TODO: This should probably export to a zip file.
$chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug);
$chapterText = $this->exportFormatter->chapterToMarkdown($chapter); $chapterText = $this->exportFormatter->chapterToMarkdown($chapter);
return $this->downloadResponse($chapterText, $chapterSlug . '.md'); return $this->download()->directly($chapterText, $chapterSlug . '.md');
} }
} }

View File

@ -4,15 +4,13 @@ namespace BookStack\Http\Controllers;
use BookStack\Exceptions\NotifyException; use BookStack\Exceptions\NotifyException;
use BookStack\Facades\Activity; use BookStack\Facades\Activity;
use BookStack\Http\Responses\DownloadResponseFactory;
use BookStack\Interfaces\Loggable; use BookStack\Interfaces\Loggable;
use BookStack\Model; use BookStack\Model;
use BookStack\Util\WebSafeMimeSniffer;
use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests; use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\Response;
use Illuminate\Routing\Controller as BaseController; use Illuminate\Routing\Controller as BaseController;
use Symfony\Component\HttpFoundation\StreamedResponse;
abstract class Controller extends BaseController abstract class Controller extends BaseController
{ {
@ -110,74 +108,11 @@ abstract class Controller extends BaseController
} }
/** /**
* Create a response that forces a download in the browser. * Create and return a new download response factory using the current request.
*/ */
protected function downloadResponse(string $content, string $fileName): Response protected function download(): DownloadResponseFactory
{ {
return response()->make($content, 200, [ return new DownloadResponseFactory(request());
'Content-Type' => 'application/octet-stream',
'Content-Disposition' => 'attachment; filename="' . str_replace('"', '', $fileName) . '"',
'X-Content-Type-Options' => 'nosniff',
]);
}
/**
* Create a response that forces a download, from a given stream of content.
*/
protected function streamedDownloadResponse($stream, string $fileName): 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);
}, 200, [
'Content-Type' => 'application/octet-stream',
'Content-Disposition' => 'attachment; filename="' . str_replace('"', '', $fileName) . '"',
'X-Content-Type-Options' => 'nosniff',
]);
}
/**
* Create a file download response that provides the file with a content-type
* correct for the file, in a way so the browser can show the content in browser.
*/
protected function inlineDownloadResponse(string $content, string $fileName): Response
{
$mime = (new WebSafeMimeSniffer())->sniff($content);
return response()->make($content, 200, [
'Content-Type' => $mime,
'Content-Disposition' => 'inline; filename="' . str_replace('"', '', $fileName) . '"',
'X-Content-Type-Options' => 'nosniff',
]);
}
/**
* Create a file download response that provides the file with a content-type
* correct for the file, in a way so the browser can show the content in browser,
* for a given content stream.
*/
protected function streamedInlineDownloadResponse($stream, string $fileName): StreamedResponse
{
$sniffContent = fread($stream, 1000);
$mime = (new WebSafeMimeSniffer())->sniff($sniffContent);
return response()->stream(function () use ($sniffContent, $stream) {
echo $sniffContent;
fpassthru($stream);
fclose($stream);
}, 200, [
'Content-Type' => $mime,
'Content-Disposition' => 'inline; filename="' . str_replace('"', '', $fileName) . '"',
'X-Content-Type-Options' => 'nosniff',
]);
} }
/** /**

View File

@ -36,7 +36,7 @@ class PageExportController extends Controller
$page->html = (new PageContent($page))->render(); $page->html = (new PageContent($page))->render();
$pdfContent = $this->exportFormatter->pageToPdf($page); $pdfContent = $this->exportFormatter->pageToPdf($page);
return $this->downloadResponse($pdfContent, $pageSlug . '.pdf'); return $this->download()->directly($pdfContent, $pageSlug . '.pdf');
} }
/** /**
@ -51,7 +51,7 @@ class PageExportController extends Controller
$page->html = (new PageContent($page))->render(); $page->html = (new PageContent($page))->render();
$containedHtml = $this->exportFormatter->pageToContainedHtml($page); $containedHtml = $this->exportFormatter->pageToContainedHtml($page);
return $this->downloadResponse($containedHtml, $pageSlug . '.html'); return $this->download()->directly($containedHtml, $pageSlug . '.html');
} }
/** /**
@ -64,7 +64,7 @@ class PageExportController extends Controller
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
$pageText = $this->exportFormatter->pageToPlainText($page); $pageText = $this->exportFormatter->pageToPlainText($page);
return $this->downloadResponse($pageText, $pageSlug . '.txt'); return $this->download()->directly($pageText, $pageSlug . '.txt');
} }
/** /**
@ -77,6 +77,6 @@ class PageExportController extends Controller
$page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug);
$pageText = $this->exportFormatter->pageToMarkdown($page); $pageText = $this->exportFormatter->pageToMarkdown($page);
return $this->downloadResponse($pageText, $pageSlug . '.md'); return $this->download()->directly($pageText, $pageSlug . '.md');
} }
} }

View File

@ -0,0 +1,77 @@
<?php
namespace BookStack\Http\Responses;
use BookStack\Util\WebSafeMimeSniffer;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
class DownloadResponseFactory
{
protected Request $request;
public function __construct(Request $request)
{
$this->request = $request;
}
/**
* Create a response that directly forces a download in the browser.
*/
public function directly(string $content, string $fileName): Response
{
return response()->make($content, 200, $this->getHeaders($fileName));
}
/**
* Create a response that forces a download, from a given stream of content.
*/
public function streamedDirectly($stream, string $fileName): 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);
}, 200, $this->getHeaders($fileName));
}
/**
* Create a file download response that provides the file with a content-type
* 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
{
$sniffContent = fread($stream, 2000);
$mime = (new WebSafeMimeSniffer())->sniff($sniffContent);
return response()->stream(function () use ($sniffContent, $stream) {
echo $sniffContent;
fpassthru($stream);
fclose($stream);
}, 200, $this->getHeaders($fileName, $mime));
}
/**
* Get the common headers to provide for a download response.
*/
protected function getHeaders(string $fileName, string $mime = 'application/octet-stream'): array
{
$disposition = ($mime === 'application/octet-stream') ? 'attachment' : 'inline';
$downloadName = str_replace('"', '', $fileName);
return [
'Content-Type' => $mime,
'Content-Disposition' => "{$disposition}; filename=\"{$downloadName}\"",
'X-Content-Type-Options' => 'nosniff',
];
}
}

View File

@ -63,16 +63,6 @@ class AttachmentService
return 'uploads/files/' . $path; return 'uploads/files/' . $path;
} }
/**
* Get an attachment from storage.
*
* @throws FileNotFoundException
*/
public function getAttachmentFromStorage(Attachment $attachment): string
{
return $this->getStorageDisk()->get($this->adjustPathForStorageDisk($attachment->path));
}
/** /**
* Stream an attachment from storage. * Stream an attachment from storage.
* *

View File

@ -17,6 +17,14 @@ class WebSafeMimeSniffer
'application/json', 'application/json',
'application/octet-stream', 'application/octet-stream',
'application/pdf', 'application/pdf',
'audio/aac',
'audio/midi',
'audio/mpeg',
'audio/ogg',
'audio/opus',
'audio/wav',
'audio/webm',
'audio/x-m4a',
'image/apng', 'image/apng',
'image/bmp', 'image/bmp',
'image/jpeg', 'image/jpeg',

587
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,7 @@ class RoleFactory extends Factory
return [ return [
'display_name' => $this->faker->sentence(3), 'display_name' => $this->faker->sentence(3),
'description' => $this->faker->sentence(10), 'description' => $this->faker->sentence(10),
'external_auth_id' => '',
]; ];
} }
} }

View File

@ -9,8 +9,7 @@
"updated_at": "2019-12-11T20:57:31.000000Z", "updated_at": "2019-12-11T20:57:31.000000Z",
"created_by": 1, "created_by": 1,
"updated_by": 1, "updated_by": 1,
"owned_by": 1, "owned_by": 1
"image_id": 3
}, },
{ {
"id": 2, "id": 2,
@ -21,8 +20,7 @@
"updated_at": "2019-12-11T20:57:23.000000Z", "updated_at": "2019-12-11T20:57:23.000000Z",
"created_by": 4, "created_by": 4,
"updated_by": 3, "updated_by": 3,
"owned_by": 3, "owned_by": 3
"image_id": 34
} }
], ],
"total": 14 "total": 14

View File

@ -7,6 +7,5 @@
"updated_at": "2020-01-12T14:16:10.000000Z", "updated_at": "2020-01-12T14:16:10.000000Z",
"created_by": 1, "created_by": 1,
"updated_by": 1, "updated_by": 1,
"owned_by": 1, "owned_by": 1
"image_id": 452
} }

View File

@ -9,8 +9,7 @@
"updated_at": "2020-04-10T13:00:45.000000Z", "updated_at": "2020-04-10T13:00:45.000000Z",
"created_by": 4, "created_by": 4,
"updated_by": 1, "updated_by": 1,
"owned_by": 1, "owned_by": 1
"image_id": 31
}, },
{ {
"id": 9, "id": 9,
@ -21,8 +20,7 @@
"updated_at": "2020-04-10T13:00:58.000000Z", "updated_at": "2020-04-10T13:00:58.000000Z",
"created_by": 4, "created_by": 4,
"updated_by": 1, "updated_by": 1,
"owned_by": 1, "owned_by": 1
"image_id": 28
}, },
{ {
"id": 10, "id": 10,
@ -33,8 +31,7 @@
"updated_at": "2020-04-10T13:00:53.000000Z", "updated_at": "2020-04-10T13:00:53.000000Z",
"created_by": 4, "created_by": 4,
"updated_by": 1, "updated_by": 1,
"owned_by": 4, "owned_by": 4
"image_id": 30
} }
], ],
"total": 3 "total": 3

View File

@ -6,7 +6,6 @@
"created_by": 1, "created_by": 1,
"updated_by": 1, "updated_by": 1,
"owned_by": 1, "owned_by": 1,
"image_id": 501,
"created_at": "2020-04-10T13:24:09.000000Z", "created_at": "2020-04-10T13:24:09.000000Z",
"updated_at": "2020-04-10T13:48:22.000000Z" "updated_at": "2020-04-10T13:48:22.000000Z"
} }

439
package-lock.json generated
View File

@ -5,20 +5,21 @@
"packages": { "packages": {
"": { "": {
"dependencies": { "dependencies": {
"clipboard": "^2.0.10", "clipboard": "^2.0.11",
"codemirror": "^5.65.2", "codemirror": "^5.65.5",
"dropzone": "^5.9.3", "dropzone": "^5.9.3",
"markdown-it": "^12.3.2", "markdown-it": "^13.0.1",
"markdown-it-task-lists": "^2.1.1", "markdown-it-task-lists": "^2.1.1",
"snabbdom": "^3.5.0",
"sortablejs": "^1.15.0" "sortablejs": "^1.15.0"
}, },
"devDependencies": { "devDependencies": {
"chokidar-cli": "^3.0", "chokidar-cli": "^3.0",
"esbuild": "0.14.36", "esbuild": "0.14.42",
"livereload": "^0.9.3", "livereload": "^0.9.3",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"punycode": "^2.1.1", "punycode": "^2.1.1",
"sass": "^1.50.0" "sass": "^1.52.1"
} }
}, },
"node_modules/ansi-regex": { "node_modules/ansi-regex": {
@ -173,9 +174,9 @@
} }
}, },
"node_modules/clipboard": { "node_modules/clipboard": {
"version": "2.0.10", "version": "2.0.11",
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.10.tgz", "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz",
"integrity": "sha512-cz3m2YVwFz95qSEbCDi2fzLN/epEN9zXBvfgAoGkvGOJZATMl9gtTDVOtBYkx2ODUJl2kvmud7n32sV2BpYR4g==", "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==",
"dependencies": { "dependencies": {
"good-listener": "^1.2.2", "good-listener": "^1.2.2",
"select": "^1.1.2", "select": "^1.1.2",
@ -194,9 +195,9 @@
} }
}, },
"node_modules/codemirror": { "node_modules/codemirror": {
"version": "5.65.2", "version": "5.65.5",
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.2.tgz", "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.5.tgz",
"integrity": "sha512-SZM4Zq7XEC8Fhroqe3LxbEEX1zUPWH1wMr5zxiBuiUF64iYOUH/JI88v4tBag8MiBS8B8gRv8O1pPXGYXQ4ErA==" "integrity": "sha512-HNyhvGLnYz5c+kIsB9QKVitiZUevha3ovbIYaQiGzKo7ECSL/elWD9RXt3JgNr0NdnyqE9/Rc/7uLfkJQL638w=="
}, },
"node_modules/color-convert": { "node_modules/color-convert": {
"version": "1.9.3", "version": "1.9.3",
@ -273,9 +274,12 @@
"dev": true "dev": true
}, },
"node_modules/entities": { "node_modules/entities": {
"version": "2.1.0", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
"integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
"engines": {
"node": ">=0.12"
},
"funding": { "funding": {
"url": "https://github.com/fb55/entities?sponsor=1" "url": "https://github.com/fb55/entities?sponsor=1"
} }
@ -341,9 +345,9 @@
} }
}, },
"node_modules/esbuild": { "node_modules/esbuild": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.42.tgz",
"integrity": "sha512-HhFHPiRXGYOCRlrhpiVDYKcFJRdO0sBElZ668M4lh2ER0YgnkLxECuFe7uWCf23FrcLc59Pqr7dHkTqmRPDHmw==", "integrity": "sha512-V0uPZotCEHokJdNqyozH6qsaQXqmZEOiZWrXnds/zaH/0SyrIayRXWRB98CENO73MIZ9T3HBIOsmds5twWtmgw==",
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"bin": { "bin": {
@ -353,32 +357,32 @@
"node": ">=12" "node": ">=12"
}, },
"optionalDependencies": { "optionalDependencies": {
"esbuild-android-64": "0.14.36", "esbuild-android-64": "0.14.42",
"esbuild-android-arm64": "0.14.36", "esbuild-android-arm64": "0.14.42",
"esbuild-darwin-64": "0.14.36", "esbuild-darwin-64": "0.14.42",
"esbuild-darwin-arm64": "0.14.36", "esbuild-darwin-arm64": "0.14.42",
"esbuild-freebsd-64": "0.14.36", "esbuild-freebsd-64": "0.14.42",
"esbuild-freebsd-arm64": "0.14.36", "esbuild-freebsd-arm64": "0.14.42",
"esbuild-linux-32": "0.14.36", "esbuild-linux-32": "0.14.42",
"esbuild-linux-64": "0.14.36", "esbuild-linux-64": "0.14.42",
"esbuild-linux-arm": "0.14.36", "esbuild-linux-arm": "0.14.42",
"esbuild-linux-arm64": "0.14.36", "esbuild-linux-arm64": "0.14.42",
"esbuild-linux-mips64le": "0.14.36", "esbuild-linux-mips64le": "0.14.42",
"esbuild-linux-ppc64le": "0.14.36", "esbuild-linux-ppc64le": "0.14.42",
"esbuild-linux-riscv64": "0.14.36", "esbuild-linux-riscv64": "0.14.42",
"esbuild-linux-s390x": "0.14.36", "esbuild-linux-s390x": "0.14.42",
"esbuild-netbsd-64": "0.14.36", "esbuild-netbsd-64": "0.14.42",
"esbuild-openbsd-64": "0.14.36", "esbuild-openbsd-64": "0.14.42",
"esbuild-sunos-64": "0.14.36", "esbuild-sunos-64": "0.14.42",
"esbuild-windows-32": "0.14.36", "esbuild-windows-32": "0.14.42",
"esbuild-windows-64": "0.14.36", "esbuild-windows-64": "0.14.42",
"esbuild-windows-arm64": "0.14.36" "esbuild-windows-arm64": "0.14.42"
} }
}, },
"node_modules/esbuild-android-64": { "node_modules/esbuild-android-64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.42.tgz",
"integrity": "sha512-jwpBhF1jmo0tVCYC/ORzVN+hyVcNZUWuozGcLHfod0RJCedTDTvR4nwlTXdx1gtncDqjk33itjO+27OZHbiavw==", "integrity": "sha512-P4Y36VUtRhK/zivqGVMqhptSrFILAGlYp0Z8r9UQqHJ3iWztRCNWnlBzD9HRx0DbueXikzOiwyOri+ojAFfW6A==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -392,9 +396,9 @@
} }
}, },
"node_modules/esbuild-android-arm64": { "node_modules/esbuild-android-arm64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.42.tgz",
"integrity": "sha512-/hYkyFe7x7Yapmfv4X/tBmyKnggUmdQmlvZ8ZlBnV4+PjisrEhAvC3yWpURuD9XoB8Wa1d5dGkTsF53pIvpjsg==", "integrity": "sha512-0cOqCubq+RWScPqvtQdjXG3Czb3AWI2CaKw3HeXry2eoA2rrPr85HF7IpdU26UWdBXgPYtlTN1LUiuXbboROhg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -408,9 +412,9 @@
} }
}, },
"node_modules/esbuild-darwin-64": { "node_modules/esbuild-darwin-64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.42.tgz",
"integrity": "sha512-kkl6qmV0dTpyIMKagluzYqlc1vO0ecgpviK/7jwPbRDEv5fejRTaBBEE2KxEQbTHcLhiiDbhG7d5UybZWo/1zQ==", "integrity": "sha512-ipiBdCA3ZjYgRfRLdQwP82rTiv/YVMtW36hTvAN5ZKAIfxBOyPXY7Cejp3bMXWgzKD8B6O+zoMzh01GZsCuEIA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -424,9 +428,9 @@
} }
}, },
"node_modules/esbuild-darwin-arm64": { "node_modules/esbuild-darwin-arm64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.42.tgz",
"integrity": "sha512-q8fY4r2Sx6P0Pr3VUm//eFYKVk07C5MHcEinU1BjyFnuYz4IxR/03uBbDwluR6ILIHnZTE7AkTUWIdidRi1Jjw==", "integrity": "sha512-bU2tHRqTPOaoH/4m0zYHbFWpiYDmaA0gt90/3BMEFaM0PqVK/a6MA2V/ypV5PO0v8QxN6gH5hBPY4YJ2lopXgA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -440,9 +444,9 @@
} }
}, },
"node_modules/esbuild-freebsd-64": { "node_modules/esbuild-freebsd-64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.42.tgz",
"integrity": "sha512-Hn8AYuxXXRptybPqoMkga4HRFE7/XmhtlQjXFHoAIhKUPPMeJH35GYEUWGbjteai9FLFvBAjEAlwEtSGxnqWww==", "integrity": "sha512-75h1+22Ivy07+QvxHyhVqOdekupiTZVLN1PMwCDonAqyXd8TVNJfIRFrdL8QmSJrOJJ5h8H1I9ETyl2L8LQDaw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -456,9 +460,9 @@
} }
}, },
"node_modules/esbuild-freebsd-arm64": { "node_modules/esbuild-freebsd-arm64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.42.tgz",
"integrity": "sha512-S3C0attylLLRiCcHiJd036eDEMOY32+h8P+jJ3kTcfhJANNjP0TNBNL30TZmEdOSx/820HJFgRrqpNAvTbjnDA==", "integrity": "sha512-W6Jebeu5TTDQMJUJVarEzRU9LlKpNkPBbjqSu+GUPTHDCly5zZEQq9uHkmHHl7OKm+mQ2zFySN83nmfCeZCyNA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -472,9 +476,9 @@
} }
}, },
"node_modules/esbuild-linux-32": { "node_modules/esbuild-linux-32": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.42.tgz",
"integrity": "sha512-Eh9OkyTrEZn9WGO4xkI3OPPpUX7p/3QYvdG0lL4rfr73Ap2HAr6D9lP59VMF64Ex01LhHSXwIsFG/8AQjh6eNw==", "integrity": "sha512-Ooy/Bj+mJ1z4jlWcK5Dl6SlPlCgQB9zg1UrTCeY8XagvuWZ4qGPyYEWGkT94HUsRi2hKsXvcs6ThTOjBaJSMfg==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@ -488,9 +492,9 @@
} }
}, },
"node_modules/esbuild-linux-64": { "node_modules/esbuild-linux-64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.42.tgz",
"integrity": "sha512-vFVFS5ve7PuwlfgoWNyRccGDi2QTNkQo/2k5U5ttVD0jRFaMlc8UQee708fOZA6zTCDy5RWsT5MJw3sl2X6KDg==", "integrity": "sha512-2L0HbzQfbTuemUWfVqNIjOfaTRt9zsvjnme6lnr7/MO9toz/MJ5tZhjqrG6uDWDxhsaHI2/nsDgrv8uEEN2eoA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -504,9 +508,9 @@
} }
}, },
"node_modules/esbuild-linux-arm": { "node_modules/esbuild-linux-arm": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.42.tgz",
"integrity": "sha512-NhgU4n+NCsYgt7Hy61PCquEz5aevI6VjQvxwBxtxrooXsxt5b2xtOUXYZe04JxqQo+XZk3d1gcr7pbV9MAQ/Lg==", "integrity": "sha512-STq69yzCMhdRaWnh29UYrLSr/qaWMm/KqwaRF1pMEK7kDiagaXhSL1zQGXbYv94GuGY/zAwzK98+6idCMUOOCg==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -520,9 +524,9 @@
} }
}, },
"node_modules/esbuild-linux-arm64": { "node_modules/esbuild-linux-arm64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.42.tgz",
"integrity": "sha512-24Vq1M7FdpSmaTYuu1w0Hdhiqkbto1I5Pjyi+4Cdw5fJKGlwQuw+hWynTcRI/cOZxBcBpP21gND7W27gHAiftw==", "integrity": "sha512-c3Ug3e9JpVr8jAcfbhirtpBauLxzYPpycjWulD71CF6ZSY26tvzmXMJYooQ2YKqDY4e/fPu5K8bm7MiXMnyxuA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -536,9 +540,9 @@
} }
}, },
"node_modules/esbuild-linux-mips64le": { "node_modules/esbuild-linux-mips64le": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.42.tgz",
"integrity": "sha512-hZUeTXvppJN+5rEz2EjsOFM9F1bZt7/d2FUM1lmQo//rXh1RTFYzhC0txn7WV0/jCC7SvrGRaRz0NMsRPf8SIA==", "integrity": "sha512-QuvpHGbYlkyXWf2cGm51LBCHx6eUakjaSrRpUqhPwjh/uvNUYvLmz2LgPTTPwCqaKt0iwL+OGVL0tXA5aDbAbg==",
"cpu": [ "cpu": [
"mips64el" "mips64el"
], ],
@ -552,9 +556,9 @@
} }
}, },
"node_modules/esbuild-linux-ppc64le": { "node_modules/esbuild-linux-ppc64le": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.42.tgz",
"integrity": "sha512-1Bg3QgzZjO+QtPhP9VeIBhAduHEc2kzU43MzBnMwpLSZ890azr4/A9Dganun8nsqD/1TBcqhId0z4mFDO8FAvg==", "integrity": "sha512-8ohIVIWDbDT+i7lCx44YCyIRrOW1MYlks9fxTo0ME2LS/fxxdoJBwHWzaDYhjvf8kNpA+MInZvyOEAGoVDrMHg==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@ -568,9 +572,9 @@
} }
}, },
"node_modules/esbuild-linux-riscv64": { "node_modules/esbuild-linux-riscv64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.42.tgz",
"integrity": "sha512-dOE5pt3cOdqEhaufDRzNCHf5BSwxgygVak9UR7PH7KPVHwSTDAZHDoEjblxLqjJYpc5XaU9+gKJ9F8mp9r5I4A==", "integrity": "sha512-DzDqK3TuoXktPyG1Lwx7vhaF49Onv3eR61KwQyxYo4y5UKTpL3NmuarHSIaSVlTFDDpcIajCDwz5/uwKLLgKiQ==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@ -584,9 +588,9 @@
} }
}, },
"node_modules/esbuild-linux-s390x": { "node_modules/esbuild-linux-s390x": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.42.tgz",
"integrity": "sha512-g4FMdh//BBGTfVHjF6MO7Cz8gqRoDPzXWxRvWkJoGroKA18G9m0wddvPbEqcQf5Tbt2vSc1CIgag7cXwTmoTXg==", "integrity": "sha512-YFRhPCxl8nb//Wn6SiS5pmtplBi4z9yC2gLrYoYI/tvwuB1jldir9r7JwAGy1Ck4D7sE7wBN9GFtUUX/DLdcEQ==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@ -600,9 +604,9 @@
} }
}, },
"node_modules/esbuild-netbsd-64": { "node_modules/esbuild-netbsd-64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.42.tgz",
"integrity": "sha512-UB2bVImxkWk4vjnP62ehFNZ73lQY1xcnL5ZNYF3x0AG+j8HgdkNF05v67YJdCIuUJpBuTyCK8LORCYo9onSW+A==", "integrity": "sha512-QYSD2k+oT9dqB/4eEM9c+7KyNYsIPgzYOSrmfNGDIyJrbT1d+CFVKvnKahDKNJLfOYj8N4MgyFaU9/Ytc6w5Vw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -616,9 +620,9 @@
} }
}, },
"node_modules/esbuild-openbsd-64": { "node_modules/esbuild-openbsd-64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.42.tgz",
"integrity": "sha512-NvGB2Chf8GxuleXRGk8e9zD3aSdRO5kLt9coTQbCg7WMGXeX471sBgh4kSg8pjx0yTXRt0MlrUDnjVYnetyivg==", "integrity": "sha512-M2meNVIKWsm2HMY7+TU9AxM7ZVwI9havdsw6m/6EzdXysyCFFSoaTQ/Jg03izjCsK17FsVRHqRe26Llj6x0MNA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -632,9 +636,9 @@
} }
}, },
"node_modules/esbuild-sunos-64": { "node_modules/esbuild-sunos-64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.42.tgz",
"integrity": "sha512-VkUZS5ftTSjhRjuRLp+v78auMO3PZBXu6xl4ajomGenEm2/rGuWlhFSjB7YbBNErOchj51Jb2OK8lKAo8qdmsQ==", "integrity": "sha512-uXV8TAZEw36DkgW8Ak3MpSJs1ofBb3Smkc/6pZ29sCAN1KzCAQzsje4sUwugf+FVicrHvlamCOlFZIXgct+iqQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -648,9 +652,9 @@
} }
}, },
"node_modules/esbuild-windows-32": { "node_modules/esbuild-windows-32": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.42.tgz",
"integrity": "sha512-bIar+A6hdytJjZrDxfMBUSEHHLfx3ynoEZXx/39nxy86pX/w249WZm8Bm0dtOAByAf4Z6qV0LsnTIJHiIqbw0w==", "integrity": "sha512-4iw/8qWmRICWi9ZOnJJf9sYt6wmtp3hsN4TdI5NqgjfOkBVMxNdM9Vt3626G1Rda9ya2Q0hjQRD9W1o+m6Lz6g==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@ -664,9 +668,9 @@
} }
}, },
"node_modules/esbuild-windows-64": { "node_modules/esbuild-windows-64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.42.tgz",
"integrity": "sha512-+p4MuRZekVChAeueT1Y9LGkxrT5x7YYJxYE8ZOTcEfeUUN43vktSn6hUNsvxzzATrSgq5QqRdllkVBxWZg7KqQ==", "integrity": "sha512-j3cdK+Y3+a5H0wHKmLGTJcq0+/2mMBHPWkItR3vytp/aUGD/ua/t2BLdfBIzbNN9nLCRL9sywCRpOpFMx3CxzA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -680,9 +684,9 @@
} }
}, },
"node_modules/esbuild-windows-arm64": { "node_modules/esbuild-windows-arm64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.42.tgz",
"integrity": "sha512-fBB4WlDqV1m18EF/aheGYQkQZHfPHiHJSBYzXIo8yKehek+0BtBwo/4PNwKGJ5T0YK0oc8pBKjgwPbzSrPLb+Q==", "integrity": "sha512-+lRAARnF+hf8J0mN27ujO+VbhPbDqJ8rCcJKye4y7YZLV6C4n3pTRThAb388k/zqF5uM0lS5O201u0OqoWSicw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -1127,9 +1131,9 @@
"dev": true "dev": true
}, },
"node_modules/linkify-it": { "node_modules/linkify-it": {
"version": "3.0.3", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
"integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
"dependencies": { "dependencies": {
"uc.micro": "^1.0.1" "uc.micro": "^1.0.1"
} }
@ -1199,13 +1203,13 @@
"dev": true "dev": true
}, },
"node_modules/markdown-it": { "node_modules/markdown-it": {
"version": "12.3.2", "version": "13.0.1",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
"integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
"dependencies": { "dependencies": {
"argparse": "^2.0.1", "argparse": "^2.0.1",
"entities": "~2.1.0", "entities": "~3.0.1",
"linkify-it": "^3.0.1", "linkify-it": "^4.0.1",
"mdurl": "^1.0.1", "mdurl": "^1.0.1",
"uc.micro": "^1.0.5" "uc.micro": "^1.0.5"
}, },
@ -1520,9 +1524,9 @@
} }
}, },
"node_modules/sass": { "node_modules/sass": {
"version": "1.50.0", "version": "1.52.1",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.50.0.tgz", "resolved": "https://registry.npmjs.org/sass/-/sass-1.52.1.tgz",
"integrity": "sha512-cLsD6MEZ5URXHStxApajEh7gW189kkjn4Rc8DQweMyF+o5HF5nfEz8QYLMlPsTOD88DknatTmBWkOcw5/LnJLQ==", "integrity": "sha512-fSzYTbr7z8oQnVJ3Acp9hV80dM1fkMN7mSD/25mpcct9F7FPBMOI8krEYALgU1aZoqGhQNhTPsuSmxjnIvAm4Q==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"chokidar": ">=3.0.0 <4.0.0", "chokidar": ">=3.0.0 <4.0.0",
@ -1597,6 +1601,14 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/snabbdom": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.5.0.tgz",
"integrity": "sha512-Ff5BKG18KrrPuskHJlA9aujPHqEabItaDl96l7ZZndF4zt5AYSczz7ZjjgQAX5IBd5cd25lw9NfgX21yVUJ+9g==",
"engines": {
"node": ">=8.3.0"
}
},
"node_modules/sortablejs": { "node_modules/sortablejs": {
"version": "1.15.0", "version": "1.15.0",
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz", "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz",
@ -2002,9 +2014,9 @@
} }
}, },
"clipboard": { "clipboard": {
"version": "2.0.10", "version": "2.0.11",
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.10.tgz", "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz",
"integrity": "sha512-cz3m2YVwFz95qSEbCDi2fzLN/epEN9zXBvfgAoGkvGOJZATMl9gtTDVOtBYkx2ODUJl2kvmud7n32sV2BpYR4g==", "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==",
"requires": { "requires": {
"good-listener": "^1.2.2", "good-listener": "^1.2.2",
"select": "^1.1.2", "select": "^1.1.2",
@ -2023,9 +2035,9 @@
} }
}, },
"codemirror": { "codemirror": {
"version": "5.65.2", "version": "5.65.5",
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.2.tgz", "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.5.tgz",
"integrity": "sha512-SZM4Zq7XEC8Fhroqe3LxbEEX1zUPWH1wMr5zxiBuiUF64iYOUH/JI88v4tBag8MiBS8B8gRv8O1pPXGYXQ4ErA==" "integrity": "sha512-HNyhvGLnYz5c+kIsB9QKVitiZUevha3ovbIYaQiGzKo7ECSL/elWD9RXt3JgNr0NdnyqE9/Rc/7uLfkJQL638w=="
}, },
"color-convert": { "color-convert": {
"version": "1.9.3", "version": "1.9.3",
@ -2093,9 +2105,9 @@
"dev": true "dev": true
}, },
"entities": { "entities": {
"version": "2.1.0", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
"integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==" "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q=="
}, },
"error-ex": { "error-ex": {
"version": "1.3.2", "version": "1.3.2",
@ -2146,170 +2158,170 @@
} }
}, },
"esbuild": { "esbuild": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.42.tgz",
"integrity": "sha512-HhFHPiRXGYOCRlrhpiVDYKcFJRdO0sBElZ668M4lh2ER0YgnkLxECuFe7uWCf23FrcLc59Pqr7dHkTqmRPDHmw==", "integrity": "sha512-V0uPZotCEHokJdNqyozH6qsaQXqmZEOiZWrXnds/zaH/0SyrIayRXWRB98CENO73MIZ9T3HBIOsmds5twWtmgw==",
"dev": true, "dev": true,
"requires": { "requires": {
"esbuild-android-64": "0.14.36", "esbuild-android-64": "0.14.42",
"esbuild-android-arm64": "0.14.36", "esbuild-android-arm64": "0.14.42",
"esbuild-darwin-64": "0.14.36", "esbuild-darwin-64": "0.14.42",
"esbuild-darwin-arm64": "0.14.36", "esbuild-darwin-arm64": "0.14.42",
"esbuild-freebsd-64": "0.14.36", "esbuild-freebsd-64": "0.14.42",
"esbuild-freebsd-arm64": "0.14.36", "esbuild-freebsd-arm64": "0.14.42",
"esbuild-linux-32": "0.14.36", "esbuild-linux-32": "0.14.42",
"esbuild-linux-64": "0.14.36", "esbuild-linux-64": "0.14.42",
"esbuild-linux-arm": "0.14.36", "esbuild-linux-arm": "0.14.42",
"esbuild-linux-arm64": "0.14.36", "esbuild-linux-arm64": "0.14.42",
"esbuild-linux-mips64le": "0.14.36", "esbuild-linux-mips64le": "0.14.42",
"esbuild-linux-ppc64le": "0.14.36", "esbuild-linux-ppc64le": "0.14.42",
"esbuild-linux-riscv64": "0.14.36", "esbuild-linux-riscv64": "0.14.42",
"esbuild-linux-s390x": "0.14.36", "esbuild-linux-s390x": "0.14.42",
"esbuild-netbsd-64": "0.14.36", "esbuild-netbsd-64": "0.14.42",
"esbuild-openbsd-64": "0.14.36", "esbuild-openbsd-64": "0.14.42",
"esbuild-sunos-64": "0.14.36", "esbuild-sunos-64": "0.14.42",
"esbuild-windows-32": "0.14.36", "esbuild-windows-32": "0.14.42",
"esbuild-windows-64": "0.14.36", "esbuild-windows-64": "0.14.42",
"esbuild-windows-arm64": "0.14.36" "esbuild-windows-arm64": "0.14.42"
} }
}, },
"esbuild-android-64": { "esbuild-android-64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.42.tgz",
"integrity": "sha512-jwpBhF1jmo0tVCYC/ORzVN+hyVcNZUWuozGcLHfod0RJCedTDTvR4nwlTXdx1gtncDqjk33itjO+27OZHbiavw==", "integrity": "sha512-P4Y36VUtRhK/zivqGVMqhptSrFILAGlYp0Z8r9UQqHJ3iWztRCNWnlBzD9HRx0DbueXikzOiwyOri+ojAFfW6A==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"esbuild-android-arm64": { "esbuild-android-arm64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.42.tgz",
"integrity": "sha512-/hYkyFe7x7Yapmfv4X/tBmyKnggUmdQmlvZ8ZlBnV4+PjisrEhAvC3yWpURuD9XoB8Wa1d5dGkTsF53pIvpjsg==", "integrity": "sha512-0cOqCubq+RWScPqvtQdjXG3Czb3AWI2CaKw3HeXry2eoA2rrPr85HF7IpdU26UWdBXgPYtlTN1LUiuXbboROhg==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"esbuild-darwin-64": { "esbuild-darwin-64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.42.tgz",
"integrity": "sha512-kkl6qmV0dTpyIMKagluzYqlc1vO0ecgpviK/7jwPbRDEv5fejRTaBBEE2KxEQbTHcLhiiDbhG7d5UybZWo/1zQ==", "integrity": "sha512-ipiBdCA3ZjYgRfRLdQwP82rTiv/YVMtW36hTvAN5ZKAIfxBOyPXY7Cejp3bMXWgzKD8B6O+zoMzh01GZsCuEIA==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"esbuild-darwin-arm64": { "esbuild-darwin-arm64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.42.tgz",
"integrity": "sha512-q8fY4r2Sx6P0Pr3VUm//eFYKVk07C5MHcEinU1BjyFnuYz4IxR/03uBbDwluR6ILIHnZTE7AkTUWIdidRi1Jjw==", "integrity": "sha512-bU2tHRqTPOaoH/4m0zYHbFWpiYDmaA0gt90/3BMEFaM0PqVK/a6MA2V/ypV5PO0v8QxN6gH5hBPY4YJ2lopXgA==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"esbuild-freebsd-64": { "esbuild-freebsd-64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.42.tgz",
"integrity": "sha512-Hn8AYuxXXRptybPqoMkga4HRFE7/XmhtlQjXFHoAIhKUPPMeJH35GYEUWGbjteai9FLFvBAjEAlwEtSGxnqWww==", "integrity": "sha512-75h1+22Ivy07+QvxHyhVqOdekupiTZVLN1PMwCDonAqyXd8TVNJfIRFrdL8QmSJrOJJ5h8H1I9ETyl2L8LQDaw==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"esbuild-freebsd-arm64": { "esbuild-freebsd-arm64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.42.tgz",
"integrity": "sha512-S3C0attylLLRiCcHiJd036eDEMOY32+h8P+jJ3kTcfhJANNjP0TNBNL30TZmEdOSx/820HJFgRrqpNAvTbjnDA==", "integrity": "sha512-W6Jebeu5TTDQMJUJVarEzRU9LlKpNkPBbjqSu+GUPTHDCly5zZEQq9uHkmHHl7OKm+mQ2zFySN83nmfCeZCyNA==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"esbuild-linux-32": { "esbuild-linux-32": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.42.tgz",
"integrity": "sha512-Eh9OkyTrEZn9WGO4xkI3OPPpUX7p/3QYvdG0lL4rfr73Ap2HAr6D9lP59VMF64Ex01LhHSXwIsFG/8AQjh6eNw==", "integrity": "sha512-Ooy/Bj+mJ1z4jlWcK5Dl6SlPlCgQB9zg1UrTCeY8XagvuWZ4qGPyYEWGkT94HUsRi2hKsXvcs6ThTOjBaJSMfg==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"esbuild-linux-64": { "esbuild-linux-64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.42.tgz",
"integrity": "sha512-vFVFS5ve7PuwlfgoWNyRccGDi2QTNkQo/2k5U5ttVD0jRFaMlc8UQee708fOZA6zTCDy5RWsT5MJw3sl2X6KDg==", "integrity": "sha512-2L0HbzQfbTuemUWfVqNIjOfaTRt9zsvjnme6lnr7/MO9toz/MJ5tZhjqrG6uDWDxhsaHI2/nsDgrv8uEEN2eoA==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"esbuild-linux-arm": { "esbuild-linux-arm": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.42.tgz",
"integrity": "sha512-NhgU4n+NCsYgt7Hy61PCquEz5aevI6VjQvxwBxtxrooXsxt5b2xtOUXYZe04JxqQo+XZk3d1gcr7pbV9MAQ/Lg==", "integrity": "sha512-STq69yzCMhdRaWnh29UYrLSr/qaWMm/KqwaRF1pMEK7kDiagaXhSL1zQGXbYv94GuGY/zAwzK98+6idCMUOOCg==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"esbuild-linux-arm64": { "esbuild-linux-arm64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.42.tgz",
"integrity": "sha512-24Vq1M7FdpSmaTYuu1w0Hdhiqkbto1I5Pjyi+4Cdw5fJKGlwQuw+hWynTcRI/cOZxBcBpP21gND7W27gHAiftw==", "integrity": "sha512-c3Ug3e9JpVr8jAcfbhirtpBauLxzYPpycjWulD71CF6ZSY26tvzmXMJYooQ2YKqDY4e/fPu5K8bm7MiXMnyxuA==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"esbuild-linux-mips64le": { "esbuild-linux-mips64le": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.42.tgz",
"integrity": "sha512-hZUeTXvppJN+5rEz2EjsOFM9F1bZt7/d2FUM1lmQo//rXh1RTFYzhC0txn7WV0/jCC7SvrGRaRz0NMsRPf8SIA==", "integrity": "sha512-QuvpHGbYlkyXWf2cGm51LBCHx6eUakjaSrRpUqhPwjh/uvNUYvLmz2LgPTTPwCqaKt0iwL+OGVL0tXA5aDbAbg==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"esbuild-linux-ppc64le": { "esbuild-linux-ppc64le": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.42.tgz",
"integrity": "sha512-1Bg3QgzZjO+QtPhP9VeIBhAduHEc2kzU43MzBnMwpLSZ890azr4/A9Dganun8nsqD/1TBcqhId0z4mFDO8FAvg==", "integrity": "sha512-8ohIVIWDbDT+i7lCx44YCyIRrOW1MYlks9fxTo0ME2LS/fxxdoJBwHWzaDYhjvf8kNpA+MInZvyOEAGoVDrMHg==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"esbuild-linux-riscv64": { "esbuild-linux-riscv64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.42.tgz",
"integrity": "sha512-dOE5pt3cOdqEhaufDRzNCHf5BSwxgygVak9UR7PH7KPVHwSTDAZHDoEjblxLqjJYpc5XaU9+gKJ9F8mp9r5I4A==", "integrity": "sha512-DzDqK3TuoXktPyG1Lwx7vhaF49Onv3eR61KwQyxYo4y5UKTpL3NmuarHSIaSVlTFDDpcIajCDwz5/uwKLLgKiQ==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"esbuild-linux-s390x": { "esbuild-linux-s390x": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.42.tgz",
"integrity": "sha512-g4FMdh//BBGTfVHjF6MO7Cz8gqRoDPzXWxRvWkJoGroKA18G9m0wddvPbEqcQf5Tbt2vSc1CIgag7cXwTmoTXg==", "integrity": "sha512-YFRhPCxl8nb//Wn6SiS5pmtplBi4z9yC2gLrYoYI/tvwuB1jldir9r7JwAGy1Ck4D7sE7wBN9GFtUUX/DLdcEQ==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"esbuild-netbsd-64": { "esbuild-netbsd-64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.42.tgz",
"integrity": "sha512-UB2bVImxkWk4vjnP62ehFNZ73lQY1xcnL5ZNYF3x0AG+j8HgdkNF05v67YJdCIuUJpBuTyCK8LORCYo9onSW+A==", "integrity": "sha512-QYSD2k+oT9dqB/4eEM9c+7KyNYsIPgzYOSrmfNGDIyJrbT1d+CFVKvnKahDKNJLfOYj8N4MgyFaU9/Ytc6w5Vw==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"esbuild-openbsd-64": { "esbuild-openbsd-64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.42.tgz",
"integrity": "sha512-NvGB2Chf8GxuleXRGk8e9zD3aSdRO5kLt9coTQbCg7WMGXeX471sBgh4kSg8pjx0yTXRt0MlrUDnjVYnetyivg==", "integrity": "sha512-M2meNVIKWsm2HMY7+TU9AxM7ZVwI9havdsw6m/6EzdXysyCFFSoaTQ/Jg03izjCsK17FsVRHqRe26Llj6x0MNA==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"esbuild-sunos-64": { "esbuild-sunos-64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.42.tgz",
"integrity": "sha512-VkUZS5ftTSjhRjuRLp+v78auMO3PZBXu6xl4ajomGenEm2/rGuWlhFSjB7YbBNErOchj51Jb2OK8lKAo8qdmsQ==", "integrity": "sha512-uXV8TAZEw36DkgW8Ak3MpSJs1ofBb3Smkc/6pZ29sCAN1KzCAQzsje4sUwugf+FVicrHvlamCOlFZIXgct+iqQ==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"esbuild-windows-32": { "esbuild-windows-32": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.42.tgz",
"integrity": "sha512-bIar+A6hdytJjZrDxfMBUSEHHLfx3ynoEZXx/39nxy86pX/w249WZm8Bm0dtOAByAf4Z6qV0LsnTIJHiIqbw0w==", "integrity": "sha512-4iw/8qWmRICWi9ZOnJJf9sYt6wmtp3hsN4TdI5NqgjfOkBVMxNdM9Vt3626G1Rda9ya2Q0hjQRD9W1o+m6Lz6g==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"esbuild-windows-64": { "esbuild-windows-64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.42.tgz",
"integrity": "sha512-+p4MuRZekVChAeueT1Y9LGkxrT5x7YYJxYE8ZOTcEfeUUN43vktSn6hUNsvxzzATrSgq5QqRdllkVBxWZg7KqQ==", "integrity": "sha512-j3cdK+Y3+a5H0wHKmLGTJcq0+/2mMBHPWkItR3vytp/aUGD/ua/t2BLdfBIzbNN9nLCRL9sywCRpOpFMx3CxzA==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"esbuild-windows-arm64": { "esbuild-windows-arm64": {
"version": "0.14.36", "version": "0.14.42",
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.36.tgz", "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.42.tgz",
"integrity": "sha512-fBB4WlDqV1m18EF/aheGYQkQZHfPHiHJSBYzXIo8yKehek+0BtBwo/4PNwKGJ5T0YK0oc8pBKjgwPbzSrPLb+Q==", "integrity": "sha512-+lRAARnF+hf8J0mN27ujO+VbhPbDqJ8rCcJKye4y7YZLV6C4n3pTRThAb388k/zqF5uM0lS5O201u0OqoWSicw==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
@ -2615,9 +2627,9 @@
"dev": true "dev": true
}, },
"linkify-it": { "linkify-it": {
"version": "3.0.3", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
"integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
"requires": { "requires": {
"uc.micro": "^1.0.1" "uc.micro": "^1.0.1"
} }
@ -2675,13 +2687,13 @@
"dev": true "dev": true
}, },
"markdown-it": { "markdown-it": {
"version": "12.3.2", "version": "13.0.1",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
"integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
"requires": { "requires": {
"argparse": "^2.0.1", "argparse": "^2.0.1",
"entities": "~2.1.0", "entities": "~3.0.1",
"linkify-it": "^3.0.1", "linkify-it": "^4.0.1",
"mdurl": "^1.0.1", "mdurl": "^1.0.1",
"uc.micro": "^1.0.5" "uc.micro": "^1.0.5"
} }
@ -2910,9 +2922,9 @@
} }
}, },
"sass": { "sass": {
"version": "1.50.0", "version": "1.52.1",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.50.0.tgz", "resolved": "https://registry.npmjs.org/sass/-/sass-1.52.1.tgz",
"integrity": "sha512-cLsD6MEZ5URXHStxApajEh7gW189kkjn4Rc8DQweMyF+o5HF5nfEz8QYLMlPsTOD88DknatTmBWkOcw5/LnJLQ==", "integrity": "sha512-fSzYTbr7z8oQnVJ3Acp9hV80dM1fkMN7mSD/25mpcct9F7FPBMOI8krEYALgU1aZoqGhQNhTPsuSmxjnIvAm4Q==",
"dev": true, "dev": true,
"requires": { "requires": {
"chokidar": ">=3.0.0 <4.0.0", "chokidar": ">=3.0.0 <4.0.0",
@ -2969,6 +2981,11 @@
"object-inspect": "^1.9.0" "object-inspect": "^1.9.0"
} }
}, },
"snabbdom": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.5.0.tgz",
"integrity": "sha512-Ff5BKG18KrrPuskHJlA9aujPHqEabItaDl96l7ZZndF4zt5AYSczz7ZjjgQAX5IBd5cd25lw9NfgX21yVUJ+9g=="
},
"sortablejs": { "sortablejs": {
"version": "1.15.0", "version": "1.15.0",
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz", "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz",

View File

@ -1,8 +1,8 @@
{ {
"private": true, "private": true,
"scripts": { "scripts": {
"build:css:dev": "sass ./resources/sass:./public/dist", "build:css:dev": "sass ./resources/sass:./public/dist --embed-sources",
"build:css:watch": "sass ./resources/sass:./public/dist --watch", "build:css:watch": "sass ./resources/sass:./public/dist --watch --embed-sources",
"build:css:production": "sass ./resources/sass:./public/dist -s compressed", "build:css:production": "sass ./resources/sass:./public/dist -s compressed",
"build:js:dev": "node dev/build/esbuild.js", "build:js:dev": "node dev/build/esbuild.js",
"build:js:watch": "chokidar --initial \"./resources/**/*.js\" -c \"npm run build:js:dev\"", "build:js:watch": "chokidar --initial \"./resources/**/*.js\" -c \"npm run build:js:dev\"",
@ -16,18 +16,19 @@
}, },
"devDependencies": { "devDependencies": {
"chokidar-cli": "^3.0", "chokidar-cli": "^3.0",
"esbuild": "0.14.36", "esbuild": "0.14.42",
"livereload": "^0.9.3", "livereload": "^0.9.3",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"punycode": "^2.1.1", "punycode": "^2.1.1",
"sass": "^1.50.0" "sass": "^1.52.1"
}, },
"dependencies": { "dependencies": {
"clipboard": "^2.0.10", "clipboard": "^2.0.11",
"codemirror": "^5.65.2", "codemirror": "^5.65.5",
"dropzone": "^5.9.3", "dropzone": "^5.9.3",
"markdown-it": "^12.3.2", "markdown-it": "^13.0.1",
"markdown-it-task-lists": "^2.1.1", "markdown-it-task-lists": "^2.1.1",
"snabbdom": "^3.5.0",
"sortablejs": "^1.15.0" "sortablejs": "^1.15.0"
} }
} }

View File

@ -29,6 +29,7 @@
<server name="MAIL_DRIVER" value="array"/> <server name="MAIL_DRIVER" value="array"/>
<server name="LOG_CHANNEL" value="single"/> <server name="LOG_CHANNEL" value="single"/>
<server name="AUTH_METHOD" value="standard"/> <server name="AUTH_METHOD" value="standard"/>
<server name="AUTH_AUTO_INITIATE" value="false"/>
<server name="DISABLE_EXTERNAL_SERVICES" value="true"/> <server name="DISABLE_EXTERNAL_SERVICES" value="true"/>
<server name="ALLOW_UNTRUSTED_SERVER_FETCHING" value="false"/> <server name="ALLOW_UNTRUSTED_SERVER_FETCHING" value="false"/>
<server name="AVATAR_URL" value=""/> <server name="AVATAR_URL" value=""/>

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M16.59 9H15V4c0-.55-.45-1-1-1h-4c-.55 0-1 .45-1 1v5H7.41c-.89 0-1.34 1.08-.71 1.71l4.59 4.59c.39.39 1.02.39 1.41 0l4.59-4.59c.63-.63.19-1.71-.7-1.71zM5 19c0 .55.45 1 1 1h12c.55 0 1-.45 1-1s-.45-1-1-1H6c-.55 0-1 .45-1 1z"/></svg>

After

Width:  |  Height:  |  Size: 297 B

View File

@ -25,6 +25,7 @@ import 'codemirror/mode/ruby/ruby';
import 'codemirror/mode/rust/rust'; import 'codemirror/mode/rust/rust';
import 'codemirror/mode/shell/shell'; import 'codemirror/mode/shell/shell';
import 'codemirror/mode/sql/sql'; import 'codemirror/mode/sql/sql';
import 'codemirror/mode/stex/stex';
import 'codemirror/mode/toml/toml'; import 'codemirror/mode/toml/toml';
import 'codemirror/mode/vb/vb'; import 'codemirror/mode/vb/vb';
import 'codemirror/mode/vbscript/vbscript'; import 'codemirror/mode/vbscript/vbscript';
@ -49,16 +50,19 @@ const modeMap = {
diff: 'diff', diff: 'diff',
for: 'fortran', for: 'fortran',
fortran: 'fortran', fortran: 'fortran',
'f#': 'text/x-fsharp',
fsharp: 'text/x-fsharp',
go: 'go', go: 'go',
haskell: 'haskell', haskell: 'haskell',
hs: 'haskell', hs: 'haskell',
html: 'htmlmixed', html: 'htmlmixed',
ini: 'properties', ini: 'properties',
javascript: 'javascript', javascript: 'text/javascript',
json: {name: 'javascript', json: true}, json: 'application/json',
js: 'javascript', js: 'text/javascript',
jl: 'julia', jl: 'text/x-julia',
julia: 'julia', julia: 'text/x-julia',
latex: 'text/x-stex',
lua: 'lua', lua: 'lua',
md: 'markdown', md: 'markdown',
mdown: 'markdown', mdown: 'markdown',
@ -69,7 +73,7 @@ const modeMap = {
pl: 'perl', pl: 'perl',
powershell: 'powershell', powershell: 'powershell',
properties: 'properties', properties: 'properties',
ocaml: 'mllike', ocaml: 'text/x-ocaml',
pascal: 'text/x-pascal', pascal: 'text/x-pascal',
pas: 'text/x-pascal', pas: 'text/x-pascal',
php: (content) => { php: (content) => {
@ -83,8 +87,11 @@ const modeMap = {
rs: 'rust', rs: 'rust',
shell: 'shell', shell: 'shell',
sh: 'shell', sh: 'shell',
stext: 'text/x-stex',
bash: 'shell', bash: 'shell',
toml: 'toml', toml: 'toml',
ts: 'text/typescript',
typescript: 'text/typescript',
sql: 'text/x-sql', sql: 'text/x-sql',
vbs: 'vbscript', vbs: 'vbscript',
vbscript: 'vbscript', vbscript: 'vbscript',
@ -242,6 +249,21 @@ export function popupEditor(elem, modeSuggestion) {
}); });
} }
/**
* Create an inline editor to replace the given textarea.
* @param {HTMLTextAreaElement} textArea
* @param {String} mode
* @returns {CodeMirror3}
*/
export function inlineEditor(textArea, mode) {
return CodeMirror.fromTextArea(textArea, {
mode: getMode(mode, textArea.value),
lineNumbers: true,
lineWrapping: false,
theme: getTheme(),
});
}
/** /**
* Set the mode of a codemirror instance. * Set the mode of a codemirror instance.
* @param cmInstance * @param cmInstance

View File

@ -0,0 +1,37 @@
import {slideUp, slideDown} from "../services/animations";
/**
* @extends {Component}
*/
class ChapterContents {
setup() {
this.list = this.$refs.list;
this.toggle = this.$refs.toggle;
this.isOpen = this.toggle.classList.contains('open');
this.toggle.addEventListener('click', this.click.bind(this));
}
open() {
this.toggle.classList.add('open');
this.toggle.setAttribute('aria-expanded', 'true');
slideDown(this.list, 180);
this.isOpen = true;
}
close() {
this.toggle.classList.remove('open');
this.toggle.setAttribute('aria-expanded', 'false');
slideUp(this.list, 180);
this.isOpen = false;
}
click(event) {
event.preventDefault();
this.isOpen ? this.close() : this.open();
}
}
export default ChapterContents;

View File

@ -1,33 +0,0 @@
import {slideUp, slideDown} from "../services/animations";
class ChapterToggle {
constructor(elem) {
this.elem = elem;
this.isOpen = elem.classList.contains('open');
elem.addEventListener('click', this.click.bind(this));
}
open() {
const list = this.elem.parentNode.querySelector('.inset-list');
this.elem.classList.add('open');
this.elem.setAttribute('aria-expanded', 'true');
slideDown(list, 240);
}
close() {
const list = this.elem.parentNode.querySelector('.inset-list');
this.elem.classList.remove('open');
this.elem.setAttribute('aria-expanded', 'false');
slideUp(list, 240);
}
click(event) {
event.preventDefault();
this.isOpen ? this.close() : this.open();
this.isOpen = !this.isOpen;
}
}
export default ChapterToggle;

View File

@ -33,10 +33,11 @@ class CodeEditor {
onSelect(this.languageLinks, event => { onSelect(this.languageLinks, event => {
const language = event.target.dataset.lang; const language = event.target.dataset.lang;
this.languageInput.value = language; this.languageInput.value = language;
this.updateEditorMode(language); this.languageInputChange(language);
}); });
onEnterPress(this.languageInput, e => this.save()); onEnterPress(this.languageInput, e => this.save());
this.languageInput.addEventListener('input', e => this.languageInputChange(this.languageInput.value));
onSelect(this.saveButton, e => this.save()); onSelect(this.saveButton, e => this.save());
onChildEvent(this.historyList, 'button', 'click', (event, elem) => { onChildEvent(this.historyList, 'button', 'click', (event, elem) => {
@ -60,7 +61,7 @@ class CodeEditor {
this.callback = callback; this.callback = callback;
this.show() this.show()
.then(() => this.updateEditorMode(language)) .then(() => this.languageInputChange(language))
.then(() => window.importVersioned('code')) .then(() => window.importVersioned('code'))
.then(Code => Code.setContent(this.editor, code)); .then(Code => Code.setContent(this.editor, code));
} }
@ -90,6 +91,22 @@ class CodeEditor {
Code.setMode(this.editor, language, this.editor.getValue()); Code.setMode(this.editor, language, this.editor.getValue());
} }
languageInputChange(language) {
this.updateEditorMode(language);
const inputLang = language.toLowerCase();
let matched = false;
for (const link of this.languageLinks) {
const lang = link.dataset.lang.toLowerCase().trim();
const isMatch = inputLang && lang.startsWith(inputLang);
link.classList.toggle('active', isMatch);
if (isMatch && !matched) {
link.scrollIntoView({block: "center", behavior: "smooth"});
matched = true;
}
}
}
loadHistory() { loadHistory() {
this.history = JSON.parse(window.sessionStorage.getItem(this.historyKey) || '{}'); this.history = JSON.parse(window.sessionStorage.getItem(this.historyKey) || '{}');
const historyKeys = Object.keys(this.history).reverse(); const historyKeys = Object.keys(this.history).reverse();

View File

@ -0,0 +1,16 @@
/**
* A simple component to render a code editor within the textarea
* this exists upon.
* @extends {Component}
*/
class CodeTextarea {
async setup() {
const mode = this.$opts.mode;
const Code = await window.importVersioned('code');
Code.inlineEditor(this.$el, mode);
}
}
export default CodeTextarea;

View File

@ -1,4 +1,5 @@
import {debounce} from "../services/util"; import {debounce} from "../services/util";
import {transitionHeight} from "../services/animations";
class DropdownSearch { class DropdownSearch {
@ -51,7 +52,9 @@ class DropdownSearch {
try { try {
const resp = await window.$http.get(this.getAjaxUrl(searchTerm)); const resp = await window.$http.get(this.getAjaxUrl(searchTerm));
const animate = transitionHeight(this.listContainerElem, 80);
this.listContainerElem.innerHTML = resp.data; this.listContainerElem.innerHTML = resp.data;
animate();
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} }

View File

@ -28,18 +28,31 @@ class DropDown {
this.menu.classList.add('anim', 'menuIn'); this.menu.classList.add('anim', 'menuIn');
this.toggle.setAttribute('aria-expanded', 'true'); this.toggle.setAttribute('aria-expanded', 'true');
const menuOriginalRect = this.menu.getBoundingClientRect();
let heightOffset = 0;
const toggleHeight = this.toggle.getBoundingClientRect().height;
const dropUpwards = menuOriginalRect.bottom > window.innerHeight;
// If enabled, Move to body to prevent being trapped within scrollable sections
if (this.moveMenu) { if (this.moveMenu) {
// Move to body to prevent being trapped within scrollable sections
this.rect = this.menu.getBoundingClientRect();
this.body.appendChild(this.menu); this.body.appendChild(this.menu);
this.menu.style.position = 'fixed'; this.menu.style.position = 'fixed';
if (this.direction === 'right') { if (this.direction === 'right') {
this.menu.style.right = `${(this.rect.right - this.rect.width)}px`; this.menu.style.right = `${(menuOriginalRect.right - menuOriginalRect.width)}px`;
} else { } else {
this.menu.style.left = `${this.rect.left}px`; this.menu.style.left = `${menuOriginalRect.left}px`;
} }
this.menu.style.top = `${this.rect.top}px`; this.menu.style.width = `${menuOriginalRect.width}px`;
this.menu.style.width = `${this.rect.width}px`; heightOffset = dropUpwards ? (window.innerHeight - menuOriginalRect.top - toggleHeight / 2) : menuOriginalRect.top;
}
// Adjust menu to display upwards if near the bottom of the screen
if (dropUpwards) {
this.menu.style.top = 'initial';
this.menu.style.bottom = `${heightOffset}px`;
} else {
this.menu.style.top = `${heightOffset}px`;
this.menu.style.bottom = 'initial';
} }
// Set listener to hide on mouse leave or window click // Set listener to hide on mouse leave or window click
@ -74,18 +87,21 @@ class DropDown {
this.menu.style.display = 'none'; this.menu.style.display = 'none';
this.menu.classList.remove('anim', 'menuIn'); this.menu.classList.remove('anim', 'menuIn');
this.toggle.setAttribute('aria-expanded', 'false'); this.toggle.setAttribute('aria-expanded', 'false');
this.menu.style.top = '';
this.menu.style.bottom = '';
if (this.moveMenu) { if (this.moveMenu) {
this.menu.style.position = ''; this.menu.style.position = '';
this.menu.style[this.direction] = ''; this.menu.style[this.direction] = '';
this.menu.style.top = '';
this.menu.style.width = ''; this.menu.style.width = '';
this.container.appendChild(this.menu); this.container.appendChild(this.menu);
} }
this.showing = false; this.showing = false;
} }
getFocusable() { getFocusable() {
return Array.from(this.menu.querySelectorAll('[tabindex],[href],button,input:not([type=hidden])')); return Array.from(this.menu.querySelectorAll('[tabindex]:not([tabindex="-1"]),[href],button,input:not([type=hidden])'));
} }
focusNext() { focusNext() {

View File

@ -6,9 +6,10 @@ import attachmentsList from "./attachments-list.js"
import autoSuggest from "./auto-suggest.js" import autoSuggest from "./auto-suggest.js"
import backToTop from "./back-to-top.js" import backToTop from "./back-to-top.js"
import bookSort from "./book-sort.js" import bookSort from "./book-sort.js"
import chapterToggle from "./chapter-toggle.js" import chapterContents from "./chapter-contents.js"
import codeEditor from "./code-editor.js" import codeEditor from "./code-editor.js"
import codeHighlighter from "./code-highlighter.js" import codeHighlighter from "./code-highlighter.js"
import codeTextarea from "./code-textarea.js"
import collapsible from "./collapsible.js" import collapsible from "./collapsible.js"
import confirmDialog from "./confirm-dialog" import confirmDialog from "./confirm-dialog"
import customCheckbox from "./custom-checkbox.js" import customCheckbox from "./custom-checkbox.js"
@ -62,9 +63,10 @@ const componentMapping = {
"auto-suggest": autoSuggest, "auto-suggest": autoSuggest,
"back-to-top": backToTop, "back-to-top": backToTop,
"book-sort": bookSort, "book-sort": bookSort,
"chapter-toggle": chapterToggle, "chapter-contents": chapterContents,
"code-editor": codeEditor, "code-editor": codeEditor,
"code-highlighter": codeHighlighter, "code-highlighter": codeHighlighter,
"code-textarea": codeTextarea,
"collapsible": collapsible, "collapsible": collapsible,
"confirm-dialog": confirmDialog, "confirm-dialog": confirmDialog,
"custom-checkbox": customCheckbox, "custom-checkbox": customCheckbox,

View File

@ -2,7 +2,7 @@ import MarkdownIt from "markdown-it";
import mdTasksLists from 'markdown-it-task-lists'; import mdTasksLists from 'markdown-it-task-lists';
import Clipboard from "../services/clipboard"; import Clipboard from "../services/clipboard";
import {debounce} from "../services/util"; import {debounce} from "../services/util";
import {patchDomFromHtmlString} from "../services/vdom";
import DrawIO from "../services/drawio"; import DrawIO from "../services/drawio";
class MarkdownEditor { class MarkdownEditor {
@ -127,18 +127,31 @@ class MarkdownEditor {
updateAndRender() { updateAndRender() {
const content = this.cm.getValue(); const content = this.cm.getValue();
this.input.value = content; this.input.value = content;
const html = this.markdown.render(content); const html = this.markdown.render(content);
window.$events.emit('editor-html-change', html); window.$events.emit('editor-html-change', html);
window.$events.emit('editor-markdown-change', content); window.$events.emit('editor-markdown-change', content);
// Set body content // Set body content
const target = this.getDisplayTarget();
this.displayDoc.body.className = 'page-content'; this.displayDoc.body.className = 'page-content';
this.displayDoc.body.innerHTML = html; patchDomFromHtmlString(target, html);
// Copy styles from page head and set custom styles for editor // Copy styles from page head and set custom styles for editor
this.loadStylesIntoDisplay(); this.loadStylesIntoDisplay();
} }
getDisplayTarget() {
const body = this.displayDoc.body;
if (body.children.length === 0) {
const wrap = document.createElement('div');
this.displayDoc.body.append(wrap);
}
return body.children[0];
}
loadStylesIntoDisplay() { loadStylesIntoDisplay() {
if (this.displayStylesLoaded) return; if (this.displayStylesLoaded) return;
this.displayDoc.documentElement.classList.add('markdown-editor-display'); this.displayDoc.documentElement.classList.add('markdown-editor-display');

View File

@ -49,7 +49,7 @@ export function slideUp(element, animTime = 400) {
const currentPaddingTop = computedStyles.getPropertyValue('padding-top'); const currentPaddingTop = computedStyles.getPropertyValue('padding-top');
const currentPaddingBottom = computedStyles.getPropertyValue('padding-bottom'); const currentPaddingBottom = computedStyles.getPropertyValue('padding-bottom');
const animStyles = { const animStyles = {
height: [`${currentHeight}px`, '0px'], maxHeight: [`${currentHeight}px`, '0px'],
overflow: ['hidden', 'hidden'], overflow: ['hidden', 'hidden'],
paddingTop: [currentPaddingTop, '0px'], paddingTop: [currentPaddingTop, '0px'],
paddingBottom: [currentPaddingBottom, '0px'], paddingBottom: [currentPaddingBottom, '0px'],
@ -73,7 +73,7 @@ export function slideDown(element, animTime = 400) {
const targetPaddingTop = computedStyles.getPropertyValue('padding-top'); const targetPaddingTop = computedStyles.getPropertyValue('padding-top');
const targetPaddingBottom = computedStyles.getPropertyValue('padding-bottom'); const targetPaddingBottom = computedStyles.getPropertyValue('padding-bottom');
const animStyles = { const animStyles = {
height: ['0px', `${targetHeight}px`], maxHeight: ['0px', `${targetHeight}px`],
overflow: ['hidden', 'hidden'], overflow: ['hidden', 'hidden'],
paddingTop: ['0px', targetPaddingTop], paddingTop: ['0px', targetPaddingTop],
paddingBottom: ['0px', targetPaddingBottom], paddingBottom: ['0px', targetPaddingBottom],
@ -82,6 +82,38 @@ export function slideDown(element, animTime = 400) {
animateStyles(element, animStyles, animTime); animateStyles(element, animStyles, animTime);
} }
/**
* Transition the height of the given element between two states.
* Call with first state, and you'll receive a function in return.
* Call the returned function in the second state to animate between those two states.
* If animating to/from 0-height use the slide-up/slide down as easier alternatives.
* @param {Element} element - Element to animate
* @param {Number} animTime - Animation time in ms
* @returns {function} - Function to run in second state to trigger animation.
*/
export function transitionHeight(element, animTime = 400) {
const startHeight = element.getBoundingClientRect().height;
const initialComputedStyles = getComputedStyle(element);
const startPaddingTop = initialComputedStyles.getPropertyValue('padding-top');
const startPaddingBottom = initialComputedStyles.getPropertyValue('padding-bottom');
return () => {
cleanupExistingElementAnimation(element);
const targetHeight = element.getBoundingClientRect().height;
const computedStyles = getComputedStyle(element);
const targetPaddingTop = computedStyles.getPropertyValue('padding-top');
const targetPaddingBottom = computedStyles.getPropertyValue('padding-bottom');
const animStyles = {
height: [`${startHeight}px`, `${targetHeight}px`],
overflow: ['hidden', 'hidden'],
paddingTop: [startPaddingTop, targetPaddingTop],
paddingBottom: [startPaddingBottom, targetPaddingBottom],
};
animateStyles(element, animStyles, animTime);
};
}
/** /**
* Animate the css styles of an element using FLIP animation techniques. * Animate the css styles of an element using FLIP animation techniques.
* Styles must be an object where the keys are style properties, camelcase, and the values * Styles must be an object where the keys are style properties, camelcase, and the values

View File

@ -0,0 +1,31 @@
import {
init,
attributesModule,
toVNode
} from "snabbdom";
let patcher;
/**
* @returns {Function}
*/
function getPatcher() {
if (patcher) return patcher;
patcher = init([
attributesModule,
]);
return patcher;
}
/**
* @param {Element} domTarget
* @param {String} html
*/
export function patchDomFromHtmlString(domTarget, html) {
const contentDom = document.createElement('div');
contentDom.innerHTML = html;
getPatcher()(toVNode(domTarget), toVNode(contentDom));
}

View File

@ -60,13 +60,7 @@ async function uploadImageFile(file, pageId) {
throw new Error(`Not an image file`); throw new Error(`Not an image file`);
} }
let ext = 'png'; const remoteFilename = file.name || `image-${Date.now()}.png`;
if (file.name) {
let fileNameMatches = file.name.match(/\.(.+)$/);
if (fileNameMatches.length > 1) ext = fileNameMatches[1];
}
const remoteFilename = "image-" + Date.now() + "." + ext;
const formData = new FormData(); const formData = new FormData();
formData.append('file', file, remoteFilename); formData.append('file', file, remoteFilename);
formData.append('uploaded_to', pageId); formData.append('uploaded_to', pageId);

View File

@ -86,7 +86,13 @@ function defineCodeBlockCustomElement(editor) {
getContent() { getContent() {
const code = this.querySelector('code') || this.querySelector('pre'); const code = this.querySelector('code') || this.querySelector('pre');
const tempEl = document.createElement('pre'); const tempEl = document.createElement('pre');
tempEl.innerHTML = code.innerHTML.replace().replace(/<br\s*[\/]?>/gi ,'\n').replace(/\ufeff/g, ''); tempEl.innerHTML = code.innerHTML.replace(/\ufeff/g, '');
const brs = tempEl.querySelectorAll('br');
for (const br of brs) {
br.replaceWith('\n');
}
return tempEl.textContent; return tempEl.textContent;
} }
@ -104,6 +110,7 @@ function defineCodeBlockCustomElement(editor) {
const container = this.shadowRoot.querySelector('.CodeMirrorContainer'); const container = this.shadowRoot.querySelector('.CodeMirrorContainer');
const renderCodeMirror = (Code) => { const renderCodeMirror = (Code) => {
console.log({content});
this.cm = Code.wysiwygView(container, content, this.getLanguage()); this.cm = Code.wysiwygView(container, content, this.getLanguage());
Code.updateLayout(this.cm); Code.updateLayout(this.cm);
setTimeout(() => { setTimeout(() => {
@ -159,6 +166,7 @@ function register(editor, url) {
showPopup(editor, textContent, '', (newCode, newLang) => { showPopup(editor, textContent, '', (newCode, newLang) => {
const pre = doc.createElement('pre'); const pre = doc.createElement('pre');
const code = doc.createElement('code'); const code = doc.createElement('code');
console.log(newCode);
code.classList.add(`language-${newLang}`); code.classList.add(`language-${newLang}`);
code.innerText = newCode; code.innerText = newCode;
pre.append(code); pre.append(code);

View File

@ -28,6 +28,8 @@ return [
// Books // Books
'book_create' => 'تم إنشاء كتاب', 'book_create' => 'تم إنشاء كتاب',
'book_create_notification' => 'تم إنشاء الكتاب بنجاح', 'book_create_notification' => 'تم إنشاء الكتاب بنجاح',
'book_create_from_chapter' => 'converted chapter to book',
'book_create_from_chapter_notification' => 'Chapter successfully converted to a book',
'book_update' => 'تم تحديث الكتاب', 'book_update' => 'تم تحديث الكتاب',
'book_update_notification' => 'تم تحديث الكتاب بنجاح', 'book_update_notification' => 'تم تحديث الكتاب بنجاح',
'book_delete' => 'تم حذف الكتاب', 'book_delete' => 'تم حذف الكتاب',
@ -38,6 +40,8 @@ return [
// Bookshelves // Bookshelves
'bookshelf_create' => 'تم إنشاء رف كتب', 'bookshelf_create' => 'تم إنشاء رف كتب',
'bookshelf_create_notification' => 'تم إنشاء الرف بنجاح', 'bookshelf_create_notification' => 'تم إنشاء الرف بنجاح',
'bookshelf_create_from_book' => 'converted book to bookshelf',
'bookshelf_create_from_book_notification' => 'Book successfully converted to a shelf',
'bookshelf_update' => 'تم تحديث الرف', 'bookshelf_update' => 'تم تحديث الرف',
'bookshelf_update_notification' => 'تم تحديث الرف بنجاح', 'bookshelf_update_notification' => 'تم تحديث الرف بنجاح',
'bookshelf_delete' => 'تم تحديث الرف', 'bookshelf_delete' => 'تم تحديث الرف',

View File

@ -38,6 +38,11 @@ return [
'registration_email_domain_invalid' => 'المجال الخاص بالبريد الإلكتروني لا يملك حق الوصول لهذا التطبيق', 'registration_email_domain_invalid' => 'المجال الخاص بالبريد الإلكتروني لا يملك حق الوصول لهذا التطبيق',
'register_success' => 'شكراً لإنشاء حسابكم! تم تسجيلكم ودخولكم للحساب الخاص بكم.', 'register_success' => 'شكراً لإنشاء حسابكم! تم تسجيلكم ودخولكم للحساب الخاص بكم.',
// Login auto-initiation
'auto_init_starting' => 'Attempting Login',
'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.',
'auto_init_start_link' => 'Proceed with authentication',
// Password Reset // Password Reset
'reset_password' => 'استعادة كلمة المرور', 'reset_password' => 'استعادة كلمة المرور',
'reset_password_send_instructions' => 'أدخل بريدك الإلكتروني بالأسفل وسيتم إرسال رسالة برابط لاستعادة كلمة المرور.', 'reset_password_send_instructions' => 'أدخل بريدك الإلكتروني بالأسفل وسيتم إرسال رسالة برابط لاستعادة كلمة المرور.',

View File

@ -47,6 +47,8 @@ return [
'previous' => 'Previous', 'previous' => 'Previous',
'filter_active' => 'Active Filter:', 'filter_active' => 'Active Filter:',
'filter_clear' => 'Clear Filter', 'filter_clear' => 'Clear Filter',
'download' => 'Download',
'open_in_tab' => 'Open in Tab',
// Sort Options // Sort Options
'sort_options' => 'خيارات الفرز', 'sort_options' => 'خيارات الفرز',

View File

@ -355,4 +355,16 @@ return [
'copy_consider_images' => 'Page image files will not be duplicated & the original images will retain their relation to the page they were originally uploaded to.', 'copy_consider_images' => 'Page image files will not be duplicated & the original images will retain their relation to the page they were originally uploaded to.',
'copy_consider_attachments' => 'Page attachments will not be copied.', 'copy_consider_attachments' => 'Page attachments will not be copied.',
'copy_consider_access' => 'A change of location, owner or permissions may result in this content being accessible to those previously without access.', 'copy_consider_access' => 'A change of location, owner or permissions may result in this content being accessible to those previously without access.',
// Conversions
'convert_to_shelf' => 'Convert to Shelf',
'convert_to_shelf_contents_desc' => 'You can convert this book to a new shelf with the same contents. Chapters contained within this book will be converted to new books. If this book contains any pages, that are not in a chapter, this book will be renamed and contain such pages, and this book will become part of the new shelf.',
'convert_to_shelf_permissions_desc' => 'Any permissions set on this book will be copied to the new shelf and to all new child books that don\'t have their own permissions enforced. Note that permissions on shelves do not auto-cascade to content within, as they do for books.',
'convert_book' => 'Convert Book',
'convert_book_confirm' => 'Are you sure you want to convert this book?',
'convert_undo_warning' => 'This cannot be as easily undone.',
'convert_to_book' => 'Convert to Book',
'convert_to_book_desc' => 'You can convert this chapter to a new book with the same contents. Any permissions set on this chapter will be copied to the new book but any inherited permissions, from the parent book, will not be copied which could lead to a change of access control.',
'convert_chapter' => 'Convert Chapter',
'convert_chapter_confirm' => 'Are you sure you want to convert this chapter?',
]; ];

View File

@ -28,6 +28,8 @@ return [
// Books // Books
'book_create' => 'създадена книга', 'book_create' => 'създадена книга',
'book_create_notification' => 'Книгата е създадена успешно', 'book_create_notification' => 'Книгата е създадена успешно',
'book_create_from_chapter' => 'converted chapter to book',
'book_create_from_chapter_notification' => 'Chapter successfully converted to a book',
'book_update' => 'обновена книга', 'book_update' => 'обновена книга',
'book_update_notification' => 'Книгата е обновена успешно', 'book_update_notification' => 'Книгата е обновена успешно',
'book_delete' => 'изтрита книга', 'book_delete' => 'изтрита книга',
@ -38,6 +40,8 @@ return [
// Bookshelves // Bookshelves
'bookshelf_create' => 'създаден рафт', 'bookshelf_create' => 'създаден рафт',
'bookshelf_create_notification' => 'Рафтът е създаден успешно', 'bookshelf_create_notification' => 'Рафтът е създаден успешно',
'bookshelf_create_from_book' => 'converted book to bookshelf',
'bookshelf_create_from_book_notification' => 'Book successfully converted to a shelf',
'bookshelf_update' => 'обновен рафт', 'bookshelf_update' => 'обновен рафт',
'bookshelf_update_notification' => 'Рафтът е обновен успешно', 'bookshelf_update_notification' => 'Рафтът е обновен успешно',
'bookshelf_delete' => 'изтрит рафт', 'bookshelf_delete' => 'изтрит рафт',

View File

@ -38,6 +38,11 @@ return [
'registration_email_domain_invalid' => 'Този емейл домейн към момента няма достъп до приложението', 'registration_email_domain_invalid' => 'Този емейл домейн към момента няма достъп до приложението',
'register_success' => 'Благодарим Ви за регистрацията! В момента сте регистриран и сте вписани в приложението.', 'register_success' => 'Благодарим Ви за регистрацията! В момента сте регистриран и сте вписани в приложението.',
// Login auto-initiation
'auto_init_starting' => 'Attempting Login',
'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.',
'auto_init_start_link' => 'Proceed with authentication',
// Password Reset // Password Reset
'reset_password' => 'Нулиране на паролата', 'reset_password' => 'Нулиране на паролата',
'reset_password_send_instructions' => 'Въведете емейла си и ще ви бъде изпратен емейл с линк за нулиране на паролата.', 'reset_password_send_instructions' => 'Въведете емейла си и ще ви бъде изпратен емейл с линк за нулиране на паролата.',

View File

@ -47,6 +47,8 @@ return [
'previous' => 'Предишен', 'previous' => 'Предишен',
'filter_active' => 'Активен филтър:', 'filter_active' => 'Активен филтър:',
'filter_clear' => 'Изчисти филтъра', 'filter_clear' => 'Изчисти филтъра',
'download' => 'Download',
'open_in_tab' => 'Open in Tab',
// Sort Options // Sort Options
'sort_options' => 'Опции за сортиране', 'sort_options' => 'Опции за сортиране',

View File

@ -355,4 +355,16 @@ return [
'copy_consider_images' => 'Файловете на изображенията в страницата няма да бъдат дубликирани и оригиналните изображения ще запазят връзката си със страницата, на която са били качени първоначално.', 'copy_consider_images' => 'Файловете на изображенията в страницата няма да бъдат дубликирани и оригиналните изображения ще запазят връзката си със страницата, на която са били качени първоначално.',
'copy_consider_attachments' => 'Прикачените към страницата обекти няма да бъдат копирани.', 'copy_consider_attachments' => 'Прикачените към страницата обекти няма да бъдат копирани.',
'copy_consider_access' => 'Смяна на местоположението, собственика или привилегиите може да направи това съдържание достъпно за тези, които не са го виждали преди.', 'copy_consider_access' => 'Смяна на местоположението, собственика или привилегиите може да направи това съдържание достъпно за тези, които не са го виждали преди.',
// Conversions
'convert_to_shelf' => 'Convert to Shelf',
'convert_to_shelf_contents_desc' => 'You can convert this book to a new shelf with the same contents. Chapters contained within this book will be converted to new books. If this book contains any pages, that are not in a chapter, this book will be renamed and contain such pages, and this book will become part of the new shelf.',
'convert_to_shelf_permissions_desc' => 'Any permissions set on this book will be copied to the new shelf and to all new child books that don\'t have their own permissions enforced. Note that permissions on shelves do not auto-cascade to content within, as they do for books.',
'convert_book' => 'Convert Book',
'convert_book_confirm' => 'Are you sure you want to convert this book?',
'convert_undo_warning' => 'This cannot be as easily undone.',
'convert_to_book' => 'Convert to Book',
'convert_to_book_desc' => 'You can convert this chapter to a new book with the same contents. Any permissions set on this chapter will be copied to the new book but any inherited permissions, from the parent book, will not be copied which could lead to a change of access control.',
'convert_chapter' => 'Convert Chapter',
'convert_chapter_confirm' => 'Are you sure you want to convert this chapter?',
]; ];

View File

@ -28,6 +28,8 @@ return [
// Books // Books
'book_create' => 'je kreirao/la knjigu', 'book_create' => 'je kreirao/la knjigu',
'book_create_notification' => 'Book successfully created', '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' => 'je ažurirao/la knjigu', 'book_update' => 'je ažurirao/la knjigu',
'book_update_notification' => 'Book successfully updated', 'book_update_notification' => 'Book successfully updated',
'book_delete' => 'je izbrisao/la knjigu', 'book_delete' => 'je izbrisao/la knjigu',
@ -38,6 +40,8 @@ return [
// Bookshelves // Bookshelves
'bookshelf_create' => 'created bookshelf', 'bookshelf_create' => 'created bookshelf',
'bookshelf_create_notification' => 'Bookshelf successfully created', 'bookshelf_create_notification' => 'Bookshelf successfully created',
'bookshelf_create_from_book' => 'converted book to bookshelf',
'bookshelf_create_from_book_notification' => 'Book successfully converted to a shelf',
'bookshelf_update' => 'je ažurirao/la policu za knjige', 'bookshelf_update' => 'je ažurirao/la policu za knjige',
'bookshelf_update_notification' => 'Bookshelf successfully updated', 'bookshelf_update_notification' => 'Bookshelf successfully updated',
'bookshelf_delete' => 'je izbrisao/la policu za knjige', 'bookshelf_delete' => 'je izbrisao/la policu za knjige',

View File

@ -38,6 +38,11 @@ return [
'registration_email_domain_invalid' => 'Ta e-mail domena nema pristup ovoj aplikaciji', 'registration_email_domain_invalid' => 'Ta e-mail domena nema pristup ovoj aplikaciji',
'register_success' => 'Hvala na registraciji! Sada ste registrovani i prijavljeni.', 'register_success' => 'Hvala na registraciji! Sada ste registrovani i prijavljeni.',
// Login auto-initiation
'auto_init_starting' => 'Attempting Login',
'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.',
'auto_init_start_link' => 'Proceed with authentication',
// Password Reset // Password Reset
'reset_password' => 'Resetuj Lozinku', 'reset_password' => 'Resetuj Lozinku',
'reset_password_send_instructions' => 'Unesite vašu e-mail adresu ispod i na nju ćemo vam poslati e-mail sa linkom za promjenu lozinke.', 'reset_password_send_instructions' => 'Unesite vašu e-mail adresu ispod i na nju ćemo vam poslati e-mail sa linkom za promjenu lozinke.',

View File

@ -47,6 +47,8 @@ return [
'previous' => 'Prethodno', 'previous' => 'Prethodno',
'filter_active' => 'Active Filter:', 'filter_active' => 'Active Filter:',
'filter_clear' => 'Clear Filter', 'filter_clear' => 'Clear Filter',
'download' => 'Download',
'open_in_tab' => 'Open in Tab',
// Sort Options // Sort Options
'sort_options' => 'Opcije sortiranja', 'sort_options' => 'Opcije sortiranja',

View File

@ -355,4 +355,16 @@ return [
'copy_consider_images' => 'Page image files will not be duplicated & the original images will retain their relation to the page they were originally uploaded to.', 'copy_consider_images' => 'Page image files will not be duplicated & the original images will retain their relation to the page they were originally uploaded to.',
'copy_consider_attachments' => 'Page attachments will not be copied.', 'copy_consider_attachments' => 'Page attachments will not be copied.',
'copy_consider_access' => 'A change of location, owner or permissions may result in this content being accessible to those previously without access.', 'copy_consider_access' => 'A change of location, owner or permissions may result in this content being accessible to those previously without access.',
// Conversions
'convert_to_shelf' => 'Convert to Shelf',
'convert_to_shelf_contents_desc' => 'You can convert this book to a new shelf with the same contents. Chapters contained within this book will be converted to new books. If this book contains any pages, that are not in a chapter, this book will be renamed and contain such pages, and this book will become part of the new shelf.',
'convert_to_shelf_permissions_desc' => 'Any permissions set on this book will be copied to the new shelf and to all new child books that don\'t have their own permissions enforced. Note that permissions on shelves do not auto-cascade to content within, as they do for books.',
'convert_book' => 'Convert Book',
'convert_book_confirm' => 'Are you sure you want to convert this book?',
'convert_undo_warning' => 'This cannot be as easily undone.',
'convert_to_book' => 'Convert to Book',
'convert_to_book_desc' => 'You can convert this chapter to a new book with the same contents. Any permissions set on this chapter will be copied to the new book but any inherited permissions, from the parent book, will not be copied which could lead to a change of access control.',
'convert_chapter' => 'Convert Chapter',
'convert_chapter_confirm' => 'Are you sure you want to convert this chapter?',
]; ];

View File

@ -28,6 +28,8 @@ return [
// Books // Books
'book_create' => 'ha creat el llibre', 'book_create' => 'ha creat el llibre',
'book_create_notification' => 'Book successfully created', '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' => 'ha actualitzat el llibre', 'book_update' => 'ha actualitzat el llibre',
'book_update_notification' => 'Book successfully updated', 'book_update_notification' => 'Book successfully updated',
'book_delete' => 'ha suprimit un llibre', 'book_delete' => 'ha suprimit un llibre',
@ -38,6 +40,8 @@ return [
// Bookshelves // Bookshelves
'bookshelf_create' => 'created bookshelf', 'bookshelf_create' => 'created bookshelf',
'bookshelf_create_notification' => 'Bookshelf successfully created', 'bookshelf_create_notification' => 'Bookshelf successfully created',
'bookshelf_create_from_book' => 'converted book to bookshelf',
'bookshelf_create_from_book_notification' => 'Book successfully converted to a shelf',
'bookshelf_update' => 'ha actualitzat el prestatge', 'bookshelf_update' => 'ha actualitzat el prestatge',
'bookshelf_update_notification' => 'Bookshelf successfully updated', 'bookshelf_update_notification' => 'Bookshelf successfully updated',
'bookshelf_delete' => 'ha suprimit un prestatge', 'bookshelf_delete' => 'ha suprimit un prestatge',

View File

@ -38,6 +38,11 @@ return [
'registration_email_domain_invalid' => 'Aquest domini de correu electrònic no té accés a aquesta aplicació', 'registration_email_domain_invalid' => 'Aquest domini de correu electrònic no té accés a aquesta aplicació',
'register_success' => 'Gràcies per registrar-vos! Ja us hi heu registrat i heu iniciat la sessió.', 'register_success' => 'Gràcies per registrar-vos! Ja us hi heu registrat i heu iniciat la sessió.',
// Login auto-initiation
'auto_init_starting' => 'Attempting Login',
'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.',
'auto_init_start_link' => 'Proceed with authentication',
// Password Reset // Password Reset
'reset_password' => 'Restableix la contrasenya', 'reset_password' => 'Restableix la contrasenya',
'reset_password_send_instructions' => 'Introduïu la vostra adreça electrònica a continuació i us enviarem un correu electrònic amb un enllaç per a restablir la contrasenya.', 'reset_password_send_instructions' => 'Introduïu la vostra adreça electrònica a continuació i us enviarem un correu electrònic amb un enllaç per a restablir la contrasenya.',

View File

@ -47,6 +47,8 @@ return [
'previous' => 'Previous', 'previous' => 'Previous',
'filter_active' => 'Active Filter:', 'filter_active' => 'Active Filter:',
'filter_clear' => 'Clear Filter', 'filter_clear' => 'Clear Filter',
'download' => 'Download',
'open_in_tab' => 'Open in Tab',
// Sort Options // Sort Options
'sort_options' => 'Opcions d\'ordenació', 'sort_options' => 'Opcions d\'ordenació',

View File

@ -355,4 +355,16 @@ return [
'copy_consider_images' => 'Page image files will not be duplicated & the original images will retain their relation to the page they were originally uploaded to.', 'copy_consider_images' => 'Page image files will not be duplicated & the original images will retain their relation to the page they were originally uploaded to.',
'copy_consider_attachments' => 'Page attachments will not be copied.', 'copy_consider_attachments' => 'Page attachments will not be copied.',
'copy_consider_access' => 'A change of location, owner or permissions may result in this content being accessible to those previously without access.', 'copy_consider_access' => 'A change of location, owner or permissions may result in this content being accessible to those previously without access.',
// Conversions
'convert_to_shelf' => 'Convert to Shelf',
'convert_to_shelf_contents_desc' => 'You can convert this book to a new shelf with the same contents. Chapters contained within this book will be converted to new books. If this book contains any pages, that are not in a chapter, this book will be renamed and contain such pages, and this book will become part of the new shelf.',
'convert_to_shelf_permissions_desc' => 'Any permissions set on this book will be copied to the new shelf and to all new child books that don\'t have their own permissions enforced. Note that permissions on shelves do not auto-cascade to content within, as they do for books.',
'convert_book' => 'Convert Book',
'convert_book_confirm' => 'Are you sure you want to convert this book?',
'convert_undo_warning' => 'This cannot be as easily undone.',
'convert_to_book' => 'Convert to Book',
'convert_to_book_desc' => 'You can convert this chapter to a new book with the same contents. Any permissions set on this chapter will be copied to the new book but any inherited permissions, from the parent book, will not be copied which could lead to a change of access control.',
'convert_chapter' => 'Convert Chapter',
'convert_chapter_confirm' => 'Are you sure you want to convert this chapter?',
]; ];

View File

@ -28,6 +28,8 @@ return [
// Books // Books
'book_create' => 'vytvořil/a knihu', 'book_create' => 'vytvořil/a knihu',
'book_create_notification' => 'Kniha byla úspěšně vytvořena', 'book_create_notification' => 'Kniha byla úspěšně vytvořena',
'book_create_from_chapter' => 'converted chapter to book',
'book_create_from_chapter_notification' => 'Chapter successfully converted to a book',
'book_update' => 'aktualizoval/a knihu', 'book_update' => 'aktualizoval/a knihu',
'book_update_notification' => 'Kniha byla úspěšně aktualizována', 'book_update_notification' => 'Kniha byla úspěšně aktualizována',
'book_delete' => 'odstranil/a knihu', 'book_delete' => 'odstranil/a knihu',
@ -38,6 +40,8 @@ return [
// Bookshelves // Bookshelves
'bookshelf_create' => 'vytvořil/a knihovnu', 'bookshelf_create' => 'vytvořil/a knihovnu',
'bookshelf_create_notification' => 'Knihovna byla úspěšně vytvořena', 'bookshelf_create_notification' => 'Knihovna byla úspěšně vytvořena',
'bookshelf_create_from_book' => 'converted book to bookshelf',
'bookshelf_create_from_book_notification' => 'Book successfully converted to a shelf',
'bookshelf_update' => 'aktualizoval/a knihovnu', 'bookshelf_update' => 'aktualizoval/a knihovnu',
'bookshelf_update_notification' => 'Knihovna byla úspěšně aktualizována', 'bookshelf_update_notification' => 'Knihovna byla úspěšně aktualizována',
'bookshelf_delete' => 'odstranil/a knihovnu', 'bookshelf_delete' => 'odstranil/a knihovnu',

View File

@ -38,6 +38,11 @@ return [
'registration_email_domain_invalid' => 'Registrace z této e-mailové domény nejsou povoleny', 'registration_email_domain_invalid' => 'Registrace z této e-mailové domény nejsou povoleny',
'register_success' => 'Děkujeme za registraci! Nyní jste zaregistrováni a přihlášeni.', 'register_success' => 'Děkujeme za registraci! Nyní jste zaregistrováni a přihlášeni.',
// Login auto-initiation
'auto_init_starting' => 'Attempting Login',
'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.',
'auto_init_start_link' => 'Proceed with authentication',
// Password Reset // Password Reset
'reset_password' => 'Obnovit heslo', 'reset_password' => 'Obnovit heslo',
'reset_password_send_instructions' => 'Níže zadejte svou e-mailovou adresu a bude vám zaslán e-mail s odkazem na obnovení hesla.', 'reset_password_send_instructions' => 'Níže zadejte svou e-mailovou adresu a bude vám zaslán e-mail s odkazem na obnovení hesla.',

View File

@ -47,6 +47,8 @@ return [
'previous' => 'Předchozí', 'previous' => 'Předchozí',
'filter_active' => 'Aktivní filtr:', 'filter_active' => 'Aktivní filtr:',
'filter_clear' => 'Zrušit filtr', 'filter_clear' => 'Zrušit filtr',
'download' => 'Download',
'open_in_tab' => 'Open in Tab',
// Sort Options // Sort Options
'sort_options' => 'Možnosti řazení', 'sort_options' => 'Možnosti řazení',

View File

@ -247,7 +247,7 @@ return [
'pages_permissions_active' => 'Oprávnění stránky byla aktivována', 'pages_permissions_active' => 'Oprávnění stránky byla aktivována',
'pages_initial_revision' => 'První vydání', 'pages_initial_revision' => 'První vydání',
'pages_initial_name' => 'Nová stránka', 'pages_initial_name' => 'Nová stránka',
'pages_editing_draft_notification' => 'Právě upravujete koncept, který byl uložen před :timeDiff.', 'pages_editing_draft_notification' => 'Právě upravujete koncept, který byl uložen :timeDiff.',
'pages_draft_edited_notification' => 'Tato stránka se od té doby změnila. Je doporučeno aktuální koncept zahodit.', 'pages_draft_edited_notification' => 'Tato stránka se od té doby změnila. Je doporučeno aktuální koncept zahodit.',
'pages_draft_page_changed_since_creation' => 'Tato stránka byla aktualizována od vytvoření tohoto konceptu. Doporučuje se zrušit tento koncept nebo se postarat o to, abyste si nepřepsali žádné již zadané změny.', 'pages_draft_page_changed_since_creation' => 'Tato stránka byla aktualizována od vytvoření tohoto konceptu. Doporučuje se zrušit tento koncept nebo se postarat o to, abyste si nepřepsali žádné již zadané změny.',
'pages_draft_edit_active' => [ 'pages_draft_edit_active' => [
@ -355,4 +355,16 @@ return [
'copy_consider_images' => 'Page image files will not be duplicated & the original images will retain their relation to the page they were originally uploaded to.', 'copy_consider_images' => 'Page image files will not be duplicated & the original images will retain their relation to the page they were originally uploaded to.',
'copy_consider_attachments' => 'Přílohy stránky nebudou zkopírovány.', 'copy_consider_attachments' => 'Přílohy stránky nebudou zkopírovány.',
'copy_consider_access' => 'Po změně umístění, vlastníka nebo oprávnění může dojít k tomu, že obsah může být přístupný těm, kteří přístup dříve něměli.', 'copy_consider_access' => 'Po změně umístění, vlastníka nebo oprávnění může dojít k tomu, že obsah může být přístupný těm, kteří přístup dříve něměli.',
// Conversions
'convert_to_shelf' => 'Convert to Shelf',
'convert_to_shelf_contents_desc' => 'You can convert this book to a new shelf with the same contents. Chapters contained within this book will be converted to new books. If this book contains any pages, that are not in a chapter, this book will be renamed and contain such pages, and this book will become part of the new shelf.',
'convert_to_shelf_permissions_desc' => 'Any permissions set on this book will be copied to the new shelf and to all new child books that don\'t have their own permissions enforced. Note that permissions on shelves do not auto-cascade to content within, as they do for books.',
'convert_book' => 'Convert Book',
'convert_book_confirm' => 'Are you sure you want to convert this book?',
'convert_undo_warning' => 'This cannot be as easily undone.',
'convert_to_book' => 'Convert to Book',
'convert_to_book_desc' => 'You can convert this chapter to a new book with the same contents. Any permissions set on this chapter will be copied to the new book but any inherited permissions, from the parent book, will not be copied which could lead to a change of access control.',
'convert_chapter' => 'Convert Chapter',
'convert_chapter_confirm' => 'Are you sure you want to convert this chapter?',
]; ];

View File

@ -0,0 +1,73 @@
<?php
/**
* Activity text strings.
* Is used for all the text within activity logs & notifications.
*/
return [
// Pages
'page_create' => 'tudalen wedi\'i chreu',
'page_create_notification' => 'Tudalen wedi\'i chreu\'n llwyddiannus',
'page_update' => 'tudalen wedi\'i diweddaru',
'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',
// Chapters
'chapter_create' => 'pennod creu',
'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',
// Books
'book_create' => 'llyfr wedi creu',
'book_create_notification' => 'Llyfr wedi\'i creu\'n llwyddiannus',
'book_create_from_chapter' => 'converted chapter to book',
'book_create_from_chapter_notification' => 'Chapter successfully converted to a book',
'book_update' => 'llyfr wedi diweddaru',
'book_update_notification' => 'Llyfr wedi\'i diweddaru\'n llwyddiannus',
'book_delete' => 'llyfr wedi\'i dileu',
'book_delete_notification' => 'Cafodd y llyfr ei dileu yn llwyddiannus',
'book_sort' => 'llyfr wedi\'i ddidoli',
'book_sort_notification' => 'Ail-archebwyd y llyfr yn llwyddiannus',
// Bookshelves
'bookshelf_create' => 'creu silff lyfrau',
'bookshelf_create_notification' => 'Silff lyfrau wedi\'i chreu\'n llwyddiannus',
'bookshelf_create_from_book' => 'converted book to bookshelf',
'bookshelf_create_from_book_notification' => 'Book successfully converted to a shelf',
'bookshelf_update' => 'silff lyfrau wedi\'i diweddaru',
'bookshelf_update_notification' => 'Diweddarwyd y silff lyfrau yn llwyddiannus',
'bookshelf_delete' => 'silff lyfrau wedi\'i dileu',
'bookshelf_delete_notification' => 'Silff lyfrau wedi\'i dileu\'n llwyddiannus',
// Favourites
'favourite_add_notification' => 'Mae ":name" wedi\'i ychwanegu at eich ffefrynnau',
'favourite_remove_notification' => 'Mae ":name" wedi\'i tynnu o\'ch ffefrynnau',
// MFA
'mfa_setup_method_notification' => 'Dull aml-ffactor wedi\'i ffurfweddu\'n llwyddiannus',
'mfa_remove_method_notification' => 'Llwyddwyd i ddileu dull aml-ffactor',
// Webhooks
'webhook_create' => 'webhook wedi creu',
'webhook_create_notification' => 'Webhook wedi\'i creu\'n llwyddiannus',
'webhook_update' => 'webhook wedi\'i diweddaru',
'webhook_update_notification' => 'Webhook wedi\'i diweddaru\'n llwyddiannus',
'webhook_delete' => 'webhook wedi\'i dileu',
'webhook_delete_notification' => 'Webhook wedi\'i dileu\'n llwyddiannus',
// Users
'user_update_notification' => 'Diweddarwyd y defnyddiwr yn llwyddiannus',
'user_delete_notification' => 'Tynnwyd y defnyddiwr yn llwyddiannus',
// Other
'commented_on' => 'gwnaeth sylwadau ar',
'permissions_update' => 'caniatadau wedi\'u diweddaru',
];

115
resources/lang/cy/auth.php Normal file
View File

@ -0,0 +1,115 @@
<?php
/**
* Authentication Language Lines
* The following language lines are used during authentication for various
* messages that we need to display to the user.
*/
return [
'failed' => 'Nid yw\'r manylion hyn yn cyfateb i\'n cofnodion.',
'throttle' => 'Gormod o ymdrechion mewngofnodi. Rhowch gynnig arall arni o gwmpas :seconds eiliadau.',
// Login & Register
'sign_up' => 'Cofrestru',
'log_in' => 'Mewngofnodi',
'log_in_with' => 'Mewngofnodi efo :socialDriver',
'sign_up_with' => 'Cofrestru efo :socialDriver',
'logout' => 'Allgofnodi',
'name' => 'Enw',
'username' => 'Enw defnyddiwr',
'email' => 'Ebost',
'password' => 'Cyfrinair',
'password_confirm' => 'Cadarnhau cyfrinair',
'password_hint' => 'Rhaid bod o leiaf 8 nod',
'forgot_password' => 'Wedi anghofio cyfrinair?',
'remember_me' => 'Cofiwch fi',
'ldap_email_hint' => 'Rhowch e-bost i\'w ddefnyddio ar gyfer y cyfrif hwn.',
'create_account' => 'Creu cyfrif',
'already_have_account' => 'Oes gennych chi gyfrif yn barod?',
'dont_have_account' => 'Dim cyfrif?',
'social_login' => 'Mewngofnodi cymdeithasol',
'social_registration' => 'Cofrestru cymdeithasol',
'social_registration_text' => 'Cofrestru a mewngofnodi gan ddefnyddio dyfais arall.',
'register_thanks' => 'Diolch am cofrestru!',
'register_confirm' => 'Gwiriwch eich e-bost a chliciwch ar y botwm cadarnhau i gael mynediad i: appName.',
'registrations_disabled' => 'Mae cofrestriadau wedi\'u hanalluogi ar hyn o bryd',
'registration_email_domain_invalid' => 'Nid oes gan y parth e-bost hwnnw fynediad i\'r rhaglen hon',
'register_success' => 'Diolch am arwyddo! Rydych bellach wedi cofrestru ac wedi mewngofnodi.',
// Login auto-initiation
'auto_init_starting' => 'Attempting Login',
'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.',
'auto_init_start_link' => 'Proceed with authentication',
// Password Reset
'reset_password' => 'Ailosod cyfrinair',
'reset_password_send_instructions' => 'Rhowch eich e-bost isod ac anfonir e-bost atoch gyda dolen ailosod cyfrinair.',
'reset_password_send_button' => 'Anfon Dolen Ailosod',
'reset_password_sent' => 'A password reset link will be sent to :email if that email address is found in the system.',
'reset_password_success' => 'Your password has been successfully reset.',
'email_reset_subject' => 'Reset your :appName password',
'email_reset_text' => 'You are receiving this email because we received a password reset request for your account.',
'email_reset_not_requested' => 'If you did not request a password reset, no further action is required.',
// Email Confirmation
'email_confirm_subject' => 'Confirm your email on :appName',
'email_confirm_greeting' => 'Thanks for joining :appName!',
'email_confirm_text' => 'Please confirm your email address by clicking the button below:',
'email_confirm_action' => 'Confirm Email',
'email_confirm_send_error' => 'Email confirmation required but the system could not send the email. Contact the admin to ensure email is set up correctly.',
'email_confirm_success' => 'Your email has been confirmed! You should now be able to login using this email address.',
'email_confirm_resent' => 'Confirmation email resent, Please check your inbox.',
'email_not_confirmed' => 'Email Address Not Confirmed',
'email_not_confirmed_text' => 'Your email address has not yet been confirmed.',
'email_not_confirmed_click_link' => 'Please click the link in the email that was sent shortly after you registered.',
'email_not_confirmed_resend' => 'If you cannot find the email you can re-send the confirmation email by submitting the form below.',
'email_not_confirmed_resend_button' => 'Resend Confirmation Email',
// User Invite
'user_invite_email_subject' => 'You have been invited to join :appName!',
'user_invite_email_greeting' => 'An account has been created for you on :appName.',
'user_invite_email_text' => 'Click the button below to set an account password and gain access:',
'user_invite_email_action' => 'Set Account Password',
'user_invite_page_welcome' => 'Welcome to :appName!',
'user_invite_page_text' => 'To finalise your account and gain access you need to set a password which will be used to log-in to :appName on future visits.',
'user_invite_page_confirm_button' => 'Confirm Password',
'user_invite_success_login' => 'Password set, you should now be able to login using your set password to access :appName!',
// Multi-factor Authentication
'mfa_setup' => 'Setup Multi-Factor Authentication',
'mfa_setup_desc' => 'Setup multi-factor authentication as an extra layer of security for your user account.',
'mfa_setup_configured' => 'Already configured',
'mfa_setup_reconfigure' => 'Reconfigure',
'mfa_setup_remove_confirmation' => 'Are you sure you want to remove this multi-factor authentication method?',
'mfa_setup_action' => 'Setup',
'mfa_backup_codes_usage_limit_warning' => 'You have less than 5 backup codes remaining, Please generate and store a new set before you run out of codes to prevent being locked out of your account.',
'mfa_option_totp_title' => 'Mobile App',
'mfa_option_totp_desc' => 'To use multi-factor authentication you\'ll need a mobile application that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator.',
'mfa_option_backup_codes_title' => 'Backup Codes',
'mfa_option_backup_codes_desc' => 'Securely store a set of one-time-use backup codes which you can enter to verify your identity.',
'mfa_gen_confirm_and_enable' => 'Confirm and Enable',
'mfa_gen_backup_codes_title' => 'Backup Codes Setup',
'mfa_gen_backup_codes_desc' => 'Store the below list of codes in a safe place. When accessing the system you\'ll be able to use one of the codes as a second authentication mechanism.',
'mfa_gen_backup_codes_download' => 'Download Codes',
'mfa_gen_backup_codes_usage_warning' => 'Each code can only be used once',
'mfa_gen_totp_title' => 'Mobile App Setup',
'mfa_gen_totp_desc' => 'To use multi-factor authentication you\'ll need a mobile application that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator.',
'mfa_gen_totp_scan' => 'Scan the QR code below using your preferred authentication app to get started.',
'mfa_gen_totp_verify_setup' => 'Verify Setup',
'mfa_gen_totp_verify_setup_desc' => 'Verify that all is working by entering a code, generated within your authentication app, in the input box below:',
'mfa_gen_totp_provide_code_here' => 'Provide your app generated code here',
'mfa_verify_access' => 'Verify Access',
'mfa_verify_access_desc' => 'Your user account requires you to confirm your identity via an additional level of verification before you\'re granted access. Verify using one of your configured methods to continue.',
'mfa_verify_no_methods' => 'No Methods Configured',
'mfa_verify_no_methods_desc' => 'No multi-factor authentication methods could be found for your account. You\'ll need to set up at least one method before you gain access.',
'mfa_verify_use_totp' => 'Verify using a mobile app',
'mfa_verify_use_backup_codes' => 'Verify using a backup code',
'mfa_verify_backup_code' => 'Backup Code',
'mfa_verify_backup_code_desc' => 'Enter one of your remaining backup codes below:',
'mfa_verify_backup_code_enter_here' => 'Enter backup code here',
'mfa_verify_totp_desc' => 'Enter the code, generated using your mobile app, below:',
'mfa_setup_login_notification' => 'Multi-factor method configured, Please now login again using the configured method.',
];

View File

@ -0,0 +1,104 @@
<?php
/**
* Common elements found throughout many areas of BookStack.
*/
return [
// Buttons
'cancel' => 'Cancel',
'confirm' => 'Confirm',
'back' => 'Back',
'save' => 'Save',
'continue' => 'Continue',
'select' => 'Select',
'toggle_all' => 'Toggle All',
'more' => 'More',
// Form Labels
'name' => 'Name',
'description' => 'Description',
'role' => 'Role',
'cover_image' => 'Cover image',
'cover_image_description' => 'This image should be approx 440x250px.',
// Actions
'actions' => 'Actions',
'view' => 'View',
'view_all' => 'View All',
'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',
'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',
// Sort Options
'sort_options' => 'Sort Options',
'sort_direction_toggle' => 'Sort Direction Toggle',
'sort_ascending' => 'Sort Ascending',
'sort_descending' => 'Sort Descending',
'sort_name' => 'Name',
'sort_default' => 'Default',
'sort_created_at' => 'Created Date',
'sort_updated_at' => 'Updated Date',
// Misc
'deleted_user' => 'Deleted User',
'no_activity' => 'No activity to show',
'no_items' => 'No items available',
'back_to_top' => 'Back to top',
'skip_to_main_content' => 'Skip to main content',
'toggle_details' => 'Toggle Details',
'toggle_thumbnails' => 'Toggle Thumbnails',
'details' => 'Details',
'grid_view' => 'Grid View',
'list_view' => 'List View',
'default' => 'Default',
'breadcrumb' => 'Breadcrumb',
'status' => 'Status',
'status_active' => 'Active',
'status_inactive' => 'Inactive',
'never' => 'Never',
'none' => 'None',
// Header
'header_menu_expand' => 'Expand Header Menu',
'profile_menu' => 'Profile Menu',
'view_profile' => 'View Profile',
'edit_profile' => 'Edit Profile',
'dark_mode' => 'Dark Mode',
'light_mode' => 'Light Mode',
// Layout tabs
'tab_info' => 'Info',
'tab_info_label' => 'Tab: Show Secondary Information',
'tab_content' => 'Content',
'tab_content_label' => 'Tab: Show Primary Content',
// Email Content
'email_action_help' => 'If youre having trouble clicking the ":actionText" button, copy and paste the URL below into your web browser:',
'email_rights' => 'All rights reserved',
// Footer Link Options
// Not directly used but available for convenience to users.
'privacy_policy' => 'Privacy Policy',
'terms_of_service' => 'Terms of Service',
];

View File

@ -0,0 +1,34 @@
<?php
/**
* Text used in custom JavaScript driven components.
*/
return [
// Image Manager
'image_select' => 'Image Select',
'image_all' => 'All',
'image_all_title' => 'View all images',
'image_book_title' => 'View images uploaded to this book',
'image_page_title' => 'View images uploaded to this page',
'image_search_hint' => 'Search by image name',
'image_uploaded' => 'Uploaded :uploadedDate',
'image_load_more' => 'Load More',
'image_image_name' => 'Image Name',
'image_delete_used' => 'This image is used in the pages below.',
'image_delete_confirm_text' => 'Are you sure you want to delete this image?',
'image_select_image' => 'Select Image',
'image_dropzone' => 'Drop images or click here to upload',
'images_deleted' => 'Images Deleted',
'image_preview' => 'Image Preview',
'image_upload_success' => 'Image uploaded successfully',
'image_update_success' => 'Image details successfully updated',
'image_delete_success' => 'Image successfully deleted',
'image_upload_remove' => 'Remove',
// Code Editor
'code_editor' => 'Edit Code',
'code_language' => 'Code Language',
'code_content' => 'Code Content',
'code_session_history' => 'Session History',
'code_save' => 'Save Code',
];

View File

@ -0,0 +1,171 @@
<?php
/**
* Page Editor Lines
* Contains text strings used within the user interface of the
* WYSIWYG page editor. Some Markdown editor strings may still
* exist in the 'entities' file instead since this was added later.
*/
return [
// General editor terms
'general' => 'General',
'advanced' => 'Advanced',
'none' => 'None',
'cancel' => 'Cancel',
'save' => 'Save',
'close' => 'Close',
'undo' => 'Undo',
'redo' => 'Redo',
'left' => 'Left',
'center' => 'Center',
'right' => 'Right',
'top' => 'Top',
'middle' => 'Middle',
'bottom' => 'Bottom',
'width' => 'Width',
'height' => 'Height',
'More' => 'More',
'select' => 'Select...',
// Toolbar
'formats' => 'Formats',
'header_large' => 'Large Header',
'header_medium' => 'Medium Header',
'header_small' => 'Small Header',
'header_tiny' => 'Tiny Header',
'paragraph' => 'Paragraph',
'blockquote' => 'Blockquote',
'inline_code' => 'Inline code',
'callouts' => 'Callouts',
'callout_information' => 'Information',
'callout_success' => 'Success',
'callout_warning' => 'Warning',
'callout_danger' => 'Danger',
'bold' => 'Bold',
'italic' => 'Italic',
'underline' => 'Underline',
'strikethrough' => 'Strikethrough',
'superscript' => 'Superscript',
'subscript' => 'Subscript',
'text_color' => 'Text color',
'custom_color' => 'Custom color',
'remove_color' => 'Remove color',
'background_color' => 'Background color',
'align_left' => 'Align left',
'align_center' => 'Align center',
'align_right' => 'Align right',
'align_justify' => 'Justify',
'list_bullet' => 'Bullet list',
'list_numbered' => 'Numbered list',
'list_task' => 'Task list',
'indent_increase' => 'Increase indent',
'indent_decrease' => 'Decrease indent',
'table' => 'Table',
'insert_image' => 'Insert image',
'insert_image_title' => 'Insert/Edit Image',
'insert_link' => 'Insert/edit link',
'insert_link_title' => 'Insert/Edit Link',
'insert_horizontal_line' => 'Insert horizontal line',
'insert_code_block' => 'Insert code block',
'insert_drawing' => 'Insert/edit drawing',
'drawing_manager' => 'Drawing manager',
'insert_media' => 'Insert/edit media',
'insert_media_title' => 'Insert/Edit Media',
'clear_formatting' => 'Clear formatting',
'source_code' => 'Source code',
'source_code_title' => 'Source Code',
'fullscreen' => 'Fullscreen',
'image_options' => 'Image options',
// Tables
'table_properties' => 'Table properties',
'table_properties_title' => 'Table Properties',
'delete_table' => 'Delete table',
'insert_row_before' => 'Insert row before',
'insert_row_after' => 'Insert row after',
'delete_row' => 'Delete row',
'insert_column_before' => 'Insert column before',
'insert_column_after' => 'Insert column after',
'delete_column' => 'Delete column',
'table_cell' => 'Cell',
'table_row' => 'Row',
'table_column' => 'Column',
'cell_properties' => 'Cell properties',
'cell_properties_title' => 'Cell Properties',
'cell_type' => 'Cell type',
'cell_type_cell' => 'Cell',
'cell_scope' => 'Scope',
'cell_type_header' => 'Header cell',
'merge_cells' => 'Merge cells',
'split_cell' => 'Split cell',
'table_row_group' => 'Row Group',
'table_column_group' => 'Column Group',
'horizontal_align' => 'Horizontal align',
'vertical_align' => 'Vertical align',
'border_width' => 'Border width',
'border_style' => 'Border style',
'border_color' => 'Border color',
'row_properties' => 'Row properties',
'row_properties_title' => 'Row Properties',
'cut_row' => 'Cut row',
'copy_row' => 'Copy row',
'paste_row_before' => 'Paste row before',
'paste_row_after' => 'Paste row after',
'row_type' => 'Row type',
'row_type_header' => 'Header',
'row_type_body' => 'Body',
'row_type_footer' => 'Footer',
'alignment' => 'Alignment',
'cut_column' => 'Cut column',
'copy_column' => 'Copy column',
'paste_column_before' => 'Paste column before',
'paste_column_after' => 'Paste column after',
'cell_padding' => 'Cell padding',
'cell_spacing' => 'Cell spacing',
'caption' => 'Caption',
'show_caption' => 'Show caption',
'constrain' => 'Constrain proportions',
'cell_border_solid' => 'Solid',
'cell_border_dotted' => 'Dotted',
'cell_border_dashed' => 'Dashed',
'cell_border_double' => 'Double',
'cell_border_groove' => 'Groove',
'cell_border_ridge' => 'Ridge',
'cell_border_inset' => 'Inset',
'cell_border_outset' => 'Outset',
'cell_border_none' => 'None',
'cell_border_hidden' => 'Hidden',
// Images, links, details/summary & embed
'source' => 'Source',
'alt_desc' => 'Alternative description',
'embed' => 'Embed',
'paste_embed' => 'Paste your embed code below:',
'url' => 'URL',
'text_to_display' => 'Text to display',
'title' => 'Title',
'open_link' => 'Open link in...',
'open_link_current' => 'Current window',
'open_link_new' => 'New window',
'insert_collapsible' => 'Insert collapsible block',
'collapsible_unwrap' => 'Unwrap',
'edit_label' => 'Edit label',
'toggle_open_closed' => 'Toggle open/closed',
'collapsible_edit' => 'Edit collapsible block',
'toggle_label' => 'Toggle label',
// About view
'about' => 'About the editor',
'about_title' => 'About the WYSIWYG Editor',
'editor_license' => 'Editor License & Copyright',
'editor_tiny_license' => 'This editor is built using :tinyLink which is provided under an LGPL v2.1 license.',
'editor_tiny_license_link' => 'The copyright and license details of TinyMCE can be found here.',
'save_continue' => 'Save Page & Continue',
'callouts_cycle' => '(Keep pressing to toggle through types)',
'link_selector' => 'Link to content',
'shortcuts' => 'Shortcuts',
'shortcut' => 'Shortcut',
'shortcuts_intro' => 'The following shortcuts are available in the editor:',
'windows_linux' => '(Windows/Linux)',
'mac' => '(Mac)',
'description' => 'Description',
];

View File

@ -0,0 +1,370 @@
<?php
/**
* Text used for 'Entities' (Document Structure Elements) such as
* Books, Shelves, Chapters & Pages
*/
return [
// Shared
'recently_created' => 'Recently Created',
'recently_created_pages' => 'Recently Created Pages',
'recently_updated_pages' => 'Recently Updated Pages',
'recently_created_chapters' => 'Recently Created Chapters',
'recently_created_books' => 'Recently Created Books',
'recently_created_shelves' => 'Recently Created Shelves',
'recently_update' => 'Recently Updated',
'recently_viewed' => 'Recently Viewed',
'recent_activity' => 'Recent Activity',
'create_now' => 'Create one now',
'revisions' => 'Revisions',
'meta_revision' => 'Revision #:revisionCount',
'meta_created' => 'Created :timeLength',
'meta_created_name' => 'Created :timeLength by :user',
'meta_updated' => 'Updated :timeLength',
'meta_updated_name' => 'Updated :timeLength by :user',
'meta_owned_name' => 'Owned by :user',
'entity_select' => 'Entity Select',
'images' => 'Images',
'my_recent_drafts' => 'My Recent Drafts',
'my_recently_viewed' => 'My Recently Viewed',
'my_most_viewed_favourites' => 'My Most Viewed Favourites',
'my_favourites' => 'My Favourites',
'no_pages_viewed' => 'You have not viewed any pages',
'no_pages_recently_created' => 'No pages have been recently created',
'no_pages_recently_updated' => 'No pages have been recently updated',
'export' => 'Export',
'export_html' => 'Contained Web File',
'export_pdf' => 'PDF File',
'export_text' => 'Plain Text File',
'export_md' => 'Markdown File',
// Permissions and restrictions
'permissions' => 'Permissions',
'permissions_intro' => 'Once enabled, These permissions will take priority over any set role permissions.',
'permissions_enable' => 'Enable Custom Permissions',
'permissions_save' => 'Save Permissions',
'permissions_owner' => 'Owner',
// Search
'search_results' => 'Search Results',
'search_total_results_found' => ':count result found|:count total results found',
'search_clear' => 'Clear Search',
'search_no_pages' => 'No pages matched this search',
'search_for_term' => 'Search for :term',
'search_more' => 'More Results',
'search_advanced' => 'Advanced Search',
'search_terms' => 'Search Terms',
'search_content_type' => 'Content Type',
'search_exact_matches' => 'Exact Matches',
'search_tags' => 'Tag Searches',
'search_options' => 'Options',
'search_viewed_by_me' => 'Viewed by me',
'search_not_viewed_by_me' => 'Not viewed by me',
'search_permissions_set' => 'Permissions set',
'search_created_by_me' => 'Created by me',
'search_updated_by_me' => 'Updated by me',
'search_owned_by_me' => 'Owned by me',
'search_date_options' => 'Date Options',
'search_updated_before' => 'Updated before',
'search_updated_after' => 'Updated after',
'search_created_before' => 'Created before',
'search_created_after' => 'Created after',
'search_set_date' => 'Set Date',
'search_update' => 'Update Search',
// Shelves
'shelf' => 'Shelf',
'shelves' => 'Shelves',
'x_shelves' => ':count Shelf|:count Shelves',
'shelves_long' => 'Bookshelves',
'shelves_empty' => 'No shelves have been created',
'shelves_create' => 'Create New Shelf',
'shelves_popular' => 'Popular Shelves',
'shelves_new' => 'New Shelves',
'shelves_new_action' => 'New Shelf',
'shelves_popular_empty' => 'The most popular shelves will appear here.',
'shelves_new_empty' => 'The most recently created shelves will appear here.',
'shelves_save' => 'Save Shelf',
'shelves_books' => 'Books on this shelf',
'shelves_add_books' => 'Add books to this shelf',
'shelves_drag_books' => 'Drag books here to add them to this shelf',
'shelves_empty_contents' => 'This shelf has no books assigned to it',
'shelves_edit_and_assign' => 'Edit shelf to assign books',
'shelves_edit_named' => 'Edit Bookshelf :name',
'shelves_edit' => 'Edit Bookshelf',
'shelves_delete' => 'Delete Bookshelf',
'shelves_delete_named' => 'Delete Bookshelf :name',
'shelves_delete_explain' => "This will delete the bookshelf with the name ':name'. Contained books will not be deleted.",
'shelves_delete_confirmation' => 'Are you sure you want to delete this bookshelf?',
'shelves_permissions' => 'Bookshelf Permissions',
'shelves_permissions_updated' => 'Bookshelf Permissions Updated',
'shelves_permissions_active' => 'Bookshelf Permissions Active',
'shelves_permissions_cascade_warning' => 'Permissions on bookshelves 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_copy_permissions_to_books' => 'Copy Permissions to Books',
'shelves_copy_permissions' => 'Copy Permissions',
'shelves_copy_permissions_explain' => 'This will apply the current permission settings of this bookshelf to all books contained within. Before activating, ensure any changes to the permissions of this bookshelf have been saved.',
'shelves_copy_permission_success' => 'Bookshelf permissions copied to :count books',
// Books
'book' => 'Book',
'books' => 'Books',
'x_books' => ':count Book|:count Books',
'books_empty' => 'No books have been created',
'books_popular' => 'Popular Books',
'books_recent' => 'Recent Books',
'books_new' => 'New Books',
'books_new_action' => 'New Book',
'books_popular_empty' => 'The most popular books will appear here.',
'books_new_empty' => 'The most recently created books will appear here.',
'books_create' => 'Create New Book',
'books_delete' => 'Delete Book',
'books_delete_named' => 'Delete Book :bookName',
'books_delete_explain' => 'This will delete the book with the name \':bookName\'. All pages and chapters will be removed.',
'books_delete_confirmation' => 'Are you sure you want to delete this book?',
'books_edit' => 'Edit Book',
'books_edit_named' => 'Edit Book :bookName',
'books_form_book_name' => 'Book Name',
'books_save' => 'Save Book',
'books_permissions' => 'Book Permissions',
'books_permissions_updated' => 'Book Permissions Updated',
'books_empty_contents' => 'No pages or chapters have been created for this book.',
'books_empty_create_page' => 'Create a new page',
'books_empty_sort_current_book' => 'Sort the current book',
'books_empty_add_chapter' => 'Add a chapter',
'books_permissions_active' => 'Book Permissions Active',
'books_search_this' => 'Search this book',
'books_navigation' => 'Book Navigation',
'books_sort' => 'Sort Book Contents',
'books_sort_named' => 'Sort Book :bookName',
'books_sort_name' => 'Sort by Name',
'books_sort_created' => 'Sort by Created Date',
'books_sort_updated' => 'Sort by Updated Date',
'books_sort_chapters_first' => 'Chapters First',
'books_sort_chapters_last' => 'Chapters Last',
'books_sort_show_other' => 'Show Other Books',
'books_sort_save' => 'Save New Order',
'books_copy' => 'Copy Book',
'books_copy_success' => 'Book successfully copied',
// Chapters
'chapter' => 'Chapter',
'chapters' => 'Chapters',
'x_chapters' => ':count Chapter|:count Chapters',
'chapters_popular' => 'Popular Chapters',
'chapters_new' => 'New Chapter',
'chapters_create' => 'Create New Chapter',
'chapters_delete' => 'Delete Chapter',
'chapters_delete_named' => 'Delete Chapter :chapterName',
'chapters_delete_explain' => 'This will delete the chapter with the name \':chapterName\'. All pages that exist within this chapter will also be deleted.',
'chapters_delete_confirm' => 'Are you sure you want to delete this chapter?',
'chapters_edit' => 'Edit Chapter',
'chapters_edit_named' => 'Edit Chapter :chapterName',
'chapters_save' => 'Save Chapter',
'chapters_move' => 'Move Chapter',
'chapters_move_named' => 'Move Chapter :chapterName',
'chapter_move_success' => 'Chapter moved to :bookName',
'chapters_copy' => 'Copy Chapter',
'chapters_copy_success' => 'Chapter successfully copied',
'chapters_permissions' => 'Chapter Permissions',
'chapters_empty' => 'No pages are currently in this chapter.',
'chapters_permissions_active' => 'Chapter Permissions Active',
'chapters_permissions_success' => 'Chapter Permissions Updated',
'chapters_search_this' => 'Search this chapter',
// Pages
'page' => 'Page',
'pages' => 'Pages',
'x_pages' => ':count Page|:count Pages',
'pages_popular' => 'Popular Pages',
'pages_new' => 'New Page',
'pages_attachments' => 'Attachments',
'pages_navigation' => 'Page Navigation',
'pages_delete' => 'Delete Page',
'pages_delete_named' => 'Delete Page :pageName',
'pages_delete_draft_named' => 'Delete Draft Page :pageName',
'pages_delete_draft' => 'Delete Draft Page',
'pages_delete_success' => 'Page deleted',
'pages_delete_draft_success' => 'Draft page deleted',
'pages_delete_confirm' => 'Are you sure you want to delete this page?',
'pages_delete_draft_confirm' => 'Are you sure you want to delete this draft page?',
'pages_editing_named' => 'Editing Page :pageName',
'pages_edit_draft_options' => 'Draft Options',
'pages_edit_save_draft' => 'Save Draft',
'pages_edit_draft' => 'Edit Page Draft',
'pages_editing_draft' => 'Editing Draft',
'pages_editing_page' => 'Editing Page',
'pages_edit_draft_save_at' => 'Draft saved at ',
'pages_edit_delete_draft' => 'Delete Draft',
'pages_edit_discard_draft' => 'Discard Draft',
'pages_edit_switch_to_markdown' => 'Switch to Markdown Editor',
'pages_edit_switch_to_markdown_clean' => '(Clean Content)',
'pages_edit_switch_to_markdown_stable' => '(Stable Content)',
'pages_edit_switch_to_wysiwyg' => 'Switch to WYSIWYG Editor',
'pages_edit_set_changelog' => 'Set Changelog',
'pages_edit_enter_changelog_desc' => 'Enter a brief description of the changes you\'ve made',
'pages_edit_enter_changelog' => 'Enter Changelog',
'pages_editor_switch_title' => 'Switch Editor',
'pages_editor_switch_are_you_sure' => 'Are you sure you want to change the editor for this page?',
'pages_editor_switch_consider_following' => 'Consider the following when changing editors:',
'pages_editor_switch_consideration_a' => 'Once saved, the new editor option will be used by any future editors, including those that may not be able to change editor type themselves.',
'pages_editor_switch_consideration_b' => 'This can potentially lead to a loss of detail and syntax in certain circumstances.',
'pages_editor_switch_consideration_c' => 'Tag or changelog changes, made since last save, won\'t persist across this change.',
'pages_save' => 'Save Page',
'pages_title' => 'Page Title',
'pages_name' => 'Page Name',
'pages_md_editor' => 'Editor',
'pages_md_preview' => 'Preview',
'pages_md_insert_image' => 'Insert Image',
'pages_md_insert_link' => 'Insert Entity Link',
'pages_md_insert_drawing' => 'Insert Drawing',
'pages_not_in_chapter' => 'Page is not in a chapter',
'pages_move' => 'Move Page',
'pages_move_success' => 'Page moved to ":parentName"',
'pages_copy' => 'Copy Page',
'pages_copy_desination' => 'Copy Destination',
'pages_copy_success' => 'Page successfully copied',
'pages_permissions' => 'Page Permissions',
'pages_permissions_success' => 'Page permissions updated',
'pages_revision' => 'Revision',
'pages_revisions' => 'Page Revisions',
'pages_revisions_named' => 'Page Revisions for :pageName',
'pages_revision_named' => 'Page Revision for :pageName',
'pages_revision_restored_from' => 'Restored from #:id; :summary',
'pages_revisions_created_by' => 'Created By',
'pages_revisions_date' => 'Revision Date',
'pages_revisions_number' => '#',
'pages_revisions_numbered' => 'Revision #:id',
'pages_revisions_numbered_changes' => 'Revision #:id Changes',
'pages_revisions_editor' => 'Editor Type',
'pages_revisions_changelog' => 'Changelog',
'pages_revisions_changes' => 'Changes',
'pages_revisions_current' => 'Current Version',
'pages_revisions_preview' => 'Preview',
'pages_revisions_restore' => 'Restore',
'pages_revisions_none' => 'This page has no revisions',
'pages_copy_link' => 'Copy Link',
'pages_edit_content_link' => 'Edit Content',
'pages_permissions_active' => 'Page Permissions Active',
'pages_initial_revision' => 'Initial publish',
'pages_initial_name' => 'New Page',
'pages_editing_draft_notification' => 'You are currently editing a draft that was last saved :timeDiff.',
'pages_draft_edited_notification' => 'This page has been updated by since that time. It is recommended that you discard this draft.',
'pages_draft_page_changed_since_creation' => 'This page has been updated since this draft was created. It is recommended that you discard this draft or take care not to overwrite any page changes.',
'pages_draft_edit_active' => [
'start_a' => ':count users have started editing this page',
'start_b' => ':userName has started editing this page',
'time_a' => 'since the page was last updated',
'time_b' => 'in the last :minCount minutes',
'message' => ':start :time. Take care not to overwrite each other\'s updates!',
],
'pages_draft_discarded' => 'Draft discarded, The editor has been updated with the current page content',
'pages_specific' => 'Specific Page',
'pages_is_template' => 'Page Template',
// Editor Sidebar
'page_tags' => 'Page Tags',
'chapter_tags' => 'Chapter Tags',
'book_tags' => 'Book Tags',
'shelf_tags' => 'Shelf Tags',
'tag' => 'Tag',
'tags' => 'Tags',
'tag_name' => 'Tag Name',
'tag_value' => 'Tag Value (Optional)',
'tags_explain' => "Add some tags to better categorise your content. \n You can assign a value to a tag for more in-depth organisation.",
'tags_add' => 'Add another tag',
'tags_remove' => 'Remove this tag',
'tags_usages' => 'Total tag usages',
'tags_assigned_pages' => 'Assigned to Pages',
'tags_assigned_chapters' => 'Assigned to Chapters',
'tags_assigned_books' => 'Assigned to Books',
'tags_assigned_shelves' => 'Assigned to Shelves',
'tags_x_unique_values' => ':count unique values',
'tags_all_values' => 'All values',
'tags_view_tags' => 'View Tags',
'tags_view_existing_tags' => 'View existing tags',
'tags_list_empty_hint' => 'Tags can be assigned via the page editor sidebar or while editing the details of a book, chapter or shelf.',
'attachments' => 'Attachments',
'attachments_explain' => 'Upload some files or attach some links to display on your page. These are visible in the page sidebar.',
'attachments_explain_instant_save' => 'Changes here are saved instantly.',
'attachments_items' => 'Attached Items',
'attachments_upload' => 'Upload File',
'attachments_link' => 'Attach Link',
'attachments_set_link' => 'Set Link',
'attachments_delete' => 'Are you sure you want to delete this attachment?',
'attachments_dropzone' => 'Drop files or click here to attach a file',
'attachments_no_files' => 'No files have been uploaded',
'attachments_explain_link' => 'You can attach a link if you\'d prefer not to upload a file. This can be a link to another page or a link to a file in the cloud.',
'attachments_link_name' => 'Link Name',
'attachment_link' => 'Attachment link',
'attachments_link_url' => 'Link to file',
'attachments_link_url_hint' => 'Url of site or file',
'attach' => 'Attach',
'attachments_insert_link' => 'Add Attachment Link to Page',
'attachments_edit_file' => 'Edit File',
'attachments_edit_file_name' => 'File Name',
'attachments_edit_drop_upload' => 'Drop files or click here to upload and overwrite',
'attachments_order_updated' => 'Attachment order updated',
'attachments_updated_success' => 'Attachment details updated',
'attachments_deleted' => 'Attachment deleted',
'attachments_file_uploaded' => 'File successfully uploaded',
'attachments_file_updated' => 'File successfully updated',
'attachments_link_attached' => 'Link successfully attached to page',
'templates' => 'Templates',
'templates_set_as_template' => 'Page is a template',
'templates_explain_set_as_template' => 'You can set this page as a template so its contents be utilized when creating other pages. Other users will be able to use this template if they have view permissions for this page.',
'templates_replace_content' => 'Replace page content',
'templates_append_content' => 'Append to page content',
'templates_prepend_content' => 'Prepend to page content',
// Profile View
'profile_user_for_x' => 'User for :time',
'profile_created_content' => 'Created Content',
'profile_not_created_pages' => ':userName has not created any pages',
'profile_not_created_chapters' => ':userName has not created any chapters',
'profile_not_created_books' => ':userName has not created any books',
'profile_not_created_shelves' => ':userName has not created any shelves',
// Comments
'comment' => 'Comment',
'comments' => 'Comments',
'comment_add' => 'Add Comment',
'comment_placeholder' => 'Leave a comment here',
'comment_count' => '{0} No Comments|{1} 1 Comment|[2,*] :count Comments',
'comment_save' => 'Save Comment',
'comment_saving' => 'Saving comment...',
'comment_deleting' => 'Deleting comment...',
'comment_new' => 'New Comment',
'comment_created' => 'commented :createDiff',
'comment_updated' => 'Updated :updateDiff by :username',
'comment_deleted_success' => 'Comment deleted',
'comment_created_success' => 'Comment added',
'comment_updated_success' => 'Comment updated',
'comment_delete_confirm' => 'Are you sure you want to delete this comment?',
'comment_in_reply_to' => 'In reply to :commentId',
// Revision
'revision_delete_confirm' => 'Are you sure you want to delete this revision?',
'revision_restore_confirm' => 'Are you sure you want to restore this revision? The current page contents will be replaced.',
'revision_delete_success' => 'Revision deleted',
'revision_cannot_delete_latest' => 'Cannot delete the latest revision.',
// Copy view
'copy_consider' => 'Please consider the below when copying content.',
'copy_consider_permissions' => 'Custom permission settings will not be copied.',
'copy_consider_owner' => 'You will become the owner of all copied content.',
'copy_consider_images' => 'Page image files will not be duplicated & the original images will retain their relation to the page they were originally uploaded to.',
'copy_consider_attachments' => 'Page attachments will not be copied.',
'copy_consider_access' => 'A change of location, owner or permissions may result in this content being accessible to those previously without access.',
// Conversions
'convert_to_shelf' => 'Convert to Shelf',
'convert_to_shelf_contents_desc' => 'You can convert this book to a new shelf with the same contents. Chapters contained within this book will be converted to new books. If this book contains any pages, that are not in a chapter, this book will be renamed and contain such pages, and this book will become part of the new shelf.',
'convert_to_shelf_permissions_desc' => 'Any permissions set on this book will be copied to the new shelf and to all new child books that don\'t have their own permissions enforced. Note that permissions on shelves do not auto-cascade to content within, as they do for books.',
'convert_book' => 'Convert Book',
'convert_book_confirm' => 'Are you sure you want to convert this book?',
'convert_undo_warning' => 'This cannot be as easily undone.',
'convert_to_book' => 'Convert to Book',
'convert_to_book_desc' => 'You can convert this chapter to a new book with the same contents. Any permissions set on this chapter will be copied to the new book but any inherited permissions, from the parent book, will not be copied which could lead to a change of access control.',
'convert_chapter' => 'Convert Chapter',
'convert_chapter_confirm' => 'Are you sure you want to convert this chapter?',
];

View File

@ -0,0 +1,109 @@
<?php
/**
* Text shown in error messaging.
*/
return [
// Permissions
'permission' => 'Nid oes gennych ganiatâd i gael mynediad i\'r dudalen y gofynnwyd amdani.',
'permissionJson' => 'Nid oes gennych ganiatâd i gyflawni\'r weithred y gofynnwyd amdani.',
// Auth
'error_user_exists_different_creds' => 'Mae defnyddiwr gyda\'r e-bost :email eisoes yn bodoli ond gyda nodweddion gwahanol.',
'email_already_confirmed' => 'E-bost eisoes wedi\'i gadarnhau, Ceisiwch fewngofnodi.',
'email_confirmation_invalid' => 'Nid yw\'r tocyn cadarnhau hwn yn ddilys neu mae eisoes wedi\'i ddefnyddio. Ceisiwch gofrestru eto.',
'email_confirmation_expired' => 'Mae\'r tocyn cadarnhad wedi dod i ben, Mae e-bost cadarnhau newydd wedi\'i anfon.',
'email_confirmation_awaiting' => 'Mae angen cadarnhau cyfeiriad e-bost y cyfrif a ddefnyddir',
'ldap_fail_anonymous' => 'Methodd mynediad LDAP gan ddefnyddio rhwymiad dienw',
'ldap_fail_authed' => 'Methodd mynediad LDAP gan ddefnyddio\'r manylion dn a chyfrinair a roddwyd',
'ldap_extension_not_installed' => 'Estyniad PHP LDAP heb ei osod',
'ldap_cannot_connect' => 'Methu cysylltu i weinydd ldap, cysylltiad cychwynnol wedi methu',
'saml_already_logged_in' => 'Wedi mewngofnodi yn barod',
'saml_user_not_registered' => 'Nid yw\'r defnyddiwr :name wedi\'i gofrestru ac mae cofrestriad awtomatig wedi\'i analluogi',
'saml_no_email_address' => 'Methu dod o hyd i gyfeiriad e-bost, ar gyfer y defnyddiwr hwn, yn y data a ddarparwyd gan y system ddilysu allanol',
'saml_invalid_response_id' => 'Nid yw\'r cais o\'r system ddilysu allanol yn cael ei gydnabod gan broses a ddechreuwyd gan y cais hwn. Gallai llywio yn ôl ar ôl mewngofnodi achosi\'r broblem hon.',
'saml_fail_authed' => 'Wedi methu mewngofnodi gan ddefnyddio :system, ni roddodd y system awdurdodiad llwyddiannus',
'oidc_already_logged_in' => 'Wedi mewngofnodi yn barod',
'oidc_user_not_registered' => 'Nid yw\'r defnyddiwr :name wedi\'i gofrestru ac mae cofrestriad awtomatig wedi\'i analluogi',
'oidc_no_email_address' => 'Methu dod o hyd i gyfeiriad e-bost, ar gyfer y defnyddiwr hwn, yn y data a ddarparwyd gan y system ddilysu allanol',
'oidc_fail_authed' => 'Wedi methu mewngofnodi gan ddefnyddio :system, ni roddodd y system awdurdodiad llwyddiannus',
'social_no_action_defined' => 'Dim gweithred wedi\'i diffinio',
'social_login_bad_response' => "Gwall a dderbyniwyd yn ystod mewngofnodi :socialAccount:\n:error",
'social_account_in_use' => 'Mae\'r cyfrif :socialAccount hwn eisoes yn cael ei ddefnyddio, Ceisiwch fewngofnodi trwy\'r opsiwn :socialAccount.',
'social_account_email_in_use' => 'Mae\'r e-bost :email eisoes yn cael ei ddefnyddio. Os oes gennych gyfrif yn barod gallwch gysylltu eich cyfrif :socialAccount o osodiadau eich proffil.',
'social_account_existing' => 'Mae\'r :socialAccount hwn eisoes ynghlwm wrth eich proffil.',
'social_account_already_used_existing' => 'Mae\'r cyfrif :socialAccount hwn eisoes yn cael ei ddefnyddio gan ddefnyddiwr arall.',
'social_account_not_used' => 'Nid yw\'r cyfrif :socialAccount hwn yn gysylltiedig ag unrhyw ddefnyddwyr. Atodwch ef yn eich gosodiadau proffil. ',
'social_account_register_instructions' => 'Os nad oes gennych gyfrif eto, gallwch gofrestru cyfrif gan ddefnyddio\'r opsiwn :socialAccount.',
'social_driver_not_found' => 'Gyrrwr cymdeithasol heb ei ganfod',
'social_driver_not_configured' => 'Nid yw eich gosodiadau cymdeithasol :socialAccount wedi\'u ffurfweddu\'n gywir.',
'invite_token_expired' => 'Mae\'r ddolen wahoddiad hon wedi dod i ben. Yn lle hynny, gallwch chi geisio ailosod cyfrinair eich cyfrif.',
// System
'path_not_writable' => 'Nid oedd modd uwchlwytho llwybr ffeil :filePath. Sicrhewch ei fod yn ysgrifenadwy i\'r gweinydd.',
'cannot_get_image_from_url' => 'Methu cael delwedd o :url',
'cannot_create_thumbs' => 'Ni all y gweinydd greu mân-luniau. Gwiriwch fod gennych yr estyniad GD PHP wedi\'i osod.',
'server_upload_limit' => 'Nid yw\'r gweinydd yn caniatáu uwchlwythiadau o\'r maint hwn. Rhowch gynnig ar faint ffeil llai.',
'uploaded' => 'Nid yw\'r gweinydd yn caniatáu uwchlwythiadau o\'r maint hwn. Rhowch gynnig ar faint ffeil llai.',
'image_upload_error' => 'Bu gwall wrth uwchlwytho\'r ddelwedd',
'image_upload_type_error' => 'Mae\'r math o ddelwedd sy\'n cael ei huwchlwytho yn annilys',
'file_upload_timeout' => 'Mae\'r amser uwchlwytho ffeil wedi dod i ben.',
// Attachments
'attachment_not_found' => 'Ni chanfuwyd yr atodiad',
// Pages
'page_draft_autosave_fail' => 'Wedi methu cadw\'r drafft. Sicrhewch fod gennych gysylltiad rhyngrwyd cyn cadw\'r dudalen hon',
'page_custom_home_deletion' => 'Methu dileu tudalen tra ei bod wedi\'i gosod fel hafan',
// Entities
'entity_not_found' => 'Endid heb ei ganfod',
'bookshelf_not_found' => 'Heb ddod o hyd i\'r silff lyfrau',
'book_not_found' => 'Ni chanfuwyd y llyfr',
'page_not_found' => 'Heb ganfod y dudalen',
'chapter_not_found' => 'Pennod heb ei chanfod',
'selected_book_not_found' => 'Ni ddaethpwyd o hyd i\'r llyfr a ddewiswyd',
'selected_book_chapter_not_found' => 'Ni ddaethpwyd o hyd i\'r Llyfr neu\'r Bennod a ddewiswyd',
'guests_cannot_save_drafts' => 'Ni all gwesteion arbed drafftiau',
// Users
'users_cannot_delete_only_admin' => 'Ni allwch ddileu\'r unig weinyddwr',
'users_cannot_delete_guest' => 'Ni allwch ddileu\'r defnyddiwr gwadd',
// Roles
'role_cannot_be_edited' => 'Nid oes modd golygu\'r rôl hon',
'role_system_cannot_be_deleted' => 'Rôl system yw\'r rôl hon ac ni ellir ei dileu',
'role_registration_default_cannot_delete' => 'Ni ellir dileu\'r rôl hon tra ei bod wedi\'i gosod fel y rôl gofrestru ddiofyn',
'role_cannot_remove_only_admin' => 'Y defnyddiwr hwn yw\'r unig ddefnyddiwr sydd wedi\'i neilltuo i rôl y gweinyddwr. Neilltuo rôl y gweinyddwr i ddefnyddiwr arall cyn ceisio ei dynnu yma.',
// Comments
'comment_list' => 'Digwyddodd gwall wrth nôl y sylwadau.',
'cannot_add_comment_to_draft' => 'Ni allwch ychwanegu sylwadau at ddrafft.',
'comment_add' => 'Digwyddodd gwall wrth ychwanegu / diweddaru\'r sylw.',
'comment_delete' => 'Digwyddodd gwall wrth dileu\'r sylwad.',
'empty_comment' => 'Methu ychwanegu sylw gwag.',
// Error pages
'404_page_not_found' => 'Heb ganfod y dudalen',
'sorry_page_not_found' => 'Mae\'n ddrwg gennym, nid oedd modd dod o hyd i\'r dudalen roeddech yn chwilio amdani.',
'sorry_page_not_found_permission_warning' => 'Os oeddech yn disgwyl i\'r dudalen hon fodoli, efallai na fyddai gennych ganiatâd i\'w gweld.',
'image_not_found' => 'Heb ganfod y delwedd',
'image_not_found_subtitle' => 'Mae\'n ddrwg gennym, ni fu modd dod o hyd i\'r ffeil delwedd roeddech yn chwilio amdani.',
'image_not_found_details' => 'Os oeddech chi\'n disgwyl i\'r ddelwedd hon fodoli efallai ei bod wedi\'i dileu.',
'return_home' => 'Dychwelyd i gartref',
'error_occurred' => 'Digwyddodd Gwall',
'app_down' => 'Mae :appName i lawr ar hyn o bryd',
'back_soon' => 'Bydd yn ôl i fyny yn fuan.',
// API errors
'api_no_authorization_found' => 'Ni chanfuwyd tocyn awdurdodi ar y cais',
'api_bad_authorization_format' => 'Canfuwyd tocyn awdurdodi ar y cais ond roedd yn ymddangos bod y fformat yn anghywir',
'api_user_token_not_found' => 'Ni chanfuwyd tocyn API cyfatebol ar gyfer y tocyn awdurdodi a ddarparwyd',
'api_incorrect_token_secret' => 'Mae\'r gyfrinach a ddarparwyd ar gyfer y tocyn API defnyddiedig a roddwyd yn anghywir',
'api_user_no_api_permission' => 'Nid oes gan berchennog y tocyn API a ddefnyddiwyd ganiatâd i wneud galwadau API',
'api_user_token_expired' => 'Mae\'r tocyn awdurdodi a ddefnyddiwyd wedi dod i ben',
// Settings & Maintenance
'maintenance_test_email_failure' => 'Gwall a daflwyd wrth anfon e-bost prawf:',
];

View File

@ -0,0 +1,12 @@
<?php
/**
* Pagination Language Lines
* The following language lines are used by the paginator library to build
* the simple pagination links.
*/
return [
'previous' => '&laquo; Previous',
'next' => 'Next &raquo;',
];

View File

@ -0,0 +1,15 @@
<?php
/**
* Password Reminder Language Lines
* The following language lines are the default lines which match reasons
* that are given by the password broker for a password update attempt has failed.
*/
return [
'password' => 'Passwords must be at least eight characters and match the confirmation.',
'user' => "We can't find a user with that e-mail address.",
'token' => 'The password reset token is invalid for this email address.',
'sent' => 'We have e-mailed your password reset link!',
'reset' => 'Your password has been reset!',
];

View File

@ -0,0 +1,309 @@
<?php
/**
* Settings text strings
* Contains all text strings used in the general settings sections of BookStack
* including users and roles.
*/
return [
// Common Messages
'settings' => 'Settings',
'settings_save' => 'Save Settings',
'settings_save_success' => 'Settings saved',
'system_version' => 'System Version',
'categories' => 'Categories',
// App Settings
'app_customization' => 'Customization',
'app_features_security' => 'Features & Security',
'app_name' => 'Application Name',
'app_name_desc' => 'This name is shown in the header and in any system-sent emails.',
'app_name_header' => 'Show name in header',
'app_public_access' => 'Public Access',
'app_public_access_desc' => 'Enabling this option will allow visitors, that are not logged-in, to access content in your BookStack instance.',
'app_public_access_desc_guest' => 'Access for public visitors can be controlled through the "Guest" user.',
'app_public_access_toggle' => 'Allow public access',
'app_public_viewing' => 'Allow public viewing?',
'app_secure_images' => 'Higher Security Image Uploads',
'app_secure_images_toggle' => 'Enable higher security image uploads',
'app_secure_images_desc' => 'For performance reasons, all images are public. This option adds a random, hard-to-guess string in front of image urls. Ensure directory indexes are not enabled to prevent easy access.',
'app_default_editor' => 'Default Page Editor',
'app_default_editor_desc' => 'Select which editor will be used by default when editing new pages. This can be overridden at a page level where permissions allow.',
'app_custom_html' => 'Custom HTML Head Content',
'app_custom_html_desc' => 'Any content added here will be inserted into the bottom of the <head> section of every page. This is handy for overriding styles or adding analytics code.',
'app_custom_html_disabled_notice' => 'Custom HTML head content is disabled on this settings page to ensure any breaking changes can be reverted.',
'app_logo' => 'Application Logo',
'app_logo_desc' => 'This image should be 43px in height. <br>Large images will be scaled down.',
'app_primary_color' => 'Application Primary Color',
'app_primary_color_desc' => 'Sets the primary color for the application including the banner, buttons, and links.',
'app_homepage' => 'Application Homepage',
'app_homepage_desc' => 'Select a view to show on the homepage instead of the default view. Page permissions are ignored for selected pages.',
'app_homepage_select' => 'Select a page',
'app_footer_links' => 'Footer Links',
'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::<key>" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".',
'app_footer_links_label' => 'Link Label',
'app_footer_links_url' => 'Link URL',
'app_footer_links_add' => 'Add Footer Link',
'app_disable_comments' => 'Disable Comments',
'app_disable_comments_toggle' => 'Disable comments',
'app_disable_comments_desc' => 'Disables comments across all pages in the application. <br> Existing comments are not shown.',
// Color settings
'content_colors' => 'Content Colors',
'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.',
'bookshelf_color' => 'Shelf Color',
'book_color' => 'Book Color',
'chapter_color' => 'Chapter Color',
'page_color' => 'Page Color',
'page_draft_color' => 'Page Draft Color',
// Registration Settings
'reg_settings' => 'Registration',
'reg_enable' => 'Enable Registration',
'reg_enable_toggle' => 'Enable registration',
'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.',
'reg_default_role' => 'Default user role after registration',
'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.',
'reg_email_confirmation' => 'Email Confirmation',
'reg_email_confirmation_toggle' => 'Require email confirmation',
'reg_confirm_email_desc' => 'If domain restriction is used then email confirmation will be required and this option will be ignored.',
'reg_confirm_restrict_domain' => 'Domain Restriction',
'reg_confirm_restrict_domain_desc' => 'Enter a comma separated list of email domains you would like to restrict registration to. Users will be sent an email to confirm their address before being allowed to interact with the application. <br> Note that users will be able to change their email addresses after successful registration.',
'reg_confirm_restrict_domain_placeholder' => 'No restriction set',
// Maintenance settings
'maint' => 'Maintenance',
'maint_image_cleanup' => 'Cleanup Images',
'maint_image_cleanup_desc' => 'Scans page & revision content to check which images and drawings are currently in use and which images are redundant. Ensure you create a full database and image backup before running this.',
'maint_delete_images_only_in_revisions' => 'Also delete images that only exist in old page revisions',
'maint_image_cleanup_run' => 'Run Cleanup',
'maint_image_cleanup_warning' => ':count potentially unused images were found. Are you sure you want to delete these images?',
'maint_image_cleanup_success' => ':count potentially unused images found and deleted!',
'maint_image_cleanup_nothing_found' => 'No unused images found, Nothing deleted!',
'maint_send_test_email' => 'Send a Test Email',
'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.',
'maint_send_test_email_run' => 'Send test email',
'maint_send_test_email_success' => 'Email sent to :address',
'maint_send_test_email_mail_subject' => 'Test Email',
'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!',
'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.',
'maint_recycle_bin_desc' => 'Deleted shelves, books, chapters & pages are sent to the recycle bin so they can be restored or permanently deleted. Older items in the recycle bin may be automatically removed after a while depending on system configuration.',
'maint_recycle_bin_open' => 'Open Recycle Bin',
// Recycle Bin
'recycle_bin' => 'Recycle Bin',
'recycle_bin_desc' => 'Here you can restore items that have been deleted or choose to permanently remove them from the system. This list is unfiltered unlike similar activity lists in the system where permission filters are applied.',
'recycle_bin_deleted_item' => 'Deleted Item',
'recycle_bin_deleted_parent' => 'Parent',
'recycle_bin_deleted_by' => 'Deleted By',
'recycle_bin_deleted_at' => 'Deletion Time',
'recycle_bin_permanently_delete' => 'Permanently Delete',
'recycle_bin_restore' => 'Restore',
'recycle_bin_contents_empty' => 'The recycle bin is currently empty',
'recycle_bin_empty' => 'Empty Recycle Bin',
'recycle_bin_empty_confirm' => 'This will permanently destroy all items in the recycle bin including content contained within each item. Are you sure you want to empty the recycle bin?',
'recycle_bin_destroy_confirm' => 'This action will permanently delete this item, along with any child elements listed below, from the system and you will not be able to restore this content. Are you sure you want to permanently delete this item?',
'recycle_bin_destroy_list' => 'Items to be Destroyed',
'recycle_bin_restore_list' => 'Items to be Restored',
'recycle_bin_restore_confirm' => 'This action will restore the deleted item, including any child elements, to their original location. If the original location has since been deleted, and is now in the recycle bin, the parent item will also need to be restored.',
'recycle_bin_restore_deleted_parent' => 'The parent of this item has also been deleted. These will remain deleted until that parent is also restored.',
'recycle_bin_restore_parent' => 'Restore Parent',
'recycle_bin_destroy_notification' => 'Deleted :count total items from the recycle bin.',
'recycle_bin_restore_notification' => 'Restored :count total items from the recycle bin.',
// Audit Log
'audit' => 'Audit Log',
'audit_desc' => 'This audit log displays a list of activities tracked in the system. This list is unfiltered unlike similar activity lists in the system where permission filters are applied.',
'audit_event_filter' => 'Event Filter',
'audit_event_filter_no_filter' => 'No Filter',
'audit_deleted_item' => 'Deleted Item',
'audit_deleted_item_name' => 'Name: :name',
'audit_table_user' => 'User',
'audit_table_event' => 'Event',
'audit_table_related' => 'Related Item or Detail',
'audit_table_ip' => 'IP Address',
'audit_table_date' => 'Activity Date',
'audit_date_from' => 'Date Range From',
'audit_date_to' => 'Date Range To',
// Role Settings
'roles' => 'Roles',
'role_user_roles' => 'User Roles',
'role_create' => 'Create New Role',
'role_create_success' => 'Role successfully created',
'role_delete' => 'Delete Role',
'role_delete_confirm' => 'This will delete the role with the name \':roleName\'.',
'role_delete_users_assigned' => 'This role has :userCount users assigned to it. If you would like to migrate the users from this role select a new role below.',
'role_delete_no_migration' => "Don't migrate users",
'role_delete_sure' => 'Are you sure you want to delete this role?',
'role_delete_success' => 'Role successfully deleted',
'role_edit' => 'Edit Role',
'role_details' => 'Role Details',
'role_name' => 'Role Name',
'role_desc' => 'Short Description of Role',
'role_mfa_enforced' => 'Requires Multi-Factor Authentication',
'role_external_auth_id' => 'External Authentication IDs',
'role_system' => 'System Permissions',
'role_manage_users' => 'Manage users',
'role_manage_roles' => 'Manage roles & role permissions',
'role_manage_entity_permissions' => 'Manage all book, chapter & page permissions',
'role_manage_own_entity_permissions' => 'Manage permissions on own book, chapter & pages',
'role_manage_page_templates' => 'Manage page templates',
'role_access_api' => 'Access system API',
'role_manage_settings' => 'Manage app settings',
'role_export_content' => 'Export content',
'role_editor_change' => 'Change page editor',
'role_asset' => 'Asset Permissions',
'roles_system_warning' => 'Be aware that access to any of the above three permissions can allow a user to alter their own privileges or the privileges of others in the system. Only assign roles with these permissions to trusted users.',
'role_asset_desc' => 'These permissions control default access to the assets within the system. Permissions on Books, Chapters and Pages will override these permissions.',
'role_asset_admins' => 'Admins are automatically given access to all content but these options may show or hide UI options.',
'role_all' => 'All',
'role_own' => 'Own',
'role_controlled_by_asset' => 'Controlled by the asset they are uploaded to',
'role_save' => 'Save Role',
'role_update_success' => 'Role successfully updated',
'role_users' => 'Users in this role',
'role_users_none' => 'No users are currently assigned to this role',
// Users
'users' => 'Users',
'user_profile' => 'User Profile',
'users_add_new' => 'Add New User',
'users_search' => 'Search Users',
'users_latest_activity' => 'Latest Activity',
'users_details' => 'User Details',
'users_details_desc' => 'Set a display name and an email address for this user. The email address will be used for logging into the application.',
'users_details_desc_no_email' => 'Set a display name for this user so others can recognise them.',
'users_role' => 'User Roles',
'users_role_desc' => 'Select which roles this user will be assigned to. If a user is assigned to multiple roles the permissions from those roles will stack and they will receive all abilities of the assigned roles.',
'users_password' => 'User Password',
'users_password_desc' => 'Set a password used to log-in to the application. This must be at least 8 characters long.',
'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.',
'users_send_invite_option' => 'Send user invite email',
'users_external_auth_id' => 'External Authentication ID',
'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.',
'users_password_warning' => 'Only fill the below if you would like to change your password.',
'users_system_public' => 'This user represents any guest users that visit your instance. It cannot be used to log in but is assigned automatically.',
'users_delete' => 'Delete User',
'users_delete_named' => 'Delete user :userName',
'users_delete_warning' => 'This will fully delete this user with the name \':userName\' from the system.',
'users_delete_confirm' => 'Are you sure you want to delete this user?',
'users_migrate_ownership' => 'Migrate Ownership',
'users_migrate_ownership_desc' => 'Select a user here if you want another user to become the owner of all items currently owned by this user.',
'users_none_selected' => 'No user selected',
'users_edit' => 'Edit User',
'users_edit_profile' => 'Edit Profile',
'users_avatar' => 'User Avatar',
'users_avatar_desc' => 'Select an image to represent this user. This should be approx 256px square.',
'users_preferred_language' => 'Preferred Language',
'users_preferred_language_desc' => 'This option will change the language used for the user-interface of the application. This will not affect any user-created content.',
'users_social_accounts' => 'Social Accounts',
'users_social_accounts_info' => 'Here you can connect your other accounts for quicker and easier login. Disconnecting an account here does not revoke previously authorized access. Revoke access from your profile settings on the connected social account.',
'users_social_connect' => 'Connect Account',
'users_social_disconnect' => 'Disconnect Account',
'users_social_connected' => ':socialAccount account was successfully attached to your profile.',
'users_social_disconnected' => ':socialAccount account was successfully disconnected from your profile.',
'users_api_tokens' => 'API Tokens',
'users_api_tokens_none' => 'No API tokens have been created for this user',
'users_api_tokens_create' => 'Create Token',
'users_api_tokens_expires' => 'Expires',
'users_api_tokens_docs' => 'API Documentation',
'users_mfa' => 'Multi-Factor Authentication',
'users_mfa_desc' => 'Setup multi-factor authentication as an extra layer of security for your user account.',
'users_mfa_x_methods' => ':count method configured|:count methods configured',
'users_mfa_configure' => 'Configure Methods',
// API Tokens
'user_api_token_create' => 'Create API Token',
'user_api_token_name' => 'Name',
'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.',
'user_api_token_expiry' => 'Expiry Date',
'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.',
'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.',
'user_api_token_create_success' => 'API token successfully created',
'user_api_token_update_success' => 'API token successfully updated',
'user_api_token' => 'API Token',
'user_api_token_id' => 'Token ID',
'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.',
'user_api_token_secret' => 'Token Secret',
'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.',
'user_api_token_created' => 'Token created :timeAgo',
'user_api_token_updated' => 'Token updated :timeAgo',
'user_api_token_delete' => 'Delete Token',
'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.',
'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?',
'user_api_token_delete_success' => 'API token successfully deleted',
// Webhooks
'webhooks' => 'Webhooks',
'webhooks_create' => 'Create New Webhook',
'webhooks_none_created' => 'No webhooks have yet been created.',
'webhooks_edit' => 'Edit Webhook',
'webhooks_save' => 'Save Webhook',
'webhooks_details' => 'Webhook Details',
'webhooks_details_desc' => 'Provide a user friendly name and a POST endpoint as a location for the webhook data to be sent to.',
'webhooks_events' => 'Webhook Events',
'webhooks_events_desc' => 'Select all the events that should trigger this webhook to be called.',
'webhooks_events_warning' => 'Keep in mind that these events will be triggered for all selected events, even if custom permissions are applied. Ensure that use of this webhook won\'t expose confidential content.',
'webhooks_events_all' => 'All system events',
'webhooks_name' => 'Webhook Name',
'webhooks_timeout' => 'Webhook Request Timeout (Seconds)',
'webhooks_endpoint' => 'Webhook Endpoint',
'webhooks_active' => 'Webhook Active',
'webhook_events_table_header' => 'Events',
'webhooks_delete' => 'Delete Webhook',
'webhooks_delete_warning' => 'This will fully delete this webhook, with the name \':webhookName\', from the system.',
'webhooks_delete_confirm' => 'Are you sure you want to delete this webhook?',
'webhooks_format_example' => 'Webhook Format Example',
'webhooks_format_example_desc' => 'Webhook data is sent as a POST request to the configured endpoint as JSON following the format below. The "related_item" and "url" properties are optional and will depend on the type of event triggered.',
'webhooks_status' => 'Webhook Status',
'webhooks_last_called' => 'Last Called:',
'webhooks_last_errored' => 'Last Errored:',
'webhooks_last_error_message' => 'Last Error Message:',
//! If editing translations files directly please ignore this in all
//! languages apart from en. Content will be auto-copied from en.
//!////////////////////////////////
'language_select' => [
'en' => 'English',
'ar' => 'العربية',
'bg' => 'Bǎlgarski',
'bs' => 'Bosanski',
'ca' => 'Català',
'cs' => 'Česky',
'da' => 'Dansk',
'de' => 'Deutsch (Sie)',
'de_informal' => 'Deutsch (Du)',
'es' => 'Español',
'es_AR' => 'Español Argentina',
'et' => 'Eesti keel',
'eu' => 'Euskara',
'fa' => 'فارسی',
'fr' => 'Français',
'he' => 'עברית',
'hr' => 'Hrvatski',
'hu' => 'Magyar',
'id' => 'Bahasa Indonesia',
'it' => 'Italian',
'ja' => '日本語',
'ko' => '한국어',
'lt' => 'Lietuvių Kalba',
'lv' => 'Latviešu Valoda',
'nl' => 'Nederlands',
'nb' => 'Norsk (Bokmål)',
'pl' => 'Polski',
'pt' => 'Português',
'pt_BR' => 'Português do Brasil',
'ru' => 'Русский',
'sk' => 'Slovensky',
'sl' => 'Slovenščina',
'sv' => 'Svenska',
'tr' => 'Türkçe',
'uk' => 'Українська',
'vi' => 'Tiếng Việt',
'zh_CN' => '简体中文',
'zh_TW' => '繁體中文',
],
//!////////////////////////////////
];

View File

@ -0,0 +1,117 @@
<?php
/**
* Validation Lines
* The following language lines contain the default error messages used by
* the validator class. Some of these rules have multiple versions such
* as the size rules. Feel free to tweak each of these messages here.
*/
return [
// Standard laravel validation lines
'accepted' => 'Rhaid derbyn y :attribute.',
'active_url' => 'Nid ywr :attribute yn URL dilys.',
'after' => 'Rhaid i\'r :attribute bod yn dyddiad ar ol :date.',
'alpha' => 'Rhaid ir :attribute cynnwys llythrennau yn unig.',
'alpha_dash' => 'Dim ond llythrennau, rhifau, llinellau toriad a thanlinellau y gall y :attribute gynnwys.',
'alpha_num' => 'Rhaid ir :attribute cynnwys llythrennau a rhifau yn unig.',
'array' => 'Rhaid i :attribute fod yn array.',
'backup_codes' => 'Nid yw\'r cod a ddarparwyd yn ddilys neu mae eisoes wedi\'i ddefnyddio.',
'before' => 'Rhaid i\'r :attribute bod yn dyddiad cyn :date.',
'between' => [
'numeric' => 'Rhaid i\'r :attribute bod rhwng :min a :max.',
'file' => 'Rhaid i\'r :attribute bod rhwng :min a :max kilobytes.',
'string' => 'Rhaid i\'r :attribute bod rhwng :min a :max cymeriadau.',
'array' => 'Rhaid i\'r :attribute cael rhwng :min a :max o eitemau.',
],
'boolean' => 'Rhaid i :attribute fod yn wir neu ddim.',
'confirmed' => 'Dydi\'r cadarnhad :attribute ddim yn cydfynd.',
'date' => 'Nid yw\'r :attribute yn dyddiad dilys.',
'date_format' => 'Nid yw\'r :attribute yn cydfynd ar format :format.',
'different' => 'Rhaid i :attribute a :other bod yn wahanol.',
'digits' => 'Rhai i\'r :attribute bod yn :digits o ddigidau.',
'digits_between' => 'Rhaid i\'r :attribute bod rhwng :min a :max o digidau.',
'email' => 'Rhaid i\'r :attribute bod yn cyfeiriad e-bost dilys.',
'ends_with' => 'Rhaid i\'r :attribute orffen gydag un o\'r canlynol: :values',
'file' => 'Rhaid darparu\'r :attribute fel ffeil ddilys.',
'filled' => 'Mae angen llenwi\'r maes :attribute.',
'gt' => [
'numeric' => 'Rhaid i\'r :attribute fod yn fwy na :value.',
'file' => 'Rhaid i\'r :attribute fod yn fwy na :value kilobytes.',
'string' => 'Rhaid i\'r :attribute fod yn fwy na :value cymeriadau.',
'array' => 'Rhaid i\'r :attribute fod yn fwy na :value eitemau.',
],
'gte' => [
'numeric' => 'The :attribute must be greater than or equal :value.',
'file' => 'The :attribute must be greater than or equal :value kilobytes.',
'string' => 'The :attribute must be greater than or equal :value characters.',
'array' => 'The :attribute must have :value items or more.',
],
'exists' => 'The selected :attribute is invalid.',
'image' => 'The :attribute must be an image.',
'image_extension' => 'The :attribute must have a valid & supported image extension.',
'in' => 'The selected :attribute is invalid.',
'integer' => 'The :attribute must be an integer.',
'ip' => 'The :attribute must be a valid IP address.',
'ipv4' => 'The :attribute must be a valid IPv4 address.',
'ipv6' => 'The :attribute must be a valid IPv6 address.',
'json' => 'The :attribute must be a valid JSON string.',
'lt' => [
'numeric' => 'The :attribute must be less than :value.',
'file' => 'The :attribute must be less than :value kilobytes.',
'string' => 'The :attribute must be less than :value characters.',
'array' => 'The :attribute must have less than :value items.',
],
'lte' => [
'numeric' => 'The :attribute must be less than or equal :value.',
'file' => 'The :attribute must be less than or equal :value kilobytes.',
'string' => 'The :attribute must be less than or equal :value characters.',
'array' => 'The :attribute must not have more than :value items.',
],
'max' => [
'numeric' => 'The :attribute may not be greater than :max.',
'file' => 'The :attribute may not be greater than :max kilobytes.',
'string' => 'The :attribute may not be greater than :max characters.',
'array' => 'The :attribute may not have more than :max items.',
],
'mimes' => 'The :attribute must be a file of type: :values.',
'min' => [
'numeric' => 'The :attribute must be at least :min.',
'file' => 'The :attribute must be at least :min kilobytes.',
'string' => 'The :attribute must be at least :min characters.',
'array' => 'The :attribute must have at least :min items.',
],
'not_in' => 'The selected :attribute is invalid.',
'not_regex' => 'The :attribute format is invalid.',
'numeric' => 'The :attribute must be a number.',
'regex' => 'The :attribute format is invalid.',
'required' => 'The :attribute field is required.',
'required_if' => 'The :attribute field is required when :other is :value.',
'required_with' => 'The :attribute field is required when :values is present.',
'required_with_all' => 'The :attribute field is required when :values is present.',
'required_without' => 'The :attribute field is required when :values is not present.',
'required_without_all' => 'The :attribute field is required when none of :values are present.',
'same' => 'The :attribute and :other must match.',
'safe_url' => 'The provided link may not be safe.',
'size' => [
'numeric' => 'The :attribute must be :size.',
'file' => 'The :attribute must be :size kilobytes.',
'string' => 'The :attribute must be :size characters.',
'array' => 'The :attribute must contain :size items.',
],
'string' => 'The :attribute must be a string.',
'timezone' => 'The :attribute must be a valid zone.',
'totp' => 'The provided code is not valid or has expired.',
'unique' => 'The :attribute has already been taken.',
'url' => 'The :attribute format is invalid.',
'uploaded' => 'The file could not be uploaded. The server may not accept files of this size.',
// Custom validation lines
'custom' => [
'password-confirm' => [
'required_with' => 'Password confirmation required',
],
],
// Custom validation attributes
'attributes' => [],
];

View File

@ -7,41 +7,45 @@ return [
// Pages // Pages
'page_create' => 'oprettede side', 'page_create' => 'oprettede side',
'page_create_notification' => 'Page successfully created', 'page_create_notification' => 'Siden blev oprettet',
'page_update' => 'opdaterede side', 'page_update' => 'opdaterede side',
'page_update_notification' => 'Page successfully updated', 'page_update_notification' => 'Siden blev opdateret',
'page_delete' => 'slettede side', 'page_delete' => 'slettede side',
'page_delete_notification' => 'Page successfully deleted', 'page_delete_notification' => 'Siden blev slettet',
'page_restore' => 'gendannede side', 'page_restore' => 'gendannede side',
'page_restore_notification' => 'Page successfully restored', 'page_restore_notification' => 'Siden blev gendannet',
'page_move' => 'flyttede side', 'page_move' => 'flyttede side',
// Chapters // Chapters
'chapter_create' => 'oprettede kapitel', 'chapter_create' => 'oprettede kapitel',
'chapter_create_notification' => 'Chapter successfully created', 'chapter_create_notification' => 'Kapitel blev oprettet',
'chapter_update' => 'opdaterede kapitel', 'chapter_update' => 'opdaterede kapitel',
'chapter_update_notification' => 'Chapter successfully updated', 'chapter_update_notification' => 'Kapitel blev opdateret',
'chapter_delete' => 'slettede kapitel', 'chapter_delete' => 'slettede kapitel',
'chapter_delete_notification' => 'Chapter successfully deleted', 'chapter_delete_notification' => 'Kapitel blev slettet',
'chapter_move' => 'flyttede kapitel', 'chapter_move' => 'flyttede kapitel',
// Books // Books
'book_create' => 'oprettede bog', 'book_create' => 'oprettede bog',
'book_create_notification' => 'Book successfully created', 'book_create_notification' => 'Bogen blev oprettet',
'book_create_from_chapter' => 'omdannede kapitel til bog',
'book_create_from_chapter_notification' => 'Kapitel blev omdannet til en bog',
'book_update' => 'opdaterede bog', 'book_update' => 'opdaterede bog',
'book_update_notification' => 'Book successfully updated', 'book_update_notification' => 'Bogen blev opdateret',
'book_delete' => 'slettede bog', 'book_delete' => 'slettede bog',
'book_delete_notification' => 'Book successfully deleted', 'book_delete_notification' => 'Bogen blev slettet',
'book_sort' => 'sorterede bogen', 'book_sort' => 'sorterede bogen',
'book_sort_notification' => 'Book successfully re-sorted', 'book_sort_notification' => 'Bogen blev re-sorteret',
// Bookshelves // Bookshelves
'bookshelf_create' => 'created bookshelf', 'bookshelf_create' => 'oprettede bogreol',
'bookshelf_create_notification' => 'Bookshelf successfully created', 'bookshelf_create_notification' => 'Bogreolen blev oprettet',
'bookshelf_create_from_book' => 'omdannede bog til bogreol',
'bookshelf_create_from_book_notification' => 'Bogen blev omdannet til en bogreal',
'bookshelf_update' => 'opdaterede bogreolen', 'bookshelf_update' => 'opdaterede bogreolen',
'bookshelf_update_notification' => 'Bookshelf successfully updated', 'bookshelf_update_notification' => 'Bogreolen blev opdateret',
'bookshelf_delete' => 'slettede bogreol', 'bookshelf_delete' => 'slettede bogreol',
'bookshelf_delete_notification' => 'Bookshelf successfully deleted', 'bookshelf_delete_notification' => 'Bogreolen blev slettet',
// Favourites // Favourites
'favourite_add_notification' => '":name" er blevet tilføjet til dine favoritter', 'favourite_add_notification' => '":name" er blevet tilføjet til dine favoritter',
@ -52,16 +56,16 @@ return [
'mfa_remove_method_notification' => 'Multi-faktor metode fjernet', 'mfa_remove_method_notification' => 'Multi-faktor metode fjernet',
// Webhooks // Webhooks
'webhook_create' => 'created webhook', 'webhook_create' => 'oprettede webhook',
'webhook_create_notification' => 'Webhook successfully created', 'webhook_create_notification' => 'Webhooken blev oprettet',
'webhook_update' => 'updated webhook', 'webhook_update' => 'opdaterede webhooken',
'webhook_update_notification' => 'Webhook successfully updated', 'webhook_update_notification' => 'Webhooken blev opdateret',
'webhook_delete' => 'deleted webhook', 'webhook_delete' => 'slettede webhooken',
'webhook_delete_notification' => 'Webhook successfully deleted', 'webhook_delete_notification' => 'Webhooken blev slettet',
// Users // Users
'user_update_notification' => 'User successfully updated', 'user_update_notification' => 'Brugeren blev opdateret',
'user_delete_notification' => 'User successfully removed', 'user_delete_notification' => 'Brugeren blev fjernet',
// Other // Other
'commented_on' => 'kommenterede til', 'commented_on' => 'kommenterede til',

View File

@ -21,7 +21,7 @@ return [
'email' => 'E-mail', 'email' => 'E-mail',
'password' => 'Adgangskode', 'password' => 'Adgangskode',
'password_confirm' => 'Bekræft adgangskode', 'password_confirm' => 'Bekræft adgangskode',
'password_hint' => 'Must be at least 8 characters', 'password_hint' => 'Skal være på mindst 8 karakterer',
'forgot_password' => 'Glemt Adgangskode?', 'forgot_password' => 'Glemt Adgangskode?',
'remember_me' => 'Husk mig', 'remember_me' => 'Husk mig',
'ldap_email_hint' => 'Angiv venligst din kontos e-mail.', 'ldap_email_hint' => 'Angiv venligst din kontos e-mail.',
@ -38,6 +38,11 @@ return [
'registration_email_domain_invalid' => 'E-Mail domænet har ikke adgang til denne applikation', 'registration_email_domain_invalid' => 'E-Mail domænet har ikke adgang til denne applikation',
'register_success' => 'Tak for din registrering. Du er nu registeret og logget ind.', 'register_success' => 'Tak for din registrering. Du er nu registeret og logget ind.',
// Login auto-initiation
'auto_init_starting' => 'Attempting Login',
'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.',
'auto_init_start_link' => 'Proceed with authentication',
// Password Reset // Password Reset
'reset_password' => 'Nulstil adgangskode', 'reset_password' => 'Nulstil adgangskode',
'reset_password_send_instructions' => 'Indtast din E-Mail herunder og du vil blive sendt en E-Mail med et link til at nulstille din adgangskode.', 'reset_password_send_instructions' => 'Indtast din E-Mail herunder og du vil blive sendt en E-Mail med et link til at nulstille din adgangskode.',
@ -54,7 +59,7 @@ return [
'email_confirm_text' => 'Bekræft venligst din E-Mail adresse ved at klikke på linket nedenfor:', 'email_confirm_text' => 'Bekræft venligst din E-Mail adresse ved at klikke på linket nedenfor:',
'email_confirm_action' => 'Bekræft E-Mail', 'email_confirm_action' => 'Bekræft E-Mail',
'email_confirm_send_error' => 'E-Mail-bekræftelse kræves, men systemet kunne ikke sende E-Mailen. Kontakt administratoren for at sikre, at E-Mail er konfigureret korrekt.', 'email_confirm_send_error' => 'E-Mail-bekræftelse kræves, men systemet kunne ikke sende E-Mailen. Kontakt administratoren for at sikre, at E-Mail er konfigureret korrekt.',
'email_confirm_success' => 'Your email has been confirmed! You should now be able to login using this email address.', 'email_confirm_success' => 'Din email er blevet bekræftet! Du bør nu kune logge ind med denne emailadresse.',
'email_confirm_resent' => 'Bekræftelsesmail sendt, tjek venligst din indboks.', 'email_confirm_resent' => 'Bekræftelsesmail sendt, tjek venligst din indboks.',
'email_not_confirmed' => 'E-Mail adresse ikke bekræftet', 'email_not_confirmed' => 'E-Mail adresse ikke bekræftet',
@ -71,7 +76,7 @@ return [
'user_invite_page_welcome' => 'Velkommen til :appName!', 'user_invite_page_welcome' => 'Velkommen til :appName!',
'user_invite_page_text' => 'For at færdiggøre din konto og få adgang skal du indstille en adgangskode, der bruges til at logge ind på :appName ved fremtidige besøg.', 'user_invite_page_text' => 'For at færdiggøre din konto og få adgang skal du indstille en adgangskode, der bruges til at logge ind på :appName ved fremtidige besøg.',
'user_invite_page_confirm_button' => 'Bekræft adgangskode', 'user_invite_page_confirm_button' => 'Bekræft adgangskode',
'user_invite_success_login' => 'Password set, you should now be able to login using your set password to access :appName!', 'user_invite_success_login' => 'Adgangskoden er sat. Du burde nu kunne logge ind med din angivede adgangskode for at tilgå :appName!',
// Multi-factor Authentication // Multi-factor Authentication
'mfa_setup' => 'Opsætning af Multi-faktor godkendelse', 'mfa_setup' => 'Opsætning af Multi-faktor godkendelse',
@ -88,23 +93,23 @@ return [
'mfa_gen_confirm_and_enable' => 'Bekræft og aktivér', 'mfa_gen_confirm_and_enable' => 'Bekræft og aktivér',
'mfa_gen_backup_codes_title' => 'Backup koder opsætning', 'mfa_gen_backup_codes_title' => 'Backup koder opsætning',
'mfa_gen_backup_codes_desc' => 'Store the below list of codes in a safe place. When accessing the system you\'ll be able to use one of the codes as a second authentication mechanism.', 'mfa_gen_backup_codes_desc' => 'Store the below list of codes in a safe place. When accessing the system you\'ll be able to use one of the codes as a second authentication mechanism.',
'mfa_gen_backup_codes_download' => 'Download Codes', 'mfa_gen_backup_codes_download' => 'Download koder',
'mfa_gen_backup_codes_usage_warning' => 'Each code can only be used once', 'mfa_gen_backup_codes_usage_warning' => 'Hver kode kan kun bruges en gang',
'mfa_gen_totp_title' => 'Mobile App Setup', 'mfa_gen_totp_title' => 'Mobil App Setup',
'mfa_gen_totp_desc' => 'To use multi-factor authentication you\'ll need a mobile application that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator.', 'mfa_gen_totp_desc' => 'To use multi-factor authentication you\'ll need a mobile application that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator.',
'mfa_gen_totp_scan' => 'Scan the QR code below using your preferred authentication app to get started.', 'mfa_gen_totp_scan' => 'Scan the QR code below using your preferred authentication app to get started.',
'mfa_gen_totp_verify_setup' => 'Verify Setup', 'mfa_gen_totp_verify_setup' => 'Verificer Opsætning',
'mfa_gen_totp_verify_setup_desc' => 'Verify that all is working by entering a code, generated within your authentication app, in the input box below:', 'mfa_gen_totp_verify_setup_desc' => 'Verify that all is working by entering a code, generated within your authentication app, in the input box below:',
'mfa_gen_totp_provide_code_here' => 'Provide your app generated code here', 'mfa_gen_totp_provide_code_here' => 'Provide your app generated code here',
'mfa_verify_access' => 'Verify Access', 'mfa_verify_access' => 'Verify Access',
'mfa_verify_access_desc' => 'Your user account requires you to confirm your identity via an additional level of verification before you\'re granted access. Verify using one of your configured methods to continue.', 'mfa_verify_access_desc' => 'Your user account requires you to confirm your identity via an additional level of verification before you\'re granted access. Verify using one of your configured methods to continue.',
'mfa_verify_no_methods' => 'No Methods Configured', 'mfa_verify_no_methods' => 'Ingen Metoder Konfigureret',
'mfa_verify_no_methods_desc' => 'No multi-factor authentication methods could be found for your account. You\'ll need to set up at least one method before you gain access.', 'mfa_verify_no_methods_desc' => 'No multi-factor authentication methods could be found for your account. You\'ll need to set up at least one method before you gain access.',
'mfa_verify_use_totp' => 'Verify using a mobile app', 'mfa_verify_use_totp' => 'Bekræft ved brug af en mobil app',
'mfa_verify_use_backup_codes' => 'Verify using a backup code', 'mfa_verify_use_backup_codes' => 'Bekræft ved hjælp af en backup kode',
'mfa_verify_backup_code' => 'Backup Code', 'mfa_verify_backup_code' => 'Backup Kode',
'mfa_verify_backup_code_desc' => 'Enter one of your remaining backup codes below:', 'mfa_verify_backup_code_desc' => 'Indtast en af dine resterende backup koder nedenfor:',
'mfa_verify_backup_code_enter_here' => 'Enter backup code here', 'mfa_verify_backup_code_enter_here' => 'Indtast backup kode her',
'mfa_verify_totp_desc' => 'Enter the code, generated using your mobile app, below:', 'mfa_verify_totp_desc' => 'Enter the code, generated using your mobile app, below:',
'mfa_setup_login_notification' => 'Multi-factor method configured, Please now login again using the configured method.', 'mfa_setup_login_notification' => 'Multi-factor method configured, Please now login again using the configured method.',
]; ];

View File

@ -45,8 +45,10 @@ return [
'unfavourite' => 'Fjern som foretrukken', 'unfavourite' => 'Fjern som foretrukken',
'next' => 'Næste', 'next' => 'Næste',
'previous' => 'Forrige', 'previous' => 'Forrige',
'filter_active' => 'Active Filter:', 'filter_active' => 'Aktivt Filter:',
'filter_clear' => 'Clear Filter', 'filter_clear' => 'Nulstil Filter',
'download' => 'Hent',
'open_in_tab' => 'Åben i ny fane',
// Sort Options // Sort Options
'sort_options' => 'Sorteringsindstillinger', 'sort_options' => 'Sorteringsindstillinger',
@ -72,10 +74,10 @@ return [
'default' => 'Standard', 'default' => 'Standard',
'breadcrumb' => 'Brødkrumme', 'breadcrumb' => 'Brødkrumme',
'status' => 'Status', 'status' => 'Status',
'status_active' => 'Active', 'status_active' => 'Aktiv',
'status_inactive' => 'Inactive', 'status_inactive' => 'Inaktiv',
'never' => 'Never', 'never' => 'Aldrig',
'none' => 'None', 'none' => 'Ingen',
// Header // Header
'header_menu_expand' => 'Udvid header menu', 'header_menu_expand' => 'Udvid header menu',

View File

@ -7,145 +7,145 @@
*/ */
return [ return [
// General editor terms // General editor terms
'general' => 'General', 'general' => 'Generel',
'advanced' => 'Advanced', 'advanced' => 'Avanceret',
'none' => 'None', 'none' => 'Ingen',
'cancel' => 'Cancel', 'cancel' => 'Annuller',
'save' => 'Save', 'save' => 'Gem',
'close' => 'Close', 'close' => 'Luk',
'undo' => 'Undo', 'undo' => 'Fortryd',
'redo' => 'Redo', 'redo' => 'Redo',
'left' => 'Left', 'left' => 'Venstre',
'center' => 'Center', 'center' => 'Midten',
'right' => 'Right', 'right' => 'Højre',
'top' => 'Top', 'top' => 'Top',
'middle' => 'Middle', 'middle' => 'Midt',
'bottom' => 'Bottom', 'bottom' => 'Bund',
'width' => 'Width', 'width' => 'Bredde',
'height' => 'Height', 'height' => 'Højde',
'More' => 'More', 'More' => 'Mere',
'select' => 'Select...', 'select' => 'Vælg...',
// Toolbar // Toolbar
'formats' => 'Formats', 'formats' => 'Formater',
'header_large' => 'Large Header', 'header_large' => 'Stor Overskrift',
'header_medium' => 'Medium Header', 'header_medium' => 'Mellemstor Overskrift',
'header_small' => 'Small Header', 'header_small' => 'Lille Overskrift',
'header_tiny' => 'Tiny Header', 'header_tiny' => 'Tiny Header',
'paragraph' => 'Paragraph', 'paragraph' => 'Paragraf',
'blockquote' => 'Blockquote', 'blockquote' => 'Citat',
'inline_code' => 'Inline code', 'inline_code' => 'Inline kode',
'callouts' => 'Callouts', 'callouts' => 'Callouts',
'callout_information' => 'Information', 'callout_information' => 'Information',
'callout_success' => 'Success', 'callout_success' => 'Succes',
'callout_warning' => 'Warning', 'callout_warning' => 'Advarsel',
'callout_danger' => 'Danger', 'callout_danger' => 'Fare',
'bold' => 'Bold', 'bold' => 'Fed',
'italic' => 'Italic', 'italic' => 'Kursiv',
'underline' => 'Underline', 'underline' => 'Understreget',
'strikethrough' => 'Strikethrough', 'strikethrough' => 'Gennemstreget',
'superscript' => 'Superscript', 'superscript' => 'Hævet',
'subscript' => 'Subscript', 'subscript' => 'Sænket',
'text_color' => 'Text color', 'text_color' => 'Tekstfarve',
'custom_color' => 'Custom color', 'custom_color' => 'Tilpasset farve',
'remove_color' => 'Remove color', 'remove_color' => 'Fjern farve',
'background_color' => 'Background color', 'background_color' => 'Baggrundsfarve',
'align_left' => 'Align left', 'align_left' => 'Venstrejusteret',
'align_center' => 'Align center', 'align_center' => 'Centrér',
'align_right' => 'Align right', 'align_right' => 'Højrejusteret',
'align_justify' => 'Justify', 'align_justify' => 'Juster',
'list_bullet' => 'Bullet list', 'list_bullet' => 'Punktliste',
'list_numbered' => 'Numbered list', 'list_numbered' => 'Nummereret liste',
'list_task' => 'Task list', 'list_task' => 'Opgaveliste',
'indent_increase' => 'Increase indent', 'indent_increase' => 'Forøg indrykning',
'indent_decrease' => 'Decrease indent', 'indent_decrease' => 'Formindsk indrykning',
'table' => 'Table', 'table' => 'Tabel',
'insert_image' => 'Insert image', 'insert_image' => 'Insert image',
'insert_image_title' => 'Insert/Edit Image', 'insert_image_title' => 'Insert/Edit Image',
'insert_link' => 'Insert/edit link', 'insert_link' => 'Indsæt/rediger link',
'insert_link_title' => 'Insert/Edit Link', 'insert_link_title' => 'Indsæt/Rediger Link',
'insert_horizontal_line' => 'Insert horizontal line', 'insert_horizontal_line' => 'Indsæt vandret linje',
'insert_code_block' => 'Insert code block', 'insert_code_block' => 'Indsæt kodeblok',
'insert_drawing' => 'Insert/edit drawing', 'insert_drawing' => 'Indsæt/rediger tegning',
'drawing_manager' => 'Drawing manager', 'drawing_manager' => 'Drawing manager',
'insert_media' => 'Insert/edit media', 'insert_media' => 'Indsæt/rediger medie',
'insert_media_title' => 'Insert/Edit Media', 'insert_media_title' => 'Indsæt/Rediger Medie',
'clear_formatting' => 'Clear formatting', 'clear_formatting' => 'Ryd formatering',
'source_code' => 'Source code', 'source_code' => 'Kildekode',
'source_code_title' => 'Source Code', 'source_code_title' => 'Kildekode',
'fullscreen' => 'Fullscreen', 'fullscreen' => 'Fuld skærm',
'image_options' => 'Image options', 'image_options' => 'Image options',
// Tables // Tables
'table_properties' => 'Table properties', 'table_properties' => 'Tabelegenskaber',
'table_properties_title' => 'Table Properties', 'table_properties_title' => 'Tabelegenskaber',
'delete_table' => 'Delete table', 'delete_table' => 'Slet tabel',
'insert_row_before' => 'Insert row before', 'insert_row_before' => 'Indsæt række før',
'insert_row_after' => 'Insert row after', 'insert_row_after' => 'Indsæt række efter',
'delete_row' => 'Delete row', 'delete_row' => 'Slet række',
'insert_column_before' => 'Insert column before', 'insert_column_before' => 'Indsæt kolonne før',
'insert_column_after' => 'Insert column after', 'insert_column_after' => 'Indsæt kolonne efter',
'delete_column' => 'Delete column', 'delete_column' => 'Slet kolonne',
'table_cell' => 'Cell', 'table_cell' => 'Celle',
'table_row' => 'Row', 'table_row' => 'Række',
'table_column' => 'Column', 'table_column' => 'Kolonne',
'cell_properties' => 'Cell properties', 'cell_properties' => 'Celle egenskaber',
'cell_properties_title' => 'Cell Properties', 'cell_properties_title' => 'Celle Egenskaber',
'cell_type' => 'Cell type', 'cell_type' => 'Celle type',
'cell_type_cell' => 'Cell', 'cell_type_cell' => 'Celle',
'cell_scope' => 'Scope', 'cell_scope' => 'Scope',
'cell_type_header' => 'Header cell', 'cell_type_header' => 'Header cell',
'merge_cells' => 'Merge cells', 'merge_cells' => 'Flet celler',
'split_cell' => 'Split cell', 'split_cell' => 'Opdel celle',
'table_row_group' => 'Row Group', 'table_row_group' => 'Række Gruppe',
'table_column_group' => 'Column Group', 'table_column_group' => 'Kolonne Gruppe',
'horizontal_align' => 'Horizontal align', 'horizontal_align' => 'Juster vandret',
'vertical_align' => 'Vertical align', 'vertical_align' => 'Juster lodret',
'border_width' => 'Border width', 'border_width' => 'Kantbredde',
'border_style' => 'Border style', 'border_style' => 'Kantstil',
'border_color' => 'Border color', 'border_color' => 'Kantfarve',
'row_properties' => 'Row properties', 'row_properties' => 'Række egenskaber',
'row_properties_title' => 'Row Properties', 'row_properties_title' => 'Række Egenskaber',
'cut_row' => 'Cut row', 'cut_row' => 'Klip række',
'copy_row' => 'Copy row', 'copy_row' => 'Kopier række',
'paste_row_before' => 'Paste row before', 'paste_row_before' => 'Indsæt række før',
'paste_row_after' => 'Paste row after', 'paste_row_after' => 'Indsæt række efter',
'row_type' => 'Row type', 'row_type' => 'Række type',
'row_type_header' => 'Header', 'row_type_header' => 'Overskrift',
'row_type_body' => 'Body', 'row_type_body' => 'Krop',
'row_type_footer' => 'Footer', 'row_type_footer' => 'Sidefod',
'alignment' => 'Alignment', 'alignment' => 'Justering',
'cut_column' => 'Cut column', 'cut_column' => 'Klip kolonne',
'copy_column' => 'Copy column', 'copy_column' => 'Kopier kolonne',
'paste_column_before' => 'Paste column before', 'paste_column_before' => 'Indsæt kolonne før',
'paste_column_after' => 'Paste column after', 'paste_column_after' => 'Indsæt kolonne efter',
'cell_padding' => 'Cell padding', 'cell_padding' => 'Cell padding',
'cell_spacing' => 'Cell spacing', 'cell_spacing' => 'Cell spacing',
'caption' => 'Caption', 'caption' => 'Caption',
'show_caption' => 'Show caption', 'show_caption' => 'Show caption',
'constrain' => 'Constrain proportions', 'constrain' => 'Constrain proportions',
'cell_border_solid' => 'Solid', 'cell_border_solid' => 'Solid',
'cell_border_dotted' => 'Dotted', 'cell_border_dotted' => 'Prikket',
'cell_border_dashed' => 'Dashed', 'cell_border_dashed' => 'Stiplet',
'cell_border_double' => 'Double', 'cell_border_double' => 'Dobbelt',
'cell_border_groove' => 'Groove', 'cell_border_groove' => 'Groove',
'cell_border_ridge' => 'Ridge', 'cell_border_ridge' => 'Ridge',
'cell_border_inset' => 'Inset', 'cell_border_inset' => 'Inset',
'cell_border_outset' => 'Outset', 'cell_border_outset' => 'Outset',
'cell_border_none' => 'None', 'cell_border_none' => 'Ingen',
'cell_border_hidden' => 'Hidden', 'cell_border_hidden' => 'Gemt',
// Images, links, details/summary & embed // Images, links, details/summary & embed
'source' => 'Source', 'source' => 'Kilde',
'alt_desc' => 'Alternative description', 'alt_desc' => 'Alternativ beskrivelse',
'embed' => 'Embed', 'embed' => 'Embed',
'paste_embed' => 'Paste your embed code below:', 'paste_embed' => 'Paste your embed code below:',
'url' => 'URL', 'url' => 'URL',
'text_to_display' => 'Text to display', 'text_to_display' => 'Tekst til visning',
'title' => 'Title', 'title' => 'Titel',
'open_link' => 'Open link in...', 'open_link' => 'Åben link i...',
'open_link_current' => 'Current window', 'open_link_current' => 'Nuværende vindue',
'open_link_new' => 'New window', 'open_link_new' => 'Nyt vindue',
'insert_collapsible' => 'Insert collapsible block', 'insert_collapsible' => 'Insert collapsible block',
'collapsible_unwrap' => 'Unwrap', 'collapsible_unwrap' => 'Unwrap',
'edit_label' => 'Edit label', 'edit_label' => 'Edit label',
@ -159,13 +159,13 @@ return [
'editor_license' => 'Editor License & Copyright', 'editor_license' => 'Editor License & Copyright',
'editor_tiny_license' => 'This editor is built using :tinyLink which is provided under an LGPL v2.1 license.', 'editor_tiny_license' => 'This editor is built using :tinyLink which is provided under an LGPL v2.1 license.',
'editor_tiny_license_link' => 'The copyright and license details of TinyMCE can be found here.', 'editor_tiny_license_link' => 'The copyright and license details of TinyMCE can be found here.',
'save_continue' => 'Save Page & Continue', 'save_continue' => 'Gem og fortsæt',
'callouts_cycle' => '(Keep pressing to toggle through types)', 'callouts_cycle' => '(Keep pressing to toggle through types)',
'link_selector' => 'Link to content', 'link_selector' => 'Link to content',
'shortcuts' => 'Shortcuts', 'shortcuts' => 'Genveje',
'shortcut' => 'Shortcut', 'shortcut' => 'Genvej',
'shortcuts_intro' => 'The following shortcuts are available in the editor:', 'shortcuts_intro' => 'Følgende genveje er tilgængelige i editoren:',
'windows_linux' => '(Windows/Linux)', 'windows_linux' => '(Windows/Linux)',
'mac' => '(Mac)', 'mac' => '(Mac)',
'description' => 'Description', 'description' => 'Beskrivelse',
]; ];

View File

@ -143,8 +143,8 @@ return [
'books_sort_chapters_last' => 'Kapitler sidst', 'books_sort_chapters_last' => 'Kapitler sidst',
'books_sort_show_other' => 'Vis andre bøger', 'books_sort_show_other' => 'Vis andre bøger',
'books_sort_save' => 'Gem ny ordre', 'books_sort_save' => 'Gem ny ordre',
'books_copy' => 'Copy Book', 'books_copy' => 'Kopier Bog',
'books_copy_success' => 'Book successfully copied', 'books_copy_success' => 'Bogen blev kopieret',
// Chapters // Chapters
'chapter' => 'Kapitel', 'chapter' => 'Kapitel',
@ -163,8 +163,8 @@ return [
'chapters_move' => 'Flyt kapitel', 'chapters_move' => 'Flyt kapitel',
'chapters_move_named' => 'Flyt kapitel :chapterName', 'chapters_move_named' => 'Flyt kapitel :chapterName',
'chapter_move_success' => 'Kapitel flyttet til :bookName', 'chapter_move_success' => 'Kapitel flyttet til :bookName',
'chapters_copy' => 'Copy Chapter', 'chapters_copy' => 'Kopier Kapitel',
'chapters_copy_success' => 'Chapter successfully copied', 'chapters_copy_success' => 'Kapitlet blev kopieret',
'chapters_permissions' => 'Kapiteltilladelser', 'chapters_permissions' => 'Kapiteltilladelser',
'chapters_empty' => 'Der er lige nu ingen sider i dette kapitel.', 'chapters_empty' => 'Der er lige nu ingen sider i dette kapitel.',
'chapters_permissions_active' => 'Aktive kapiteltilladelser', 'chapters_permissions_active' => 'Aktive kapiteltilladelser',
@ -196,14 +196,14 @@ return [
'pages_edit_draft_save_at' => 'Kladde gemt ved ', 'pages_edit_draft_save_at' => 'Kladde gemt ved ',
'pages_edit_delete_draft' => 'Slet kladde', 'pages_edit_delete_draft' => 'Slet kladde',
'pages_edit_discard_draft' => 'Kassér kladde', 'pages_edit_discard_draft' => 'Kassér kladde',
'pages_edit_switch_to_markdown' => 'Switch to Markdown Editor', 'pages_edit_switch_to_markdown' => 'Skift til Markdown redigering',
'pages_edit_switch_to_markdown_clean' => '(Clean Content)', 'pages_edit_switch_to_markdown_clean' => '(Clean Content)',
'pages_edit_switch_to_markdown_stable' => '(Stable Content)', 'pages_edit_switch_to_markdown_stable' => '(Stable Content)',
'pages_edit_switch_to_wysiwyg' => 'Switch to WYSIWYG Editor', 'pages_edit_switch_to_wysiwyg' => 'Skift til WYSIWYG redigering',
'pages_edit_set_changelog' => 'Sæt ændringsoversigt', 'pages_edit_set_changelog' => 'Sæt ændringsoversigt',
'pages_edit_enter_changelog_desc' => 'Indtast en kort beskrivelse af ændringer du har lavet', 'pages_edit_enter_changelog_desc' => 'Indtast en kort beskrivelse af ændringer du har lavet',
'pages_edit_enter_changelog' => 'Indtast ændringsoversigt', 'pages_edit_enter_changelog' => 'Indtast ændringsoversigt',
'pages_editor_switch_title' => 'Switch Editor', 'pages_editor_switch_title' => 'Skift Editor',
'pages_editor_switch_are_you_sure' => 'Are you sure you want to change the editor for this page?', 'pages_editor_switch_are_you_sure' => 'Are you sure you want to change the editor for this page?',
'pages_editor_switch_consider_following' => 'Consider the following when changing editors:', 'pages_editor_switch_consider_following' => 'Consider the following when changing editors:',
'pages_editor_switch_consideration_a' => 'Once saved, the new editor option will be used by any future editors, including those that may not be able to change editor type themselves.', 'pages_editor_switch_consideration_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.',
@ -249,7 +249,7 @@ return [
'pages_initial_name' => 'Ny side', 'pages_initial_name' => 'Ny side',
'pages_editing_draft_notification' => 'Du redigerer en kladde der sidst var gemt :timeDiff.', 'pages_editing_draft_notification' => 'Du redigerer en kladde der sidst var gemt :timeDiff.',
'pages_draft_edited_notification' => 'Siden har været opdateret siden da. Det er anbefalet at du kasserer denne kladde.', 'pages_draft_edited_notification' => 'Siden har været opdateret siden da. Det er anbefalet at du kasserer denne kladde.',
'pages_draft_page_changed_since_creation' => 'This page has been updated since this draft was created. It is recommended that you discard this draft or take care not to overwrite any page changes.', 'pages_draft_page_changed_since_creation' => 'Denne side er blevet opdateret siden dette udkast blev oprettet. Det anbefales at du kasserer dette udkast eller passer på ikke at overskrive nogen sideændringer.',
'pages_draft_edit_active' => [ 'pages_draft_edit_active' => [
'start_a' => ':count brugerer har begyndt at redigere denne side', 'start_a' => ':count brugerer har begyndt at redigere denne side',
'start_b' => ':userName er begyndt at redigere denne side', 'start_b' => ':userName er begyndt at redigere denne side',
@ -274,14 +274,14 @@ return [
'tags_add' => 'Tilføj endnu et tag', 'tags_add' => 'Tilføj endnu et tag',
'tags_remove' => 'Fjern dette tag', 'tags_remove' => 'Fjern dette tag',
'tags_usages' => 'Total tag usages', 'tags_usages' => 'Total tag usages',
'tags_assigned_pages' => 'Assigned to Pages', 'tags_assigned_pages' => 'Tildelt til sider',
'tags_assigned_chapters' => 'Assigned to Chapters', 'tags_assigned_chapters' => 'Tildelt til Kapitler',
'tags_assigned_books' => 'Assigned to Books', 'tags_assigned_books' => 'Tildelt til Bøger',
'tags_assigned_shelves' => 'Assigned to Shelves', 'tags_assigned_shelves' => 'Tildelt til bogreoler',
'tags_x_unique_values' => ':count unique values', 'tags_x_unique_values' => ':count unikke værdier',
'tags_all_values' => 'All values', 'tags_all_values' => 'Alle værdier',
'tags_view_tags' => 'View Tags', 'tags_view_tags' => 'Vis Tags',
'tags_view_existing_tags' => 'View existing tags', 'tags_view_existing_tags' => 'Vis eksisterende tags',
'tags_list_empty_hint' => 'Tags can be assigned via the page editor sidebar or while editing the details of a book, chapter or shelf.', 'tags_list_empty_hint' => 'Tags can be assigned via the page editor sidebar or while editing the details of a book, chapter or shelf.',
'attachments' => 'Vedhæftninger', 'attachments' => 'Vedhæftninger',
'attachments_explain' => 'Upload nogle filer, eller vedhæft nogle links, der skal vises på siden. Disse er synlige i sidepanelet.', 'attachments_explain' => 'Upload nogle filer, eller vedhæft nogle links, der skal vises på siden. Disse er synlige i sidepanelet.',
@ -355,4 +355,16 @@ return [
'copy_consider_images' => 'Page image files will not be duplicated & the original images will retain their relation to the page they were originally uploaded to.', 'copy_consider_images' => 'Page image files will not be duplicated & the original images will retain their relation to the page they were originally uploaded to.',
'copy_consider_attachments' => 'Page attachments will not be copied.', 'copy_consider_attachments' => 'Page attachments will not be copied.',
'copy_consider_access' => 'A change of location, owner or permissions may result in this content being accessible to those previously without access.', 'copy_consider_access' => 'A change of location, owner or permissions may result in this content being accessible to those previously without access.',
// Conversions
'convert_to_shelf' => 'Convert to Shelf',
'convert_to_shelf_contents_desc' => 'You can convert this book to a new shelf with the same contents. Chapters contained within this book will be converted to new books. If this book contains any pages, that are not in a chapter, this book will be renamed and contain such pages, and this book will become part of the new shelf.',
'convert_to_shelf_permissions_desc' => 'Any permissions set on this book will be copied to the new shelf and to all new child books that don\'t have their own permissions enforced. Note that permissions on shelves do not auto-cascade to content within, as they do for books.',
'convert_book' => 'Omdan Bog',
'convert_book_confirm' => 'Are you sure you want to convert this book?',
'convert_undo_warning' => 'This cannot be as easily undone.',
'convert_to_book' => 'Omdan til Bog',
'convert_to_book_desc' => 'You can convert this chapter to a new book with the same contents. Any permissions set on this chapter will be copied to the new book but any inherited permissions, from the parent book, will not be copied which could lead to a change of access control.',
'convert_chapter' => 'Omdan Kapitel',
'convert_chapter_confirm' => 'Er du sikker på at du vil omdanne dette kapitel?',
]; ];

View File

@ -10,8 +10,8 @@ return [
'settings' => 'Indstillinger', 'settings' => 'Indstillinger',
'settings_save' => 'Gem indstillinger', 'settings_save' => 'Gem indstillinger',
'settings_save_success' => 'Indstillingerne blev gemt', 'settings_save_success' => 'Indstillingerne blev gemt',
'system_version' => 'System Version', 'system_version' => 'Systemversion',
'categories' => 'Categories', 'categories' => 'Kategorier',
// App Settings // App Settings
'app_customization' => 'Tilpasning', 'app_customization' => 'Tilpasning',
@ -27,8 +27,8 @@ return [
'app_secure_images' => 'Højere sikkerhed for billeduploads', 'app_secure_images' => 'Højere sikkerhed for billeduploads',
'app_secure_images_toggle' => 'Aktiver højere sikkerhed for billeduploads', 'app_secure_images_toggle' => 'Aktiver højere sikkerhed for billeduploads',
'app_secure_images_desc' => 'Af performanceårsager er alle billeder offentlige. Denne funktion tilføjer en tilfældig, vanskelig at gætte streng foran billed-url\'er. Sørg for, at mappeindeksering ikke er aktiveret for at forhindre nem adgang.', 'app_secure_images_desc' => 'Af performanceårsager er alle billeder offentlige. Denne funktion tilføjer en tilfældig, vanskelig at gætte streng foran billed-url\'er. Sørg for, at mappeindeksering ikke er aktiveret for at forhindre nem adgang.',
'app_default_editor' => 'Default Page Editor', 'app_default_editor' => 'Standard Side Editor',
'app_default_editor_desc' => 'Select which editor will be used by default when editing new pages. This can be overridden at a page level where permissions allow.', 'app_default_editor_desc' => 'Vælg hvilken editor der som standard skal bruges ved redigering af nye sider. Dette kan tilsidesættes på side niveau, hvor tilladelser tillader det.',
'app_custom_html' => 'Tilpasset HTML head indhold', 'app_custom_html' => 'Tilpasset HTML head indhold',
'app_custom_html_desc' => 'Alt indhold tilføjet her, vil blive indsat i bunden af <head> sektionen på alle sider. Dette er brugbart til overskrivning af styles og tilføjelse af analytics kode.', 'app_custom_html_desc' => 'Alt indhold tilføjet her, vil blive indsat i bunden af <head> sektionen på alle sider. Dette er brugbart til overskrivning af styles og tilføjelse af analytics kode.',
'app_custom_html_disabled_notice' => 'Brugerdefineret HTML head indhold er deaktiveret på denne indstillingsside for at, at ændringer kan rulles tilbage.', 'app_custom_html_disabled_notice' => 'Brugerdefineret HTML head indhold er deaktiveret på denne indstillingsside for at, at ændringer kan rulles tilbage.',
@ -152,7 +152,7 @@ return [
'role_access_api' => 'Tilgå system-API', 'role_access_api' => 'Tilgå system-API',
'role_manage_settings' => 'Administrer app-indstillinger', 'role_manage_settings' => 'Administrer app-indstillinger',
'role_export_content' => 'Eksporter indhold', 'role_export_content' => 'Eksporter indhold',
'role_editor_change' => 'Change page editor', 'role_editor_change' => 'Skift side editor',
'role_asset' => 'Tilladelser for medier og "assets"', 'role_asset' => 'Tilladelser for medier og "assets"',
'roles_system_warning' => 'Vær opmærksom på, at adgang til alle af de ovennævnte tre tilladelser, kan give en bruger mulighed for at ændre deres egne brugerrettigheder eller brugerrettigheder for andre i systemet. Tildel kun roller med disse tilladelser til betroede brugere.', 'roles_system_warning' => 'Vær opmærksom på, at adgang til alle af de ovennævnte tre tilladelser, kan give en bruger mulighed for at ændre deres egne brugerrettigheder eller brugerrettigheder for andre i systemet. Tildel kun roller med disse tilladelser til betroede brugere.',
'role_asset_desc' => 'Disse tilladelser kontrollerer standardadgang til medier og "assets" i systemet. Tilladelser til bøger, kapitler og sider tilsidesætter disse tilladelser.', 'role_asset_desc' => 'Disse tilladelser kontrollerer standardadgang til medier og "assets" i systemet. Tilladelser til bøger, kapitler og sider tilsidesætter disse tilladelser.',
@ -177,7 +177,7 @@ return [
'users_role' => 'Brugerroller', 'users_role' => 'Brugerroller',
'users_role_desc' => 'Vælg hvilke roller denne bruger skal tildeles. Hvis en bruger er tildelt flere roller, sammenføres tilladelserne fra disse roller, og de får alle evnerne fra de tildelte roller.', 'users_role_desc' => 'Vælg hvilke roller denne bruger skal tildeles. Hvis en bruger er tildelt flere roller, sammenføres tilladelserne fra disse roller, og de får alle evnerne fra de tildelte roller.',
'users_password' => 'Brugeradgangskode', 'users_password' => 'Brugeradgangskode',
'users_password_desc' => 'Set a password used to log-in to the application. This must be at least 8 characters long.', 'users_password_desc' => 'Sæt et kodeord, der bruges til at logge på applikationen. Dette skal være mindst 8 tegn langt.',
'users_send_invite_text' => 'Du kan vælge at sende denne bruger en invitation på E-Mail, som giver dem mulighed for at indstille deres egen adgangskode, ellers kan du indstille deres adgangskode selv.', 'users_send_invite_text' => 'Du kan vælge at sende denne bruger en invitation på E-Mail, som giver dem mulighed for at indstille deres egen adgangskode, ellers kan du indstille deres adgangskode selv.',
'users_send_invite_option' => 'Send bruger en invitationsmail', 'users_send_invite_option' => 'Send bruger en invitationsmail',
'users_external_auth_id' => 'Ekstern godkendelses ID', 'users_external_auth_id' => 'Ekstern godkendelses ID',
@ -236,30 +236,30 @@ return [
// Webhooks // Webhooks
'webhooks' => 'Webhooks', 'webhooks' => 'Webhooks',
'webhooks_create' => 'Create New Webhook', 'webhooks_create' => 'Opret ny Webhook',
'webhooks_none_created' => 'No webhooks have yet been created.', 'webhooks_none_created' => 'Ingen webhooks er blevet oprettet endnu.',
'webhooks_edit' => 'Edit Webhook', 'webhooks_edit' => 'Rediger Webhook',
'webhooks_save' => 'Save Webhook', 'webhooks_save' => 'Gem Webhook',
'webhooks_details' => 'Webhook Details', 'webhooks_details' => 'Webhook detaljer',
'webhooks_details_desc' => 'Provide a user friendly name and a POST endpoint as a location for the webhook data to be sent to.', 'webhooks_details_desc' => 'Angiv et brugervenligt navn og et POST endpoint som en lokation for webhook data at blive sendt til.',
'webhooks_events' => 'Webhook Events', 'webhooks_events' => 'Webhook Begivenheder',
'webhooks_events_desc' => 'Select all the events that should trigger this webhook to be called.', 'webhooks_events_desc' => 'Vælg alle begivenhederd er skal udløse denne webhook til at blive kaldt.',
'webhooks_events_warning' => 'Keep in mind that these events will be triggered for all selected events, even if custom permissions are applied. Ensure that use of this webhook won\'t expose confidential content.', 'webhooks_events_warning' => 'Husk, at disse begivenheder vil blive udløst for alle valgte begivenheder, selv om brugerdefinerede tilladelser bliver anvendt. Sørg for, at brugen af denne webhook ikke vil afsløre fortroligt indhold.',
'webhooks_events_all' => 'All system events', 'webhooks_events_all' => 'Alle systemhændelser',
'webhooks_name' => 'Webhook Name', 'webhooks_name' => 'Webhook Navn',
'webhooks_timeout' => 'Webhook Request Timeout (Seconds)', 'webhooks_timeout' => 'Webhook forespørgsel timeout (Sekunder)',
'webhooks_endpoint' => 'Webhook Endpoint', 'webhooks_endpoint' => 'Webhook Endpoint',
'webhooks_active' => 'Webhook Active', 'webhooks_active' => 'Webhook Aktiv',
'webhook_events_table_header' => 'Events', 'webhook_events_table_header' => 'Begivenheder',
'webhooks_delete' => 'Delete Webhook', 'webhooks_delete' => 'Slet Webhook',
'webhooks_delete_warning' => 'This will fully delete this webhook, with the name \':webhookName\', from the system.', 'webhooks_delete_warning' => 'Dette vil helt slette denne webhook med navnet \':webhookName\' fra systemet.',
'webhooks_delete_confirm' => 'Are you sure you want to delete this webhook?', 'webhooks_delete_confirm' => 'Er du sikker på at du vil slette denne webhook?',
'webhooks_format_example' => 'Webhook Format Example', 'webhooks_format_example' => 'Webhook format eksempel',
'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_format_example_desc' => 'Webhook data bliver sendt som en POST anmodning til det konfigurerede endpoint som JSON efter formatet nedenfor. Egenskaberne "related_item" og "url" er valgri og vil afhænge af den type begivenhed udløst.',
'webhooks_status' => 'Webhook Status', 'webhooks_status' => 'Webhook Status',
'webhooks_last_called' => 'Last Called:', 'webhooks_last_called' => 'Sidst Kaldt:',
'webhooks_last_errored' => 'Last Errored:', 'webhooks_last_errored' => 'Sidst Fejlet:',
'webhooks_last_error_message' => 'Last Error Message:', 'webhooks_last_error_message' => 'Sidste fejlmeddelelse:',
//! If editing translations files directly please ignore this in all //! If editing translations files directly please ignore this in all

View File

@ -32,7 +32,7 @@ return [
'digits_between' => ':attribute skal være mellem :min og :max cifre.', 'digits_between' => ':attribute skal være mellem :min og :max cifre.',
'email' => ':attribute skal være en gyldig mail-adresse.', 'email' => ':attribute skal være en gyldig mail-adresse.',
'ends_with' => ':attribute skal slutte på en af følgende værdier: :values', 'ends_with' => ':attribute skal slutte på en af følgende værdier: :values',
'file' => 'The :attribute must be provided as a valid file.', 'file' => ':attribute skal leveres som en gyldig fil.',
'filled' => ':attribute er obligatorisk.', 'filled' => ':attribute er obligatorisk.',
'gt' => [ 'gt' => [
'numeric' => ':attribute skal være større end :value.', 'numeric' => ':attribute skal være større end :value.',

View File

@ -28,6 +28,8 @@ return [
// Books // Books
'book_create' => 'hat das Buch erstellt', 'book_create' => 'hat das Buch erstellt',
'book_create_notification' => 'Das Buch wurde erfolgreich erstellt', 'book_create_notification' => 'Das Buch wurde erfolgreich erstellt',
'book_create_from_chapter' => 'converted chapter to book',
'book_create_from_chapter_notification' => 'Chapter successfully converted to a book',
'book_update' => 'hat das Buch aktualisiert', 'book_update' => 'hat das Buch aktualisiert',
'book_update_notification' => 'Das Buch wurde erfolgreich aktualisiert', 'book_update_notification' => 'Das Buch wurde erfolgreich aktualisiert',
'book_delete' => 'hat das Buch gelöscht', 'book_delete' => 'hat das Buch gelöscht',
@ -38,6 +40,8 @@ return [
// Bookshelves // Bookshelves
'bookshelf_create' => 'erstelltes Bücherregal', 'bookshelf_create' => 'erstelltes Bücherregal',
'bookshelf_create_notification' => 'Das Bücherregal wurde erfolgreich erstellt', 'bookshelf_create_notification' => 'Das Bücherregal wurde erfolgreich erstellt',
'bookshelf_create_from_book' => 'converted book to bookshelf',
'bookshelf_create_from_book_notification' => 'Book successfully converted to a shelf',
'bookshelf_update' => 'hat das Bücherregal geändert', 'bookshelf_update' => 'hat das Bücherregal geändert',
'bookshelf_update_notification' => 'Das Bücherregal wurde erfolgreich geändert', 'bookshelf_update_notification' => 'Das Bücherregal wurde erfolgreich geändert',
'bookshelf_delete' => 'hat das Bücherregal gelöscht', 'bookshelf_delete' => 'hat das Bücherregal gelöscht',

View File

@ -38,6 +38,11 @@ return [
'registration_email_domain_invalid' => 'Sie können sich mit dieser E-Mail nicht registrieren.', 'registration_email_domain_invalid' => 'Sie können sich mit dieser E-Mail nicht registrieren.',
'register_success' => 'Vielen Dank für Ihre Registrierung! Die Daten sind gespeichert und Sie sind angemeldet.', 'register_success' => 'Vielen Dank für Ihre Registrierung! Die Daten sind gespeichert und Sie sind angemeldet.',
// Login auto-initiation
'auto_init_starting' => 'Attempting Login',
'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.',
'auto_init_start_link' => 'Proceed with authentication',
// Password Reset // Password Reset
'reset_password' => 'Passwort vergessen', 'reset_password' => 'Passwort vergessen',
'reset_password_send_instructions' => 'Bitte geben Sie Ihre E-Mail-Adresse ein. Danach erhalten Sie eine E-Mail mit einem Link zum Zurücksetzen Ihres Passwortes.', 'reset_password_send_instructions' => 'Bitte geben Sie Ihre E-Mail-Adresse ein. Danach erhalten Sie eine E-Mail mit einem Link zum Zurücksetzen Ihres Passwortes.',

View File

@ -47,6 +47,8 @@ return [
'previous' => 'Vorheriges', 'previous' => 'Vorheriges',
'filter_active' => 'Gesetzte Filter:', 'filter_active' => 'Gesetzte Filter:',
'filter_clear' => 'Filter löschen', 'filter_clear' => 'Filter löschen',
'download' => 'Herunterladen',
'open_in_tab' => 'In Neuem Tab öffnen',
// Sort Options // Sort Options
'sort_options' => 'Sortieroptionen', 'sort_options' => 'Sortieroptionen',

Some files were not shown because too many files have changed in this diff Show More