Compare commits

..

80 Commits

Author SHA1 Message Date
Dan Brown
68d437d05b Updated version and assets for release v21.08.6 2021-10-15 14:34:44 +01:00
Dan Brown
1e56aaea04 Merge branch 'master' into release 2021-10-15 14:34:23 +01:00
Dan Brown
5ba964b677 Updated readme with latest version info
Also updated version file to be current
2021-10-15 14:30:49 +01:00
Dan Brown
5647a8a091 New Crowdin updates (#2980)
* New translations entities.php (Spanish, Argentina)

* New translations activities.php (Spanish, Argentina)

* New translations auth.php (Spanish, Argentina)

* New translations settings.php (Spanish, Argentina)

* New translations validation.php (Spanish, Argentina)

* New translations auth.php (Spanish, Argentina)
2021-10-15 14:17:32 +01:00
Dan Brown
f3c147d33b Applied latest styleci changes 2021-10-15 14:16:45 +01:00
Dan Brown
747f81d5d8 Updated php dependancies 2021-10-15 13:15:32 +01:00
Dan Brown
c9c0e5e16f Fixed guest user email showing in TOTP setup url
- Occured during enforced MFA setup upon login.
- Added test to cover.

Fixes #2971
2021-10-14 18:02:16 +01:00
Dan Brown
d21b60079c Merge pull request #2977 from BookStackApp/custom_debug_view
Added custom whoops-based debug view
2021-10-14 17:41:06 +01:00
Dan Brown
ffa4377e65 Added testing to cover debug view 2021-10-14 17:40:22 +01:00
Dan Brown
9b8bb49a33 Added custom whoops-based debug view
Provides a simple bookstack focused view that does not rely on JavaScript.
Contains links to BookStack specific resources in addition to commonly
desired debug details.
2021-10-14 15:33:08 +01:00
Dan Brown
69301f7575 Merge pull request #2965 from Haxatron/master
Update DOMPDF chroot directory
2021-10-11 10:25:28 +01:00
Haxatron
b043257d9a Update dompdf.php
base_path => public_path
2021-10-10 01:06:08 +08:00
Dan Brown
ca764caf2d Added throttling to password reset requests 2021-10-08 23:19:37 +01:00
Dan Brown
dab170a6fe Updated version and assets for release v21.08.5 2021-10-08 22:25:36 +01:00
Dan Brown
a8de717d9b Merge branch 'master' into release 2021-10-08 22:25:05 +01:00
Dan Brown
543ea6ef71 Updated translator attribution before release v21.08.5 2021-10-08 22:24:32 +01:00
Dan Brown
a9b3df537f Applied changes from styleci 2021-10-08 22:23:17 +01:00
Dan Brown
c2339ac9db New Crowdin updates (#2953)
* New translations settings.php (Chinese Simplified)

* New translations entities.php (Slovak)

* New translations entities.php (Portuguese, Brazilian)

* New translations entities.php (Slovenian)

* New translations entities.php (Swedish)

* New translations entities.php (Turkish)

* New translations entities.php (Ukrainian)

* New translations entities.php (Chinese Simplified)

* New translations entities.php (Chinese Traditional)

* New translations entities.php (Indonesian)

* New translations entities.php (Portuguese)

* New translations entities.php (Persian)

* New translations entities.php (Spanish, Argentina)

* New translations entities.php (Croatian)

* New translations entities.php (Latvian)

* New translations entities.php (Bosnian)

* New translations entities.php (Norwegian Bokmal)

* New translations entities.php (Russian)

* New translations entities.php (Polish)

* New translations entities.php (Vietnamese)

* New translations entities.php (Danish)

* New translations entities.php (French)

* New translations entities.php (Spanish)

* New translations entities.php (Arabic)

* New translations entities.php (Bulgarian)

* New translations entities.php (Catalan)

* New translations entities.php (Czech)

* New translations entities.php (German)

* New translations entities.php (Dutch)

* New translations entities.php (Hebrew)

* New translations entities.php (Hungarian)

* New translations entities.php (Italian)

* New translations entities.php (Japanese)

* New translations entities.php (Korean)

* New translations entities.php (Lithuanian)

* New translations entities.php (German Informal)

* New translations entities.php (French)

* New translations entities.php (Spanish)

* New translations settings.php (Czech)

* New translations entities.php (Czech)

* New translations activities.php (Czech)

* New translations auth.php (Czech)

* New translations common.php (Czech)

* New translations validation.php (Czech)

* New translations entities.php (Portuguese)

* New translations settings.php (Portuguese)

* New translations entities.php (Portuguese)

* New translations activities.php (Portuguese)

* New translations auth.php (Portuguese)

* New translations common.php (Portuguese)

* New translations validation.php (Portuguese)

* New translations entities.php (Chinese Simplified)

* New translations entities.php (Chinese Simplified)

* New translations activities.php (Ukrainian)

* New translations activities.php (Ukrainian)
2021-10-08 22:22:01 +01:00
Dan Brown
41541df6ec Added testing to cover work done in last commit
Relevant to comments in 7224fbcc89.
Added test cases. Ensured they failed pre-commit.
Also tested a range of the altered endpoints manually on both local and
s3-like filesystems.
2021-10-08 21:47:59 +01:00
Dan Brown
7224fbcc89 Added protections against path traversal in file system operations
- Files within the storage/ path could be accessed via path traversal
  references in content, accessed upon HTML export.
- This addresses this via two layers:
  - Scoped local flysystem filesystems down to the specific image &
    file folders since flysystem has built-in checking against the
    escaping of the root folder.
  - Added path normalization before enforcement of uploads/{images,file}
    prefix to prevent traversal at a path level.

Thanks to @Haxatron via huntr.dev for discovery and reporting.
Ref: https://huntr.dev/bounties/ac268a17-72b5-446f-a09a-9945ef58607a/
2021-10-08 17:47:14 +01:00
Dan Brown
81d6b1b016 Fixed search query issues when table prefixes are used
- Old raw select query was causing bad select clause in query
  when table prefixes were active.
2021-10-08 15:25:12 +01:00
Dan Brown
41ac69adb1 Forced response cache revalidation on logged-in responses
- Prevents authenticated responses being visible when back button
  pressed in browser.
- Previously, 'no-cache, private' was added by default by Symfony which
  would have prevents proxy cache issues but this adds no-store and a
  max-age option to also invalidate all caching.

Thanks to @haxatron via huntr.dev
Ref: https://huntr.dev/bounties/6cda9df9-4987-4e1c-b48f-855b6901ef53/
2021-10-08 15:22:09 +01:00
Dan Brown
55be75dee2 Merge pull request #2957 from BookStackApp/dependabot/composer/composer/composer-2.1.9
Bump composer/composer from 2.1.8 to 2.1.9
2021-10-06 10:52:02 +01:00
dependabot[bot]
644bbebb6e Bump composer/composer from 2.1.8 to 2.1.9
Bumps [composer/composer](https://github.com/composer/composer) from 2.1.8 to 2.1.9.
- [Release notes](https://github.com/composer/composer/releases)
- [Changelog](https://github.com/composer/composer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/composer/composer/compare/2.1.8...2.1.9)

---
updated-dependencies:
- dependency-name: composer/composer
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-05 20:57:31 +00:00
Dan Brown
f99af807d0 Reviewed and refactored additional editor draft save warnings
- Added testing to cover warning cases.
- Refactored logic to be simpler and move much of the business out of
  the controller.
- Added new message that's more suitable to the case this was handling.
- For detecting an outdated draft, checked the draft created_at time
  instead of updated_at to better fit the scenario being checked.
- Updated some method types to align with those potentially being used
  in the logic of the code.
- Added a cache of shown messages on the front-end to prevent them
  re-showing on every save during the session, even if dismissed.
2021-10-04 20:26:55 +01:00
Dan Brown
756b55bbff Merge branch 'conflict_warnings' of https://github.com/MatthieuParis/BookStack into MatthieuParis-conflict_warnings 2021-10-04 17:10:40 +01:00
Dan Brown
78fe95b6fc Updated version and assets for release v21.08.4 2021-10-04 16:25:24 +01:00
Dan Brown
e0c24e41aa Merge branch 'master' into release 2021-10-04 16:24:54 +01:00
Dan Brown
e37bbf2925 Updated translator attribution before release v21.08.4 2021-10-04 16:24:17 +01:00
Dan Brown
ec61e45a2b New Crowdin updates (#2926)
* New translations settings.php (French)

* New translations auth.php (French)

* New translations settings.php (French)

* New translations entities.php (French)

* New translations activities.php (French)

* New translations common.php (French)

* New translations entities.php (French)

* New translations common.php (French)

* New translations components.php (French)

* New translations settings.php (French)

* New translations auth.php (French)

* New translations settings.php (Russian)

* New translations validation.php (Russian)

* New translations settings.php (Russian)

* New translations auth.php (Russian)

* New translations settings.php (Russian)

* New translations auth.php (Russian)

* New translations entities.php (French)

* New translations auth.php (French)

* New translations entities.php (French)

* New translations auth.php (French)

* New translations settings.php (French)

* New translations validation.php (French)

* New translations settings.php (French)

* New translations entities.php (French)

* New translations errors.php (French)

* New translations passwords.php (French)

* New translations settings.php (French)

* New translations entities.php (French)

* New translations settings.php (French)

* New translations entities.php (German)

* New translations settings.php (German)

* New translations entities.php (German Informal)

* New translations settings.php (German Informal)

* New translations settings.php (German)

* New translations settings.php (German Informal)

* New translations settings.php (French)

* New translations settings.php (Vietnamese)

* New translations settings.php (Slovenian)

* New translations settings.php (Swedish)

* New translations settings.php (Turkish)

* New translations settings.php (Ukrainian)

* New translations settings.php (Chinese Simplified)

* New translations settings.php (Chinese Traditional)

* New translations settings.php (Portuguese, Brazilian)

* New translations settings.php (Portuguese)

* New translations settings.php (Indonesian)

* New translations settings.php (Persian)

* New translations settings.php (Spanish, Argentina)

* New translations settings.php (Croatian)

* New translations settings.php (Latvian)

* New translations settings.php (Bosnian)

* New translations settings.php (Slovak)

* New translations settings.php (Polish)

* New translations settings.php (Russian)

* New translations settings.php (Czech)

* New translations settings.php (German)

* New translations settings.php (German Informal)

* New translations settings.php (Spanish)

* New translations settings.php (Arabic)

* New translations settings.php (Bulgarian)

* New translations settings.php (Catalan)

* New translations settings.php (Danish)

* New translations settings.php (Dutch)

* New translations settings.php (Hebrew)

* New translations settings.php (Hungarian)

* New translations settings.php (Italian)

* New translations settings.php (Japanese)

* New translations settings.php (Korean)

* New translations settings.php (Lithuanian)

* New translations settings.php (Norwegian Bokmal)

* New translations settings.php (Spanish)

* New translations activities.php (Slovak)

* New translations errors.php (Slovak)

* New translations settings.php (Slovak)

* New translations auth.php (Slovak)

* New translations common.php (Slovak)

* New translations entities.php (Slovak)

* New translations settings.php (Slovak)

* New translations activities.php (Slovak)

* New translations settings.php (French)

* New translations settings.php (Russian)

* New translations settings.php (German)

* New translations settings.php (Polish)

* New translations validation.php (Polish)

* New translations auth.php (Vietnamese)

* New translations auth.php (Vietnamese)

* New translations activities.php (Vietnamese)

* New translations common.php (Vietnamese)

* New translations entities.php (Vietnamese)

* New translations settings.php (Chinese Simplified)

* New translations settings.php (Italian)

* New translations auth.php (Italian)

* New translations common.php (Italian)

* New translations common.php (German)

* New translations common.php (German Informal)

* New translations settings.php (German)

* New translations common.php (German)

* New translations common.php (German Informal)

* New translations errors.php (German)
2021-10-04 16:22:16 +01:00
Dan Brown
d3a9645161 Allowed page includes on custom home
For #2279
Old hold-over for when include content permissions were handled less
delicately.
2021-10-04 11:26:26 +01:00
Dan Brown
505d7e604e Applied StyleCI changes 2021-09-29 23:53:11 +01:00
Dan Brown
025442fcd9 Reviewed addition to db table prefix
Review of #2935

- Removed from .env files and added warnings for use if found in config
  file.
- Updated permission service to use whereColumn queries to auto-handle
  use of prefixes.
2021-09-29 18:41:11 +01:00
Dan Brown
0f66c8a0cc Merge branch 'floviolleau-db-prefixes' of https://github.com/floviolleau/BookStack into floviolleau-floviolleau-db-prefixes 2021-09-29 18:13:38 +01:00
Dan Brown
887a79f130 Reviewed adding IP recording to activity & audit log
Review of #2936

- Added testing to cover
- Added APP_PROXIES to .env.example.complete with details.
- Renamed migration to better align the name and to set the migration
  date to fit with production deploy order.
- Removed index from IP column in migration since an index does not yet
  provide any value.
- Updated table header text label.
- Prevented IP recording when in demo mode.
2021-09-26 17:18:12 +01:00
Dan Brown
8972f7b212 Merge branch 'log-ip-address' of https://github.com/johnroyer/BookStack into johnroyer-log-ip-address 2021-09-26 16:17:28 +01:00
Dan Brown
c100560bd9 Applied style ci changes again 2021-09-26 15:49:25 +01:00
Dan Brown
05d99a312d Applied styleci changes 2021-09-26 15:48:22 +01:00
Dan Brown
5c7eb0df57 Caught old string helper function usage
Found by Laravel Shift Workbench
2021-09-26 15:41:11 +01:00
Dan Brown
c32b315cd7 Standardised facade usage to use via their FQCN
Done via Laravel Shift Workbench
2021-09-26 15:37:55 +01:00
Zero
c0da5616f3 Fix coding style 2021-09-23 11:07:13 +08:00
Zero
6418824139 Update translation file 2021-09-20 11:29:14 +08:00
Zero
b834f58e87 Add user IP into audit table 2021-09-20 11:29:14 +08:00
Zero
8efaeb068b Save user IP to audit log 2021-09-20 11:29:14 +08:00
Zero
5cf0c99e32 Add IP column 2021-09-20 11:29:14 +08:00
floviolleau
dbfa2d58ed Allow to use DB tables prefix 2021-09-19 14:33:54 +02:00
floviolleau
f8abad1e3b Allow to use DB tables prefix 2021-09-19 14:32:35 +02:00
floviolleau
1a8ae41263 Allow to use DB tables prefix 2021-09-19 14:31:18 +02:00
floviolleau
00af40ab14 Allow to use DB tables prefix 2021-09-19 14:28:57 +02:00
Dan Brown
ffdfdc7449 Fixed dodgy test helper signature causing tests to fail
Just needed some argument defaults to make them optional for existing
uses.
2021-09-18 21:29:42 +01:00
Dan Brown
ba075b46f9 Merge pull request #2928 from BookStackApp/browserkit_removal
Convert old BrowserKit tests
2021-09-18 21:28:16 +01:00
Dan Brown
c08c8d7aa3 Applied styleci style changes 2021-09-18 21:21:44 +01:00
Dan Brown
6454e24657 Removed browserkit testing from project
Converted last bits of the roles tests and removed dependancies.
Updated other PHP dependancies at the same time.
2021-09-18 21:20:38 +01:00
Dan Brown
d74255df5d Started updating RolesTest away from Browserkit 2021-09-18 00:33:03 +01:00
Dan Brown
a4d9bca9e1 Converted AuthTest away from BrowserKit
Moved some user managment tests out to more relevant classess along the
way.
Found some tweaks to make for email confirmation routing as part of
this.
2021-09-17 23:44:54 +01:00
Dan Brown
90c759e5ca Rewrote entity permissions tests to be non-browser-kit 2021-09-17 22:35:28 +01:00
Dan Brown
5d93dd258e Finished moving EntityTests out to new TestCase files 2021-09-17 21:29:16 +01:00
Dan Brown
de8cceb0f7 Moved more tests out of EntityTest 2021-09-15 22:18:37 +01:00
Dan Brown
8a7408bd31 Fixed social auth login audit log messages
Was logging the whole social account instance instead of just the
method.
Updated tests to cover.

Fixes #2930
2021-09-15 20:55:10 +01:00
Dan Brown
121a746d59 Moved/Updated old Activity tracking tests, started on entity tests
Started moving old EntityTests into more appropriate places within
non-browserkit-test classes. Still many more to do.
2021-09-13 23:26:39 +01:00
Dan Brown
badaf08e55 Removed browserkit from a couple of classess
Done a little reorganisation while there of misplaced tests.
Moved MarkdownTest to a new PageEditorTest to avoid confusion with
other markdown elements and to align with other page tests.
2021-09-13 22:54:21 +01:00
Dan Brown
8565187138 Added border to generated TOTP QR code
To fix QR code not being scannable when in dark mode due to
lack of border matching background of QR code.

Fixes #2925
2021-09-13 14:23:54 +01:00
Dan Brown
fa8553839b Updated version and assets for release v21.08.3 2021-09-12 16:31:02 +01:00
Dan Brown
b8fcefc794 Merge branch 'master' into release 2021-09-12 16:30:35 +01:00
Dan Brown
2eafd8335c Updated translators for v21.08.3 2021-09-12 16:25:33 +01:00
Dan Brown
e2f9089f56 New Crowdin updates (#2915)
* New translations auth.php (Spanish)

* New translations activities.php (Italian)

* New translations settings.php (Italian)

* New translations entities.php (Italian)

* New translations validation.php (Italian)

* New translations activities.php (Danish)

* New translations auth.php (Danish)

* New translations common.php (Danish)

* New translations settings.php (Danish)

* New translations entities.php (Danish)

* New translations auth.php (Danish)

* New translations common.php (Danish)

* New translations errors.php (Danish)

* New translations validation.php (Danish)

* New translations activities.php (Russian)

* New translations auth.php (French)

* New translations auth.php (French)

* New translations settings.php (French)

* New translations entities.php (French)

* New translations auth.php (French)
2021-09-12 16:25:05 +01:00
Dan Brown
ef459ca4c4 Altered the parsing of custom head to prevent htmlentities on content
Was causing things like emjoi within script content to be somewhat
mangled. Instead we force UTF8 only parsing via XML declaration.

Added test to cover.

For #2923
2021-09-12 16:19:17 +01:00
Dan Brown
fb80bb5d58 Applied latest styleci changes 2021-09-06 22:19:06 +01:00
Dan Brown
88c698796b Fixed issue with HTML tags in custom head scripts
Fixes a strange issue of HTML tags within script tags being malformed
when part of the HTML custom head content due to the PHP parsing we do.
DOMDocument seemed to cause this upon load.
Adding LIBXML_SCHEMA_CREATE to the ->loadHTML call seems to fix this but
not really sure why. Doesn't seem to cause further issues though.
Tested with multiple scripts and styles and comments and meta tags.

- Also added new testing class to cover.
- As part of testing, added new folder within tests to house setting
  specific tests.

For #2914
2021-09-05 23:52:39 +01:00
Dan Brown
88bcb68fcb Updated version and assets for release v21.08.2 2021-09-04 15:07:20 +01:00
Dan Brown
7c000553ae Merge branch 'master' into release 2021-09-04 15:06:33 +01:00
Dan Brown
d815e1b9f2 Merge branch 'html-filtering' 2021-09-04 14:53:46 +01:00
Dan Brown
492af79c27 Added a couple of additional CSP rules
As per guidance from google's CSP evaluator.
2021-09-04 14:34:43 +01:00
Dan Brown
253f386f00 Finished off script CSP rules
- Added caching for custom html head parsing to add nonce.
- Also moved api docs page into web routes to prevent issues.
2021-09-04 13:57:04 +01:00
Dan Brown
fd44e4ba74 Started application of CSP headers 2021-09-03 23:32:42 +01:00
Dan Brown
040997fdc4 Added filter for xlink:href svg xss
Simply remove all such attributes
2021-09-03 22:34:49 +01:00
Dan Brown
5e6092aaf8 Added extra HTML filtering of dangerous content
In particular, That around the casing of dangerous values within
attributes. This uses some xpath translation to handle different casing
in contains searching.
2021-09-02 22:02:30 +01:00
MatthieuParis
3c4415f3ff Typo. 2021-08-08 21:59:04 +02:00
MatthieuParis
c2e031ae3e Testing command suppressed. 2021-08-08 20:35:12 +02:00
MatthieuParis
537b1614c4 Display warnings when saving draft if another user is editing the page or if the page was updated since the current user has started editing the page. 2021-08-08 19:20:15 +02:00
207 changed files with 3686 additions and 2963 deletions

View File

@@ -41,4 +41,4 @@ MAIL_HOST=localhost
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_ENCRYPTION=null

View File

@@ -42,6 +42,14 @@ APP_TIMEZONE=UTC
# overrides can be made. Defaults to disabled.
APP_THEME=false
# Trusted Proxies
# Used to indicate trust of systems that proxy to the application so
# certain header values (Such as "X-Forwarded-For") can be used from the
# incoming proxy request to provide origin detail.
# Set to an IP address, or multiple comma seperated IP addresses.
# Can alternatively be set to "*" to trust all proxy addresses.
APP_PROXIES=null
# Database details
# Host can contain a port (localhost:3306) or a separate DB_PORT option can be used.
DB_HOST=localhost

View File

@@ -184,3 +184,11 @@ Frost-ZX :: Chinese Simplified
Kuzma Simonov (ovmach) :: Russian
Vojtěch Krystek (acantophis) :: Czech
Michał Lipok (mLipok) :: Polish
Nicolas Pawlak (Mikolajek) :: French; Polish; German
Thomas Hansen (thomasdk81) :: Danish
Hl2run :: Slovak
Ngo Tri Hoai (trihoai) :: Vietnamese
Atalonica :: Catalan
慕容潭谈 (591442386) :: Chinese Simplified
Radim Pesek (ramess18) :: Czech
anastasiia.motylko :: Ukrainian

View File

@@ -55,9 +55,12 @@ class ActivityService
*/
protected function newActivityForUser(string $type): Activity
{
$ip = request()->ip() ?? '';
return $this->activity->newInstance()->forceFill([
'type' => strtolower($type),
'user_id' => user()->id,
'ip' => config('app.env') === 'demo' ? '127.0.0.1' : $ip,
]);
}

View File

@@ -7,10 +7,11 @@ use BookStack\Traits\HasCreatorAndUpdater;
use Illuminate\Database\Eloquent\Relations\MorphTo;
/**
* @property string text
* @property string html
* @property int|null parent_id
* @property int local_id
* @property int $id
* @property string $text
* @property string $html
* @property int|null $parent_id
* @property int $local_id
*/
class Comment extends Model
{

View File

@@ -4,8 +4,8 @@ namespace BookStack\Actions;
use BookStack\Auth\Permissions\PermissionService;
use BookStack\Entities\Models\Entity;
use DB;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
class TagRepo
{

View File

@@ -8,6 +8,7 @@ use BaconQrCode\Renderer\ImageRenderer;
use BaconQrCode\Renderer\RendererStyle\Fill;
use BaconQrCode\Renderer\RendererStyle\RendererStyle;
use BaconQrCode\Writer;
use BookStack\Auth\User;
use PragmaRX\Google2FA\Google2FA;
use PragmaRX\Google2FA\Support\Constants;
@@ -36,11 +37,11 @@ class TotpService
/**
* Generate a TOTP URL from secret key.
*/
public function generateUrl(string $secret): string
public function generateUrl(string $secret, User $user): string
{
return $this->google2fa->getQRCodeUrl(
setting('app-name'),
user()->email,
$user->email,
$secret
);
}
@@ -54,7 +55,7 @@ class TotpService
return (new Writer(
new ImageRenderer(
new RendererStyle(192, 0, null, null, $color),
new RendererStyle(192, 4, null, null, $color),
new SvgImageBackEnd()
)
))->writeString($url);

View File

@@ -141,7 +141,7 @@ class SocialAuthService
// When a user is not logged in and a matching SocialAccount exists,
// Simply log the user into the application.
if (!$isLoggedIn && $socialAccount !== null) {
$this->loginService->login($socialAccount->user, $socialAccount);
$this->loginService->login($socialAccount->user, $socialDriver);
return redirect()->intended('/');
}

View File

@@ -603,7 +603,7 @@ class PermissionService
/**
* Filter items that have entities set as a polymorphic relation.
*
* @param Builder|\Illuminate\Database\Query\Builder $query
* @param Builder|QueryBuilder $query
*/
public function filterRestrictedEntityRelations($query, string $tableName, string $entityIdColumn, string $entityTypeColumn, string $action = 'view')
{
@@ -611,9 +611,10 @@ class PermissionService
$q = $query->where(function ($query) use ($tableDetails, $action) {
$query->whereExists(function ($permissionQuery) use (&$tableDetails, $action) {
/** @var Builder $permissionQuery */
$permissionQuery->select(['role_id'])->from('joint_permissions')
->whereRaw('joint_permissions.entity_id=' . $tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn'])
->whereRaw('joint_permissions.entity_type=' . $tableDetails['tableName'] . '.' . $tableDetails['entityTypeColumn'])
->whereColumn('joint_permissions.entity_id', '=', $tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn'])
->whereColumn('joint_permissions.entity_type', '=', $tableDetails['tableName'] . '.' . $tableDetails['entityTypeColumn'])
->where('action', '=', $action)
->whereIn('role_id', $this->getCurrentUserRoles())
->where(function (QueryBuilder $query) {
@@ -639,8 +640,9 @@ class PermissionService
$q = $query->where(function ($query) use ($tableDetails, $morphClass) {
$query->where(function ($query) use (&$tableDetails, $morphClass) {
$query->whereExists(function ($permissionQuery) use (&$tableDetails, $morphClass) {
/** @var Builder $permissionQuery */
$permissionQuery->select('id')->from('joint_permissions')
->whereRaw('joint_permissions.entity_id=' . $tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn'])
->whereColumn('joint_permissions.entity_id', '=', $tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn'])
->where('entity_type', '=', $morphClass)
->where('action', '=', 'view')
->whereIn('role_id', $this->getCurrentUserRoles())

View File

@@ -13,12 +13,13 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* Class Role.
*
* @property int $id
* @property string $display_name
* @property string $description
* @property string $external_auth_id
* @property string $system_name
* @property bool $mfa_enforced
* @property int $id
* @property string $display_name
* @property string $description
* @property string $external_auth_id
* @property string $system_name
* @property bool $mfa_enforced
* @property Collection $users
*/
class Role extends Model implements Loggable
{

View File

@@ -15,7 +15,7 @@ use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Pagination\LengthAwarePaginator;
use Log;
use Illuminate\Support\Facades\Log;
class UserRepo
{

View File

@@ -70,6 +70,7 @@ return [
'email' => 'emails.password',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],

View File

@@ -69,7 +69,10 @@ return [
'port' => $mysql_port,
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
// Prefixes are only semi-supported and may be unstable
// since they are not tested as part of our automated test suite.
// If used, the prefix should not be changed otherwise you will likely receive errors.
'prefix' => env('DB_TABLE_PREFIX', ''),
'prefix_indexes' => true,
'strict' => false,
'engine' => null,

View File

@@ -70,7 +70,7 @@ return [
* direct class use like:
* $dompdf = new DOMPDF(); $dompdf->load_html($htmldata); $dompdf->render(); $pdfdata = $dompdf->output();
*/
'chroot' => realpath(base_path()),
'chroot' => realpath(public_path()),
/**
* Whether to use Unicode fonts or not.

View File

@@ -37,9 +37,14 @@ return [
'root' => public_path(),
],
'local_secure' => [
'local_secure_attachments' => [
'driver' => 'local',
'root' => storage_path(),
'root' => storage_path('uploads/files/'),
],
'local_secure_images' => [
'driver' => 'local',
'root' => storage_path('uploads/images/'),
],
's3' => [

View File

@@ -3,8 +3,8 @@
namespace BookStack\Console\Commands;
use BookStack\Entities\Tools\SearchIndex;
use DB;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class RegenerateSearch extends Command
{

View File

@@ -12,9 +12,12 @@ use Illuminate\Support\Collection;
/**
* Class Book.
*
* @property string $description
* @property int $image_id
* @property Image|null $cover
* @property string $description
* @property int $image_id
* @property Image|null $cover
* @property \Illuminate\Database\Eloquent\Collection $chapters
* @property \Illuminate\Database\Eloquent\Collection $pages
* @property \Illuminate\Database\Eloquent\Collection $directPages
*/
class Book extends Entity implements HasCoverImage
{

View File

@@ -5,6 +5,7 @@ namespace BookStack\Entities\Models;
use BookStack\Auth\User;
use BookStack\Model;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* Class PageRevision.
@@ -14,11 +15,13 @@ use Carbon\Carbon;
* @property string $book_slug
* @property int $created_by
* @property Carbon $created_at
* @property Carbon $updated_at
* @property string $type
* @property string $summary
* @property string $markdown
* @property string $html
* @property int $revision_number
* @property Page $page
*/
class PageRevision extends Model
{
@@ -26,20 +29,16 @@ class PageRevision extends Model
/**
* Get the user that created the page revision.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function createdBy()
public function createdBy(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
/**
* Get the page this revision originates from.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function page()
public function page(): BelongsTo
{
return $this->belongsTo(Page::class);
}

View File

@@ -316,6 +316,7 @@ class PageContent
}
// Find page and skip this if page not found
/** @var ?Page $matchedPage */
$matchedPage = Page::visible()->find($pageId);
if ($matchedPage === null) {
$html = str_replace($fullMatch, '', $html);

View File

@@ -21,8 +21,6 @@ class PageEditActivity
/**
* Check if there's active editing being performed on this page.
*
* @return bool
*/
public function hasActiveEditing(): bool
{
@@ -43,12 +41,38 @@ class PageEditActivity
return trans('entities.pages_draft_edit_active.message', ['start' => $userMessage, 'time' => $timeMessage]);
}
/**
* Get any editor clash warning messages to show for the given draft revision.
*
* @param PageRevision|Page $draft
*
* @return string[]
*/
public function getWarningMessagesForDraft($draft): array
{
$warnings = [];
if ($this->hasActiveEditing()) {
$warnings[] = $this->activeEditingMessage();
}
if ($draft instanceof PageRevision && $this->hasPageBeenUpdatedSinceDraftCreated($draft)) {
$warnings[] = trans('entities.pages_draft_page_changed_since_creation');
}
return $warnings;
}
/**
* Check if the page has been updated since the draft has been saved.
*/
protected function hasPageBeenUpdatedSinceDraftCreated(PageRevision $draft): bool
{
return $draft->page->updated_at->timestamp > $draft->created_at->timestamp;
}
/**
* Get the message to show when the user will be editing one of their drafts.
*
* @param PageRevision $draft
*
* @return string
*/
public function getEditingActiveDraftMessage(PageRevision $draft): string
{

View File

@@ -156,7 +156,9 @@ class SearchRunner
})->groupBy('entity_type', 'entity_id');
$entitySelect->join($this->db->raw('(' . $subQuery->toSql() . ') as s'), function (JoinClause $join) {
$join->on('id', '=', 'entity_id');
})->selectRaw($entity->getTable() . '.*, s.score')->orderBy('score', 'desc');
})->addSelect($entity->getTable() . '.*')
->selectRaw('s.score')
->orderBy('score', 'desc');
$entitySelect->mergeBindings($subQuery);
}

View File

@@ -55,7 +55,7 @@ class StoppedAuthenticationException extends \Exception implements Responsable
], 401);
}
if (session()->get('sent-email-confirmation') === true) {
if (session()->pull('sent-email-confirmation') === true) {
return redirect('/register/confirm');
}

View File

@@ -0,0 +1,49 @@
<?php
namespace BookStack\Exceptions;
use Whoops\Handler\Handler;
class WhoopsBookStackPrettyHandler extends Handler
{
/**
* @return int|null A handler may return nothing, or a Handler::HANDLE_* constant
*/
public function handle()
{
$exception = $this->getException();
echo view('errors.debug', [
'error' => $exception->getMessage(),
'errorClass' => get_class($exception),
'trace' => $exception->getTraceAsString(),
'environment' => $this->getEnvironment(),
])->render();
return Handler::QUIT;
}
protected function safeReturn(callable $callback, $default = null)
{
try {
return $callback();
} catch (\Exception $e) {
return $default;
}
}
protected function getEnvironment(): array
{
return [
'PHP Version' => phpversion(),
'BookStack Version' => $this->safeReturn(function () {
$versionFile = base_path('version');
return trim(file_get_contents($versionFile));
}, 'unknown'),
'Theme Configured' => $this->safeReturn(function () {
return config('view.theme');
}) ?? 'None',
];
}
}

View File

@@ -56,7 +56,7 @@ class ForgotPasswordController extends Controller
$this->logActivity(ActivityType::AUTH_PASSWORD_RESET, $request->get('email'));
}
if ($response === Password::RESET_LINK_SENT || $response === Password::INVALID_USER) {
if (in_array($response, [Password::RESET_LINK_SENT, Password::INVALID_USER, Password::RESET_THROTTLED])) {
$message = trans('auth.reset_password_sent', ['email' => $request->get('email')]);
$this->showSuccessNotification($message);

View File

@@ -31,7 +31,7 @@ class MfaTotpController extends Controller
session()->put(static::SETUP_SECRET_SESSION_KEY, encrypt($totpSecret));
}
$qrCodeUrl = $totp->generateUrl($totpSecret);
$qrCodeUrl = $totp->generateUrl($totpSecret, $this->currentOrLastAttemptedUser());
$svg = $totp->generateQrCodeSvg($qrCodeUrl);
return view('mfa.totp-generate', [

View File

@@ -12,7 +12,7 @@ use BookStack\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Validator;
use Illuminate\Support\Facades\Validator;
class RegisterController extends Controller
{

View File

@@ -96,9 +96,10 @@ class HomeController extends Controller
if ($homepageOption === 'page') {
$homepageSetting = setting('app-homepage', '0:');
$id = intval(explode(':', $homepageSetting)[0]);
/** @var Page $customHomepage */
$customHomepage = Page::query()->where('draft', '=', false)->findOrFail($id);
$pageContent = new PageContent($customHomepage);
$customHomepage->html = $pageContent->render(true);
$customHomepage->html = $pageContent->render(false);
return view('home.specific-page', array_merge($commonData, ['customHomepage' => $customHomepage]));
}

View File

@@ -259,13 +259,13 @@ class PageController extends Controller
}
$draft = $this->pageRepo->updatePageDraft($page, $request->only(['name', 'html', 'markdown']));
$updateTime = $draft->updated_at->timestamp;
$warnings = (new PageEditActivity($page))->getWarningMessagesForDraft($draft);
return response()->json([
'status' => 'success',
'message' => trans('entities.pages_edit_draft_save_at'),
'timestamp' => $updateTime,
'warning' => implode("\n", $warnings),
'timestamp' => $draft->updated_at->timestamp,
]);
}

View File

@@ -24,12 +24,13 @@ class Kernel extends HttpKernel
*/
protected $middlewareGroups = [
'web' => [
\BookStack\Http\Middleware\ControlIframeSecurity::class,
\BookStack\Http\Middleware\ApplyCspRules::class,
\BookStack\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\BookStack\Http\Middleware\VerifyCsrfToken::class,
\BookStack\Http\Middleware\PreventAuthenticatedResponseCaching::class,
\BookStack\Http\Middleware\CheckEmailConfirmed::class,
\BookStack\Http\Middleware\RunThemeActions::class,
\BookStack\Http\Middleware\Localization::class,
@@ -39,6 +40,7 @@ class Kernel extends HttpKernel
\BookStack\Http\Middleware\EncryptCookies::class,
\BookStack\Http\Middleware\StartSessionIfCookieExists::class,
\BookStack\Http\Middleware\ApiAuthenticate::class,
\BookStack\Http\Middleware\PreventAuthenticatedResponseCaching::class,
\BookStack\Http\Middleware\CheckEmailConfirmed::class,
],
];

View File

@@ -0,0 +1,45 @@
<?php
namespace BookStack\Http\Middleware;
use BookStack\Util\CspService;
use Closure;
use Illuminate\Http\Request;
class ApplyCspRules
{
/**
* @var CspService
*/
protected $cspService;
public function __construct(CspService $cspService)
{
$this->cspService = $cspService;
}
/**
* Handle an incoming request.
*
* @param Request $request
* @param Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
view()->share('cspNonce', $this->cspService->getNonce());
if ($this->cspService->allowedIFrameHostsConfigured()) {
config()->set('session.same_site', 'none');
}
$response = $next($request);
$this->cspService->setFrameAncestors($response);
$this->cspService->setScriptSrc($response);
$this->cspService->setObjectSrc($response);
$this->cspService->setBaseUri($response);
return $response;
}
}

View File

@@ -1,37 +0,0 @@
<?php
namespace BookStack\Http\Middleware;
use Closure;
/**
* Sets CSP headers to restrict the hosts that BookStack can be
* iframed within. Also adjusts the cookie samesite options
* so that cookies will operate in the third-party context.
*/
class ControlIframeSecurity
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
$iframeHosts = collect(explode(' ', config('app.iframe_hosts', '')))->filter();
if ($iframeHosts->count() > 0) {
config()->set('session.same_site', 'none');
}
$iframeHosts->prepend("'self'");
$response = $next($request);
$cspValue = 'frame-ancestors ' . $iframeHosts->join(' ');
$response->headers->set('Content-Security-Policy', $cspValue);
return $response;
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace BookStack\Http\Middleware;
use Closure;
use Symfony\Component\HttpFoundation\Response;
class PreventAuthenticatedResponseCaching
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
/** @var Response $response */
$response = $next($request);
if (signedInUser()) {
$response->headers->set('Cache-Control', 'max-age=0, no-store, private');
$response->headers->set('Pragma', 'no-cache');
$response->headers->set('Expires', 'Sun, 12 Jul 2015 19:01:00 GMT');
}
return $response;
}
}

View File

@@ -2,7 +2,6 @@
namespace BookStack\Providers;
use Blade;
use BookStack\Auth\Access\LoginService;
use BookStack\Auth\Access\SocialAuthService;
use BookStack\Entities\BreadcrumbsViewComposer;
@@ -10,15 +9,19 @@ use BookStack\Entities\Models\Book;
use BookStack\Entities\Models\Bookshelf;
use BookStack\Entities\Models\Chapter;
use BookStack\Entities\Models\Page;
use BookStack\Exceptions\WhoopsBookStackPrettyHandler;
use BookStack\Settings\Setting;
use BookStack\Settings\SettingService;
use BookStack\Util\CspService;
use Illuminate\Contracts\Cache\Repository;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
use Laravel\Socialite\Contracts\Factory as SocialiteFactory;
use Schema;
use URL;
use Whoops\Handler\HandlerInterface;
class AppServiceProvider extends ServiceProvider
{
@@ -64,6 +67,10 @@ class AppServiceProvider extends ServiceProvider
*/
public function register()
{
$this->app->bind(HandlerInterface::class, function ($app) {
return $app->make(WhoopsBookStackPrettyHandler::class);
});
$this->app->singleton(SettingService::class, function ($app) {
return new SettingService($app->make(Setting::class), $app->make(Repository::class));
});
@@ -71,5 +78,9 @@ class AppServiceProvider extends ServiceProvider
$this->app->singleton(SocialAuthService::class, function ($app) {
return new SocialAuthService($app->make(SocialiteFactory::class), $app->make(LoginService::class));
});
$this->app->singleton(CspService::class, function ($app) {
return new CspService();
});
}
}

View File

@@ -2,7 +2,6 @@
namespace BookStack\Providers;
use Auth;
use BookStack\Api\ApiTokenGuard;
use BookStack\Auth\Access\ExternalBaseUserProvider;
use BookStack\Auth\Access\Guards\LdapSessionGuard;
@@ -10,6 +9,7 @@ use BookStack\Auth\Access\Guards\Saml2SessionGuard;
use BookStack\Auth\Access\LdapService;
use BookStack\Auth\Access\LoginService;
use BookStack\Auth\Access\RegistrationService;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\ServiceProvider;
class AuthServiceProvider extends ServiceProvider

View File

@@ -3,7 +3,7 @@
namespace BookStack\Providers;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Route;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{

View File

@@ -0,0 +1,64 @@
<?php
namespace BookStack\Theming;
use BookStack\Util\CspService;
use BookStack\Util\HtmlContentFilter;
use BookStack\Util\HtmlNonceApplicator;
use Illuminate\Contracts\Cache\Repository as Cache;
class CustomHtmlHeadContentProvider
{
/**
* @var CspService
*/
protected $cspService;
/**
* @var Cache
*/
protected $cache;
public function __construct(CspService $cspService, Cache $cache)
{
$this->cspService = $cspService;
$this->cache = $cache;
}
/**
* Fetch our custom HTML head content prepared for use on web pages.
* Content has a nonce applied for CSP.
*/
public function forWeb(): string
{
$content = $this->getSourceContent();
$hash = md5($content);
$html = $this->cache->remember('custom-head-web:' . $hash, 86400, function () use ($content) {
return HtmlNonceApplicator::prepare($content);
});
return HtmlNonceApplicator::apply($html, $this->cspService->getNonce());
}
/**
* Fetch our custom HTML head content prepared for use in export formats.
* Scripts are stripped to avoid potential issues.
*/
public function forExport(): string
{
$content = $this->getSourceContent();
$hash = md5($content);
return $this->cache->remember('custom-head-export:' . $hash, 86400, function () use ($content) {
return HtmlContentFilter::removeScripts($content);
});
}
/**
* Get the original custom head content to use.
*/
protected function getSourceContent(): string
{
return setting('app-custom-head', '');
}
}

View File

@@ -7,8 +7,9 @@ use Exception;
use Illuminate\Contracts\Filesystem\Factory as FileSystem;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Illuminate\Contracts\Filesystem\Filesystem as FileSystemInstance;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Log;
use League\Flysystem\Util;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class AttachmentService
@@ -27,15 +28,39 @@ class AttachmentService
* Get the storage that will be used for storing files.
*/
protected function getStorage(): FileSystemInstance
{
return $this->fileSystem->disk($this->getStorageDiskName());
}
/**
* Get the name of the storage disk to use.
*/
protected function getStorageDiskName(): string
{
$storageType = config('filesystems.attachments');
// Override default location if set to local public to ensure not visible.
if ($storageType === 'local') {
$storageType = 'local_secure';
// Change to our secure-attachment disk if any of the local options
// are used to prevent escaping that location.
if ($storageType === 'local' || $storageType === 'local_secure') {
$storageType = 'local_secure_attachments';
}
return $this->fileSystem->disk($storageType);
return $storageType;
}
/**
* Change the originally provided path to fit any disk-specific requirements.
* This also ensures the path is kept to the expected root folders.
*/
protected function adjustPathForStorageDisk(string $path): string
{
$path = Util::normalizePath(str_replace('uploads/files/', '', $path));
if ($this->getStorageDiskName() === 'local_secure_attachments') {
return $path;
}
return 'uploads/files/' . $path;
}
/**
@@ -45,26 +70,22 @@ class AttachmentService
*/
public function getAttachmentFromStorage(Attachment $attachment): string
{
return $this->getStorage()->get($attachment->path);
return $this->getStorage()->get($this->adjustPathForStorageDisk($attachment->path));
}
/**
* Store a new attachment upon user upload.
*
* @param UploadedFile $uploadedFile
* @param int $page_id
*
* @throws FileUploadException
*
* @return Attachment
*/
public function saveNewUpload(UploadedFile $uploadedFile, $page_id)
public function saveNewUpload(UploadedFile $uploadedFile, int $page_id): Attachment
{
$attachmentName = $uploadedFile->getClientOriginalName();
$attachmentPath = $this->putFileInStorage($uploadedFile);
$largestExistingOrder = Attachment::where('uploaded_to', '=', $page_id)->max('order');
$largestExistingOrder = Attachment::query()->where('uploaded_to', '=', $page_id)->max('order');
$attachment = Attachment::forceCreate([
/** @var Attachment $attachment */
$attachment = Attachment::query()->forceCreate([
'name' => $attachmentName,
'path' => $attachmentPath,
'extension' => $uploadedFile->getClientOriginalExtension(),
@@ -78,17 +99,12 @@ class AttachmentService
}
/**
* Store a upload, saving to a file and deleting any existing uploads
* Store an upload, saving to a file and deleting any existing uploads
* attached to that file.
*
* @param UploadedFile $uploadedFile
* @param Attachment $attachment
*
* @throws FileUploadException
*
* @return Attachment
*/
public function saveUpdatedUpload(UploadedFile $uploadedFile, Attachment $attachment)
public function saveUpdatedUpload(UploadedFile $uploadedFile, Attachment $attachment): Attachment
{
if (!$attachment->external) {
$this->deleteFileInStorage($attachment);
@@ -160,8 +176,6 @@ class AttachmentService
/**
* Delete a File from the database and storage.
*
* @param Attachment $attachment
*
* @throws Exception
*/
public function deleteFile(Attachment $attachment)
@@ -179,15 +193,13 @@ class AttachmentService
/**
* Delete a file from the filesystem it sits on.
* Cleans any empty leftover folders.
*
* @param Attachment $attachment
*/
protected function deleteFileInStorage(Attachment $attachment)
{
$storage = $this->getStorage();
$dirPath = dirname($attachment->path);
$dirPath = $this->adjustPathForStorageDisk(dirname($attachment->path));
$storage->delete($attachment->path);
$storage->delete($this->adjustPathForStorageDisk($attachment->path));
if (count($storage->allFiles($dirPath)) === 0) {
$storage->deleteDirectory($dirPath);
}
@@ -196,13 +208,9 @@ class AttachmentService
/**
* Store a file in storage with the given filename.
*
* @param UploadedFile $uploadedFile
*
* @throws FileUploadException
*
* @return string
*/
protected function putFileInStorage(UploadedFile $uploadedFile)
protected function putFileInStorage(UploadedFile $uploadedFile): string
{
$attachmentData = file_get_contents($uploadedFile->getRealPath());
@@ -210,14 +218,14 @@ class AttachmentService
$basePath = 'uploads/files/' . date('Y-m-M') . '/';
$uploadFileName = Str::random(16) . '.' . $uploadedFile->getClientOriginalExtension();
while ($storage->exists($basePath . $uploadFileName)) {
while ($storage->exists($this->adjustPathForStorageDisk($basePath . $uploadFileName))) {
$uploadFileName = Str::random(3) . $uploadFileName;
}
$attachmentPath = $basePath . $uploadFileName;
try {
$storage->put($attachmentPath, $attachmentData);
$storage->put($this->adjustPathForStorageDisk($attachmentPath), $attachmentData);
} catch (Exception $e) {
Log::error('Error when attempting file upload:' . $e->getMessage());

View File

@@ -3,7 +3,6 @@
namespace BookStack\Uploads;
use BookStack\Exceptions\ImageUploadException;
use DB;
use ErrorException;
use Exception;
use Illuminate\Contracts\Cache\Repository as Cache;
@@ -11,9 +10,11 @@ use Illuminate\Contracts\Filesystem\Factory as FileSystem;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Illuminate\Contracts\Filesystem\Filesystem as FileSystemInstance;
use Illuminate\Contracts\Filesystem\Filesystem as Storage;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Intervention\Image\Exception\NotSupportedException;
use Intervention\Image\ImageManager;
use League\Flysystem\Util;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class ImageService
@@ -38,16 +39,43 @@ class ImageService
/**
* Get the storage that will be used for storing images.
*/
protected function getStorage(string $type = ''): FileSystemInstance
protected function getStorage(string $imageType = ''): FileSystemInstance
{
return $this->fileSystem->disk($this->getStorageDiskName($imageType));
}
/**
* Change the originally provided path to fit any disk-specific requirements.
* This also ensures the path is kept to the expected root folders.
*/
protected function adjustPathForStorageDisk(string $path, string $imageType = ''): string
{
$path = Util::normalizePath(str_replace('uploads/images/', '', $path));
if ($this->getStorageDiskName($imageType) === 'local_secure_images') {
return $path;
}
return 'uploads/images/' . $path;
}
/**
* Get the name of the storage disk to use.
*/
protected function getStorageDiskName(string $imageType): string
{
$storageType = config('filesystems.images');
// Ensure system images (App logo) are uploaded to a public space
if ($type === 'system' && $storageType === 'local_secure') {
if ($imageType === 'system' && $storageType === 'local_secure') {
$storageType = 'local';
}
return $this->fileSystem->disk($storageType);
if ($storageType === 'local_secure') {
$storageType = 'local_secure_images';
}
return $storageType;
}
/**
@@ -104,7 +132,7 @@ class ImageService
$imagePath = '/uploads/images/' . $type . '/' . date('Y-m') . '/';
while ($storage->exists($imagePath . $fileName)) {
while ($storage->exists($this->adjustPathForStorageDisk($imagePath . $fileName, $type))) {
$fileName = Str::random(3) . $fileName;
}
@@ -114,7 +142,7 @@ class ImageService
}
try {
$this->saveImageDataInPublicSpace($storage, $fullPath, $imageData);
$this->saveImageDataInPublicSpace($storage, $this->adjustPathForStorageDisk($fullPath, $type), $imageData);
} catch (Exception $e) {
\Log::error('Error when attempting image upload:' . $e->getMessage());
@@ -216,13 +244,13 @@ class ImageService
}
$storage = $this->getStorage($image->type);
if ($storage->exists($thumbFilePath)) {
if ($storage->exists($this->adjustPathForStorageDisk($thumbFilePath, $image->type))) {
return $this->getPublicUrl($thumbFilePath);
}
$thumbData = $this->resizeImage($storage->get($imagePath), $width, $height, $keepRatio);
$thumbData = $this->resizeImage($storage->get($this->adjustPathForStorageDisk($imagePath, $image->type)), $width, $height, $keepRatio);
$this->saveImageDataInPublicSpace($storage, $thumbFilePath, $thumbData);
$this->saveImageDataInPublicSpace($storage, $this->adjustPathForStorageDisk($thumbFilePath, $image->type), $thumbData);
$this->cache->put('images-' . $image->id . '-' . $thumbFilePath, $thumbFilePath, 60 * 60 * 72);
return $this->getPublicUrl($thumbFilePath);
@@ -279,10 +307,9 @@ class ImageService
*/
public function getImageData(Image $image): string
{
$imagePath = $image->path;
$storage = $this->getStorage();
return $storage->get($imagePath);
return $storage->get($this->adjustPathForStorageDisk($image->path, $image->type));
}
/**
@@ -292,7 +319,7 @@ class ImageService
*/
public function destroy(Image $image)
{
$this->destroyImagesFromPath($image->path);
$this->destroyImagesFromPath($image->path, $image->type);
$image->delete();
}
@@ -300,9 +327,10 @@ class ImageService
* Destroys an image at the given path.
* Searches for image thumbnails in addition to main provided path.
*/
protected function destroyImagesFromPath(string $path): bool
protected function destroyImagesFromPath(string $path, string $imageType): bool
{
$storage = $this->getStorage();
$path = $this->adjustPathForStorageDisk($path, $imageType);
$storage = $this->getStorage($imageType);
$imageFolder = dirname($path);
$imageFileName = basename($path);
@@ -326,7 +354,7 @@ class ImageService
}
/**
* Check whether or not a folder is empty.
* Check whether a folder is empty.
*/
protected function isFolderEmpty(FileSystemInstance $storage, string $path): bool
{
@@ -374,7 +402,7 @@ class ImageService
}
/**
* Convert a image URI to a Base64 encoded string.
* Convert an image URI to a Base64 encoded string.
* Attempts to convert the URL to a system storage url then
* fetch the data from the disk or storage location.
* Returns null if the image data cannot be fetched from storage.
@@ -388,6 +416,7 @@ class ImageService
return null;
}
$storagePath = $this->adjustPathForStorageDisk($storagePath);
$storage = $this->getStorage();
$imageData = null;
if ($storage->exists($storagePath)) {

96
app/Util/CspService.php Normal file
View File

@@ -0,0 +1,96 @@
<?php
namespace BookStack\Util;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Response;
class CspService
{
/** @var string */
protected $nonce;
public function __construct(string $nonce = '')
{
$this->nonce = $nonce ?: Str::random(24);
}
/**
* Get the nonce value for CSP.
*/
public function getNonce(): string
{
return $this->nonce;
}
/**
* Sets CSP 'script-src' headers to restrict the forms of script that can
* run on the page.
*/
public function setScriptSrc(Response $response)
{
if (config('app.allow_content_scripts')) {
return;
}
$parts = [
'http:',
'https:',
'\'nonce-' . $this->nonce . '\'',
'\'strict-dynamic\'',
];
$value = 'script-src ' . implode(' ', $parts);
$response->headers->set('Content-Security-Policy', $value, false);
}
/**
* Sets CSP "frame-ancestors" headers to restrict the hosts that BookStack can be
* iframed within. Also adjusts the cookie samesite options so that cookies will
* operate in the third-party context.
*/
public function setFrameAncestors(Response $response)
{
$iframeHosts = $this->getAllowedIframeHosts();
array_unshift($iframeHosts, "'self'");
$cspValue = 'frame-ancestors ' . implode(' ', $iframeHosts);
$response->headers->set('Content-Security-Policy', $cspValue, false);
}
/**
* Check if the user has configured some allowed iframe hosts.
*/
public function allowedIFrameHostsConfigured(): bool
{
return count($this->getAllowedIframeHosts()) > 0;
}
/**
* Sets CSP 'object-src' headers to restrict the types of dynamic content
* that can be embedded on the page.
*/
public function setObjectSrc(Response $response)
{
if (config('app.allow_content_scripts')) {
return;
}
$response->headers->set('Content-Security-Policy', 'object-src \'self\'', false);
}
/**
* Sets CSP 'base-uri' headers to restrict what base tags can be set on
* the page to prevent manipulation of relative links.
*/
public function setBaseUri(Response $response)
{
$response->headers->set('Content-Security-Policy', 'base-uri \'self\'', false);
}
protected function getAllowedIframeHosts(): array
{
$hosts = config('app.iframe_hosts', '');
return array_filter(explode(' ', $hosts));
}
}

View File

@@ -2,6 +2,7 @@
namespace BookStack\Util;
use DOMAttr;
use DOMDocument;
use DOMNodeList;
use DOMXPath;
@@ -9,7 +10,7 @@ use DOMXPath;
class HtmlContentFilter
{
/**
* Remove all of the script elements from the given HTML.
* Remove all the script elements from the given HTML.
*/
public static function removeScripts(string $html): string
{
@@ -28,28 +29,29 @@ class HtmlContentFilter
static::removeNodes($scriptElems);
// Remove clickable links to JavaScript URI
$badLinks = $xPath->query('//*[contains(@href, \'javascript:\')]');
$badLinks = $xPath->query('//*[' . static::xpathContains('@href', 'javascript:') . ']');
static::removeNodes($badLinks);
// Remove forms with calls to JavaScript URI
$badForms = $xPath->query('//*[contains(@action, \'javascript:\')] | //*[contains(@formaction, \'javascript:\')]');
$badForms = $xPath->query('//*[' . static::xpathContains('@action', 'javascript:') . '] | //*[' . static::xpathContains('@formaction', 'javascript:') . ']');
static::removeNodes($badForms);
// Remove meta tag to prevent external redirects
$metaTags = $xPath->query('//meta[contains(@content, \'url\')]');
$metaTags = $xPath->query('//meta[' . static::xpathContains('@content', 'url') . ']');
static::removeNodes($metaTags);
// Remove data or JavaScript iFrames
$badIframes = $xPath->query('//*[contains(@src, \'data:\')] | //*[contains(@src, \'javascript:\')] | //*[@srcdoc]');
$badIframes = $xPath->query('//*[' . static::xpathContains('@src', 'data:') . '] | //*[' . static::xpathContains('@src', 'javascript:') . '] | //*[@srcdoc]');
static::removeNodes($badIframes);
// Remove elements with a xlink:href attribute
// Used in SVG but deprecated anyway, so we'll be a bit more heavy-handed here.
$xlinkHrefAttributes = $xPath->query('//@*[contains(name(), \'xlink:href\')]');
static::removeAttributes($xlinkHrefAttributes);
// Remove 'on*' attributes
$onAttributes = $xPath->query('//@*[starts-with(name(), \'on\')]');
foreach ($onAttributes as $attr) {
/** @var \DOMAttr $attr */
$attrName = $attr->nodeName;
$attr->parentNode->removeAttribute($attrName);
}
static::removeAttributes($onAttributes);
$html = '';
$topElems = $doc->documentElement->childNodes->item(0)->childNodes;
@@ -61,7 +63,19 @@ class HtmlContentFilter
}
/**
* Removed all of the given DOMNodes.
* Create a xpath contains statement with a translation automatically built within
* to affectively search in a cases-insensitive manner.
*/
protected static function xpathContains(string $property, string $value): string
{
$value = strtolower($value);
$upperVal = strtoupper($value);
return 'contains(translate(' . $property . ', \'' . $upperVal . '\', \'' . $value . '\'), \'' . $value . '\')';
}
/**
* Remove all the given DOMNodes.
*/
protected static function removeNodes(DOMNodeList $nodes): void
{
@@ -69,4 +83,16 @@ class HtmlContentFilter
$node->parentNode->removeChild($node);
}
}
/**
* Remove all the given attribute nodes.
*/
protected static function removeAttributes(DOMNodeList $attrs): void
{
/** @var DOMAttr $attr */
foreach ($attrs as $attr) {
$attrName = $attr->nodeName;
$attr->parentNode->removeAttribute($attrName);
}
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace BookStack\Util;
use DOMDocument;
use DOMElement;
use DOMNodeList;
use DOMXPath;
class HtmlNonceApplicator
{
protected static $placeholder = '[CSP_NONCE_VALUE]';
/**
* Prepare the given HTML content with nonce attributes including a placeholder
* value which we can target later.
*/
public static function prepare(string $html): string
{
if (empty($html)) {
return $html;
}
$html = '<?xml encoding="utf-8" ?><body>' . $html . '</body>';
libxml_use_internal_errors(true);
$doc = new DOMDocument();
$doc->loadHTML($html, LIBXML_SCHEMA_CREATE);
$xPath = new DOMXPath($doc);
// Apply to scripts
$scriptElems = $xPath->query('//script');
static::addNonceAttributes($scriptElems, static::$placeholder);
// Apply to styles
$styleElems = $xPath->query('//style');
static::addNonceAttributes($styleElems, static::$placeholder);
$returnHtml = '';
$topElems = $doc->documentElement->childNodes->item(0)->childNodes;
foreach ($topElems as $child) {
$content = $doc->saveHTML($child);
$returnHtml .= $content;
}
return $returnHtml;
}
/**
* Apply the give nonce value to the given prepared HTML.
*/
public static function apply(string $html, string $nonce): string
{
return str_replace(static::$placeholder, $nonce, $html);
}
protected static function addNonceAttributes(DOMNodeList $nodes, string $attrValue): void
{
/** @var DOMElement $node */
foreach ($nodes as $node) {
$node->setAttribute('nonce', $attrValue);
}
}
}

View File

@@ -17,10 +17,10 @@
"barryvdh/laravel-dompdf": "^0.9.0",
"barryvdh/laravel-snappy": "^0.4.8",
"doctrine/dbal": "^2.12.1",
"facade/ignition": "^1.16.4",
"fideloper/proxy": "^4.4.1",
"filp/whoops": "^2.14",
"intervention/image": "^2.5.1",
"laravel/framework": "^6.20.16",
"laravel/framework": "^6.20.33",
"laravel/socialite": "^5.1",
"league/commonmark": "^1.5",
"league/flysystem-aws-s3-v3": "^1.0.29",
@@ -41,9 +41,9 @@
"barryvdh/laravel-debugbar": "^3.5.1",
"barryvdh/laravel-ide-helper": "^2.8.2",
"fakerphp/faker": "^1.13.0",
"laravel/browser-kit-testing": "^5.2",
"mockery/mockery": "^1.3.3",
"phpunit/phpunit": "^9.5.3"
"phpunit/phpunit": "^9.5.3",
"symfony/dom-crawler": "^5.3"
},
"autoload": {
"classmap": [

880
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,7 @@
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Str;
class CreateJointPermissionsTable extends Migration
{
@@ -53,7 +54,7 @@ class CreateJointPermissionsTable extends Migration
// Ensure unique name
while (DB::table('roles')->where('name', '=', $publicRoleData['display_name'])->count() > 0) {
$publicRoleData['display_name'] = $publicRoleData['display_name'] . str_random(2);
$publicRoleData['display_name'] = $publicRoleData['display_name'] . Str::random(2);
}
$publicRoleId = DB::table('roles')->insertGetId($publicRoleData);

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddActivitiesIpColumn extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('activities', function (Blueprint $table) {
$table->string('ip', 45)->after('user_id');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('activities', function (Blueprint $table) {
$table->dropColumn('ip');
});
}
}

2
public/dist/app.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -14,17 +14,18 @@ A platform for storing and organising information and documentation. Details for
* [Documentation](https://www.bookstackapp.com/docs)
* [Demo Instance](https://demo.bookstackapp.com)
* [Admin Login](https://demo.bookstackapp.com/login?email=admin@example.com&password=password)
* [Screenshots](https://www.bookstackapp.com/#screenshots)
* [BookStack Blog](https://www.bookstackapp.com/blog)
* [Issue List](https://github.com/BookStackApp/BookStack/issues)
* [Discord Chat](https://discord.gg/ztkBqR2)
## 📚 Project Definition
BookStack is an opinionated wiki system that provides a pleasant and simple out of the box experience. New users to an instance should find the experience intuitive and only basic word-processing skills should be required to get involved in creating content on BookStack. The platform should provide advanced power features to those that desire it but they should not interfere with the core simple user experience.
BookStack is an opinionated wiki system that provides a pleasant and simple out-of-the-box experience. New users to an instance should find the experience intuitive and only basic word-processing skills should be required to get involved in creating content on BookStack. The platform should provide advanced power features to those that desire it but they should not interfere with the core simple user experience.
BookStack is not designed as an extensible platform to be used for purposes that differ to the statement above.
In regards to development philosophy, BookStack has a relaxed, open & positive approach. At the end of the day this is free software developed and maintained by people donating their own free time.
In regard to development philosophy, BookStack has a relaxed, open & positive approach. At the end of the day this is free software developed and maintained by people donating their own free time.
## 🛣️ Road Map
@@ -41,17 +42,23 @@ Below is a high-level road map view for BookStack to provide a sense of directio
## 🚀 Release Versioning & Process
BookStack releases are each assigned a version number, such as "v0.25.2", in the format `v<phase>.<feature>.<patch>`. A change only in the `patch` number indicates a fairly minor release that mainly contains fixes and therefore is very unlikely to cause breakages upon update. A change in the `feature` number indicates a release which will generally bring new features in addition to fixes and enhancements. These releases have a small chance of introducing breaking changes upon update so it's worth checking for any notes in the [update guide](https://www.bookstackapp.com/docs/admin/updates/). A change in the `phase` indicates a much large change in BookStack that will likely incur breakages requiring manual intervention.
BookStack releases are each assigned a date-based version number in the format `v<year>.<month>[.<optional_patch_number>]`. For example:
- `v20.12` - New feature released launched during December 2020.
- `v21.06.2` - Second patch release upon the June 2021 feature release.
Patch releases are generally fairly minor, primarily intended for fixes and therefore is fairly unlikely to cause breakages upon update.
Feature releases are generally larger, bringing new features in addition to fixes and enhancements. These releases have a greater chance of introducing breaking changes upon update, so it's worth checking for any notes in the [update guide](https://www.bookstackapp.com/docs/admin/updates/).
Each BookStack release will have a [milestone](https://github.com/BookStackApp/BookStack/milestones) created with issues & pull requests assigned to it to define what will be in that release. Milestones are built up then worked through until complete at which point, after some testing and documentation updates, the release will be deployed.
For feature releases, and some patch releases, the release will be accompanied by a post on the [BookStack blog](https://www.bookstackapp.com/blog/) which will provide additional detail on features, changes & updates otherwise the [GitHub release page](https://github.com/BookStackApp/BookStack/releases) will show a list of changes. You can sign up to be alerted to new BookStack blogs posts (once per week maximum) [at this link](https://updates.bookstackapp.com/signup/bookstack-news-and-updates).
Feature releases, and some patch releases, will be accompanied by a post on the [BookStack blog](https://www.bookstackapp.com/blog/) which will provide additional detail on features, changes & updates otherwise the [GitHub release page](https://github.com/BookStackApp/BookStack/releases) will show a list of changes. You can sign up to be alerted to new BookStack blogs posts (once per week maximum) [at this link](https://updates.bookstackapp.com/signup/bookstack-news-and-updates).
## 🛠️ Development & Testing
All development on BookStack is currently done on the master branch. When it's time for a release the master branch is merged into release with built & minified CSS & JS then tagged at its version. Here are the current development requirements:
* [Node.js](https://nodejs.org/en/) v12.0+
* [Node.js](https://nodejs.org/en/) v14.0+
This project uses SASS for CSS development and this is built, along with the JavaScript, using a range of npm scripts. The below npm commands can be used to install the dependencies & run the build tasks:

View File

@@ -40,6 +40,7 @@ class PageEditor {
frequency: 30000,
last: 0,
};
this.shownWarningsCache = new Set();
if (this.pageId !== 0 && this.draftsEnabled) {
window.setTimeout(() => {
@@ -119,6 +120,10 @@ class PageEditor {
}
this.draftNotifyChange(`${resp.data.message} ${Dates.utcTimeStampToLocalTime(resp.data.timestamp)}`);
this.autoSave.last = Date.now();
if (resp.data.warning && !this.shownWarningsCache.has(resp.data.warning)) {
window.$events.emit('warning', resp.data.warning);
this.shownWarningsCache.add(resp.data.warning);
}
} catch (err) {
// Save the editor content in LocalStorage as a last resort, just in case.
try {

View File

@@ -234,6 +234,7 @@ return [
'pages_initial_name' => 'صفحة جديدة',
'pages_editing_draft_notification' => 'جارٍ تعديل مسودة لم يتم حفظها من :timeDiff.',
'pages_draft_edited_notification' => 'تم تحديث هذه الصفحة منذ ذلك الوقت. من الأفضل التخلص من هذه المسودة.',
'pages_draft_page_changed_since_creation' => 'This page has been updated since this draft was created. It is recommended that you discard this draft or take care not to overwrite any page changes.',
'pages_draft_edit_active' => [
'start_a' => ':count من المستخدمين بدأوا بتعديل هذه الصفحة',
'start_b' => ':userName بدأ بتعديل هذه الصفحة',

View File

@@ -119,6 +119,7 @@ return [
'audit_table_user' => 'المستخدم',
'audit_table_event' => 'الحدث',
'audit_table_related' => 'العنصر أو التفاصيل ذات الصلة',
'audit_table_ip' => 'IP Address',
'audit_table_date' => 'تاريخ النشاط',
'audit_date_from' => 'نطاق التاريخ من',
'audit_date_to' => 'نطاق التاريخ إلى',

View File

@@ -234,6 +234,7 @@ return [
'pages_initial_name' => 'Нова страница',
'pages_editing_draft_notification' => 'В момента редактирате чернова, която беше последно обновена :timeDiff.',
'pages_draft_edited_notification' => 'Тази страница беше актуализирана от тогава. Препоръчително е да изтриете настоящата чернова.',
'pages_draft_page_changed_since_creation' => 'This page has been updated since this draft was created. It is recommended that you discard this draft or take care not to overwrite any page changes.',
'pages_draft_edit_active' => [
'start_a' => ':count потребителя започнаха да редактират настоящата страница',
'start_b' => ':userName в момента редактира тази страница',

View File

@@ -119,6 +119,7 @@ return [
'audit_table_user' => 'Потребител',
'audit_table_event' => 'Събитие',
'audit_table_related' => 'Related Item or Detail',
'audit_table_ip' => 'IP Address',
'audit_table_date' => 'Дата на активност',
'audit_date_from' => 'Време от',
'audit_date_to' => 'Време до',

View File

@@ -234,6 +234,7 @@ return [
'pages_initial_name' => 'Nova stranica',
'pages_editing_draft_notification' => 'Trenutno uređujete skicu koja je posljednji put snimljena :timeDiff.',
'pages_draft_edited_notification' => 'Ova stranica je ažurirana nakon tog vremena. Preporučujemo da odbacite ovu skicu.',
'pages_draft_page_changed_since_creation' => 'This page has been updated since this draft was created. It is recommended that you discard this draft or take care not to overwrite any page changes.',
'pages_draft_edit_active' => [
'start_a' => ':count korisnika je počelo sa uređivanjem ove stranice',
'start_b' => ':userName je počeo/la sa uređivanjem ove stranice',

View File

@@ -119,6 +119,7 @@ return [
'audit_table_user' => 'User',
'audit_table_event' => 'Event',
'audit_table_related' => 'Related Item or Detail',
'audit_table_ip' => 'IP Address',
'audit_table_date' => 'Activity Date',
'audit_date_from' => 'Date Range From',
'audit_date_to' => 'Date Range To',

View File

@@ -234,6 +234,7 @@ return [
'pages_initial_name' => 'Pàgina nova',
'pages_editing_draft_notification' => 'Esteu editant un esborrany que es va desar per darrer cop :timeDiff.',
'pages_draft_edited_notification' => 'Aquesta pàgina s\'ha actualitzat d\'ençà d\'aleshores. Us recomanem que descarteu aquest esborrany.',
'pages_draft_page_changed_since_creation' => 'This page has been updated since this draft was created. It is recommended that you discard this draft or take care not to overwrite any page changes.',
'pages_draft_edit_active' => [
'start_a' => ':count usuaris han començat a editar aquesta pàgina',
'start_b' => ':userName ha començat a editar aquesta pàgina',

View File

@@ -119,6 +119,7 @@ return [
'audit_table_user' => 'Usuari',
'audit_table_event' => 'Esdeveniment',
'audit_table_related' => 'Element relacionat o detall',
'audit_table_ip' => 'IP Address',
'audit_table_date' => 'Data de l\'activitat',
'audit_date_from' => 'Rang de dates a partir de',
'audit_date_to' => 'Rang de rates fins a',

View File

@@ -48,8 +48,8 @@ return [
'favourite_remove_notification' => '":name" byla odstraněna z Vašich oblíbených',
// MFA
'mfa_setup_method_notification' => 'Multi-factor method successfully configured',
'mfa_remove_method_notification' => 'Multi-factor method successfully removed',
'mfa_setup_method_notification' => 'Vícefaktorová metoda byla úspěšně nakonfigurována',
'mfa_remove_method_notification' => 'Vícefaktorová metoda byla úspěšně odstraněna',
// Other
'commented_on' => 'okomentoval/a',

View File

@@ -83,16 +83,16 @@ return [
'mfa_setup_remove_confirmation' => 'Are you sure you want to remove this multi-factor authentication method?',
'mfa_setup_action' => 'Setup',
'mfa_backup_codes_usage_limit_warning' => 'You have less than 5 backup codes remaining, Please generate and store a new set before you run out of codes to prevent being locked out of your account.',
'mfa_option_totp_title' => 'Mobile App',
'mfa_option_totp_title' => 'Mobilní aplikace',
'mfa_option_totp_desc' => 'To use multi-factor authentication you\'ll need a mobile application that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator.',
'mfa_option_backup_codes_title' => 'Backup Codes',
'mfa_option_backup_codes_desc' => 'Securely store a set of one-time-use backup codes which you can enter to verify your identity.',
'mfa_gen_confirm_and_enable' => 'Confirm and Enable',
'mfa_gen_confirm_and_enable' => 'Potvrdit a povolit',
'mfa_gen_backup_codes_title' => 'Backup Codes Setup',
'mfa_gen_backup_codes_desc' => 'Store the below list of codes in a safe place. When accessing the system you\'ll be able to use one of the codes as a second authentication mechanism.',
'mfa_gen_backup_codes_download' => 'Download Codes',
'mfa_gen_backup_codes_usage_warning' => 'Each code can only be used once',
'mfa_gen_totp_title' => 'Mobile App Setup',
'mfa_gen_totp_title' => 'Nastavení mobilní aplikace',
'mfa_gen_totp_desc' => 'To use multi-factor authentication you\'ll need a mobile application that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator.',
'mfa_gen_totp_scan' => 'Scan the QR code below using your preferred authentication app to get started.',
'mfa_gen_totp_verify_setup' => 'Verify Setup',

View File

@@ -39,7 +39,7 @@ return [
'reset' => 'Obnovit',
'remove' => 'Odebrat',
'add' => 'Přidat',
'configure' => 'Configure',
'configure' => 'Nastavit',
'fullscreen' => 'Celá obrazovka',
'favourite' => 'Přidat do oblíbených',
'unfavourite' => 'Odebrat z oblíbených',

View File

@@ -99,7 +99,7 @@ return [
'shelves_permissions' => 'Oprávnění knihovny',
'shelves_permissions_updated' => 'Oprávnění knihovny byla aktualizována',
'shelves_permissions_active' => 'Oprávnění knihovny byla aktivována',
'shelves_permissions_cascade_warning' => 'Permissions on bookshelves do not automatically cascade to contained books. This is because a book can exist on multiple shelves. Permissions can however be copied down to child books using the option found below.',
'shelves_permissions_cascade_warning' => 'Oprávnění v Knihovnách nejsou automaticky kaskádována do obsažených knih. To proto, že kniha může existovat ve více Knihovnách. Oprávnění však lze zkopírovat do podřízených knih pomocí níže uvedené možnosti.',
'shelves_copy_permissions_to_books' => 'Kopírovat oprávnění na knihy',
'shelves_copy_permissions' => 'Kopírovat oprávnění',
'shelves_copy_permissions_explain' => 'Toto použije aktuální nastavení oprávnění knihovny na všechny knihy v ní obsažené. Před aktivací se ujistěte, že byly uloženy všechny změny oprávnění této knihovny.',
@@ -234,6 +234,7 @@ return [
'pages_initial_name' => 'Nová stránka',
'pages_editing_draft_notification' => 'Právě upravujete koncept, který byl uložen před :timeDiff.',
'pages_draft_edited_notification' => 'Tato stránka se od té doby změnila. Je doporučeno aktuální koncept zahodit.',
'pages_draft_page_changed_since_creation' => 'Tato stránka byla aktualizována od vytvoření tohoto konceptu. Doporučuje se zrušit tento koncept nebo se postarat o to, abyste si nepřepsali žádné již zadané změny.',
'pages_draft_edit_active' => [
'start_a' => 'Uživatelé začali upravovat tuto stránku (celkem :count)',
'start_b' => ':userName začal/a upravovat tuto stránku',

View File

@@ -119,6 +119,7 @@ return [
'audit_table_user' => 'Uživatel',
'audit_table_event' => 'Událost',
'audit_table_related' => 'Související položka nebo detail',
'audit_table_ip' => 'IP adresa',
'audit_table_date' => 'Datum aktivity',
'audit_date_from' => 'Časový rozsah od',
'audit_date_to' => 'Časový rozsah do',
@@ -138,7 +139,7 @@ return [
'role_details' => 'Detaily role',
'role_name' => 'Název role',
'role_desc' => 'Stručný popis role',
'role_mfa_enforced' => 'Requires Multi-Factor Authentication',
'role_mfa_enforced' => 'Vyžaduje Vícefaktorové ověření',
'role_external_auth_id' => 'Přihlašovací identifikátory třetích stran',
'role_system' => 'Systémová oprávnění',
'role_manage_users' => 'Správa uživatelů',
@@ -148,7 +149,7 @@ return [
'role_manage_page_templates' => 'Správa šablon stránek',
'role_access_api' => 'Přístup k systémovému API',
'role_manage_settings' => 'Správa nastavení aplikace',
'role_export_content' => 'Export content',
'role_export_content' => 'Exportovat obsah',
'role_asset' => 'Obsahová oprávnění',
'roles_system_warning' => 'Berte na vědomí, že přístup k některému ze tří výše uvedených oprávnění může uživateli umožnit změnit svá vlastní oprávnění nebo oprávnění ostatních uživatelů v systému. Přiřazujte role s těmito oprávněními pouze důvěryhodným uživatelům.',
'role_asset_desc' => 'Tato oprávnění řídí přístup k obsahu napříč systémem. Specifická oprávnění na knihách, kapitolách a stránkách převáží tato nastavení.',
@@ -206,10 +207,10 @@ return [
'users_api_tokens_create' => 'Vytvořit Token',
'users_api_tokens_expires' => 'Vyprší',
'users_api_tokens_docs' => 'API Dokumentace',
'users_mfa' => 'Multi-Factor Authentication',
'users_mfa_desc' => 'Setup multi-factor authentication as an extra layer of security for your user account.',
'users_mfa' => 'Vícefázové ověření',
'users_mfa_desc' => 'Nastavit vícefaktorové ověřování jako další vrstvu zabezpečení vašeho uživatelského účtu.',
'users_mfa_x_methods' => ':count method configured|:count methods configured',
'users_mfa_configure' => 'Configure Methods',
'users_mfa_configure' => 'Konfigurovat metody',
// API Tokens
'user_api_token_create' => 'Vytvořit API Token',

View File

@@ -15,7 +15,7 @@ return [
'alpha_dash' => ':attribute může obsahovat pouze písmena, číslice, pomlčky a podtržítka. České znaky (á, é, í, ó, ú, ů, ž, š, č, ř, ď, ť, ň) nejsou podporovány.',
'alpha_num' => ':attribute může obsahovat pouze písmena a číslice.',
'array' => ':attribute musí být pole.',
'backup_codes' => 'The provided code is not valid or has already been used.',
'backup_codes' => 'Zadaný kód není platný nebo již byl použit.',
'before' => ':attribute musí být datum před :date.',
'between' => [
'numeric' => ':attribute musí být hodnota mezi :min a :max.',
@@ -99,7 +99,7 @@ return [
],
'string' => ':attribute musí být řetězec znaků.',
'timezone' => ':attribute musí být platná časová zóna.',
'totp' => 'The provided code is not valid or has expired.',
'totp' => 'Zadaný kód je neplatný nebo vypršel.',
'unique' => ':attribute musí být unikátní.',
'url' => 'Formát :attribute je neplatný.',
'uploaded' => 'Nahrávání :attribute se nezdařilo.',

View File

@@ -44,12 +44,12 @@ return [
'bookshelf_delete_notification' => 'Bogreolen blev opdateret',
// Favourites
'favourite_add_notification' => '":name" has been added to your favourites',
'favourite_remove_notification' => '":name" has been removed from your favourites',
'favourite_add_notification' => '":name" er blevet tilføjet til dine favoritter',
'favourite_remove_notification' => '":name" er blevet fjernet fra dine favoritter',
// MFA
'mfa_setup_method_notification' => 'Multi-factor method successfully configured',
'mfa_remove_method_notification' => 'Multi-factor method successfully removed',
'mfa_setup_method_notification' => 'Multi-faktor metode konfigureret',
'mfa_remove_method_notification' => 'Multi-faktor metode fjernet',
// Other
'commented_on' => 'kommenterede til',

View File

@@ -76,19 +76,19 @@ return [
'user_invite_success' => 'Adgangskode indstillet, du har nu adgang til :appName!',
// Multi-factor Authentication
'mfa_setup' => 'Setup Multi-Factor Authentication',
'mfa_setup_desc' => 'Setup multi-factor authentication as an extra layer of security for your user account.',
'mfa_setup_configured' => 'Already configured',
'mfa_setup_reconfigure' => 'Reconfigure',
'mfa_setup_remove_confirmation' => 'Are you sure you want to remove this multi-factor authentication method?',
'mfa_setup_action' => 'Setup',
'mfa_backup_codes_usage_limit_warning' => 'You have less than 5 backup codes remaining, Please generate and store a new set before you run out of codes to prevent being locked out of your account.',
'mfa_option_totp_title' => 'Mobile App',
'mfa_option_totp_desc' => 'To use multi-factor authentication you\'ll need a mobile application that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator.',
'mfa_option_backup_codes_title' => 'Backup Codes',
'mfa_option_backup_codes_desc' => 'Securely store a set of one-time-use backup codes which you can enter to verify your identity.',
'mfa_gen_confirm_and_enable' => 'Confirm and Enable',
'mfa_gen_backup_codes_title' => 'Backup Codes Setup',
'mfa_setup' => 'Opsætning af Multi-faktor godkendelse',
'mfa_setup_desc' => 'Opsæt multi-faktor godkendelse som et ekstra lag af sikkerhed for din brugerkonto.',
'mfa_setup_configured' => 'Allerede konfigureret',
'mfa_setup_reconfigure' => 'Genkonfigurer',
'mfa_setup_remove_confirmation' => 'Er du sikker på, at du vil fjerne denne multi-faktor godkendelsesmetode?',
'mfa_setup_action' => 'Opsætning',
'mfa_backup_codes_usage_limit_warning' => 'Du har mindre end 5 backup koder tilbage, generere og gem et nyt sæt før du løber tør for koder, for at forhindre at blive lukket ude af din konto.',
'mfa_option_totp_title' => 'Mobil app',
'mfa_option_totp_desc' => 'For at bruge multi-faktor godkendelse, skal du bruge en mobil app, der understøtter TOTP såsom Google Authenticator, Authy eller Microsoft Authenticator.',
'mfa_option_backup_codes_title' => 'Backup koder',
'mfa_option_backup_codes_desc' => 'Gem sikkert et sæt af engangs backup koder, som du kan indtaste for at bekræfte din identitet.',
'mfa_gen_confirm_and_enable' => 'Bekræft og aktivér',
'mfa_gen_backup_codes_title' => 'Backup koder opsætning',
'mfa_gen_backup_codes_desc' => 'Store the below list of codes in a safe place. When accessing the system you\'ll be able to use one of the codes as a second authentication mechanism.',
'mfa_gen_backup_codes_download' => 'Download Codes',
'mfa_gen_backup_codes_usage_warning' => 'Each code can only be used once',

View File

@@ -39,12 +39,12 @@ return [
'reset' => 'Nulstil',
'remove' => 'Fjern',
'add' => 'Tilføj',
'configure' => 'Configure',
'configure' => 'Konfigurer',
'fullscreen' => 'Fuld skærm',
'favourite' => 'Favourite',
'unfavourite' => 'Unfavourite',
'next' => 'Next',
'previous' => 'Previous',
'favourite' => 'Foretrukken',
'unfavourite' => 'Fjern som foretrukken',
'next' => 'Næste',
'previous' => 'Forrige',
// Sort Options
'sort_options' => 'Sorteringsindstillinger',
@@ -61,7 +61,7 @@ return [
'no_activity' => 'Ingen aktivitet at vise',
'no_items' => 'Intet indhold tilgængeligt',
'back_to_top' => 'Tilbage til toppen',
'skip_to_main_content' => 'Skip to main content',
'skip_to_main_content' => 'Spring til indhold',
'toggle_details' => 'Vis/skjul detaljer',
'toggle_thumbnails' => 'Vis/skjul miniaturer',
'details' => 'Detaljer',

View File

@@ -27,8 +27,8 @@ return [
'images' => 'Billeder',
'my_recent_drafts' => 'Mine seneste kladder',
'my_recently_viewed' => 'Mine senest viste',
'my_most_viewed_favourites' => 'My Most Viewed Favourites',
'my_favourites' => 'My Favourites',
'my_most_viewed_favourites' => 'Mine mest viste favoritter',
'my_favourites' => 'Mine favoritter',
'no_pages_viewed' => 'Du har ikke besøgt nogle sider',
'no_pages_recently_created' => 'Ingen sider er blevet oprettet for nyligt',
'no_pages_recently_updated' => 'Ingen sider er blevet opdateret for nyligt',
@@ -36,7 +36,7 @@ return [
'export_html' => 'Indeholdt webfil',
'export_pdf' => 'PDF-fil',
'export_text' => 'Almindelig tekstfil',
'export_md' => 'Markdown File',
'export_md' => 'Markdown Fil',
// Permissions and restrictions
'permissions' => 'Rettigheder',
@@ -99,7 +99,7 @@ return [
'shelves_permissions' => 'Reoltilladelser',
'shelves_permissions_updated' => 'Reoltilladelser opdateret',
'shelves_permissions_active' => 'Aktive reoltilladelser',
'shelves_permissions_cascade_warning' => 'Permissions on bookshelves do not automatically cascade to contained books. This is because a book can exist on multiple shelves. Permissions can however be copied down to child books using the option found below.',
'shelves_permissions_cascade_warning' => 'Tilladelser på reoler nedarves ikke automatisk til indeholdte bøger. Dette skyldes, at en bog kan eksistere på flere hylder. Tilladelser kan dog kopieres ned til underliggende bøger ved hjælp af muligheden, der findes nedenfor.',
'shelves_copy_permissions_to_books' => 'Kopier tilladelser til bøger',
'shelves_copy_permissions' => 'Kopier tilladelser',
'shelves_copy_permissions_explain' => 'Dette vil anvende de aktuelle tilladelsesindstillinger på denne boghylde på alle bøger indeholdt i. Før aktivering skal du sikre dig, at ændringer i tilladelserne til denne boghylde er blevet gemt.',
@@ -234,6 +234,7 @@ return [
'pages_initial_name' => 'Ny side',
'pages_editing_draft_notification' => 'Du redigerer en kladde der sidst var gemt :timeDiff.',
'pages_draft_edited_notification' => 'Siden har været opdateret siden da. Det er anbefalet at du kasserer denne kladde.',
'pages_draft_page_changed_since_creation' => 'This page has been updated since this draft was created. It is recommended that you discard this draft or take care not to overwrite any page changes.',
'pages_draft_edit_active' => [
'start_a' => ':count brugerer har begyndt at redigere denne side',
'start_b' => ':userName er begyndt at redigere denne side',

View File

@@ -83,9 +83,9 @@ return [
'404_page_not_found' => 'Siden blev ikke fundet',
'sorry_page_not_found' => 'Beklager, siden du leder efter blev ikke fundet.',
'sorry_page_not_found_permission_warning' => 'Hvis du forventede, at denne side skulle eksistere, har du muligvis ikke tilladelse til at se den.',
'image_not_found' => 'Image Not Found',
'image_not_found_subtitle' => 'Sorry, The image file you were looking for could not be found.',
'image_not_found_details' => 'If you expected this image to exist it might have been deleted.',
'image_not_found' => 'Billede ikke fundet',
'image_not_found_subtitle' => 'Beklager, billedet du ledte efter kunne ikke findes.',
'image_not_found_details' => 'Hvis du forventede, at dette billede skulle eksistere, kan det være blevet slettet.',
'return_home' => 'Gå tilbage til hjem',
'error_occurred' => 'Der opstod en fejl',
'app_down' => ':appName er nede lige nu',

View File

@@ -92,7 +92,7 @@ return [
'recycle_bin' => 'Papirkurv',
'recycle_bin_desc' => 'Her kan du gendanne elementer, der er blevet slettet eller vælge at permanent fjerne dem fra systemet. Denne liste er ufiltreret, i modsætning til lignende aktivitetslister i systemet, hvor tilladelsesfiltre anvendes.',
'recycle_bin_deleted_item' => 'Slettet element',
'recycle_bin_deleted_parent' => 'Parent',
'recycle_bin_deleted_parent' => 'Overordnet',
'recycle_bin_deleted_by' => 'Slettet af',
'recycle_bin_deleted_at' => 'Sletningstidspunkt',
'recycle_bin_permanently_delete' => 'Slet permanent',
@@ -105,7 +105,7 @@ return [
'recycle_bin_restore_list' => 'Elementer der skal gendannes',
'recycle_bin_restore_confirm' => 'Denne handling vil gendanne det slettede element, herunder alle underelementer, til deres oprindelige placering. Hvis den oprindelige placering siden er blevet slettet, og nu er i papirkurven, vil det overordnede element også skulle gendannes.',
'recycle_bin_restore_deleted_parent' => 'Det overordnede element til dette element er også blevet slettet. Disse vil forblive slettet indtil det overordnede også er gendannet.',
'recycle_bin_restore_parent' => 'Restore Parent',
'recycle_bin_restore_parent' => 'Gendan Overordnet',
'recycle_bin_destroy_notification' => 'Slettede :count elementer fra papirkurven.',
'recycle_bin_restore_notification' => 'Gendannede :count elementer fra papirkurven.',
@@ -119,6 +119,7 @@ return [
'audit_table_user' => 'Bruger',
'audit_table_event' => 'Hændelse',
'audit_table_related' => 'Relateret element eller detalje',
'audit_table_ip' => 'IP Address',
'audit_table_date' => 'Aktivitetsdato',
'audit_date_from' => 'Datointerval fra',
'audit_date_to' => 'Datointerval til',
@@ -138,7 +139,7 @@ return [
'role_details' => 'Rolledetaljer',
'role_name' => 'Rollenavn',
'role_desc' => 'Kort beskrivelse af rolle',
'role_mfa_enforced' => 'Requires Multi-Factor Authentication',
'role_mfa_enforced' => 'Kræver multifaktor godkendelse',
'role_external_auth_id' => 'Eksterne godkendelses-IDer',
'role_system' => 'Systemtilladelser',
'role_manage_users' => 'Administrere brugere',
@@ -148,7 +149,7 @@ return [
'role_manage_page_templates' => 'Administrer side-skabeloner',
'role_access_api' => 'Tilgå system-API',
'role_manage_settings' => 'Administrer app-indstillinger',
'role_export_content' => 'Export content',
'role_export_content' => 'Eksporter indhold',
'role_asset' => 'Tilladelser for medier og "assets"',
'roles_system_warning' => 'Vær opmærksom på, at adgang til alle af de ovennævnte tre tilladelser, kan give en bruger mulighed for at ændre deres egne brugerrettigheder eller brugerrettigheder for andre i systemet. Tildel kun roller med disse tilladelser til betroede brugere.',
'role_asset_desc' => 'Disse tilladelser kontrollerer standardadgang til medier og "assets" i systemet. Tilladelser til bøger, kapitler og sider tilsidesætter disse tilladelser.',
@@ -206,10 +207,10 @@ return [
'users_api_tokens_create' => 'Opret Token',
'users_api_tokens_expires' => 'Udløber',
'users_api_tokens_docs' => 'API-dokumentation',
'users_mfa' => 'Multi-Factor Authentication',
'users_mfa_desc' => 'Setup multi-factor authentication as an extra layer of security for your user account.',
'users_mfa_x_methods' => ':count method configured|:count methods configured',
'users_mfa_configure' => 'Configure Methods',
'users_mfa' => 'Multi-faktor godkendelse',
'users_mfa_desc' => 'Opsæt multi-faktor godkendelse som et ekstra lag af sikkerhed for din brugerkonto.',
'users_mfa_x_methods' => ':count metode konfigureret|:count metoder konfigureret',
'users_mfa_configure' => 'Konfigurer metoder',
// API Tokens
'user_api_token_create' => 'Opret API-token',

View File

@@ -15,7 +15,7 @@ return [
'alpha_dash' => ':attribute må kun bestå af bogstaver, tal, binde- og under-streger.',
'alpha_num' => ':attribute må kun indeholde bogstaver og tal.',
'array' => ':attribute skal være et array.',
'backup_codes' => 'The provided code is not valid or has already been used.',
'backup_codes' => 'Den angivne kode er ikke gyldig eller er allerede brugt.',
'before' => ':attribute skal være en dato før :date.',
'between' => [
'numeric' => ':attribute skal være mellem :min og :max.',
@@ -99,7 +99,7 @@ return [
],
'string' => ':attribute skal være tekst.',
'timezone' => ':attribute skal være en gyldig zone.',
'totp' => 'The provided code is not valid or has expired.',
'totp' => 'Den angivne kode er ikke gyldig eller er udløbet.',
'unique' => ':attribute er allerede i brug.',
'url' => ':attribute-formatet er ugyldigt.',
'uploaded' => 'Filen kunne ikke oploades. Serveren accepterer muligvis ikke filer af denne størrelse.',

View File

@@ -33,7 +33,7 @@ return [
'copy' => 'Kopieren',
'reply' => 'Antworten',
'delete' => 'Löschen',
'delete_confirm' => 'Löschen Bestätigen',
'delete_confirm' => 'Löschen bestätigen',
'search' => 'Suchen',
'search_clear' => 'Suche löschen',
'reset' => 'Zurücksetzen',
@@ -41,7 +41,7 @@ return [
'add' => 'Hinzufügen',
'configure' => 'Konfigurieren',
'fullscreen' => 'Vollbild',
'favourite' => 'Favorit',
'favourite' => 'Favoriten',
'unfavourite' => 'Kein Favorit',
'next' => 'Nächste',
'previous' => 'Vorheriges',
@@ -57,9 +57,9 @@ return [
'sort_updated_at' => 'Aktualisierungsdatum',
// Misc
'deleted_user' => 'Gelöschte Benutzer',
'deleted_user' => 'Gelöschter Benutzer',
'no_activity' => 'Keine Aktivitäten zum Anzeigen',
'no_items' => 'Keine Einträge gefunden.',
'no_items' => 'Keine Einträge gefunden',
'back_to_top' => 'nach oben',
'skip_to_main_content' => 'Direkt zum Hauptinhalt',
'toggle_details' => 'Details zeigen/verstecken',

View File

@@ -99,7 +99,7 @@ return [
'shelves_permissions' => 'Regal-Berechtigungen',
'shelves_permissions_updated' => 'Regal-Berechtigungen aktualisiert',
'shelves_permissions_active' => 'Regal-Berechtigungen aktiv',
'shelves_permissions_cascade_warning' => 'Permissions on bookshelves do not automatically cascade to contained books. This is because a book can exist on multiple shelves. Permissions can however be copied down to child books using the option found below.',
'shelves_permissions_cascade_warning' => 'Die Berechtigungen in Bücherregalen werden nicht automatisch auf enthaltene Bücher kaskadiert, weil ein Buch in mehreren Regalen existieren kann. Berechtigungen können jedoch mit der unten stehenden Option in untergeordnete Bücher kopiert werden.',
'shelves_copy_permissions_to_books' => 'Kopiere die Berechtigungen zum Buch',
'shelves_copy_permissions' => 'Berechtigungen kopieren',
'shelves_copy_permissions_explain' => 'Hiermit werden die Berechtigungen des aktuellen Regals auf alle enthaltenen Bücher übertragen. Überprüfen Sie vor der Aktivierung, ob alle Berechtigungsänderungen am aktuellen Regal gespeichert wurden.',
@@ -234,6 +234,7 @@ return [
'pages_initial_name' => 'Neue Seite',
'pages_editing_draft_notification' => 'Sie bearbeiten momenten einen Entwurf, der zuletzt :timeDiff gespeichert wurde.',
'pages_draft_edited_notification' => 'Diese Seite wurde seit diesem Zeitpunkt verändert. Wir empfehlen Ihnen, diesen Entwurf zu verwerfen.',
'pages_draft_page_changed_since_creation' => 'This page has been updated since this draft was created. It is recommended that you discard this draft or take care not to overwrite any page changes.',
'pages_draft_edit_active' => [
'start_a' => ':count Benutzer bearbeiten derzeit diese Seite.',
'start_b' => ':userName bearbeitet jetzt diese Seite.',

View File

@@ -5,7 +5,7 @@
return [
// Permissions
'permission' => 'Sie haben keine Berechtigung, auf diese Seite zuzugreifen.',
'permission' => 'Sie haben keine Zugriffsberechtigung auf die angeforderte Seite.',
'permissionJson' => 'Sie haben keine Berechtigung, die angeforderte Aktion auszuführen.',
// Auth
@@ -14,7 +14,7 @@ return [
'email_confirmation_invalid' => 'Der Bestätigungslink ist nicht gültig oder wurde bereits verwendet. Bitte registrieren Sie sich erneut.',
'email_confirmation_expired' => 'Der Bestätigungslink ist abgelaufen. Es wurde eine neue Bestätigungs-E-Mail gesendet.',
'email_confirmation_awaiting' => 'Die E-Mail-Adresse für das verwendete Konto muss bestätigt werden',
'ldap_fail_anonymous' => 'Anonymer LDAP-Zugriff ist fehlgeschlafgen',
'ldap_fail_anonymous' => 'Anonymer LDAP-Zugriff ist fehlgeschlagen',
'ldap_fail_authed' => 'LDAP-Zugriff mit DN und Passwort ist fehlgeschlagen',
'ldap_extension_not_installed' => 'LDAP-PHP-Erweiterung ist nicht installiert.',
'ldap_cannot_connect' => 'Die Verbindung zum LDAP-Server ist fehlgeschlagen. Beim initialen Verbindungsaufbau trat ein Fehler auf.',
@@ -43,14 +43,14 @@ return [
'uploaded' => 'Der Server verbietet das Hochladen von Dateien mit dieser Dateigröße. Bitte versuchen Sie es mit einer kleineren Datei.',
'image_upload_error' => 'Beim Hochladen des Bildes trat ein Fehler auf.',
'image_upload_type_error' => 'Der Bildtyp der hochgeladenen Datei ist ungültig.',
'file_upload_timeout' => 'Der Upload der Datei ist abgelaufen.',
'file_upload_timeout' => 'Der Datei-Upload hat das Zeitlimit überschritten.',
// Attachments
'attachment_not_found' => 'Anhang konnte nicht gefunden werden.',
// Pages
'page_draft_autosave_fail' => 'Fehler beim Speichern des Entwurfs. Stellen Sie sicher, dass Sie mit dem Internet verbunden sind, bevor Sie den Entwurf dieser Seite speichern.',
'page_custom_home_deletion' => 'Eine als Startseite gesetzte Seite kann nicht gelöscht werden.',
'page_custom_home_deletion' => 'Eine als Startseite gesetzte Seite kann nicht gelöscht werden',
// Entities
'entity_not_found' => 'Eintrag nicht gefunden',
@@ -58,48 +58,48 @@ return [
'book_not_found' => 'Buch nicht gefunden',
'page_not_found' => 'Seite nicht gefunden',
'chapter_not_found' => 'Kapitel nicht gefunden',
'selected_book_not_found' => 'Das gewählte Buch wurde nicht gefunden.',
'selected_book_not_found' => 'Das gewählte Buch wurde nicht gefunden',
'selected_book_chapter_not_found' => 'Das gewählte Buch oder Kapitel wurde nicht gefunden.',
'guests_cannot_save_drafts' => 'Gäste können keine Entwürfe speichern',
// Users
'users_cannot_delete_only_admin' => 'Sie können den einzigen Administrator nicht löschen.',
'users_cannot_delete_only_admin' => 'Sie können den einzigen Administrator nicht löschen',
'users_cannot_delete_guest' => 'Sie können den Gast-Benutzer nicht löschen',
// Roles
'role_cannot_be_edited' => 'Diese Rolle kann nicht bearbeitet werden.',
'role_cannot_be_edited' => 'Diese Rolle kann nicht bearbeitet werden',
'role_system_cannot_be_deleted' => 'Dies ist eine Systemrolle und kann nicht gelöscht werden',
'role_registration_default_cannot_delete' => 'Diese Rolle kann nicht gelöscht werden, solange sie als Standardrolle für neue Registrierungen gesetzt ist',
'role_cannot_remove_only_admin' => 'Dieser Benutzer ist der einzige Benutzer, welchem die Administratorrolle zugeordnet ist. Ordnen Sie die Administratorrolle einem anderen Benutzer zu, bevor Sie versuchen, sie hier zu entfernen.',
'role_cannot_remove_only_admin' => 'Dieser Benutzer ist der einzige Benutzer, welchem die Administratorrolle zugeordnet ist. Ordnen Sie die Administratorrolle einem anderen Benutzer zu bevor Sie versuchen sie hier zu entfernen.',
// Comments
'comment_list' => 'Beim Abrufen der Kommentare ist ein Fehler aufgetreten.',
'cannot_add_comment_to_draft' => 'Du kannst keine Kommentare zu einem Entwurf hinzufügen.',
'comment_add' => 'Beim Hinzufügen des Kommentars ist ein Fehler aufgetreten.',
'comment_delete' => 'Beim Löschen des Kommentars ist ein Fehler aufgetreten.',
'empty_comment' => 'Kann keinen leeren Kommentar hinzufügen',
'empty_comment' => 'Kann keinen leeren Kommentar hinzufügen.',
// Error pages
'404_page_not_found' => 'Seite nicht gefunden',
'sorry_page_not_found' => 'Entschuldigung. Die Seite, die Sie angefordert haben, wurde nicht gefunden.',
'sorry_page_not_found' => 'Entschuldigung. Die angeforderte Seite wurde nicht gefunden.',
'sorry_page_not_found_permission_warning' => 'Wenn Sie erwartet haben, dass diese Seite existiert, haben Sie möglicherweise nicht die Berechtigung, sie anzuzeigen.',
'image_not_found' => 'Bild nicht gefunden',
'image_not_found_subtitle' => 'Entschuldigung. Das Bild, die Sie angefordert haben, wurde nicht gefunden.',
'image_not_found_subtitle' => 'Entschuldigung. Das angeforderte Bild wurde nicht gefunden.',
'image_not_found_details' => 'Wenn Sie erwartet haben, dass dieses Bild existiert, könnte es gelöscht worden sein.',
'return_home' => 'Zurück zur Startseite',
'error_occurred' => 'Es ist ein Fehler aufgetreten',
'app_down' => ':appName befindet sich aktuell im Wartungsmodus.',
'app_down' => ':appName befindet sich aktuell im Wartungsmodus',
'back_soon' => 'Wir werden so schnell wie möglich wieder online sein.',
// API errors
'api_no_authorization_found' => 'Kein Autorisierungs-Token für die Anfrage gefunden',
'api_bad_authorization_format' => 'Ein Autorisierungs-Token wurde auf die Anfrage gefunden, aber das Format schien falsch zu sein',
'api_user_token_not_found' => 'Es wurde kein passender API-Token für den angegebenen Autorisierungs-Token gefunden',
'api_incorrect_token_secret' => 'Das für den angegebenen API-Token angegebene Kennwort ist falsch',
'api_user_no_api_permission' => 'Der Besitzer des verwendeten API-Token hat keine Berechtigung für API-Aufrufe',
'api_user_token_expired' => 'Das verwendete Autorisierungs-Token ist abgelaufen',
'api_no_authorization_found' => 'Kein Autorisierungstoken für die Anfrage gefunden',
'api_bad_authorization_format' => 'Ein Autorisierungstoken wurde auf die Anfrage gefunden, aber das Format schien falsch zu sein',
'api_user_token_not_found' => 'Es wurde kein passender API-Token für den angegebenen Autorisierungstoken gefunden',
'api_incorrect_token_secret' => 'Das Kennwort für das angegebene API-Token ist falsch',
'api_user_no_api_permission' => 'Der Besitzer des verwendeten API-Tokens hat keine Berechtigung für API-Aufrufe',
'api_user_token_expired' => 'Das verwendete Autorisierungstoken ist abgelaufen',
// Settings & Maintenance
'maintenance_test_email_failure' => 'Fehler beim Senden einer Test E-Mail:',
'maintenance_test_email_failure' => 'Fehler beim Versenden einer Test E-Mail:',
];

View File

@@ -18,7 +18,7 @@ return [
'app_name_desc' => 'Dieser Name wird im Header und in E-Mails angezeigt.',
'app_name_header' => 'Anwendungsname im Header anzeigen?',
'app_public_access' => 'Öffentlicher Zugriff',
'app_public_access_desc' => 'Wenn Sie diese Option aktivieren, können Besucher, die nicht angemeldet sind, auf Inhalte in Ihrer BookStack-Instanz zugreifen.',
'app_public_access_desc' => 'Wenn Sie diese Option aktivieren können Besucher, die nicht angemeldet sind, auf Inhalte in Ihrer BookStack-Instanz zugreifen.',
'app_public_access_desc_guest' => 'Der Zugang für öffentliche Besucher kann über den Benutzer "Guest" gesteuert werden.',
'app_public_access_toggle' => 'Öffentlichen Zugriff erlauben',
'app_public_viewing' => 'Öffentliche Ansicht erlauben?',
@@ -40,7 +40,7 @@ Wenn Sie nicht eingeben, wird die Anwendung auf die Standardfarbe zurückgesetzt
'app_homepage_desc' => 'Wählen Sie eine Seite als Startseite aus, die statt der Standardansicht angezeigt werden soll. Seitenberechtigungen werden für die ausgewählten Seiten ignoriert.',
'app_homepage_select' => 'Wählen Sie eine Seite aus',
'app_footer_links' => 'Fußzeilen-Links',
'app_footer_links_desc' => 'Fügen Sie Links hinzu, die innerhalb der Seitenfußzeile angezeigt werden. Diese werden am unteren Ende der meisten Seiten angezeigt, einschließlich derjenigen, die keinen Login benötigen. Sie können die Bezeichnung "trans::<key>" verwenden, um systemdefinierte Übersetzungen zu verwenden. Beispiel: Mit "trans::common.privacy_policy" wird der übersetzte Text "Privacy Policy" bereitgestellt, und "trans::common.terms_of_service" liefert den übersetzten Text "Terms of Service".',
'app_footer_links_desc' => 'Fügen Sie Links hinzu, die innerhalb der Seitenfußzeile angezeigt werden. Diese werden am unteren Ende der meisten Seiten angezeigt, einschließlich derjenigen, die keinen Login benötigen. Sie können die Bezeichnung "trans::<key>" verwenden, um systemdefinierte Übersetzungen zu verwenden. Beispiel: Mit "trans::common.privacy_policy" wird der übersetzte Text "Privacy Policy" bereitgestellt und "trans::common.terms_of_service" liefert den übersetzten Text "Terms of Service".',
'app_footer_links_label' => 'Link-Label',
'app_footer_links_url' => 'Link-URL',
'app_footer_links_add' => 'Fußzeilen-Link hinzufügen',
@@ -59,7 +59,7 @@ Wenn Sie nicht eingeben, wird die Anwendung auf die Standardfarbe zurückgesetzt
// Registration Settings
'reg_settings' => 'Registrierungseinstellungen',
'reg_enable' => 'Registrierung erlauben?',
'reg_enable' => 'Registrierung erlauben',
'reg_enable_toggle' => 'Registrierung erlauben',
'reg_enable_desc' => 'Wenn die Registrierung erlaubt ist, kann sich der Benutzer als Anwendungsbenutzer anmelden. Bei der Registrierung erhält er eine einzige, voreingestellte Benutzerrolle.',
'reg_default_role' => 'Standard-Benutzerrolle nach Registrierung',
@@ -108,7 +108,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung
'recycle_bin_restore_list' => 'Zu wiederherzustellende Elemente',
'recycle_bin_restore_confirm' => 'Mit dieser Aktion wird das gelöschte Element einschließlich aller untergeordneten Elemente an seinen ursprünglichen Ort wiederherstellen. Wenn der ursprüngliche Ort gelöscht wurde und sich nun im Papierkorb befindet, muss auch das übergeordnete Element wiederhergestellt werden.',
'recycle_bin_restore_deleted_parent' => 'Das übergeordnete Elements wurde ebenfalls gelöscht. Dieses Element wird weiterhin als gelöscht zählen, bis auch das übergeordnete Element wiederhergestellt wurde.',
'recycle_bin_restore_parent' => 'Elternteil wiederherstellen',
'recycle_bin_restore_parent' => 'Übergeordneter Eintrag wiederherstellen',
'recycle_bin_destroy_notification' => ':count Elemente wurden aus dem Papierkorb gelöscht.',
'recycle_bin_restore_notification' => ':count Elemente wurden aus dem Papierkorb wiederhergestellt.',
@@ -122,6 +122,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung
'audit_table_user' => 'Benutzer',
'audit_table_event' => 'Ereignis',
'audit_table_related' => 'Verknüpftes Element oder Detail',
'audit_table_ip' => 'IP Adresse',
'audit_table_date' => 'Aktivitätsdatum',
'audit_date_from' => 'Zeitraum von',
'audit_date_to' => 'Zeitraum bis',
@@ -151,7 +152,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung
'role_manage_page_templates' => 'Seitenvorlagen verwalten',
'role_access_api' => 'Systemzugriffs-API',
'role_manage_settings' => 'Globaleinstellungen verwalten',
'role_export_content' => 'Export content',
'role_export_content' => 'Inhalt exportieren',
'role_asset' => 'Berechtigungen',
'roles_system_warning' => 'Beachten Sie, dass der Zugriff auf eine der oben genannten drei Berechtigungen einem Benutzer erlauben kann, seine eigenen Berechtigungen oder die Rechte anderer im System zu ändern. Weisen Sie nur Rollen, mit diesen Berechtigungen, vertrauenswürdigen Benutzern zu.',
'role_asset_desc' => 'Diese Berechtigungen gelten für den Standard-Zugriff innerhalb des Systems. Berechtigungen für Bücher, Kapitel und Seiten überschreiben diese Berechtigungenen.',

View File

@@ -33,15 +33,15 @@ return [
'copy' => 'Kopieren',
'reply' => 'Antworten',
'delete' => 'Löschen',
'delete_confirm' => 'Löschen Bestätigen',
'delete_confirm' => 'Löschen bestätigen',
'search' => 'Suchen',
'search_clear' => 'Suche löschen',
'reset' => 'Zurücksetzen',
'remove' => 'Entfernen',
'add' => 'Hinzufügen',
'configure' => 'Configure',
'configure' => 'Konfigurieren',
'fullscreen' => 'Vollbild',
'favourite' => 'Favorit',
'favourite' => 'Favoriten',
'unfavourite' => 'Kein Favorit',
'next' => 'Nächste',
'previous' => 'Vorheriges',
@@ -57,7 +57,7 @@ return [
'sort_updated_at' => 'Aktualisierungsdatum',
// Misc
'deleted_user' => 'Gelöschte Benutzer',
'deleted_user' => 'Gelöschter Benutzer',
'no_activity' => 'Keine Aktivitäten zum Anzeigen',
'no_items' => 'Keine Einträge gefunden.',
'back_to_top' => 'nach oben',

View File

@@ -36,7 +36,7 @@ return [
'export_html' => 'HTML-Datei',
'export_pdf' => 'PDF-Datei',
'export_text' => 'Textdatei',
'export_md' => 'Markdown-Datei',
'export_md' => 'Markdown-Dateir',
// Permissions and restrictions
'permissions' => 'Berechtigungen',
@@ -99,7 +99,7 @@ return [
'shelves_permissions' => 'Regal-Berechtigungen',
'shelves_permissions_updated' => 'Regal-Berechtigungen aktualisiert',
'shelves_permissions_active' => 'Regal-Berechtigungen aktiv',
'shelves_permissions_cascade_warning' => 'Permissions on bookshelves do not automatically cascade to contained books. This is because a book can exist on multiple shelves. Permissions can however be copied down to child books using the option found below.',
'shelves_permissions_cascade_warning' => 'Die Berechtigungen in Bücherregalen werden nicht automatisch auf enthaltene Bücher kaskadiert, weil ein Buch in mehreren Regalen existieren kann. Berechtigungen können jedoch mit der unten stehenden Option in untergeordnete Bücher kopiert werden.',
'shelves_copy_permissions_to_books' => 'Kopiere die Berechtigungen zum Buch',
'shelves_copy_permissions' => 'Berechtigungen kopieren',
'shelves_copy_permissions_explain' => 'Hiermit werden die Berechtigungen des aktuellen Regals auf alle enthaltenen Bücher übertragen. Überprüfe vor der Aktivierung, ob alle Berechtigungsänderungen am aktuellen Regal gespeichert wurden.',
@@ -234,6 +234,7 @@ return [
'pages_initial_name' => 'Neue Seite',
'pages_editing_draft_notification' => 'Du bearbeitest momenten einen Entwurf, der zuletzt :timeDiff gespeichert wurde.',
'pages_draft_edited_notification' => 'Diese Seite wurde seit diesem Zeitpunkt verändert. Wir empfehlen Ihnen, diesen Entwurf zu verwerfen.',
'pages_draft_page_changed_since_creation' => 'This page has been updated since this draft was created. It is recommended that you discard this draft or take care not to overwrite any page changes.',
'pages_draft_edit_active' => [
'start_a' => ':count Benutzer bearbeiten derzeit diese Seite.',
'start_b' => ':userName bearbeitet jetzt diese Seite.',

View File

@@ -108,7 +108,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung
'recycle_bin_restore_list' => 'Wiederherzustellende Einträge',
'recycle_bin_restore_confirm' => 'Mit dieser Aktion wird der gelöschte Eintrag einschließlich aller untergeordneten Einträge an seinen ursprünglichen Ort wiederherstellen. Wenn der ursprüngliche Ort gelöscht wurde und sich nun im Papierkorb befindet, muss auch der übergeordnete Eintrag wiederhergestellt werden.',
'recycle_bin_restore_deleted_parent' => 'Der übergeordnete Eintrag wurde ebenfalls gelöscht. Dieser Eintrag wird weiterhin als gelöscht zählen, bis auch der übergeordnete Eintrag wiederhergestellt wurde.',
'recycle_bin_restore_parent' => 'Elternteil wiederherstellen',
'recycle_bin_restore_parent' => 'Übergeordneter Eintrag wiederherstellen',
'recycle_bin_destroy_notification' => ':count Einträge wurden aus dem Papierkorb gelöscht.',
'recycle_bin_restore_notification' => ':count Einträge wurden aus dem Papierkorb wiederhergestellt.',
@@ -122,6 +122,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung
'audit_table_user' => 'Benutzer',
'audit_table_event' => 'Ereignis',
'audit_table_related' => 'Verknüpfter Eintrag oder Detail',
'audit_table_ip' => 'IP Address',
'audit_table_date' => 'Aktivitätsdatum',
'audit_date_from' => 'Zeitraum von',
'audit_date_to' => 'Zeitraum bis',
@@ -151,7 +152,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung
'role_manage_page_templates' => 'Seitenvorlagen verwalten',
'role_access_api' => 'Systemzugriffs-API',
'role_manage_settings' => 'Globaleinstellungen verwalten',
'role_export_content' => 'Export content',
'role_export_content' => 'Inhalt exportieren',
'role_asset' => 'Berechtigungen',
'roles_system_warning' => 'Beachten Sie, dass der Zugriff auf eine der oben genannten drei Berechtigungen einem Benutzer erlauben kann, seine eigenen Berechtigungen oder die Rechte anderer im System zu ändern. Weisen Sie nur Rollen, mit diesen Berechtigungen, vertrauenswürdigen Benutzern zu.',
'role_asset_desc' => 'Diese Berechtigungen gelten für den Standard-Zugriff innerhalb des Systems. Berechtigungen für Bücher, Kapitel und Seiten überschreiben diese Berechtigungenen.',
@@ -210,7 +211,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung
'users_api_tokens_expires' => 'Endet',
'users_api_tokens_docs' => 'API Dokumentation',
'users_mfa' => 'Multi-Faktor-Authentifizierung',
'users_mfa_desc' => 'Richten Sie Multi-Faktor-Authentifizierung als zusätzliche Sicherheitsstufe für Ihr Benutzerkonto ein.',
'users_mfa_desc' => 'Richte die Multi-Faktor-Authentifizierung als zusätzliche Sicherheitsstufe für dein Benutzerkonto ein.',
'users_mfa_x_methods' => ':count Methode konfiguriert|:count Methoden konfiguriert',
'users_mfa_configure' => 'Methoden konfigurieren',

View File

@@ -234,6 +234,7 @@ return [
'pages_initial_name' => 'New Page',
'pages_editing_draft_notification' => 'You are currently editing a draft that was last saved :timeDiff.',
'pages_draft_edited_notification' => 'This page has been updated by since that time. It is recommended that you discard this draft.',
'pages_draft_page_changed_since_creation' => 'This page has been updated since this draft was created. It is recommended that you discard this draft or take care not to overwrite any page changes.',
'pages_draft_edit_active' => [
'start_a' => ':count users have started editing this page',
'start_b' => ':userName has started editing this page',

View File

@@ -119,6 +119,7 @@ return [
'audit_table_user' => 'User',
'audit_table_event' => 'Event',
'audit_table_related' => 'Related Item or Detail',
'audit_table_ip' => 'IP Address',
'audit_table_date' => 'Activity Date',
'audit_date_from' => 'Date Range From',
'audit_date_to' => 'Date Range To',

View File

@@ -80,11 +80,11 @@ return [
'mfa_setup_desc' => 'La autenticación en dos pasos añade una capa de seguridad adicional a tu cuenta de usuario.',
'mfa_setup_configured' => 'Ya está configurado',
'mfa_setup_reconfigure' => 'Reconfigurar',
'mfa_setup_remove_confirmation' => '¿Está seguro de que desea eliminar este método de autenticación de dos pasos?',
'mfa_setup_remove_confirmation' => '¿Está seguro de que desea eliminar este método de autenticación en dos pasos?',
'mfa_setup_action' => 'Configuración',
'mfa_backup_codes_usage_limit_warning' => 'Quedan menos de 5 códigos de respaldo, Por favor, genera y almacena un nuevo conjunto antes de que te quedes sin códigos para evitar que te bloquees fuera de tu cuenta.',
'mfa_option_totp_title' => 'Aplicación para móviles',
'mfa_option_totp_desc' => 'Para utilizar la autenticación de dos pasos necesitarás una aplicación móvil que soporte TOTP como Google Authenticator, Authy o Microsoft Authenticator.',
'mfa_option_totp_desc' => 'Para utilizar la autenticación en dos pasos necesitarás una aplicación móvil que soporte TOTP como Google Authenticator, Authy o Microsoft Authenticator.',
'mfa_option_backup_codes_title' => 'Códigos de Respaldo',
'mfa_option_backup_codes_desc' => 'Almacena de forma segura un conjunto de códigos de respaldo de un solo uso que puedes introducir para verificar tu identidad.',
'mfa_gen_confirm_and_enable' => 'Confirmar y Activar',
@@ -93,7 +93,7 @@ return [
'mfa_gen_backup_codes_download' => 'Descargar Códigos',
'mfa_gen_backup_codes_usage_warning' => 'Cada código sólo puede utilizarse una vez',
'mfa_gen_totp_title' => 'Configuración de Aplicación móvil',
'mfa_gen_totp_desc' => 'Para utilizar la autenticación de dos pasos necesitarás una aplicación móvil que soporte TOTP como Google Authenticator, Authy o Microsoft Authenticator.',
'mfa_gen_totp_desc' => 'Para utilizar la autenticación en dos pasos necesitarás una aplicación móvil que soporte TOTP como Google Authenticator, Authy o Microsoft Authenticator.',
'mfa_gen_totp_scan' => 'Escanea el código QR mostrado a continuación usando tu aplicación de autenticación preferida para empezar.',
'mfa_gen_totp_verify_setup' => 'Verificar Configuración',
'mfa_gen_totp_verify_setup_desc' => 'Verifica que todo está funcionando introduciendo un código, generado en tu aplicación de autenticación, en el campo de texto a continuación:',
@@ -101,7 +101,7 @@ return [
'mfa_verify_access' => 'Verificar Acceso',
'mfa_verify_access_desc' => 'Tu cuenta de usuario requiere que confirmes tu identidad a través de un nivel adicional de verificación antes de que te conceda el acceso. Verifica tu identidad usando uno de los métodos configurados para continuar.',
'mfa_verify_no_methods' => 'No hay Métodos Configurados',
'mfa_verify_no_methods_desc' => 'No se han encontrado métodos de autenticación de dos pasos para tu cuenta. Tendrás que configurar al menos un método antes de obtener acceso.',
'mfa_verify_no_methods_desc' => 'No se han encontrado métodos de autenticación en dos pasos para tu cuenta. Tendrás que configurar al menos un método antes de obtener acceso.',
'mfa_verify_use_totp' => 'Verificar usando una aplicación móvil',
'mfa_verify_use_backup_codes' => 'Verificar usando un código de respaldo',
'mfa_verify_backup_code' => 'Códigos de Respaldo',

View File

@@ -234,6 +234,7 @@ return [
'pages_initial_name' => 'Página nueva',
'pages_editing_draft_notification' => 'Está actualmente editando un borrador que fue guardado por última vez el :timeDiff.',
'pages_draft_edited_notification' => 'Esta página ha sido actualizada desde ese momento. Se recomienda que cancele este borrador.',
'pages_draft_page_changed_since_creation' => 'Esta página ha sido actualizada desde que se creó este borrador. Se recomienda descartar este borrador o tener cuidado de no sobrescribir ningún cambio en la página.',
'pages_draft_edit_active' => [
'start_a' => ':count usuarios han comenzado a editar esta página',
'start_b' => ':userName ha comenzado a editar esta página',

View File

@@ -119,6 +119,7 @@ return [
'audit_table_user' => 'Usuario',
'audit_table_event' => 'Evento',
'audit_table_related' => 'Elemento o detalle relacionados',
'audit_table_ip' => 'Dirección IP',
'audit_table_date' => 'Fecha de la actividad',
'audit_date_from' => 'Rango de fecha desde',
'audit_date_to' => 'Rango de fecha hasta',

View File

@@ -48,8 +48,8 @@ return [
'favourite_remove_notification' => '".name" se eliminó de sus favoritos',
// MFA
'mfa_setup_method_notification' => 'Método de Autenticación en Dos Pasos configurado correctamente',
'mfa_remove_method_notification' => 'Método de Autenticación en Dos Pasos eliminado correctamente',
'mfa_setup_method_notification' => 'Método de autenticación de múltiples factores configurado satisfactoriamente',
'mfa_remove_method_notification' => 'Método de autenticación de múltiples factores eliminado satisfactoriamente',
// Other
'commented_on' => 'comentado',

View File

@@ -76,37 +76,37 @@ return [
'user_invite_success' => 'Contraseña establecida, ahora tiene acceso a :appName!',
// Multi-factor Authentication
'mfa_setup' => 'Configurar Autenticación en Dos Pasos',
'mfa_setup_desc' => 'La autenticación en dos pasos añade una capa de seguridad adicional a tu cuenta de usuario.',
'mfa_setup' => 'Configurar autenticación de múltiples factores',
'mfa_setup_desc' => 'Configure la autenticación de múltiples factores como una capa extra de seguridad para su cuenta de usuario.',
'mfa_setup_configured' => 'Ya está configurado',
'mfa_setup_reconfigure' => 'Reconfigurar',
'mfa_setup_remove_confirmation' => '¿Está seguro de que desea eliminar este método de autenticación de dos pasos?',
'mfa_setup_remove_confirmation' => '¿Está seguro que desea eliminar este método de autenticación de múltiples factores?',
'mfa_setup_action' => 'Configuración',
'mfa_backup_codes_usage_limit_warning' => 'Quedan menos de 5 códigos de respaldo, Por favor, genera y almacena un nuevo conjunto antes de que te quedes sin códigos para evitar que te bloquees fuera de tu cuenta.',
'mfa_option_totp_title' => 'Aplicación para móviles',
'mfa_option_totp_desc' => 'Para utilizar la autenticación de dos pasos necesitarás una aplicación móvil que soporte TOTP como Google Authenticator, Authy o Microsoft Authenticator.',
'mfa_backup_codes_usage_limit_warning' => 'Quedan menos de 5 códigos de respaldo, Por favor, genere y guarde un nuevo conjunto antes de que se quede sin códigos para evitar que se bloquee su cuenta.',
'mfa_option_totp_title' => 'Aplicación móvil',
'mfa_option_totp_desc' => 'Para utilizar la autenticación en dos pasos necesitará una aplicación móvil que soporte TOTP como Google Authenticator, Authy o Microsoft Authenticator.',
'mfa_option_backup_codes_title' => 'Códigos de Respaldo',
'mfa_option_backup_codes_desc' => 'Almacena de forma segura un conjunto de códigos de respaldo de un solo uso que puedes introducir para verificar tu identidad.',
'mfa_option_backup_codes_desc' => 'Almacene de forma segura un conjunto de códigos de respaldo de un solo uso que pueda introducir para verificar su identidad.',
'mfa_gen_confirm_and_enable' => 'Confirmar y Activar',
'mfa_gen_backup_codes_title' => 'Configuración de Códigos de Respaldo',
'mfa_gen_backup_codes_desc' => 'Guarda la siguiente lista de códigos en un lugar seguro. Al acceder al sistema podrás usar uno de los códigos como un segundo mecanismo de autenticación.',
'mfa_gen_backup_codes_desc' => 'Guarde la siguiente lista de códigos en un lugar seguro. Al acceder al sistema podrá usar uno de los códigos como un segundo mecanismo de autenticación.',
'mfa_gen_backup_codes_download' => 'Descargar Códigos',
'mfa_gen_backup_codes_usage_warning' => 'Cada código sólo puede utilizarse una vez',
'mfa_gen_backup_codes_usage_warning' => 'Cada código puede utilizarse sólo una vez',
'mfa_gen_totp_title' => 'Configuración de Aplicación móvil',
'mfa_gen_totp_desc' => 'Para utilizar la autenticación de dos pasos necesitarás una aplicación móvil que soporte TOTP como Google Authenticator, Authy o Microsoft Authenticator.',
'mfa_gen_totp_desc' => 'Para utilizar la autenticación en dos pasos necesitará una aplicación móvil que soporte TOTP como Google Authenticator, Authy o Microsoft Authenticator.',
'mfa_gen_totp_scan' => 'Escanea el código QR mostrado a continuación usando tu aplicación de autenticación preferida para empezar.',
'mfa_gen_totp_verify_setup' => 'Verificar Configuración',
'mfa_gen_totp_verify_setup_desc' => 'Verifica que todo está funcionando introduciendo un código, generado en tu aplicación de autenticación, en el campo de texto a continuación:',
'mfa_gen_totp_provide_code_here' => 'Introduce aquí tu código generado por la aplicación',
'mfa_verify_access' => 'Verificar Acceso',
'mfa_verify_access_desc' => 'Tu cuenta de usuario requiere que confirmes tu identidad a través de un nivel adicional de verificación antes de que te conceda el acceso. Verifica tu identidad usando uno de los métodos configurados para continuar.',
'mfa_verify_access_desc' => 'Su cuenta de usuario requiere que confirme su identidad a través de un nivel adicional de verificación antes de que se le conceda el acceso. Verifique su identidad usando uno de los métodos configurados para continuar.',
'mfa_verify_no_methods' => 'No hay Métodos Configurados',
'mfa_verify_no_methods_desc' => 'No se han encontrado métodos de autenticación de dos pasos para tu cuenta. Tendrás que configurar al menos un método antes de obtener acceso.',
'mfa_verify_no_methods_desc' => 'No se han encontrado métodos de autenticación de múltiples factores para su cuenta. Tendrá que configurar al menos un método antes de obtener acceso.',
'mfa_verify_use_totp' => 'Verificar usando una aplicación móvil',
'mfa_verify_use_backup_codes' => 'Verificar usando un código de respaldo',
'mfa_verify_backup_code' => 'Códigos de Respaldo',
'mfa_verify_backup_code' => 'Código de Respaldo',
'mfa_verify_backup_code_desc' => 'Introduzca uno de sus códigos de respaldo restantes a continuación:',
'mfa_verify_backup_code_enter_here' => 'Introduce el código de respaldo aquí',
'mfa_verify_totp_desc' => 'Introduzca el código, generado con tu aplicación móvil, a continuación:',
'mfa_setup_login_notification' => 'Método de dos factores configurado. Por favor, inicia sesión de nuevo utilizando el método configurado.',
'mfa_verify_backup_code_enter_here' => 'Introduzca el código de respaldo aquí',
'mfa_verify_totp_desc' => 'A continuación, introduzca el código generado con su aplicación móvil:',
'mfa_setup_login_notification' => 'Método de dos factores configurado. Por favor, inicie sesión nuevamente utilizando el método configurado.',
];

View File

@@ -99,7 +99,7 @@ return [
'shelves_permissions' => 'Permisos del Estante',
'shelves_permissions_updated' => 'Permisos del Estante actualizados',
'shelves_permissions_active' => 'Permisos Activos del Estante',
'shelves_permissions_cascade_warning' => 'Permissions on bookshelves do not automatically cascade to contained books. This is because a book can exist on multiple shelves. Permissions can however be copied down to child books using the option found below.',
'shelves_permissions_cascade_warning' => 'Los permisos en los estantes no se aplican automáticamente a los libros contenidos. Esto se debe a que un libro puede existir en múltiples estantes. Sin embargo, los permisos pueden ser aplicados a los libros del estante utilizando la opción a continuación.',
'shelves_copy_permissions_to_books' => 'Copiar Permisos a los Libros',
'shelves_copy_permissions' => 'Copiar Permisos',
'shelves_copy_permissions_explain' => 'Esta acción aplicará los permisos de este estante a todos los libros contenidos en él. Antes de activarlos, asegúrese que los cambios a los permisos de este estante estén guardados.',
@@ -234,6 +234,7 @@ return [
'pages_initial_name' => 'Página nueva',
'pages_editing_draft_notification' => 'Usted está actualmente editando un borrador que fue guardado por última vez el :timeDiff.',
'pages_draft_edited_notification' => 'Esta página ha sido actualizada desde aquel momento. Se recomienda que cancele este borrador.',
'pages_draft_page_changed_since_creation' => 'Esta página fue actualizada desde que se creó este borrador. Se recomienda descartar este borrador o tener cuidado de no sobrescribir ningún cambio en la página.',
'pages_draft_edit_active' => [
'start_a' => ':count usuarios han comenzado a editar esta página',
'start_b' => ':userName ha comenzado a editar esta página',

View File

@@ -92,7 +92,7 @@ return [
'recycle_bin' => 'Papelera de Reciclaje',
'recycle_bin_desc' => 'Aquí puede restaurar elementos que hayan sido eliminados o elegir eliminarlos permanentemente del sistema. Esta lista no está filtrada a diferencia de las listas de actividad similares en el sistema donde se aplican los filtros de permisos.',
'recycle_bin_deleted_item' => 'Elemento Eliminado',
'recycle_bin_deleted_parent' => 'Superior',
'recycle_bin_deleted_parent' => 'Padre',
'recycle_bin_deleted_by' => 'Eliminado por',
'recycle_bin_deleted_at' => 'Fecha de eliminación',
'recycle_bin_permanently_delete' => 'Eliminar permanentemente',
@@ -105,7 +105,7 @@ return [
'recycle_bin_restore_list' => 'Elementos a restaurar',
'recycle_bin_restore_confirm' => 'Esta acción restaurará el elemento eliminado, incluyendo cualquier elemento secundario, a su ubicación original. Si la ubicación original ha sido eliminada, y ahora está en la papelera de reciclaje, el elemento padre también tendrá que ser restaurado.',
'recycle_bin_restore_deleted_parent' => 'El padre de este elemento también ha sido eliminado. Estos permanecerán eliminados hasta que el padre también sea restaurado.',
'recycle_bin_restore_parent' => 'Restaurar Superior',
'recycle_bin_restore_parent' => 'Restaurar Padre',
'recycle_bin_destroy_notification' => 'Eliminados :count elementos de la papelera de reciclaje.',
'recycle_bin_restore_notification' => 'Restaurados :count elementos desde la papelera de reciclaje.',
@@ -119,6 +119,7 @@ return [
'audit_table_user' => 'Usuario',
'audit_table_event' => 'Evento',
'audit_table_related' => 'Elemento o detalle relacionados',
'audit_table_ip' => 'Dirección IP',
'audit_table_date' => 'Fecha de la Actividad',
'audit_date_from' => 'Inicio del Rango de Fecha',
'audit_date_to' => 'Final del Rango de Fecha',
@@ -138,7 +139,7 @@ return [
'role_details' => 'Detalles de rol',
'role_name' => 'Nombre de rol',
'role_desc' => 'Descripción corta de rol',
'role_mfa_enforced' => 'Requiere Autenticación en Dos Pasos',
'role_mfa_enforced' => 'Requiere autenticación de múltiples factores',
'role_external_auth_id' => 'IDs de Autenticación Externa',
'role_system' => 'Permisos de sistema',
'role_manage_users' => 'Gestionar usuarios',
@@ -149,7 +150,7 @@ return [
'role_manage_page_templates' => 'Gestionar las plantillas de páginas',
'role_access_api' => 'API de sistema de acceso',
'role_manage_settings' => 'Gestionar ajustes de activos',
'role_export_content' => 'Export content',
'role_export_content' => 'Exportar contenido',
'role_asset' => 'Permisos de activos',
'roles_system_warning' => 'Tenga en cuenta que el acceso a cualquiera de los tres permisos anteriores puede permitir a un usuario modificar sus propios privilegios o los privilegios de otros usuarios en el sistema. Asignar roles con estos permisos sólo a usuarios de comfianza.',
'role_asset_desc' => 'Estos permisos controlan el acceso por defecto a los activos del sistema. Permisos definidos en Libros, Capítulos y Páginas ignorarán estos permisos.',
@@ -207,8 +208,8 @@ return [
'users_api_tokens_create' => 'Crear token',
'users_api_tokens_expires' => 'Expira',
'users_api_tokens_docs' => 'Documentación API',
'users_mfa' => 'Autenticación en Dos Pasos',
'users_mfa_desc' => 'La autenticación en dos pasos añade una capa de seguridad adicional a tu cuenta.',
'users_mfa' => 'Autenticación de múltiples factores',
'users_mfa_desc' => 'Configure la autenticación de múltiples factores como una capa extra de seguridad para su cuenta de usuario.',
'users_mfa_x_methods' => ':count método configurado|:count métodos configurados',
'users_mfa_configure' => 'Configurar Métodos',

View File

@@ -15,7 +15,7 @@ return [
'alpha_dash' => 'El :attribute solo puede contener letras, números y guiones.',
'alpha_num' => 'El :attribute solo puede contener letras y número.',
'array' => 'El :attribute debe de ser un array.',
'backup_codes' => 'El código suministrado no es válido o ya ha sido utilizado.',
'backup_codes' => 'El código suministrado no es válido o ya fue utilizado.',
'before' => 'El :attribute debe ser una fecha anterior a :date.',
'between' => [
'numeric' => 'El :attribute debe estar entre :min y :max.',
@@ -99,7 +99,7 @@ return [
],
'string' => 'El atributo :attribute debe ser una cadena.',
'timezone' => 'El atributo :attribute debe ser una zona válida.',
'totp' => 'El código suministrado no es válido o ya ha expirado.',
'totp' => 'El código suministrado no es válido o ya expiró.',
'unique' => 'El atributo :attribute ya ha sido tomado.',
'url' => 'El atributo :attribute tiene un formato inválido.',
'uploaded' => 'El archivo no se pudo subir. Puede ser que el servidor no acepte archivos de este tamaño.',

View File

@@ -234,6 +234,7 @@ return [
'pages_initial_name' => 'New Page',
'pages_editing_draft_notification' => 'You are currently editing a draft that was last saved :timeDiff.',
'pages_draft_edited_notification' => 'This page has been updated by since that time. It is recommended that you discard this draft.',
'pages_draft_page_changed_since_creation' => 'This page has been updated since this draft was created. It is recommended that you discard this draft or take care not to overwrite any page changes.',
'pages_draft_edit_active' => [
'start_a' => ':count users have started editing this page',
'start_b' => ':userName has started editing this page',

View File

@@ -119,6 +119,7 @@ return [
'audit_table_user' => 'User',
'audit_table_event' => 'Event',
'audit_table_related' => 'Related Item or Detail',
'audit_table_ip' => 'IP Address',
'audit_table_date' => 'Activity Date',
'audit_date_from' => 'Date Range From',
'audit_date_to' => 'Date Range To',

View File

@@ -26,11 +26,11 @@ return [
'chapter_move' => 'a déplacé le chapitre',
// Books
'book_create' => 'a créé le livre',
'book_create' => 'a créé un livre',
'book_create_notification' => 'Livre créé avec succès',
'book_update' => 'a modifié le livre',
'book_update_notification' => 'Livre modifié avec succès',
'book_delete' => 'a supprimé le livre',
'book_delete' => 'a supprimé un livre',
'book_delete_notification' => 'Livre supprimé avec succès',
'book_sort' => 'a réordonné le livre',
'book_sort_notification' => 'Livre réordonné avec succès',
@@ -53,5 +53,5 @@ return [
// Other
'commented_on' => 'a commenté',
'permissions_update' => 'mettre à jour les autorisations',
'permissions_update' => 'a mis à jour les autorisations sur',
];

View File

@@ -57,13 +57,13 @@ return [
'email_confirm_action' => 'Confirmez votre adresse e-mail',
'email_confirm_send_error' => 'La confirmation par e-mail est requise mais le système n\'a pas pu envoyer l\'e-mail. Contactez l\'administrateur système.',
'email_confirm_success' => 'Votre adresse e-mail a été confirmée !',
'email_confirm_resent' => 'L\'e-mail de confirmation a été ré-envoyé. Vérifiez votre boîte de récéption.',
'email_confirm_resent' => 'L\'e-mail de confirmation a été ré-envoyé. Vérifiez votre boîte de réception.',
'email_not_confirmed' => 'Adresse e-mail non confirmée',
'email_not_confirmed_text' => 'Votre adresse e-mail n\'a pas été confirmée.',
'email_not_confirmed_click_link' => 'Merci de cliquer sur le lien dans l\'e-mail qui vous a été envoyé après l\'enregistrement.',
'email_not_confirmed_resend' => 'Si vous ne retrouvez plus l\'e-mail, vous pouvez renvoyer un e-mail de confirmation en utilisant le formulaire ci-dessous.',
'email_not_confirmed_resend_button' => 'Renvoyez l\'e-mail de confirmation',
'email_not_confirmed_resend_button' => 'Renvoyer l\'e-mail de confirmation',
// User Invite
'user_invite_email_subject' => 'Vous avez été invité(e) à rejoindre :appName !',
@@ -76,37 +76,37 @@ return [
'user_invite_success' => 'Mot de passe renseigné, vous avez maintenant accès à :appName !',
// Multi-factor Authentication
'mfa_setup' => 'Configuration authentification multi-facteurs',
'mfa_setup_desc' => 'Configurez l\'authentification multi-facteurs ajoute une couche supplémentaire de sécurité à votre compte utilisateur.',
'mfa_setup' => 'Authentification multi-facteurs',
'mfa_setup_desc' => 'Configurer l\'authentification multi-facteurs ajoute une couche supplémentaire de sécurité à votre compte utilisateur.',
'mfa_setup_configured' => 'Déjà configuré',
'mfa_setup_reconfigure' => 'Reconfigurer',
'mfa_setup_remove_confirmation' => 'Êtes-vous sûr de vouloir supprimer cette méthode d\'authentification multi-facteurs ?',
'mfa_setup_action' => 'Configuration',
'mfa_backup_codes_usage_limit_warning' => 'You have less than 5 backup codes remaining, Please generate and store a new set before you run out of codes to prevent being locked out of your account.',
'mfa_backup_codes_usage_limit_warning' => 'Il vous reste moins de 5 codes de secours, veuillez générer et stocker un nouveau jeu de codes afin d\'éviter tout verrouillage de votre compte.',
'mfa_option_totp_title' => 'Application mobile',
'mfa_option_totp_desc' => 'Pour utiliser l\'authentification multi-facteurs, vous aurez besoin d\'une application mobile qui supporte TOTP comme Google Authenticator, Authy ou Microsoft Authenticator.',
'mfa_option_backup_codes_title' => 'Backup Codes',
'mfa_option_backup_codes_desc' => 'Securely store a set of one-time-use backup codes which you can enter to verify your identity.',
'mfa_option_backup_codes_title' => 'Codes de secours',
'mfa_option_backup_codes_desc' => 'Stockez en toute sécurité un jeu de codes de secours que vous pourrez utiliser pour vérifier votre identité.',
'mfa_gen_confirm_and_enable' => 'Confirmer et activer',
'mfa_gen_backup_codes_title' => 'Backup Codes Setup',
'mfa_gen_backup_codes_title' => 'Configuration des codes de secours',
'mfa_gen_backup_codes_desc' => 'Stockez la liste des codes ci-dessous dans un endroit sûr. Lorsque vous accédez au système, vous pourrez utiliser l\'un des codes comme un deuxième mécanisme d\'authentification.',
'mfa_gen_backup_codes_download' => 'Télécharger le code',
'mfa_gen_backup_codes_download' => 'Télécharger les codes',
'mfa_gen_backup_codes_usage_warning' => 'Chaque code ne peut être utilisé qu\'une seule fois',
'mfa_gen_totp_title' => 'Configuration de l\'application mobile',
'mfa_gen_totp_desc' => 'To use multi-factor authentication you\'ll need a mobile application that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator.',
'mfa_gen_totp_scan' => 'Scan the QR code below using your preferred authentication app to get started.',
'mfa_gen_totp_desc' => 'Pour utiliser l\'authentification multi-facteurs, vous aurez besoin d\'une application mobile qui supporte TOTP comme Google Authenticator, Authy ou Microsoft Authenticator.',
'mfa_gen_totp_scan' => 'Scannez le QR code ci-dessous avec votre application d\'authentification préférée pour débuter.',
'mfa_gen_totp_verify_setup' => 'Vérifier la configuration',
'mfa_gen_totp_verify_setup_desc' => 'Verify that all is working by entering a code, generated within your authentication app, in the input box below:',
'mfa_gen_totp_provide_code_here' => 'Fournir le code généré par votre application ici',
'mfa_gen_totp_verify_setup_desc' => 'Vérifiez que tout fonctionne en utilisant un code généré par votre application d\'authentification, dans la zone ci-dessous :',
'mfa_gen_totp_provide_code_here' => 'Fournissez le code généré par votre application ici',
'mfa_verify_access' => 'Vérifier l\'accès',
'mfa_verify_access_desc' => 'Your user account requires you to confirm your identity via an additional level of verification before you\'re granted access. Verify using one of your configured methods to continue.',
'mfa_verify_access_desc' => 'Votre compte d\'utilisateur vous demande de confirmer votre identité par un niveau supplémentaire de vérification avant que vous n\'ayez accès. Vérifiez-la en utilisant l\'une de vos méthodes configurées pour continuer.',
'mfa_verify_no_methods' => 'Aucune méthode configurée',
'mfa_verify_no_methods_desc' => 'Aucune méthode d\'authentification multi-facteurs n\'a pu être trouvée pour votre compte. Vous devez configurer au moins une méthode avant d\'obtenir l\'accès.',
'mfa_verify_use_totp' => 'Vérifier à l\'aide d\'une application mobile',
'mfa_verify_use_backup_codes' => 'Verify using a backup code',
'mfa_verify_backup_code' => 'Backup Code',
'mfa_verify_backup_code_desc' => 'Enter one of your remaining backup codes below:',
'mfa_verify_backup_code_enter_here' => 'Enter backup code here',
'mfa_verify_use_backup_codes' => 'Vérifier en utilisant un code de secours',
'mfa_verify_backup_code' => 'Code de secours',
'mfa_verify_backup_code_desc' => 'Entrez l\'un de vos codes de secours restants ci-dessous :',
'mfa_verify_backup_code_enter_here' => 'Saisissez un code de secours ici',
'mfa_verify_totp_desc' => 'Entrez ci-dessous le code généré à l\'aide de votre application mobile :',
'mfa_setup_login_notification' => 'Méthode multi-facteurs configurée. Veuillez maintenant vous reconnecter en utilisant la méthode configurée.',
];

View File

@@ -27,14 +27,14 @@ return [
'view_all' => 'Tout afficher',
'create' => 'Créer',
'update' => 'Modifier',
'edit' => 'Editer',
'edit' => 'Éditer',
'sort' => 'Trier',
'move' => 'Déplacer',
'copy' => 'Copier',
'reply' => 'Répondre',
'delete' => 'Supprimer',
'delete_confirm' => 'Confirmer la suppression',
'search' => 'Chercher',
'search' => 'Rechercher',
'search_clear' => 'Réinitialiser la recherche',
'reset' => 'Réinitialiser',
'remove' => 'Enlever',

View File

@@ -26,7 +26,7 @@ return [
'image_upload_remove' => 'Supprimer',
// Code Editor
'code_editor' => 'Editer le code',
'code_editor' => 'Éditer le code',
'code_language' => 'Langage du code',
'code_content' => 'Contenu du code',
'code_session_history' => 'Historique de session',

View File

@@ -22,12 +22,12 @@ return [
'meta_created_name' => 'Créé :timeLength par :user',
'meta_updated' => 'Mis à jour :timeLength',
'meta_updated_name' => 'Mis à jour :timeLength par :user',
'meta_owned_name' => 'Possédé par :user',
'meta_owned_name' => 'Appartient à :user',
'entity_select' => 'Sélectionner l\'entité',
'images' => 'Images',
'my_recent_drafts' => 'Mes brouillons récents',
'my_recently_viewed' => 'Vus récemment',
'my_most_viewed_favourites' => 'Mes Favoris les plus vus',
'my_most_viewed_favourites' => 'Mes favoris les plus vus',
'my_favourites' => 'Mes favoris',
'no_pages_viewed' => 'Vous n\'avez rien visité récemment',
'no_pages_recently_created' => 'Aucune page créée récemment',
@@ -40,7 +40,7 @@ return [
// Permissions and restrictions
'permissions' => 'Autorisations',
'permissions_intro' => 'Une fois activées ces permissions prendront la priorité sur tous les sets de permissions préexistants.',
'permissions_intro' => 'Une fois activées, ces permissions auront la priorité sur tous les jeux de permissions préexistants.',
'permissions_enable' => 'Activer les permissions personnalisées',
'permissions_save' => 'Enregistrer les permissions',
'permissions_owner' => 'Propriétaire',
@@ -80,8 +80,8 @@ return [
'shelves_empty' => 'Aucune étagère n\'a été créée',
'shelves_create' => 'Créer une nouvelle étagère',
'shelves_popular' => 'Étagères populaires',
'shelves_new' => 'Nouvelles Étagères',
'shelves_new_action' => 'Nouvelle Étagère',
'shelves_new' => 'Nouvelles étagères',
'shelves_new_action' => 'Nouvelle étagère',
'shelves_popular_empty' => 'Les étagères les plus populaires apparaîtront ici.',
'shelves_new_empty' => 'Les étagères les plus récentes apparaitront ici.',
'shelves_save' => 'Enregistrer l\'étagère',
@@ -99,7 +99,7 @@ return [
'shelves_permissions' => 'Permissions de l\'étagère',
'shelves_permissions_updated' => 'Permissions de l\'étagère mises à jour',
'shelves_permissions_active' => 'Permissions de l\'étagère activées',
'shelves_permissions_cascade_warning' => 'Permissions on bookshelves do not automatically cascade to contained books. This is because a book can exist on multiple shelves. Permissions can however be copied down to child books using the option found below.',
'shelves_permissions_cascade_warning' => 'Les permissions sur les étagères ne sont pas automatiquement recopiées aux livres qu\'elles contiennent, car un livre peut exister dans plusieurs étagères. Les permissions peuvent cependant être recopiées vers les livres contenus en utilisant l\'option ci-dessous.',
'shelves_copy_permissions_to_books' => 'Copier les permissions vers les livres',
'shelves_copy_permissions' => 'Copier les permissions',
'shelves_copy_permissions_explain' => 'Ceci va appliquer les permissions actuelles de cette étagère à tous les livres qu\'elle contient. Avant de continuer, assurez-vous que toutes les permissions de cette étagère ont été sauvegardées.',
@@ -132,7 +132,7 @@ return [
'books_empty_sort_current_book' => 'Trier les pages du livre',
'books_empty_add_chapter' => 'Ajouter un chapitre',
'books_permissions_active' => 'Permissions personnalisées activées',
'books_search_this' => 'Chercher dans le livre',
'books_search_this' => 'Rechercher dans ce livre',
'books_navigation' => 'Navigation dans le livre',
'books_sort' => 'Trier les contenus du livre',
'books_sort_named' => 'Trier le livre :bookName',
@@ -174,7 +174,7 @@ return [
'pages_popular' => 'Pages populaires',
'pages_new' => 'Nouvelle page',
'pages_attachments' => 'Fichiers joints',
'pages_navigation' => 'Navigation des pages',
'pages_navigation' => 'Navigation dans la page',
'pages_delete' => 'Supprimer la page',
'pages_delete_named' => 'Supprimer la page :pageName',
'pages_delete_draft_named' => 'supprimer le brouillon de la page :pageName',
@@ -189,16 +189,16 @@ return [
'pages_edit_draft' => 'Modifier le brouillon',
'pages_editing_draft' => 'Modification du brouillon',
'pages_editing_page' => 'Modification de la page',
'pages_edit_draft_save_at' => 'Brouillon sauvé le ',
'pages_edit_draft_save_at' => 'Brouillon enregistré le ',
'pages_edit_delete_draft' => 'Supprimer le brouillon',
'pages_edit_discard_draft' => 'Ecarter le brouillon',
'pages_edit_discard_draft' => 'Jeter le brouillon',
'pages_edit_set_changelog' => 'Remplir le journal des changements',
'pages_edit_enter_changelog_desc' => 'Entrez une brève description des changements effectués',
'pages_edit_enter_changelog' => 'Entrer dans le journal des changements',
'pages_save' => 'Enregistrez la page',
'pages_edit_enter_changelog' => 'Ouvrir le journal des changements',
'pages_save' => 'Enregistrer la page',
'pages_title' => 'Titre de la page',
'pages_name' => 'Nom de la page',
'pages_md_editor' => 'Editeur',
'pages_md_editor' => 'Éditeur',
'pages_md_preview' => 'Prévisualisation',
'pages_md_insert_image' => 'Insérer une image',
'pages_md_insert_link' => 'Insérer un lien',
@@ -223,7 +223,7 @@ return [
'pages_revisions_numbered_changes' => 'Modification #:id',
'pages_revisions_changelog' => 'Journal des changements',
'pages_revisions_changes' => 'Changements',
'pages_revisions_current' => 'Version courante',
'pages_revisions_current' => 'Version actuelle',
'pages_revisions_preview' => 'Prévisualisation',
'pages_revisions_restore' => 'Restaurer',
'pages_revisions_none' => 'Cette page n\'a aucune révision',
@@ -232,8 +232,9 @@ return [
'pages_permissions_active' => 'Permissions de page actives',
'pages_initial_revision' => 'Publication initiale',
'pages_initial_name' => 'Nouvelle page',
'pages_editing_draft_notification' => 'Vous éditez actuellement un brouillon qui a été sauvé :timeDiff.',
'pages_draft_edited_notification' => 'La page a été mise à jour depuis votre dernière visite. Vous devriez écarter ce brouillon.',
'pages_editing_draft_notification' => 'Vous éditez actuellement un brouillon qui a été enregistré :timeDiff.',
'pages_draft_edited_notification' => 'La page a été mise à jour depuis votre dernière visite. Vous devriez jeter ce brouillon.',
'pages_draft_page_changed_since_creation' => 'Cette page a été mise à jour depuis que ce brouillon a été créé. Il est recommandé de supprimer ce brouillon ou de veiller à ne pas écraser toute modification de page.',
'pages_draft_edit_active' => [
'start_a' => ':count utilisateurs ont commencé à éditer cette page',
'start_b' => ':userName a commencé à éditer cette page',
@@ -242,7 +243,7 @@ return [
'message' => ':start :time. Attention à ne pas écraser les mises à jour de quelqu\'un d\'autre !',
],
'pages_draft_discarded' => 'Brouillon écarté, la page est dans sa version actuelle.',
'pages_specific' => 'Page Spécifique',
'pages_specific' => 'Page spécifique',
'pages_is_template' => 'Modèle de page',
// Editor Sidebar
@@ -253,10 +254,10 @@ return [
'tag' => 'Mot-clé',
'tags' => 'Mots-clés',
'tag_name' => 'Nom du tag',
'tag_value' => 'Valeur du mot-clé (Optionnel)',
'tag_value' => 'Valeur du mot-clé (optionnel)',
'tags_explain' => "Ajouter des mots-clés pour catégoriser votre contenu.",
'tags_add' => 'Ajouter un autre mot-clé',
'tags_remove' => 'Supprimer le tag',
'tags_remove' => 'Supprimer le mot-clé',
'attachments' => 'Fichiers joints',
'attachments_explain' => 'Ajouter des fichiers ou des liens pour les afficher sur votre page. Ils seront affichés dans la barre latérale',
'attachments_explain_instant_save' => 'Ces changements sont enregistrés immédiatement.',
@@ -267,13 +268,13 @@ return [
'attachments_delete' => 'Êtes-vous sûr de vouloir supprimer la pièce jointe ?',
'attachments_dropzone' => 'Glissez des fichiers ou cliquez ici pour attacher des fichiers',
'attachments_no_files' => 'Aucun fichier ajouté',
'attachments_explain_link' => 'Vous pouvez attacher un lien si vous ne souhaitez pas uploader un fichier.',
'attachments_explain_link' => 'Vous pouvez ajouter un lien si vous ne souhaitez pas uploader un fichier.',
'attachments_link_name' => 'Nom du lien',
'attachment_link' => 'Lien de l\'attachement',
'attachments_link_url' => 'Lien sur un fichier',
'attachments_link_url_hint' => 'URL du site ou du fichier',
'attach' => 'Attacher',
'attachments_insert_link' => 'Ajouter un lien de pièce jointe à la page',
'attach' => 'Ajouter',
'attachments_insert_link' => 'Ajouter un lien à la page',
'attachments_edit_file' => 'Modifier le fichier',
'attachments_edit_file_name' => 'Nom du fichier',
'attachments_edit_drop_upload' => 'Glissez un fichier ou cliquer pour mettre à jour le fichier',
@@ -288,7 +289,7 @@ return [
'templates_explain_set_as_template' => 'Vous pouvez définir cette page comme modèle pour que son contenu soit utilisé lors de la création d\'autres pages. Les autres utilisateurs pourront utiliser ce modèle s\'ils ont les permissions pour cette page.',
'templates_replace_content' => 'Remplacer le contenu de la page',
'templates_append_content' => 'Ajouter après le contenu de la page',
'templates_prepend_content' => 'Ajouter devant le contenu de la page',
'templates_prepend_content' => 'Ajouter avant le contenu de la page',
// Profile View
'profile_user_for_x' => 'Utilisateur depuis :time',
@@ -313,7 +314,7 @@ return [
'comment_deleted_success' => 'Commentaire supprimé',
'comment_created_success' => 'Commentaire ajouté',
'comment_updated_success' => 'Commentaire mis à jour',
'comment_delete_confirm' => 'Etes-vous sûr de vouloir supprimer ce commentaire ?',
'comment_delete_confirm' => 'Êtes-vous sûr de vouloir supprimer ce commentaire ?',
'comment_in_reply_to' => 'En réponse à :commentId',
// Revision

View File

@@ -16,24 +16,24 @@ return [
'email_confirmation_awaiting' => 'L\'adresse e-mail du compte utilisé doit être confirmée',
'ldap_fail_anonymous' => 'L\'accès LDAP anonyme n\'a pas abouti',
'ldap_fail_authed' => 'L\'accès LDAP n\'a pas abouti avec cet utilisateur et ce mot de passe',
'ldap_extension_not_installed' => 'L\'extension LDAP PHP n\'est pas installée',
'ldap_extension_not_installed' => 'L\'extension PHP LDAP n\'est pas installée',
'ldap_cannot_connect' => 'Impossible de se connecter au serveur LDAP, la connexion initiale a échoué',
'saml_already_logged_in' => 'Déjà connecté',
'saml_user_not_registered' => 'L\'utilisateur :name n\'est pas enregistré et l\'enregistrement automatique est désactivé',
'saml_no_email_address' => 'Impossible de trouver une adresse e-mail, pour cet utilisateur, dans les données fournies par le système d\'authentification externe',
'saml_invalid_response_id' => 'La requête du système d\'authentification externe n\'est pas reconnue par un processus démarré par cette application. Naviguer après une connexion peut causer ce problème.',
'saml_fail_authed' => 'Connexion avec :system échoue, le système n\'a pas fourni l\'autorisation réussie',
'saml_fail_authed' => 'Connexion avec :system échouée, le système n\'a pas fourni l\'autorisation réussie',
'social_no_action_defined' => 'Pas d\'action définie',
'social_login_bad_response' => "Erreur pendant la tentative de connexion à :socialAccount : \n:error",
'social_account_in_use' => 'Ce compte :socialAccount est déjà utilisé. Essayez de vous connecter via :socialAccount.',
'social_account_email_in_use' => 'L\'email :email est déjà utilisé. Si vous avez déjà un compte :socialAccount, vous pouvez le joindre à votre profil existant.',
'social_account_email_in_use' => 'L\'email :email est déjà utilisé. Si vous avez déjà un compte :socialAccount, vous pouvez le rattacher à votre profil existant.',
'social_account_existing' => 'Ce compte :socialAccount est déjà rattaché à votre profil.',
'social_account_already_used_existing' => 'Ce compte :socialAccount est déjà utilisé par un autre utilisateur.',
'social_account_not_used' => 'Ce compte :socialAccount n\'est lié à aucun utilisateur. ',
'social_account_register_instructions' => 'Si vous n\'avez pas encore de compte, vous pouvez le lier avec l\'option :socialAccount.',
'social_driver_not_found' => 'Pilote de compte social absent',
'social_account_register_instructions' => 'Si vous n\'avez pas encore de compte, vous pouvez en créer un avec l\'option :socialAccount.',
'social_driver_not_found' => 'Pilote de compte de réseaux sociaux absent',
'social_driver_not_configured' => 'Vos préférences pour le compte :socialAccount sont incorrectes.',
'invite_token_expired' => 'Le lien de cette invitation a expiré. Vous pouvez essayer de réinitiliser votre mot de passe.',
'invite_token_expired' => 'Le lien de cette invitation a expiré. Vous pouvez essayer de réinitialiser votre mot de passe.',
// System
'path_not_writable' => 'Impossible d\'écrire dans :filePath. Assurez-vous d\'avoir les droits d\'écriture sur le serveur',
@@ -42,14 +42,14 @@ return [
'server_upload_limit' => 'La taille du fichier est trop grande.',
'uploaded' => 'Le serveur n\'autorise pas l\'envoi d\'un fichier de cette taille. Veuillez essayer avec une taille de fichier réduite.',
'image_upload_error' => 'Une erreur est survenue pendant l\'envoi de l\'image',
'image_upload_type_error' => 'LE format de l\'image envoyée n\'est pas valide',
'image_upload_type_error' => 'Le format de l\'image envoyée n\'est pas valide',
'file_upload_timeout' => 'Le téléchargement du fichier a expiré.',
// Attachments
'attachment_not_found' => 'Fichier joint non trouvé',
// Pages
'page_draft_autosave_fail' => 'Le brouillon n\'a pas pu être sauvé. Vérifiez votre connexion internet',
'page_draft_autosave_fail' => 'Le brouillon n\'a pas pu être enregistré. Vérifiez votre connexion internet',
'page_custom_home_deletion' => 'Impossible de supprimer une page définie comme page d\'accueil',
// Entities
@@ -60,10 +60,10 @@ return [
'chapter_not_found' => 'Chapitre non trouvé',
'selected_book_not_found' => 'Ce livre n\'a pas été trouvé',
'selected_book_chapter_not_found' => 'Ce livre ou chapitre n\'a pas été trouvé',
'guests_cannot_save_drafts' => 'Les invités ne peuvent pas sauver de brouillons',
'guests_cannot_save_drafts' => 'Les invités ne peuvent pas enregistrer de brouillons',
// Users
'users_cannot_delete_only_admin' => 'Vous ne pouvez pas supprimer le dernier admin',
'users_cannot_delete_only_admin' => 'Vous ne pouvez pas supprimer le dernier administrateur',
'users_cannot_delete_guest' => 'Vous ne pouvez pas supprimer l\'utilisateur invité',
// Roles
@@ -74,7 +74,7 @@ return [
// Comments
'comment_list' => 'Une erreur s\'est produite lors de la récupération des commentaires.',
'cannot_add_comment_to_draft' => 'Vous ne pouvez pas ajouter de commentaires à un projet.',
'cannot_add_comment_to_draft' => 'Vous ne pouvez pas ajouter de commentaires à un brouillon.',
'comment_add' => 'Une erreur s\'est produite lors de l\'ajout du commentaire.',
'comment_delete' => 'Une erreur s\'est produite lors de la suppression du commentaire.',
'empty_comment' => 'Impossible d\'ajouter un commentaire vide.',
@@ -82,10 +82,10 @@ return [
// Error pages
'404_page_not_found' => 'Page non trouvée',
'sorry_page_not_found' => 'Désolé, cette page n\'a pas pu être trouvée.',
'sorry_page_not_found_permission_warning' => 'Si vous vous attendiez à ce que cette page existe, il se peut que vous n\'ayez pas l\'autorisation de la consulter.',
'sorry_page_not_found_permission_warning' => 'Si cette page est censée exister, il se peut que vous n\'ayez pas l\'autorisation de la consulter.',
'image_not_found' => 'Image non trouvée',
'image_not_found_subtitle' => 'Désolé, l\'image que vous cherchez ne peut être trouvée.',
'image_not_found_details' => 'Si vous vous attendiez à ce que cette image existe, elle pourrait avoir été supprimée.',
'image_not_found_details' => 'Si cette image était censée exister, il se pourrait qu\'elle ait été supprimée.',
'return_home' => 'Retour à l\'accueil',
'error_occurred' => 'Une erreur est survenue',
'app_down' => ':appName n\'est pas en service pour le moment',
@@ -96,7 +96,7 @@ return [
'api_bad_authorization_format' => 'Un jeton d\'autorisation a été trouvé pour la requête, mais le format semble incorrect',
'api_user_token_not_found' => 'Aucun jeton API correspondant n\'a été trouvé pour le jeton d\'autorisation fourni',
'api_incorrect_token_secret' => 'Le secret fourni pour le jeton d\'API utilisé est incorrect',
'api_user_no_api_permission' => 'Le propriétaire du jeton API utilisé n\'a pas la permission de passer des appels API',
'api_user_no_api_permission' => 'Le propriétaire du jeton API utilisé n\'a pas la permission de passer des requêtes API',
'api_user_token_expired' => 'Le jeton d\'autorisation utilisé a expiré',
// Settings & Maintenance

View File

@@ -6,10 +6,10 @@
*/
return [
'password' => 'Les mots de passe doivent faire au moins 6 caractères et correspondre à la confirmation.',
'password' => 'Les mots de passe doivent faire au moins 8 caractères et correspondre à la confirmation.',
'user' => "Nous n'avons pas trouvé d'utilisateur avec cette adresse.",
'token' => 'Le mot de passe reset du token n\'est pas valide pour cette adresse e-mail.',
'sent' => 'Nous vous avons envoyé un lien de réinitialisation de mot de passe !',
'sent' => 'Nous vous avons envoyé un lien de réinitialisation de mot de passe par e-mail !',
'reset' => 'Votre mot de passe a été réinitialisé !',
];

View File

@@ -21,15 +21,15 @@ return [
'app_public_access_desc' => 'L\'activation de cette option permettra aux visiteurs, qui ne sont pas connectés, d\'accéder au contenu de votre instance BookStack.',
'app_public_access_desc_guest' => 'L\'accès pour les visiteurs publics peut être contrôlé par l\'utilisateur "Guest".',
'app_public_access_toggle' => 'Autoriser l\'accès public',
'app_public_viewing' => 'Accepter le visionnage public des pages ?',
'app_secure_images' => 'Activer l\'ajout d\'image sécurisé ?',
'app_public_viewing' => 'Accepter l\'affichage public des pages ?',
'app_secure_images' => 'Ajout d\'image sécurisé',
'app_secure_images_toggle' => 'Activer l\'ajout d\'image sécurisé',
'app_secure_images_desc' => 'Pour des questions de performances, toutes les images sont publiques. Cette option ajoute une chaîne aléatoire difficile à deviner dans les URLs des images.',
'app_editor' => 'Éditeur des pages',
'app_editor_desc' => 'Sélectionnez l\'éditeur qui sera utilisé pour modifier les pages.',
'app_custom_html' => 'HTML personnalisé dans l\'en-tête',
'app_custom_html_desc' => 'Le contenu inséré ici sera ajouté en bas de la balise <head> de toutes les pages. Vous pouvez l\'utiliser pour ajouter du CSS personnalisé ou un tracker analytique.',
'app_custom_html_disabled_notice' => 'Le contenu de la tête HTML personnalisée est désactivé sur cette page de paramètres pour garantir que les modifications les plus récentes peuvent être annulées.',
'app_custom_html_disabled_notice' => 'Le contenu de l\'en-tête HTML personnalisé est désactivé sur cette page de paramètres pour garantir que les modifications les plus récentes puissent être annulées.',
'app_logo' => 'Logo de l\'application',
'app_logo_desc' => 'Cette image doit faire 43px de hauteur. <br>Les images plus larges seront réduites.',
'app_primary_color' => 'Couleur principale de l\'application',
@@ -38,7 +38,7 @@ return [
'app_homepage_desc' => 'Choisissez une page à afficher sur la page d\'accueil au lieu de la vue par défaut. Les permissions sont ignorées pour les pages sélectionnées.',
'app_homepage_select' => 'Choisissez une page',
'app_footer_links' => 'Liens de pied de page',
'app_footer_links_desc' => 'Ajoutez des liens dans le pied de page du site. Ils seront affichés en bas de la plupart des pages, incluant celles qui ne nécesittent pas de connexion. Vous pouvez utiliser l\'étiquette "trans::<key>" pour utiliser les traductions définies par le système. Par exemple, utiliser "trans::common.privacy_policy" fournira la traduction de "Politique de Confidentalité" et "trans::common.terms_of_service" fournira la traduction de "Conditions d\'utilisation".',
'app_footer_links_desc' => 'Ajouter des liens à afficher dans le pied de page du site. Ils seront affichés en bas de la plupart des pages, y compris celles qui ne nécessitent pas de connexion. Vous pouvez utiliser une étiquette de "trans::<key>" pour utiliser les traductions définies par le système. Par exemple : utiliser "trans::common.privacy_policy" fournira le texte traduit "Privacy Policy" et "trans::common.terms_of_service" fournira le texte traduit "Terms of Service".',
'app_footer_links_label' => 'Libellé du lien',
'app_footer_links_url' => 'URL du lien',
'app_footer_links_add' => 'Ajouter un lien en pied de page',
@@ -49,11 +49,11 @@ return [
// Color settings
'content_colors' => 'Couleur du contenu',
'content_colors_desc' => 'Définit les couleurs pour tous les éléments de la hiérarchie d\'organisation des pages. Choisir les couleurs avec une luminosité similaire aux couleurs par défaut est recommandé pour la lisibilité.',
'bookshelf_color' => 'Couleur de l\'étagère',
'book_color' => 'Couleur du livre',
'chapter_color' => 'Couleur du chapitre',
'page_color' => 'Couleur de la page',
'page_draft_color' => 'Couleur du brouillon',
'bookshelf_color' => 'Couleur des étagères',
'book_color' => 'Couleur des livres',
'chapter_color' => 'Couleur des chapitres',
'page_color' => 'Couleur des pages',
'page_draft_color' => 'Couleur des brouillons',
// Registration Settings
'reg_settings' => 'Préférence pour l\'inscription',
@@ -72,19 +72,19 @@ return [
// Maintenance settings
'maint' => 'Maintenance',
'maint_image_cleanup' => 'Nettoyer les images',
'maint_image_cleanup_desc' => "Scan le contenu des pages et des révisions pour vérifier les images et les dessins en cours d'utilisation et lesquels sont redondant. Veuillez à faire une sauvegarde de la base de données et des images avant de lancer ceci.",
'maint_image_cleanup_desc' => "Scanne le contenu des pages et des révisions pour vérifier les images, les dessins en cours d'utilisation et les doublons. Assurez-vous d'avoir une sauvegarde de la base de données et des images avant de lancer ceci.",
'maint_delete_images_only_in_revisions' => 'Supprimer également les images qui n\'existent que dans les anciennes révisions de page',
'maint_image_cleanup_run' => 'Lancer le nettoyage',
'maint_image_cleanup_warning' => ':count images potentiellement inutilisées trouvées. Etes-vous sûr de vouloir supprimer ces images ?',
'maint_image_cleanup_warning' => ':count images potentiellement inutilisées trouvées. Êtes-vous sûr de vouloir supprimer ces images ?',
'maint_image_cleanup_success' => ':count images potentiellement inutilisées trouvées et supprimées !',
'maint_image_cleanup_nothing_found' => 'Aucune image inutilisée trouvée, rien à supprimer !',
'maint_send_test_email' => 'Envoyer un email de test',
'maint_send_test_email' => 'Envoyer un e-mail de test',
'maint_send_test_email_desc' => 'Ceci envoie un e-mail de test à votre adresse e-mail spécifiée dans votre profil.',
'maint_send_test_email_run' => 'Envoyer un email de test',
'maint_send_test_email_success' => 'Email envoyé à :address',
'maint_send_test_email_mail_subject' => 'Email de test',
'maint_send_test_email_mail_greeting' => 'La livraison d\'email semble fonctionner !',
'maint_send_test_email_mail_text' => 'Félicitations ! Lorsque vous avez reçu cette notification par courriel, vos paramètres d\'email semblent être configurés correctement.',
'maint_send_test_email_run' => 'Envoyer un e-mail de test',
'maint_send_test_email_success' => 'E-mail envoyé à :address',
'maint_send_test_email_mail_subject' => 'E-mail de test',
'maint_send_test_email_mail_greeting' => 'L\'envoi d\'e-mail semble fonctionner !',
'maint_send_test_email_mail_text' => 'Félicitations ! Comme vous avez bien reçu cette notification, vos paramètres d\'e-mail semblent être configurés correctement.',
'maint_recycle_bin_desc' => 'Les étagères, livres, chapitres et pages supprimés sont envoyés dans la corbeille afin qu\'ils puissent être restaurés ou supprimés définitivement. Les éléments plus anciens de la corbeille peuvent être supprimés automatiquement après un certain temps selon la configuration du système.',
'maint_recycle_bin_open' => 'Ouvrir la corbeille',
@@ -98,7 +98,7 @@ return [
'recycle_bin_permanently_delete' => 'Supprimer définitivement',
'recycle_bin_restore' => 'Restaurer',
'recycle_bin_contents_empty' => 'La corbeille est vide',
'recycle_bin_empty' => 'Vider la Corbeille',
'recycle_bin_empty' => 'Vider la corbeille',
'recycle_bin_empty_confirm' => 'Cela détruira définitivement tous les éléments de la corbeille, y compris le contenu contenu de chaque élément. Êtes-vous sûr de vouloir vider la corbeille ?',
'recycle_bin_destroy_confirm' => 'Cette action supprimera définitivement cet élément, ainsi que tous les éléments enfants listés ci-dessous du système et vous ne pourrez pas restaurer ce contenu. Êtes-vous sûr de vouloir supprimer définitivement cet élément ?',
'recycle_bin_destroy_list' => 'Éléments à détruire',
@@ -117,9 +117,10 @@ return [
'audit_deleted_item' => 'Élément supprimé',
'audit_deleted_item_name' => 'Nom: :name',
'audit_table_user' => 'Utilisateur',
'audit_table_event' => 'Evènement',
'audit_table_related' => 'Élément ou détail lié',
'audit_table_date' => 'Date d\'activation',
'audit_table_event' => 'Événement',
'audit_table_related' => 'Élément concerné ou action réalisée',
'audit_table_ip' => 'Adresse IP',
'audit_table_date' => 'Horodatage',
'audit_date_from' => 'À partir du',
'audit_date_to' => 'Jusqu\'au',
@@ -148,9 +149,9 @@ return [
'role_manage_page_templates' => 'Gérer les modèles de page',
'role_access_api' => 'Accès à l\'API du système',
'role_manage_settings' => 'Gérer les préférences de l\'application',
'role_export_content' => 'Export content',
'role_export_content' => 'Exporter le contenu',
'role_asset' => 'Permissions des ressources',
'roles_system_warning' => 'Sachez que l\'accès à l\'une des trois permissions ci-dessus peut permettre à un utilisateur de modifier ses propres privilèges ou les privilèges des autres utilisateurs du système. Attribuer uniquement des rôles avec ces permissions à des utilisateurs de confiance.',
'roles_system_warning' => 'Sachez que l\'accès à l\'une des trois permissions ci-dessus peut permettre à un utilisateur de modifier ses propres privilèges ou les privilèges des autres utilisateurs du système. N\'attribuez uniquement des rôles avec ces permissions qu\'à des utilisateurs de confiance.',
'role_asset_desc' => 'Ces permissions contrôlent l\'accès par défaut des ressources dans le système. Les permissions dans les livres, les chapitres et les pages ignoreront ces permissions',
'role_asset_admins' => 'Les administrateurs ont automatiquement accès à tous les contenus mais les options suivantes peuvent afficher ou masquer certaines options de l\'interface.',
'role_all' => 'Tous',
@@ -165,7 +166,7 @@ return [
'users' => 'Utilisateurs',
'user_profile' => 'Profil d\'utilisateur',
'users_add_new' => 'Ajouter un nouvel utilisateur',
'users_search' => 'Chercher les utilisateurs',
'users_search' => 'Rechercher les utilisateurs',
'users_latest_activity' => 'Dernière activité',
'users_details' => 'Informations de l\'utilisateur',
'users_details_desc' => 'Définissez un nom et une adresse e-mail pour cet utilisateur. L\'adresse e-mail sera utilisée pour se connecter à l\'application.',
@@ -173,20 +174,20 @@ return [
'users_role' => 'Rôles de l\'utilisateur',
'users_role_desc' => 'Sélectionnez les rôles auxquels cet utilisateur sera affecté. Si un utilisateur est affecté à plusieurs rôles, les permissions de ces rôles s\'empileront et ils recevront toutes les capacités des rôles affectés.',
'users_password' => 'Mot de passe de l\'utilisateur',
'users_password_desc' => 'Définissez un mot de passe utilisé pour vous connecter à l\'application. Il doit comporter au moins 5 caractères.',
'users_send_invite_text' => 'Vous pouvez choisir d\'envoyer à cet utilisateur un email d\'invitation qui lui permet de définir son propre mot de passe, sinon vous pouvez définir son mot de passe vous-même.',
'users_password_desc' => 'Définissez un mot de passe utilisé pour vous connecter à l\'application. Il doit comporter au moins 6 caractères.',
'users_send_invite_text' => 'Vous pouvez choisir d\'envoyer à cet utilisateur un e-mail d\'invitation qui lui permet de définir son propre mot de passe, sinon vous pouvez définir son mot de passe vous-même.',
'users_send_invite_option' => 'Envoyer l\'e-mail d\'invitation',
'users_external_auth_id' => 'Identifiant d\'authentification externe',
'users_external_auth_id_desc' => 'C\'est l\'ID utilisé pour correspondre à cet utilisateur lors de la communication avec votre système d\'authentification externe.',
'users_password_warning' => 'Remplissez ce formulaire uniquement si vous souhaitez changer de mot de passe:',
'users_password_warning' => 'Remplissez ce formulaire uniquement si vous souhaitez changer de mot de passe :',
'users_system_public' => 'Cet utilisateur représente les invités visitant votre instance. Il est assigné automatiquement aux invités.',
'users_delete' => 'Supprimer un utilisateur',
'users_delete_named' => 'Supprimer l\'utilisateur :userName',
'users_delete_warning' => 'Ceci va supprimer \':userName\' du système.',
'users_delete_confirm' => 'Êtes-vous sûr(e) de vouloir supprimer cet utilisateur ?',
'users_migrate_ownership' => 'Migré propriété',
'users_migrate_ownership' => 'Transférer la propriété',
'users_migrate_ownership_desc' => 'Sélectionnez un utilisateur ici si vous voulez qu\'un autre utilisateur devienne le propriétaire de tous les éléments actuellement détenus par cet utilisateur.',
'users_none_selected' => 'Aucun utilisateur n\'a été séléctionné',
'users_none_selected' => 'Aucun utilisateur n\'a été sélectionné',
'users_delete_success' => 'Utilisateur supprimé avec succès',
'users_edit' => 'Modifier l\'utilisateur',
'users_edit_profile' => 'Modifier le profil',
@@ -195,20 +196,20 @@ return [
'users_avatar_desc' => 'Cette image doit être un carré d\'environ 256 px.',
'users_preferred_language' => 'Langue préférée',
'users_preferred_language_desc' => 'Cette option changera la langue utilisée pour l\'interface utilisateur de l\'application. Ceci n\'affectera aucun contenu créé par l\'utilisateur.',
'users_social_accounts' => 'Comptes sociaux',
'users_social_accounts' => 'Réseaux sociaux',
'users_social_accounts_info' => 'Vous pouvez connecter des réseaux sociaux à votre compte pour vous connecter plus rapidement. Déconnecter un compte n\'enlèvera pas les accès autorisés précédemment sur votre compte de réseau social.',
'users_social_connect' => 'Connecter le compte',
'users_social_disconnect' => 'Déconnecter le compte',
'users_social_connected' => 'Votre compte :socialAccount a été ajouté avec succès.',
'users_social_disconnected' => 'Votre compte :socialAccount a été déconnecté avec succès',
'users_api_tokens' => 'Jetons de l\'API',
'users_api_tokens' => 'Jetons API',
'users_api_tokens_none' => 'Aucun jeton API n\'a été créé pour cet utilisateur',
'users_api_tokens_create' => 'Créer un jeton',
'users_api_tokens_expires' => 'Expiré',
'users_api_tokens_docs' => 'Documentation de l\'API',
'users_mfa' => 'Authentification multi-facteurs',
'users_mfa_desc' => 'Configurez l\'authentification multi-facteurs ajoute une couche supplémentaire de sécurité à votre compte utilisateur.',
'users_mfa_x_methods' => ':count method configured|:count methods configured',
'users_mfa_desc' => 'Configurer l\'authentification multi-facteurs ajoute une couche supplémentaire de sécurité à votre compte utilisateur.',
'users_mfa_x_methods' => ':count méthode configurée|:count méthodes configurées',
'users_mfa_configure' => 'Méthode de configuration',
// API Tokens
@@ -218,19 +219,19 @@ return [
'user_api_token_expiry' => 'Date d\'expiration',
'user_api_token_expiry_desc' => 'Définissez une date à laquelle ce jeton expire. Après cette date, les demandes effectuées à l\'aide de ce jeton ne fonctionneront plus. Le fait de laisser ce champ vide entraînera une expiration dans 100 ans.',
'user_api_token_create_secret_message' => 'Immédiatement après la création de ce jeton, un "ID de jeton" "et" Secret de jeton "sera généré et affiché. Le secret ne sera affiché qu\'une seule fois, alors assurez-vous de copier la valeur dans un endroit sûr et sécurisé avant de continuer.',
'user_api_token_create_success' => 'L\'API token a été créé avec succès',
'user_api_token_update_success' => 'L\'API token a été mis à jour avec succès',
'user_api_token' => 'Token API',
'user_api_token_create_success' => 'Le jeton API a été créé avec succès',
'user_api_token_update_success' => 'Le jeton API a été mis à jour avec succès',
'user_api_token' => 'Jeton API',
'user_api_token_id' => 'Token ID',
'user_api_token_id_desc' => 'Il s\'agit d\'un identifiant généré par le système non modifiable pour ce jeton qui devra être fourni dans les demandes d\'API.',
'user_api_token_secret' => 'Token Secret',
'user_api_token_secret_desc' => 'Il s\'agit d\'un secret généré par le système pour ce jeton, qui devra être fourni dans les demandes d\'API. Cela ne sera affiché qu\'une seule fois, alors copiez cette valeur dans un endroit sûr et sécurisé.',
'user_api_token_created' => 'Jeton créé :timeAgo',
'user_api_token_updated' => 'Jeton mis à jour :timeAgo',
'user_api_token_delete' => 'Supprimer le Token',
'user_api_token_delete' => 'Supprimer le jeton',
'user_api_token_delete_warning' => 'Cela supprimera complètement le jeton d\'API avec le nom \':tokenName\'.',
'user_api_token_delete_confirm' => 'Souhaitez-vous vraiment effacer l\'API Token ?',
'user_api_token_delete_success' => 'L\'API token a été supprimé avec succès',
'user_api_token_delete_confirm' => 'Souhaitez-vous vraiment effacer ce jeton API ?',
'user_api_token_delete_success' => 'Le jeton API a été supprimé avec succès',
//! If editing translations files directly please ignore this in all
//! languages apart from en. Content will be auto-copied from en.

View File

@@ -19,7 +19,7 @@ return [
'before' => ':attribute doit être inférieur à :date.',
'between' => [
'numeric' => ':attribute doit être compris entre :min et :max.',
'file' => ':attribute doit être compris entre :min et :max kilobytes.',
'file' => ':attribute doit être compris entre :min et :max Ko.',
'string' => ':attribute doit être compris entre :min et :max caractères.',
'array' => ':attribute doit être compris entre :min et :max éléments.',
],
@@ -35,13 +35,13 @@ return [
'filled' => ':attribute est un champ requis.',
'gt' => [
'numeric' => ':attribute doit être plus grand que :value.',
'file' => ':attribute doit être plus grand que :value kilobytes.',
'file' => ':attribute doit être plus grand que :value Ko.',
'string' => ':attribute doit être plus grand que :value caractères.',
'array' => ':attribute doit avoir plus que :value éléments.',
],
'gte' => [
'numeric' => ':attribute doit être plus grand ou égal à :value.',
'file' => ':attribute doit être plus grand ou égal à :value kilobytes.',
'file' => ':attribute doit être plus grand ou égal à :value Ko.',
'string' => ':attribute doit être plus grand ou égal à :value caractères.',
'array' => ':attribute doit avoir :value éléments ou plus.',
],
@@ -53,22 +53,22 @@ return [
'ip' => ':attribute doit être une adresse IP valide.',
'ipv4' => ':attribute doit être une adresse IPv4 valide.',
'ipv6' => ':attribute doit être une adresse IPv6 valide.',
'json' => ':attribute doit être une chaine JSON valide.',
'json' => ':attribute doit être une chaîne JSON valide.',
'lt' => [
'numeric' => ':attribute doit être plus petit que :value.',
'file' => ':attribute doit être plus petit que :value kilobytes.',
'file' => ':attribute doit être plus petit que :value Ko.',
'string' => ':attribute doit être plus petit que :value caractères.',
'array' => ':attribute doit avoir moins de :value éléments.',
],
'lte' => [
'numeric' => ':attribute doit être plus petit ou égal à :value.',
'file' => ':attribute doit être plus petit ou égal à :value kilobytes.',
'file' => ':attribute doit être plus petit ou égal à :value Ko.',
'string' => ':attribute doit être plus petit ou égal à :value caractères.',
'array' => ':attribute ne doit pas avoir plus de :value éléments.',
],
'max' => [
'numeric' => ':attribute ne doit pas excéder :max.',
'file' => ':attribute ne doit pas excéder :max kilobytes.',
'file' => ':attribute ne doit pas excéder :max Ko.',
'string' => ':attribute ne doit pas excéder :max caractères.',
'array' => ':attribute ne doit pas contenir plus de :max éléments.',
],

View File

@@ -234,6 +234,7 @@ return [
'pages_initial_name' => 'דף חדש',
'pages_editing_draft_notification' => 'הינך עורך טיוטה אשר נשמרה לאחרונה ב :timeDiff',
'pages_draft_edited_notification' => 'דף זה עודכן מאז, מומלץ להתעלם מהטיוטה הזו.',
'pages_draft_page_changed_since_creation' => 'This page has been updated since this draft was created. It is recommended that you discard this draft or take care not to overwrite any page changes.',
'pages_draft_edit_active' => [
'start_a' => ':count משתמשים החלו לערוך דף זה',
'start_b' => ':userName החל לערוך דף זה',

View File

@@ -119,6 +119,7 @@ return [
'audit_table_user' => 'משתמש',
'audit_table_event' => 'אירוע',
'audit_table_related' => 'פריט או פרט קשור',
'audit_table_ip' => 'IP Address',
'audit_table_date' => 'זמן הפעילות',
'audit_date_from' => 'טווח תאריכים החל מ...',
'audit_date_to' => 'טווח תאריכים עד ל...',

View File

@@ -234,6 +234,7 @@ return [
'pages_initial_name' => 'Nova stranica',
'pages_editing_draft_notification' => 'Uređujete nacrt stranice posljednji put spremljen :timeDiff.',
'pages_draft_edited_notification' => 'Ova je stranica u međuvremenu ažurirana. Preporučujemo da odbacite ovaj nacrt.',
'pages_draft_page_changed_since_creation' => 'This page has been updated since this draft was created. It is recommended that you discard this draft or take care not to overwrite any page changes.',
'pages_draft_edit_active' => [
'start_a' => ':count korisnika koji uređuju ovu stranicu',
'start_b' => ':userName je počeo uređivati ovu stranicu',

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