Compare commits

..

16 Commits

Author SHA1 Message Date
Dan Brown
3131050acd Updated version and assets for release v25.07.2 2025-08-28 17:41:48 +01:00
Dan Brown
c0d2874892 Merge branch 'development' into release 2025-08-28 17:39:31 +01:00
Dan Brown
481f356068 Updated translator & dependency attribution before release v25.07.2 2025-08-28 17:39:10 +01:00
Dan Brown
955837c9aa Packages: Upgraded php deps to latest versions 2025-08-28 15:02:26 +01:00
Dan Brown
c6e35c2e7c Merge pull request #5775 from BookStackApp/lexical_aug25
Lexical: August 2025 fixes
2025-08-28 15:00:16 +01:00
Dan Brown
0436ccfebf Updated translations with latest Crowdin changes (#5759) 2025-08-28 14:59:36 +01:00
Dan Brown
f5da31037d Lexical: Fixed details tests
Updated to use new test pattern while there.
2025-08-28 11:17:18 +01:00
Dan Brown
46613f76f6 Lexical: Added backspace handling for details
Allows more reliable removal of details block on backspace at first
child position with the details block.
2025-08-27 14:09:38 +01:00
Dan Brown
519acaf324 Lexical: Added better selection display for collapisble blocks 2025-08-27 12:51:36 +01:00
Dan Brown
849bc4d6c3 Lexical: Improved nested details interaction
- Set to open by default on insert.
- Updated selection handling not to always fully cascade to lowest
  editable child on selection, so parents can be reliably selected.
- Updated mouse handling to treat details panes like the root element,
  inserting within-details where relevant.
2025-08-26 14:45:15 +01:00
Dan Brown
ee994fa2b7 Testing: Addressed deprecation in test helper
Also updated version in phpunit config
2025-08-25 15:01:13 +01:00
Dan Brown
13a79b3f96 Shelves: Addressed book edits removing non-visible books
Tracks the non-visible existing books on change, to retain as part of
the assigned books sync.
Added test to cover.

For #5728
2025-08-25 14:17:55 +01:00
Dan Brown
7c79b10fb6 Imports: Fixed drawing IDs not being updated in content
Would leave imported content with inaccessible images in many cases (or
wrong references) although the drawing was still being uploaded &
related to the page.
Added test to cover.

For #5761
2025-08-24 14:02:21 +01:00
Dan Brown
5c481b4282 Testing: Added more deprecation output 2025-08-15 12:42:44 +01:00
Dan Brown
9443682ae4 Maintenance: Addressed a range of deprecations
Updated deps to address deprecations fixed in newer Laravel framework
version.
2025-08-15 12:20:35 +01:00
Dan Brown
0311e3d2d7 Readme: Updated sponsor link
Was leading to a 404.
2025-08-14 16:00:46 +01:00
60 changed files with 758 additions and 442 deletions

View File

@@ -503,3 +503,5 @@ 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

View File

@@ -56,20 +56,37 @@ class BookshelfRepo
/**
* Update which books are assigned to this shelf by syncing the given book ids.
* Function ensures the books are visible to the current user and existing.
* 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.
*/
protected function updateBooks(Bookshelf $shelf, array $bookIds)
protected function updateBooks(Bookshelf $shelf, array $bookIds): void
{
$numericIDs = collect($bookIds)->map(function ($id) {
return intval($id);
});
$syncData = $this->bookQueries->visibleForList()
$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()
->whereIn('id', $bookIds)
->pluck('id')
->mapWithKeys(function ($bookId) use ($numericIDs) {
return [$bookId => ['order' => $numericIDs->search($bookId)]];
});
->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)];
}
$shelf->books()->sync($syncData);
}

View File

@@ -76,7 +76,7 @@ class ZipExportBuilder
$zipFile = tempnam(sys_get_temp_dir(), 'bszip-');
$zip = new ZipArchive();
$opened = $zip->open($zipFile, ZipArchive::CREATE);
$opened = $zip->open($zipFile, ZipArchive::OVERWRITE);
if ($opened !== true) {
throw new ZipExportException('Failed to create zip file for export.');
}

View File

@@ -29,7 +29,10 @@ class ZipImportReferences
/** @var Image[] */
protected array $images = [];
/** @var array<string, Model> */
/**
* Mapping keyed by "type:old-reference-id" with values being the new imported equivalent model.
* @var array<string, Model>
*/
protected array $referenceMap = [];
/** @var array<int, ZipExportPage> */
@@ -108,6 +111,22 @@ 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) {
@@ -134,7 +153,9 @@ 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,

254
composer.lock generated
View File

@@ -62,16 +62,16 @@
},
{
"name": "aws/aws-sdk-php",
"version": "3.352.5",
"version": "3.356.6",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
"reference": "e226dcc96c0a1165d9c8248ec637d1006b883609"
"reference": "079d1936bef94cb7d76113b62e993f2996db6e24"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/e226dcc96c0a1165d9c8248ec637d1006b883609",
"reference": "e226dcc96c0a1165d9c8248ec637d1006b883609",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/079d1936bef94cb7d76113b62e993f2996db6e24",
"reference": "079d1936bef94cb7d76113b62e993f2996db6e24",
"shasum": ""
},
"require": {
@@ -153,9 +153,9 @@
"support": {
"forum": "https://github.com/aws/aws-sdk-php/discussions",
"issues": "https://github.com/aws/aws-sdk-php/issues",
"source": "https://github.com/aws/aws-sdk-php/tree/3.352.5"
"source": "https://github.com/aws/aws-sdk-php/tree/3.356.6"
},
"time": "2025-08-08T18:09:38+00:00"
"time": "2025-08-27T18:06:10+00:00"
},
{
"name": "bacon/bacon-qr-code",
@@ -1117,22 +1117,22 @@
},
{
"name": "guzzlehttp/guzzle",
"version": "7.9.3",
"version": "7.10.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77"
"reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77",
"reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
"reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/promises": "^1.5.3 || ^2.0.3",
"guzzlehttp/psr7": "^2.7.0",
"guzzlehttp/promises": "^2.3",
"guzzlehttp/psr7": "^2.8",
"php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
@@ -1223,7 +1223,7 @@
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.9.3"
"source": "https://github.com/guzzle/guzzle/tree/7.10.0"
},
"funding": [
{
@@ -1239,20 +1239,20 @@
"type": "tidelift"
}
],
"time": "2025-03-27T13:37:11+00:00"
"time": "2025-08-23T22:36:01+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "2.2.0",
"version": "2.3.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c"
"reference": "481557b130ef3790cf82b713667b43030dc9c957"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c",
"reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c",
"url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957",
"reference": "481557b130ef3790cf82b713667b43030dc9c957",
"shasum": ""
},
"require": {
@@ -1260,7 +1260,7 @@
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"phpunit/phpunit": "^8.5.39 || ^9.6.20"
"phpunit/phpunit": "^8.5.44 || ^9.6.25"
},
"type": "library",
"extra": {
@@ -1306,7 +1306,7 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/2.2.0"
"source": "https://github.com/guzzle/promises/tree/2.3.0"
},
"funding": [
{
@@ -1322,20 +1322,20 @@
"type": "tidelift"
}
],
"time": "2025-03-27T13:27:01+00:00"
"time": "2025-08-22T14:34:08+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "2.7.1",
"version": "2.8.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16"
"reference": "21dc724a0583619cd1652f673303492272778051"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16",
"reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051",
"reference": "21dc724a0583619cd1652f673303492272778051",
"shasum": ""
},
"require": {
@@ -1351,7 +1351,7 @@
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"http-interop/http-factory-tests": "0.9.0",
"phpunit/phpunit": "^8.5.39 || ^9.6.20"
"phpunit/phpunit": "^8.5.44 || ^9.6.25"
},
"suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
@@ -1422,7 +1422,7 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.7.1"
"source": "https://github.com/guzzle/psr7/tree/2.8.0"
},
"funding": [
{
@@ -1438,20 +1438,20 @@
"type": "tidelift"
}
],
"time": "2025-03-27T12:30:47+00:00"
"time": "2025-08-23T21:21:41+00:00"
},
{
"name": "guzzlehttp/uri-template",
"version": "v1.0.4",
"version": "v1.0.5",
"source": {
"type": "git",
"url": "https://github.com/guzzle/uri-template.git",
"reference": "30e286560c137526eccd4ce21b2de477ab0676d2"
"reference": "4f4bbd4e7172148801e76e3decc1e559bdee34e1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/uri-template/zipball/30e286560c137526eccd4ce21b2de477ab0676d2",
"reference": "30e286560c137526eccd4ce21b2de477ab0676d2",
"url": "https://api.github.com/repos/guzzle/uri-template/zipball/4f4bbd4e7172148801e76e3decc1e559bdee34e1",
"reference": "4f4bbd4e7172148801e76e3decc1e559bdee34e1",
"shasum": ""
},
"require": {
@@ -1460,7 +1460,7 @@
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"phpunit/phpunit": "^8.5.36 || ^9.6.15",
"phpunit/phpunit": "^8.5.44 || ^9.6.25",
"uri-template/tests": "1.0.0"
},
"type": "library",
@@ -1508,7 +1508,7 @@
],
"support": {
"issues": "https://github.com/guzzle/uri-template/issues",
"source": "https://github.com/guzzle/uri-template/tree/v1.0.4"
"source": "https://github.com/guzzle/uri-template/tree/v1.0.5"
},
"funding": [
{
@@ -1524,7 +1524,7 @@
"type": "tidelift"
}
],
"time": "2025-02-03T10:55:03+00:00"
"time": "2025-08-22T14:27:06+00:00"
},
{
"name": "intervention/gif",
@@ -1739,16 +1739,16 @@
},
{
"name": "laravel/framework",
"version": "v11.45.1",
"version": "v11.45.2",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "b09ba32795b8e71df10856a2694706663984a239"
"reference": "d134bf11e2208c0c5bd488cf19e612ca176b820a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/b09ba32795b8e71df10856a2694706663984a239",
"reference": "b09ba32795b8e71df10856a2694706663984a239",
"url": "https://api.github.com/repos/laravel/framework/zipball/d134bf11e2208c0c5bd488cf19e612ca176b820a",
"reference": "d134bf11e2208c0c5bd488cf19e612ca176b820a",
"shasum": ""
},
"require": {
@@ -1856,7 +1856,7 @@
"league/flysystem-read-only": "^3.25.1",
"league/flysystem-sftp-v3": "^3.25.1",
"mockery/mockery": "^1.6.10",
"orchestra/testbench-core": "^9.13.2",
"orchestra/testbench-core": "^9.16.0",
"pda/pheanstalk": "^5.0.6",
"php-http/discovery": "^1.15",
"phpstan/phpstan": "^2.0",
@@ -1950,7 +1950,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2025-06-03T14:01:40+00:00"
"time": "2025-08-13T20:28:00+00:00"
},
{
"name": "laravel/prompts",
@@ -3540,16 +3540,16 @@
},
{
"name": "nikic/php-parser",
"version": "v5.6.0",
"version": "v5.6.1",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56"
"reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/221b0d0fdf1369c71047ad1d18bb5880017bbc56",
"reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
"reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
"shasum": ""
},
"require": {
@@ -3568,7 +3568,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.0-dev"
"dev-master": "5.x-dev"
}
},
"autoload": {
@@ -3592,9 +3592,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v5.6.0"
"source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1"
},
"time": "2025-07-27T20:03:57+00:00"
"time": "2025-08-13T20:13:15+00:00"
},
{
"name": "nunomaduro/termwind",
@@ -3866,16 +3866,16 @@
},
{
"name": "phpoption/phpoption",
"version": "1.9.3",
"version": "1.9.4",
"source": {
"type": "git",
"url": "https://github.com/schmittjoh/php-option.git",
"reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54"
"reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54",
"reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54",
"url": "https://api.github.com/repos/schmittjoh/php-option/zipball/638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d",
"reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d",
"shasum": ""
},
"require": {
@@ -3883,7 +3883,7 @@
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28"
"phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34"
},
"type": "library",
"extra": {
@@ -3925,7 +3925,7 @@
],
"support": {
"issues": "https://github.com/schmittjoh/php-option/issues",
"source": "https://github.com/schmittjoh/php-option/tree/1.9.3"
"source": "https://github.com/schmittjoh/php-option/tree/1.9.4"
},
"funding": [
{
@@ -3937,7 +3937,7 @@
"type": "tidelift"
}
],
"time": "2024-07-20T21:41:07+00:00"
"time": "2025-08-21T11:53:16+00:00"
},
{
"name": "phpseclib/phpseclib",
@@ -6311,7 +6311,7 @@
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.32.0",
"version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
@@ -6370,7 +6370,7 @@
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0"
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
},
"funding": [
{
@@ -6381,6 +6381,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -6390,16 +6394,16 @@
},
{
"name": "symfony/polyfill-intl-grapheme",
"version": "v1.32.0",
"version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
"reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe"
"reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
"reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70",
"reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70",
"shasum": ""
},
"require": {
@@ -6448,7 +6452,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0"
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0"
},
"funding": [
{
@@ -6459,16 +6463,20 @@
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
"time": "2025-06-27T09:58:17+00:00"
},
{
"name": "symfony/polyfill-intl-idn",
"version": "v1.32.0",
"version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
@@ -6531,7 +6539,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.32.0"
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0"
},
"funding": [
{
@@ -6542,6 +6550,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -6551,7 +6563,7 @@
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.32.0",
"version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
@@ -6612,7 +6624,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0"
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0"
},
"funding": [
{
@@ -6623,6 +6635,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -6632,7 +6648,7 @@
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.32.0",
"version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
@@ -6693,7 +6709,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
},
"funding": [
{
@@ -6704,6 +6720,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -6713,7 +6733,7 @@
},
{
"name": "symfony/polyfill-php80",
"version": "v1.32.0",
"version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
@@ -6773,7 +6793,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0"
"source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0"
},
"funding": [
{
@@ -6784,6 +6804,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -6793,16 +6817,16 @@
},
{
"name": "symfony/polyfill-php83",
"version": "v1.32.0",
"version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php83.git",
"reference": "2fb86d65e2d424369ad2905e83b236a8805ba491"
"reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491",
"reference": "2fb86d65e2d424369ad2905e83b236a8805ba491",
"url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5",
"reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5",
"shasum": ""
},
"require": {
@@ -6849,7 +6873,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php83/tree/v1.32.0"
"source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0"
},
"funding": [
{
@@ -6860,16 +6884,20 @@
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
"time": "2025-07-08T02:45:35+00:00"
},
{
"name": "symfony/polyfill-uuid",
"version": "v1.32.0",
"version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-uuid.git",
@@ -6928,7 +6956,7 @@
"uuid"
],
"support": {
"source": "https://github.com/symfony/polyfill-uuid/tree/v1.32.0"
"source": "https://github.com/symfony/polyfill-uuid/tree/v1.33.0"
},
"funding": [
{
@@ -6939,6 +6967,10 @@
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
@@ -8182,16 +8214,16 @@
},
{
"name": "larastan/larastan",
"version": "v3.6.0",
"version": "v3.6.1",
"source": {
"type": "git",
"url": "https://github.com/larastan/larastan.git",
"reference": "6431d010dd383a9279eb8874a76ddb571738564a"
"reference": "3c223047e374befd1b64959784685d6ecccf66aa"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/larastan/larastan/zipball/6431d010dd383a9279eb8874a76ddb571738564a",
"reference": "6431d010dd383a9279eb8874a76ddb571738564a",
"url": "https://api.github.com/repos/larastan/larastan/zipball/3c223047e374befd1b64959784685d6ecccf66aa",
"reference": "3c223047e374befd1b64959784685d6ecccf66aa",
"shasum": ""
},
"require": {
@@ -8259,7 +8291,7 @@
],
"support": {
"issues": "https://github.com/larastan/larastan/issues",
"source": "https://github.com/larastan/larastan/tree/v3.6.0"
"source": "https://github.com/larastan/larastan/tree/v3.6.1"
},
"funding": [
{
@@ -8267,7 +8299,7 @@
"type": "github"
}
],
"time": "2025-07-11T06:52:52+00:00"
"time": "2025-08-25T07:24:56+00:00"
},
{
"name": "mockery/mockery",
@@ -8689,16 +8721,16 @@
},
{
"name": "phpunit/php-code-coverage",
"version": "11.0.10",
"version": "11.0.11",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "1a800a7446add2d79cc6b3c01c45381810367d76"
"reference": "4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1a800a7446add2d79cc6b3c01c45381810367d76",
"reference": "1a800a7446add2d79cc6b3c01c45381810367d76",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4",
"reference": "4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4",
"shasum": ""
},
"require": {
@@ -8755,7 +8787,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/show"
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.11"
},
"funding": [
{
@@ -8775,7 +8807,7 @@
"type": "tidelift"
}
],
"time": "2025-06-18T08:56:18+00:00"
"time": "2025-08-27T14:37:49+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -9024,16 +9056,16 @@
},
{
"name": "phpunit/phpunit",
"version": "11.5.31",
"version": "11.5.35",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "fc44414e0779e94640663b809557b0b599548260"
"reference": "d341ee94ee5007b286fc7907b383aae6b5b3cc91"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fc44414e0779e94640663b809557b0b599548260",
"reference": "fc44414e0779e94640663b809557b0b599548260",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d341ee94ee5007b286fc7907b383aae6b5b3cc91",
"reference": "d341ee94ee5007b286fc7907b383aae6b5b3cc91",
"shasum": ""
},
"require": {
@@ -9047,7 +9079,7 @@
"phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1",
"php": ">=8.2",
"phpunit/php-code-coverage": "^11.0.10",
"phpunit/php-code-coverage": "^11.0.11",
"phpunit/php-file-iterator": "^5.1.0",
"phpunit/php-invoker": "^5.0.1",
"phpunit/php-text-template": "^4.0.1",
@@ -9105,7 +9137,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.31"
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.35"
},
"funding": [
{
@@ -9129,7 +9161,7 @@
"type": "tidelift"
}
],
"time": "2025-08-11T05:27:39+00:00"
"time": "2025-08-28T05:13:54+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -9908,23 +9940,23 @@
},
{
"name": "sebastian/recursion-context",
"version": "6.0.2",
"version": "6.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/recursion-context.git",
"reference": "694d156164372abbd149a4b85ccda2e4670c0e16"
"reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/694d156164372abbd149a4b85ccda2e4670c0e16",
"reference": "694d156164372abbd149a4b85ccda2e4670c0e16",
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/f6458abbf32a6c8174f8f26261475dc133b3d9dc",
"reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc",
"shasum": ""
},
"require": {
"php": ">=8.2"
},
"require-dev": {
"phpunit/phpunit": "^11.0"
"phpunit/phpunit": "^11.3"
},
"type": "library",
"extra": {
@@ -9960,15 +9992,27 @@
"support": {
"issues": "https://github.com/sebastianbergmann/recursion-context/issues",
"security": "https://github.com/sebastianbergmann/recursion-context/security/policy",
"source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.2"
"source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.3"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
},
{
"url": "https://liberapay.com/sebastianbergmann",
"type": "liberapay"
},
{
"url": "https://thanks.dev/u/gh/sebastianbergmann",
"type": "thanks_dev"
},
{
"url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context",
"type": "tidelift"
}
],
"time": "2024-07-03T05:10:34+00:00"
"time": "2025-08-13T04:42:22+00:00"
},
{
"name": "sebastian/type",

View File

@@ -2,6 +2,7 @@
namespace Database\Factories\Entities\Models;
use BookStack\Entities\Tools\PageEditorType;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
@@ -29,6 +30,7 @@ class PageFactory extends Factory
'html' => $html,
'text' => strip_tags($html),
'revision_count' => 1,
'editor' => 'wysiwyg',
];
}
}

View File

@@ -1 +1 @@
8718aa88d39b7ede22c7e7734da8533165776f51210905afc360a996ca3a7356
fa162564940d9a81e4dd0b20ae8775d32f2ea5c615e33ebcc8adf035d958c352

View File

@@ -18,35 +18,35 @@ return [
'page_move_notification' => 'Sha mogut la pàgina',
// Chapters
'chapter_create' => 'ha creat el capítol',
'chapter_create' => 'S\'ha creat el capítol',
'chapter_create_notification' => 'Sha creat el capítol',
'chapter_update' => 'ha actualitzat el capítol',
'chapter_update_notification' => 'Sha actualitzat el capítol',
'chapter_delete' => 'ha suprimit el capítol',
'chapter_delete_notification' => 'Sha suprimit el capítol',
'chapter_move' => 'ha mogut el capítol',
'chapter_move' => 's\'ha mogut el capítol',
'chapter_move_notification' => 'Sha mogut el capítol',
// Books
'book_create' => 'ha creat el llibre',
'book_create' => 'llibre creat',
'book_create_notification' => 'Sha creat el llibre',
'book_create_from_chapter' => 'ha convertit el capítol a llibre',
'book_create_from_chapter_notification' => 'Sha convertit el capítol a llibre',
'book_update' => 'ha actualitzat el llibre',
'book_update' => 'llibre actualitzat',
'book_update_notification' => 'Sha actualitzat el llibre',
'book_delete' => 'ha suprimit el llibre',
'book_delete' => 'llibre suprimit',
'book_delete_notification' => 'Sha suprimit el llibre',
'book_sort' => 'ha ordenat el llibre',
'book_sort' => 'llibre ordenat',
'book_sort_notification' => 'Sha tornat a ordenar el llibre',
// Bookshelves
'bookshelf_create' => 'ha creat el prestatge',
'bookshelf_create_notification' => 'Sha creat el prestatge',
'bookshelf_create_from_book' => 'ha convertit el llibre a prestatge',
'bookshelf_create_from_book' => 'llibre convertit a prestatge',
'bookshelf_create_from_book_notification' => 'Sha convertit el llibre a prestatge',
'bookshelf_update' => 'ha actualitzat el prestatge',
'bookshelf_update' => 'prestatge actualitzat',
'bookshelf_update_notification' => 'Sha actualitzat el prestatge',
'bookshelf_delete' => 'ha suprimit el prestatge',
'bookshelf_delete' => 'prestatge suprimit',
'bookshelf_delete_notification' => 'Sha suprimit el prestatge',
// Revisions
@@ -85,12 +85,12 @@ return [
'webhook_delete_notification' => 'Sha suprimit el webhook',
// Imports
'import_create' => 'created import',
'import_create_notification' => 'Import successfully uploaded',
'import_run' => 'updated import',
'import_run_notification' => 'Content successfully imported',
'import_delete' => 'deleted import',
'import_delete_notification' => 'Import successfully deleted',
'import_create' => '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',
// Users
'user_create' => 'ha creat lusuari',
@@ -128,12 +128,12 @@ return [
'comment_delete' => 'ha suprimit un comentari',
// Sort Rules
'sort_rule_create' => 'created sort rule',
'sort_rule_create_notification' => 'Sort rule successfully created',
'sort_rule_update' => 'updated sort rule',
'sort_rule_update_notification' => 'Sort rule successfully updated',
'sort_rule_delete' => 'deleted sort rule',
'sort_rule_delete_notification' => 'Sort rule successfully deleted',
'sort_rule_create' => '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',
// Other
'permissions_update' => 'ha actualitzat els permisos',

View File

@@ -30,8 +30,8 @@ return [
'create' => 'Crea',
'update' => 'Actualitza',
'edit' => 'Edita',
'archive' => 'Archive',
'unarchive' => 'Un-Archive',
'archive' => 'Arxivar',
'unarchive' => 'Desarxivar',
'sort' => 'Ordena',
'move' => 'Mou',
'copy' => 'Copia',
@@ -111,5 +111,5 @@ return [
'terms_of_service' => 'Condicions del servei',
// OpenSearch
'opensearch_description' => 'Search :appName',
'opensearch_description' => 'Buscar :appName',
];

View File

@@ -25,7 +25,7 @@ return [
'width' => 'Amplada',
'height' => 'Altura',
'More' => 'Més',
'select' => 'Selecciona…',
'select' => 'Selecciona …',
// Toolbar
'formats' => 'Formats',
@@ -48,7 +48,7 @@ return [
'superscript' => 'Superíndex',
'subscript' => 'Subíndex',
'text_color' => 'Color del text',
'highlight_color' => 'Highlight color',
'highlight_color' => 'Color ressaltat',
'custom_color' => 'Color personalitzat',
'remove_color' => 'Elimina el color',
'background_color' => 'Color de fons',
@@ -149,7 +149,7 @@ return [
'url' => 'URL',
'text_to_display' => 'Text per a mostrar',
'title' => 'Títol',
'browse_links' => 'Browse links',
'browse_links' => 'Explorar enllaços',
'open_link' => 'Obre lenllaç',
'open_link_in' => 'Obre lenllaç…',
'open_link_current' => 'A la finestra actual',
@@ -166,8 +166,8 @@ return [
'about' => 'Quant a lEditor',
'about_title' => 'Quant a lEditor WYSIWYG',
'editor_license' => 'Llicència i copyright de lEditor',
'editor_lexical_license' => 'This editor is built as a fork of :lexicalLink which is distributed under the MIT license.',
'editor_lexical_license_link' => 'Full license details can be found here.',
'editor_lexical_license' => '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_tiny_license' => 'Aquest editor sha 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',

View File

@@ -39,34 +39,34 @@ return [
'export_pdf' => 'Fitxer PDF',
'export_text' => 'Fitxer de text sense format',
'export_md' => 'Fitxer Markdown',
'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:',
'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',
'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',
// Permissions and restrictions
'permissions' => 'Permisos',
@@ -170,9 +170,9 @@ return [
'books_search_this' => 'Cerca en aquest llibre',
'books_navigation' => 'Navegació del llibre',
'books_sort' => 'Ordena el contingut dun llibre',
'books_sort_desc' => 'Move chapters and pages within a book to reorganise its contents. Other books can be added which allows easy moving of chapters and pages between books. Optionally an auto sort rule can be set to automatically sort this book\'s contents upon changes.',
'books_sort_auto_sort' => 'Auto Sort Option',
'books_sort_auto_sort_active' => 'Auto Sort Active: :sortName',
'books_sort_desc' => '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_named' => 'Ordena el llibre &laquo;:bookName&raquo;',
'books_sort_name' => 'Ordena pel nom',
'books_sort_created' => 'Ordena per la data de creació',
@@ -234,7 +234,7 @@ return [
'pages_delete_draft' => 'Suprimeix lesborrany de pàgina',
'pages_delete_success' => 'Sha suprimit la pàgina',
'pages_delete_draft_success' => 'Sha suprimit lesborrany de 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_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_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 &laquo;:pageName&raquo;',
@@ -251,8 +251,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 leditor WYSIWYG',
'pages_edit_switch_to_new_wysiwyg' => 'Switch to new WYSIWYG',
'pages_edit_switch_to_new_wysiwyg_desc' => '(In Beta Testing)',
'pages_edit_switch_to_new_wysiwyg' => 'Canviar al nou editor WYSIWYG',
'pages_edit_switch_to_new_wysiwyg_desc' => '(En Beta Test)',
'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 +272,7 @@ return [
'pages_md_insert_drawing' => 'Insereix un dibuix',
'pages_md_show_preview' => 'Mostra la visualització prèvia',
'pages_md_sync_scroll' => 'Sincronitza el desplaçament de la visualització prèvia',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_md_plain_editor' => 'Editor de text pla',
'pages_drawing_unsaved' => 'Sha trobat un dibuix sense desar',
'pages_drawing_unsaved_confirm' => 'Shan trobat dades dun dibuix dun intent anterior de desar un dibuix. Voleu restaurar aquest dibuix no desat per a reprendren ledició?',
'pages_not_in_chapter' => 'La pàgina no és un capítol',
@@ -397,11 +397,11 @@ return [
'comment' => 'Comentari',
'comments' => 'Comentaris',
'comment_add' => 'Afegeix un comentari',
'comment_none' => 'No comments to display',
'comment_none' => 'No hi ha comentaris per mostrar',
'comment_placeholder' => 'Deixa un comentari aquí',
'comment_thread_count' => ':count Comment Thread|:count Comment Threads',
'comment_archived_count' => ':count Archived',
'comment_archived_threads' => 'Archived Threads',
'comment_thread_count' => ':count fil de comentaris|:count fils de comentaris',
'comment_archived_count' => ':count Arxivats',
'comment_archived_threads' => 'Fils arxivats',
'comment_save' => 'Desa el comentari',
'comment_new' => 'Crea un comentari',
'comment_created' => 'ha comentat :createDiff',
@@ -410,14 +410,14 @@ return [
'comment_deleted_success' => 'Sha suprimit el comentari',
'comment_created_success' => 'Sha afegit un comentari',
'comment_updated_success' => 'Sha actualitzat un comentari',
'comment_archive_success' => 'Comment archived',
'comment_unarchive_success' => 'Comment un-archived',
'comment_view' => 'View comment',
'comment_jump_to_thread' => 'Jump to thread',
'comment_archive_success' => 'Comentari arxivat',
'comment_unarchive_success' => 'Comentari desarxivat',
'comment_view' => 'Mostra el comentari',
'comment_jump_to_thread' => 'Anar al fil',
'comment_delete_confirm' => 'Esteu segur que voleu suprimir aquest comentari?',
'comment_in_reply_to' => 'En resposta a :commentId',
'comment_reference' => 'Reference',
'comment_reference_outdated' => '(Outdated)',
'comment_reference' => 'Referència',
'comment_reference_outdated' => '(Obsolet)',
'comment_editor_explain' => 'Vet aquí els comentaris que shan fet en aquesta pàgina. Els comentaris es poden fer i gestionar quan es visualitza la pàgina desada.',
// Revision

View File

@@ -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 fer lacció sol·licitada.',
'permissionJson' => 'No teniu permís per a executar lacció 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' => 'User account could not be registered for the provided details',
'email_already_confirmed' => 'Ja sha confirmat el correu electrònic. Proveu diniciar sessió.',
'auth_pre_register_theme_prevention' => 'El compte d\'usuari no s\'ha pogut registrar amb els detalls proporcionats',
'email_already_confirmed' => 'Ladreça electrònica ja està confirmada. Proveu diniciar la sessió.',
'email_confirmation_invalid' => 'Aquest testimoni de confirmació no és vàlid o ja sha utilitzat. Proveu de tornar-vos a registrar.',
'email_confirmation_expired' => 'Aquest testimoni de confirmació ha caducat. Sha enviat un altre correu electrònic de confirmació.',
'email_confirmation_awaiting' => 'Cal confirmar ladreça electrònica del compte que utilitzeu.',
'email_confirmation_awaiting' => 'Cal confirmar ladreça electrònica del compte que utilitzeu',
'ldap_fail_anonymous' => 'Laccés LDAP anònim ha fallat',
'ldap_fail_authed' => 'Laccés LDAP amb el nom distintiu i la contrasenya proporcionades',
'ldap_fail_authed' => 'Laccés LDAP amb el nom distintiu i la contrasenya proporcionats ha fallat',
'ldap_extension_not_installed' => 'Lextensió PHP de lLDAP no està instal·lada',
'ldap_cannot_connect' => 'No sha 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 sha definit cap acció',
'social_login_bad_response' => "Sha produït un error en linici de sessió amb :socialAccount: \n:error",
'social_account_in_use' => 'Aquest compte de :socialAccount ja sestà utilitzant. Proveu diniciar sessió amb :socialAccount.',
'social_account_email_in_use' => 'Ladreça electrònica :email ja sestà utilitzant. Si ja teniu uns compte podeu connectar-hi el vostre compte de :socialAccount des de la configuració del vostre perfil.',
'social_account_email_in_use' => 'Ladreç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_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 lopció :socialAccount.',
'social_driver_not_found' => 'No sha trobat el controlador social',
'social_driver_not_configured' => 'La configuració de :socialAccount no és correcta.',
'invite_token_expired' => 'Aquest enllaç dinvitació ha caducat. Proveu de reinicialitzar la contrasenya.',
'login_user_not_found' => 'A user for this action could not be found.',
'invite_token_expired' => 'Aquest enllaç dinvitació 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ó.',
// System
'path_not_writable' => 'No sha pogut pujar a :filePath. Assegureu-vos que teniu permisos descriptura al servidor.',
@@ -78,7 +78,7 @@ return [
// Users
'users_cannot_delete_only_admin' => 'No podeu suprimir ladministrador únic.',
'users_cannot_delete_guest' => 'No podeu suprimir lusuari convidat.',
'users_could_not_send_invite' => 'Could not create user since invite email failed to send',
'users_could_not_send_invite' => 'No s\'ha pogut crear l\'usuari, ja que no s\'ha pogut enviar el correu d\'invitació',
// 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' => 'Could not read ZIP file.',
'import_zip_cant_decode_data' => 'Could not find and decode ZIP data.json content.',
'import_zip_no_data' => 'ZIP file data has no expected book, chapter or page content.',
'import_validation_failed' => 'Import ZIP failed to validate with errors:',
'import_zip_failed_notification' => 'Failed to import ZIP file.',
'import_perms_books' => 'You are lacking the required permissions to create books.',
'import_perms_chapters' => 'You are lacking the required permissions to create chapters.',
'import_perms_pages' => 'You are lacking the required permissions to create pages.',
'import_perms_images' => 'You are lacking the required permissions to create images.',
'import_perms_attachments' => 'You are lacking the required permission to create attachments.',
'import_zip_cant_read' => '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.',
// API errors
'api_no_authorization_found' => 'No sha trobat cap testimoni dautorització en aquesta sol·licitud.',

View File

@@ -13,7 +13,7 @@ return [
'updated_page_debounce' => 'Per a evitar que sacumulin 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' => 'Camí de la pàgina:',
'detail_page_path' => 'Ruta de la pàgina:',
'detail_commenter' => 'Autor del comentari:',
'detail_comment' => 'Comentari:',
'detail_created_by' => 'Creada per:',

View File

@@ -8,7 +8,7 @@ return [
// Common Messages
'settings' => 'Configuració',
'settings_save' => 'Configuració de desat',
'settings_save' => 'Guardar configuració',
'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ó les visitants podran accedir a la vostra instància del BookStack sense iniciar sessió.',
'app_public_access_desc_guest' => 'Laccés per als visitants públics es pot gestionar amb lusuari &laquo;Convidat&raquo;.',
'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' => 'Laccés per als visitants públics es pot gestionar amb lusuari Convidat.',
'app_public_access_toggle' => 'Permet laccés públic',
'app_public_viewing' => 'Esteu segur que voleu permetre laccés públic?',
'app_secure_images' => 'Pujada dimatges amb més seguretat',
@@ -75,34 +75,34 @@ return [
'reg_confirm_restrict_domain_placeholder' => 'No hi ha cap restricció',
// Sorting Settings
'sorting' => 'Sorting',
'sorting_book_default' => 'Default Book Sort',
'sorting_book_default_desc' => 'Select the default sort rule to apply to new books. This won\'t affect existing books, and can be overridden per-book.',
'sorting_rules' => 'Sort Rules',
'sorting_rules_desc' => 'These are predefined sorting operations which can be applied to content in the system.',
'sort_rule_assigned_to_x_books' => 'Assigned to :count Book|Assigned to :count Books',
'sort_rule_create' => 'Create Sort Rule',
'sort_rule_edit' => 'Edit Sort Rule',
'sort_rule_delete' => 'Delete Sort Rule',
'sort_rule_delete_desc' => 'Remove this sort rule from the system. Books using this sort will revert to manual sorting.',
'sort_rule_delete_warn_books' => 'This sort rule is currently used on :count book(s). Are you sure you want to delete this?',
'sort_rule_delete_warn_default' => 'This sort rule is currently used as the default for books. Are you sure you want to delete this?',
'sort_rule_details' => 'Sort Rule Details',
'sort_rule_details_desc' => 'Set a name for this sort rule, which will appear in lists when users are selecting a sort.',
'sort_rule_operations' => 'Sort Operations',
'sort_rule_operations_desc' => 'Configure the sort actions to be performed by moving them from the list of available operations. Upon use, the operations will be applied in order, from top to bottom. Any changes made here will be applied to all assigned books upon save.',
'sort_rule_available_operations' => 'Available Operations',
'sort_rule_available_operations_empty' => 'No operations remaining',
'sort_rule_configured_operations' => 'Configured Operations',
'sort_rule_configured_operations_empty' => 'Drag/add operations from the "Available Operations" list',
'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',
'sort_rule_op_asc' => '(Asc)',
'sort_rule_op_desc' => '(Desc)',
'sort_rule_op_name' => 'Name - Alphabetical',
'sort_rule_op_name_numeric' => 'Name - Numeric',
'sort_rule_op_created_date' => 'Created Date',
'sort_rule_op_updated_date' => 'Updated Date',
'sort_rule_op_chapters_first' => 'Chapters First',
'sort_rule_op_chapters_last' => 'Chapters Last',
'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',
// 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' => '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_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_list' => 'Elements per destruir',
'recycle_bin_restore_list' => 'Elements per restaurar',
'recycle_bin_restore_confirm' => 'Aquesta acció restaurarà lelement suprimit, incloent-hi els elements fills, a la seva ubicació original. Si la ubicació original sha suprimit i és a la paperera, lelement pare també shaurà de restaurar.',
@@ -192,7 +192,7 @@ return [
'role_access_api' => 'Accés a lAPI del sistema',
'role_manage_settings' => 'Gestió de la configuració de laplicació',
'role_export_content' => 'Exportació de contingut',
'role_import_content' => 'Import content',
'role_import_content' => 'Importar contingut',
'role_editor_change' => 'Canvi de leditor 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 derror:',
// Licensing
'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',
'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',
//! If editing translations files directly please ignore this in all
//! languages apart from en. Content will be auto-copied from en.

View File

@@ -105,10 +105,10 @@ return [
'url' => 'El format :attribute no és vàlid.',
'uploaded' => 'No sha pogut pujar el fitxer. És possible que el servidor no admeti fitxers daquesta mida.',
'zip_file' => 'The :attribute needs to reference a file within the ZIP.',
'zip_file_mime' => 'The :attribute needs to reference a file of type :validTypes, found :foundType.',
'zip_model_expected' => 'Data object expected but ":type" found.',
'zip_unique' => 'The :attribute must be unique for the object type within the ZIP.',
'zip_file' => '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.',
// Custom validation lines
'custom' => [

View File

@@ -6,11 +6,11 @@
*/
return [
'failed' => 'Dee indtastede brugeroplysninger stemmer ikke overens med vores registreringer.',
'failed' => 'De indtastede brugeroplysninger stemmer ikke overens med vores registreringer.',
'throttle' => 'For mange mislykkede loginforsøg. Prøv igen om :seconds sekunder.',
// Login & Register
'sign_up' => 'Registrér',
'sign_up' => 'Registrer',
'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-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_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_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-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' => '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_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',

View File

@@ -30,8 +30,8 @@ return [
'create' => 'Opret',
'update' => 'Opdater',
'edit' => 'Rediger',
'archive' => 'Archive',
'unarchive' => 'Un-Archive',
'archive' => 'Arkiver',
'unarchive' => 'Tilbagekald',
'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',

View File

@@ -6,8 +6,8 @@ return [
// Image Manager
'image_select' => 'Billedselektion',
'image_list' => 'Billede Liste',
'image_details' => 'Billede Detaljer',
'image_list' => 'Billedliste',
'image_details' => 'Billeddetaljer',
'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.',

View File

@@ -272,7 +272,7 @@ return [
'pages_md_insert_drawing' => 'Indsæt tegning',
'pages_md_show_preview' => 'Vis forhåndsvisning',
'pages_md_sync_scroll' => 'Rulning af forhåndsvisning af synkronisering',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_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 +400,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 Archived',
'comment_archived_count' => ':count Arkiveret',
'comment_archived_threads' => 'Archived Threads',
'comment_save' => 'Gem kommentar',
'comment_new' => 'Ny kommentar',
@@ -412,12 +412,12 @@ return [
'comment_updated_success' => 'Kommentaren er opdateret',
'comment_archive_success' => 'Comment archived',
'comment_unarchive_success' => 'Comment un-archived',
'comment_view' => 'View comment',
'comment_jump_to_thread' => 'Jump to thread',
'comment_view' => 'Se kommentar',
'comment_jump_to_thread' => 'Hop til tråd',
'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' => '(Outdated)',
'comment_reference_outdated' => '(Forældet)',
'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

View File

@@ -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-mail adresse.",
'user' => "Vi kan ikke finde en bruger med den e-mailadresse.",
'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!',

View File

@@ -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 & Ignorerede',
'notifications_watched' => 'Overvågede og 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 & Sikkerhed',
'auth' => 'Adgang og 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' => 'Administrator Indstillinger',
'profile_admin_options' => 'Administratorindstillinger',
'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',

View File

@@ -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 Side Editor',
'app_default_editor' => 'Standard sideeditor',
'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' => 'Program ikon',
'app_icon' => 'Programikon',
'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.',

View File

@@ -63,10 +63,10 @@ return [
'import_delete_desc' => 'See kustutab üleslaaditud ZIP-faili, ja seda ei saa tagasi võtta.',
'import_errors' => 'Importimise vead',
'import_errors_desc' => 'Importimisel esinesid järgmised vead:',
'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',
'breadcrumb_siblings_for_page' => 'Sirvi teisi lehti',
'breadcrumb_siblings_for_chapter' => 'Sirvi teisi peatükke',
'breadcrumb_siblings_for_book' => 'Sirvi teisi raamatuid',
'breadcrumb_siblings_for_bookshelf' => 'Sirvi teisi riiuleid',
// Permissions and restrictions
'permissions' => 'Õigused',

View File

@@ -63,10 +63,10 @@ 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',
'breadcrumb_siblings_for_page' => '階層内のページ',
'breadcrumb_siblings_for_chapter' => '階層内のチャプタ',
'breadcrumb_siblings_for_book' => '階層内のブック',
'breadcrumb_siblings_for_bookshelf' => '階層内の棚',
// Permissions and restrictions
'permissions' => '権限',

View File

@@ -122,7 +122,7 @@ return [
'recycle_bin_destroy' => 'verwijderde van prullenbak',
// Comments
'commented_on' => 'reageerde op',
'commented_on' => 'plaatste opmerking in',
'comment_create' => 'voegde opmerking toe',
'comment_update' => 'paste opmerking aan',
'comment_delete' => 'verwijderde opmerking',

View File

@@ -40,7 +40,7 @@ return [
'delete_confirm' => 'Verwijdering bevestigen',
'search' => 'Zoek',
'search_clear' => 'Zoekopdracht wissen',
'reset' => 'Reset',
'reset' => 'Wissen',
'remove' => 'Verwijder',
'add' => 'Voeg toe',
'configure' => 'Configureer',

View File

@@ -48,7 +48,7 @@ return [
'superscript' => 'Superscript',
'subscript' => 'Subscript',
'text_color' => 'Tekstkleur',
'highlight_color' => 'Highlight color',
'highlight_color' => 'Accentkleur',
'custom_color' => 'Aangepaste kleur',
'remove_color' => 'Verwijder kleur',
'background_color' => 'Tekstmarkeringskleur',

View File

@@ -63,10 +63,10 @@ return [
'import_delete_desc' => 'Dit zal het Zip-bestand van de import permanent verwijderen.',
'import_errors' => 'Importeerfouten',
'import_errors_desc' => 'De volgende fouten deden zich voor tijdens het importeren:',
'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',
'breadcrumb_siblings_for_page' => 'Navigeer pagina\'s op hetzelfde niveau',
'breadcrumb_siblings_for_chapter' => 'Navigeer hoofdstukken op hetzelfde niveau',
'breadcrumb_siblings_for_book' => 'Navigeer boeken op hetzelfde niveau',
'breadcrumb_siblings_for_bookshelf' => 'Navigeer boekenplanken op hetzelfde niveau',
// Permissions and restrictions
'permissions' => 'Machtigingen',
@@ -272,11 +272,11 @@ return [
'pages_md_insert_drawing' => 'Tekening invoegen',
'pages_md_show_preview' => 'Toon voorbeeld',
'pages_md_sync_scroll' => 'Synchroniseer scrollen van voorbeeld',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_md_plain_editor' => 'Normale tekst bewerker',
'pages_drawing_unsaved' => 'Niet-opgeslagen Tekening Gevonden',
'pages_drawing_unsaved_confirm' => 'Er zijn niet-opgeslagen tekeninggegevens gevonden van een eerdere mislukte poging om de tekening op te slaan. Wil je deze niet-opgeslagen tekening herstellen en verder bewerken?',
'pages_not_in_chapter' => 'Pagina is niet in een hoofdstuk',
'pages_move' => 'Pagina verplaatsten',
'pages_move' => 'Pagina Verplaatsen',
'pages_copy' => 'Pagina kopiëren',
'pages_copy_desination' => 'Kopieër bestemming',
'pages_copy_success' => 'Pagina succesvol gekopieerd',
@@ -394,27 +394,27 @@ return [
'profile_not_created_shelves' => ':userName heeft geen boekenplanken gemaakt',
// Comments
'comment' => 'Reactie',
'comments' => 'Reacties',
'comment_add' => 'Reactie toevoegen',
'comment' => 'Opmerking',
'comments' => 'Opmerkingen',
'comment_add' => 'Opmerking toevoegen',
'comment_none' => 'Geen opmerkingen om weer te geven',
'comment_placeholder' => 'Laat hier een reactie achter',
'comment_thread_count' => ':count Reactie Thread|:count Reactie Threads',
'comment_placeholder' => 'Laat hier een opmerking achter',
'comment_thread_count' => ':count Opmerking Thread|:count Opmerking Threads',
'comment_archived_count' => ':count Gearchiveerd',
'comment_archived_threads' => 'Gearchiveerde Threads',
'comment_save' => 'Sla reactie op',
'comment_new' => 'Nieuwe reactie',
'comment_created' => 'reactie gegeven :createDiff',
'comment_save' => 'Sla opmerking op',
'comment_new' => 'Nieuwe opmerking',
'comment_created' => 'opmerking gegeven :createDiff',
'comment_updated' => 'Updatet :updateDiff door :username',
'comment_updated_indicator' => 'Bijgewerkt',
'comment_deleted_success' => 'Reactie verwijderd',
'comment_created_success' => 'Reactie toegevoegd',
'comment_updated_success' => 'Reactie bijgewerkt',
'comment_deleted_success' => 'Opmerking verwijderd',
'comment_created_success' => 'Opmerking toegevoegd',
'comment_updated_success' => 'Opmerking bijgewerkt',
'comment_archive_success' => 'Opmerking gearchiveerd',
'comment_unarchive_success' => 'Opmerking teruggehaald',
'comment_view' => 'Opmerking weergeven',
'comment_jump_to_thread' => 'Ga naar thread',
'comment_delete_confirm' => 'Weet je zeker dat je deze reactie wilt verwijderen?',
'comment_delete_confirm' => 'Weet je zeker dat je deze opmerking wilt verwijderen?',
'comment_in_reply_to' => 'Als antwoord op :commentId',
'comment_reference' => 'Verwijzing',
'comment_reference_outdated' => '(Verouderd)',
@@ -466,11 +466,11 @@ return [
'watch_desc_comments_page' => 'Geef een melding van pagina wijzigingen en nieuwe opmerkingen.',
'watch_change_default' => 'Standaardvoorkeuren voor meldingen wijzigen',
'watch_detail_ignore' => 'Meldingen negeren',
'watch_detail_new' => 'Op de uitkijk voor nieuwe pagina\'s',
'watch_detail_updates' => 'Op de uitkijk voor nieuwe pagina\'s en aanpassingen',
'watch_detail_comments' => 'Op de uitkijk voor nieuwe pagina\'s, aanpassingen en opmerkingen',
'watch_detail_parent_book' => 'Op de uitkijk via hogerliggend boek',
'watch_detail_parent_book_ignore' => 'Aan het negeren via hogerliggend boek',
'watch_detail_parent_chapter' => 'Op de uitkijk via hogerliggend hoofdstuk',
'watch_detail_parent_chapter_ignore' => 'Aan het negeren via hogerliggend hoofdstuk',
'watch_detail_new' => 'Nieuwe pagina\'s aan het volgen',
'watch_detail_updates' => 'Nieuwe pagina\'s en aanpassingen aan het volgen',
'watch_detail_comments' => 'Nieuwe pagina\'s, aanpassingen en opmerkingen aan het volgen',
'watch_detail_parent_book' => 'Aan het volgen via bovenliggend boek',
'watch_detail_parent_book_ignore' => 'Aan het negeren via bovenliggend boek',
'watch_detail_parent_chapter' => 'Aan het volgen via bovenliggend hoofdstuk',
'watch_detail_parent_chapter_ignore' => 'Aan het negeren via bovenliggend hoofdstuk',
];

View File

@@ -87,11 +87,11 @@ return [
'role_cannot_remove_only_admin' => 'Deze gebruiker is de enige gebruiker die is toegewezen aan de beheerdersrol. Wijs de beheerdersrol toe aan een andere gebruiker voordat u probeert deze hier te verwijderen.',
// Comments
'comment_list' => 'Er is een fout opgetreden tijdens het ophalen van de reacties.',
'cannot_add_comment_to_draft' => 'Je kunt geen reacties toevoegen aan een concept.',
'comment_add' => 'Er is een fout opgetreden tijdens het aanpassen / toevoegen van de reactie.',
'comment_delete' => 'Er is een fout opgetreden tijdens het verwijderen van de reactie.',
'empty_comment' => 'Kan geen lege reactie toevoegen.',
'comment_list' => 'Er is een fout opgetreden tijdens het ophalen van de opmerkingen.',
'cannot_add_comment_to_draft' => 'Je kunt geen opmerkingen toevoegen aan een concept.',
'comment_add' => 'Er is een fout opgetreden tijdens het aanpassen / toevoegen van de opmerking.',
'comment_delete' => 'Er is een fout opgetreden tijdens het verwijderen van de opmerking.',
'empty_comment' => 'Kan geen lege opmerking toevoegen.',
// Error pages
'404_page_not_found' => 'Pagina Niet Gevonden',

View File

@@ -5,7 +5,7 @@
return [
'new_comment_subject' => 'Nieuwe opmerking op pagina: :pageName',
'new_comment_intro' => 'Een gebruiker heeft gereageerd op een pagina in :appName:',
'new_comment_intro' => 'Een gebruiker heeft een opmerking geplaatst op een pagina in :appName:',
'new_page_subject' => 'Nieuwe pagina: :pageName',
'new_page_intro' => 'Een nieuwe pagina is gemaakt in :appName:',
'updated_page_subject' => 'Aangepaste pagina: :pageName',
@@ -14,7 +14,7 @@ return [
'detail_page_name' => 'Pagina Naam:',
'detail_page_path' => 'Paginapad:',
'detail_commenter' => 'Reageerder:',
'detail_commenter' => 'Commentator:',
'detail_comment' => 'Opmerking:',
'detail_created_by' => 'Gemaakt Door:',
'detail_updated_by' => 'Aangepast Door:',

View File

@@ -27,7 +27,7 @@ return [
'notifications_save' => 'Voorkeuren opslaan',
'notifications_update_success' => 'Voorkeuren voor meldingen zijn bijgewerkt!',
'notifications_watched' => 'Gevolgde & Genegeerde Items',
'notifications_watched_desc' => 'Hieronder staan de items waarvoor aangepaste \'Volg\'-voorkeuren zijn toegepast. Om je voorkeuren voor deze items bij te werken, bekijk je het item en zoek je naar de \'Volg\' opties in de zijbalk.',
'notifications_watched_desc' => 'Hieronder staan de items waarvoor aangepaste volgvoorkeuren zijn toegepast. Om je voorkeuren voor deze items bij te werken, bekijk je het item en zoek je naar de volgopties in de zijbalk.',
'auth' => 'Toegang & Beveiliging',
'auth_change_password' => 'Wachtwoord Wijzigen',

View File

@@ -43,9 +43,9 @@ return [
'app_footer_links_label' => 'Link label',
'app_footer_links_url' => 'Link URL',
'app_footer_links_add' => 'Voettekst link toevoegen',
'app_disable_comments' => 'Reacties uitschakelen',
'app_disable_comments_toggle' => 'Reacties uitschakelen',
'app_disable_comments_desc' => 'Schakel reacties uit op alle pagina\'s in de applicatie. <br> Bestaande reacties worden niet getoond.',
'app_disable_comments' => 'Opmerkingen uitschakelen',
'app_disable_comments_toggle' => 'Opmerkingen uitschakelen',
'app_disable_comments_desc' => 'Schakel opmerkingen uit op alle pagina\'s in de applicatie. <br> Bestaande opmerkingen worden niet getoond.',
// Color settings
'color_scheme' => 'Kleurenschema van applicatie',

View File

@@ -29,10 +29,10 @@ return [
// Toolbar
'formats' => 'Форматы',
'header_large' => 'Большой',
'header_medium' => 'Средний',
'header_small' => 'Маленький',
'header_tiny' => 'Крошечный',
'header_large' => 'Крупный заголовок',
'header_medium' => 'Средний заголовок',
'header_small' => 'Небольшой заголовок',
'header_tiny' => 'Маленький заголовок',
'paragraph' => 'Обычный текст',
'blockquote' => 'Цитата',
'inline_code' => 'Встроенный код',

View File

@@ -30,8 +30,8 @@ return [
'create' => 'Створити',
'update' => 'Оновити',
'edit' => 'Редагувати',
'archive' => 'Archive',
'unarchive' => 'Un-Archive',
'archive' => 'Архів',
'unarchive' => 'Розархівувати',
'sort' => 'Сортувати',
'move' => 'Перемістити',
'copy' => 'Копіювати',

View File

@@ -48,7 +48,7 @@ return [
'superscript' => 'Верхній індекс',
'subscript' => 'Нижній індекс',
'text_color' => 'Колір тексту',
'highlight_color' => 'Highlight color',
'highlight_color' => 'Колір підсвічування',
'custom_color' => 'Власний колір',
'remove_color' => 'Видалити колір',
'background_color' => 'Колір фону',

View File

@@ -63,10 +63,10 @@ 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',
'breadcrumb_siblings_for_page' => 'Переглянути інші сторінки',
'breadcrumb_siblings_for_chapter' => 'Переглянути інші розділи',
'breadcrumb_siblings_for_book' => 'Переглянути інші книги',
'breadcrumb_siblings_for_bookshelf' => 'Переглянути інші полиці',
// Permissions and restrictions
'permissions' => 'Дозволи',
@@ -252,7 +252,7 @@ return [
'pages_edit_switch_to_markdown_stable' => '(Стабілізувати вміст)',
'pages_edit_switch_to_wysiwyg' => 'Змінити редактор на WYSIWYG',
'pages_edit_switch_to_new_wysiwyg' => 'Перейти на новий WYSIWYG',
'pages_edit_switch_to_new_wysiwyg_desc' => '(In Beta Testing)',
'pages_edit_switch_to_new_wysiwyg_desc' => '(На бета-тестування)',
'pages_edit_set_changelog' => 'Встановити журнал змін',
'pages_edit_enter_changelog_desc' => 'Введіть короткий опис внесених вами змін',
'pages_edit_enter_changelog' => 'Введіть список змін',
@@ -272,7 +272,7 @@ return [
'pages_md_insert_drawing' => 'Вставити малюнок',
'pages_md_show_preview' => 'Показати попередній перегляд',
'pages_md_sync_scroll' => 'Синхронізація прокручування попереднього перегляду',
'pages_md_plain_editor' => 'Plaintext editor',
'pages_md_plain_editor' => 'Текстовий редактор',
'pages_drawing_unsaved' => 'Знайдено незбережену чернетку',
'pages_drawing_unsaved_confirm' => 'Незбережені чернетки були знайдені з попередньої спроби зберегти звіт. Хочете відновити і продовжити редагування цієї чернетки?',
'pages_not_in_chapter' => 'Сторінка не знаходиться в розділі',
@@ -397,11 +397,11 @@ return [
'comment' => 'Коментар',
'comments' => 'Коментарі',
'comment_add' => 'Додати коментар',
'comment_none' => 'No comments to display',
'comment_none' => 'Немає коментарів для відображення',
'comment_placeholder' => 'Залиште коментар тут',
'comment_thread_count' => ':count Comment Thread|:count Comment Threads',
'comment_archived_count' => ':count Archived',
'comment_archived_threads' => 'Archived Threads',
'comment_thread_count' => ':count тема коментарів|:count теми коментарів',
'comment_archived_count' => 'Архівовано :count',
'comment_archived_threads' => 'Архівовані теми',
'comment_save' => 'Зберегти коментар',
'comment_new' => 'Новий коментар',
'comment_created' => 'прокоментував :createDiff',
@@ -410,14 +410,14 @@ return [
'comment_deleted_success' => 'Коментар видалено',
'comment_created_success' => 'Коментар додано',
'comment_updated_success' => 'Коментар оновлено',
'comment_archive_success' => 'Comment archived',
'comment_unarchive_success' => 'Comment un-archived',
'comment_view' => 'View comment',
'comment_jump_to_thread' => 'Jump to thread',
'comment_archive_success' => 'Коментар архівовано',
'comment_unarchive_success' => 'Коментар розархівовано',
'comment_view' => 'Переглянути коментар',
'comment_jump_to_thread' => 'Перейти до теми',
'comment_delete_confirm' => 'Ви впевнені, що хочете видалити цей коментар?',
'comment_in_reply_to' => 'У відповідь на :commentId',
'comment_reference' => 'Reference',
'comment_reference_outdated' => '(Outdated)',
'comment_reference' => 'По посиланню',
'comment_reference_outdated' => '(Застарілий)',
'comment_editor_explain' => 'Ось коментарі, які залишилися на цій сторінці. Коментарі можна додати та керовані при перегляді збереженої сторінки.',
// Revision

View File

@@ -48,7 +48,7 @@ return [
'superscript' => 'Chỉ số trên',
'subscript' => 'Chỉ số dưới',
'text_color' => 'Màu chữ',
'highlight_color' => 'Highlight color',
'highlight_color' => 'Màu đánh dấu',
'custom_color' => 'Màu tùy chỉnh',
'remove_color' => 'Xóa màu',
'background_color' => 'Màu nền',

View File

@@ -60,13 +60,13 @@ return [
'import_location' => 'Vị trí nhập',
'import_location_desc' => 'Chọn vị trí đích cho nội dung đã nhập của bạn. Bạn sẽ cần các quyền liên quan để tạo trong vị trí bạn chọn.',
'import_delete_confirm' => 'Bạn có chắc chắn muốn xóa lượt nhập này không?',
'import_delete_desc' => 'Thao tác này sẽ xóa tệp ZIP nhập đã tải lên và không thể hoàn tác.',
'import_errors' => 'Lỗi nhập',
'import_delete_desc' => 'Thao tác này sẽ xóa tệp ZIP đã tải lên, và không thể hoàn tác.',
'import_errors' => 'Lỗi khi nhập dữ liệu',
'import_errors_desc' => 'Các lỗi sau đã xảy ra trong quá trình nhập:',
'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',
'breadcrumb_siblings_for_page' => 'Điều hướng anh chị em cho trang',
'breadcrumb_siblings_for_chapter' => 'Điều hướng anh chị em cho chương',
'breadcrumb_siblings_for_book' => 'Điều hướng anh chị em cho sách',
'breadcrumb_siblings_for_bookshelf' => 'Điều hướng anh chị em cho kệ sách',
// Permissions and restrictions
'permissions' => 'Quyền',

View File

@@ -1,5 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd" bootstrap="vendor/autoload.php" colors="true">
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.5/phpunit.xsd"
bootstrap="vendor/autoload.php"
displayDetailsOnTestsThatTriggerDeprecations="true"
colors="true">
<testsuites>
<testsuite name="Application Test Suite">
<directory>./tests/</directory>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -48,7 +48,7 @@ Big thanks to these companies for supporting the project.
#### Gold Sponsor
<table><tbody><tr>
<td align="center"><a href="https://www.federated.computer/bookstack-wiki" target="_blank">
<td align="center"><a href="https://www.federated.computer/bookstack" target="_blank">
<img width="480" src="https://www.bookstackapp.com/images/sponsors/federated-computer.png" alt="Federated.computer">
</a></td>
</tr></tbody></table>

View File

@@ -1,4 +1,4 @@
import {createEditor, LexicalEditor} from 'lexical';
import {createEditor} from 'lexical';
import {createEmptyHistoryState, registerHistory} from '@lexical/history';
import {registerRichText} from '@lexical/rich-text';
import {mergeRegister} from '@lexical/utils';
@@ -20,6 +20,7 @@ import {modals} from "./ui/defaults/modals";
import {CodeBlockDecorator} from "./ui/decorators/code-block";
import {DiagramDecorator} from "./ui/decorators/diagram";
import {registerMouseHandling} from "./services/mouse-handling";
import {registerSelectionHandling} from "./services/selection-handling";
const theme = {
text: {
@@ -53,6 +54,7 @@ export function createPageEditorInstance(container: HTMLElement, htmlContent: st
registerShortcuts(context),
registerKeyboardHandling(context),
registerMouseHandling(context),
registerSelectionHandling(context),
registerTableResizer(editor, context.scrollDOM),
registerTableSelectionHandler(editor),
registerTaskListHandler(editor, context.editorDOM),

View File

@@ -383,6 +383,14 @@ export class LexicalNode {
return isSelected;
}
/**
* Indicate if this node should be selected directly instead of the default
* where the selection would descend to the nearest initial child element.
*/
shouldSelectDirectly(): boolean {
return false;
}
/**
* Returns this nodes key.
*/

View File

@@ -476,12 +476,12 @@ export class RangeSelection implements BaseSelection {
const startOffset = firstPoint.offset;
const endOffset = lastPoint.offset;
if ($isElementNode(firstNode)) {
if ($isElementNode(firstNode) && !firstNode.shouldSelectDirectly()) {
const firstNodeDescendant =
firstNode.getDescendantByIndex<ElementNode>(startOffset);
firstNode = firstNodeDescendant != null ? firstNodeDescendant : firstNode;
}
if ($isElementNode(lastNode)) {
if ($isElementNode(lastNode) && !lastNode.shouldSelectDirectly()) {
let lastNodeDescendant =
lastNode.getDescendantByIndex<ElementNode>(endOffset);
// We don't want to over-select, as node selection infers the child before
@@ -499,7 +499,7 @@ export class RangeSelection implements BaseSelection {
let nodes: Array<LexicalNode>;
if (firstNode.is(lastNode)) {
if ($isElementNode(firstNode) && firstNode.getChildrenSize() > 0) {
if ($isElementNode(firstNode) && firstNode.getChildrenSize() > 0 && !firstNode.shouldSelectDirectly()) {
nodes = [];
} else {
nodes = [firstNode];

View File

@@ -150,6 +150,20 @@ export class ElementNode extends LexicalNode {
}
return node;
}
getFirstSelectableDescendant<T extends LexicalNode>(): null | T {
if (this.shouldSelectDirectly()) {
return null;
}
let node = this.getFirstChild<T>();
while ($isElementNode(node) && !node.shouldSelectDirectly()) {
const child = node.getFirstChild<T>();
if (child === null) {
break;
}
node = child;
}
return node;
}
getLastDescendant<T extends LexicalNode>(): null | T {
let node = this.getLastChild<T>();
while ($isElementNode(node)) {
@@ -161,6 +175,20 @@ export class ElementNode extends LexicalNode {
}
return node;
}
getLastSelectableDescendant<T extends LexicalNode>(): null | T {
if (this.shouldSelectDirectly()) {
return null;
}
let node = this.getLastChild<T>();
while ($isElementNode(node) && !node.shouldSelectDirectly()) {
const child = node.getLastChild<T>();
if (child === null) {
break;
}
node = child;
}
return node;
}
getDescendantByIndex<T extends LexicalNode>(index: number): null | T {
const children = this.getChildren<T>();
const childrenLength = children.length;
@@ -279,7 +307,7 @@ export class ElementNode extends LexicalNode {
let anchorOffset = _anchorOffset;
let focusOffset = _focusOffset;
const childrenCount = this.getChildrenSize();
if (!this.canBeEmpty()) {
if (!this.canBeEmpty() && !this.shouldSelectDirectly()) {
if (_anchorOffset === 0 && _focusOffset === 0) {
const firstChild = this.getFirstChild();
if ($isTextNode(firstChild) || $isElementNode(firstChild)) {
@@ -319,11 +347,11 @@ export class ElementNode extends LexicalNode {
return selection;
}
selectStart(): RangeSelection {
const firstNode = this.getFirstDescendant();
const firstNode = this.getFirstSelectableDescendant();
return firstNode ? firstNode.selectStart() : this.select();
}
selectEnd(): RangeSelection {
const lastNode = this.getLastDescendant();
const lastNode = this.getLastSelectableDescendant();
return lastNode ? lastNode.selectEnd() : this.select();
}
clear(): this {

View File

@@ -75,6 +75,9 @@ export class DetailsNode extends ElementNode {
if (this.__open) {
el.setAttribute('open', 'true');
el.removeAttribute('contenteditable');
} else {
el.setAttribute('contenteditable', 'false');
}
const summary = document.createElement('summary');
@@ -84,7 +87,7 @@ export class DetailsNode extends ElementNode {
event.preventDefault();
_editor.update(() => {
this.select();
})
});
});
el.append(summary);
@@ -96,6 +99,11 @@ export class DetailsNode extends ElementNode {
if (prevNode.__open !== this.__open) {
dom.toggleAttribute('open', this.__open);
if (this.__open) {
dom.removeAttribute('contenteditable');
} else {
dom.setAttribute('contenteditable', 'false');
}
}
return prevNode.__id !== this.__id
@@ -144,6 +152,7 @@ export class DetailsNode extends ElementNode {
}
element.removeAttribute('open');
element.removeAttribute('contenteditable');
return {element};
}
@@ -165,6 +174,14 @@ export class DetailsNode extends ElementNode {
return node;
}
shouldSelectDirectly(): boolean {
return true;
}
canBeEmpty(): boolean {
return false;
}
}
export function $createDetailsNode() {

View File

@@ -1,6 +1,5 @@
import {dispatchKeydownEventForNode, initializeUnitTest} from "lexical/__tests__/utils";
import {$createDetailsNode, DetailsNode} from "@lexical/rich-text/LexicalDetailsNode";
import {$createParagraphNode, $getRoot, LexicalNode, ParagraphNode} from "lexical";
import {createTestContext} from "lexical/__tests__/utils";
import {$createDetailsNode} from "@lexical/rich-text/LexicalDetailsNode";
const editorConfig = Object.freeze({
namespace: '',
@@ -9,32 +8,28 @@ const editorConfig = Object.freeze({
});
describe('LexicalDetailsNode tests', () => {
initializeUnitTest((testEnv) => {
test('createDOM()', () => {
const {editor} = createTestContext();
let html!: string;
test('createDOM()', () => {
const {editor} = testEnv;
let html!: string;
editor.updateAndCommit(() => {
const details = $createDetailsNode();
html = details.createDOM(editorConfig, editor).outerHTML;
});
expect(html).toBe(`<details><summary contenteditable="false"></summary></details>`);
editor.updateAndCommit(() => {
const details = $createDetailsNode();
html = details.createDOM(editorConfig, editor).outerHTML;
});
test('exportDOM()', () => {
const {editor} = testEnv;
let html!: string;
expect(html).toBe(`<details contenteditable="false"><summary contenteditable="false"></summary></details>`);
});
editor.updateAndCommit(() => {
const details = $createDetailsNode();
html = (details.exportDOM(editor).element as HTMLElement).outerHTML;
});
test('exportDOM()', () => {
const {editor} = createTestContext();
let html!: string;
expect(html).toBe(`<details><summary></summary></details>`);
editor.updateAndCommit(() => {
const details = $createDetailsNode();
details.setSummary('Hello there<>!')
html = (details.exportDOM(editor).element as HTMLElement).outerHTML;
});
expect(html).toBe(`<details><summary>Hello there&lt;&gt;!</summary></details>`);
});
})

View File

@@ -18,6 +18,7 @@ import {$setInsetForSelection} from "../utils/lists";
import {$isListItemNode} from "@lexical/list";
import {$isDetailsNode, DetailsNode} from "@lexical/rich-text/LexicalDetailsNode";
import {$isDiagramNode} from "../utils/diagrams";
import {$unwrapDetailsNode} from "../utils/details";
function isSingleSelectedNode(nodes: LexicalNode[]): boolean {
if (nodes.length === 1) {
@@ -172,6 +173,35 @@ function getDetailsScenario(editor: LexicalEditor): {
}
}
function unwrapDetailsNode(context: EditorUiContext, event: KeyboardEvent): boolean {
const selection = $getSelection();
const nodes = selection?.getNodes() || [];
if (nodes.length !== 1) {
return false;
}
const selectedNearestBlock = $getNearestNodeBlockParent(nodes[0]);
if (!selectedNearestBlock) {
return false;
}
const selectedParentBlock = selectedNearestBlock.getParent();
const selectRange = selection?.getStartEndPoints();
if (selectRange && $isDetailsNode(selectedParentBlock) && selectRange[0].offset === 0 && selectedNearestBlock.getIndexWithinParent() === 0) {
event.preventDefault();
context.editor.update(() => {
$unwrapDetailsNode(selectedParentBlock);
selectedNearestBlock.selectStart();
context.manager.triggerLayoutUpdate();
});
return true;
}
return false;
}
function $isSingleListItem(nodes: LexicalNode[]): boolean {
if (nodes.length !== 1) {
return false;
@@ -201,9 +231,9 @@ function handleInsetOnTab(editor: LexicalEditor, event: KeyboardEvent|null): boo
}
export function registerKeyboardHandling(context: EditorUiContext): () => void {
const unregisterBackspace = context.editor.registerCommand(KEY_BACKSPACE_COMMAND, (): boolean => {
const unregisterBackspace = context.editor.registerCommand(KEY_BACKSPACE_COMMAND, (event): boolean => {
deleteSingleSelectedNode(context.editor);
return false;
return unwrapDetailsNode(context, event);
}, COMMAND_PRIORITY_LOW);
const unregisterDelete = context.editor.registerCommand(KEY_DELETE_COMMAND, (): boolean => {

View File

@@ -1,31 +1,41 @@
import {EditorUiContext} from "../ui/framework/core";
import {
$createParagraphNode, $getRoot,
$getSelection,
$createParagraphNode, $getNearestNodeFromDOMNode, $getRoot,
$isDecoratorNode, CLICK_COMMAND,
COMMAND_PRIORITY_LOW, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_UP_COMMAND,
KEY_BACKSPACE_COMMAND,
KEY_DELETE_COMMAND,
KEY_ENTER_COMMAND, KEY_TAB_COMMAND,
LexicalEditor,
COMMAND_PRIORITY_LOW, ElementNode,
LexicalNode
} from "lexical";
import {$isImageNode} from "@lexical/rich-text/LexicalImageNode";
import {$isMediaNode} from "@lexical/rich-text/LexicalMediaNode";
import {getLastSelection} from "../utils/selection";
import {$getNearestNodeBlockParent, $getParentOfType, $selectOrCreateAdjacent} from "../utils/nodes";
import {$setInsetForSelection} from "../utils/lists";
import {$isListItemNode} from "@lexical/list";
import {$isDetailsNode, DetailsNode} from "@lexical/rich-text/LexicalDetailsNode";
import {$isDiagramNode} from "../utils/diagrams";
import {$isTableNode} from "@lexical/table";
import {$isDetailsNode} from "@lexical/rich-text/LexicalDetailsNode";
function isHardToEscapeNode(node: LexicalNode): boolean {
return $isDecoratorNode(node) || $isImageNode(node) || $isMediaNode(node) || $isDiagramNode(node) || $isTableNode(node);
return $isDecoratorNode(node)
|| $isImageNode(node)
|| $isMediaNode(node)
|| $isDiagramNode(node)
|| $isTableNode(node)
|| $isDetailsNode(node);
}
function $getContextNode(event: MouseEvent): ElementNode {
if (event.target instanceof HTMLElement) {
const nearestDetails = event.target.closest('details');
if (nearestDetails) {
const detailsNode = $getNearestNodeFromDOMNode(nearestDetails);
if ($isDetailsNode(detailsNode)) {
return detailsNode;
}
}
}
return $getRoot();
}
function insertBelowLastNode(context: EditorUiContext, event: MouseEvent): boolean {
const lastNode = $getRoot().getLastChild();
const contextNode = $getContextNode(event);
const lastNode = contextNode.getLastChild();
if (!lastNode || !isHardToEscapeNode(lastNode)) {
return false;
}
@@ -40,7 +50,7 @@ function insertBelowLastNode(context: EditorUiContext, event: MouseEvent): boole
if (isClickBelow) {
context.editor.update(() => {
const newNode = $createParagraphNode();
$getRoot().append(newNode);
contextNode.append(newNode);
newNode.select();
});
return true;
@@ -49,7 +59,6 @@ function insertBelowLastNode(context: EditorUiContext, event: MouseEvent): boole
return false;
}
export function registerMouseHandling(context: EditorUiContext): () => void {
const unregisterClick = context.editor.registerCommand(CLICK_COMMAND, (event): boolean => {
insertBelowLastNode(context, event);

View File

@@ -0,0 +1,49 @@
import {EditorUiContext} from "../ui/framework/core";
import {
$getSelection,
COMMAND_PRIORITY_LOW,
SELECTION_CHANGE_COMMAND
} from "lexical";
import {$isDetailsNode} from "@lexical/rich-text/LexicalDetailsNode";
const trackedDomNodes = new Set<HTMLElement>();
/**
* Set a selection indicator on nodes which require it.
* @param context
*/
function setSelectionIndicator(context: EditorUiContext): boolean {
for (const domNode of trackedDomNodes) {
domNode.classList.remove('selected');
trackedDomNodes.delete(domNode);
}
const selection = $getSelection();
const nodes = selection?.getNodes() || [];
if (nodes.length === 1) {
if ($isDetailsNode(nodes[0])) {
const domEl = context.editor.getElementByKey(nodes[0].getKey());
if (domEl) {
domEl.classList.add('selected');
trackedDomNodes.add(domEl);
}
}
}
return false;
}
export function registerSelectionHandling(context: EditorUiContext): () => void {
const unregisterSelectionChange = context.editor.registerCommand(SELECTION_CHANGE_COMMAND, (): boolean => {
setSelectionIndicator(context);
return false;
}, COMMAND_PRIORITY_LOW);
return () => {
unregisterSelectionChange();
};
}

View File

@@ -34,6 +34,7 @@ import {$isDiagramNode, $openDrawingEditorForNode, showDiagramManagerForInsert}
import {$createLinkedImageNodeFromImageData, showImageManager} from "../../../utils/images";
import {$showDetailsForm, $showImageForm, $showLinkForm, $showMediaForm} from "../forms/objects";
import {formatCodeBlock} from "../../../utils/formats";
import {$unwrapDetailsNode} from "../../../utils/details";
export const link: EditorButtonDefinition = {
label: 'Insert/edit link',
@@ -193,6 +194,8 @@ export const details: EditorButtonDefinition = {
.filter(n => n !== null) as ElementNode[];
const uniqueTopLevels = [...new Set(topLevels)];
detailsNode.setOpen(true);
if (uniqueTopLevels.length > 0) {
uniqueTopLevels[0].insertAfter(detailsNode);
} else {
@@ -249,11 +252,7 @@ export const detailsUnwrap: EditorButtonDefinition = {
context.editor.update(() => {
const details = $getNodeFromSelection($getSelection(), $isDetailsNode);
if ($isDetailsNode(details)) {
const children = details.getChildren();
for (const child of children) {
details.insertBefore(child);
}
details.remove();
$unwrapDetailsNode(details);
context.manager.triggerLayoutUpdate();
}
})

View File

@@ -0,0 +1,9 @@
import {DetailsNode} from "@lexical/rich-text/LexicalDetailsNode";
export function $unwrapDetailsNode(node: DetailsNode) {
const children = node.getChildren();
for (const child of children) {
node.insertBefore(child);
}
node.remove();
}

View File

@@ -437,6 +437,20 @@ body.editor-is-fullscreen {
.editor-node-resizer.active .editor-node-resizer-ghost {
display: block;
}
.editor-content-area details[contenteditable="false"],
.editor-content-area summary[contenteditable="false"] {
user-select: none;
}
.editor-content-area details[contenteditable="false"] > details * {
pointer-events: none;
}
.editor-content-area details summary {
caret-color: transparent;
}
.editor-content-area details.selected {
outline: 1px dashed var(--editor-color-primary);
outline-offset: 1px;
}
.editor-table-marker {
position: fixed;

View File

@@ -259,6 +259,35 @@ class BookShelfTest extends TestCase
$this->assertDatabaseHas('bookshelves_books', ['bookshelf_id' => $shelf->id, 'book_id' => $booksToInclude[1]->id]);
}
public function test_shelf_edit_does_not_alter_books_we_dont_have_access_to()
{
$shelf = $this->entities->shelf();
$shelf->books()->detach();
$this->entities->book();
$this->entities->book();
$newBooks = [$this->entities->book(), $this->entities->book()];
$originalBooks = [$this->entities->book(), $this->entities->book()];
foreach ($originalBooks as $book) {
$this->permissions->disableEntityInheritedPermissions($book);
$shelf->books()->attach($book->id);
}
$this->asEditor()->put($shelf->getUrl(), [
'name' => $shelf->name,
'books' => "{$newBooks[0]->id},{$newBooks[1]->id}",
])->assertRedirect($shelf->getUrl());
$resultingBooksById = $shelf->books()->get()->keyBy('id')->toArray();
$this->assertCount(4, $resultingBooksById);
foreach ($newBooks as $book) {
$this->assertArrayHasKey($book->id, $resultingBooksById);
}
foreach ($originalBooks as $book) {
$this->assertArrayHasKey($book->id, $resultingBooksById);
}
}
public function test_shelf_create_new_book()
{
$shelf = $this->entities->shelf();

View File

@@ -393,4 +393,42 @@ class ZipImportRunnerTest extends TestCase
ZipTestHelper::deleteZipForImport($import);
}
public function test_drawing_references_are_updated_within_content()
{
$testImagePath = $this->files->testFilePath('test-image.png');
$parent = $this->entities->chapter();
$import = ZipTestHelper::importFromData([], [
'page' => [
'name' => 'Page A',
'html' => '<div drawio-diagram="1125"><img src="[[bsexport:image:1125]]"></div>',
'images' => [
[
'id' => 1125,
'name' => 'Cat',
'type' => 'drawio',
'file' => 'my_drawing'
]
],
],
], [
'my_drawing' => $testImagePath,
]);
$this->asAdmin();
/** @var Page $page */
$page = $this->runner->run($import, $parent);
$pageImages = Image::where('uploaded_to', '=', $page->id)->whereIn('type', ['gallery', 'drawio'])->get();
$this->assertCount(1, $pageImages);
$this->assertEquals('drawio', $pageImages[0]->type);
$drawingId = $pageImages[0]->id;
$this->assertStringContainsString("drawio-diagram=\"{$drawingId}\"", $page->html);
$this->assertStringNotContainsString('[[bsexport:image:1125]]', $page->html);
$this->assertStringNotContainsString('drawio-diagram="1125"', $page->html);
ZipTestHelper::deleteZipForImport($import);
}
}

View File

@@ -76,7 +76,7 @@ class ZipImportTest extends TestCase
{
$zipFile = tempnam(sys_get_temp_dir(), 'bstest-');
$zip = new ZipArchive();
$zip->open($zipFile, ZipArchive::CREATE);
$zip->open($zipFile, ZipArchive::OVERWRITE);
$zip->addFromString('beans', 'cat');
$zip->close();

View File

@@ -46,7 +46,7 @@ class ZipTestHelper
$zipFile = tempnam(sys_get_temp_dir(), 'bstest-');
$zip = new ZipArchive();
$zip->open($zipFile, ZipArchive::CREATE);
$zip->open($zipFile, ZipArchive::OVERWRITE);
$zip->addFromString('data.json', json_encode($data));
foreach ($files as $name => $file) {

View File

@@ -6,7 +6,6 @@ use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Bookshelf;
use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Entity;
use BookStack\Entities\Models\HasCoverImage;
use BookStack\Entities\Models\Page;
use BookStack\Entities\Repos\BookRepo;
use BookStack\Entities\Repos\BookshelfRepo;
@@ -34,9 +33,9 @@ class EntityProvider
];
/**
* Get an un-fetched page from the system.
* Get an unfetched page from the system.
*/
public function page(callable $queryFilter = null): Page
public function page(callable|null $queryFilter = null): Page
{
/** @var Page $page */
$page = Page::query()->when($queryFilter, $queryFilter)->whereNotIn('id', $this->fetchCache['page'])->first();
@@ -64,9 +63,9 @@ class EntityProvider
}
/**
* Get an un-fetched chapter from the system.
* Get an unfetched chapter from the system.
*/
public function chapter(callable $queryFilter = null): Chapter
public function chapter(callable|null $queryFilter = null): Chapter
{
/** @var Chapter $chapter */
$chapter = Chapter::query()->when($queryFilter, $queryFilter)->whereNotIn('id', $this->fetchCache['chapter'])->first();
@@ -80,9 +79,9 @@ class EntityProvider
}
/**
* Get an un-fetched book from the system.
* Get an unfetched book from the system.
*/
public function book(callable $queryFilter = null): Book
public function book(callable|null $queryFilter = null): Book
{
/** @var Book $book */
$book = Book::query()->when($queryFilter, $queryFilter)->whereNotIn('id', $this->fetchCache['book'])->first();
@@ -101,9 +100,9 @@ class EntityProvider
}
/**
* Get an un-fetched shelf from the system.
* Get an unfetched shelf from the system.
*/
public function shelf(callable $queryFilter = null): Bookshelf
public function shelf(callable|null $queryFilter = null): Bookshelf
{
/** @var Bookshelf $shelf */
$shelf = Bookshelf::query()->when($queryFilter, $queryFilter)->whereNotIn('id', $this->fetchCache['bookshelf'])->first();

View File

@@ -1 +1 @@
v25.07.1
v25.07.2