Compare commits

..

55 Commits

Author SHA1 Message Date
Dan Brown
92d15d9cf2 Updated version and assets for release v25.07 2025-07-30 09:46:37 +01:00
Dan Brown
b06147fef7 Merge branch 'development' into release 2025-07-30 09:45:40 +01:00
Dan Brown
776ec7b9e7 Updated translations with latest Crowdin changes (#5696) 2025-07-30 09:36:34 +01:00
Dan Brown
8aa6bdc8ab Updated translator & dependency attribution before release v25.07 2025-07-30 09:27:17 +01:00
Dan Brown
4ab17157b1 API: Added ZIP export endpoint comments 2025-07-30 09:13:58 +01:00
Dan Brown
6d7ffab115 Deps: Updated PHP composer dependancy versions, fixed test namespaces 2025-07-27 11:24:54 +01:00
Dan Brown
c8cfec96dc Merge pull request #5731 from BookStackApp/lexical_jul25
New WYSIWYG editor changes for July 2025
2025-07-26 10:08:44 +01:00
Dan Brown
d145efb6f6 Lexical: Updated tests after link changes 2025-07-25 14:25:02 +01:00
Dan Brown
c54101c603 Lexical: Updated URL handling, added mouse handling
- Removed URL protocol allow-list to allow any as per old editor.
- Added mouse handling, so that clicks below many last hard-to-escape
  block types will add an empty new paragraph for easy escaping &
  editing.
2025-07-25 13:58:48 +01:00
Dan Brown
865e5aecc9 Lexical: Source code input changes
- Increased default source code view size.
- Updated HTML generation to output each top-level block on its own
  line.
2025-07-24 17:24:59 +01:00
Dan Brown
ae4d1d804a Lexical: Table cell bg and format setting fixes
- Updated table cell background color setting to be stable by
  specifically using the background property over the general styles.
- Updated format shorcuts to be correct header levels as per old editor
  and format menu.
- Updated format changes to properly update UI afterwards.
2025-07-24 16:51:11 +01:00
Dan Brown
5fc19b0edf Lexical: Fixed highlight format action, changed label 2025-07-24 13:48:00 +01:00
Dan Brown
0a73b70b64 Merge pull request #5725 from BookStackApp/md_plaintext
MarkDown Editor: TypeScript Conversion & Plaintext Editor
2025-07-23 15:48:10 +01:00
Dan Brown
2668aae09b TypeScript: Updated compile target, addressed issues 2025-07-23 15:41:55 +01:00
Dan Brown
3b9c0b34ae MD Editor: Fixed plaintext dark styles, updated npm packages 2025-07-23 14:59:26 +01:00
Dan Brown
53f32849a9 MD Editor: Last tests/check over plaintext use/switching 2025-07-23 14:49:41 +01:00
Dan Brown
7ca8bdc231 MD Editor: Added custom textarea undo/redo, updated positioning methods 2025-07-23 12:17:36 +01:00
Dan Brown
6621d55f3d MD Editor: Worked to improve/fix positioning code
Still pending testing. Old logic did not work when lines would wrap, so
changing things to a character/line measuring technique.
Fixed some other isues too while testing shortcuts.
2025-07-22 16:42:47 +01:00
Dan Brown
d55db06c01 MD Editor: Added plaintext/cm switching
Also aligned the construction of the inputs where possible.
2025-07-22 10:34:29 +01:00
Dan Brown
6b4b500a33 MD Editor: Added plaintext input implementation 2025-07-21 18:53:22 +01:00
Dan Brown
5ffec2c52d MD Editor: Updated actions to use input interface 2025-07-21 14:24:51 +01:00
Dan Brown
ec07793cda MD Editor: Started work on input interface
Created implementation for codemirror, yet to use it.
2025-07-21 11:49:58 +01:00
Dan Brown
61adc735c8 MD Editor: Finished conversion to Typescript 2025-07-20 15:05:19 +01:00
Dan Brown
7bbf591a7f MD Editor: Starting conversion to typescript 2025-07-20 12:33:22 +01:00
Dan Brown
61f8d18af5 Changelog: Tweaked spacing, count and element referencing
During review of #5663
2025-07-19 14:53:02 +01:00
Dan Brown
f786d25f2e Merge branch 'enhance-changelog-textarea' of github.com:shresthkapoor7/BookStack into shresthkapoor7-enhance-changelog-textarea 2025-07-19 14:39:57 +01:00
Dan Brown
e62f4426ea Merge pull request #5721 from BookStackApp/zip_export_api_endpoints
API: ZIP Import/Export
2025-07-18 16:34:10 +01:00
Dan Brown
32ba3a591f ZIP Imports: Added API examples, finished testing
Also updated some types on a couple of controllers.
2025-07-18 16:19:14 +01:00
Dan Brown
73025719a4 ZIP Imports: Added API test cases 2025-07-18 14:05:32 +01:00
Dan Brown
d55684531f API: Added zip export tests, reorganised tests
Extracted an extra method into helper for reuse.
2025-07-18 10:58:10 +01:00
Dan Brown
d15eb129b0 API: Initial review pass of zip import/export endpoints
Review of #5592
2025-07-18 09:54:49 +01:00
Dan Brown
3626a2265b Merge branch 'development' of github.com:LM-Nishant/BookStack into LM-Nishant-development 2025-07-18 09:19:32 +01:00
Dan Brown
d13abc7e1d Mail: Removed custom symfony/mailer fork
Moved to standard symfony mailer now that my patches have been
upstreamed. This changes the config to work with the symfony option,
following the same overall logic.
Also updated testing to allow test runs via mulitple custom env options.

Closes #5636
2025-07-15 15:24:31 +01:00
Dan Brown
2442829ef2 Merge branch 'development' of github.com:BookStackApp/BookStack into development 2025-07-14 14:18:51 +01:00
Dan Brown
795b28162a Readme: Added SiteSpeakAI sponsor 2025-07-14 14:18:24 +01:00
Dan Brown
31706ea06b Merge pull request #5689 from BookStackApp/permission_table_locking
Better parallel permission gen handling
2025-07-09 18:02:15 +01:00
Dan Brown
4b9e6042d5 Merge pull request #5676 from BookStackApp/lexical_comments
New WYSIWYG editor for comments & descriptions
2025-07-09 18:01:25 +01:00
Dan Brown
d279b0830b Merge pull request #5685 from BookStackApp/sidebar_rejig
Tri-layout sidebar enhancements
2025-07-09 18:00:56 +01:00
Dan Brown
181ab91b1d Merge pull request #5681 from BookStackApp/parent_tag_classes
Parent tag classes
2025-07-09 17:58:13 +01:00
Dan Brown
35a51197ce Perms: Fixed some issues made when adding transactions 2025-07-06 22:52:06 +01:00
Dan Brown
47fd578edb Perms: Added transactions around permission effecting actions 2025-07-02 22:25:59 +01:00
Dan Brown
add091305c Perms: Removed entity perm regen on general update
Should not be needed here as this is not directly used for information
which should impact permissions.
Been through uses to ensure that this is the case.
2025-07-02 12:15:25 +01:00
Dan Brown
0dcb2ec78c Layout: Converted tri-layout component to ts 2025-06-30 15:36:27 +01:00
Dan Brown
9186e77d27 Layout: Added scroll fade to the sidebars 2025-06-30 14:10:48 +01:00
Dan Brown
6045aff33a Layout: Improved sidebar sizing, and dropdown consideration
- Updated tri-layout sidebars to have less padding and to avoid cutting
  off content when in single-sidebar mode.
- Updated dropdown handling to consider the parent scroll container when
  deciding to drop upwards, to help prevent cut-off.
2025-06-30 13:19:45 +01:00
Dan Brown
dca9765d5d Customization: Added parent tag classes
For #5217
2025-06-28 22:27:28 +01:00
Dan Brown
a37d0c57dc Tests: Updated comment test to account for new editor usage 2025-06-27 10:33:28 +01:00
Dan Brown
054475135a Lexical: Added some styling and tweaks for basic editors 2025-06-27 10:19:45 +01:00
Dan Brown
02a35b6db4 Lexical: Added new WYSIWYG to chapter/book/shelf descriptions 2025-06-26 11:00:17 +01:00
Dan Brown
b80992ca59 Comments: Switched to lexical editor
Required a lot of changes to provide at least a decent attempt at proper
editor teardown control.
Also updates HtmlDescriptionFilter and testing to address issue with bad
child iteration which could lead to missed items.
Renamed editor version from comments to basic as it'll also be used for
item descriptions.
2025-06-25 14:16:01 +01:00
Dan Brown
c606970e38 Lexical: Started comment implementation
Refactors some UI and toolbar code for better abstract use across editor
versions.
2025-06-24 17:47:53 +01:00
Shresth Kapoor
3617ab1540 Enhance changelog input to textarea with character counter 2025-06-18 20:10:20 -04:00
nchoudhary@logicmines.in
64da80cbf4 added routes for zip export 2025-04-25 13:00:06 +05:30
nchoudhary@logicmines.in
5fa728f28a Develop functionality to import ZIP files. Create an API controller and define a route entry for handling the import process. Implement logic to read the list of files within the ZIP, process the directory structure, and automatically create associated pages, chapters, and books based on the ZIP file's contents. 2025-04-25 12:48:34 +05:30
nchoudhary@logicmines.in
c61ce8dee4 Implement functionality to export a book, along with its pages and chapters, as a ZIP file. 2025-04-25 12:45:09 +05:30
269 changed files with 3975 additions and 2318 deletions

View File

@@ -493,3 +493,10 @@ Angel Pandey (angel-pandey) :: Nepali
Supriya Shrestha (supriyashrestha) :: Nepali
gprabhat :: Nepali
CellCat :: Chinese Simplified
Al Desrahim (aldesrahim) :: Indonesian
ahmad abbaspour (deshneh.dar.diss) :: Persian
Erjon K. (ekr) :: Albanian
LiZerui (iamzrli) :: Chinese Traditional
Ticker (ticker.com) :: Hebrew
CrazyComputer :: Chinese Simplified
Firr (FirrV) :: Russian

View File

@@ -12,6 +12,8 @@ use Illuminate\Database\Eloquent\Relations\MorphTo;
* @property int $id
* @property string $name
* @property string $value
* @property int $entity_id
* @property string $entity_type
* @property int $order
*/
class Tag extends Model

View File

@@ -3,17 +3,15 @@
namespace BookStack\Activity\Tools;
use BookStack\Activity\Models\Tag;
use BookStack\Entities\Models\BookChild;
use BookStack\Entities\Models\Entity;
use BookStack\Entities\Models\Page;
class TagClassGenerator
{
protected array $tags;
/**
* @param Tag[] $tags
*/
public function __construct(array $tags)
{
$this->tags = $tags;
public function __construct(
protected Entity $entity
) {
}
/**
@@ -22,14 +20,23 @@ class TagClassGenerator
public function generate(): array
{
$classes = [];
$tags = $this->entity->tags->all();
foreach ($this->tags as $tag) {
$name = $this->normalizeTagClassString($tag->name);
$value = $this->normalizeTagClassString($tag->value);
$classes[] = 'tag-name-' . $name;
if ($value) {
$classes[] = 'tag-value-' . $value;
$classes[] = 'tag-pair-' . $name . '-' . $value;
foreach ($tags as $tag) {
array_push($classes, ...$this->generateClassesForTag($tag));
}
if ($this->entity instanceof BookChild && userCan('view', $this->entity->book)) {
$bookTags = $this->entity->book->tags;
foreach ($bookTags as $bookTag) {
array_push($classes, ...$this->generateClassesForTag($bookTag, 'book-'));
}
}
if ($this->entity instanceof Page && $this->entity->chapter && userCan('view', $this->entity->chapter)) {
$chapterTags = $this->entity->chapter->tags;
foreach ($chapterTags as $chapterTag) {
array_push($classes, ...$this->generateClassesForTag($chapterTag, 'chapter-'));
}
}
@@ -41,6 +48,22 @@ class TagClassGenerator
return implode(' ', $this->generate());
}
/**
* @return string[]
*/
protected function generateClassesForTag(Tag $tag, string $prefix = ''): array
{
$classes = [];
$name = $this->normalizeTagClassString($tag->name);
$value = $this->normalizeTagClassString($tag->value);
$classes[] = "{$prefix}tag-name-{$name}";
if ($value) {
$classes[] = "{$prefix}tag-value-{$value}";
$classes[] = "{$prefix}tag-pair-{$name}-{$value}";
}
return $classes;
}
protected function normalizeTagClassString(string $value): string
{
$value = str_replace(' ', '', strtolower($value));

View File

@@ -11,6 +11,7 @@
// Configured mail encryption method.
// STARTTLS should still be attempted, but tls/ssl forces TLS usage.
$mailEncryption = env('MAIL_ENCRYPTION', null);
$mailPort = intval(env('MAIL_PORT', 587));
return [
@@ -33,13 +34,13 @@ return [
'transport' => 'smtp',
'scheme' => null,
'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
'port' => env('MAIL_PORT', 587),
'port' => $mailPort,
'username' => env('MAIL_USERNAME'),
'password' => env('MAIL_PASSWORD'),
'verify_peer' => env('MAIL_VERIFY_SSL', true),
'timeout' => null,
'local_domain' => null,
'tls_required' => ($mailEncryption === 'tls' || $mailEncryption === 'ssl'),
'require_tls' => ($mailEncryption === 'tls' || $mailEncryption === 'ssl' || $mailPort === 465),
],
'sendmail' => [

View File

@@ -18,6 +18,7 @@ use BookStack\Exceptions\NotFoundException;
use BookStack\Facades\Activity;
use BookStack\Http\Controller;
use BookStack\References\ReferenceFetcher;
use BookStack\Util\DatabaseTransaction;
use BookStack\Util\SimpleListOptions;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
@@ -263,7 +264,9 @@ class BookController extends Controller
$this->checkPermission('bookshelf-create-all');
$this->checkPermission('book-create-all');
$shelf = $transformer->transformBookToShelf($book);
$shelf = (new DatabaseTransaction(function () use ($book, $transformer) {
return $transformer->transformBookToShelf($book);
}))->run();
return redirect($shelf->getUrl());
}

View File

@@ -9,12 +9,11 @@ use BookStack\Entities\Repos\ChapterRepo;
use BookStack\Exceptions\PermissionsException;
use BookStack\Http\ApiController;
use Exception;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Http\Request;
class ChapterApiController extends ApiController
{
protected $rules = [
protected array $rules = [
'create' => [
'book_id' => ['required', 'integer'],
'name' => ['required', 'string', 'max:255'],

View File

@@ -18,6 +18,7 @@ use BookStack\Exceptions\NotifyException;
use BookStack\Exceptions\PermissionsException;
use BookStack\Http\Controller;
use BookStack\References\ReferenceFetcher;
use BookStack\Util\DatabaseTransaction;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Throwable;
@@ -269,7 +270,9 @@ class ChapterController extends Controller
$this->checkOwnablePermission('chapter-delete', $chapter);
$this->checkPermission('book-create-all');
$book = $transformer->transformChapterToBook($chapter);
$book = (new DatabaseTransaction(function () use ($chapter, $transformer) {
return $transformer->transformChapterToBook($chapter);
}))->run();
return redirect($book->getUrl());
}

View File

@@ -12,7 +12,7 @@ use Illuminate\Http\Request;
class PageApiController extends ApiController
{
protected $rules = [
protected array $rules = [
'create' => [
'book_id' => ['required_without:chapter_id', 'integer'],
'chapter_id' => ['required_without:book_id', 'integer'],

View File

@@ -77,7 +77,6 @@ class BaseRepo
$entity->touch();
}
$entity->rebuildPermissions();
$entity->indexForSearch();
$this->referenceStore->updateForEntity($entity);
@@ -139,7 +138,7 @@ class BaseRepo
/**
* Sort the parent of the given entity, if any auto sort actions are set for it.
* Typical ran during create/update/insert events.
* Typically ran during create/update/insert events.
*/
public function sortParent(Entity $entity): void
{

View File

@@ -10,6 +10,7 @@ use BookStack\Exceptions\ImageUploadException;
use BookStack\Facades\Activity;
use BookStack\Sorting\SortRule;
use BookStack\Uploads\ImageRepo;
use BookStack\Util\DatabaseTransaction;
use Exception;
use Illuminate\Http\UploadedFile;
@@ -28,19 +29,22 @@ class BookRepo
*/
public function create(array $input): Book
{
$book = new Book();
$this->baseRepo->create($book, $input);
$this->baseRepo->updateCoverImage($book, $input['image'] ?? null);
$this->baseRepo->updateDefaultTemplate($book, intval($input['default_template_id'] ?? null));
Activity::add(ActivityType::BOOK_CREATE, $book);
return (new DatabaseTransaction(function () use ($input) {
$book = new Book();
$defaultBookSortSetting = intval(setting('sorting-book-default', '0'));
if ($defaultBookSortSetting && SortRule::query()->find($defaultBookSortSetting)) {
$book->sort_rule_id = $defaultBookSortSetting;
$book->save();
}
$this->baseRepo->create($book, $input);
$this->baseRepo->updateCoverImage($book, $input['image'] ?? null);
$this->baseRepo->updateDefaultTemplate($book, intval($input['default_template_id'] ?? null));
Activity::add(ActivityType::BOOK_CREATE, $book);
return $book;
$defaultBookSortSetting = intval(setting('sorting-book-default', '0'));
if ($defaultBookSortSetting && SortRule::query()->find($defaultBookSortSetting)) {
$book->sort_rule_id = $defaultBookSortSetting;
$book->save();
}
return $book;
}))->run();
}
/**

View File

@@ -7,6 +7,7 @@ use BookStack\Entities\Models\Bookshelf;
use BookStack\Entities\Queries\BookQueries;
use BookStack\Entities\Tools\TrashCan;
use BookStack\Facades\Activity;
use BookStack\Util\DatabaseTransaction;
use Exception;
class BookshelfRepo
@@ -23,13 +24,14 @@ class BookshelfRepo
*/
public function create(array $input, array $bookIds): Bookshelf
{
$shelf = new Bookshelf();
$this->baseRepo->create($shelf, $input);
$this->baseRepo->updateCoverImage($shelf, $input['image'] ?? null);
$this->updateBooks($shelf, $bookIds);
Activity::add(ActivityType::BOOKSHELF_CREATE, $shelf);
return $shelf;
return (new DatabaseTransaction(function () use ($input, $bookIds) {
$shelf = new Bookshelf();
$this->baseRepo->create($shelf, $input);
$this->baseRepo->updateCoverImage($shelf, $input['image'] ?? null);
$this->updateBooks($shelf, $bookIds);
Activity::add(ActivityType::BOOKSHELF_CREATE, $shelf);
return $shelf;
}))->run();
}
/**

View File

@@ -11,6 +11,7 @@ use BookStack\Entities\Tools\TrashCan;
use BookStack\Exceptions\MoveOperationException;
use BookStack\Exceptions\PermissionsException;
use BookStack\Facades\Activity;
use BookStack\Util\DatabaseTransaction;
use Exception;
class ChapterRepo
@@ -27,16 +28,18 @@ class ChapterRepo
*/
public function create(array $input, Book $parentBook): Chapter
{
$chapter = new Chapter();
$chapter->book_id = $parentBook->id;
$chapter->priority = (new BookContents($parentBook))->getLastPriority() + 1;
$this->baseRepo->create($chapter, $input);
$this->baseRepo->updateDefaultTemplate($chapter, intval($input['default_template_id'] ?? null));
Activity::add(ActivityType::CHAPTER_CREATE, $chapter);
return (new DatabaseTransaction(function () use ($input, $parentBook) {
$chapter = new Chapter();
$chapter->book_id = $parentBook->id;
$chapter->priority = (new BookContents($parentBook))->getLastPriority() + 1;
$this->baseRepo->create($chapter, $input);
$this->baseRepo->updateDefaultTemplate($chapter, intval($input['default_template_id'] ?? null));
Activity::add(ActivityType::CHAPTER_CREATE, $chapter);
$this->baseRepo->sortParent($chapter);
$this->baseRepo->sortParent($chapter);
return $chapter;
return $chapter;
}))->run();
}
/**
@@ -88,12 +91,14 @@ class ChapterRepo
throw new PermissionsException('User does not have permission to create a chapter within the chosen book');
}
$chapter->changeBook($parent->id);
$chapter->rebuildPermissions();
Activity::add(ActivityType::CHAPTER_MOVE, $chapter);
return (new DatabaseTransaction(function () use ($chapter, $parent) {
$chapter->changeBook($parent->id);
$chapter->rebuildPermissions();
Activity::add(ActivityType::CHAPTER_MOVE, $chapter);
$this->baseRepo->sortParent($chapter);
$this->baseRepo->sortParent($chapter);
return $parent;
return $parent;
}))->run();
}
}

View File

@@ -18,6 +18,7 @@ use BookStack\Exceptions\PermissionsException;
use BookStack\Facades\Activity;
use BookStack\References\ReferenceStore;
use BookStack\References\ReferenceUpdater;
use BookStack\Util\DatabaseTransaction;
use Exception;
class PageRepo
@@ -61,8 +62,10 @@ class PageRepo
]);
}
$page->save();
$page->refresh()->rebuildPermissions();
(new DatabaseTransaction(function () use ($page) {
$page->save();
$page->refresh()->rebuildPermissions();
}))->run();
return $page;
}
@@ -72,26 +75,29 @@ class PageRepo
*/
public function publishDraft(Page $draft, array $input): Page
{
$draft->draft = false;
$draft->revision_count = 1;
$draft->priority = $this->getNewPriority($draft);
$this->updateTemplateStatusAndContentFromInput($draft, $input);
$this->baseRepo->update($draft, $input);
return (new DatabaseTransaction(function () use ($draft, $input) {
$draft->draft = false;
$draft->revision_count = 1;
$draft->priority = $this->getNewPriority($draft);
$this->updateTemplateStatusAndContentFromInput($draft, $input);
$this->baseRepo->update($draft, $input);
$draft->rebuildPermissions();
$summary = trim($input['summary'] ?? '') ?: trans('entities.pages_initial_revision');
$this->revisionRepo->storeNewForPage($draft, $summary);
$draft->refresh();
$summary = trim($input['summary'] ?? '') ?: trans('entities.pages_initial_revision');
$this->revisionRepo->storeNewForPage($draft, $summary);
$draft->refresh();
Activity::add(ActivityType::PAGE_CREATE, $draft);
$this->baseRepo->sortParent($draft);
Activity::add(ActivityType::PAGE_CREATE, $draft);
$this->baseRepo->sortParent($draft);
return $draft;
return $draft;
}))->run();
}
/**
* Directly update the content for the given page from the provided input.
* Used for direct content access in a way that performs required changes
* (Search index & reference regen) without performing an official update.
* (Search index and reference regen) without performing an official update.
*/
public function setContentFromInput(Page $page, array $input): void
{
@@ -116,7 +122,7 @@ class PageRepo
$page->revision_count++;
$page->save();
// Remove all update drafts for this user & page.
// Remove all update drafts for this user and page.
$this->revisionRepo->deleteDraftsForCurrentUser($page);
// Save a revision after updating
@@ -269,16 +275,18 @@ class PageRepo
throw new PermissionsException('User does not have permission to create a page within the new parent');
}
$page->chapter_id = ($parent instanceof Chapter) ? $parent->id : null;
$newBookId = ($parent instanceof Chapter) ? $parent->book->id : $parent->id;
$page->changeBook($newBookId);
$page->rebuildPermissions();
return (new DatabaseTransaction(function () use ($page, $parent) {
$page->chapter_id = ($parent instanceof Chapter) ? $parent->id : null;
$newBookId = ($parent instanceof Chapter) ? $parent->book->id : $parent->id;
$page->changeBook($newBookId);
$page->rebuildPermissions();
Activity::add(ActivityType::PAGE_MOVE, $page);
Activity::add(ActivityType::PAGE_MOVE, $page);
$this->baseRepo->sortParent($page);
$this->baseRepo->sortParent($page);
return $parent;
return $parent;
}))->run();
}
/**

View File

@@ -13,17 +13,12 @@ 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;
public function __construct(
protected BookRepo $bookRepo,
protected BookshelfRepo $shelfRepo,
protected Cloner $cloner,
protected TrashCan $trashCan
) {
}
/**

View File

@@ -15,6 +15,7 @@ use BookStack\Exceptions\NotifyException;
use BookStack\Facades\Activity;
use BookStack\Uploads\AttachmentService;
use BookStack\Uploads\ImageService;
use BookStack\Util\DatabaseTransaction;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Carbon;
@@ -357,25 +358,26 @@ class TrashCan
/**
* Destroy the given entity.
* Returns the number of total entities destroyed in the operation.
*
* @throws Exception
*/
public function destroyEntity(Entity $entity): int
{
if ($entity instanceof Page) {
return $this->destroyPage($entity);
}
if ($entity instanceof Chapter) {
return $this->destroyChapter($entity);
}
if ($entity instanceof Book) {
return $this->destroyBook($entity);
}
if ($entity instanceof Bookshelf) {
return $this->destroyShelf($entity);
}
$result = (new DatabaseTransaction(function () use ($entity) {
if ($entity instanceof Page) {
return $this->destroyPage($entity);
} else if ($entity instanceof Chapter) {
return $this->destroyChapter($entity);
} else if ($entity instanceof Book) {
return $this->destroyBook($entity);
} else if ($entity instanceof Bookshelf) {
return $this->destroyShelf($entity);
}
return null;
}))->run();
return 0;
return $result ?? 0;
}
/**

View File

@@ -4,6 +4,7 @@ namespace BookStack\Exports\Controllers;
use BookStack\Entities\Queries\BookQueries;
use BookStack\Exports\ExportFormatter;
use BookStack\Exports\ZipExports\ZipExportBuilder;
use BookStack\Http\ApiController;
use Throwable;
@@ -63,4 +64,15 @@ class BookExportApiController extends ApiController
return $this->download()->directly($markdown, $book->slug . '.md');
}
/**
* Export a book as a contained ZIP export file.
*/
public function exportZip(int $id, ZipExportBuilder $builder)
{
$book = $this->queries->findVisibleByIdOrFail($id);
$zip = $builder->buildForBook($book);
return $this->download()->streamedFileDirectly($zip, $book->slug . '.zip', true);
}
}

View File

@@ -4,6 +4,7 @@ namespace BookStack\Exports\Controllers;
use BookStack\Entities\Queries\ChapterQueries;
use BookStack\Exports\ExportFormatter;
use BookStack\Exports\ZipExports\ZipExportBuilder;
use BookStack\Http\ApiController;
use Throwable;
@@ -63,4 +64,15 @@ class ChapterExportApiController extends ApiController
return $this->download()->directly($markdown, $chapter->slug . '.md');
}
/**
* Export a chapter as a contained ZIP file.
*/
public function exportZip(int $id, ZipExportBuilder $builder)
{
$chapter = $this->queries->findVisibleByIdOrFail($id);
$zip = $builder->buildForChapter($chapter);
return $this->download()->streamedFileDirectly($zip, $chapter->slug . '.zip', true);
}
}

View File

@@ -0,0 +1,144 @@
<?php
declare(strict_types=1);
namespace BookStack\Exports\Controllers;
use BookStack\Exceptions\ZipImportException;
use BookStack\Exceptions\ZipValidationException;
use BookStack\Exports\ImportRepo;
use BookStack\Http\ApiController;
use BookStack\Uploads\AttachmentService;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Response;
class ImportApiController extends ApiController
{
public function __construct(
protected ImportRepo $imports,
) {
$this->middleware('can:content-import');
}
/**
* List existing ZIP imports visible to the user.
* Requires permission to import content.
*/
public function list(): JsonResponse
{
$query = $this->imports->queryVisible();
return $this->apiListingResponse($query, [
'id', 'name', 'size', 'type', 'created_by', 'created_at', 'updated_at'
]);
}
/**
* Start a new import from a ZIP file.
* This does not actually run the import since that is performed via the "run" endpoint.
* This uploads, validates and stores the ZIP file so it's ready to be imported.
*
* This "file" parameter must be a BookStack-compatible ZIP file, and this must be
* sent via a 'multipart/form-data' type request.
*
* Requires permission to import content.
*/
public function create(Request $request): JsonResponse
{
$this->validate($request, $this->rules()['create']);
$file = $request->file('file');
try {
$import = $this->imports->storeFromUpload($file);
} catch (ZipValidationException $exception) {
$message = "ZIP upload failed with the following validation errors: \n" . $this->formatErrors($exception->errors);
return $this->jsonError($message, 422);
}
return response()->json($import);
}
/**
* Read details of a pending ZIP import.
* The "details" property contains high-level metadata regarding the ZIP import content,
* and the structure of this will change depending on import "type".
* Requires permission to import content.
*/
public function read(int $id): JsonResponse
{
$import = $this->imports->findVisible($id);
$import->setAttribute('details', $import->decodeMetadata());
return response()->json($import);
}
/**
* Run the import process for an uploaded ZIP import.
* The "parent_id" and "parent_type" parameters are required when the import type is "chapter" or "page".
* On success, this endpoint returns the imported item.
* Requires permission to import content.
*/
public function run(int $id, Request $request): JsonResponse
{
$import = $this->imports->findVisible($id);
$parent = null;
$rules = $this->rules()['run'];
if ($import->type === 'page' || $import->type === 'chapter') {
$rules['parent_type'][] = 'required';
$rules['parent_id'][] = 'required';
$data = $this->validate($request, $rules);
$parent = "{$data['parent_type']}:{$data['parent_id']}";
}
try {
$entity = $this->imports->runImport($import, $parent);
} catch (ZipImportException $exception) {
$message = "ZIP import failed with the following errors: \n" . $this->formatErrors($exception->errors);
return $this->jsonError($message);
}
return response()->json($entity->withoutRelations());
}
/**
* Delete a pending ZIP import from the system.
* Requires permission to import content.
*/
public function delete(int $id): Response
{
$import = $this->imports->findVisible($id);
$this->imports->deleteImport($import);
return response('', 204);
}
protected function rules(): array
{
return [
'create' => [
'file' => ['required', ...AttachmentService::getFileValidationRules()],
],
'run' => [
'parent_type' => ['string', 'in:book,chapter'],
'parent_id' => ['int'],
],
];
}
protected function formatErrors(array $errors): string
{
$parts = [];
foreach ($errors as $key => $error) {
if (is_string($key)) {
$parts[] = "[{$key}] {$error}";
} else {
$parts[] = $error;
}
}
return implode("\n", $parts);
}
}

View File

@@ -4,6 +4,7 @@ namespace BookStack\Exports\Controllers;
use BookStack\Entities\Queries\PageQueries;
use BookStack\Exports\ExportFormatter;
use BookStack\Exports\ZipExports\ZipExportBuilder;
use BookStack\Http\ApiController;
use Throwable;
@@ -63,4 +64,15 @@ class PageExportApiController extends ApiController
return $this->download()->directly($markdown, $page->slug . '.md');
}
/**
* Export a page as a contained ZIP file.
*/
public function exportZip(int $id, ZipExportBuilder $builder)
{
$page = $this->queries->findVisibleByIdOrFail($id);
$zip = $builder->buildForPage($page);
return $this->download()->streamedFileDirectly($zip, $page->slug . '.zip', true);
}
}

View File

@@ -28,6 +28,8 @@ class Import extends Model implements Loggable
{
use HasFactory;
protected $hidden = ['metadata'];
public function getSizeString(): string
{
$mb = round($this->size / 1000000, 2);

View File

@@ -17,6 +17,7 @@ use BookStack\Exports\ZipExports\ZipExportValidator;
use BookStack\Exports\ZipExports\ZipImportRunner;
use BookStack\Facades\Activity;
use BookStack\Uploads\FileStorage;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpFoundation\File\UploadedFile;
@@ -34,6 +35,11 @@ class ImportRepo
* @return Collection<Import>
*/
public function getVisibleImports(): Collection
{
return $this->queryVisible()->get();
}
public function queryVisible(): Builder
{
$query = Import::query();
@@ -41,7 +47,7 @@ class ImportRepo
$query->where('created_by', user()->id);
}
return $query->get();
return $query;
}
public function findVisible(int $id): Import

View File

@@ -8,7 +8,7 @@ use Illuminate\Http\JsonResponse;
abstract class ApiController extends Controller
{
protected $rules = [];
protected array $rules = [];
/**
* Provide a paginated listing JSON response in a standard format

View File

@@ -16,7 +16,7 @@ class ContentPermissionApiController extends ApiController
) {
}
protected $rules = [
protected array $rules = [
'update' => [
'owner_id' => ['int'],

View File

@@ -29,7 +29,7 @@ class JointPermissionBuilder
/**
* Re-generate all entity permission from scratch.
*/
public function rebuildForAll()
public function rebuildForAll(): void
{
JointPermission::query()->truncate();
@@ -51,7 +51,7 @@ class JointPermissionBuilder
/**
* Rebuild the entity jointPermissions for a particular entity.
*/
public function rebuildForEntity(Entity $entity)
public function rebuildForEntity(Entity $entity): void
{
$entities = [$entity];
if ($entity instanceof Book) {
@@ -119,7 +119,7 @@ class JointPermissionBuilder
/**
* Build joint permissions for the given book and role combinations.
*/
protected function buildJointPermissionsForBooks(EloquentCollection $books, array $roles, bool $deleteOld = false)
protected function buildJointPermissionsForBooks(EloquentCollection $books, array $roles, bool $deleteOld = false): void
{
$entities = clone $books;
@@ -143,7 +143,7 @@ class JointPermissionBuilder
/**
* Rebuild the entity jointPermissions for a collection of entities.
*/
protected function buildJointPermissionsForEntities(array $entities)
protected function buildJointPermissionsForEntities(array $entities): void
{
$roles = Role::query()->get()->values()->all();
$this->deleteManyJointPermissionsForEntities($entities);
@@ -155,21 +155,19 @@ class JointPermissionBuilder
*
* @param Entity[] $entities
*/
protected function deleteManyJointPermissionsForEntities(array $entities)
protected function deleteManyJointPermissionsForEntities(array $entities): void
{
$simpleEntities = $this->entitiesToSimpleEntities($entities);
$idsByType = $this->entitiesToTypeIdMap($simpleEntities);
DB::transaction(function () use ($idsByType) {
foreach ($idsByType as $type => $ids) {
foreach (array_chunk($ids, 1000) as $idChunk) {
DB::table('joint_permissions')
->where('entity_type', '=', $type)
->whereIn('entity_id', $idChunk)
->delete();
}
foreach ($idsByType as $type => $ids) {
foreach (array_chunk($ids, 1000) as $idChunk) {
DB::table('joint_permissions')
->where('entity_type', '=', $type)
->whereIn('entity_id', $idChunk)
->delete();
}
});
}
}
/**
@@ -195,7 +193,7 @@ class JointPermissionBuilder
* @param Entity[] $originalEntities
* @param Role[] $roles
*/
protected function createManyJointPermissions(array $originalEntities, array $roles)
protected function createManyJointPermissions(array $originalEntities, array $roles): void
{
$entities = $this->entitiesToSimpleEntities($originalEntities);
$jointPermissions = [];
@@ -225,11 +223,9 @@ class JointPermissionBuilder
}
}
DB::transaction(function () use ($jointPermissions) {
foreach (array_chunk($jointPermissions, 1000) as $jointPermissionChunk) {
DB::table('joint_permissions')->insert($jointPermissionChunk);
}
});
foreach (array_chunk($jointPermissions, 1000) as $jointPermissionChunk) {
DB::table('joint_permissions')->insert($jointPermissionChunk);
}
}
/**

View File

@@ -7,6 +7,7 @@ use BookStack\Entities\Tools\PermissionsUpdater;
use BookStack\Http\Controller;
use BookStack\Permissions\Models\EntityPermission;
use BookStack\Users\Models\Role;
use BookStack\Util\DatabaseTransaction;
use Illuminate\Http\Request;
class PermissionsController extends Controller
@@ -40,7 +41,9 @@ class PermissionsController extends Controller
$page = $this->queries->pages->findVisibleBySlugsOrFail($bookSlug, $pageSlug);
$this->checkOwnablePermission('restrictions-manage', $page);
$this->permissionsUpdater->updateFromPermissionsForm($page, $request);
(new DatabaseTransaction(function () use ($page, $request) {
$this->permissionsUpdater->updateFromPermissionsForm($page, $request);
}))->run();
$this->showSuccessNotification(trans('entities.pages_permissions_success'));
@@ -70,7 +73,9 @@ class PermissionsController extends Controller
$chapter = $this->queries->chapters->findVisibleBySlugsOrFail($bookSlug, $chapterSlug);
$this->checkOwnablePermission('restrictions-manage', $chapter);
$this->permissionsUpdater->updateFromPermissionsForm($chapter, $request);
(new DatabaseTransaction(function () use ($chapter, $request) {
$this->permissionsUpdater->updateFromPermissionsForm($chapter, $request);
}))->run();
$this->showSuccessNotification(trans('entities.chapters_permissions_success'));
@@ -100,7 +105,9 @@ class PermissionsController extends Controller
$book = $this->queries->books->findVisibleBySlugOrFail($slug);
$this->checkOwnablePermission('restrictions-manage', $book);
$this->permissionsUpdater->updateFromPermissionsForm($book, $request);
(new DatabaseTransaction(function () use ($book, $request) {
$this->permissionsUpdater->updateFromPermissionsForm($book, $request);
}))->run();
$this->showSuccessNotification(trans('entities.books_permissions_updated'));
@@ -130,7 +137,9 @@ class PermissionsController extends Controller
$shelf = $this->queries->shelves->findVisibleBySlugOrFail($slug);
$this->checkOwnablePermission('restrictions-manage', $shelf);
$this->permissionsUpdater->updateFromPermissionsForm($shelf, $request);
(new DatabaseTransaction(function () use ($shelf, $request) {
$this->permissionsUpdater->updateFromPermissionsForm($shelf, $request);
}))->run();
$this->showSuccessNotification(trans('entities.shelves_permissions_updated'));
@@ -145,7 +154,10 @@ class PermissionsController extends Controller
$shelf = $this->queries->shelves->findVisibleBySlugOrFail($slug);
$this->checkOwnablePermission('restrictions-manage', $shelf);
$updateCount = $this->permissionsUpdater->updateBookPermissionsFromShelf($shelf);
$updateCount = (new DatabaseTransaction(function () use ($shelf) {
return $this->permissionsUpdater->updateBookPermissionsFromShelf($shelf);
}))->run();
$this->showSuccessNotification(trans('entities.shelves_copy_permission_success', ['count' => $updateCount]));
return redirect($shelf->getUrl());

View File

@@ -7,6 +7,7 @@ use BookStack\Exceptions\PermissionsException;
use BookStack\Facades\Activity;
use BookStack\Permissions\Models\RolePermission;
use BookStack\Users\Models\Role;
use BookStack\Util\DatabaseTransaction;
use Exception;
use Illuminate\Database\Eloquent\Collection;
@@ -48,38 +49,42 @@ class PermissionsRepo
*/
public function saveNewRole(array $roleData): Role
{
$role = new Role($roleData);
$role->mfa_enforced = boolval($roleData['mfa_enforced'] ?? false);
$role->save();
return (new DatabaseTransaction(function () use ($roleData) {
$role = new Role($roleData);
$role->mfa_enforced = boolval($roleData['mfa_enforced'] ?? false);
$role->save();
$permissions = $roleData['permissions'] ?? [];
$this->assignRolePermissions($role, $permissions);
$this->permissionBuilder->rebuildForRole($role);
$permissions = $roleData['permissions'] ?? [];
$this->assignRolePermissions($role, $permissions);
$this->permissionBuilder->rebuildForRole($role);
Activity::add(ActivityType::ROLE_CREATE, $role);
Activity::add(ActivityType::ROLE_CREATE, $role);
return $role;
return $role;
}))->run();
}
/**
* Updates an existing role.
* Ensures Admin system role always have core permissions.
* Ensures the Admin system role always has core permissions.
*/
public function updateRole($roleId, array $roleData): Role
{
$role = $this->getRoleById($roleId);
if (isset($roleData['permissions'])) {
$this->assignRolePermissions($role, $roleData['permissions']);
}
return (new DatabaseTransaction(function () use ($role, $roleData) {
if (isset($roleData['permissions'])) {
$this->assignRolePermissions($role, $roleData['permissions']);
}
$role->fill($roleData);
$role->save();
$this->permissionBuilder->rebuildForRole($role);
$role->fill($roleData);
$role->save();
$this->permissionBuilder->rebuildForRole($role);
Activity::add(ActivityType::ROLE_UPDATE, $role);
Activity::add(ActivityType::ROLE_UPDATE, $role);
return $role;
return $role;
}))->run();
}
/**
@@ -114,7 +119,7 @@ class PermissionsRepo
/**
* Delete a role from the system.
* Check it's not an admin role or set as default before deleting.
* If a migration Role ID is specified the users assign to the current role
* If a migration Role ID is specified, the users assigned to the current role
* will be added to the role of the specified id.
*
* @throws PermissionsException
@@ -131,17 +136,19 @@ class PermissionsRepo
throw new PermissionsException(trans('errors.role_registration_default_cannot_delete'));
}
if ($migrateRoleId !== 0) {
$newRole = Role::query()->find($migrateRoleId);
if ($newRole) {
$users = $role->users()->pluck('id')->toArray();
$newRole->users()->sync($users);
(new DatabaseTransaction(function () use ($migrateRoleId, $role) {
if ($migrateRoleId !== 0) {
$newRole = Role::query()->find($migrateRoleId);
if ($newRole) {
$users = $role->users()->pluck('id')->toArray();
$newRole->users()->sync($users);
}
}
}
$role->entityPermissions()->delete();
$role->jointPermissions()->delete();
Activity::add(ActivityType::ROLE_DELETE, $role);
$role->delete();
$role->entityPermissions()->delete();
$role->jointPermissions()->delete();
Activity::add(ActivityType::ROLE_DELETE, $role);
$role->delete();
}))->run();
}
}

View File

@@ -9,7 +9,7 @@ use Illuminate\Http\Request;
class SearchApiController extends ApiController
{
protected $rules = [
protected array $rules = [
'all' => [
'query' => ['required'],
'page' => ['integer', 'min:1'],

View File

@@ -7,6 +7,7 @@ use BookStack\Entities\Queries\BookQueries;
use BookStack\Entities\Tools\BookContents;
use BookStack\Facades\Activity;
use BookStack\Http\Controller;
use BookStack\Util\DatabaseTransaction;
use Illuminate\Http\Request;
class BookSortController extends Controller
@@ -55,16 +56,18 @@ class BookSortController extends Controller
// Sort via map
if ($request->filled('sort-tree')) {
$sortMap = BookSortMap::fromJson($request->get('sort-tree'));
$booksInvolved = $sorter->sortUsingMap($sortMap);
(new DatabaseTransaction(function () use ($book, $request, $sorter, &$loggedActivityForBook) {
$sortMap = BookSortMap::fromJson($request->get('sort-tree'));
$booksInvolved = $sorter->sortUsingMap($sortMap);
// Rebuild permissions and add activity for involved books.
foreach ($booksInvolved as $bookInvolved) {
Activity::add(ActivityType::BOOK_SORT, $bookInvolved);
if ($bookInvolved->id === $book->id) {
$loggedActivityForBook = true;
// Add activity for involved books.
foreach ($booksInvolved as $bookInvolved) {
Activity::add(ActivityType::BOOK_SORT, $bookInvolved);
if ($bookInvolved->id === $book->id) {
$loggedActivityForBook = true;
}
}
}
}))->run();
}
if ($request->filled('auto-sort')) {

View File

@@ -2,7 +2,6 @@
namespace BookStack\Sorting;
use BookStack\App\Model;
use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\BookChild;
use BookStack\Entities\Models\Chapter;

View File

@@ -16,7 +16,7 @@ class RoleApiController extends ApiController
'display_name', 'description', 'mfa_enforced', 'external_auth_id', 'created_at', 'updated_at',
];
protected $rules = [
protected array $rules = [
'create' => [
'display_name' => ['required', 'string', 'min:3', 'max:180'],
'description' => ['string', 'max:180'],

View File

@@ -0,0 +1,42 @@
<?php
namespace BookStack\Util;
use Closure;
use Illuminate\Support\Facades\DB;
use Throwable;
/**
* Run the given code within a database transactions.
* Wraps Laravel's own transaction method, but sets a specific runtime isolation method.
* This sets a session level since this won't cause issues if already within a transaction,
* and this should apply to the next transactions anyway.
*
* "READ COMMITTED" ensures that changes from other transactions can be read within
* a transaction, even if started afterward (and for example, it was blocked by the initial
* transaction). This is quite important for things like permission generation, where we would
* want to consider the changes made by other committed transactions by the time we come to
* regenerate permission access.
*
* @throws Throwable
* @template TReturn of mixed
*/
class DatabaseTransaction
{
/**
* @param (Closure(static): TReturn) $callback
*/
public function __construct(
protected Closure $callback
) {
}
/**
* @return TReturn
*/
public function run(): mixed
{
DB::statement('SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED');
return DB::transaction($this->callback);
}
}

View File

@@ -4,7 +4,6 @@ namespace BookStack\Util;
use DOMAttr;
use DOMElement;
use DOMNamedNodeMap;
use DOMNode;
/**
@@ -25,6 +24,7 @@ class HtmlDescriptionFilter
'ul' => [],
'li' => [],
'strong' => [],
'span' => [],
'em' => [],
'br' => [],
];
@@ -59,7 +59,6 @@ class HtmlDescriptionFilter
return;
}
/** @var DOMNamedNodeMap $attrs */
$attrs = $element->attributes;
for ($i = $attrs->length - 1; $i >= 0; $i--) {
/** @var DOMAttr $attr */
@@ -70,7 +69,8 @@ class HtmlDescriptionFilter
}
}
foreach ($element->childNodes as $child) {
$childNodes = [...$element->childNodes];
foreach ($childNodes as $child) {
if ($child instanceof DOMElement) {
static::filterElement($child);
}

View File

@@ -38,8 +38,7 @@
"socialiteproviders/microsoft-azure": "^5.1",
"socialiteproviders/okta": "^4.2",
"socialiteproviders/twitch": "^5.3",
"ssddanbrown/htmldiff": "^2.0.0",
"ssddanbrown/symfony-mailer": "7.2.x-dev"
"ssddanbrown/htmldiff": "^2.0.0"
},
"require-dev": {
"fakerphp/faker": "^1.21",

269
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "d9b8455cf3ec02c21bea7ee94463331b",
"content-hash": "b7695cb9945ec550970c67da96934daf",
"packages": [
{
"name": "aws/aws-crt-php",
@@ -62,16 +62,16 @@
},
{
"name": "aws/aws-sdk-php",
"version": "3.349.2",
"version": "3.351.7",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
"reference": "63cc727845f077d17cb94791deb327249e1626ce"
"reference": "9506d7fdb3cb84f8d7b175c594db9993264814be"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/63cc727845f077d17cb94791deb327249e1626ce",
"reference": "63cc727845f077d17cb94791deb327249e1626ce",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/9506d7fdb3cb84f8d7b175c594db9993264814be",
"reference": "9506d7fdb3cb84f8d7b175c594db9993264814be",
"shasum": ""
},
"require": {
@@ -153,9 +153,9 @@
"support": {
"forum": "https://github.com/aws/aws-sdk-php/discussions",
"issues": "https://github.com/aws/aws-sdk-php/issues",
"source": "https://github.com/aws/aws-sdk-php/tree/3.349.2"
"source": "https://github.com/aws/aws-sdk-php/tree/3.351.7"
},
"time": "2025-07-03T18:08:27+00:00"
"time": "2025-07-25T18:06:34+00:00"
},
{
"name": "bacon/bacon-qr-code",
@@ -1955,16 +1955,16 @@
},
{
"name": "laravel/prompts",
"version": "v0.3.5",
"version": "v0.3.6",
"source": {
"type": "git",
"url": "https://github.com/laravel/prompts.git",
"reference": "57b8f7efe40333cdb925700891c7d7465325d3b1"
"reference": "86a8b692e8661d0fb308cec64f3d176821323077"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/prompts/zipball/57b8f7efe40333cdb925700891c7d7465325d3b1",
"reference": "57b8f7efe40333cdb925700891c7d7465325d3b1",
"url": "https://api.github.com/repos/laravel/prompts/zipball/86a8b692e8661d0fb308cec64f3d176821323077",
"reference": "86a8b692e8661d0fb308cec64f3d176821323077",
"shasum": ""
},
"require": {
@@ -2008,9 +2008,9 @@
"description": "Add beautiful and user-friendly forms to your command-line applications.",
"support": {
"issues": "https://github.com/laravel/prompts/issues",
"source": "https://github.com/laravel/prompts/tree/v0.3.5"
"source": "https://github.com/laravel/prompts/tree/v0.3.6"
},
"time": "2025-02-11T13:34:40+00:00"
"time": "2025-07-07T14:17:42+00:00"
},
{
"name": "laravel/serializable-closure",
@@ -2075,16 +2075,16 @@
},
{
"name": "laravel/socialite",
"version": "v5.21.0",
"version": "v5.23.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/socialite.git",
"reference": "d83639499ad14985c9a6a9713b70073300ce998d"
"reference": "e9e0fc83b9d8d71c8385a5da20e5b95ca6234cf5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/socialite/zipball/d83639499ad14985c9a6a9713b70073300ce998d",
"reference": "d83639499ad14985c9a6a9713b70073300ce998d",
"url": "https://api.github.com/repos/laravel/socialite/zipball/e9e0fc83b9d8d71c8385a5da20e5b95ca6234cf5",
"reference": "e9e0fc83b9d8d71c8385a5da20e5b95ca6234cf5",
"shasum": ""
},
"require": {
@@ -2143,7 +2143,7 @@
"issues": "https://github.com/laravel/socialite/issues",
"source": "https://github.com/laravel/socialite"
},
"time": "2025-05-19T12:56:37+00:00"
"time": "2025-07-23T14:16:08+00:00"
},
{
"name": "laravel/tinker",
@@ -2213,16 +2213,16 @@
},
{
"name": "league/commonmark",
"version": "2.7.0",
"version": "2.7.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/commonmark.git",
"reference": "6fbb36d44824ed4091adbcf4c7d4a3923cdb3405"
"reference": "10732241927d3971d28e7ea7b5712721fa2296ca"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/6fbb36d44824ed4091adbcf4c7d4a3923cdb3405",
"reference": "6fbb36d44824ed4091adbcf4c7d4a3923cdb3405",
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/10732241927d3971d28e7ea7b5712721fa2296ca",
"reference": "10732241927d3971d28e7ea7b5712721fa2296ca",
"shasum": ""
},
"require": {
@@ -2251,7 +2251,7 @@
"symfony/process": "^5.4 | ^6.0 | ^7.0",
"symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0",
"unleashedtech/php-coding-standard": "^3.1.1",
"vimeo/psalm": "^4.24.0 || ^5.0.0"
"vimeo/psalm": "^4.24.0 || ^5.0.0 || ^6.0.0"
},
"suggest": {
"symfony/yaml": "v2.3+ required if using the Front Matter extension"
@@ -2316,7 +2316,7 @@
"type": "tidelift"
}
],
"time": "2025-05-05T12:20:28+00:00"
"time": "2025-07-20T12:47:49+00:00"
},
{
"name": "league/config",
@@ -3049,16 +3049,16 @@
},
{
"name": "masterminds/html5",
"version": "2.9.0",
"version": "2.10.0",
"source": {
"type": "git",
"url": "https://github.com/Masterminds/html5-php.git",
"reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6"
"reference": "fcf91eb64359852f00d921887b219479b4f21251"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6",
"reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6",
"url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251",
"reference": "fcf91eb64359852f00d921887b219479b4f21251",
"shasum": ""
},
"require": {
@@ -3110,9 +3110,9 @@
],
"support": {
"issues": "https://github.com/Masterminds/html5-php/issues",
"source": "https://github.com/Masterminds/html5-php/tree/2.9.0"
"source": "https://github.com/Masterminds/html5-php/tree/2.10.0"
},
"time": "2024-03-31T07:05:07+00:00"
"time": "2025-07-25T09:04:22+00:00"
},
{
"name": "monolog/monolog",
@@ -4894,16 +4894,16 @@
},
{
"name": "sabberworm/php-css-parser",
"version": "v8.8.0",
"version": "v8.9.0",
"source": {
"type": "git",
"url": "https://github.com/MyIntervals/PHP-CSS-Parser.git",
"reference": "3de493bdddfd1f051249af725c7e0d2c38fed740"
"reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/3de493bdddfd1f051249af725c7e0d2c38fed740",
"reference": "3de493bdddfd1f051249af725c7e0d2c38fed740",
"url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/d8e916507b88e389e26d4ab03c904a082aa66bb9",
"reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9",
"shasum": ""
},
"require": {
@@ -4911,7 +4911,8 @@
"php": "^5.6.20 || ^7.0.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
},
"require-dev": {
"phpunit/phpunit": "5.7.27 || 6.5.14 || 7.5.20 || 8.5.41"
"phpunit/phpunit": "5.7.27 || 6.5.14 || 7.5.20 || 8.5.41",
"rawr/cross-data-providers": "^2.0.0"
},
"suggest": {
"ext-mbstring": "for parsing UTF-8 CSS"
@@ -4953,9 +4954,9 @@
],
"support": {
"issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues",
"source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.8.0"
"source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.9.0"
},
"time": "2025-03-23T17:59:05+00:00"
"time": "2025-07-11T13:20:48+00:00"
},
{
"name": "socialiteproviders/discord",
@@ -5325,80 +5326,6 @@
],
"time": "2025-07-07T11:55:59+00:00"
},
{
"name": "ssddanbrown/symfony-mailer",
"version": "7.2.x-dev",
"source": {
"type": "git",
"url": "https://github.com/ssddanbrown/symfony-mailer.git",
"reference": "e9de8dccd76a63fc23475016e6574da6f5f12a2d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ssddanbrown/symfony-mailer/zipball/e9de8dccd76a63fc23475016e6574da6f5f12a2d",
"reference": "e9de8dccd76a63fc23475016e6574da6f5f12a2d",
"shasum": ""
},
"require": {
"egulias/email-validator": "^2.1.10|^3|^4",
"php": ">=8.2",
"psr/event-dispatcher": "^1",
"psr/log": "^1|^2|^3",
"symfony/event-dispatcher": "^6.4|^7.0",
"symfony/mime": "^7.2",
"symfony/service-contracts": "^2.5|^3"
},
"conflict": {
"symfony/http-client-contracts": "<2.5",
"symfony/http-kernel": "<6.4",
"symfony/messenger": "<6.4",
"symfony/mime": "<6.4",
"symfony/twig-bridge": "<6.4"
},
"replace": {
"symfony/mailer": "^7.0"
},
"require-dev": {
"symfony/console": "^6.4|^7.0",
"symfony/http-client": "^6.4|^7.0",
"symfony/messenger": "^6.4|^7.0",
"symfony/twig-bridge": "^6.4|^7.0"
},
"default-branch": true,
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Mailer\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Dan Brown",
"homepage": "https://danb.me"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Helps sending emails",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/ssddanbrown/symfony-mailer/tree/7.2"
},
"time": "2025-01-11T14:57:07+00:00"
},
{
"name": "symfony/clock",
"version": "v7.3.0",
@@ -6189,6 +6116,86 @@
],
"time": "2025-06-28T08:24:55+00:00"
},
{
"name": "symfony/mailer",
"version": "v7.3.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/mailer.git",
"reference": "b5db5105b290bdbea5ab27b89c69effcf1cb3368"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mailer/zipball/b5db5105b290bdbea5ab27b89c69effcf1cb3368",
"reference": "b5db5105b290bdbea5ab27b89c69effcf1cb3368",
"shasum": ""
},
"require": {
"egulias/email-validator": "^2.1.10|^3|^4",
"php": ">=8.2",
"psr/event-dispatcher": "^1",
"psr/log": "^1|^2|^3",
"symfony/event-dispatcher": "^6.4|^7.0",
"symfony/mime": "^7.2",
"symfony/service-contracts": "^2.5|^3"
},
"conflict": {
"symfony/http-client-contracts": "<2.5",
"symfony/http-kernel": "<6.4",
"symfony/messenger": "<6.4",
"symfony/mime": "<6.4",
"symfony/twig-bridge": "<6.4"
},
"require-dev": {
"symfony/console": "^6.4|^7.0",
"symfony/http-client": "^6.4|^7.0",
"symfony/messenger": "^6.4|^7.0",
"symfony/twig-bridge": "^6.4|^7.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Mailer\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Helps sending emails",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/mailer/tree/v7.3.1"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-06-27T19:55:54+00:00"
},
{
"name": "symfony/mime",
"version": "v7.3.0",
@@ -8131,16 +8138,16 @@
},
{
"name": "larastan/larastan",
"version": "v3.5.0",
"version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/larastan/larastan.git",
"reference": "e8ccd73008487ba91da9877b373f8c447743f1ce"
"reference": "6431d010dd383a9279eb8874a76ddb571738564a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/larastan/larastan/zipball/e8ccd73008487ba91da9877b373f8c447743f1ce",
"reference": "e8ccd73008487ba91da9877b373f8c447743f1ce",
"url": "https://api.github.com/repos/larastan/larastan/zipball/6431d010dd383a9279eb8874a76ddb571738564a",
"reference": "6431d010dd383a9279eb8874a76ddb571738564a",
"shasum": ""
},
"require": {
@@ -8208,7 +8215,7 @@
],
"support": {
"issues": "https://github.com/larastan/larastan/issues",
"source": "https://github.com/larastan/larastan/tree/v3.5.0"
"source": "https://github.com/larastan/larastan/tree/v3.6.0"
},
"funding": [
{
@@ -8216,7 +8223,7 @@
"type": "github"
}
],
"time": "2025-06-19T22:41:50+00:00"
"time": "2025-07-11T06:52:52+00:00"
},
{
"name": "mockery/mockery",
@@ -8580,16 +8587,16 @@
},
{
"name": "phpstan/phpstan",
"version": "2.1.17",
"version": "2.1.20",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "89b5ef665716fa2a52ecd2633f21007a6a349053"
"reference": "a9ccfef95210f92ba6feea6e8d1eef42b5605499"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/89b5ef665716fa2a52ecd2633f21007a6a349053",
"reference": "89b5ef665716fa2a52ecd2633f21007a6a349053",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/a9ccfef95210f92ba6feea6e8d1eef42b5605499",
"reference": "a9ccfef95210f92ba6feea6e8d1eef42b5605499",
"shasum": ""
},
"require": {
@@ -8634,7 +8641,7 @@
"type": "github"
}
],
"time": "2025-05-21T20:55:28+00:00"
"time": "2025-07-26T20:45:26+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -8973,16 +8980,16 @@
},
{
"name": "phpunit/phpunit",
"version": "11.5.26",
"version": "11.5.27",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "4ad8fe263a0b55b54a8028c38a18e3c5bef312e0"
"reference": "446d43867314781df7e9adf79c3ec7464956fd8f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4ad8fe263a0b55b54a8028c38a18e3c5bef312e0",
"reference": "4ad8fe263a0b55b54a8028c38a18e3c5bef312e0",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/446d43867314781df7e9adf79c3ec7464956fd8f",
"reference": "446d43867314781df7e9adf79c3ec7464956fd8f",
"shasum": ""
},
"require": {
@@ -8992,7 +8999,7 @@
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
"myclabs/deep-copy": "^1.13.1",
"myclabs/deep-copy": "^1.13.3",
"phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1",
"php": ">=8.2",
@@ -9054,7 +9061,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.26"
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.27"
},
"funding": [
{
@@ -9078,7 +9085,7 @@
"type": "tidelift"
}
],
"time": "2025-07-04T05:58:21+00:00"
"time": "2025-07-11T04:10:06+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -10318,9 +10325,7 @@
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
"ssddanbrown/symfony-mailer": 20
},
"stability-flags": {},
"prefer-stable": true,
"prefer-lowest": false,
"platform": {

View File

@@ -24,6 +24,7 @@ class ImportFactory extends Factory
'path' => 'uploads/files/imports/' . Str::random(10) . '.zip',
'name' => $this->faker->words(3, true),
'type' => 'book',
'size' => rand(1, 1001),
'metadata' => '{"name": "My book"}',
'created_at' => User::factory(),
];

View File

@@ -0,0 +1,4 @@
{
"parent_type": "book",
"parent_id": 28
}

View File

@@ -0,0 +1,10 @@
{
"type": "chapter",
"name": "Pension Providers",
"created_by": 1,
"size": 2757,
"path": "uploads\/files\/imports\/ghnxmS3u9QxLWu82.zip",
"updated_at": "2025-07-18T14:50:27.000000Z",
"created_at": "2025-07-18T14:50:27.000000Z",
"id": 31
}

View File

@@ -0,0 +1,23 @@
{
"data": [
{
"id": 25,
"name": "IT Department",
"size": 618462,
"type": "book",
"created_by": 1,
"created_at": "2024-12-20T18:40:38.000000Z",
"updated_at": "2024-12-20T18:40:38.000000Z"
},
{
"id": 27,
"name": "Clients",
"size": 15364,
"type": "chapter",
"created_by": 1,
"created_at": "2025-03-20T12:41:44.000000Z",
"updated_at": "2025-03-20T12:41:44.000000Z"
}
],
"total": 2
}

View File

@@ -0,0 +1,51 @@
{
"id": 25,
"name": "IT Department",
"path": "uploads\/files\/imports\/7YOpZ6sGIEbYdRFL.zip",
"size": 618462,
"type": "book",
"created_by": 1,
"created_at": "2024-12-20T18:40:38.000000Z",
"updated_at": "2024-12-20T18:40:38.000000Z",
"details": {
"id": 4,
"name": "IT Department",
"chapters": [
{
"id": 3,
"name": "Server Systems",
"priority": 1,
"pages": [
{
"id": 22,
"name": "prod-aws-stonehawk",
"priority": 0,
"attachments": [],
"images": [],
"tags": []
}
],
"tags": []
}
],
"pages": [
{
"id": 23,
"name": "Member Onboarding Guide",
"priority": 0,
"attachments": [],
"images": [],
"tags": []
},
{
"id": 25,
"name": "IT Holiday Party Event",
"priority": 2,
"attachments": [],
"images": [],
"tags": []
}
],
"tags": []
}
}

View File

@@ -0,0 +1,14 @@
{
"id": 1067,
"book_id": 28,
"slug": "pension-providers",
"name": "Pension Providers",
"description": "Details on the various pension providers that are available",
"priority": 7,
"created_at": "2025-07-18T14:53:35.000000Z",
"updated_at": "2025-07-18T14:53:36.000000Z",
"created_by": 1,
"updated_by": 1,
"owned_by": 1,
"default_template_id": null
}

View File

@@ -13,7 +13,7 @@ const entryPoints = {
app: path.join(__dirname, '../../resources/js/app.ts'),
code: path.join(__dirname, '../../resources/js/code/index.mjs'),
'legacy-modes': path.join(__dirname, '../../resources/js/code/legacy-modes.mjs'),
markdown: path.join(__dirname, '../../resources/js/markdown/index.mjs'),
markdown: path.join(__dirname, '../../resources/js/markdown/index.mts'),
wysiwyg: path.join(__dirname, '../../resources/js/wysiwyg/index.ts'),
};

View File

@@ -1 +1 @@
866bc8d0890e1bd814b1a2a55058f4eecd86dab836d3eb5f23a93885afc43610
ecb1c038267dde9336e703e14a89d43848880ebb630465e313b4726570f2db04

View File

@@ -345,7 +345,7 @@ Link: tj/co
codemirror
License: MIT
License File: node_modules/codemirror/LICENSE
Copyright: Copyright (C) 2018-2021 by Marijn Haverbeke <*******@*****.***> and others
Copyright: Copyright (C) 2018-2021 by Marijn Haverbeke <******@*********.******> and others
Source: https://github.com/codemirror/basic-setup.git
Link: https://github.com/codemirror/basic-setup.git
-----------
@@ -711,13 +711,13 @@ eslint-scope
License: BSD-2-Clause
License File: node_modules/eslint-scope/LICENSE
Copyright: Copyright (C) 2012-2013 Yusuke Suzuki (twitter: @Constellation) and other contributors.
Source: eslint/js
Source: https://github.com/eslint/js.git
Link: https://github.com/eslint/js/blob/main/packages/eslint-scope/README.md
-----------
eslint-visitor-keys
License: Apache-2.0
License File: node_modules/eslint-visitor-keys/LICENSE
Source: eslint/js
Source: https://github.com/eslint/js.git
Link: https://github.com/eslint/js/blob/main/packages/eslint-visitor-keys/README.md
-----------
eslint
@@ -731,7 +731,7 @@ License: BSD-2-Clause
License File: node_modules/espree/LICENSE
Copyright: Copyright (c) Open JS Foundation
All rights reserved.
Source: eslint/js
Source: https://github.com/eslint/js.git
Link: https://github.com/eslint/js/blob/main/packages/espree/README.md
-----------
esprima
@@ -1252,6 +1252,13 @@ Copyright: Copyright (c) 2019 Inspect JS
Source: git+https://github.com/inspect-js/is-map.git
Link: https://github.com/inspect-js/is-map#readme
-----------
is-negative-zero
License: MIT
License File: node_modules/is-negative-zero/LICENSE
Copyright: Copyright (c) 2014 Jordan Harband
Source: git://github.com/inspect-js/is-negative-zero.git
Link: https://github.com/inspect-js/is-negative-zero
-----------
is-number-object
License: MIT
License File: node_modules/is-number-object/LICENSE
@@ -2493,6 +2500,13 @@ Copyright: Copyright (c) 2016-2022 Isaac Z. Schlueter <*@***.**>, James Talmage
Source: tapjs/stack-utils
Link: tapjs/stack-utils
-----------
stop-iteration-iterator
License: MIT
License File: node_modules/stop-iteration-iterator/LICENSE
Copyright: Copyright (c) 2023 Jordan Harband
Source: git+https://github.com/ljharb/stop-iteration-iterator.git
Link: https://github.com/ljharb/stop-iteration-iterator#readme
-----------
string-length
License: MIT
License File: node_modules/string-length/license
@@ -2992,6 +3006,13 @@ Copyright: Copyright (c) 2014-present Sebastian McKenzie and other contributors
Source: https://github.com/babel/babel.git
Link: https://github.com/babel/babel.git
-----------
@babel/helper-globals
License: MIT
License File: node_modules/@babel/helper-globals/LICENSE
Copyright: Copyright (c) 2014-present Sebastian McKenzie and other contributors
Source: https://github.com/babel/babel.git
Link: https://github.com/babel/babel.git
-----------
@babel/helper-module-imports
License: MIT
License File: node_modules/@babel/helper-module-imports/LICENSE
@@ -3038,7 +3059,7 @@ Link: https://github.com/babel/babel.git
License: MIT
License File: node_modules/@babel/helpers/LICENSE
Copyright: Copyright (c) 2014-present Sebastian McKenzie and other contributors
Copyright (c) 2014-present, Facebook, Inc. (ONLY ./src/helpers/regeneratorRuntime.js)
Copyright (c) 2014-present, Facebook, Inc. (ONLY ./src/helpers/regenerator* files)
Source: https://github.com/babel/babel.git
Link: https://babel.dev/docs/en/next/babel-helpers
-----------
@@ -3233,7 +3254,7 @@ Link: https://github.com/codemirror/lang-javascript.git
@codemirror/lang-json
License: MIT
License File: node_modules/@codemirror/lang-json/LICENSE
Copyright: Copyright (C) 2018-2021 by Marijn Haverbeke <*******@*****.***> and others
Copyright: Copyright (C) 2018-2021 by Marijn Haverbeke <******@*********.******> and others
Source: https://github.com/codemirror/lang-json.git
Link: https://github.com/codemirror/lang-json.git
-----------
@@ -3247,7 +3268,7 @@ Link: https://github.com/codemirror/lang-markdown.git
@codemirror/lang-php
License: MIT
License File: node_modules/@codemirror/lang-php/LICENSE
Copyright: Copyright (C) 2018-2021 by Marijn Haverbeke <*******@*****.***> and others
Copyright: Copyright (C) 2018-2021 by Marijn Haverbeke <******@*********.******> and others
Source: https://github.com/codemirror/lang-php.git
Link: https://github.com/codemirror/lang-php.git
-----------
@@ -3337,7 +3358,7 @@ Link: https://github.com/eslint-community/regexpp#readme
License: Apache-2.0
License File: node_modules/@eslint/config-array/LICENSE
Source: git+https://github.com/eslint/rewrite.git
Link: https://github.com/eslint/rewrite#readme
Link: https://github.com/eslint/rewrite/tree/main/packages/config-array#readme
-----------
@eslint/config-helpers
License: Apache-2.0
@@ -3349,7 +3370,7 @@ Link: https://github.com/eslint/rewrite/tree/main/packages/config-helpers#readme
License: Apache-2.0
License File: node_modules/@eslint/core/LICENSE
Source: git+https://github.com/eslint/rewrite.git
Link: https://github.com/eslint/rewrite#readme
Link: https://github.com/eslint/rewrite/tree/main/packages/core#readme
-----------
@eslint/eslintrc
License: MIT
@@ -3373,7 +3394,7 @@ Link: https://github.com/eslint/rewrite#readme
License: Apache-2.0
License File: node_modules/@eslint/plugin-kit/LICENSE
Source: git+https://github.com/eslint/rewrite.git
Link: https://github.com/eslint/rewrite#readme
Link: https://github.com/eslint/rewrite/tree/main/packages/plugin-kit#readme
-----------
@humanfs/core
License: Apache-2.0
@@ -3514,9 +3535,9 @@ Link: https://github.com/jestjs/jest.git
@jridgewell/gen-mapping
License: MIT
License File: node_modules/@jridgewell/gen-mapping/LICENSE
Copyright: Copyright 2022 Justin Ridgewell <**********@******.***>
Source: https://github.com/jridgewell/gen-mapping
Link: https://github.com/jridgewell/gen-mapping
Copyright: Copyright 2024 Justin Ridgewell <******@*********.****>
Source: git+https://github.com/jridgewell/sourcemaps.git
Link: https://github.com/jridgewell/sourcemaps/tree/main/packages/gen-mapping
-----------
@jridgewell/resolve-uri
License: MIT
@@ -3525,26 +3546,19 @@ Copyright: Copyright 2019 Justin Ridgewell <**********@******.***>
Source: https://github.com/jridgewell/resolve-uri
Link: https://github.com/jridgewell/resolve-uri
-----------
@jridgewell/set-array
License: MIT
License File: node_modules/@jridgewell/set-array/LICENSE
Copyright: Copyright 2022 Justin Ridgewell <**********@******.***>
Source: https://github.com/jridgewell/set-array
Link: https://github.com/jridgewell/set-array
-----------
@jridgewell/sourcemap-codec
License: MIT
License File: node_modules/@jridgewell/sourcemap-codec/LICENSE
Copyright: Copyright (c) 2015 Rich Harris
Source: git+https://github.com/jridgewell/sourcemap-codec.git
Link: git+https://github.com/jridgewell/sourcemap-codec.git
Copyright: Copyright 2024 Justin Ridgewell <******@*********.****>
Source: git+https://github.com/jridgewell/sourcemaps.git
Link: https://github.com/jridgewell/sourcemaps/tree/main/packages/sourcemap-codec
-----------
@jridgewell/trace-mapping
License: MIT
License File: node_modules/@jridgewell/trace-mapping/LICENSE
Copyright: Copyright 2022 Justin Ridgewell <******@*********.****>
Source: git+https://github.com/jridgewell/trace-mapping.git
Link: git+https://github.com/jridgewell/trace-mapping.git
Copyright: Copyright 2024 Justin Ridgewell <******@*********.****>
Source: git+https://github.com/jridgewell/sourcemaps.git
Link: https://github.com/jridgewell/sourcemaps/tree/main/packages/trace-mapping
-----------
@lezer/common
License: MIT
@@ -3813,6 +3827,27 @@ License: MIT
Source: https://www.github.com/DefinitelyTyped/DefinitelyTyped.git
Link: https://www.github.com/DefinitelyTyped/DefinitelyTyped.git
-----------
@types/linkify-it
License: MIT
License File: node_modules/@types/linkify-it/LICENSE
Copyright: Copyright (c) Microsoft Corporation.
Source: https://github.com/DefinitelyTyped/DefinitelyTyped.git
Link: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/linkify-it
-----------
@types/markdown-it
License: MIT
License File: node_modules/@types/markdown-it/LICENSE
Copyright: Copyright (c) Microsoft Corporation.
Source: https://github.com/DefinitelyTyped/DefinitelyTyped.git
Link: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/markdown-it
-----------
@types/mdurl
License: MIT
License File: node_modules/@types/mdurl/LICENSE
Copyright: Copyright (c) Microsoft Corporation.
Source: https://github.com/DefinitelyTyped/DefinitelyTyped.git
Link: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/mdurl
-----------
@types/node
License: MIT
License File: node_modules/@types/node/LICENSE

View File

@@ -543,13 +543,6 @@ Copyright: Copyright (c) 2024 Nathan Herald, Rohland de Charmoy, Dan Brown
Source: https://codeberg.org/danb/HtmlDiff
Link: https://codeberg.org/danb/HtmlDiff
-----------
ssddanbrown/symfony-mailer
License: MIT
License File: vendor/ssddanbrown/symfony-mailer/LICENSE
Copyright: Copyright (c) 2019-present Fabien Potencier
Source: https://github.com/ssddanbrown/symfony-mailer.git
Link: https://symfony.com
-----------
symfony/clock
License: MIT
License File: vendor/symfony/clock/LICENSE
@@ -620,6 +613,13 @@ Copyright: Copyright (c) 2004-present Fabien Potencier
Source: https://github.com/symfony/http-kernel.git
Link: https://symfony.com
-----------
symfony/mailer
License: MIT
License File: vendor/symfony/mailer/LICENSE
Copyright: Copyright (c) 2019-present Fabien Potencier
Source: https://github.com/symfony/mailer.git
Link: https://symfony.com
-----------
symfony/mime
License: MIT
License File: vendor/symfony/mime/LICENSE

View File

@@ -30,8 +30,8 @@ return [
'create' => 'إنشاء',
'update' => 'تحديث',
'edit' => 'تعديل',
'archive' => 'Archive',
'unarchive' => 'Un-Archive',
'archive' => 'أرشف',
'unarchive' => 'إلغاء الأرشفة',
'sort' => 'سرد',
'move' => 'نقل',
'copy' => 'نسخ',

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'نص مرتفع',
'subscript' => 'نص منخفض',
'text_color' => 'لون النص',
'highlight_color' => 'لون التمييز',
'custom_color' => 'لون مخصص',
'remove_color' => 'إزالة اللون',
'background_color' => 'لون الخلفية',

View File

@@ -248,7 +248,7 @@ return [
'pages_edit_switch_to_markdown_stable' => '(محتوى مستقر)',
'pages_edit_switch_to_wysiwyg' => 'التبديل إلى محرر ما تراه هو ما تحصل عليه -WYSIWYG-',
'pages_edit_switch_to_new_wysiwyg' => 'التبديل إلى محرر ما تراه هو ما تحصل عليه الجديد -new WYSIWYG-',
'pages_edit_switch_to_new_wysiwyg_desc' => '(In Beta Testing)',
'pages_edit_switch_to_new_wysiwyg_desc' => '(في الاختبار التجريبي)',
'pages_edit_set_changelog' => 'تثبيت سجل التعديل',
'pages_edit_enter_changelog_desc' => 'ضع وصف مختصر للتعديلات التي تمت',
'pages_edit_enter_changelog' => 'أدخل سجل التعديل',
@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'إدخال رسمة',
'pages_md_show_preview' => 'عرض المعاينة',
'pages_md_sync_scroll' => 'مزامنة معاينة التمرير',
'pages_md_plain_editor' => 'محرر النصوص العادي',
'pages_drawing_unsaved' => 'تم العثور على رسم غير محفوظ',
'pages_drawing_unsaved_confirm' => 'تم العثور على بيانات رسم غير محفوظة من محاولة حفظ رسم سابقة فاشلة. هل ترغب في استعادة هذا الرسم غير المحفوظ ومواصلة تحريره؟',
'pages_not_in_chapter' => 'صفحة ليست في فصل',

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'Горен индекс',
'subscript' => 'Долен индекс',
'text_color' => 'Цвят на текста',
'highlight_color' => 'Highlight color',
'custom_color' => 'Цвят по избор',
'remove_color' => 'Премахване на цвят',
'background_color' => 'Фонов цвят',

View File

@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'Вмъкни рисунка',
'pages_md_show_preview' => 'Show preview',
'pages_md_sync_scroll' => 'Sync preview scroll',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'Unsaved Drawing Found',
'pages_drawing_unsaved_confirm' => 'Unsaved drawing data was found from a previous failed drawing save attempt. Would you like to restore and continue editing this unsaved drawing?',
'pages_not_in_chapter' => 'Страницата не принадлежи в никоя глава',

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'Superscript',
'subscript' => 'Subscript',
'text_color' => 'Text color',
'highlight_color' => 'Highlight color',
'custom_color' => 'Custom color',
'remove_color' => 'Remove color',
'background_color' => 'Background color',

View File

@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'Insert Drawing',
'pages_md_show_preview' => 'Show preview',
'pages_md_sync_scroll' => 'Sync preview scroll',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'Unsaved Drawing Found',
'pages_drawing_unsaved_confirm' => 'Unsaved drawing data was found from a previous failed drawing save attempt. Would you like to restore and continue editing this unsaved drawing?',
'pages_not_in_chapter' => 'Page is not in a chapter',

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'Superscript',
'subscript' => 'Subscript',
'text_color' => 'Text color',
'highlight_color' => 'Highlight color',
'custom_color' => 'Custom color',
'remove_color' => 'Remove color',
'background_color' => 'Background color',

View File

@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'Insert Drawing',
'pages_md_show_preview' => 'Show preview',
'pages_md_sync_scroll' => 'Sync preview scroll',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'Unsaved Drawing Found',
'pages_drawing_unsaved_confirm' => 'Unsaved drawing data was found from a previous failed drawing save attempt. Would you like to restore and continue editing this unsaved drawing?',
'pages_not_in_chapter' => 'Page is not in a chapter',

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'Superíndex',
'subscript' => 'Subíndex',
'text_color' => 'Color del text',
'highlight_color' => 'Highlight color',
'custom_color' => 'Color personalitzat',
'remove_color' => 'Elimina el color',
'background_color' => 'Color de fons',

View File

@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'Insereix un dibuix',
'pages_md_show_preview' => 'Mostra la visualització prèvia',
'pages_md_sync_scroll' => 'Sincronitza el desplaçament de la visualització prèvia',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'Sha trobat un dibuix sense desar',
'pages_drawing_unsaved_confirm' => 'Shan trobat dades dun dibuix dun intent anterior de desar un dibuix. Voleu restaurar aquest dibuix no desat per a reprendren ledició?',
'pages_not_in_chapter' => 'La pàgina no és un capítol',

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'horní index',
'subscript' => 'Dolní index',
'text_color' => 'Barva textu:',
'highlight_color' => 'Highlight color',
'custom_color' => 'Vlastní barva',
'remove_color' => 'Odstranit barvu',
'background_color' => 'Barva pozadí',

View File

@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'Vložit kresbu',
'pages_md_show_preview' => 'Zobrazit náhled',
'pages_md_sync_scroll' => 'Synchronizovat náhled',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'Nalezen neuložený výkres',
'pages_drawing_unsaved_confirm' => 'Byly nalezeny neuložené kresby z předchozí neúspěšné pokusu o uložení kresby. Chcete je obnovit a pokračovat v úpravě této neuložené kresby?',
'pages_not_in_chapter' => 'Stránka není v kapitole',
@@ -395,7 +396,7 @@ return [
'comment_none' => 'Žádné komentáře k zobrazení',
'comment_placeholder' => 'Zde zadejte komentář',
'comment_thread_count' => '{0}:count vláken komentářů|{1}:count vlákno komentářů|[2,4]:count vlákna komentářů|[5,*]:count vláken komentářů',
'comment_archived_count' => ':count archivováno',
'comment_archived_count' => '[0,1]:count archivováno|[2,4]:count archivována|[5,*]:count archivováno',
'comment_archived_threads' => 'Archivovaná vlákna',
'comment_save' => 'Uložit komentář',
'comment_new' => 'Nový komentář',

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'Uwchysgrif',
'subscript' => 'Isysgrif',
'text_color' => 'Lliw testun',
'highlight_color' => 'Highlight color',
'custom_color' => 'Lliw addasu',
'remove_color' => 'Dileu lliw',
'background_color' => 'Lliw cefnder',

View File

@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'Mewnosod Llun',
'pages_md_show_preview' => 'Dangos rhagolwg',
'pages_md_sync_scroll' => 'Cydamseru sgrôl ragolwg',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'Canfuwyd Llun heb ei Gadw',
'pages_drawing_unsaved_confirm' => 'Canfuwyd data llun heb ei gadw o ymgais aflwyddiannus blaenorol i gadw llun. Hoffech chi adfer a pharhau i olygu\'r llun heb ei gadw?',
'pages_not_in_chapter' => 'Nid yw\'r dudalen mewn pennod',

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'Hævet',
'subscript' => 'Sænket',
'text_color' => 'Tekstfarve',
'highlight_color' => 'Highlight color',
'custom_color' => 'Tilpasset farve',
'remove_color' => 'Fjern farve',
'background_color' => 'Baggrundsfarve',

View File

@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'Indsæt tegning',
'pages_md_show_preview' => 'Vis forhåndsvisning',
'pages_md_sync_scroll' => 'Rulning af forhåndsvisning af synkronisering',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'Ikke gemt tegning fundet',
'pages_drawing_unsaved_confirm' => 'Der blev fundet ikke-gemte tegningsdata fra et tidligere mislykket forsøg på at gemme en tegning. Vil du gendanne og fortsætte med at redigere denne ikke-gemte tegning?',
'pages_not_in_chapter' => 'Side er ikke i et kapitel',

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'Hochgestellt',
'subscript' => 'Tiefgestellt',
'text_color' => 'Schriftfarbe',
'highlight_color' => 'Highlight color',
'custom_color' => 'Benutzerdefinierte Farbe',
'remove_color' => 'Farbe entfernen',
'background_color' => 'Hintergrundfarbe',

View File

@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'Zeichnung einfügen',
'pages_md_show_preview' => 'Vorschau anzeigen',
'pages_md_sync_scroll' => 'Vorschau synchronisieren',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'Ungespeicherte Zeichnung gefunden',
'pages_drawing_unsaved_confirm' => 'Es wurden ungespeicherte Zeichnungsdaten von einem früheren, fehlgeschlagenen Versuch, die Zeichnung zu speichern, gefunden. Möchten Sie diese ungespeicherte Zeichnung wiederherstellen und weiter bearbeiten?',
'pages_not_in_chapter' => 'Seite ist in keinem Kapitel',

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'Hochgestellt',
'subscript' => 'Tiefgestellt',
'text_color' => 'Textfarbe',
'highlight_color' => 'Highlight color',
'custom_color' => 'Benutzerdefinierte Farbe',
'remove_color' => 'Farbe entfernen',
'background_color' => 'Hintergrundfarbe',

View File

@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'Zeichnung einfügen',
'pages_md_show_preview' => 'Vorschau anzeigen',
'pages_md_sync_scroll' => 'Vorschau synchronisieren',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'Ungespeicherte Zeichnung gefunden',
'pages_drawing_unsaved_confirm' => 'Es wurden ungespeicherte Zeichnungsdaten von einem früheren, fehlgeschlagenen Versuch, die Zeichnung zu speichern, gefunden. Möchtest du diese ungespeicherte Zeichnung wiederherstellen und weiter bearbeiten?',
'pages_not_in_chapter' => 'Seite ist in keinem Kapitel',

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'Εκθέτης',
'subscript' => 'Δείκτης',
'text_color' => 'Χρώμα κειμένου',
'highlight_color' => 'Highlight color',
'custom_color' => 'Προσαρμογή χρώματος',
'remove_color' => 'Αφαίρεση χρώματος',
'background_color' => 'Χρώμα φόντου',

View File

@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'Εισαγωγή Σχεδίου',
'pages_md_show_preview' => 'Εμφάνιση προεπισκόπησης',
'pages_md_sync_scroll' => 'Συγχρονισμός προεπισκόπησης',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'Unsaved Drawing Found',
'pages_drawing_unsaved_confirm' => 'Unsaved drawing data was found from a previous failed drawing save attempt. Would you like to restore and continue editing this unsaved drawing?',
'pages_not_in_chapter' => 'Η σελίδα δεν είναι σε κεφάλαιο',

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'Superscript',
'subscript' => 'Subscript',
'text_color' => 'Text color',
'highlight_color' => 'Highlight color',
'custom_color' => 'Custom color',
'remove_color' => 'Remove color',
'background_color' => 'Background color',

View File

@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'Insert Drawing',
'pages_md_show_preview' => 'Show preview',
'pages_md_sync_scroll' => 'Sync preview scroll',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'Unsaved Drawing Found',
'pages_drawing_unsaved_confirm' => 'Unsaved drawing data was found from a previous failed drawing save attempt. Would you like to restore and continue editing this unsaved drawing?',
'pages_not_in_chapter' => 'Page is not in a chapter',

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'Superíndice',
'subscript' => 'Subíndice',
'text_color' => 'Color de texto',
'highlight_color' => 'Highlight color',
'custom_color' => 'Color personalizado',
'remove_color' => 'Eliminar color',
'background_color' => 'Color de fondo',

View File

@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'Insertar Dibujo',
'pages_md_show_preview' => 'Mostrar vista previa',
'pages_md_sync_scroll' => 'Sincronizar desplazamiento de vista previa',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'Encontrado dibujo sin guardar',
'pages_drawing_unsaved_confirm' => 'Se encontraron datos no guardados del dibujo de un intento de guardado fallido. ¿Desea restaurar y continuar editando el dibujo no guardado?',
'pages_not_in_chapter' => 'La página no está en un capítulo',

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'Superíndice',
'subscript' => 'Subíndice',
'text_color' => 'Color del texto',
'highlight_color' => 'Highlight color',
'custom_color' => 'Color personalizado',
'remove_color' => 'Eliminar color',
'background_color' => 'Color de fondo',

View File

@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'Insertar Dibujo',
'pages_md_show_preview' => 'Mostrar vista previa',
'pages_md_sync_scroll' => 'Sincronizar desplazamiento de vista previa',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'Encontrado dibujo sin guardar',
'pages_drawing_unsaved_confirm' => 'Se encontraron datos del dibujo no guardados durante un intento de guardado fallido anterior. ¿Desea restaurar y continuar editando el dibujo no guardado?',
'pages_not_in_chapter' => 'La página no esá en el capítulo',

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'Ülaindeks',
'subscript' => 'Alaindeks',
'text_color' => 'Teksti värv',
'highlight_color' => 'Highlight color',
'custom_color' => 'Kohandatud värv',
'remove_color' => 'Eemalda värv',
'background_color' => 'Taustavärv',

View File

@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'Lisa joonis',
'pages_md_show_preview' => 'Näita eelvaadet',
'pages_md_sync_scroll' => 'Sünkrooni eelvaate kerimine',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'Leiti salvestamata joonis',
'pages_drawing_unsaved_confirm' => 'Varasemast ebaõnnestunud salvestuskatsest leiti salvestamata joonis. Kas soovid salvestamata joonise taastada ja selle muutmist jätkata?',
'pages_not_in_chapter' => 'Leht ei kuulu peatüki alla',

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'Gain-eskripta',
'subscript' => 'Azpi-script',
'text_color' => 'Testuaren kolorea',
'highlight_color' => 'Highlight color',
'custom_color' => 'Kolore pertsonalizatua',
'remove_color' => 'Kolorea ezabatu',
'background_color' => 'Atzeko planoaren kolorea',

View File

@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'Txertatu marrazki berria',
'pages_md_show_preview' => 'Show preview',
'pages_md_sync_scroll' => 'Sync preview scroll',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'Unsaved Drawing Found',
'pages_drawing_unsaved_confirm' => 'Unsaved drawing data was found from a previous failed drawing save attempt. Would you like to restore and continue editing this unsaved drawing?',
'pages_not_in_chapter' => 'Page is not in a chapter',

View File

@@ -6,7 +6,7 @@
return [
// Pages
'page_create' => 'تاریخ ایجاد',
'page_create' => 'صفحه ایجاد شد',
'page_create_notification' => 'صفحه با موفقیت ایجاد شد',
'page_update' => 'به روزرسانی صفحه',
'page_update_notification' => 'صفحه با موفقیت به روزرسانی شد',
@@ -85,12 +85,12 @@ return [
'webhook_delete_notification' => 'وب هوک با موفقیت حذف شد',
// Imports
'import_create' => 'created import',
'import_create_notification' => 'Import successfully uploaded',
'import_run' => 'updated import',
'import_run_notification' => 'Content successfully imported',
'import_delete' => 'deleted import',
'import_delete_notification' => 'Import successfully deleted',
'import_create' => 'ورودی ایجاد شد',
'import_create_notification' => 'فایل با موفقیت آپلود شد',
'import_run' => 'آیتم واردشده بروزرسانی شد',
'import_run_notification' => 'محتوا با موفقیت انتقال یافت',
'import_delete' => 'آیتم ورودی حدف شده',
'import_delete_notification' => 'آیتم واردشده با موفقیت حذف شد',
// Users
'user_create' => 'کاربر ایجاد شده',
@@ -128,12 +128,12 @@ return [
'comment_delete' => 'نظر حذف شده',
// Sort Rules
'sort_rule_create' => 'created sort rule',
'sort_rule_create_notification' => 'Sort rule successfully created',
'sort_rule_update' => 'updated sort rule',
'sort_rule_update_notification' => 'Sort rule successfully updated',
'sort_rule_delete' => 'deleted sort rule',
'sort_rule_delete_notification' => 'Sort rule successfully deleted',
'sort_rule_create' => 'قانون مرتب‌سازی ایجاد شد',
'sort_rule_create_notification' => 'قانون مرتب‌سازی با موفقیت ایجاد شد',
'sort_rule_update' => 'قانون مرتب‌سازی به‌روزرسانی شد',
'sort_rule_update_notification' => 'قانون مرتب‌سازی با موفقیت به‌روزرسانی شد',
'sort_rule_delete' => 'قانون مرتب‌سازی حذف شد',
'sort_rule_delete_notification' => 'قانون مرتب‌سازی با موفقیت حذف شد',
// Other
'permissions_update' => 'به روزرسانی مجوزها',

View File

@@ -91,7 +91,7 @@ return [
'mfa_option_totp_title' => 'برنامه ی موبایل',
'mfa_option_totp_desc' => 'برای استفاده از احراز هویت چند عاملی به یک برنامه موبایلی نیاز دارید که از TOTP پشتیبانی کند، مانند Google Authenticator، Authy یا Microsoft Authenticator.',
'mfa_option_backup_codes_title' => 'کدهای پشتیبان',
'mfa_option_backup_codes_desc' => 'Generates a set of one-time-use backup codes which you\'ll enter on login to verify your identity. Make sure to store these in a safe & secure place.',
'mfa_option_backup_codes_desc' => 'این فرایند مجموعه‌ای از کدهای پشتیبان یک‌بار مصرف تولید می‌کند که هنگام ورود به سامانه جهت تأیید هویت باید از آن‌ها استفاده کنید. توصیه می‌شود این کدها را در محلّی امن و محفوظ نگهداری نمایید.',
'mfa_gen_confirm_and_enable' => 'تایید و فعال کنید',
'mfa_gen_backup_codes_title' => 'راه اندازی کدهای پشتیبان',
'mfa_gen_backup_codes_desc' => 'لیست کدهای زیر را در مکانی امن ذخیره کنید. هنگام دسترسی به سیستم، می توانید از یکی از کدها به عنوان مکانیزم احراز هویت دوم استفاده کنید.',

View File

@@ -30,8 +30,8 @@ return [
'create' => 'ایجاد',
'update' => 'به‌روز رسانی',
'edit' => 'ويرايش',
'archive' => 'Archive',
'unarchive' => 'Un-Archive',
'archive' => 'انتقال به بایگانی',
'unarchive' => 'فعّال‌سازی دوباره (خروج از بایگانی)',
'sort' => 'مرتب سازی',
'move' => 'جابجایی',
'copy' => 'کپی',
@@ -111,5 +111,5 @@ return [
'terms_of_service' => 'شرایط خدمات',
// OpenSearch
'opensearch_description' => 'Search :appName',
'opensearch_description' => 'جست‌وجو در :appName',
];

View File

@@ -34,8 +34,8 @@ return [
'image_delete_success' => 'تصویر با موفقیت حذف شد',
'image_replace' => 'جایگزینی تصویر',
'image_replace_success' => 'تصویر با موفقیت به روز شد',
'image_rebuild_thumbs' => 'Regenerate Size Variations',
'image_rebuild_thumbs_success' => 'Image size variations successfully rebuilt!',
'image_rebuild_thumbs' => 'بازتولید اندازه‌های گوناگونی از تصویر',
'image_rebuild_thumbs_success' => 'اندازه‌های گوناگونی از تصویر با موفقیت بازتولید شدند.',
// Code Editor
'code_editor' => 'ویرایش کد',

View File

@@ -13,7 +13,7 @@ return [
'cancel' => 'لغو',
'save' => 'ذخیره',
'close' => 'بستن',
'apply' => 'Apply',
'apply' => 'اعمال',
'undo' => 'برگشت',
'redo' => 'از نو',
'left' => 'چپ',
@@ -48,6 +48,7 @@ return [
'superscript' => 'بالانویسی',
'subscript' => 'پایین نویسی',
'text_color' => 'رنگ متن',
'highlight_color' => 'Highlight color',
'custom_color' => 'رنگ دلخواه',
'remove_color' => 'حذف رنگ',
'background_color' => 'رنگ زمینه',
@@ -82,9 +83,9 @@ return [
'table_properties' => 'تنظیمات جدول',
'table_properties_title' => 'تنظیمات جدول',
'delete_table' => 'حذف جدول',
'table_clear_formatting' => 'Clear table formatting',
'resize_to_contents' => 'Resize to contents',
'row_header' => 'Row header',
'table_clear_formatting' => 'حذف قالب‌بندی جدول',
'resize_to_contents' => 'تغییر اندازه بر اساس محتوا',
'row_header' => 'عنوان سطر',
'insert_row_before' => 'افزودن سطر به قبل',
'insert_row_after' => 'افزودن سطر به بعد',
'delete_row' => 'حذف سطر',
@@ -148,7 +149,7 @@ return [
'url' => 'آدرس',
'text_to_display' => 'متن جهت نمایش',
'title' => 'عنوان',
'browse_links' => 'Browse links',
'browse_links' => 'مرور پیوندها',
'open_link' => 'بازکردن لینک',
'open_link_in' => 'باز کردن لینک در ...',
'open_link_current' => 'پنجره کنونی',
@@ -165,8 +166,8 @@ return [
'about' => 'درباره ویرایشگر',
'about_title' => 'درباره ویرایشگر WYSIWYG',
'editor_license' => 'مجوز و حق کپی رایت ویرایشگر',
'editor_lexical_license' => 'This editor is built as a fork of :lexicalLink which is distributed under the MIT license.',
'editor_lexical_license_link' => 'Full license details can be found here.',
'editor_lexical_license' => 'این ویرایشگر بر پایه‌ی نسخه‌ای مشتق‌شده از «:lexicalLink» ساخته شده است که تحت مجوز MIT منتشر می‌شود.',
'editor_lexical_license_link' => 'جزئیات کامل مجوز را می‌توانید این‌جا مشاهده کنید.',
'editor_tiny_license' => 'این ویرایشگر توسط :tinyLink و تحت مجوز MIT ساخته شده است.',
'editor_tiny_license_link' => 'جزئیات کپی رایت و مجوز TinyMCE را می توانید در اینجا پیدا کنید.',
'save_continue' => 'ذخیره صفحه و ادامه',

View File

@@ -39,30 +39,30 @@ return [
'export_pdf' => 'فایل PDF',
'export_text' => 'پرونده متنی ساده',
'export_md' => 'راهنما مارک‌دون',
'export_zip' => 'Portable ZIP',
'default_template' => 'Default Page Template',
'default_template_explain' => 'Assign a page template that will be used as the default content for all pages created within this item. Keep in mind this will only be used if the page creator has view access to the chosen template page.',
'default_template_select' => 'Select a template page',
'import' => 'Import',
'import_validate' => 'Validate Import',
'import_desc' => 'Import books, chapters & pages using a portable zip export from the same, or a different, instance. Select a ZIP file to proceed. After the file has been uploaded and validated you\'ll be able to configure & confirm the import in the next view.',
'import_zip_select' => 'Select ZIP file to upload',
'import_zip_validation_errors' => 'Errors were detected while validating the provided ZIP file:',
'import_pending' => 'Pending Imports',
'import_pending_none' => 'No imports have been started.',
'import_continue' => 'Continue Import',
'import_continue_desc' => 'Review the content due to be imported from the uploaded ZIP file. When ready, run the import to add its contents to this system. The uploaded ZIP import file will be automatically removed on successful import.',
'import_details' => 'Import Details',
'import_run' => 'Run Import',
'import_size' => ':size Import ZIP Size',
'import_uploaded_at' => 'Uploaded :relativeTime',
'import_uploaded_by' => 'Uploaded by',
'import_location' => 'Import Location',
'import_location_desc' => 'Select a target location for your imported content. You\'ll need the relevant permissions to create within the location you choose.',
'import_delete_confirm' => 'Are you sure you want to delete this import?',
'import_delete_desc' => 'This will delete the uploaded import ZIP file, and cannot be undone.',
'import_errors' => 'Import Errors',
'import_errors_desc' => 'The follow errors occurred during the import attempt:',
'export_zip' => 'فایل فشرده‌ی قابل‌حمل (ZIP)',
'default_template' => 'قالب پیش‌فرض صفحه',
'default_template_explain' => 'قالبی برای صفحه تعیین کنید که به‌عنوان محتوای پیش‌فرض در تمام صفحاتی که در این مورد ایجاد می‌شوند، به‌کار رود. توجه داشته باشید این قالب تنها در صورتی اعمال می‌شود که سازندهٔ صفحه به صفحهٔ قالب انتخاب‌شده دسترسی نمایشی داشته باشد.',
'default_template_select' => 'انتخاب صفحهٔ قالب',
'import' => 'وارد کردن',
'import_validate' => 'اعتبارسنجی آیتم‌های واردشده',
'import_desc' => 'می‌توانید کتاب‌ها، فصل‌ها و صفحات را با استفاده از یک فایل فشرده (ZIP) که از همین سامانه یا نمونه‌ای دیگر استخراج شده، وارد کنید. برای ادامه، یک فایل ZIP انتخاب نمایید. پس از بارگذاری و اعتبارسنجی فایل، در مرحله بعد می‌توانید تنظیمات انتقال را انجام داده و انتقال را تأیید کنید.',
'import_zip_select' => 'انتخاب فایل ZIP برای بارگذاری',
'import_zip_validation_errors' => 'هنگام اعتبارسنجی فایل ZIP ارائه‌شده، خطاهایی شناسایی شد:',
'import_pending' => 'ورودی‌های در انتظار انتقال',
'import_pending_none' => 'هیچ انتقال ورودی آغاز نشده است.',
'import_continue' => 'ادامه فرآیند انتقال ورودی',
'import_continue_desc' => 'محتوای فایل ZIP بارگذاری‌شده را که قرار است وارد سامانه شود، مرور کنید. پس از اطمینان از صحت آن، انتقال را آغاز نمایید تا محتوا به این سامانه افزوده شود. توجه داشته باشید که پس از انتقال موفق، فایل ZIP بارگذاری‌شده به‌صورت خودکار حذف خواهد شد.',
'import_details' => 'جزئیات انتقال ورودی',
'import_run' => 'شروع فرایند انتقال ورودی',
'import_size' => 'حجم فایل ZIP واردشده: :size',
'import_uploaded_at' => 'زمان بارگذاری: :relativeTime',
'import_uploaded_by' => 'بارگذاری شده توسط:',
'import_location' => 'مکان انتقال',
'import_location_desc' => 'برای محتوای واردشده، مقصدی انتخاب کنید. برای ایجاد محتوا در آن مقصد، داشتن مجوزهای لازم ضروری است.',
'import_delete_confirm' => 'مطمئن هستید که می‌خواهید آیتم واردشده را حدف کنید؟',
'import_delete_desc' => 'با انجام این کار، فایل ZIP واردشده حذف می‌شود و این عمل بازگشت‌ناپذیر است.',
'import_errors' => 'خطای انتقال ورودی',
'import_errors_desc' => 'در جریان تلاش برای انتقال ورودی، خطاهای زیر رخ داد:',
// Permissions and restrictions
'permissions' => 'مجوزها',
@@ -166,9 +166,9 @@ return [
'books_search_this' => 'این کتاب را جستجو کنید',
'books_navigation' => 'ناوبری کتاب',
'books_sort' => 'مرتب سازی مطالب کتاب',
'books_sort_desc' => 'Move chapters and pages within a book to reorganise its contents. Other books can be added which allows easy moving of chapters and pages between books. Optionally an auto sort rule can be set to automatically sort this book\'s contents upon changes.',
'books_sort_auto_sort' => 'Auto Sort Option',
'books_sort_auto_sort_active' => 'Auto Sort Active: :sortName',
'books_sort_desc' => 'برای سامان‌دهی محتوای یک کتاب، می‌توانید فصل‌ها و صفحات آن را جابه‌جا کنید. همچنین می‌توانید کتاب‌های دیگری بیفزایید تا جابه‌جایی فصل‌ها و صفحات میان کتاب‌ها آسان شود. در صورت تمایل، می‌توانید قاعده‌ای برای مرتب‌سازی خودکار تعیین کنید تا محتوای کتاب در صورت ایجاد تغییرات، به طور خودکار مرتب شود.',
'books_sort_auto_sort' => 'گزینه مرتب‌سازی خودکار',
'books_sort_auto_sort_active' => 'مرتب‌سازی خودکار با قاعده: :sortName فعال است',
'books_sort_named' => 'مرتب‌سازی کتاب:bookName',
'books_sort_name' => 'مرتب سازی بر اساس نام',
'books_sort_created' => 'مرتب سازی بر اساس تاریخ ایجاد',
@@ -230,7 +230,9 @@ return [
'pages_delete_draft' => 'حذف صفحه پیش نویس',
'pages_delete_success' => 'صفحه حذف شد',
'pages_delete_draft_success' => 'صفحه پیش نویس حذف شد',
'pages_delete_warning_template' => 'This page is in active use as a book or chapter default page template. These books or chapters will no longer have a default page template assigned after this page is deleted.',
'pages_delete_warning_template' => 'این صفحه هم‌اکنون به‌عنوان قالب پیش‌فرض صفحه برای یک کتاب یا فصل در حال استفاده است. پس از حذف این صفحه، کتاب‌ها یا فصل‌های مربوطه دیگر قالب پیش‌فرض صفحه نخواهند داشت.
',
'pages_delete_confirm' => 'آیا مطمئن هستید که می خواهید این صفحه را حذف کنید؟',
'pages_delete_draft_confirm' => 'آیا مطمئن هستید که می خواهید این صفحه پیش نویس را حذف کنید؟',
'pages_editing_named' => 'ویرایش صفحه :pageName',
@@ -247,8 +249,9 @@ return [
'pages_edit_switch_to_markdown_clean' => '(مطالب تمیز)',
'pages_edit_switch_to_markdown_stable' => '(محتوای پایدار)',
'pages_edit_switch_to_wysiwyg' => 'به ویرایشگر WYSIWYG بروید',
'pages_edit_switch_to_new_wysiwyg' => 'Switch to new WYSIWYG',
'pages_edit_switch_to_new_wysiwyg_desc' => '(In Beta Testing)',
'pages_edit_switch_to_new_wysiwyg' => 'تغییر به ویرایشگر جدید WYSIWYG
(ویرایشگر WYSIWYG: «آنچه می‌بینید همان است که به‌دست می‌آورید»)',
'pages_edit_switch_to_new_wysiwyg_desc' => '(در مرحله آزمایش بتا)',
'pages_edit_set_changelog' => 'تنظیم تغییرات',
'pages_edit_enter_changelog_desc' => 'توضیح مختصری از تغییراتی که ایجاد کرده اید وارد کنید',
'pages_edit_enter_changelog' => 'وارد کردن تغییرات',
@@ -268,6 +271,7 @@ return [
'pages_md_insert_drawing' => 'درج طرح',
'pages_md_show_preview' => 'دیدن پیش نمایش',
'pages_md_sync_scroll' => 'هماهنگ سازی اسکرول پیش نمایش',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'نقاشی ذخیره نشده پیدا شد',
'pages_drawing_unsaved_confirm' => 'نسخه‌ای ذخیره‌نشده از طراحی‌های قبلی پیدا شد. آیا می‌خواهید این طراحی ذخیره‌نشده را بازیابی کنید و به ویرایش آن ادامه دهید؟',
'pages_not_in_chapter' => 'صفحه در یک فصل نیست',
@@ -301,9 +305,9 @@ return [
'pages_pointer_enter_mode' => 'ورود به حالت انتخاب قسمت',
'pages_pointer_label' => 'گزینه‌های قسمت صفحه',
'pages_pointer_permalink' => 'لینک ثابت قسمت صفحه',
'pages_pointer_include_tag' => 'Page Section Include Tag',
'pages_pointer_toggle_link' => 'Permalink mode, Press to show include tag',
'pages_pointer_toggle_include' => 'Include tag mode, Press to show permalink',
'pages_pointer_include_tag' => 'افزودن برچسب برای این بخش از صفحه',
'pages_pointer_toggle_link' => 'حالت پیوند دائمی؛ برای مشاهده برچسب افزوده شده، کلیک کنید',
'pages_pointer_toggle_include' => 'حالت افزودن برچسب؛ برای نمایش پیوند دائمی کلیک کنید',
'pages_permissions_active' => 'مجوزهای صفحه فعال است',
'pages_initial_revision' => 'انتشار اولیه',
'pages_references_update_revision' => 'به‌روز‌رسانی خودکار لینک‌های داخلی سیستم',
@@ -324,7 +328,7 @@ return [
'pages_is_template' => 'الگوی صفحه',
// Editor Sidebar
'toggle_sidebar' => 'Toggle Sidebar',
'toggle_sidebar' => 'نمایش/پنهان‌سازی نوار کناری',
'page_tags' => 'برچسب‌های صفحه',
'chapter_tags' => 'برچسب‌های فصل',
'book_tags' => 'برچسب های کتاب',
@@ -392,11 +396,11 @@ return [
'comment' => 'اظهار نظر',
'comments' => 'نظرات',
'comment_add' => 'افزودن توضیح',
'comment_none' => 'No comments to display',
'comment_none' => 'نظری برای نمایش وجود ندارد',
'comment_placeholder' => 'اینجا نظر بدهید',
'comment_thread_count' => ':count Comment Thread|:count Comment Threads',
'comment_archived_count' => ':count Archived',
'comment_archived_threads' => 'Archived Threads',
'comment_thread_count' => ':count رشته گفت‌وگو',
'comment_archived_count' => ':count مورد بایگانی‌شده',
'comment_archived_threads' => 'رشته‌ گفت‌وگوهای بایگانی‌شده',
'comment_save' => 'ذخیره نظر',
'comment_new' => 'نظر جدید',
'comment_created' => ':createDiff نظر داد',
@@ -405,14 +409,14 @@ return [
'comment_deleted_success' => 'نظر حذف شد',
'comment_created_success' => 'نظر اضافه شد',
'comment_updated_success' => 'نظر به روز شد',
'comment_archive_success' => 'Comment archived',
'comment_unarchive_success' => 'Comment un-archived',
'comment_view' => 'View comment',
'comment_jump_to_thread' => 'Jump to thread',
'comment_archive_success' => 'نظر بایگانی شد',
'comment_unarchive_success' => 'نظر از بایگانی خارج شد',
'comment_view' => 'دیدن نظر',
'comment_jump_to_thread' => 'رفتن به رشته گفت‌وگو',
'comment_delete_confirm' => 'آیا مطمئن هستید که می خواهید این نظر را حذف کنید؟',
'comment_in_reply_to' => 'در پاسخ به :commentId',
'comment_reference' => 'Reference',
'comment_reference_outdated' => '(Outdated)',
'comment_reference' => 'مرجع',
'comment_reference_outdated' => '(نسخه قدیمی)',
'comment_editor_explain' => 'در اینجا نظراتی که در این صفحه گذاشته شده است، مشاهده می‌شود. نظرات را می‌توان در هنگام مشاهده صفحه ذخیره شده، اضافه و مدیریت کرد.',
// Revision

View File

@@ -18,10 +18,10 @@ return [
'ldap_fail_anonymous' => 'دسترسی LDAP با استفاده از صحافی ناشناس انجام نشد',
'ldap_fail_authed' => 'دسترسی به LDAP با استفاده از جزئیات داده شده و رمز عبور انجام نشد',
'ldap_extension_not_installed' => 'افزونه PHP LDAP نصب نشده است',
'ldap_cannot_connect' => 'اتصال به سرور LDAP امکان پذیر نیست، اتصال اولیه برقرار نشد',
'ldap_cannot_connect' => 'اتصال به سرور LDAP امکانپذیر نیست، اتصال اولیه برقرار نشد',
'saml_already_logged_in' => 'قبلا وارد سیستم شده اید',
'saml_no_email_address' => 'آدرس داده ای برای این کاربر در داده های ارائه شده توسط سیستم احراز هویت خارجی یافت نشد',
'saml_invalid_response_id' => 'درخواست از سیستم احراز هویت خارجی توسط فرایندی که توسط این نرم افزار آغاز شده است شناخته نمی شود. بازگشت به سیستم پس از ورود به سیستم می تواند باعث این مسئله شود.',
'saml_invalid_response_id' => 'درخواست ارسال‌شده از سامانه احراز هویت خارجی، توسط فرآیند آغازشده از سوی این نرمافزار شناسایی نشد. ممکن است بازگشت به صفحه قبل پس از ورود، موجب ایجاد این مشکل شده باشد.',
'saml_fail_authed' => 'ورود به سیستم :system انجام نشد، سیستم مجوز موفقیت آمیز ارائه نکرد',
'oidc_already_logged_in' => 'قبلا وارد شده اید',
'oidc_no_email_address' => 'آدرس ایمیلی برای این کاربر در داده های ارائه شده توسط سیستم احراز هویت خارجی یافت نشد',
@@ -43,7 +43,7 @@ return [
'path_not_writable' => 'مسیر فایل :filePath را نمی توان در آن آپلود کرد. مطمئن شوید که روی سرور قابل نوشتن است.',
'cannot_get_image_from_url' => 'نمی توان تصویر را از :url دریافت کرد',
'cannot_create_thumbs' => 'سرور نمی تواند تصاویر کوچک ایجاد کند. لطفاً بررسی کنید که پسوند GD PHP را نصب کرده اید.',
'server_upload_limit' => 'سرور اجازه آپلود در این اندازه را نمی دهد. لطفا اندازه فایل کوچکتر را امتحان کنید.',
'server_upload_limit' => 'سرور اجازه آپلود با این حجم را نمی دهد. لطفا فایلی با حجم کم‌تر را امتحان کنید.',
'server_post_limit' => 'سرور نمی‌تواند داده مقادیر ارائه شده داده را دریافت کند. با مقدار کمتر و فایل کوچکتر دوباره امتحان کنید.',
'uploaded' => 'سرور اجازه آپلود در این اندازه را نمی دهد. لطفا اندازه فایل کوچکتر را امتحان کنید.',
@@ -78,7 +78,7 @@ return [
// Users
'users_cannot_delete_only_admin' => 'شما نمی توانید تنها ادمین را حذف کنید',
'users_cannot_delete_guest' => 'شما نمی توانید کاربر مهمان را حذف کنید',
'users_could_not_send_invite' => 'Could not create user since invite email failed to send',
'users_could_not_send_invite' => 'امکان ایجاد کاربر وجود ندارد؛ زیرا ارسال ایمیل دعوت با خطا مواجه شد.',
// Roles
'role_cannot_be_edited' => 'این نقش قابل ویرایش نیست',
@@ -106,16 +106,16 @@ return [
'back_soon' => 'به زودی پشتیبان خواهد شد.',
// Import
'import_zip_cant_read' => 'Could not read ZIP file.',
'import_zip_cant_decode_data' => 'Could not find and decode ZIP data.json content.',
'import_zip_no_data' => 'ZIP file data has no expected book, chapter or page content.',
'import_validation_failed' => 'Import ZIP failed to validate with errors:',
'import_zip_failed_notification' => 'Failed to import ZIP file.',
'import_perms_books' => 'You are lacking the required permissions to create books.',
'import_perms_chapters' => 'You are lacking the required permissions to create chapters.',
'import_perms_pages' => 'You are lacking the required permissions to create pages.',
'import_perms_images' => 'You are lacking the required permissions to create images.',
'import_perms_attachments' => 'You are lacking the required permission to create attachments.',
'import_zip_cant_read' => 'امکان ایجاد کاربر وجود ندارد؛ زیرا ارسال ایمیل دعوت با خطا مواجه شد.',
'import_zip_cant_decode_data' => 'محتوای data.json در فایل ZIP پیدا یا رمزگشایی نشد.',
'import_zip_no_data' => 'داده‌های فایل ZIP فاقد محتوای کتاب، فصل یا صفحه مورد انتظار است.',
'import_validation_failed' => 'اعتبارسنجی فایل ZIP واردشده با خطا مواجه شد:',
'import_zip_failed_notification' => ' فایل ZIP وارد نشد.',
'import_perms_books' => 'شما مجوز لازم برای ایجاد کتاب را ندارید.',
'import_perms_chapters' => 'شما مجوز لازم برای ایجاد فصل را ندارید.',
'import_perms_pages' => 'شما مجوز لازم برای ایجاد صفحه را ندارید.',
'import_perms_images' => 'شما مجوز لازم برای ایجاد تصویر را ندارید.',
'import_perms_attachments' => 'شما مجوز لازم برای ایجاد پیوست را ندارید.',
// API errors
'api_no_authorization_found' => 'هیچ نشانه مجوزی در درخواست یافت نشد',

View File

@@ -22,6 +22,6 @@ return [
'action_view_comment' => 'مشاهده نظر',
'action_view_page' => 'مشاهده صفحه',
'footer_reason' => 'This notification was sent to you because :link cover this type of activity for this item.',
'footer_reason' => 'این اعلان برای شما ارسال شده است، زیرا پیوند (:link) فعالیتی از این نوع را برای این مورد پوشش می‌دهد.',
'footer_reason_link' => 'تنظیمات اطلاع‌رسانی شما',
];

View File

@@ -15,7 +15,7 @@ return [
// App Settings
'app_customization' => 'سفارشی‌سازی',
'app_features_security' => 'ویژگی‌ها و امنیت',
'app_name' => 'نام نرم افزار',
'app_name' => 'نام نرمافزار',
'app_name_desc' => 'این نام در هدر و در هر ایمیل ارسال شده توسط سیستم نشان داده شده است.',
'app_name_header' => 'نمایش نام در هدر',
'app_public_access' => 'دسترسی عمومی',
@@ -75,34 +75,34 @@ return [
'reg_confirm_restrict_domain_placeholder' => 'بدون محدودیت',
// Sorting Settings
'sorting' => 'Sorting',
'sorting_book_default' => 'Default Book Sort',
'sorting_book_default_desc' => 'Select the default sort rule to apply to new books. This won\'t affect existing books, and can be overridden per-book.',
'sorting_rules' => 'Sort Rules',
'sorting_rules_desc' => 'These are predefined sorting operations which can be applied to content in the system.',
'sort_rule_assigned_to_x_books' => 'Assigned to :count Book|Assigned to :count Books',
'sort_rule_create' => 'Create Sort Rule',
'sort_rule_edit' => 'Edit Sort Rule',
'sort_rule_delete' => 'Delete Sort Rule',
'sort_rule_delete_desc' => 'Remove this sort rule from the system. Books using this sort will revert to manual sorting.',
'sort_rule_delete_warn_books' => 'This sort rule is currently used on :count book(s). Are you sure you want to delete this?',
'sort_rule_delete_warn_default' => 'This sort rule is currently used as the default for books. Are you sure you want to delete this?',
'sort_rule_details' => 'Sort Rule Details',
'sort_rule_details_desc' => 'Set a name for this sort rule, which will appear in lists when users are selecting a sort.',
'sort_rule_operations' => 'Sort Operations',
'sort_rule_operations_desc' => 'Configure the sort actions to be performed by moving them from the list of available operations. Upon use, the operations will be applied in order, from top to bottom. Any changes made here will be applied to all assigned books upon save.',
'sort_rule_available_operations' => 'Available Operations',
'sort_rule_available_operations_empty' => 'No operations remaining',
'sort_rule_configured_operations' => 'Configured Operations',
'sort_rule_configured_operations_empty' => 'Drag/add operations from the "Available Operations" list',
'sort_rule_op_asc' => '(Asc)',
'sort_rule_op_desc' => '(Desc)',
'sort_rule_op_name' => 'Name - Alphabetical',
'sort_rule_op_name_numeric' => 'Name - Numeric',
'sort_rule_op_created_date' => 'Created Date',
'sort_rule_op_updated_date' => 'Updated Date',
'sort_rule_op_chapters_first' => 'Chapters First',
'sort_rule_op_chapters_last' => 'Chapters Last',
'sorting' => 'مرتب‌سازی',
'sorting_book_default' => 'مرتب‌سازی پیش‌فرض کتاب',
'sorting_book_default_desc' => 'قانون پیش‌فرض مرتب‌سازی را برای کتاب‌های جدید انتخاب کنید. تغییر قانون بر ترتیب کتاب‌های موجود تأثیری ندارد و می‌تواند برای هر کتاب به‌صورت جداگانه تغییر یابد.',
'sorting_rules' => 'قوانین مرتب‌سازی',
'sorting_rules_desc' => 'این‌ها عملیات مرتب‌سازی از پیش تعریف‌شده‌ای هستند که می‌توانید آن‌ها را بر محتوای سیستم اعمال کنید.',
'sort_rule_assigned_to_x_books' => 'اختصاص داده شده به :count کتاب',
'sort_rule_create' => 'ایجاد قانون مرتب‌سازی',
'sort_rule_edit' => 'ویرایش قانون مرتب‌سازی',
'sort_rule_delete' => 'حذف قانون مرتب‌سازی',
'sort_rule_delete_desc' => 'این قانون مرتب‌سازی را از سیستم حذف کنید. کتاب‌هایی که از این شیوه مرتب‌سازی استفاده می‌کنند، به حالت مرتب‌سازی دستی بازخواهند گشت.',
'sort_rule_delete_warn_books' => 'در حال حاضر این قانون مرتب‌سازی برای :count کتاب به‌کار می‌رود. آیا مطمئن هستید که می‌خواهید آن را حذف کنید؟',
'sort_rule_delete_warn_default' => 'این قانون مرتب‌سازی هم‌اکنون به عنوان پیش‌فرض کتاب‌ها تعیین شده است. آیا مطمئن هستید که می‌خواهید آن را حذف کنید؟',
'sort_rule_details' => 'جزئیات قانون مرتب‌سازی',
'sort_rule_details_desc' => 'برای این قانون مرتب‌سازی یک نام انتخاب کنید. این نام هنگام انتخاب شیوه مرتب‌سازی در فهرست‌ها نمایش داده خواهد شد.',
'sort_rule_operations' => 'عملیات مرتب‌سازی',
'sort_rule_operations_desc' => 'عملیات مرتب‌سازی را پیکربندی کنید. برای این منظور، آن‌ها را در فهرست عملیاتِ در دسترس جابه‌جا کنید تا ترتیب اجرای آن‌ها مشخص شود. هنگام استفاده، این عملیات به‌ترتیب از بالا به پایین اعمال خواهند شد. هر تغییری که در این بخش ایجاد کنید، پس از ذخیره، برای همه کتاب‌های اختصاص‌یافته اجرا می‌شود.',
'sort_rule_available_operations' => 'عملیات موجود',
'sort_rule_available_operations_empty' => 'عملیاتی باقی نمانده است',
'sort_rule_configured_operations' => 'عملیات پیکربندی‌شده',
'sort_rule_configured_operations_empty' => 'عملیات را از فهرست «عملیات موجود» حذف یا اضافه کنید',
'sort_rule_op_asc' => '(صعودی)',
'sort_rule_op_desc' => '(نزولی)',
'sort_rule_op_name' => 'نام - الفبایی',
'sort_rule_op_name_numeric' => 'نام - عددی',
'sort_rule_op_created_date' => 'تاریخ ایجاد',
'sort_rule_op_updated_date' => 'تاریخ به‌روزرسانی',
'sort_rule_op_chapters_first' => 'ابتدا فصل‌ها',
'sort_rule_op_chapters_last' => 'فصل‌ها در آخر',
// Maintenance settings
'maint' => 'نگهداری',
@@ -192,7 +192,7 @@ return [
'role_access_api' => 'دسترسی به API سیستم',
'role_manage_settings' => 'تنظیمات برنامه را مدیریت کنید',
'role_export_content' => 'صادرات محتوا',
'role_import_content' => 'Import content',
'role_import_content' => 'وارد کردن محتوا',
'role_editor_change' => 'تغییر ویرایشگر صفحه',
'role_notifications' => 'دریافت و مدیریت اعلان‌ها',
'role_asset' => 'مجوزهای دارایی',

View File

@@ -105,10 +105,10 @@ return [
'url' => ':attribute معتبر نمی‌باشد.',
'uploaded' => 'بارگذاری فایل :attribute موفقیت آمیز نبود.',
'zip_file' => 'The :attribute needs to reference a file within the ZIP.',
'zip_file_mime' => 'The :attribute needs to reference a file of type :validTypes, found :foundType.',
'zip_model_expected' => 'Data object expected but ":type" found.',
'zip_unique' => 'The :attribute must be unique for the object type within the ZIP.',
'zip_file' => 'ویژگی :attribute باید به یک فایل درون پرونده فشرده شده اشاره کند.',
'zip_file_mime' => 'ویژگی :attribute باید به فایلی با نوع :validTypes اشاره کند، اما نوع یافت‌شده :foundType است.',
'zip_model_expected' => 'سیستم در این بخش انتظار دریافت یک شیء داده‌ای را داشت، اما «:type» دریافت گردید',
'zip_unique' => 'برای هر نوع شیء در فایل ZIP، مقدار ویژگی :attribute باید یکتا و بدون تکرار باشد.',
// Custom validation lines
'custom' => [

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'Yläindeksi',
'subscript' => 'Alaindeksi',
'text_color' => 'Tekstin väri',
'highlight_color' => 'Highlight color',
'custom_color' => 'Mukautettu väri',
'remove_color' => 'Poista väri',
'background_color' => 'Taustaväri',

View File

@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'Lisää piirustus',
'pages_md_show_preview' => 'Näytä esikatselu',
'pages_md_sync_scroll' => 'Vieritä esikatselua koodin vierityksen mukaan',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'Tallentamaton piirustus löytyi',
'pages_drawing_unsaved_confirm' => 'Järjestelmä löysi tallentamattoman piirustuksen. Haluatko palauttaa piirustuksen ja jatkaa sen muokkaamista?',
'pages_not_in_chapter' => 'Sivu ei kuulu mihinkään lukuun',

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'Exposant',
'subscript' => 'Indice',
'text_color' => 'Couleur Texte',
'highlight_color' => 'Highlight color',
'custom_color' => 'Couleur personnalisée',
'remove_color' => 'Supprimer la couleur',
'background_color' => 'Couleur d\'arrière-plan',

View File

@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'Insérer un dessin',
'pages_md_show_preview' => 'Prévisualisation',
'pages_md_sync_scroll' => 'Défilement prévisualisation',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'Dessin non enregistré trouvé',
'pages_drawing_unsaved_confirm' => 'Des données de dessin non enregistrées ont été trouvées à partir d\'une tentative de sauvegarde de dessin échouée. Voulez-vous restaurer et continuer à modifier ce dessin non sauvegardé ?',
'pages_not_in_chapter' => 'La page n\'est pas dans un chapitre',

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'כתב עילי',
'subscript' => 'כתב תחתי',
'text_color' => 'צבע טקסט',
'highlight_color' => 'Highlight color',
'custom_color' => 'צבע מותאם',
'remove_color' => 'הסר צבע',
'background_color' => 'צבע רקע',

View File

@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'הכנס סרטוט',
'pages_md_show_preview' => 'Show preview',
'pages_md_sync_scroll' => 'Sync preview scroll',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'Unsaved Drawing Found',
'pages_drawing_unsaved_confirm' => 'Unsaved drawing data was found from a previous failed drawing save attempt. Would you like to restore and continue editing this unsaved drawing?',
'pages_not_in_chapter' => 'דף אינו חלק מפרק',

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'Gornji indeks',
'subscript' => 'Donji indeks',
'text_color' => 'Boja teksta',
'highlight_color' => 'Highlight color',
'custom_color' => 'Prilagođena boja',
'remove_color' => 'Ukloni boju',
'background_color' => 'Boja pozadine',

View File

@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'Umetni crtež',
'pages_md_show_preview' => 'Prikaži pregled',
'pages_md_sync_scroll' => 'Sinkroniziraj pomicanje pregleda',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'Pronađen je Nespremljen Crtež',
'pages_drawing_unsaved_confirm' => 'Pronađeni su nespremljeni podaci crteža iz prethodnog neuspjelog pokušaja spremanja crteža. Želite li obnoviti i nastaviti uređivati ovaj nespremljeni crtež?',
'pages_not_in_chapter' => 'Stranica nije u poglavlju',

View File

@@ -48,6 +48,7 @@ return [
'superscript' => 'Felső index',
'subscript' => 'Alsó index',
'text_color' => 'Szöveg szín',
'highlight_color' => 'Highlight color',
'custom_color' => 'Egyéni szín',
'remove_color' => 'Szín eltávolítása',
'background_color' => 'Háttérszín',

View File

@@ -268,6 +268,7 @@ return [
'pages_md_insert_drawing' => 'Rajz beillesztése',
'pages_md_show_preview' => 'Előnézet megjelenítése',
'pages_md_sync_scroll' => 'Előnézet pozíció szinkronizálása',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_drawing_unsaved' => 'Nem mentett rajz található',
'pages_drawing_unsaved_confirm' => 'A rendszer nem mentett rajzadatokat talált egy korábbi sikertelen rajzmentési kísérletből. Szeretné visszaállítani és folytatni a nem mentett rajz szerkesztését?',
'pages_not_in_chapter' => 'Az oldal nincs fejezetben',

View File

@@ -72,7 +72,7 @@ return [
'mfa_remove_method_notification' => 'Metode multi-faktor sukses dihapus',
// Settings
'settings_update' => 'updated settings',
'settings_update' => 'memperbarui setelan',
'settings_update_notification' => 'Pengaturan berhasil diperbarui',
'maintenance_action_run' => 'menjalankan tindakan pemeliharaan',
@@ -85,12 +85,12 @@ return [
'webhook_delete_notification' => 'Webhook berhasil dihapus',
// Imports
'import_create' => 'created import',
'import_create_notification' => 'Import successfully uploaded',
'import_run' => 'updated import',
'import_run_notification' => 'Content successfully imported',
'import_delete' => 'deleted import',
'import_delete_notification' => 'Import successfully deleted',
'import_create' => 'telat membuat impor',
'import_create_notification' => 'Impor berhasil diunggah',
'import_run' => 'telah memperbarui impor',
'import_run_notification' => 'Konten berhasil diimpor',
'import_delete' => 'telah menghapus impor',
'import_delete_notification' => 'Impor berhasil dihapus',
// Users
'user_create' => 'pengguna yang dibuat',
@@ -109,31 +109,31 @@ return [
'api_token_delete_notification' => 'token API berhasil dihapus ',
// Roles
'role_create' => 'created role',
'role_create' => 'telah membuat peran',
'role_create_notification' => 'Peran berhasil dibuat',
'role_update' => 'updated role',
'role_update' => 'telah memperbarui peran',
'role_update_notification' => 'Peran berhasil diperbarui',
'role_delete' => 'deleted role',
'role_delete' => 'telah menghapus peran',
'role_delete_notification' => 'Peran berhasil dihapus',
// Recycle Bin
'recycle_bin_empty' => 'emptied recycle bin',
'recycle_bin_restore' => 'restored from recycle bin',
'recycle_bin_destroy' => 'removed from recycle bin',
'recycle_bin_empty' => 'telah mengosongkan tempat sampah',
'recycle_bin_restore' => 'telah mengembalikan dari tempat sampah',
'recycle_bin_destroy' => 'telah menghapus dari tempat sampah',
// Comments
'commented_on' => 'berkomentar pada',
'comment_create' => 'added comment',
'comment_update' => 'updated comment',
'comment_delete' => 'deleted comment',
'comment_create' => 'telah menambah komentar',
'comment_update' => 'telah memperbarui komentar',
'comment_delete' => 'telah menghapus komentar',
// Sort Rules
'sort_rule_create' => 'created sort rule',
'sort_rule_create_notification' => 'Sort rule successfully created',
'sort_rule_update' => 'updated sort rule',
'sort_rule_update_notification' => 'Sort rule successfully updated',
'sort_rule_delete' => 'deleted sort rule',
'sort_rule_delete_notification' => 'Sort rule successfully deleted',
'sort_rule_create' => 'telah membuat aturan penyortiran',
'sort_rule_create_notification' => 'Aturan penyortiran berhasil dibuat',
'sort_rule_update' => 'telah mengubah aturan penyortiran',
'sort_rule_update_notification' => 'Aturan penyortiran berhasil diubah',
'sort_rule_delete' => 'telah menghapus aturan penyortiran',
'sort_rule_delete_notification' => 'Aturan penyortiran berhasil dihapus',
// Other
'permissions_update' => 'izin diperbarui',

View File

@@ -86,32 +86,32 @@ return [
'mfa_setup_configured' => 'Sudah dikonfigurasi',
'mfa_setup_reconfigure' => 'Konfigurasi ulang',
'mfa_setup_remove_confirmation' => 'Apakah Anda yakin ingin menghapus metode autentikasi multi-faktor ini?',
'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_setup_action' => 'Atur',
'mfa_backup_codes_usage_limit_warning' => 'Anda memiliki kurang dari 5 kode cadangan yang tersisa. Harap buat dan simpan set baru sebelum Anda kehabisan kode untuk mencegah akun Anda terkunci.',
'mfa_option_totp_title' => 'Aplikasi Seluler',
'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_totp_desc' => 'Untuk menggunakan autentikasi multi-faktor, Anda memerlukan aplikasi seluler yang mendukung TOTP seperti Google Authenticator, Authy, atau Microsoft Authenticator.',
'mfa_option_backup_codes_title' => 'Kode Cadangan',
'mfa_option_backup_codes_desc' => 'Generates a set of one-time-use backup codes which you\'ll enter on login to verify your identity. Make sure to store these in a safe & secure place.',
'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_option_backup_codes_desc' => 'Menghasilkan serangkaian kode cadangan sekali pakai yang akan Anda masukkan saat masuk untuk memverifikasi identitas Anda. Pastikan untuk menyimpannya di tempat yang aman.',
'mfa_gen_confirm_and_enable' => 'Konfirmasi dan Aktifkan',
'mfa_gen_backup_codes_title' => 'Pengaturan Kode Cadangan',
'mfa_gen_backup_codes_desc' => 'Simpan daftar kode di bawah ini di tempat yang aman. Saat mengakses sistem, Anda dapat menggunakan salah satu kode sebagai mekanisme autentikasi kedua.',
'mfa_gen_backup_codes_download' => 'Unduh Kode',
'mfa_gen_backup_codes_usage_warning' => 'Setiap kode hanya dapat digunakan satu kali',
'mfa_gen_totp_title' => 'Pengaturan Aplikasi Seluler',
'mfa_gen_totp_desc' => 'Untuk menggunakan autentikasi multi-faktor, Anda memerlukan aplikasi seluler yang mendukung TOTP seperti Google Authenticator, Authy, atau Microsoft Authenticator.',
'mfa_gen_totp_scan' => 'Pindai kode QR di bawah ini menggunakan aplikasi autentikasi pilihan Anda untuk memulai.',
'mfa_gen_totp_verify_setup' => 'Verifikasi Pengaturan',
'mfa_gen_totp_verify_setup_desc' => 'Verifikasi bahwa semuanya berfungsi dengan memasukkan kode yang dibuat dalam aplikasi autentikasi Anda pada kolom input di bawah ini:',
'mfa_gen_totp_provide_code_here' => 'Berikan kode yang dihasilkan aplikasi Anda di sini',
'mfa_verify_access' => 'Verifikasi Akses',
'mfa_verify_access_desc' => 'Akun pengguna Anda mengharuskan Anda mengonfirmasi identitas Anda melalui tingkat verifikasi tambahan sebelum Anda diberikan akses. Verifikasi menggunakan salah satu metode yang telah Anda konfigurasikan untuk melanjutkan.',
'mfa_verify_no_methods' => 'Tidak Ada Metode yang Dikonfigurasi',
'mfa_verify_no_methods_desc' => 'Tidak ada metode autentikasi multi-faktor yang ditemukan untuk akun Anda. Anda perlu menyiapkan setidaknya satu metode sebelum mendapatkan akses.',
'mfa_verify_use_totp' => 'Verifikasi menggunakan aplikasi seluler',
'mfa_verify_use_backup_codes' => 'Verifikasi menggunakan kode cadangan',
'mfa_verify_backup_code' => 'Kode Cadangan',
'mfa_verify_backup_code_desc' => 'Enter one of your remaining backup codes below:',
'mfa_verify_backup_code_enter_here' => 'Enter backup code here',
'mfa_verify_totp_desc' => 'Enter the code, generated using your mobile app, below:',
'mfa_setup_login_notification' => 'Multi-factor method configured, Please now login again using the configured method.',
'mfa_verify_backup_code_desc' => 'Masukkan salah satu kode cadangan Anda yang tersisa di bawah ini:',
'mfa_verify_backup_code_enter_here' => 'Masukkan kode cadangan di sini',
'mfa_verify_totp_desc' => 'Masukkan kode yang dibuat menggunakan aplikasi seluler Anda di bawah ini:',
'mfa_setup_login_notification' => 'Metode multi-faktor dikonfigurasi. Silakan masuk lagi menggunakan metode yang dikonfigurasi.',
];

View File

@@ -6,7 +6,7 @@ return [
// Buttons
'cancel' => 'Batal',
'close' => 'Close',
'close' => 'Tutup',
'confirm' => 'Konfirmasi',
'back' => 'Kembali',
'save' => 'Simpan',
@@ -20,18 +20,18 @@ return [
'description' => 'Deskripsi',
'role' => 'Peran',
'cover_image' => 'Sampul gambar',
'cover_image_description' => 'This image should be approximately 440x250px although it will be flexibly scaled & cropped to fit the user interface in different scenarios as required, so actual dimensions for display will differ.',
'cover_image_description' => 'Gambar ini harus berukuran sekitar 440x250px walaupun nanti akan disesuaikan & terpotong secara fleksibel agar sesuai dengan tampilan pengguna, sehingga dimensi sebenarnya untuk tampilan akan berbeda.',
// Actions
'actions' => 'Tindakan',
'view' => 'Lihat',
'view_all' => 'Lihat Semua',
'new' => 'New',
'new' => 'Buat Baru',
'create' => 'Buat',
'update' => 'Perbarui',
'edit' => 'Sunting',
'archive' => 'Archive',
'unarchive' => 'Un-Archive',
'archive' => 'Buat Arsip',
'unarchive' => 'Batalkan Arsip',
'sort' => 'Sortir',
'move' => 'Pindahkan',
'copy' => 'Salin',
@@ -43,18 +43,18 @@ return [
'reset' => 'Atur ulang',
'remove' => 'Hapus',
'add' => 'Tambah',
'configure' => 'Configure',
'manage' => 'Manage',
'configure' => 'Atur',
'manage' => 'Kelola',
'fullscreen' => 'Layar Penuh',
'favourite' => 'Favorit',
'unfavourite' => 'Batal favorit',
'next' => 'Selanjutnya',
'previous' => 'Sebelumnya',
'filter_active' => 'Active Filter:',
'filter_clear' => 'Clear Filter',
'download' => 'Download',
'open_in_tab' => 'Open in Tab',
'open' => 'Open',
'filter_active' => 'Filter Aktif:',
'filter_clear' => 'Hapus Filter',
'download' => 'Unduh',
'open_in_tab' => 'Buka di tab baru',
'open' => 'Buka',
// Sort Options
'sort_options' => 'Opsi Sortir',
@@ -80,20 +80,20 @@ return [
'default' => 'Bawaan',
'breadcrumb' => 'Breadcrumb',
'status' => 'Status',
'status_active' => 'Active',
'status_inactive' => 'Inactive',
'never' => 'Never',
'none' => 'None',
'status_active' => 'Aktif',
'status_inactive' => 'Tidak Aktif',
'never' => 'Jangan Pernah',
'none' => 'Tidak Satupun',
// Header
'homepage' => 'Homepage',
'homepage' => 'Beranda',
'header_menu_expand' => 'Perluas Menu Tajuk',
'profile_menu' => 'Menu Profil',
'view_profile' => 'Tampilkan Profil',
'edit_profile' => 'Sunting Profil',
'dark_mode' => 'Mode Gelap',
'light_mode' => 'Mode Terang',
'global_search' => 'Global Search',
'global_search' => 'Pencarian Global',
// Layout tabs
'tab_info' => 'Informasi',
@@ -111,5 +111,5 @@ return [
'terms_of_service' => 'Ketentuan Layanan',
// OpenSearch
'opensearch_description' => 'Search :appName',
'opensearch_description' => 'Cari :appName',
];

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