mirror of
https://github.com/BookStackApp/BookStack.git
synced 2026-02-05 16:49:47 +03:00
Compare commits
1 Commits
v25.07.2
...
drawio_ren
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9f5e98ba9 |
18
.github/translators.txt
vendored
18
.github/translators.txt
vendored
@@ -438,7 +438,7 @@ javadataherian :: Persian
|
||||
Ludo-code :: French
|
||||
hollsten :: Swedish
|
||||
Ngoc Lan Phung (lanpncz) :: Vietnamese
|
||||
Worive :: Catalan; French
|
||||
Worive :: Catalan
|
||||
Илья Скаба (skabailya) :: Russian
|
||||
Irjan Olsen (Irch) :: Norwegian Bokmal
|
||||
Aleksandar Jovanovic (jovanoviczaleksandar) :: Serbian (Cyrillic)
|
||||
@@ -489,19 +489,3 @@ Hari (muhhari) :: Indonesian
|
||||
仙君御 (xjy) :: Chinese Simplified
|
||||
TapioM :: Finnish
|
||||
lingb58 :: Chinese Traditional
|
||||
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
|
||||
João Faro (FaroJoaoFaro) :: Portuguese
|
||||
Danilo dos Santos Barbosa (bozochegou) :: Portuguese, Brazilian
|
||||
Chris (furesoft) :: German
|
||||
Silvia Isern (eiendragon) :: Catalan
|
||||
Dennis Kron Pedersen (ahjdp) :: Danish
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -8,10 +8,10 @@ Homestead.yaml
|
||||
.idea
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
/public/dist/*.map
|
||||
/public/dist
|
||||
/public/plugins
|
||||
/public/css/*.map
|
||||
/public/js/*.map
|
||||
/public/css
|
||||
/public/js
|
||||
/public/bower
|
||||
/public/build/
|
||||
/public/favicon.ico
|
||||
|
||||
@@ -57,13 +57,16 @@ class LdapSessionGuard extends ExternalBaseSessionGuard
|
||||
/**
|
||||
* Attempt to authenticate a user using the given credentials.
|
||||
*
|
||||
* @param array $credentials
|
||||
* @param bool $remember
|
||||
*
|
||||
* @throws LdapException
|
||||
* @throws LdapException*@throws \BookStack\Exceptions\JsonDebugException
|
||||
* @throws LoginAttemptException
|
||||
* @throws JsonDebugException
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function attempt(array $credentials = [], $remember = false): bool
|
||||
public function attempt(array $credentials = [], $remember = false)
|
||||
{
|
||||
$username = $credentials['username'];
|
||||
$userDetails = $this->ldapService->getUserDetails($username);
|
||||
|
||||
@@ -11,7 +11,6 @@ use BookStack\Entities\Tools\MixedEntityListLoader;
|
||||
use BookStack\Permissions\PermissionApplicator;
|
||||
use BookStack\Users\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
|
||||
class ActivityQueries
|
||||
@@ -68,7 +67,6 @@ class ActivityQueries
|
||||
|
||||
$activity = $query->orderBy('created_at', 'desc')
|
||||
->with(['loggable' => function (Relation $query) {
|
||||
/** @var MorphTo<Entity, Activity> $query */
|
||||
$query->withTrashed();
|
||||
}, 'user.avatar'])
|
||||
->skip($count * ($page - 1))
|
||||
|
||||
@@ -12,8 +12,6 @@ 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
|
||||
|
||||
@@ -20,8 +20,7 @@ class PageUpdateNotificationHandler extends BaseNotificationHandler
|
||||
throw new \InvalidArgumentException("Detail for page update notifications must be a page");
|
||||
}
|
||||
|
||||
// Get the last update from activity
|
||||
/** @var ?Activity $lastUpdate */
|
||||
// Get last update from activity
|
||||
$lastUpdate = $detail->activity()
|
||||
->where('type', '=', ActivityType::PAGE_UPDATE)
|
||||
->where('id', '!=', $activity->id)
|
||||
|
||||
@@ -3,15 +3,17 @@
|
||||
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
|
||||
{
|
||||
public function __construct(
|
||||
protected Entity $entity
|
||||
) {
|
||||
protected array $tags;
|
||||
|
||||
/**
|
||||
* @param Tag[] $tags
|
||||
*/
|
||||
public function __construct(array $tags)
|
||||
{
|
||||
$this->tags = $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -20,23 +22,14 @@ class TagClassGenerator
|
||||
public function generate(): array
|
||||
{
|
||||
$classes = [];
|
||||
$tags = $this->entity->tags->all();
|
||||
|
||||
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-'));
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,22 +41,6 @@ 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));
|
||||
|
||||
@@ -50,7 +50,7 @@ class WebhookFormatter
|
||||
}
|
||||
|
||||
if ($this->detail instanceof Model) {
|
||||
$data['related_item'] = $this->formatModel($this->detail);
|
||||
$data['related_item'] = $this->formatModel();
|
||||
}
|
||||
|
||||
return $data;
|
||||
@@ -83,8 +83,10 @@ class WebhookFormatter
|
||||
);
|
||||
}
|
||||
|
||||
protected function formatModel(Model $model): array
|
||||
protected function formatModel(): array
|
||||
{
|
||||
/** @var Model $model */
|
||||
$model = $this->detail;
|
||||
$model->unsetRelations();
|
||||
|
||||
foreach ($this->modelFormatters as $formatter) {
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
// 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 [
|
||||
|
||||
@@ -34,13 +33,13 @@ return [
|
||||
'transport' => 'smtp',
|
||||
'scheme' => null,
|
||||
'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
|
||||
'port' => $mailPort,
|
||||
'port' => env('MAIL_PORT', 587),
|
||||
'username' => env('MAIL_USERNAME'),
|
||||
'password' => env('MAIL_PASSWORD'),
|
||||
'verify_peer' => env('MAIL_VERIFY_SSL', true),
|
||||
'timeout' => null,
|
||||
'local_domain' => null,
|
||||
'require_tls' => ($mailEncryption === 'tls' || $mailEncryption === 'ssl' || $mailPort === 465),
|
||||
'tls_required' => ($mailEncryption === 'tls' || $mailEncryption === 'ssl'),
|
||||
],
|
||||
|
||||
'sendmail' => [
|
||||
|
||||
@@ -18,7 +18,6 @@ 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;
|
||||
@@ -264,9 +263,7 @@ class BookController extends Controller
|
||||
$this->checkPermission('bookshelf-create-all');
|
||||
$this->checkPermission('book-create-all');
|
||||
|
||||
$shelf = (new DatabaseTransaction(function () use ($book, $transformer) {
|
||||
return $transformer->transformBookToShelf($book);
|
||||
}))->run();
|
||||
$shelf = $transformer->transformBookToShelf($book);
|
||||
|
||||
return redirect($shelf->getUrl());
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace BookStack\Entities\Controllers;
|
||||
|
||||
use BookStack\Entities\Models\Book;
|
||||
use BookStack\Entities\Models\Chapter;
|
||||
use BookStack\Entities\Queries\ChapterQueries;
|
||||
use BookStack\Entities\Queries\EntityQueries;
|
||||
@@ -10,11 +9,12 @@ 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 array $rules = [
|
||||
protected $rules = [
|
||||
'create' => [
|
||||
'book_id' => ['required', 'integer'],
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
@@ -144,10 +144,7 @@ class ChapterApiController extends ApiController
|
||||
$chapter->load(['tags']);
|
||||
$chapter->makeVisible('description_html');
|
||||
$chapter->setAttribute('description_html', $chapter->descriptionHtml());
|
||||
|
||||
/** @var Book $book */
|
||||
$book = $chapter->book()->first();
|
||||
$chapter->setAttribute('book_slug', $book->slug);
|
||||
$chapter->setAttribute('book_slug', $chapter->book()->first()->slug);
|
||||
|
||||
return $chapter;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ 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;
|
||||
@@ -270,9 +269,7 @@ class ChapterController extends Controller
|
||||
$this->checkOwnablePermission('chapter-delete', $chapter);
|
||||
$this->checkPermission('book-create-all');
|
||||
|
||||
$book = (new DatabaseTransaction(function () use ($chapter, $transformer) {
|
||||
return $transformer->transformChapterToBook($chapter);
|
||||
}))->run();
|
||||
$book = $transformer->transformChapterToBook($chapter);
|
||||
|
||||
return redirect($book->getUrl());
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class PageApiController extends ApiController
|
||||
{
|
||||
protected array $rules = [
|
||||
protected $rules = [
|
||||
'create' => [
|
||||
'book_id' => ['required_without:chapter_id', 'integer'],
|
||||
'chapter_id' => ['required_without:book_id', 'integer'],
|
||||
|
||||
@@ -26,7 +26,6 @@ use BookStack\Users\Models\HasOwner;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
@@ -284,14 +283,10 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable
|
||||
public function getParent(): ?self
|
||||
{
|
||||
if ($this instanceof Page) {
|
||||
/** @var BelongsTo<Chapter|Book, Page> $builder */
|
||||
$builder = $this->chapter_id ? $this->chapter() : $this->book();
|
||||
return $builder->withTrashed()->first();
|
||||
return $this->chapter_id ? $this->chapter()->withTrashed()->first() : $this->book()->withTrashed()->first();
|
||||
}
|
||||
if ($this instanceof Chapter) {
|
||||
/** @var BelongsTo<Book, Page> $builder */
|
||||
$builder = $this->book();
|
||||
return $builder->withTrashed()->first();
|
||||
return $this->book()->withTrashed()->first();
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -300,7 +295,7 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable
|
||||
/**
|
||||
* Rebuild the permissions for this entity.
|
||||
*/
|
||||
public function rebuildPermissions(): void
|
||||
public function rebuildPermissions()
|
||||
{
|
||||
app()->make(JointPermissionBuilder::class)->rebuildForEntity(clone $this);
|
||||
}
|
||||
@@ -308,7 +303,7 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable
|
||||
/**
|
||||
* Index the current entity for search.
|
||||
*/
|
||||
public function indexForSearch(): void
|
||||
public function indexForSearch()
|
||||
{
|
||||
app()->make(SearchIndex::class)->indexEntity(clone $this);
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ class BaseRepo
|
||||
$entity->touch();
|
||||
}
|
||||
|
||||
$entity->rebuildPermissions();
|
||||
$entity->indexForSearch();
|
||||
$this->referenceStore->updateForEntity($entity);
|
||||
|
||||
@@ -138,7 +139,7 @@ class BaseRepo
|
||||
|
||||
/**
|
||||
* Sort the parent of the given entity, if any auto sort actions are set for it.
|
||||
* Typically ran during create/update/insert events.
|
||||
* Typical ran during create/update/insert events.
|
||||
*/
|
||||
public function sortParent(Entity $entity): void
|
||||
{
|
||||
|
||||
@@ -10,7 +10,6 @@ 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;
|
||||
|
||||
@@ -29,22 +28,19 @@ class BookRepo
|
||||
*/
|
||||
public function create(array $input): Book
|
||||
{
|
||||
return (new DatabaseTransaction(function () use ($input) {
|
||||
$book = new 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);
|
||||
|
||||
$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);
|
||||
$defaultBookSortSetting = intval(setting('sorting-book-default', '0'));
|
||||
if ($defaultBookSortSetting && SortRule::query()->find($defaultBookSortSetting)) {
|
||||
$book->sort_rule_id = $defaultBookSortSetting;
|
||||
$book->save();
|
||||
}
|
||||
|
||||
$defaultBookSortSetting = intval(setting('sorting-book-default', '0'));
|
||||
if ($defaultBookSortSetting && SortRule::query()->find($defaultBookSortSetting)) {
|
||||
$book->sort_rule_id = $defaultBookSortSetting;
|
||||
$book->save();
|
||||
}
|
||||
|
||||
return $book;
|
||||
}))->run();
|
||||
return $book;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,6 @@ 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
|
||||
@@ -24,14 +23,13 @@ class BookshelfRepo
|
||||
*/
|
||||
public function create(array $input, array $bookIds): Bookshelf
|
||||
{
|
||||
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();
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,37 +54,20 @@ class BookshelfRepo
|
||||
|
||||
/**
|
||||
* Update which books are assigned to this shelf by syncing the given book ids.
|
||||
* Function ensures the managed books are visible to the current user and existing,
|
||||
* and that the user does not alter the assignment of books that are not visible to them.
|
||||
* Function ensures the books are visible to the current user and existing.
|
||||
*/
|
||||
protected function updateBooks(Bookshelf $shelf, array $bookIds): void
|
||||
protected function updateBooks(Bookshelf $shelf, array $bookIds)
|
||||
{
|
||||
$numericIDs = collect($bookIds)->map(function ($id) {
|
||||
return intval($id);
|
||||
});
|
||||
|
||||
$existingBookIds = $shelf->books()->pluck('id')->toArray();
|
||||
$visibleExistingBookIds = $this->bookQueries->visibleForList()
|
||||
->whereIn('id', $existingBookIds)
|
||||
->pluck('id')
|
||||
->toArray();
|
||||
$nonVisibleExistingBookIds = array_values(array_diff($existingBookIds, $visibleExistingBookIds));
|
||||
|
||||
$newIdsToAssign = $this->bookQueries->visibleForList()
|
||||
$syncData = $this->bookQueries->visibleForList()
|
||||
->whereIn('id', $bookIds)
|
||||
->pluck('id')
|
||||
->toArray();
|
||||
|
||||
$maxNewIndex = max($numericIDs->keys()->toArray() ?: [0]);
|
||||
|
||||
$syncData = [];
|
||||
foreach ($newIdsToAssign as $id) {
|
||||
$syncData[$id] = ['order' => $numericIDs->search($id)];
|
||||
}
|
||||
|
||||
foreach ($nonVisibleExistingBookIds as $index => $id) {
|
||||
$syncData[$id] = ['order' => $maxNewIndex + ($index + 1)];
|
||||
}
|
||||
->mapWithKeys(function ($bookId) use ($numericIDs) {
|
||||
return [$bookId => ['order' => $numericIDs->search($bookId)]];
|
||||
});
|
||||
|
||||
$shelf->books()->sync($syncData);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ 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
|
||||
@@ -28,18 +27,16 @@ class ChapterRepo
|
||||
*/
|
||||
public function create(array $input, Book $parentBook): 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);
|
||||
$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;
|
||||
}))->run();
|
||||
return $chapter;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,14 +88,12 @@ class ChapterRepo
|
||||
throw new PermissionsException('User does not have permission to create a chapter within the chosen book');
|
||||
}
|
||||
|
||||
return (new DatabaseTransaction(function () use ($chapter, $parent) {
|
||||
$chapter->changeBook($parent->id);
|
||||
$chapter->rebuildPermissions();
|
||||
Activity::add(ActivityType::CHAPTER_MOVE, $chapter);
|
||||
$chapter->changeBook($parent->id);
|
||||
$chapter->rebuildPermissions();
|
||||
Activity::add(ActivityType::CHAPTER_MOVE, $chapter);
|
||||
|
||||
$this->baseRepo->sortParent($chapter);
|
||||
$this->baseRepo->sortParent($chapter);
|
||||
|
||||
return $parent;
|
||||
}))->run();
|
||||
return $parent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ use BookStack\Exceptions\PermissionsException;
|
||||
use BookStack\Facades\Activity;
|
||||
use BookStack\References\ReferenceStore;
|
||||
use BookStack\References\ReferenceUpdater;
|
||||
use BookStack\Util\DatabaseTransaction;
|
||||
use Exception;
|
||||
|
||||
class PageRepo
|
||||
@@ -62,10 +61,8 @@ class PageRepo
|
||||
]);
|
||||
}
|
||||
|
||||
(new DatabaseTransaction(function () use ($page) {
|
||||
$page->save();
|
||||
$page->refresh()->rebuildPermissions();
|
||||
}))->run();
|
||||
$page->save();
|
||||
$page->refresh()->rebuildPermissions();
|
||||
|
||||
return $page;
|
||||
}
|
||||
@@ -75,29 +72,26 @@ class PageRepo
|
||||
*/
|
||||
public function publishDraft(Page $draft, array $input): Page
|
||||
{
|
||||
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();
|
||||
$draft->draft = false;
|
||||
$draft->revision_count = 1;
|
||||
$draft->priority = $this->getNewPriority($draft);
|
||||
$this->updateTemplateStatusAndContentFromInput($draft, $input);
|
||||
$this->baseRepo->update($draft, $input);
|
||||
|
||||
$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;
|
||||
}))->run();
|
||||
return $draft;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 and reference regen) without performing an official update.
|
||||
* (Search index & reference regen) without performing an official update.
|
||||
*/
|
||||
public function setContentFromInput(Page $page, array $input): void
|
||||
{
|
||||
@@ -122,7 +116,7 @@ class PageRepo
|
||||
$page->revision_count++;
|
||||
$page->save();
|
||||
|
||||
// Remove all update drafts for this user and page.
|
||||
// Remove all update drafts for this user & page.
|
||||
$this->revisionRepo->deleteDraftsForCurrentUser($page);
|
||||
|
||||
// Save a revision after updating
|
||||
@@ -275,18 +269,16 @@ class PageRepo
|
||||
throw new PermissionsException('User does not have permission to create a page within the new parent');
|
||||
}
|
||||
|
||||
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();
|
||||
$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;
|
||||
}))->run();
|
||||
return $parent;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,12 +13,17 @@ use BookStack\Facades\Activity;
|
||||
|
||||
class HierarchyTransformer
|
||||
{
|
||||
public function __construct(
|
||||
protected BookRepo $bookRepo,
|
||||
protected BookshelfRepo $shelfRepo,
|
||||
protected Cloner $cloner,
|
||||
protected TrashCan $trashCan
|
||||
) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,7 +15,6 @@ 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;
|
||||
@@ -358,26 +357,25 @@ class TrashCan
|
||||
|
||||
/**
|
||||
* Destroy the given entity.
|
||||
* Returns the number of total entities destroyed in the operation.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function destroyEntity(Entity $entity): int
|
||||
{
|
||||
$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();
|
||||
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);
|
||||
}
|
||||
|
||||
return $result ?? 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
7
app/Exceptions/DrawioPngReaderException.php
Normal file
7
app/Exceptions/DrawioPngReaderException.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace BookStack\Exceptions;
|
||||
|
||||
class DrawioPngReaderException extends \Exception
|
||||
{
|
||||
}
|
||||
@@ -4,7 +4,6 @@ namespace BookStack\Exports\Controllers;
|
||||
|
||||
use BookStack\Entities\Queries\BookQueries;
|
||||
use BookStack\Exports\ExportFormatter;
|
||||
use BookStack\Exports\ZipExports\ZipExportBuilder;
|
||||
use BookStack\Http\ApiController;
|
||||
use Throwable;
|
||||
|
||||
@@ -64,15 +63,4 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace BookStack\Exports\Controllers;
|
||||
|
||||
use BookStack\Entities\Queries\ChapterQueries;
|
||||
use BookStack\Exports\ExportFormatter;
|
||||
use BookStack\Exports\ZipExports\ZipExportBuilder;
|
||||
use BookStack\Http\ApiController;
|
||||
use Throwable;
|
||||
|
||||
@@ -64,15 +63,4 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
@@ -89,7 +89,7 @@ class ImportController extends Controller
|
||||
try {
|
||||
$entity = $this->imports->runImport($import, $parent);
|
||||
} catch (ZipImportException $exception) {
|
||||
session()->forget(['success', 'warning']);
|
||||
session()->flush();
|
||||
$this->showErrorNotification(trans('errors.import_zip_failed_notification'));
|
||||
return redirect($import->getUrl())->with('import_errors', $exception->errors);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace BookStack\Exports\Controllers;
|
||||
|
||||
use BookStack\Entities\Queries\PageQueries;
|
||||
use BookStack\Exports\ExportFormatter;
|
||||
use BookStack\Exports\ZipExports\ZipExportBuilder;
|
||||
use BookStack\Http\ApiController;
|
||||
use Throwable;
|
||||
|
||||
@@ -64,15 +63,4 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,6 @@ class Import extends Model implements Loggable
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $hidden = ['metadata'];
|
||||
|
||||
public function getSizeString(): string
|
||||
{
|
||||
$mb = round($this->size / 1000000, 2);
|
||||
|
||||
@@ -17,7 +17,6 @@ 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;
|
||||
@@ -35,11 +34,6 @@ class ImportRepo
|
||||
* @return Collection<Import>
|
||||
*/
|
||||
public function getVisibleImports(): Collection
|
||||
{
|
||||
return $this->queryVisible()->get();
|
||||
}
|
||||
|
||||
public function queryVisible(): Builder
|
||||
{
|
||||
$query = Import::query();
|
||||
|
||||
@@ -47,7 +41,7 @@ class ImportRepo
|
||||
$query->where('created_by', user()->id);
|
||||
}
|
||||
|
||||
return $query;
|
||||
return $query->get();
|
||||
}
|
||||
|
||||
public function findVisible(int $id): Import
|
||||
|
||||
@@ -76,7 +76,7 @@ class ZipExportBuilder
|
||||
|
||||
$zipFile = tempnam(sys_get_temp_dir(), 'bszip-');
|
||||
$zip = new ZipArchive();
|
||||
$opened = $zip->open($zipFile, ZipArchive::OVERWRITE);
|
||||
$opened = $zip->open($zipFile, ZipArchive::CREATE);
|
||||
if ($opened !== true) {
|
||||
throw new ZipExportException('Failed to create zip file for export.');
|
||||
}
|
||||
|
||||
@@ -17,17 +17,17 @@ use BookStack\Uploads\Image;
|
||||
|
||||
class ZipExportReferences
|
||||
{
|
||||
/** @var array<int, ZipExportPage> */
|
||||
/** @var ZipExportPage[] */
|
||||
protected array $pages = [];
|
||||
/** @var array<int, ZipExportChapter> */
|
||||
/** @var ZipExportChapter[] */
|
||||
protected array $chapters = [];
|
||||
/** @var array<int, ZipExportBook> */
|
||||
/** @var ZipExportBook[] */
|
||||
protected array $books = [];
|
||||
|
||||
/** @var array<int, ZipExportAttachment> */
|
||||
/** @var ZipExportAttachment[] */
|
||||
protected array $attachments = [];
|
||||
|
||||
/** @var array<int, ZipExportImage> */
|
||||
/** @var ZipExportImage[] */
|
||||
protected array $images = [];
|
||||
|
||||
public function __construct(
|
||||
@@ -134,12 +134,11 @@ class ZipExportReferences
|
||||
|
||||
// Find and include images if in visibility
|
||||
$page = $model->getPage();
|
||||
$pageExportModel = $this->pages[$page->id] ?? ($exportModel instanceof ZipExportPage ? $exportModel : null);
|
||||
if (isset($this->images[$model->id]) || ($page && $pageExportModel && userCan('view', $page))) {
|
||||
if ($page && userCan('view', $page)) {
|
||||
if (!isset($this->images[$model->id])) {
|
||||
$exportImage = ZipExportImage::fromModel($model, $files);
|
||||
$this->images[$model->id] = $exportImage;
|
||||
$pageExportModel->images[] = $exportImage;
|
||||
$exportModel->images[] = $exportImage;
|
||||
}
|
||||
return "[[bsexport:image:{$model->id}]]";
|
||||
}
|
||||
|
||||
@@ -29,10 +29,7 @@ class ZipImportReferences
|
||||
/** @var Image[] */
|
||||
protected array $images = [];
|
||||
|
||||
/**
|
||||
* Mapping keyed by "type:old-reference-id" with values being the new imported equivalent model.
|
||||
* @var array<string, Model>
|
||||
*/
|
||||
/** @var array<string, Model> */
|
||||
protected array $referenceMap = [];
|
||||
|
||||
/** @var array<int, ZipExportPage> */
|
||||
@@ -111,22 +108,6 @@ class ZipImportReferences
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function replaceDrawingIdReferences(string $content): string
|
||||
{
|
||||
$referenceRegex = '/\sdrawio-diagram=[\'"](\d+)[\'"]/';
|
||||
|
||||
$result = preg_replace_callback($referenceRegex, function ($matches) {
|
||||
$key = 'image:' . $matches[1];
|
||||
$model = $this->referenceMap[$key] ?? null;
|
||||
if ($model instanceof Image && $model->type === 'drawio') {
|
||||
return ' drawio-diagram="' . $model->id . '"';
|
||||
}
|
||||
return $matches[0];
|
||||
}, $content);
|
||||
|
||||
return $result ?: $content;
|
||||
}
|
||||
|
||||
public function replaceReferences(): void
|
||||
{
|
||||
foreach ($this->books as $book) {
|
||||
@@ -153,9 +134,7 @@ class ZipImportReferences
|
||||
$exportPage = $this->zipExportPageMap[$page->id];
|
||||
$contentType = $exportPage->markdown ? 'markdown' : 'html';
|
||||
$content = $exportPage->markdown ?: ($exportPage->html ?: '');
|
||||
|
||||
$parsed = $this->parser->parseReferences($content, $this->handleReference(...));
|
||||
$parsed = $this->replaceDrawingIdReferences($parsed);
|
||||
|
||||
$this->pageRepo->setContentFromInput($page, [
|
||||
$contentType => $parsed,
|
||||
|
||||
@@ -8,7 +8,7 @@ use Illuminate\Http\JsonResponse;
|
||||
|
||||
abstract class ApiController extends Controller
|
||||
{
|
||||
protected array $rules = [];
|
||||
protected $rules = [];
|
||||
|
||||
/**
|
||||
* Provide a paginated listing JSON response in a standard format
|
||||
|
||||
@@ -16,7 +16,7 @@ class ContentPermissionApiController extends ApiController
|
||||
) {
|
||||
}
|
||||
|
||||
protected array $rules = [
|
||||
protected $rules = [
|
||||
'update' => [
|
||||
'owner_id' => ['int'],
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class JointPermissionBuilder
|
||||
/**
|
||||
* Re-generate all entity permission from scratch.
|
||||
*/
|
||||
public function rebuildForAll(): void
|
||||
public function rebuildForAll()
|
||||
{
|
||||
JointPermission::query()->truncate();
|
||||
|
||||
@@ -51,7 +51,7 @@ class JointPermissionBuilder
|
||||
/**
|
||||
* Rebuild the entity jointPermissions for a particular entity.
|
||||
*/
|
||||
public function rebuildForEntity(Entity $entity): void
|
||||
public function rebuildForEntity(Entity $entity)
|
||||
{
|
||||
$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): void
|
||||
protected function buildJointPermissionsForBooks(EloquentCollection $books, array $roles, bool $deleteOld = false)
|
||||
{
|
||||
$entities = clone $books;
|
||||
|
||||
@@ -143,7 +143,7 @@ class JointPermissionBuilder
|
||||
/**
|
||||
* Rebuild the entity jointPermissions for a collection of entities.
|
||||
*/
|
||||
protected function buildJointPermissionsForEntities(array $entities): void
|
||||
protected function buildJointPermissionsForEntities(array $entities)
|
||||
{
|
||||
$roles = Role::query()->get()->values()->all();
|
||||
$this->deleteManyJointPermissionsForEntities($entities);
|
||||
@@ -155,19 +155,21 @@ class JointPermissionBuilder
|
||||
*
|
||||
* @param Entity[] $entities
|
||||
*/
|
||||
protected function deleteManyJointPermissionsForEntities(array $entities): void
|
||||
protected function deleteManyJointPermissionsForEntities(array $entities)
|
||||
{
|
||||
$simpleEntities = $this->entitiesToSimpleEntities($entities);
|
||||
$idsByType = $this->entitiesToTypeIdMap($simpleEntities);
|
||||
|
||||
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();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,7 +195,7 @@ class JointPermissionBuilder
|
||||
* @param Entity[] $originalEntities
|
||||
* @param Role[] $roles
|
||||
*/
|
||||
protected function createManyJointPermissions(array $originalEntities, array $roles): void
|
||||
protected function createManyJointPermissions(array $originalEntities, array $roles)
|
||||
{
|
||||
$entities = $this->entitiesToSimpleEntities($originalEntities);
|
||||
$jointPermissions = [];
|
||||
@@ -223,9 +225,11 @@ class JointPermissionBuilder
|
||||
}
|
||||
}
|
||||
|
||||
foreach (array_chunk($jointPermissions, 1000) as $jointPermissionChunk) {
|
||||
DB::table('joint_permissions')->insert($jointPermissionChunk);
|
||||
}
|
||||
DB::transaction(function () use ($jointPermissions) {
|
||||
foreach (array_chunk($jointPermissions, 1000) as $jointPermissionChunk) {
|
||||
DB::table('joint_permissions')->insert($jointPermissionChunk);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,6 @@ 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
|
||||
@@ -41,9 +40,7 @@ class PermissionsController extends Controller
|
||||
$page = $this->queries->pages->findVisibleBySlugsOrFail($bookSlug, $pageSlug);
|
||||
$this->checkOwnablePermission('restrictions-manage', $page);
|
||||
|
||||
(new DatabaseTransaction(function () use ($page, $request) {
|
||||
$this->permissionsUpdater->updateFromPermissionsForm($page, $request);
|
||||
}))->run();
|
||||
$this->permissionsUpdater->updateFromPermissionsForm($page, $request);
|
||||
|
||||
$this->showSuccessNotification(trans('entities.pages_permissions_success'));
|
||||
|
||||
@@ -73,9 +70,7 @@ class PermissionsController extends Controller
|
||||
$chapter = $this->queries->chapters->findVisibleBySlugsOrFail($bookSlug, $chapterSlug);
|
||||
$this->checkOwnablePermission('restrictions-manage', $chapter);
|
||||
|
||||
(new DatabaseTransaction(function () use ($chapter, $request) {
|
||||
$this->permissionsUpdater->updateFromPermissionsForm($chapter, $request);
|
||||
}))->run();
|
||||
$this->permissionsUpdater->updateFromPermissionsForm($chapter, $request);
|
||||
|
||||
$this->showSuccessNotification(trans('entities.chapters_permissions_success'));
|
||||
|
||||
@@ -105,9 +100,7 @@ class PermissionsController extends Controller
|
||||
$book = $this->queries->books->findVisibleBySlugOrFail($slug);
|
||||
$this->checkOwnablePermission('restrictions-manage', $book);
|
||||
|
||||
(new DatabaseTransaction(function () use ($book, $request) {
|
||||
$this->permissionsUpdater->updateFromPermissionsForm($book, $request);
|
||||
}))->run();
|
||||
$this->permissionsUpdater->updateFromPermissionsForm($book, $request);
|
||||
|
||||
$this->showSuccessNotification(trans('entities.books_permissions_updated'));
|
||||
|
||||
@@ -137,9 +130,7 @@ class PermissionsController extends Controller
|
||||
$shelf = $this->queries->shelves->findVisibleBySlugOrFail($slug);
|
||||
$this->checkOwnablePermission('restrictions-manage', $shelf);
|
||||
|
||||
(new DatabaseTransaction(function () use ($shelf, $request) {
|
||||
$this->permissionsUpdater->updateFromPermissionsForm($shelf, $request);
|
||||
}))->run();
|
||||
$this->permissionsUpdater->updateFromPermissionsForm($shelf, $request);
|
||||
|
||||
$this->showSuccessNotification(trans('entities.shelves_permissions_updated'));
|
||||
|
||||
@@ -154,10 +145,7 @@ class PermissionsController extends Controller
|
||||
$shelf = $this->queries->shelves->findVisibleBySlugOrFail($slug);
|
||||
$this->checkOwnablePermission('restrictions-manage', $shelf);
|
||||
|
||||
$updateCount = (new DatabaseTransaction(function () use ($shelf) {
|
||||
return $this->permissionsUpdater->updateBookPermissionsFromShelf($shelf);
|
||||
}))->run();
|
||||
|
||||
$updateCount = $this->permissionsUpdater->updateBookPermissionsFromShelf($shelf);
|
||||
$this->showSuccessNotification(trans('entities.shelves_copy_permission_success', ['count' => $updateCount]));
|
||||
|
||||
return redirect($shelf->getUrl());
|
||||
|
||||
@@ -7,7 +7,6 @@ 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;
|
||||
|
||||
@@ -49,42 +48,38 @@ class PermissionsRepo
|
||||
*/
|
||||
public function saveNewRole(array $roleData): Role
|
||||
{
|
||||
return (new DatabaseTransaction(function () use ($roleData) {
|
||||
$role = new Role($roleData);
|
||||
$role->mfa_enforced = boolval($roleData['mfa_enforced'] ?? false);
|
||||
$role->save();
|
||||
$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;
|
||||
}))->run();
|
||||
return $role;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing role.
|
||||
* Ensures the Admin system role always has core permissions.
|
||||
* Ensures Admin system role always have core permissions.
|
||||
*/
|
||||
public function updateRole($roleId, array $roleData): Role
|
||||
{
|
||||
$role = $this->getRoleById($roleId);
|
||||
|
||||
return (new DatabaseTransaction(function () use ($role, $roleData) {
|
||||
if (isset($roleData['permissions'])) {
|
||||
$this->assignRolePermissions($role, $roleData['permissions']);
|
||||
}
|
||||
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;
|
||||
}))->run();
|
||||
return $role;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,7 +114,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 assigned to the current role
|
||||
* If a migration Role ID is specified the users assign to the current role
|
||||
* will be added to the role of the specified id.
|
||||
*
|
||||
* @throws PermissionsException
|
||||
@@ -136,19 +131,17 @@ class PermissionsRepo
|
||||
throw new PermissionsException(trans('errors.role_registration_default_cannot_delete'));
|
||||
}
|
||||
|
||||
(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);
|
||||
}
|
||||
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();
|
||||
}))->run();
|
||||
$role->entityPermissions()->delete();
|
||||
$role->jointPermissions()->delete();
|
||||
Activity::add(ActivityType::ROLE_DELETE, $role);
|
||||
$role->delete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use Illuminate\Http\Request;
|
||||
|
||||
class SearchApiController extends ApiController
|
||||
{
|
||||
protected array $rules = [
|
||||
protected $rules = [
|
||||
'all' => [
|
||||
'query' => ['required'],
|
||||
'page' => ['integer', 'min:1'],
|
||||
|
||||
@@ -7,7 +7,6 @@ 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
|
||||
@@ -56,18 +55,16 @@ class BookSortController extends Controller
|
||||
|
||||
// Sort via map
|
||||
if ($request->filled('sort-tree')) {
|
||||
(new DatabaseTransaction(function () use ($book, $request, $sorter, &$loggedActivityForBook) {
|
||||
$sortMap = BookSortMap::fromJson($request->get('sort-tree'));
|
||||
$booksInvolved = $sorter->sortUsingMap($sortMap);
|
||||
$sortMap = BookSortMap::fromJson($request->get('sort-tree'));
|
||||
$booksInvolved = $sorter->sortUsingMap($sortMap);
|
||||
|
||||
// Add activity for involved books.
|
||||
foreach ($booksInvolved as $bookInvolved) {
|
||||
Activity::add(ActivityType::BOOK_SORT, $bookInvolved);
|
||||
if ($bookInvolved->id === $book->id) {
|
||||
$loggedActivityForBook = true;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
}))->run();
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->filled('auto-sort')) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace BookStack\Sorting;
|
||||
|
||||
use BookStack\App\Model;
|
||||
use BookStack\Entities\Models\Book;
|
||||
use BookStack\Entities\Models\BookChild;
|
||||
use BookStack\Entities\Models\Chapter;
|
||||
|
||||
@@ -50,7 +50,6 @@ class LocaleManager
|
||||
'ku' => 'ku_TR',
|
||||
'lt' => 'lt_LT',
|
||||
'lv' => 'lv_LV',
|
||||
'ne' => 'ne_NP',
|
||||
'nb' => 'nb_NO',
|
||||
'nl' => 'nl_NL',
|
||||
'nn' => 'nn_NO',
|
||||
|
||||
122
app/Uploads/DrawioPngReader.php
Normal file
122
app/Uploads/DrawioPngReader.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace BookStack\Uploads;
|
||||
|
||||
use BookStack\Exceptions\DrawioPngReaderException;
|
||||
|
||||
/**
|
||||
* Reads the PNG file format: https://www.w3.org/TR/2003/REC-PNG-20031110/
|
||||
* So that it can extract embedded drawing data for alternative use.
|
||||
*/
|
||||
class DrawioPngReader
|
||||
{
|
||||
/**
|
||||
* @param resource $fileStream
|
||||
*/
|
||||
public function __construct(
|
||||
protected $fileStream
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DrawioPngReaderException
|
||||
*/
|
||||
public function extractDrawing(): string
|
||||
{
|
||||
$signature = fread($this->fileStream, 8);
|
||||
$pngSignature = "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A";
|
||||
if ($signature !== $pngSignature) {
|
||||
throw new DrawioPngReaderException('File does not appear to be a valid PNG file');
|
||||
}
|
||||
|
||||
$offset = 8;
|
||||
$searching = true;
|
||||
|
||||
while ($searching) {
|
||||
fseek($this->fileStream, $offset);
|
||||
|
||||
$lengthBytes = $this->readData(4);
|
||||
$chunkTypeBytes = $this->readData(4);
|
||||
$length = unpack('Nvalue', $lengthBytes)['value'];
|
||||
|
||||
if ($chunkTypeBytes === 'tEXt') {
|
||||
fseek($this->fileStream, $offset + 8);
|
||||
$data = $this->readData($length);
|
||||
$crc = $this->readData(4);
|
||||
$drawingData = $this->readTextForDrawing($data);
|
||||
if ($drawingData !== null) {
|
||||
$crcResult = $this->calculateCrc($chunkTypeBytes . $data);
|
||||
if ($crc !== $crcResult) {
|
||||
throw new DrawioPngReaderException('Drawing data withing PNG file appears to be corrupted');
|
||||
}
|
||||
return $drawingData;
|
||||
}
|
||||
} else if ($chunkTypeBytes === 'IEND') {
|
||||
$searching = false;
|
||||
}
|
||||
|
||||
$offset += 12 + $length; // 12 = length + type + crc bytes
|
||||
}
|
||||
|
||||
throw new DrawioPngReaderException('Unable to find drawing data within PNG file');
|
||||
}
|
||||
|
||||
protected function readTextForDrawing(string $data): ?string
|
||||
{
|
||||
// Check the keyword is mxfile to ensure we're getting the right data
|
||||
if (!str_starts_with($data, "mxfile\u{0}")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Extract & cleanup the drawing text
|
||||
$drawingText = substr($data, 7);
|
||||
return urldecode($drawingText);
|
||||
}
|
||||
|
||||
protected function readData(int $length): string
|
||||
{
|
||||
$bytes = fread($this->fileStream, $length);
|
||||
if ($bytes === false || strlen($bytes) < $length) {
|
||||
throw new DrawioPngReaderException('Unable to find drawing data within PNG file');
|
||||
}
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
protected function getCrcTable(): array
|
||||
{
|
||||
$table = [];
|
||||
|
||||
for ($n = 0; $n < 256; $n++) {
|
||||
$c = $n;
|
||||
for ($k = 0; $k < 8; $k++) {
|
||||
if ($c & 1) {
|
||||
$c = 0xedb88320 ^ ($c >> 1);
|
||||
} else {
|
||||
$c = $c >> 1;
|
||||
}
|
||||
}
|
||||
$table[$n] = $c;
|
||||
}
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a CRC for the given bytes following:
|
||||
* https://www.w3.org/TR/2003/REC-PNG-20031110/#D-CRCAppendix
|
||||
*/
|
||||
protected function calculateCrc(string $bytes): string
|
||||
{
|
||||
$table = $this->getCrcTable();
|
||||
|
||||
$length = strlen($bytes);
|
||||
$c = 0xffffffff;
|
||||
|
||||
for ($n = 0; $n < $length; $n++) {
|
||||
$tableIndex = ($c ^ ord($bytes[$n])) & 0xff;
|
||||
$c = $table[$tableIndex] ^ ($c >> 8);
|
||||
}
|
||||
|
||||
return pack('N', $c ^ 0xffffffff);
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ class RoleApiController extends ApiController
|
||||
'display_name', 'description', 'mfa_enforced', 'external_auth_id', 'created_at', 'updated_at',
|
||||
];
|
||||
|
||||
protected array $rules = [
|
||||
protected $rules = [
|
||||
'create' => [
|
||||
'display_name' => ['required', 'string', 'min:3', 'max:180'],
|
||||
'description' => ['string', 'max:180'],
|
||||
|
||||
@@ -7,8 +7,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
/**
|
||||
* @property int $created_by
|
||||
* @property int $updated_by
|
||||
* @property ?User $createdBy
|
||||
* @property ?User $updatedBy
|
||||
*/
|
||||
trait HasCreatorAndUpdater
|
||||
{
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace BookStack\Util;
|
||||
|
||||
use DOMAttr;
|
||||
use DOMElement;
|
||||
use DOMNamedNodeMap;
|
||||
use DOMNode;
|
||||
|
||||
/**
|
||||
@@ -24,7 +25,6 @@ class HtmlDescriptionFilter
|
||||
'ul' => [],
|
||||
'li' => [],
|
||||
'strong' => [],
|
||||
'span' => [],
|
||||
'em' => [],
|
||||
'br' => [],
|
||||
];
|
||||
@@ -59,6 +59,7 @@ class HtmlDescriptionFilter
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var DOMNamedNodeMap $attrs */
|
||||
$attrs = $element->attributes;
|
||||
for ($i = $attrs->length - 1; $i >= 0; $i--) {
|
||||
/** @var DOMAttr $attr */
|
||||
@@ -69,8 +70,7 @@ class HtmlDescriptionFilter
|
||||
}
|
||||
}
|
||||
|
||||
$childNodes = [...$element->childNodes];
|
||||
foreach ($childNodes as $child) {
|
||||
foreach ($element->childNodes as $child) {
|
||||
if ($child instanceof DOMElement) {
|
||||
static::filterElement($child);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,8 @@
|
||||
"socialiteproviders/microsoft-azure": "^5.1",
|
||||
"socialiteproviders/okta": "^4.2",
|
||||
"socialiteproviders/twitch": "^5.3",
|
||||
"ssddanbrown/htmldiff": "^2.0.0"
|
||||
"ssddanbrown/htmldiff": "^1.0.2",
|
||||
"ssddanbrown/symfony-mailer": "7.2.x-dev"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.21",
|
||||
|
||||
935
composer.lock
generated
935
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Database\Factories\Entities\Models;
|
||||
|
||||
use BookStack\Entities\Tools\PageEditorType;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
@@ -30,7 +29,6 @@ class PageFactory extends Factory
|
||||
'html' => $html,
|
||||
'text' => strip_tags($html),
|
||||
'revision_count' => 1,
|
||||
'editor' => 'wysiwyg',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ 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(),
|
||||
];
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"parent_type": "book",
|
||||
"parent_id": 28
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
{
|
||||
"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": []
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
@@ -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.mts'),
|
||||
markdown: path.join(__dirname, '../../resources/js/markdown/index.mjs'),
|
||||
wysiwyg: path.join(__dirname, '../../resources/js/wysiwyg/index.ts'),
|
||||
};
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
fa162564940d9a81e4dd0b20ae8775d32f2ea5c615e33ebcc8adf035d958c352
|
||||
22e02ee72d21ff719c1073abbec8302f8e2096ba6d072e133051064ed24b45b1
|
||||
|
||||
@@ -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: https://github.com/eslint/js.git
|
||||
Source: eslint/js
|
||||
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: https://github.com/eslint/js.git
|
||||
Source: eslint/js
|
||||
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: https://github.com/eslint/js.git
|
||||
Source: eslint/js
|
||||
Link: https://github.com/eslint/js/blob/main/packages/espree/README.md
|
||||
-----------
|
||||
esprima
|
||||
@@ -1252,13 +1252,6 @@ 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
|
||||
@@ -2500,13 +2493,6 @@ 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
|
||||
@@ -3006,13 +2992,6 @@ 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
|
||||
@@ -3059,7 +3038,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/regenerator* files)
|
||||
Copyright (c) 2014-present, Facebook, Inc. (ONLY ./src/helpers/regeneratorRuntime.js)
|
||||
Source: https://github.com/babel/babel.git
|
||||
Link: https://babel.dev/docs/en/next/babel-helpers
|
||||
-----------
|
||||
@@ -3254,7 +3233,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
|
||||
-----------
|
||||
@@ -3268,7 +3247,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
|
||||
-----------
|
||||
@@ -3358,7 +3337,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/tree/main/packages/config-array#readme
|
||||
Link: https://github.com/eslint/rewrite#readme
|
||||
-----------
|
||||
@eslint/config-helpers
|
||||
License: Apache-2.0
|
||||
@@ -3370,7 +3349,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/tree/main/packages/core#readme
|
||||
Link: https://github.com/eslint/rewrite#readme
|
||||
-----------
|
||||
@eslint/eslintrc
|
||||
License: MIT
|
||||
@@ -3394,7 +3373,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/tree/main/packages/plugin-kit#readme
|
||||
Link: https://github.com/eslint/rewrite#readme
|
||||
-----------
|
||||
@humanfs/core
|
||||
License: Apache-2.0
|
||||
@@ -3535,9 +3514,9 @@ Link: https://github.com/jestjs/jest.git
|
||||
@jridgewell/gen-mapping
|
||||
License: MIT
|
||||
License File: node_modules/@jridgewell/gen-mapping/LICENSE
|
||||
Copyright: Copyright 2024 Justin Ridgewell <******@*********.****>
|
||||
Source: git+https://github.com/jridgewell/sourcemaps.git
|
||||
Link: https://github.com/jridgewell/sourcemaps/tree/main/packages/gen-mapping
|
||||
Copyright: Copyright 2022 Justin Ridgewell <**********@******.***>
|
||||
Source: https://github.com/jridgewell/gen-mapping
|
||||
Link: https://github.com/jridgewell/gen-mapping
|
||||
-----------
|
||||
@jridgewell/resolve-uri
|
||||
License: MIT
|
||||
@@ -3546,19 +3525,26 @@ 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 2024 Justin Ridgewell <******@*********.****>
|
||||
Source: git+https://github.com/jridgewell/sourcemaps.git
|
||||
Link: https://github.com/jridgewell/sourcemaps/tree/main/packages/sourcemap-codec
|
||||
Copyright: Copyright (c) 2015 Rich Harris
|
||||
Source: git+https://github.com/jridgewell/sourcemap-codec.git
|
||||
Link: git+https://github.com/jridgewell/sourcemap-codec.git
|
||||
-----------
|
||||
@jridgewell/trace-mapping
|
||||
License: MIT
|
||||
License File: node_modules/@jridgewell/trace-mapping/LICENSE
|
||||
Copyright: Copyright 2024 Justin Ridgewell <******@*********.****>
|
||||
Source: git+https://github.com/jridgewell/sourcemaps.git
|
||||
Link: https://github.com/jridgewell/sourcemaps/tree/main/packages/trace-mapping
|
||||
Copyright: Copyright 2022 Justin Ridgewell <******@*********.****>
|
||||
Source: git+https://github.com/jridgewell/trace-mapping.git
|
||||
Link: git+https://github.com/jridgewell/trace-mapping.git
|
||||
-----------
|
||||
@lezer/common
|
||||
License: MIT
|
||||
@@ -3827,27 +3813,6 @@ 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
|
||||
|
||||
@@ -467,7 +467,7 @@ License: MIT
|
||||
License File: vendor/psy/psysh/LICENSE
|
||||
Copyright: Copyright (c) 2012-2023 Justin Hileman
|
||||
Source: https://github.com/bobthecow/psysh.git
|
||||
Link: https://psysh.org
|
||||
Link: http://psysh.org
|
||||
-----------
|
||||
ralouphie/getallheaders
|
||||
License: MIT
|
||||
@@ -543,6 +543,13 @@ 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
|
||||
@@ -613,13 +620,6 @@ 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
|
||||
|
||||
@@ -30,8 +30,8 @@ return [
|
||||
'create' => 'إنشاء',
|
||||
'update' => 'تحديث',
|
||||
'edit' => 'تعديل',
|
||||
'archive' => 'أرشف',
|
||||
'unarchive' => 'إلغاء الأرشفة',
|
||||
'archive' => 'Archive',
|
||||
'unarchive' => 'Un-Archive',
|
||||
'sort' => 'سرد',
|
||||
'move' => 'نقل',
|
||||
'copy' => 'نسخ',
|
||||
|
||||
@@ -48,7 +48,6 @@ return [
|
||||
'superscript' => 'نص مرتفع',
|
||||
'subscript' => 'نص منخفض',
|
||||
'text_color' => 'لون النص',
|
||||
'highlight_color' => 'لون التمييز',
|
||||
'custom_color' => 'لون مخصص',
|
||||
'remove_color' => 'إزالة اللون',
|
||||
'background_color' => 'لون الخلفية',
|
||||
|
||||
@@ -63,10 +63,6 @@ return [
|
||||
'import_delete_desc' => 'سيؤدي هذا إلى حذف مِلَفّ الاستيراد المضغوط ZIP، ولا يمكن التراجع عنه.',
|
||||
'import_errors' => 'أخطاء الاستيراد',
|
||||
'import_errors_desc' => 'حدثت الأخطاء التالية خلال محاولة الاستيراد:',
|
||||
'breadcrumb_siblings_for_page' => 'Navigate siblings for page',
|
||||
'breadcrumb_siblings_for_chapter' => 'Navigate siblings for chapter',
|
||||
'breadcrumb_siblings_for_book' => 'Navigate siblings for book',
|
||||
'breadcrumb_siblings_for_bookshelf' => 'Navigate siblings for shelf',
|
||||
|
||||
// Permissions and restrictions
|
||||
'permissions' => 'الأذونات',
|
||||
@@ -252,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' => '(في الاختبار التجريبي)',
|
||||
'pages_edit_switch_to_new_wysiwyg_desc' => '(In Beta Testing)',
|
||||
'pages_edit_set_changelog' => 'تثبيت سجل التعديل',
|
||||
'pages_edit_enter_changelog_desc' => 'ضع وصف مختصر للتعديلات التي تمت',
|
||||
'pages_edit_enter_changelog' => 'أدخل سجل التعديل',
|
||||
@@ -272,7 +268,6 @@ 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' => 'صفحة ليست في فصل',
|
||||
|
||||
@@ -348,7 +348,6 @@ return [
|
||||
'lt' => 'Lietuvių Kalba',
|
||||
'lv' => 'Latviešu Valoda',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Nederlands',
|
||||
'pl' => 'Polski',
|
||||
|
||||
@@ -48,7 +48,6 @@ return [
|
||||
'superscript' => 'Горен индекс',
|
||||
'subscript' => 'Долен индекс',
|
||||
'text_color' => 'Цвят на текста',
|
||||
'highlight_color' => 'Highlight color',
|
||||
'custom_color' => 'Цвят по избор',
|
||||
'remove_color' => 'Премахване на цвят',
|
||||
'background_color' => 'Фонов цвят',
|
||||
|
||||
@@ -63,10 +63,6 @@ return [
|
||||
'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:',
|
||||
'breadcrumb_siblings_for_page' => 'Navigate siblings for page',
|
||||
'breadcrumb_siblings_for_chapter' => 'Navigate siblings for chapter',
|
||||
'breadcrumb_siblings_for_book' => 'Navigate siblings for book',
|
||||
'breadcrumb_siblings_for_bookshelf' => 'Navigate siblings for shelf',
|
||||
|
||||
// Permissions and restrictions
|
||||
'permissions' => 'Права',
|
||||
@@ -272,7 +268,6 @@ 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' => 'Страницата не принадлежи в никоя глава',
|
||||
|
||||
@@ -348,7 +348,6 @@ return [
|
||||
'lt' => 'Lietuvių Kalba',
|
||||
'lv' => 'Latviešu Valoda',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Nederlands',
|
||||
'pl' => 'Polski',
|
||||
|
||||
@@ -48,7 +48,6 @@ 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',
|
||||
|
||||
@@ -63,10 +63,6 @@ return [
|
||||
'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:',
|
||||
'breadcrumb_siblings_for_page' => 'Navigate siblings for page',
|
||||
'breadcrumb_siblings_for_chapter' => 'Navigate siblings for chapter',
|
||||
'breadcrumb_siblings_for_book' => 'Navigate siblings for book',
|
||||
'breadcrumb_siblings_for_bookshelf' => 'Navigate siblings for shelf',
|
||||
|
||||
// Permissions and restrictions
|
||||
'permissions' => 'Permissions',
|
||||
@@ -272,7 +268,6 @@ 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',
|
||||
|
||||
@@ -348,7 +348,6 @@ return [
|
||||
'lt' => 'Lietuvių Kalba',
|
||||
'lv' => 'Latviešu Valoda',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Nederlands',
|
||||
'pl' => 'Polski',
|
||||
|
||||
@@ -48,7 +48,6 @@ 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',
|
||||
|
||||
@@ -63,10 +63,6 @@ return [
|
||||
'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:',
|
||||
'breadcrumb_siblings_for_page' => 'Navigate siblings for page',
|
||||
'breadcrumb_siblings_for_chapter' => 'Navigate siblings for chapter',
|
||||
'breadcrumb_siblings_for_book' => 'Navigate siblings for book',
|
||||
'breadcrumb_siblings_for_bookshelf' => 'Navigate siblings for shelf',
|
||||
|
||||
// Permissions and restrictions
|
||||
'permissions' => 'Dozvole',
|
||||
@@ -272,7 +268,6 @@ 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',
|
||||
|
||||
@@ -348,7 +348,6 @@ return [
|
||||
'lt' => 'Lietuvių Kalba',
|
||||
'lv' => 'Latviešu Valoda',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Nederlands',
|
||||
'pl' => 'Polski',
|
||||
|
||||
@@ -18,35 +18,35 @@ return [
|
||||
'page_move_notification' => 'S’ha mogut la pàgina',
|
||||
|
||||
// Chapters
|
||||
'chapter_create' => 'S\'ha creat el capítol',
|
||||
'chapter_create' => 'ha creat el capítol',
|
||||
'chapter_create_notification' => 'S’ha creat el capítol',
|
||||
'chapter_update' => 'ha actualitzat el capítol',
|
||||
'chapter_update_notification' => 'S’ha actualitzat el capítol',
|
||||
'chapter_delete' => 'ha suprimit el capítol',
|
||||
'chapter_delete_notification' => 'S’ha suprimit el capítol',
|
||||
'chapter_move' => 's\'ha mogut el capítol',
|
||||
'chapter_move' => 'ha mogut el capítol',
|
||||
'chapter_move_notification' => 'S’ha mogut el capítol',
|
||||
|
||||
// Books
|
||||
'book_create' => 'llibre creat',
|
||||
'book_create' => 'ha creat el llibre',
|
||||
'book_create_notification' => 'S’ha creat el llibre',
|
||||
'book_create_from_chapter' => 'ha convertit el capítol a llibre',
|
||||
'book_create_from_chapter_notification' => 'S’ha convertit el capítol a llibre',
|
||||
'book_update' => 'llibre actualitzat',
|
||||
'book_update' => 'ha actualitzat el llibre',
|
||||
'book_update_notification' => 'S’ha actualitzat el llibre',
|
||||
'book_delete' => 'llibre suprimit',
|
||||
'book_delete' => 'ha suprimit el llibre',
|
||||
'book_delete_notification' => 'S’ha suprimit el llibre',
|
||||
'book_sort' => 'llibre ordenat',
|
||||
'book_sort' => 'ha ordenat el llibre',
|
||||
'book_sort_notification' => 'S’ha tornat a ordenar el llibre',
|
||||
|
||||
// Bookshelves
|
||||
'bookshelf_create' => 'ha creat el prestatge',
|
||||
'bookshelf_create_notification' => 'S’ha creat el prestatge',
|
||||
'bookshelf_create_from_book' => 'llibre convertit a prestatge',
|
||||
'bookshelf_create_from_book' => 'ha convertit el llibre a prestatge',
|
||||
'bookshelf_create_from_book_notification' => 'S’ha convertit el llibre a prestatge',
|
||||
'bookshelf_update' => 'prestatge actualitzat',
|
||||
'bookshelf_update' => 'ha actualitzat el prestatge',
|
||||
'bookshelf_update_notification' => 'S’ha actualitzat el prestatge',
|
||||
'bookshelf_delete' => 'prestatge suprimit',
|
||||
'bookshelf_delete' => 'ha suprimit el prestatge',
|
||||
'bookshelf_delete_notification' => 'S’ha suprimit el prestatge',
|
||||
|
||||
// Revisions
|
||||
@@ -85,12 +85,12 @@ return [
|
||||
'webhook_delete_notification' => 'S’ha suprimit el webhook',
|
||||
|
||||
// Imports
|
||||
'import_create' => 'importació creada',
|
||||
'import_create_notification' => 'L\'importació s\'ha carregat correctament',
|
||||
'import_run' => 'importació actualitzada',
|
||||
'import_run_notification' => 'Contingut importat correctament',
|
||||
'import_delete' => 'importació eliminada',
|
||||
'import_delete_notification' => 'Importació eliminada correctament',
|
||||
'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',
|
||||
|
||||
// Users
|
||||
'user_create' => 'ha creat l’usuari',
|
||||
@@ -128,12 +128,12 @@ return [
|
||||
'comment_delete' => 'ha suprimit un comentari',
|
||||
|
||||
// Sort Rules
|
||||
'sort_rule_create' => 'crear regla d\'ordenació',
|
||||
'sort_rule_create_notification' => 'Regla d\'ordenació creada correctament',
|
||||
'sort_rule_update' => 'regla d\'ordenació actualitzada',
|
||||
'sort_rule_update_notification' => 'Regla d\'ordenació actualitzada correctament',
|
||||
'sort_rule_delete' => 'regla d\'ordenació eliminada',
|
||||
'sort_rule_delete_notification' => 'Regla d\'ordenació eliminada correctament',
|
||||
'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',
|
||||
|
||||
// Other
|
||||
'permissions_update' => 'ha actualitzat els permisos',
|
||||
|
||||
@@ -30,8 +30,8 @@ return [
|
||||
'create' => 'Crea',
|
||||
'update' => 'Actualitza',
|
||||
'edit' => 'Edita',
|
||||
'archive' => 'Arxivar',
|
||||
'unarchive' => 'Desarxivar',
|
||||
'archive' => 'Archive',
|
||||
'unarchive' => 'Un-Archive',
|
||||
'sort' => 'Ordena',
|
||||
'move' => 'Mou',
|
||||
'copy' => 'Copia',
|
||||
@@ -111,5 +111,5 @@ return [
|
||||
'terms_of_service' => 'Condicions del servei',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Buscar :appName',
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
||||
@@ -13,7 +13,7 @@ return [
|
||||
'cancel' => 'Cancel·la',
|
||||
'save' => 'Desa',
|
||||
'close' => 'Tanca',
|
||||
'apply' => 'Aplicar',
|
||||
'apply' => 'Apply',
|
||||
'undo' => 'Desfés',
|
||||
'redo' => 'Refés',
|
||||
'left' => 'Esquerra',
|
||||
@@ -25,7 +25,7 @@ return [
|
||||
'width' => 'Amplada',
|
||||
'height' => 'Altura',
|
||||
'More' => 'Més',
|
||||
'select' => 'Selecciona …',
|
||||
'select' => 'Selecciona…',
|
||||
|
||||
// Toolbar
|
||||
'formats' => 'Formats',
|
||||
@@ -48,7 +48,6 @@ return [
|
||||
'superscript' => 'Superíndex',
|
||||
'subscript' => 'Subíndex',
|
||||
'text_color' => 'Color del text',
|
||||
'highlight_color' => 'Color ressaltat',
|
||||
'custom_color' => 'Color personalitzat',
|
||||
'remove_color' => 'Elimina el color',
|
||||
'background_color' => 'Color de fons',
|
||||
@@ -149,7 +148,7 @@ return [
|
||||
'url' => 'URL',
|
||||
'text_to_display' => 'Text per a mostrar',
|
||||
'title' => 'Títol',
|
||||
'browse_links' => 'Explorar enllaços',
|
||||
'browse_links' => 'Browse links',
|
||||
'open_link' => 'Obre l’enllaç',
|
||||
'open_link_in' => 'Obre l’enllaç…',
|
||||
'open_link_current' => 'A la finestra actual',
|
||||
@@ -166,8 +165,8 @@ return [
|
||||
'about' => 'Quant a l’Editor',
|
||||
'about_title' => 'Quant a l’Editor WYSIWYG',
|
||||
'editor_license' => 'Llicència i copyright de l’Editor',
|
||||
'editor_lexical_license' => 'Aquest editor està construït com una bifurcació de :lexicalLink i es distribueix sota la llicència MIT.',
|
||||
'editor_lexical_license_link' => 'Tots els detalls complets de la llicència es poden trobar aquí.',
|
||||
'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_tiny_license' => 'Aquest editor s’ha creat amb :tinyLink que es proporciona amb la llicència MIT.',
|
||||
'editor_tiny_license_link' => 'Detalls de la llicència i el copyright de TinyMCE.',
|
||||
'save_continue' => 'Desa la pàgina i continua',
|
||||
|
||||
@@ -39,34 +39,30 @@ return [
|
||||
'export_pdf' => 'Fitxer PDF',
|
||||
'export_text' => 'Fitxer de text sense format',
|
||||
'export_md' => 'Fitxer Markdown',
|
||||
'export_zip' => 'ZIP portable',
|
||||
'default_template' => 'Plantilla de pàgina per defecte',
|
||||
'default_template_explain' => 'Assigna una plantilla de pàgina que s\'utilitzarà com a contingut predeterminat per a totes les pàgines creades en aquest element. Tingues en compte que això només s\'utilitzarà si el creador de pàgines té accés a la plantilla de pàgina triada.',
|
||||
'default_template_select' => 'Seleccioneu una plantilla de pàgina',
|
||||
'import' => 'Importar',
|
||||
'import_validate' => 'Validar importació',
|
||||
'import_desc' => 'Importar llibres, capítols i pàgines utilitzant una exportació ZIP portable de la mateixa o una altra instància. Selecciona un arxiu ZIP per continuar. Després que l\'arxiu s\'hagi penjat i validat, podrà configurar i confirmar l\'importació en la següent vista.',
|
||||
'import_zip_select' => 'Seleccioneu un fitxer ZIP per pujar',
|
||||
'import_zip_validation_errors' => 'S\'han detectat errors al validar l\'arxiu ZIP proporcionat:',
|
||||
'import_pending' => 'Importació pendent',
|
||||
'import_pending_none' => 'No s\'han iniciat les importacions.',
|
||||
'import_continue' => 'Continuar importació',
|
||||
'import_continue_desc' => 'Revisa el contingut que s\'ha d\'importar de l\'arxiu ZIP penjat. Quan estigui llest, executa l\'importació per afegir el seu contingut al sistema. L\'arxiu d\'importació ZIP penjat s\'eliminarà automàticament al finalitzar l\'importació correctament.',
|
||||
'import_details' => 'Detalls d\'importació',
|
||||
'import_run' => 'Executar importació',
|
||||
'import_size' => ':size Mida de l\'arxiu ZIP',
|
||||
'import_uploaded_at' => 'Penjat :relativeTime',
|
||||
'import_uploaded_by' => 'Actualitzat per',
|
||||
'import_location' => 'Importar ubicació',
|
||||
'import_location_desc' => 'Selecciona una ubicació de destí pel contingut importat. Necessitarà els permisos pertinents per crear-lo dins de la ubicació triada.',
|
||||
'import_delete_confirm' => 'Esteu segur que voleu suplir aquesta importació?',
|
||||
'import_delete_desc' => 'Això eliminarà l\'arxiu ZIP d\'importació penjat i no es pot desfer.',
|
||||
'import_errors' => 'Importar errors',
|
||||
'import_errors_desc' => 'S\'han produït els següents errors durant l\'intent d\'importació:',
|
||||
'breadcrumb_siblings_for_page' => 'Navegar entre pàgines del mateix nivell',
|
||||
'breadcrumb_siblings_for_chapter' => 'Navegar entre capítols del mateix nivell',
|
||||
'breadcrumb_siblings_for_book' => 'Navegar entre llibres del mateix nivell',
|
||||
'breadcrumb_siblings_for_bookshelf' => 'Navegar entre llibreries del mateix nivell',
|
||||
'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:',
|
||||
|
||||
// Permissions and restrictions
|
||||
'permissions' => 'Permisos',
|
||||
@@ -170,9 +166,9 @@ return [
|
||||
'books_search_this' => 'Cerca en aquest llibre',
|
||||
'books_navigation' => 'Navegació del llibre',
|
||||
'books_sort' => 'Ordena el contingut d’un llibre',
|
||||
'books_sort_desc' => 'Mou capítols i pàgines dins d\'un llibre per reorganitzar el seu contingut. Es poden afegir altres llibres que permetin moure fàcilment capítols i pàgines entre llibres. De manera opcional, es poden establir regles d\'ordenació automàtica per ordenar automàticament el contingut d\'aquest llibre quan hi hagi canvis.',
|
||||
'books_sort_auto_sort' => 'Opció d\'ordenació automàtica',
|
||||
'books_sort_auto_sort_active' => 'Opció d\'ordenació activa :sortName',
|
||||
'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_named' => 'Ordena el llibre «:bookName»',
|
||||
'books_sort_name' => 'Ordena pel nom',
|
||||
'books_sort_created' => 'Ordena per la data de creació',
|
||||
@@ -234,7 +230,7 @@ return [
|
||||
'pages_delete_draft' => 'Suprimeix l’esborrany de pàgina',
|
||||
'pages_delete_success' => 'S’ha suprimit la pàgina',
|
||||
'pages_delete_draft_success' => 'S’ha suprimit l’esborrany de pàgina',
|
||||
'pages_delete_warning_template' => 'Aquesta pàgina està en ús com a plantilla de pàgina predeterminada de llibre o capítol. Aquests llibres o capítols ja no tindran una plantilla de pàgina predeterminada assignada després d\'eliminar aquesta pàgina.',
|
||||
'pages_delete_warning_template' => 'This page is in active use as a book or chapter default page template. These books or chapters will no longer have a default page template assigned after this page is deleted.',
|
||||
'pages_delete_confirm' => 'Esteu segur que voleu suprimir aquesta pàgina?',
|
||||
'pages_delete_draft_confirm' => 'Esteu segur que voleu suprimir aquest esborrany de pàgina?',
|
||||
'pages_editing_named' => 'Edició de la pàgina «:pageName»',
|
||||
@@ -251,8 +247,8 @@ return [
|
||||
'pages_edit_switch_to_markdown_clean' => '(Contingut net)',
|
||||
'pages_edit_switch_to_markdown_stable' => '(Contingut estable)',
|
||||
'pages_edit_switch_to_wysiwyg' => 'Canvia a l’editor WYSIWYG',
|
||||
'pages_edit_switch_to_new_wysiwyg' => 'Canviar al nou editor WYSIWYG',
|
||||
'pages_edit_switch_to_new_wysiwyg_desc' => '(En Beta Test)',
|
||||
'pages_edit_switch_to_new_wysiwyg' => 'Switch to new WYSIWYG',
|
||||
'pages_edit_switch_to_new_wysiwyg_desc' => '(In Beta Testing)',
|
||||
'pages_edit_set_changelog' => 'Registre de canvis',
|
||||
'pages_edit_enter_changelog_desc' => 'Introduïu una descripció breu dels canvis que heu fet',
|
||||
'pages_edit_enter_changelog' => 'Registra un canvi',
|
||||
@@ -272,7 +268,6 @@ 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' => 'Editor de text pla',
|
||||
'pages_drawing_unsaved' => 'S’ha trobat un dibuix sense desar',
|
||||
'pages_drawing_unsaved_confirm' => 'S’han trobat dades d’un dibuix d’un intent anterior de desar un dibuix. Voleu restaurar aquest dibuix no desat per a reprendre’n l’edició?',
|
||||
'pages_not_in_chapter' => 'La pàgina no és un capítol',
|
||||
@@ -397,11 +392,11 @@ return [
|
||||
'comment' => 'Comentari',
|
||||
'comments' => 'Comentaris',
|
||||
'comment_add' => 'Afegeix un comentari',
|
||||
'comment_none' => 'No hi ha comentaris per mostrar',
|
||||
'comment_none' => 'No comments to display',
|
||||
'comment_placeholder' => 'Deixa un comentari aquí',
|
||||
'comment_thread_count' => ':count fil de comentaris|:count fils de comentaris',
|
||||
'comment_archived_count' => ':count Arxivats',
|
||||
'comment_archived_threads' => 'Fils arxivats',
|
||||
'comment_thread_count' => ':count Comment Thread|:count Comment Threads',
|
||||
'comment_archived_count' => ':count Archived',
|
||||
'comment_archived_threads' => 'Archived Threads',
|
||||
'comment_save' => 'Desa el comentari',
|
||||
'comment_new' => 'Crea un comentari',
|
||||
'comment_created' => 'ha comentat :createDiff',
|
||||
@@ -410,14 +405,14 @@ return [
|
||||
'comment_deleted_success' => 'S’ha suprimit el comentari',
|
||||
'comment_created_success' => 'S’ha afegit un comentari',
|
||||
'comment_updated_success' => 'S’ha actualitzat un comentari',
|
||||
'comment_archive_success' => 'Comentari arxivat',
|
||||
'comment_unarchive_success' => 'Comentari desarxivat',
|
||||
'comment_view' => 'Mostra el comentari',
|
||||
'comment_jump_to_thread' => 'Anar al fil',
|
||||
'comment_archive_success' => 'Comment archived',
|
||||
'comment_unarchive_success' => 'Comment un-archived',
|
||||
'comment_view' => 'View comment',
|
||||
'comment_jump_to_thread' => 'Jump to thread',
|
||||
'comment_delete_confirm' => 'Esteu segur que voleu suprimir aquest comentari?',
|
||||
'comment_in_reply_to' => 'En resposta a :commentId',
|
||||
'comment_reference' => 'Referència',
|
||||
'comment_reference_outdated' => '(Obsolet)',
|
||||
'comment_reference' => 'Reference',
|
||||
'comment_reference_outdated' => '(Outdated)',
|
||||
'comment_editor_explain' => 'Vet aquí els comentaris que s’han fet en aquesta pàgina. Els comentaris es poden fer i gestionar quan es visualitza la pàgina desada.',
|
||||
|
||||
// Revision
|
||||
|
||||
@@ -6,17 +6,17 @@ return [
|
||||
|
||||
// Permissions
|
||||
'permission' => 'No teniu permís per a accedir a la pàgina sol·licitada.',
|
||||
'permissionJson' => 'No teniu permís per a executar l’acció sol·licitada.',
|
||||
'permissionJson' => 'No teniu permís per a fer l’acció sol·licitada.',
|
||||
|
||||
// Auth
|
||||
'error_user_exists_different_creds' => 'Ja existeix un usuari amb el correu electrònic :email però amb unes credencials diferents.',
|
||||
'auth_pre_register_theme_prevention' => 'El compte d\'usuari no s\'ha pogut registrar amb els detalls proporcionats',
|
||||
'email_already_confirmed' => 'L’adreça electrònica ja està confirmada. Proveu d’iniciar la sessió.',
|
||||
'auth_pre_register_theme_prevention' => 'User account could not be registered for the provided details',
|
||||
'email_already_confirmed' => 'Ja s’ha confirmat el correu electrònic. Proveu d’iniciar sessió.',
|
||||
'email_confirmation_invalid' => 'Aquest testimoni de confirmació no és vàlid o ja s’ha utilitzat. Proveu de tornar-vos a registrar.',
|
||||
'email_confirmation_expired' => 'Aquest testimoni de confirmació ha caducat. S’ha enviat un altre correu electrònic de confirmació.',
|
||||
'email_confirmation_awaiting' => 'Cal confirmar l’adreça electrònica del compte que utilitzeu',
|
||||
'email_confirmation_awaiting' => 'Cal confirmar l’adreça electrònica del compte que utilitzeu.',
|
||||
'ldap_fail_anonymous' => 'L’accés LDAP anònim ha fallat',
|
||||
'ldap_fail_authed' => 'L’accés LDAP amb el nom distintiu i la contrasenya proporcionats ha fallat',
|
||||
'ldap_fail_authed' => 'L’accés LDAP amb el nom distintiu i la contrasenya proporcionades',
|
||||
'ldap_extension_not_installed' => 'L’extensió PHP de l’LDAP no està instal·lada',
|
||||
'ldap_cannot_connect' => 'No s’ha pogut connectar amb el servidor LDAP perquè la connexió inicial ha fallat',
|
||||
'saml_already_logged_in' => 'Ja heu iniciat sessió',
|
||||
@@ -29,15 +29,15 @@ return [
|
||||
'social_no_action_defined' => 'No s’ha definit cap acció',
|
||||
'social_login_bad_response' => "S’ha produït un error en l’inici de sessió amb :socialAccount: \n:error",
|
||||
'social_account_in_use' => 'Aquest compte de :socialAccount ja s’està utilitzant. Proveu d’iniciar sessió amb :socialAccount.',
|
||||
'social_account_email_in_use' => 'L’adreça electrònica :email ja està en ús. Si ja teniu un compte, podeu connectar-hi el vostre compte de :socialAccount a la configuració del vostre perfil.',
|
||||
'social_account_email_in_use' => 'L’adreça electrònica :email ja s’està utilitzant. Si ja teniu uns compte podeu connectar-hi el vostre compte de :socialAccount des de la configuració del vostre perfil.',
|
||||
'social_account_existing' => 'Aquest compte de :socialAccount ja està associat al vostre perfil.',
|
||||
'social_account_already_used_existing' => 'Aquest compte de :socialAccount ja està associat a un altre usuari.',
|
||||
'social_account_not_used' => 'Aquest compte de :socialAccount no està associat a cap usuari. Associeu-lo a la configuració del vostre perfil. ',
|
||||
'social_account_register_instructions' => 'Si encara no teniu un compte, podeu registrar-vos amb l’opció :socialAccount.',
|
||||
'social_driver_not_found' => 'No s’ha trobat el controlador social',
|
||||
'social_driver_not_configured' => 'La configuració de :socialAccount no és correcta.',
|
||||
'invite_token_expired' => 'Aquest enllaç d’invitació ha caducat. Podeu provar de restablir la contrasenya del vostre compte.',
|
||||
'login_user_not_found' => 'No s\'ha pogut trobar un usuari per aquesta acció.',
|
||||
'invite_token_expired' => 'Aquest enllaç d’invitació ha caducat. Proveu de reinicialitzar la contrasenya.',
|
||||
'login_user_not_found' => 'A user for this action could not be found.',
|
||||
|
||||
// System
|
||||
'path_not_writable' => 'No s’ha pogut pujar a :filePath. Assegureu-vos que teniu permisos d’escriptura al servidor.',
|
||||
@@ -78,7 +78,7 @@ return [
|
||||
// Users
|
||||
'users_cannot_delete_only_admin' => 'No podeu suprimir l’administrador únic.',
|
||||
'users_cannot_delete_guest' => 'No podeu suprimir l’usuari convidat.',
|
||||
'users_could_not_send_invite' => 'No s\'ha pogut crear l\'usuari, ja que no s\'ha pogut enviar el correu d\'invitació',
|
||||
'users_could_not_send_invite' => 'Could not create user since invite email failed to send',
|
||||
|
||||
// Roles
|
||||
'role_cannot_be_edited' => 'No es pot editar aquest rol.',
|
||||
@@ -106,16 +106,16 @@ return [
|
||||
'back_soon' => 'Aviat ho arreglarem.',
|
||||
|
||||
// Import
|
||||
'import_zip_cant_read' => 'No es pot llegir el fitxer ZIP.',
|
||||
'import_zip_cant_decode_data' => 'No s\'ha pogut trobar i descodificar el fitxer data.json en el fitxer ZIP.',
|
||||
'import_zip_no_data' => 'Les dades del fitxer ZIP no contenen cap llibre, capítol o contingut de pàgina.',
|
||||
'import_validation_failed' => 'Error en validar la importació del ZIP amb els errors:',
|
||||
'import_zip_failed_notification' => 'Error en importar l\'arxiu ZIP.',
|
||||
'import_perms_books' => 'Li falten els permisos necessaris per crear llibres.',
|
||||
'import_perms_chapters' => 'Li falten els permisos necessaris per crear capítols.',
|
||||
'import_perms_pages' => 'Li falten els permisos necessaris per crear pàgines.',
|
||||
'import_perms_images' => 'Li falten els permisos necessaris per crear imatges.',
|
||||
'import_perms_attachments' => 'Li falten els permisos necessaris per crear adjunts.',
|
||||
'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.',
|
||||
|
||||
// API errors
|
||||
'api_no_authorization_found' => 'No s’ha trobat cap testimoni d’autorització en aquesta sol·licitud.',
|
||||
|
||||
@@ -13,7 +13,7 @@ return [
|
||||
'updated_page_debounce' => 'Per a evitar que s’acumulin les notificacions, durant un temps no se us notificarà cap canvi fet en aquesta pàgina pel mateix usuari.',
|
||||
|
||||
'detail_page_name' => 'Nom de la pàgina:',
|
||||
'detail_page_path' => 'Ruta de la pàgina:',
|
||||
'detail_page_path' => 'Camí de la pàgina:',
|
||||
'detail_commenter' => 'Autor del comentari:',
|
||||
'detail_comment' => 'Comentari:',
|
||||
'detail_created_by' => 'Creada per:',
|
||||
|
||||
@@ -8,7 +8,7 @@ return [
|
||||
|
||||
// Common Messages
|
||||
'settings' => 'Configuració',
|
||||
'settings_save' => 'Guardar configuració',
|
||||
'settings_save' => 'Configuració de desat',
|
||||
'system_version' => 'Versió de sistema',
|
||||
'categories' => 'Categories',
|
||||
|
||||
@@ -19,8 +19,8 @@ return [
|
||||
'app_name_desc' => 'El nom es mostra a la capçalera i als correus electrònics enviats pel sistema.',
|
||||
'app_name_header' => 'Mostra el nom a la capçalera',
|
||||
'app_public_access' => 'Accés públic',
|
||||
'app_public_access_desc' => 'Si activeu aquesta opció permetrà als visitants, accedir a la vostra instància del BookStack sense iniciar sessió.',
|
||||
'app_public_access_desc_guest' => 'L’accés per als visitants públics es pot gestionar amb l’usuari Convidat.',
|
||||
'app_public_access_desc' => 'Si activeu aquesta opció les visitants podran accedir a la vostra instància del BookStack sense iniciar sessió.',
|
||||
'app_public_access_desc_guest' => 'L’accés per als visitants públics es pot gestionar amb l’usuari «Convidat».',
|
||||
'app_public_access_toggle' => 'Permet l’accés públic',
|
||||
'app_public_viewing' => 'Esteu segur que voleu permetre l’accés públic?',
|
||||
'app_secure_images' => 'Pujada d’imatges amb més seguretat',
|
||||
@@ -75,34 +75,34 @@ return [
|
||||
'reg_confirm_restrict_domain_placeholder' => 'No hi ha cap restricció',
|
||||
|
||||
// Sorting Settings
|
||||
'sorting' => 'Ordenar',
|
||||
'sorting_book_default' => 'Ordre predeterminat del llibre',
|
||||
'sorting_book_default_desc' => 'Selecciona la regla d\'ordenació predeterminada per aplicar a nous llibres. Això no afectarà els llibres existents, i pot ser anul·lat per llibre.',
|
||||
'sorting_rules' => 'Regles d\'ordenació',
|
||||
'sorting_rules_desc' => 'Són operacions d\'ordenació predefinides que es poden aplicar al contingut en el sistema.',
|
||||
'sort_rule_assigned_to_x_books' => 'Assignat a :count llibre | Assignat a :count llibres',
|
||||
'sort_rule_create' => 'Crear regla d\'ordenació',
|
||||
'sort_rule_edit' => 'Editar regla d\'ordenació',
|
||||
'sort_rule_delete' => 'Eliminar regla d\'ordenació',
|
||||
'sort_rule_delete_desc' => 'Eliminar aquesta regla d\'ordenació del sistema. Els llibres que utilitzin aquest tipus, es revertiran a l\'ordenació manual.',
|
||||
'sort_rule_delete_warn_books' => 'Aquesta regla d\'ordenació s\'utilitza actualment en :count llibre(s). Està segur que vol eliminar-la?',
|
||||
'sort_rule_delete_warn_default' => 'Aquesta regla d\'ordenació s\'utilitza actualment com a predeterminada per als llibres. Està segur que vol eliminar-la?',
|
||||
'sort_rule_details' => 'Detalls de la regla d\'ordenació',
|
||||
'sort_rule_details_desc' => 'Defineix un nom per aquesta regla d\'ordenació, que apareixerà a les llistes quan els usuaris estiguin seleccionant un ordre.',
|
||||
'sort_rule_operations' => 'Operacions d\'ordenació',
|
||||
'sort_rule_operations_desc' => 'Configura les accions d\'ordenació a realitzar movent-les de la llista d\'operacions disponibles. En utilitzar-se, les operacions s\'aplicaran en ordre, de dalt cap a baix. Qualsevol canvi realitzat aquí, s\'aplicarà a tots els llibres assignats en guardar.',
|
||||
'sort_rule_available_operations' => 'Operacions disponibles',
|
||||
'sort_rule_available_operations_empty' => 'No hi ha operacions pendents',
|
||||
'sort_rule_configured_operations' => 'Operacions configurades',
|
||||
'sort_rule_configured_operations_empty' => 'Arrossegar/afegir operacions des de la llista d\'Operacions Disponibles',
|
||||
'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' => 'Nom - Alfabètic',
|
||||
'sort_rule_op_name_numeric' => 'Nom - Numèric',
|
||||
'sort_rule_op_created_date' => 'Data de creació',
|
||||
'sort_rule_op_updated_date' => 'Data d\'actualització',
|
||||
'sort_rule_op_chapters_first' => 'Capítols a l\'inici',
|
||||
'sort_rule_op_chapters_last' => 'Capítols al final',
|
||||
'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',
|
||||
|
||||
// Maintenance settings
|
||||
'maint' => 'Manteniment',
|
||||
@@ -139,7 +139,7 @@ return [
|
||||
'recycle_bin_contents_empty' => 'La paperera és buida',
|
||||
'recycle_bin_empty' => 'Buida la paperera',
|
||||
'recycle_bin_empty_confirm' => 'Se suprimiran permanentment tots els elements que hi ha a la paperera incloent-hi el contingut que hi hagi a cada element. Esteu segur que voleu buidar la paperera?',
|
||||
'recycle_bin_destroy_confirm' => 'Aquesta acció suprimirà del sistema de manera permanent aquest element, juntament amb tots els fills que es llisten a sota, i no podreu restaurar aquest contingut. Segur que voleu suprimir de manera permanent aquest element?',
|
||||
'recycle_bin_destroy_confirm' => 'This action will permanently delete this item from the system, along with any child elements listed below, and you will not be able to restore this content. Are you sure you want to permanently delete this item?',
|
||||
'recycle_bin_destroy_list' => 'Elements per destruir',
|
||||
'recycle_bin_restore_list' => 'Elements per restaurar',
|
||||
'recycle_bin_restore_confirm' => 'Aquesta acció restaurarà l’element suprimit, incloent-hi els elements fills, a la seva ubicació original. Si la ubicació original s’ha suprimit i és a la paperera, l’element pare també s’haurà de restaurar.',
|
||||
@@ -192,7 +192,7 @@ return [
|
||||
'role_access_api' => 'Accés a l’API del sistema',
|
||||
'role_manage_settings' => 'Gestió de la configuració de l’aplicació',
|
||||
'role_export_content' => 'Exportació de contingut',
|
||||
'role_import_content' => 'Importar contingut',
|
||||
'role_import_content' => 'Import content',
|
||||
'role_editor_change' => 'Canvi de l’editor de pàgina',
|
||||
'role_notifications' => 'Recepció i gestió de notificacions',
|
||||
'role_asset' => 'Permisos de recursos',
|
||||
@@ -308,13 +308,13 @@ return [
|
||||
'webhooks_last_error_message' => 'Darrer missatge d’error:',
|
||||
|
||||
// Licensing
|
||||
'licenses' => 'Llicències',
|
||||
'licenses_desc' => 'Aquesta pàgina detalla informació sobre la llicència de BookStack a més dels projectes i biblioteques que s\'utilitzen en BookStack. Molts projectes enumerats aquí poden ser utilitzats només en un context de desenvolupament.',
|
||||
'licenses_bookstack' => 'Llicència de BookStack',
|
||||
'licenses_php' => 'Llicències de Biblioteques de PHP',
|
||||
'licenses_js' => 'Llicències de Biblioteques de JavaScript',
|
||||
'licenses_other' => 'Altres llicències',
|
||||
'license_details' => 'Detalls de la llicència',
|
||||
'licenses' => 'Licenses',
|
||||
'licenses_desc' => 'This page details license information for BookStack in addition to the projects & libraries that are used within BookStack. Many projects listed may only be used in a development context.',
|
||||
'licenses_bookstack' => 'BookStack License',
|
||||
'licenses_php' => 'PHP Library Licenses',
|
||||
'licenses_js' => 'JavaScript Library Licenses',
|
||||
'licenses_other' => 'Other Licenses',
|
||||
'license_details' => 'License Details',
|
||||
|
||||
//! If editing translations files directly please ignore this in all
|
||||
//! languages apart from en. Content will be auto-copied from en.
|
||||
@@ -348,7 +348,6 @@ return [
|
||||
'lt' => 'Lietuvių Kalba',
|
||||
'lv' => 'Latviešu Valoda',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Nederlands',
|
||||
'pl' => 'Polski',
|
||||
|
||||
@@ -105,10 +105,10 @@ return [
|
||||
'url' => 'El format :attribute no és vàlid.',
|
||||
'uploaded' => 'No s’ha pogut pujar el fitxer. És possible que el servidor no admeti fitxers d’aquesta mida.',
|
||||
|
||||
'zip_file' => 'El :attribute necessita fer referència a un arxiu dins del ZIP.',
|
||||
'zip_file_mime' => 'El :attribute necessita fer referència a un arxiu de tipus :validTyes, trobat :foundType.',
|
||||
'zip_model_expected' => 'S\'esperava un objecte de dades, però s\'ha trobat ":type".',
|
||||
'zip_unique' => 'El :attribute ha de ser únic pel tipus d\'objecte dins del ZIP.',
|
||||
'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.',
|
||||
|
||||
// Custom validation lines
|
||||
'custom' => [
|
||||
|
||||
@@ -47,8 +47,7 @@ return [
|
||||
'strikethrough' => 'Proškrtnuté',
|
||||
'superscript' => 'horní index',
|
||||
'subscript' => 'Dolní index',
|
||||
'text_color' => 'Barva textu',
|
||||
'highlight_color' => 'Barva zvýraznění',
|
||||
'text_color' => 'Barva textu:',
|
||||
'custom_color' => 'Vlastní barva',
|
||||
'remove_color' => 'Odstranit barvu',
|
||||
'background_color' => 'Barva pozadí',
|
||||
|
||||
@@ -63,10 +63,6 @@ return [
|
||||
'import_delete_desc' => 'Potvrzením odstraníte nahraný ZIP soubor. Tento krok nelze vrátit zpět.',
|
||||
'import_errors' => 'Chyby importu',
|
||||
'import_errors_desc' => 'Při pokusu o import došlo k následujícím chybám:',
|
||||
'breadcrumb_siblings_for_page' => 'Navigate siblings for page',
|
||||
'breadcrumb_siblings_for_chapter' => 'Navigate siblings for chapter',
|
||||
'breadcrumb_siblings_for_book' => 'Navigate siblings for book',
|
||||
'breadcrumb_siblings_for_bookshelf' => 'Navigate siblings for shelf',
|
||||
|
||||
// Permissions and restrictions
|
||||
'permissions' => 'Oprávnění',
|
||||
@@ -138,7 +134,7 @@ return [
|
||||
'shelves_copy_permissions_to_books' => 'Kopírovat oprávnění na knihy',
|
||||
'shelves_copy_permissions' => 'Kopírovat oprávnění',
|
||||
'shelves_copy_permissions_explain' => 'Tímto se použije aktuální nastavení oprávnění police na všechny knihy v ní obsažené. Před aktivací se ujistěte, že byly uloženy všechny změny oprávnění této police.',
|
||||
'shelves_copy_permission_success' => '{1}Oprávnění police byla zkopírována na :count knihu|[2,4]Oprávnění police byla zkopírována na :count knihy|[5,*]Oprávnění police byla zkopírována na :count knih',
|
||||
'shelves_copy_permission_success' => 'Oprávnění police byla zkopírována na :count knih',
|
||||
|
||||
// Books
|
||||
'book' => 'Kniha',
|
||||
@@ -198,7 +194,7 @@ return [
|
||||
// Chapters
|
||||
'chapter' => 'Kapitola',
|
||||
'chapters' => 'Kapitoly',
|
||||
'x_chapters' => '{0}:count kapitol|{1}:count kapitola|[2,4]:count kapitoly|[5,*]:count kapitol',
|
||||
'x_chapters' => '{0}:count Kapitol|{1}:count Kapitola|[2,4]:count Kapitoly|[5,*]:count Kapitol',
|
||||
'chapters_popular' => 'Populární kapitoly',
|
||||
'chapters_new' => 'Nová kapitola',
|
||||
'chapters_create' => 'Vytvořit novou kapitolu',
|
||||
@@ -223,7 +219,7 @@ return [
|
||||
// Pages
|
||||
'page' => 'Stránka',
|
||||
'pages' => 'Stránky',
|
||||
'x_pages' => '{0}:count stran|{1}:count strana|[2,4]:count strany|[5,*]:count stran',
|
||||
'x_pages' => '{0}:count Stran|{1}:count Strana|[2,4]:count Strany|[5,*]:count Stran',
|
||||
'pages_popular' => 'Populární stránky',
|
||||
'pages_new' => 'Nová stránka',
|
||||
'pages_attachments' => 'Přílohy',
|
||||
@@ -248,8 +244,8 @@ return [
|
||||
'pages_edit_delete_draft_confirm' => 'Jste si jisti, že chcete odstranit změny vašich konceptů? Všechny vaše změny, od posledního úplného uložení, budou ztraceny a editor bude aktualizován s nejnovějším stavem nekonceptu stránky.',
|
||||
'pages_edit_discard_draft' => 'Zahodit koncept',
|
||||
'pages_edit_switch_to_markdown' => 'Přepnout na Markdown Editor',
|
||||
'pages_edit_switch_to_markdown_clean' => '(Prostý zápis)',
|
||||
'pages_edit_switch_to_markdown_stable' => '(Formátovaný zápis)',
|
||||
'pages_edit_switch_to_markdown_clean' => '(Vytvořený obsah)',
|
||||
'pages_edit_switch_to_markdown_stable' => '(Stabilní obsah)',
|
||||
'pages_edit_switch_to_wysiwyg' => 'Přepnout na WYSIWYG Editor',
|
||||
'pages_edit_switch_to_new_wysiwyg' => 'Přepnout na nový WYSIWYG',
|
||||
'pages_edit_switch_to_new_wysiwyg_desc' => '(V beta testování)',
|
||||
@@ -272,7 +268,6 @@ 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' => 'Upravovat prostý text',
|
||||
'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',
|
||||
@@ -317,7 +312,7 @@ return [
|
||||
'pages_draft_edited_notification' => 'Tato stránka se od té doby změnila. Je doporučeno aktuální koncept zahodit.',
|
||||
'pages_draft_page_changed_since_creation' => 'Tato stránka byla aktualizována od vytvoření tohoto konceptu. Doporučuje se zrušit tento koncept nebo se postarat o to, abyste si nepřepsali žádné již zadané změny.',
|
||||
'pages_draft_edit_active' => [
|
||||
'start_a' => '{1}:count uživatel začal upravovat tuto stránku|[2,4]:count uživatelé začali upravovat tuto stránku|[5,*]:count uživatelů začalo upravovat tuto stránku',
|
||||
'start_a' => 'Uživatelé začali upravovat tuto stránku (celkem :count)',
|
||||
'start_b' => ':userName začal/a upravovat tuto stránku',
|
||||
'time_a' => 'od doby, kdy byla tato stránky naposledy aktualizována',
|
||||
'time_b' => 'v posledních minutách (:minCount min.)',
|
||||
@@ -347,7 +342,7 @@ return [
|
||||
'tags_assigned_chapters' => 'Přiřazeno ke kapitolám',
|
||||
'tags_assigned_books' => 'Přiřazeno ke knihám',
|
||||
'tags_assigned_shelves' => 'Přiřazeno k policím',
|
||||
'tags_x_unique_values' => '{1}:count jedinečná hodnota|[2,4]:count jedinečné hodnoty|[5,*]:count jedinečných hodnot',
|
||||
'tags_x_unique_values' => ':count jedinečných hodnot',
|
||||
'tags_all_values' => 'Všechny hodnoty',
|
||||
'tags_view_tags' => 'Zobrazit štítky',
|
||||
'tags_view_existing_tags' => 'Zobrazit existující štítky',
|
||||
@@ -399,8 +394,8 @@ return [
|
||||
'comment_add' => 'Přidat komentář',
|
||||
'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' => '[0,1]:count archivováno|[2,4]:count archivována|[5,*]:count archivováno',
|
||||
'comment_thread_count' => ':count vlákno komentáře|:count vláken komentářů',
|
||||
'comment_archived_count' => ':count archivováno',
|
||||
'comment_archived_threads' => 'Archivovaná vlákna',
|
||||
'comment_save' => 'Uložit komentář',
|
||||
'comment_new' => 'Nový komentář',
|
||||
|
||||
@@ -348,7 +348,6 @@ return [
|
||||
'lt' => 'Lietuvių Kalba',
|
||||
'lv' => 'Latviešu Valoda',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Nederlands',
|
||||
'pl' => 'Polski',
|
||||
|
||||
@@ -48,7 +48,6 @@ 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',
|
||||
|
||||
@@ -63,10 +63,6 @@ return [
|
||||
'import_delete_desc' => 'Bydd hwn yn dileu\'r mewnforyn ffeil ZIP sy wedi\'i lwytho i fyny, a fydd e ddim gallu cael ei ddadwneud.',
|
||||
'import_errors' => 'Gwallau Mewnforyn',
|
||||
'import_errors_desc' => 'Digwyddodd y gwallau canlynol yn ystod cynnig y mewnforyn:',
|
||||
'breadcrumb_siblings_for_page' => 'Navigate siblings for page',
|
||||
'breadcrumb_siblings_for_chapter' => 'Navigate siblings for chapter',
|
||||
'breadcrumb_siblings_for_book' => 'Navigate siblings for book',
|
||||
'breadcrumb_siblings_for_bookshelf' => 'Navigate siblings for shelf',
|
||||
|
||||
// Permissions and restrictions
|
||||
'permissions' => 'Caniatâd',
|
||||
@@ -272,7 +268,6 @@ 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',
|
||||
|
||||
@@ -348,7 +348,6 @@ return [
|
||||
'lt' => 'Lietuvių Kalba',
|
||||
'lv' => 'Latviešu Valoda',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Nederlands',
|
||||
'pl' => 'Polski',
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
*/
|
||||
return [
|
||||
|
||||
'failed' => 'De indtastede brugeroplysninger stemmer ikke overens med vores registreringer.',
|
||||
'failed' => 'Dee indtastede brugeroplysninger stemmer ikke overens med vores registreringer.',
|
||||
'throttle' => 'For mange mislykkede loginforsøg. Prøv igen om :seconds sekunder.',
|
||||
|
||||
// Login & Register
|
||||
'sign_up' => 'Registrer',
|
||||
'sign_up' => 'Registrér',
|
||||
'log_in' => 'Log ind',
|
||||
'log_in_with' => 'Log ind med :socialDriver',
|
||||
'sign_up_with' => 'Registrér med :socialDriver',
|
||||
@@ -45,28 +45,28 @@ return [
|
||||
|
||||
// Password Reset
|
||||
'reset_password' => 'Nulstil adgangskode',
|
||||
'reset_password_send_instructions' => 'Indtast din e-mail herunder og du vil blive sendt en e-mail med et link til at nulstille din adgangskode.',
|
||||
'reset_password_send_instructions' => 'Indtast din E-Mail herunder og du vil blive sendt en E-Mail med et link til at nulstille din adgangskode.',
|
||||
'reset_password_send_button' => 'Send link til nulstilling',
|
||||
'reset_password_sent' => 'Et link til nulstilling af adgangskode sendes til :email, hvis den e-mail-adresse findes i systemet.',
|
||||
'reset_password_success' => 'Din adgangskode er blevet nulstillet.',
|
||||
'email_reset_subject' => 'Nulstil din :appName adgangskode',
|
||||
'email_reset_text' => 'Du modtager denne e-mail fordi vi har modtaget en anmodning om at nulstille din adgangskode.',
|
||||
'email_reset_text' => 'Du modtager denne E-Mail fordi vi har modtaget en anmodning om at nulstille din adgangskode.',
|
||||
'email_reset_not_requested' => 'Hvis du ikke har anmodet om at få din adgangskode nulstillet, behøver du ikke at foretage dig noget.',
|
||||
|
||||
// Email Confirmation
|
||||
'email_confirm_subject' => 'Bekræft din E-Mail på :appName',
|
||||
'email_confirm_greeting' => 'Tak for at oprette dig på :appName!',
|
||||
'email_confirm_text' => 'Bekræft venligst din e-mail adresse ved at klikke på linket nedenfor:',
|
||||
'email_confirm_action' => 'Bekræft e-mail',
|
||||
'email_confirm_send_error' => 'E-mailbekræftelse kræves, men systemet kunne ikke sende e-mailen. Kontakt administratoren for at sikre, at e-mail er konfigureret korrekt.',
|
||||
'email_confirm_success' => 'Din e-mail er blevet bekræftet! Du bør nu kunne logge ind med denne e-mailadresse.',
|
||||
'email_confirm_text' => 'Bekræft venligst din E-Mail adresse ved at klikke på linket nedenfor:',
|
||||
'email_confirm_action' => 'Bekræft E-Mail',
|
||||
'email_confirm_send_error' => 'E-Mail-bekræftelse kræves, men systemet kunne ikke sende E-Mailen. Kontakt administratoren for at sikre, at E-Mail er konfigureret korrekt.',
|
||||
'email_confirm_success' => 'Din email er blevet bekræftet! Du bør nu kune logge ind med denne emailadresse.',
|
||||
'email_confirm_resent' => 'Bekræftelsesmail sendt, tjek venligst din indboks.',
|
||||
'email_confirm_thanks' => 'Tak for bekræftelsen!',
|
||||
'email_confirm_thanks_desc' => 'Vent venligst et øjeblik, mens din bekræftelse behandles. Hvis du ikke bliver omdirigeret efter 3 sekunder, skal du trykke på linket "Fortsæt" nedenfor for at fortsætte.',
|
||||
|
||||
'email_not_confirmed' => 'E-mailadresse ikke bekræftet',
|
||||
'email_not_confirmed_text' => 'Din e-mailadresse er endnu ikke blevet bekræftet.',
|
||||
'email_not_confirmed_click_link' => 'Klik venligst på linket i e-mailen der blev sendt kort efter du registrerede dig.',
|
||||
'email_not_confirmed' => 'E-Mail adresse ikke bekræftet',
|
||||
'email_not_confirmed_text' => 'Din E-Mail adresse er endnu ikke blevet bekræftet.',
|
||||
'email_not_confirmed_click_link' => 'Klik venligst på linket i E-Mailen der blev sendt kort efter du registrerede dig.',
|
||||
'email_not_confirmed_resend' => 'Hvis du ikke kan finde E-Mailen, kan du du få gensendt bekræftelsesemailen ved at trykke herunder.',
|
||||
'email_not_confirmed_resend_button' => 'Gensend bekræftelsesemail',
|
||||
|
||||
|
||||
@@ -30,8 +30,8 @@ return [
|
||||
'create' => 'Opret',
|
||||
'update' => 'Opdater',
|
||||
'edit' => 'Rediger',
|
||||
'archive' => 'Arkiver',
|
||||
'unarchive' => 'Tilbagekald',
|
||||
'archive' => 'Archive',
|
||||
'unarchive' => 'Un-Archive',
|
||||
'sort' => 'Sorter',
|
||||
'move' => 'Flyt',
|
||||
'copy' => 'Kopier',
|
||||
@@ -50,8 +50,8 @@ return [
|
||||
'unfavourite' => 'Fjern som foretrukken',
|
||||
'next' => 'Næste',
|
||||
'previous' => 'Forrige',
|
||||
'filter_active' => 'Aktivt filter:',
|
||||
'filter_clear' => 'Nulstil filter',
|
||||
'filter_active' => 'Aktivt Filter:',
|
||||
'filter_clear' => 'Nulstil Filter',
|
||||
'download' => 'Hent',
|
||||
'open_in_tab' => 'Åben i ny fane',
|
||||
'open' => 'Åbn',
|
||||
|
||||
@@ -6,8 +6,8 @@ return [
|
||||
|
||||
// Image Manager
|
||||
'image_select' => 'Billedselektion',
|
||||
'image_list' => 'Billedliste',
|
||||
'image_details' => 'Billeddetaljer',
|
||||
'image_list' => 'Billede Liste',
|
||||
'image_details' => 'Billede Detaljer',
|
||||
'image_upload' => 'Upload billede',
|
||||
'image_intro' => 'Her kan du vælge og administrere billeder, der tidligere er blevet uploadet til systemet.',
|
||||
'image_intro_upload' => 'Upload et nyt billede ved at trække en billedfil ind i dette vindue, eller ved at bruge knappen "Upload billede" ovenfor.',
|
||||
|
||||
@@ -48,7 +48,6 @@ 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',
|
||||
|
||||
@@ -63,10 +63,6 @@ return [
|
||||
'import_delete_desc' => 'Dette vil slette den uploadede ZIP-fil og kan ikke fortrydes.',
|
||||
'import_errors' => 'Importfejl',
|
||||
'import_errors_desc' => 'Følgende fejl opstod under importforsøget:',
|
||||
'breadcrumb_siblings_for_page' => 'Navigate siblings for page',
|
||||
'breadcrumb_siblings_for_chapter' => 'Navigate siblings for chapter',
|
||||
'breadcrumb_siblings_for_book' => 'Navigate siblings for book',
|
||||
'breadcrumb_siblings_for_bookshelf' => 'Navigate siblings for shelf',
|
||||
|
||||
// Permissions and restrictions
|
||||
'permissions' => 'Rettigheder',
|
||||
@@ -272,7 +268,6 @@ 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' => 'Klartekst 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',
|
||||
@@ -400,7 +395,7 @@ return [
|
||||
'comment_none' => 'No comments to display',
|
||||
'comment_placeholder' => 'Skriv en kommentar her',
|
||||
'comment_thread_count' => ':count Comment Thread|:count Comment Threads',
|
||||
'comment_archived_count' => ':count Arkiveret',
|
||||
'comment_archived_count' => ':count Archived',
|
||||
'comment_archived_threads' => 'Archived Threads',
|
||||
'comment_save' => 'Gem kommentar',
|
||||
'comment_new' => 'Ny kommentar',
|
||||
@@ -412,12 +407,12 @@ return [
|
||||
'comment_updated_success' => 'Kommentaren er opdateret',
|
||||
'comment_archive_success' => 'Comment archived',
|
||||
'comment_unarchive_success' => 'Comment un-archived',
|
||||
'comment_view' => 'Se kommentar',
|
||||
'comment_jump_to_thread' => 'Hop til tråd',
|
||||
'comment_view' => 'View comment',
|
||||
'comment_jump_to_thread' => 'Jump to thread',
|
||||
'comment_delete_confirm' => 'Er du sikker på, at du vil slette denne kommentar?',
|
||||
'comment_in_reply_to' => 'Som svar til :commentId',
|
||||
'comment_reference' => 'Reference',
|
||||
'comment_reference_outdated' => '(Forældet)',
|
||||
'comment_reference_outdated' => '(Outdated)',
|
||||
'comment_editor_explain' => 'Her er de kommentarer, der er blevet efterladt på denne side. Kommentarer kan tilføjes og administreres, når du ser den gemte side.',
|
||||
|
||||
// Revision
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
return [
|
||||
|
||||
'password' => 'Adgangskoder skal være mindst otte tegn og svare til bekræftelsen.',
|
||||
'user' => "Vi kan ikke finde en bruger med den e-mailadresse.",
|
||||
'user' => "Vi kan ikke finde en bruger med den e-mail adresse.",
|
||||
'token' => 'Linket til nulstilling af adgangskode er ugyldigt for denne e-mail-adresse.',
|
||||
'sent' => 'Vi har sendt dig en e-mail med et link til at nulstille adgangskoden!',
|
||||
'reset' => 'Dit kodeord er blevet nulstillet!',
|
||||
|
||||
@@ -24,12 +24,12 @@ return [
|
||||
'notifications_opt_own_page_changes' => 'Adviser ved ændringer af sider, jeg ejer',
|
||||
'notifications_opt_own_page_comments' => 'Adviser ved kommentarer på sider, jeg ejer',
|
||||
'notifications_opt_comment_replies' => 'Adviser ved svar på mine kommentarer',
|
||||
'notifications_save' => 'Gem indstillinger',
|
||||
'notifications_save' => 'Gem Indstillinger',
|
||||
'notifications_update_success' => 'Indstillinger for notifikationer er blevet opdateret!',
|
||||
'notifications_watched' => 'Overvågede og ignorerede',
|
||||
'notifications_watched' => 'Overvågede & Ignorerede',
|
||||
'notifications_watched_desc' => 'Nedenfor er de elementer, der har brugerdefinerede overvågning aktivt. For at opdatere dine præferencer for disse, gå til elementet og find derefter overvågning i sidepanelet.',
|
||||
|
||||
'auth' => 'Adgang og sikkerhed',
|
||||
'auth' => 'Adgang & Sikkerhed',
|
||||
'auth_change_password' => 'Skift adgangskode',
|
||||
'auth_change_password_desc' => 'Skift den adgangskode, du bruger til at logge ind med. Den skal være mindst 8 tegn lang.',
|
||||
'auth_change_password_success' => 'Adgangskoden er blevet opdateret!',
|
||||
@@ -41,7 +41,7 @@ return [
|
||||
'profile_email_desc' => 'Denne e-mail vil blive brugt til notifikationer og, afhængigt af aktiv systemgodkendelse, systemadgang.',
|
||||
'profile_email_no_permission' => 'Desværre har du ikke tilladelse til at ændre din e-mailadresse. Hvis du ønsker at ændre dette, skal du bede en administrator om at ændre dette for dig.',
|
||||
'profile_avatar_desc' => 'Vælg et billede som vil blive brugt til at repræsentere dig selv over for andre i systemet. Ideelt set bør dette billede være kvadrat og omkring 256px i bredde og højde.',
|
||||
'profile_admin_options' => 'Administratorindstillinger',
|
||||
'profile_admin_options' => 'Administrator Indstillinger',
|
||||
'profile_admin_options_desc' => 'Yderligere indstillinger på administratorniveau, såsom dem der håndterer rolleopgaver, kan findes for din brugerkonto i området "Indstillinger > Brugere".',
|
||||
|
||||
'delete_account' => 'Slet konto',
|
||||
|
||||
@@ -26,14 +26,14 @@ return [
|
||||
'app_secure_images' => 'Højere sikkerhed for billeduploads',
|
||||
'app_secure_images_toggle' => 'Aktiver højere sikkerhed for billeduploads',
|
||||
'app_secure_images_desc' => 'Af performanceårsager er alle billeder offentlige. Denne funktion tilføjer en tilfældig, vanskelig at gætte streng foran billed-url\'er. Sørg for, at mappeindeksering ikke er aktiveret for at forhindre nem adgang.',
|
||||
'app_default_editor' => 'Standard sideeditor',
|
||||
'app_default_editor' => 'Standard Side Editor',
|
||||
'app_default_editor_desc' => 'Vælg hvilken editor der som standard skal bruges ved redigering af nye sider. Dette kan tilsidesættes på side niveau, hvor tilladelser tillader det.',
|
||||
'app_custom_html' => 'Tilpasset HTML head indhold',
|
||||
'app_custom_html_desc' => 'Alt indhold tilføjet her, vil blive indsat i bunden af <head> sektionen på alle sider. Dette er brugbart til overskrivning af styles og tilføjelse af analytics kode.',
|
||||
'app_custom_html_disabled_notice' => 'Brugerdefineret HTML head indhold er deaktiveret på denne indstillingsside for at, at ændringer kan rulles tilbage.',
|
||||
'app_logo' => 'Applikationslogo',
|
||||
'app_logo_desc' => 'Det bruges blandt andet i applikationens headerbar. Dette billede skal være 86px i højden. Store billeder vil blive skaleret ned.',
|
||||
'app_icon' => 'Programikon',
|
||||
'app_icon' => 'Program ikon',
|
||||
'app_icon_desc' => 'Dette ikon bruges til browserfaner og genvejsikoner. Det skal være et 256px kvadratisk PNG-billede.',
|
||||
'app_homepage' => 'Applikationsforside',
|
||||
'app_homepage_desc' => 'Vælg en visning, der skal vises på forsiden i stedet for standardvisningen. Sidetilladelser ignoreres for de valgte sider.',
|
||||
@@ -348,7 +348,6 @@ return [
|
||||
'lt' => 'Lietuvių Kalba',
|
||||
'lv' => 'Latviešu Valoda',
|
||||
'nb' => 'Norsk (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Nederlands',
|
||||
'pl' => 'Polski',
|
||||
|
||||
@@ -48,7 +48,6 @@ return [
|
||||
'superscript' => 'Hochgestellt',
|
||||
'subscript' => 'Tiefgestellt',
|
||||
'text_color' => 'Schriftfarbe',
|
||||
'highlight_color' => 'Markierungsfarbe',
|
||||
'custom_color' => 'Benutzerdefinierte Farbe',
|
||||
'remove_color' => 'Farbe entfernen',
|
||||
'background_color' => 'Hintergrundfarbe',
|
||||
|
||||
@@ -63,10 +63,6 @@ return [
|
||||
'import_delete_desc' => 'Dies löscht die hochgeladene ZIP-Datei und kann nicht rückgängig gemacht werden.',
|
||||
'import_errors' => 'Importfehler',
|
||||
'import_errors_desc' => 'Die folgenden Fehler sind während des Importversuchs aufgetreten:',
|
||||
'breadcrumb_siblings_for_page' => 'Navigate siblings for page',
|
||||
'breadcrumb_siblings_for_chapter' => 'Navigate siblings for chapter',
|
||||
'breadcrumb_siblings_for_book' => 'Navigate siblings for book',
|
||||
'breadcrumb_siblings_for_bookshelf' => 'Navigate siblings for shelf',
|
||||
|
||||
// Permissions and restrictions
|
||||
'permissions' => 'Berechtigungen',
|
||||
@@ -272,7 +268,6 @@ 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',
|
||||
|
||||
@@ -349,7 +349,6 @@ Hinweis: Benutzer können ihre E-Mail-Adresse nach erfolgreicher Registrierung
|
||||
'lt' => 'Litauisch',
|
||||
'lv' => 'Lettisch',
|
||||
'nb' => 'Norwegisch (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Niederländisch',
|
||||
'pl' => 'Polnisch',
|
||||
|
||||
@@ -48,7 +48,6 @@ return [
|
||||
'superscript' => 'Hochgestellt',
|
||||
'subscript' => 'Tiefgestellt',
|
||||
'text_color' => 'Textfarbe',
|
||||
'highlight_color' => 'Markierungsfarbe',
|
||||
'custom_color' => 'Benutzerdefinierte Farbe',
|
||||
'remove_color' => 'Farbe entfernen',
|
||||
'background_color' => 'Hintergrundfarbe',
|
||||
|
||||
@@ -63,10 +63,6 @@ return [
|
||||
'import_delete_desc' => 'Dies löscht die hochgeladene ZIP-Datei und kann nicht rückgängig gemacht werden.',
|
||||
'import_errors' => 'Importfehler',
|
||||
'import_errors_desc' => 'Die folgenden Fehler sind während des Importversuchs aufgetreten:',
|
||||
'breadcrumb_siblings_for_page' => 'Navigate siblings for page',
|
||||
'breadcrumb_siblings_for_chapter' => 'Navigate siblings for chapter',
|
||||
'breadcrumb_siblings_for_book' => 'Navigate siblings for book',
|
||||
'breadcrumb_siblings_for_bookshelf' => 'Navigate siblings for shelf',
|
||||
|
||||
// Permissions and restrictions
|
||||
'permissions' => 'Berechtigungen',
|
||||
@@ -272,7 +268,6 @@ 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',
|
||||
|
||||
@@ -349,7 +349,6 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung
|
||||
'lt' => 'Litauisch',
|
||||
'lv' => 'Lettisch',
|
||||
'nb' => 'Norwegisch (Bokmål)',
|
||||
'ne' => 'नेपाली',
|
||||
'nn' => 'Nynorsk',
|
||||
'nl' => 'Niederländisch',
|
||||
'pl' => 'Polnisch',
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user