diff --git a/.github/translators.txt b/.github/translators.txt index d7db20fc4..ec38b3342 100644 --- a/.github/translators.txt +++ b/.github/translators.txt @@ -280,3 +280,11 @@ DerLinkman (derlinkman) :: German; German Informal TurnArabic :: Arabic Martin Sebek (sebekmartin) :: Czech Kuchinashi Hoshikawa (kuchinashi) :: Chinese Simplified +digilady :: Greek +Linus (LinusOP) :: Swedish +Felipe Cardoso (felipecardosoruff) :: Portuguese, Brazilian +RandomUser0815 :: German +Ismael Mesquita (mesquitoliveira) :: Portuguese, Brazilian +구인회 (laskdjlaskdj12) :: Korean +LiZerui (CNLiZerui) :: Chinese Traditional +Fabrice Boyer (FabriceBoyer) :: French diff --git a/LICENSE b/LICENSE index 0ec2e91ab..5b3d8699a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,6 @@ The MIT License (MIT) -Copyright (c) 2015-present, Dan Brown and the BookStack Project contributors -https://github.com/BookStackApp/BookStack/graphs/contributors +Copyright (c) 2015-2022, Dan Brown and the BookStack Project contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/app/Actions/TagRepo.php b/app/Actions/TagRepo.php index 172d8ec6e..2618ed2e9 100644 --- a/app/Actions/TagRepo.php +++ b/app/Actions/TagRepo.php @@ -57,21 +57,21 @@ class TagRepo * Get tag name suggestions from scanning existing tag names. * If no search term is given the 50 most popular tag names are provided. */ - public function getNameSuggestions(?string $searchTerm): Collection + public function getNameSuggestions(string $searchTerm): Collection { $query = Tag::query() ->select('*', DB::raw('count(*) as count')) ->groupBy('name'); if ($searchTerm) { - $query = $query->where('name', 'LIKE', $searchTerm . '%')->orderBy('name', 'desc'); + $query = $query->where('name', 'LIKE', $searchTerm . '%')->orderBy('name', 'asc'); } else { $query = $query->orderBy('count', 'desc')->take(50); } $query = $this->permissions->restrictEntityRelationQuery($query, 'tags', 'entity_id', 'entity_type'); - return $query->get(['name'])->pluck('name'); + return $query->pluck('name'); } /** @@ -79,7 +79,7 @@ class TagRepo * If no search is given the 50 most popular values are provided. * Passing a tagName will only find values for a tags with a particular name. */ - public function getValueSuggestions(?string $searchTerm, ?string $tagName): Collection + public function getValueSuggestions(string $searchTerm, string $tagName): Collection { $query = Tag::query() ->select('*', DB::raw('count(*) as count')) @@ -97,7 +97,7 @@ class TagRepo $query = $this->permissions->restrictEntityRelationQuery($query, 'tags', 'entity_id', 'entity_type'); - return $query->get(['value'])->pluck('value'); + return $query->pluck('value'); } /** diff --git a/app/Api/ApiEntityListFormatter.php b/app/Api/ApiEntityListFormatter.php new file mode 100644 index 000000000..c170ecf0c --- /dev/null +++ b/app/Api/ApiEntityListFormatter.php @@ -0,0 +1,107 @@ + + */ + protected $fields = [ + 'id', 'name', 'slug', 'book_id', 'chapter_id', + 'draft', 'template', 'created_at', 'updated_at', + ]; + + public function __construct(array $list) + { + $this->list = $list; + + // Default dynamic fields + $this->withField('url', fn(Entity $entity) => $entity->getUrl()); + } + + /** + * Add a field to be used in the formatter, with the property using the given + * name and value being the return type of the given callback. + */ + public function withField(string $property, callable $callback): self + { + $this->fields[$property] = $callback; + return $this; + } + + /** + * Show the 'type' property in the response reflecting the entity type. + * EG: page, chapter, bookshelf, book + * To be included in results with non-pre-determined types. + */ + public function withType(): self + { + $this->withField('type', fn(Entity $entity) => $entity->getType()); + return $this; + } + + /** + * Include tags in the formatted data. + */ + public function withTags(): self + { + $this->withField('tags', fn(Entity $entity) => $entity->tags); + return $this; + } + + /** + * Format the data and return an array of formatted content. + * @return array[] + */ + public function format(): array + { + $results = []; + + foreach ($this->list as $item) { + $results[] = $this->formatSingle($item); + } + + return $results; + } + + /** + * Format a single entity item to a plain array. + */ + protected function formatSingle(Entity $entity): array + { + $result = []; + $values = (clone $entity)->toArray(); + + foreach ($this->fields as $field => $callback) { + if (is_string($callback)) { + $field = $callback; + if (!isset($values[$field])) { + continue; + } + $value = $values[$field]; + } else { + $value = $callback($entity); + if (is_null($value)) { + continue; + } + } + + $result[$field] = $value; + } + + return $result; + } +} diff --git a/app/Api/ListingResponseBuilder.php b/app/Api/ListingResponseBuilder.php index 7de5ddf07..39752e6d4 100644 --- a/app/Api/ListingResponseBuilder.php +++ b/app/Api/ListingResponseBuilder.php @@ -2,7 +2,6 @@ namespace BookStack\Api; -use BookStack\Model; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; use Illuminate\Http\JsonResponse; diff --git a/app/Auth/Access/LoginService.php b/app/Auth/Access/LoginService.php index f41570417..c80943166 100644 --- a/app/Auth/Access/LoginService.php +++ b/app/Auth/Access/LoginService.php @@ -5,6 +5,7 @@ namespace BookStack\Auth\Access; use BookStack\Actions\ActivityType; use BookStack\Auth\Access\Mfa\MfaSession; use BookStack\Auth\User; +use BookStack\Exceptions\LoginAttemptException; use BookStack\Exceptions\StoppedAuthenticationException; use BookStack\Facades\Activity; use BookStack\Facades\Theme; @@ -149,6 +150,7 @@ class LoginService * May interrupt the flow if extra authentication requirements are imposed. * * @throws StoppedAuthenticationException + * @throws LoginAttemptException */ public function attempt(array $credentials, string $method, bool $remember = false): bool { diff --git a/app/Auth/Access/Saml2Service.php b/app/Auth/Access/Saml2Service.php index b0bf39995..a95e3b1d2 100644 --- a/app/Auth/Access/Saml2Service.php +++ b/app/Auth/Access/Saml2Service.php @@ -20,14 +20,11 @@ use OneLogin\Saml2\ValidationError; */ class Saml2Service { - protected $config; - protected $registrationService; - protected $loginService; - protected $groupSyncService; + protected array $config; + protected RegistrationService $registrationService; + protected LoginService $loginService; + protected GroupSyncService $groupSyncService; - /** - * Saml2Service constructor. - */ public function __construct( RegistrationService $registrationService, LoginService $loginService, @@ -169,7 +166,7 @@ class Saml2Service */ public function metadata(): string { - $toolKit = $this->getToolkit(); + $toolKit = $this->getToolkit(true); $settings = $toolKit->getSettings(); $metadata = $settings->getSPMetadata(); $errors = $settings->validateMetadata($metadata); @@ -190,7 +187,7 @@ class Saml2Service * @throws Error * @throws Exception */ - protected function getToolkit(): Auth + protected function getToolkit(bool $spOnly = false): Auth { $settings = $this->config['onelogin']; $overrides = $this->config['onelogin_overrides'] ?? []; @@ -200,14 +197,14 @@ class Saml2Service } $metaDataSettings = []; - if ($this->config['autoload_from_metadata']) { + if (!$spOnly && $this->config['autoload_from_metadata']) { $metaDataSettings = IdPMetadataParser::parseRemoteXML($settings['idp']['entityId']); } $spSettings = $this->loadOneloginServiceProviderDetails(); $settings = array_replace_recursive($settings, $spSettings, $metaDataSettings, $overrides); - return new Auth($settings); + return new Auth($settings, $spOnly); } /** diff --git a/app/Auth/Permissions/EntityPermission.php b/app/Auth/Permissions/EntityPermission.php index 131771a38..32ebc440d 100644 --- a/app/Auth/Permissions/EntityPermission.php +++ b/app/Auth/Permissions/EntityPermission.php @@ -2,20 +2,41 @@ namespace BookStack\Auth\Permissions; +use BookStack\Auth\Role; use BookStack\Model; +use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\MorphTo; +/** + * @property int $id + * @property int $role_id + * @property int $entity_id + * @property string $entity_type + * @property boolean $view + * @property boolean $create + * @property boolean $update + * @property boolean $delete + */ class EntityPermission extends Model { - protected $fillable = ['role_id', 'action']; + public const PERMISSIONS = ['view', 'create', 'update', 'delete']; + + protected $fillable = ['role_id', 'view', 'create', 'update', 'delete']; public $timestamps = false; /** - * Get all this restriction's attached entity. - * - * @return \Illuminate\Database\Eloquent\Relations\MorphTo + * Get this restriction's attached entity. */ - public function restrictable() + public function restrictable(): MorphTo { return $this->morphTo('restrictable'); } + + /** + * Get the role assigned to this entity permission. + */ + public function role(): BelongsTo + { + return $this->belongsTo(Role::class); + } } diff --git a/app/Auth/Permissions/JointPermissionBuilder.php b/app/Auth/Permissions/JointPermissionBuilder.php index f377eef5c..79903c027 100644 --- a/app/Auth/Permissions/JointPermissionBuilder.php +++ b/app/Auth/Permissions/JointPermissionBuilder.php @@ -40,7 +40,7 @@ class JointPermissionBuilder }); // Chunk through all bookshelves - Bookshelf::query()->withTrashed()->select(['id', 'restricted', 'owned_by']) + Bookshelf::query()->withTrashed()->select(['id', 'owned_by']) ->chunk(50, function (EloquentCollection $shelves) use ($roles) { $this->createManyJointPermissions($shelves->all(), $roles); }); @@ -92,7 +92,7 @@ class JointPermissionBuilder }); // Chunk through all bookshelves - Bookshelf::query()->select(['id', 'restricted', 'owned_by']) + Bookshelf::query()->select(['id', 'owned_by']) ->chunk(50, function ($shelves) use ($roles) { $this->createManyJointPermissions($shelves->all(), $roles); }); @@ -138,12 +138,11 @@ class JointPermissionBuilder protected function bookFetchQuery(): Builder { return Book::query()->withTrashed() - ->select(['id', 'restricted', 'owned_by'])->with([ + ->select(['id', 'owned_by'])->with([ 'chapters' => function ($query) { - $query->withTrashed()->select(['id', 'restricted', 'owned_by', 'book_id']); }, 'pages' => function ($query) { - $query->withTrashed()->select(['id', 'restricted', 'owned_by', 'book_id', 'chapter_id']); + $query->withTrashed()->select(['id', 'owned_by', 'book_id', 'chapter_id']); }, ]); } @@ -218,7 +217,6 @@ class JointPermissionBuilder $simple = new SimpleEntityData(); $simple->id = $attrs['id']; $simple->type = $entity->getMorphClass(); - $simple->restricted = boolval($attrs['restricted'] ?? 0); $simple->owned_by = $attrs['owned_by'] ?? 0; $simple->book_id = $attrs['book_id'] ?? null; $simple->chapter_id = $attrs['chapter_id'] ?? null; @@ -240,21 +238,14 @@ class JointPermissionBuilder $this->readyEntityCache($entities); $jointPermissions = []; - // Create a mapping of entity restricted statuses - $entityRestrictedMap = []; - foreach ($entities as $entity) { - $entityRestrictedMap[$entity->type . ':' . $entity->id] = $entity->restricted; - } - // Fetch related entity permissions $permissions = $this->getEntityPermissionsForEntities($entities); // Create a mapping of explicit entity permissions $permissionMap = []; foreach ($permissions as $permission) { - $key = $permission->restrictable_type . ':' . $permission->restrictable_id . ':' . $permission->role_id; - $isRestricted = $entityRestrictedMap[$permission->restrictable_type . ':' . $permission->restrictable_id]; - $permissionMap[$key] = $isRestricted; + $key = $permission->entity_type . ':' . $permission->entity_id . ':' . $permission->role_id; + $permissionMap[$key] = $permission->view; } // Create a mapping of role permissions @@ -319,11 +310,10 @@ class JointPermissionBuilder { $idsByType = $this->entitiesToTypeIdMap($entities); $permissionFetch = EntityPermission::query() - ->where('action', '=', 'view') ->where(function (Builder $query) use ($idsByType) { foreach ($idsByType as $type => $ids) { $query->orWhere(function (Builder $query) use ($type, $ids) { - $query->where('restrictable_type', '=', $type)->whereIn('restrictable_id', $ids); + $query->where('entity_type', '=', $type)->whereIn('entity_id', $ids); }); } }); @@ -345,7 +335,7 @@ class JointPermissionBuilder return $this->createJointPermissionDataArray($entity, $roleId, true, true); } - if ($entity->restricted) { + if ($this->entityPermissionsActiveForRole($permissionMap, $entity, $roleId)) { $hasAccess = $this->mapHasActiveRestriction($permissionMap, $entity, $roleId); return $this->createJointPermissionDataArray($entity, $roleId, $hasAccess, $hasAccess); @@ -358,13 +348,14 @@ class JointPermissionBuilder // For chapters and pages, Check if explicit permissions are set on the Book. $book = $this->getBook($entity->book_id); $hasExplicitAccessToParents = $this->mapHasActiveRestriction($permissionMap, $book, $roleId); - $hasPermissiveAccessToParents = !$book->restricted; + $hasPermissiveAccessToParents = !$this->entityPermissionsActiveForRole($permissionMap, $book, $roleId); // For pages with a chapter, Check if explicit permissions are set on the Chapter if ($entity->type === 'page' && $entity->chapter_id !== 0) { $chapter = $this->getChapter($entity->chapter_id); - $hasPermissiveAccessToParents = $hasPermissiveAccessToParents && !$chapter->restricted; - if ($chapter->restricted) { + $chapterRestricted = $this->entityPermissionsActiveForRole($permissionMap, $chapter, $roleId); + $hasPermissiveAccessToParents = $hasPermissiveAccessToParents && !$chapterRestricted; + if ($chapterRestricted) { $hasExplicitAccessToParents = $this->mapHasActiveRestriction($permissionMap, $chapter, $roleId); } } @@ -377,14 +368,25 @@ class JointPermissionBuilder ); } + /** + * Check if entity permissions are defined within the given map, for the given entity and role. + * Checks for the default `role_id=0` backup option as a fallback. + */ + protected function entityPermissionsActiveForRole(array $permissionMap, SimpleEntityData $entity, int $roleId): bool + { + $keyPrefix = $entity->type . ':' . $entity->id . ':'; + return isset($permissionMap[$keyPrefix . $roleId]) || isset($permissionMap[$keyPrefix . '0']); + } + /** * Check for an active restriction in an entity map. */ protected function mapHasActiveRestriction(array $entityMap, SimpleEntityData $entity, int $roleId): bool { - $key = $entity->type . ':' . $entity->id . ':' . $roleId; + $roleKey = $entity->type . ':' . $entity->id . ':' . $roleId; + $defaultKey = $entity->type . ':' . $entity->id . ':0'; - return $entityMap[$key] ?? false; + return $entityMap[$roleKey] ?? $entityMap[$defaultKey] ?? false; } /** diff --git a/app/Auth/Permissions/PermissionApplicator.php b/app/Auth/Permissions/PermissionApplicator.php index d840ccd16..af372cb74 100644 --- a/app/Auth/Permissions/PermissionApplicator.php +++ b/app/Auth/Permissions/PermissionApplicator.php @@ -59,11 +59,15 @@ class PermissionApplicator */ protected function hasEntityPermission(Entity $entity, array $userRoleIds, string $action): ?bool { + $this->ensureValidEntityAction($action); + $adminRoleId = Role::getSystemRole('admin')->id; if (in_array($adminRoleId, $userRoleIds)) { return true; } + // The chain order here is very important due to the fact we walk up the chain + // in the loop below. Earlier items in the chain have higher priority. $chain = [$entity]; if ($entity instanceof Page && $entity->chapter_id) { $chain[] = $entity->chapter; @@ -74,16 +78,26 @@ class PermissionApplicator } foreach ($chain as $currentEntity) { - if (is_null($currentEntity->restricted)) { - throw new InvalidArgumentException('Entity restricted field used but has not been loaded'); + $allowedByRoleId = $currentEntity->permissions() + ->whereIn('role_id', [0, ...$userRoleIds]) + ->pluck($action, 'role_id'); + + // Continue up the chain if no applicable entity permission overrides. + if ($allowedByRoleId->isEmpty()) { + continue; } - if ($currentEntity->restricted) { - return $currentEntity->permissions() - ->whereIn('role_id', $userRoleIds) - ->where('action', '=', $action) - ->count() > 0; + // If we have user-role-specific permissions set, allow if any of those + // role permissions allow access. + $hasDefault = $allowedByRoleId->has(0); + if (!$hasDefault || $allowedByRoleId->count() > 1) { + return $allowedByRoleId->search(function (bool $allowed, int $roleId) { + return $roleId !== 0 && $allowed; + }) !== false; } + + // Otherwise, return the default "Other roles" fallback value. + return $allowedByRoleId->get(0); } return null; @@ -95,18 +109,16 @@ class PermissionApplicator */ public function checkUserHasEntityPermissionOnAny(string $action, string $entityClass = ''): bool { - if (strpos($action, '-') !== false) { - throw new InvalidArgumentException('Action should be a simple entity permission action, not a role permission'); - } + $this->ensureValidEntityAction($action); $permissionQuery = EntityPermission::query() - ->where('action', '=', $action) + ->where($action, '=', true) ->whereIn('role_id', $this->getCurrentUserRoleIds()); if (!empty($entityClass)) { /** @var Entity $entityInstance */ $entityInstance = app()->make($entityClass); - $permissionQuery = $permissionQuery->where('restrictable_type', '=', $entityInstance->getMorphClass()); + $permissionQuery = $permissionQuery->where('entity_type', '=', $entityInstance->getMorphClass()); } $hasPermission = $permissionQuery->count() > 0; @@ -255,4 +267,16 @@ class PermissionApplicator return $this->currentUser()->roles->pluck('id')->values()->all(); } + + /** + * Ensure the given action is a valid and expected entity action. + * Throws an exception if invalid otherwise does nothing. + * @throws InvalidArgumentException + */ + protected function ensureValidEntityAction(string $action): void + { + if (!in_array($action, EntityPermission::PERMISSIONS)) { + throw new InvalidArgumentException('Action should be a simple entity permission action, not a role permission'); + } + } } diff --git a/app/Auth/Permissions/PermissionFormData.php b/app/Auth/Permissions/PermissionFormData.php new file mode 100644 index 000000000..8044a3c56 --- /dev/null +++ b/app/Auth/Permissions/PermissionFormData.php @@ -0,0 +1,68 @@ +entity = $entity; + } + + /** + * Get the permissions with assigned roles. + */ + public function permissionsWithRoles(): array + { + return $this->entity->permissions() + ->with('role') + ->where('role_id', '!=', 0) + ->get() + ->sortBy('role.display_name') + ->all(); + } + + /** + * Get the roles that don't yet have specific permissions for the + * entity we're managing permissions for. + */ + public function rolesNotAssigned(): array + { + $assigned = $this->entity->permissions()->pluck('role_id'); + return Role::query() + ->where('system_name', '!=', 'admin') + ->whereNotIn('id', $assigned) + ->orderBy('display_name', 'asc') + ->get() + ->all(); + } + + /** + * Get the entity permission for the "Everyone Else" option. + */ + public function everyoneElseEntityPermission(): EntityPermission + { + /** @var ?EntityPermission $permission */ + $permission = $this->entity->permissions() + ->where('role_id', '=', 0) + ->first(); + return $permission ?? (new EntityPermission()); + } + + /** + * Get the "Everyone Else" role entry. + */ + public function everyoneElseRole(): Role + { + return (new Role())->forceFill([ + 'id' => 0, + 'display_name' => trans('entities.permissions_role_everyone_else'), + 'description' => trans('entities.permissions_role_everyone_else_desc'), + ]); + } +} diff --git a/app/Auth/Permissions/PermissionsRepo.php b/app/Auth/Permissions/PermissionsRepo.php index 2c2bedb72..6dcef7256 100644 --- a/app/Auth/Permissions/PermissionsRepo.php +++ b/app/Auth/Permissions/PermissionsRepo.php @@ -139,6 +139,7 @@ class PermissionsRepo } } + $role->entityPermissions()->delete(); $role->jointPermissions()->delete(); Activity::add(ActivityType::ROLE_DELETE, $role); $role->delete(); diff --git a/app/Auth/Permissions/SimpleEntityData.php b/app/Auth/Permissions/SimpleEntityData.php index 6ec0c4179..62f5984f8 100644 --- a/app/Auth/Permissions/SimpleEntityData.php +++ b/app/Auth/Permissions/SimpleEntityData.php @@ -6,7 +6,6 @@ class SimpleEntityData { public int $id; public string $type; - public bool $restricted; public int $owned_by; public ?int $book_id; public ?int $chapter_id; diff --git a/app/Auth/Role.php b/app/Auth/Role.php index 51b2ce301..17a4edcc0 100644 --- a/app/Auth/Role.php +++ b/app/Auth/Role.php @@ -2,6 +2,7 @@ namespace BookStack\Auth; +use BookStack\Auth\Permissions\EntityPermission; use BookStack\Auth\Permissions\JointPermission; use BookStack\Auth\Permissions\RolePermission; use BookStack\Interfaces\Loggable; @@ -54,6 +55,14 @@ class Role extends Model implements Loggable return $this->belongsToMany(RolePermission::class, 'permission_role', 'role_id', 'permission_id'); } + /** + * Get the entity permissions assigned to this role. + */ + public function entityPermissions(): HasMany + { + return $this->hasMany(EntityPermission::class); + } + /** * Check if this role has a permission. */ @@ -109,17 +118,6 @@ class Role extends Model implements Loggable return static::query()->where('hidden', '=', false)->orderBy('name')->get(); } - /** - * Get the roles that can be restricted. - */ - public static function restrictable(): Collection - { - return static::query() - ->where('system_name', '!=', 'admin') - ->orderBy('display_name', 'asc') - ->get(); - } - /** * {@inheritdoc} */ diff --git a/app/Auth/UserRepo.php b/app/Auth/UserRepo.php index 28ce96c49..c589fd964 100644 --- a/app/Auth/UserRepo.php +++ b/app/Auth/UserRepo.php @@ -10,6 +10,7 @@ use BookStack\Exceptions\UserUpdateException; use BookStack\Facades\Activity; use BookStack\Uploads\UserAvatars; use Exception; +use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Log; use Illuminate\Support\Str; @@ -61,7 +62,7 @@ class UserRepo $user = new User(); $user->name = $data['name']; $user->email = $data['email']; - $user->password = bcrypt(empty($data['password']) ? Str::random(32) : $data['password']); + $user->password = Hash::make(empty($data['password']) ? Str::random(32) : $data['password']); $user->email_confirmed = $emailConfirmed; $user->external_auth_id = $data['external_auth_id'] ?? ''; @@ -126,7 +127,7 @@ class UserRepo } if (!empty($data['password'])) { - $user->password = bcrypt($data['password']); + $user->password = Hash::make($data['password']); } if (!empty($data['language'])) { diff --git a/app/Config/app.php b/app/Config/app.php index 738aacdbc..90726c904 100644 --- a/app/Config/app.php +++ b/app/Config/app.php @@ -75,7 +75,7 @@ return [ 'locale' => env('APP_LANG', 'en'), // Locales available - 'locales' => ['en', 'ar', 'bg', 'bs', 'ca', 'cs', 'cy', 'da', 'de', 'de_informal', 'es', 'es_AR', 'et', 'eu', 'fa', 'fr', 'he', 'hr', 'hu', 'id', 'it', 'ja', 'ko', 'lt', 'lv', 'nl', 'nb', 'pt', 'pt_BR', 'sk', 'sl', 'sv', 'pl', 'ro', 'ru', 'tr', 'uk', 'uz', 'vi', 'zh_CN', 'zh_TW'], + 'locales' => ['en', 'ar', 'bg', 'bs', 'ca', 'cs', 'cy', 'da', 'de', 'de_informal', 'el', 'es', 'es_AR', 'et', 'eu', 'fa', 'fr', 'he', 'hr', 'hu', 'id', 'it', 'ja', 'ko', 'lt', 'lv', 'nl', 'nb', 'pt', 'pt_BR', 'sk', 'sl', 'sv', 'pl', 'ro', 'ru', 'tr', 'uk', 'uz', 'vi', 'zh_CN', 'zh_TW'], // Application Fallback Locale 'fallback_locale' => 'en', @@ -114,6 +114,8 @@ return [ Illuminate\Foundation\Providers\FoundationServiceProvider::class, Illuminate\Hashing\HashServiceProvider::class, Illuminate\Mail\MailServiceProvider::class, + Illuminate\Notifications\NotificationServiceProvider::class, + Illuminate\Pagination\PaginationServiceProvider::class, Illuminate\Pipeline\PipelineServiceProvider::class, Illuminate\Queue\QueueServiceProvider::class, Illuminate\Redis\RedisServiceProvider::class, @@ -121,27 +123,22 @@ return [ Illuminate\Session\SessionServiceProvider::class, Illuminate\Validation\ValidationServiceProvider::class, Illuminate\View\ViewServiceProvider::class, - Illuminate\Notifications\NotificationServiceProvider::class, - SocialiteProviders\Manager\ServiceProvider::class, // Third party service providers - Intervention\Image\ImageServiceProvider::class, Barryvdh\DomPDF\ServiceProvider::class, Barryvdh\Snappy\ServiceProvider::class, - - // BookStack replacement service providers (Extends Laravel) - BookStack\Providers\PaginationServiceProvider::class, - BookStack\Providers\TranslationServiceProvider::class, + Intervention\Image\ImageServiceProvider::class, + SocialiteProviders\Manager\ServiceProvider::class, // BookStack custom service providers BookStack\Providers\ThemeServiceProvider::class, - BookStack\Providers\AuthServiceProvider::class, BookStack\Providers\AppServiceProvider::class, - BookStack\Providers\BroadcastServiceProvider::class, + BookStack\Providers\AuthServiceProvider::class, BookStack\Providers\EventServiceProvider::class, BookStack\Providers\RouteServiceProvider::class, - BookStack\Providers\CustomFacadeProvider::class, - BookStack\Providers\CustomValidationServiceProvider::class, + BookStack\Providers\TranslationServiceProvider::class, + BookStack\Providers\ValidationRuleServiceProvider::class, + BookStack\Providers\ViewTweaksServiceProvider::class, ], /* diff --git a/app/Console/Commands/CopyShelfPermissions.php b/app/Console/Commands/CopyShelfPermissions.php index 32adf0683..ec4c875ff 100644 --- a/app/Console/Commands/CopyShelfPermissions.php +++ b/app/Console/Commands/CopyShelfPermissions.php @@ -3,7 +3,7 @@ namespace BookStack\Console\Commands; use BookStack\Entities\Models\Bookshelf; -use BookStack\Entities\Repos\BookshelfRepo; +use BookStack\Entities\Tools\PermissionsUpdater; use Illuminate\Console\Command; class CopyShelfPermissions extends Command @@ -25,19 +25,16 @@ class CopyShelfPermissions extends Command */ protected $description = 'Copy shelf permissions to all child books'; - /** - * @var BookshelfRepo - */ - protected $bookshelfRepo; + protected PermissionsUpdater $permissionsUpdater; /** * Create a new command instance. * * @return void */ - public function __construct(BookshelfRepo $repo) + public function __construct(PermissionsUpdater $permissionsUpdater) { - $this->bookshelfRepo = $repo; + $this->permissionsUpdater = $permissionsUpdater; parent::__construct(); } @@ -69,18 +66,18 @@ class CopyShelfPermissions extends Command return; } - $shelves = Bookshelf::query()->get(['id', 'restricted']); + $shelves = Bookshelf::query()->get(['id']); } if ($shelfSlug) { - $shelves = Bookshelf::query()->where('slug', '=', $shelfSlug)->get(['id', 'restricted']); + $shelves = Bookshelf::query()->where('slug', '=', $shelfSlug)->get(['id']); if ($shelves->count() === 0) { $this->info('No shelves found with the given slug.'); } } foreach ($shelves as $shelf) { - $this->bookshelfRepo->copyDownPermissions($shelf, false); + $this->permissionsUpdater->updateBookPermissionsFromShelf($shelf, false); $this->info('Copied permissions for shelf [' . $shelf->id . ']'); } diff --git a/app/Entities/Models/Book.php b/app/Entities/Models/Book.php index 8217d2cab..fc4556857 100644 --- a/app/Entities/Models/Book.php +++ b/app/Entities/Models/Book.php @@ -19,6 +19,7 @@ use Illuminate\Support\Collection; * @property \Illuminate\Database\Eloquent\Collection $chapters * @property \Illuminate\Database\Eloquent\Collection $pages * @property \Illuminate\Database\Eloquent\Collection $directPages + * @property \Illuminate\Database\Eloquent\Collection $shelves */ class Book extends Entity implements HasCoverImage { @@ -27,7 +28,7 @@ class Book extends Entity implements HasCoverImage public $searchFactor = 1.2; protected $fillable = ['name', 'description']; - protected $hidden = ['restricted', 'pivot', 'image_id', 'deleted_at']; + protected $hidden = ['pivot', 'image_id', 'deleted_at']; /** * Get the url for this book. @@ -119,4 +120,13 @@ class Book extends Entity implements HasCoverImage return $pages->concat($chapters)->sortBy('priority')->sortByDesc('draft'); } + + /** + * Get a visible book by its slug. + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + */ + public static function getBySlug(string $slug): self + { + return static::visible()->where('slug', '=', $slug)->firstOrFail(); + } } diff --git a/app/Entities/Models/Bookshelf.php b/app/Entities/Models/Bookshelf.php index cdc6648f9..ad52d9d37 100644 --- a/app/Entities/Models/Bookshelf.php +++ b/app/Entities/Models/Bookshelf.php @@ -17,7 +17,7 @@ class Bookshelf extends Entity implements HasCoverImage protected $fillable = ['name', 'description', 'image_id']; - protected $hidden = ['restricted', 'image_id', 'deleted_at']; + protected $hidden = ['image_id', 'deleted_at']; /** * Get the books in this shelf. @@ -109,4 +109,13 @@ class Bookshelf extends Entity implements HasCoverImage $maxOrder = $this->books()->max('order'); $this->books()->attach($book->id, ['order' => $maxOrder + 1]); } + + /** + * Get a visible shelf by its slug. + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + */ + public static function getBySlug(string $slug): self + { + return static::visible()->where('slug', '=', $slug)->firstOrFail(); + } } diff --git a/app/Entities/Models/Chapter.php b/app/Entities/Models/Chapter.php index af4bbd8e3..98889ce3f 100644 --- a/app/Entities/Models/Chapter.php +++ b/app/Entities/Models/Chapter.php @@ -19,7 +19,7 @@ class Chapter extends BookChild public $searchFactor = 1.2; protected $fillable = ['name', 'description', 'priority']; - protected $hidden = ['restricted', 'pivot', 'deleted_at']; + protected $hidden = ['pivot', 'deleted_at']; /** * Get the pages that this chapter contains. @@ -58,4 +58,13 @@ class Chapter extends BookChild ->orderBy('priority', 'asc') ->get(); } + + /** + * Get a visible chapter by its book and page slugs. + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + */ + public static function getBySlugs(string $bookSlug, string $chapterSlug): self + { + return static::visible()->whereSlugs($bookSlug, $chapterSlug)->firstOrFail(); + } } diff --git a/app/Entities/Models/Entity.php b/app/Entities/Models/Entity.php index 26a52073e..8bfe69365 100644 --- a/app/Entities/Models/Entity.php +++ b/app/Entities/Models/Entity.php @@ -42,7 +42,6 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property Carbon $deleted_at * @property int $created_by * @property int $updated_by - * @property bool $restricted * @property Collection $tags * * @method static Entity|Builder visible() @@ -176,16 +175,15 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable */ public function permissions(): MorphMany { - return $this->morphMany(EntityPermission::class, 'restrictable'); + return $this->morphMany(EntityPermission::class, 'entity'); } /** * Check if this entity has a specific restriction set against it. */ - public function hasRestriction(int $role_id, string $action): bool + public function hasPermissions(): bool { - return $this->permissions()->where('role_id', '=', $role_id) - ->where('action', '=', $action)->count() > 0; + return $this->permissions()->count() > 0; } /** diff --git a/app/Entities/Models/Page.php b/app/Entities/Models/Page.php index 93729d7f2..7a60b3ada 100644 --- a/app/Entities/Models/Page.php +++ b/app/Entities/Models/Page.php @@ -39,7 +39,7 @@ class Page extends BookChild public $textField = 'text'; - protected $hidden = ['html', 'markdown', 'text', 'restricted', 'pivot', 'deleted_at']; + protected $hidden = ['html', 'markdown', 'text', 'pivot', 'deleted_at']; protected $casts = [ 'draft' => 'boolean', @@ -145,4 +145,13 @@ class Page extends BookChild return $refreshed; } + + /** + * Get a visible page by its book and page slugs. + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + */ + public static function getBySlugs(string $bookSlug, string $pageSlug): self + { + return static::visible()->whereSlugs($bookSlug, $pageSlug)->firstOrFail(); + } } diff --git a/app/Entities/Models/PageRevision.php b/app/Entities/Models/PageRevision.php index 6517b0080..cd22db0c8 100644 --- a/app/Entities/Models/PageRevision.php +++ b/app/Entities/Models/PageRevision.php @@ -31,7 +31,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; class PageRevision extends Model implements Loggable { protected $fillable = ['name', 'text', 'summary']; - protected $hidden = ['html', 'markdown', 'restricted', 'text']; + protected $hidden = ['html', 'markdown', 'text']; /** * Get the user that created the page revision. diff --git a/app/Entities/Repos/BookshelfRepo.php b/app/Entities/Repos/BookshelfRepo.php index 1f144b1a8..d7759deb4 100644 --- a/app/Entities/Repos/BookshelfRepo.php +++ b/app/Entities/Repos/BookshelfRepo.php @@ -134,31 +134,6 @@ class BookshelfRepo $shelf->books()->sync($syncData); } - /** - * Copy down the permissions of the given shelf to all child books. - */ - public function copyDownPermissions(Bookshelf $shelf, $checkUserPermissions = true): int - { - $shelfPermissions = $shelf->permissions()->get(['role_id', 'action'])->toArray(); - $shelfBooks = $shelf->books()->get(['id', 'restricted', 'owned_by']); - $updatedBookCount = 0; - - /** @var Book $book */ - foreach ($shelfBooks as $book) { - if ($checkUserPermissions && !userCan('restrictions-manage', $book)) { - continue; - } - $book->permissions()->delete(); - $book->restricted = $shelf->restricted; - $book->permissions()->createMany($shelfPermissions); - $book->save(); - $book->rebuildPermissions(); - $updatedBookCount++; - } - - return $updatedBookCount; - } - /** * Remove a bookshelf from the system. * diff --git a/app/Entities/Tools/BookContents.php b/app/Entities/Tools/BookContents.php index 6f11e8cbe..0ad424de2 100644 --- a/app/Entities/Tools/BookContents.php +++ b/app/Entities/Tools/BookContents.php @@ -11,22 +11,15 @@ use Illuminate\Support\Collection; class BookContents { - /** - * @var Book - */ - protected $book; + protected Book $book; - /** - * BookContents constructor. - */ public function __construct(Book $book) { $this->book = $book; } /** - * Get the current priority of the last item - * at the top-level of the book. + * Get the current priority of the last item at the top-level of the book. */ public function getLastPriority(): int { diff --git a/app/Entities/Tools/Cloner.php b/app/Entities/Tools/Cloner.php index 92b62a754..52a8f4cf0 100644 --- a/app/Entities/Tools/Cloner.php +++ b/app/Entities/Tools/Cloner.php @@ -4,6 +4,7 @@ namespace BookStack\Entities\Tools; use BookStack\Actions\Tag; use BookStack\Entities\Models\Book; +use BookStack\Entities\Models\Bookshelf; use BookStack\Entities\Models\Chapter; use BookStack\Entities\Models\Entity; use BookStack\Entities\Models\Page; @@ -71,8 +72,10 @@ class Cloner $bookDetails = $this->entityToInputData($original); $bookDetails['name'] = $newName; + // Clone book $copyBook = $this->bookRepo->create($bookDetails); + // Clone contents $directChildren = $original->getDirectChildren(); foreach ($directChildren as $child) { if ($child instanceof Chapter && userCan('chapter-create', $copyBook)) { @@ -84,6 +87,14 @@ class Cloner } } + // Clone bookshelf relationships + /** @var Bookshelf $shelf */ + foreach ($original->shelves as $shelf) { + if (userCan('bookshelf-update', $shelf)) { + $shelf->appendBook($copyBook); + } + } + return $copyBook; } @@ -111,8 +122,7 @@ class Cloner */ public function copyEntityPermissions(Entity $sourceEntity, Entity $targetEntity): void { - $targetEntity->restricted = $sourceEntity->restricted; - $permissions = $sourceEntity->permissions()->get(['role_id', 'action'])->toArray(); + $permissions = $sourceEntity->permissions()->get(['role_id', 'view', 'create', 'update', 'delete'])->toArray(); $targetEntity->permissions()->delete(); $targetEntity->permissions()->createMany($permissions); $targetEntity->rebuildPermissions(); diff --git a/app/Entities/Tools/HierarchyTransformer.php b/app/Entities/Tools/HierarchyTransformer.php index 50d9e2eae..43cf2390e 100644 --- a/app/Entities/Tools/HierarchyTransformer.php +++ b/app/Entities/Tools/HierarchyTransformer.php @@ -65,7 +65,7 @@ class HierarchyTransformer foreach ($book->chapters as $index => $chapter) { $newBook = $this->transformChapterToBook($chapter); $shelfBookSyncData[$newBook->id] = ['order' => $index]; - if (!$newBook->restricted) { + if (!$newBook->hasPermissions()) { $this->cloner->copyEntityPermissions($shelf, $newBook); } } diff --git a/app/Entities/Tools/PermissionsUpdater.php b/app/Entities/Tools/PermissionsUpdater.php index c771ee4b6..eb4eb6b48 100644 --- a/app/Entities/Tools/PermissionsUpdater.php +++ b/app/Entities/Tools/PermissionsUpdater.php @@ -3,7 +3,10 @@ namespace BookStack\Entities\Tools; use BookStack\Actions\ActivityType; +use BookStack\Auth\Permissions\EntityPermission; use BookStack\Auth\User; +use BookStack\Entities\Models\Book; +use BookStack\Entities\Models\Bookshelf; use BookStack\Entities\Models\Entity; use BookStack\Facades\Activity; use Illuminate\Http\Request; @@ -16,11 +19,9 @@ class PermissionsUpdater */ public function updateFromPermissionsForm(Entity $entity, Request $request) { - $restricted = $request->get('restricted') === 'true'; - $permissions = $request->get('restrictions', null); + $permissions = $request->get('permissions', null); $ownerId = $request->get('owned_by', null); - $entity->restricted = $restricted; $entity->permissions()->delete(); if (!is_null($permissions)) { @@ -52,18 +53,43 @@ class PermissionsUpdater } /** - * Format permissions provided from a permission form to be - * EntityPermission data. + * Format permissions provided from a permission form to be EntityPermission data. */ - protected function formatPermissionsFromRequestToEntityPermissions(array $permissions): Collection + protected function formatPermissionsFromRequestToEntityPermissions(array $permissions): array { - return collect($permissions)->flatMap(function ($restrictions, $roleId) { - return collect($restrictions)->keys()->map(function ($action) use ($roleId) { - return [ - 'role_id' => $roleId, - 'action' => strtolower($action), - ]; - }); - }); + $formatted = []; + + foreach ($permissions as $roleId => $info) { + $entityPermissionData = ['role_id' => $roleId]; + foreach (EntityPermission::PERMISSIONS as $permission) { + $entityPermissionData[$permission] = (($info[$permission] ?? false) === "true"); + } + $formatted[] = $entityPermissionData; + } + + return $formatted; + } + + /** + * Copy down the permissions of the given shelf to all child books. + */ + public function updateBookPermissionsFromShelf(Bookshelf $shelf, $checkUserPermissions = true): int + { + $shelfPermissions = $shelf->permissions()->get(['role_id', 'view', 'create', 'update', 'delete'])->toArray(); + $shelfBooks = $shelf->books()->get(['id', 'owned_by']); + $updatedBookCount = 0; + + /** @var Book $book */ + foreach ($shelfBooks as $book) { + if ($checkUserPermissions && !userCan('restrictions-manage', $book)) { + continue; + } + $book->permissions()->delete(); + $book->permissions()->createMany($shelfPermissions); + $book->rebuildPermissions(); + $updatedBookCount++; + } + + return $updatedBookCount; } } diff --git a/app/Http/Controllers/Api/BookApiController.php b/app/Http/Controllers/Api/BookApiController.php index 15565c361..d57b48a43 100644 --- a/app/Http/Controllers/Api/BookApiController.php +++ b/app/Http/Controllers/Api/BookApiController.php @@ -2,14 +2,18 @@ namespace BookStack\Http\Controllers\Api; +use BookStack\Api\ApiEntityListFormatter; use BookStack\Entities\Models\Book; +use BookStack\Entities\Models\Chapter; +use BookStack\Entities\Models\Entity; use BookStack\Entities\Repos\BookRepo; +use BookStack\Entities\Tools\BookContents; use Illuminate\Http\Request; use Illuminate\Validation\ValidationException; class BookApiController extends ApiController { - protected $bookRepo; + protected BookRepo $bookRepo; public function __construct(BookRepo $bookRepo) { @@ -47,11 +51,25 @@ class BookApiController extends ApiController /** * View the details of a single book. + * The response data will contain 'content' property listing the chapter and pages directly within, in + * the same structure as you'd see within the BookStack interface when viewing a book. Top-level + * contents will have a 'type' property to distinguish between pages & chapters. */ public function read(string $id) { $book = Book::visible()->with(['tags', 'cover', 'createdBy', 'updatedBy', 'ownedBy'])->findOrFail($id); + $contents = (new BookContents($book))->getTree(true, false)->all(); + $contentsApiData = (new ApiEntityListFormatter($contents)) + ->withType() + ->withField('pages', function (Entity $entity) { + if ($entity instanceof Chapter) { + return (new ApiEntityListFormatter($entity->pages->all()))->format(); + } + return null; + })->format(); + $book->setAttribute('contents', $contentsApiData); + return response()->json($book); } diff --git a/app/Http/Controllers/Api/BookshelfApiController.php b/app/Http/Controllers/Api/BookshelfApiController.php index 620df1638..b6b78e80e 100644 --- a/app/Http/Controllers/Api/BookshelfApiController.php +++ b/app/Http/Controllers/Api/BookshelfApiController.php @@ -13,9 +13,6 @@ class BookshelfApiController extends ApiController { protected BookshelfRepo $bookshelfRepo; - /** - * BookshelfApiController constructor. - */ public function __construct(BookshelfRepo $bookshelfRepo) { $this->bookshelfRepo = $bookshelfRepo; diff --git a/app/Http/Controllers/Api/SearchApiController.php b/app/Http/Controllers/Api/SearchApiController.php index 7ef714390..bf59ec671 100644 --- a/app/Http/Controllers/Api/SearchApiController.php +++ b/app/Http/Controllers/Api/SearchApiController.php @@ -2,6 +2,7 @@ namespace BookStack\Http\Controllers\Api; +use BookStack\Api\ApiEntityListFormatter; use BookStack\Entities\Models\Entity; use BookStack\Search\SearchOptions; use BookStack\Search\SearchResultsFormatter; @@ -10,8 +11,8 @@ use Illuminate\Http\Request; class SearchApiController extends ApiController { - protected $searchRunner; - protected $resultsFormatter; + protected SearchRunner $searchRunner; + protected SearchResultsFormatter $resultsFormatter; protected $rules = [ 'all' => [ @@ -50,24 +51,17 @@ class SearchApiController extends ApiController $results = $this->searchRunner->searchEntities($options, 'all', $page, $count); $this->resultsFormatter->format($results['results']->all(), $options); - /** @var Entity $result */ - foreach ($results['results'] as $result) { - $result->setVisible([ - 'id', 'name', 'slug', 'book_id', - 'chapter_id', 'draft', 'template', - 'created_at', 'updated_at', - 'tags', 'type', 'preview_html', 'url', - ]); - $result->setAttribute('type', $result->getType()); - $result->setAttribute('url', $result->getUrl()); - $result->setAttribute('preview_html', [ - 'name' => (string) $result->getAttribute('preview_name'), - 'content' => (string) $result->getAttribute('preview_content'), - ]); - } + $data = (new ApiEntityListFormatter($results['results']->all())) + ->withType()->withTags() + ->withField('preview_html', function (Entity $entity) { + return [ + 'name' => (string) $entity->getAttribute('preview_name'), + 'content' => (string) $entity->getAttribute('preview_content'), + ]; + })->format(); return response()->json([ - 'data' => $results['results'], + 'data' => $data, 'total' => $results['total'], ]); } diff --git a/app/Http/Controllers/Auth/ConfirmEmailController.php b/app/Http/Controllers/Auth/ConfirmEmailController.php index 873d88475..ea633ff3a 100644 --- a/app/Http/Controllers/Auth/ConfirmEmailController.php +++ b/app/Http/Controllers/Auth/ConfirmEmailController.php @@ -14,9 +14,9 @@ use Illuminate\Http\Request; class ConfirmEmailController extends Controller { - protected $emailConfirmationService; - protected $loginService; - protected $userRepo; + protected EmailConfirmationService $emailConfirmationService; + protected LoginService $loginService; + protected UserRepo $userRepo; /** * Create a new controller instance. diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php index b345fad1c..2bdc31df5 100644 --- a/app/Http/Controllers/Auth/ForgotPasswordController.php +++ b/app/Http/Controllers/Auth/ForgotPasswordController.php @@ -4,24 +4,11 @@ namespace BookStack\Http\Controllers\Auth; use BookStack\Actions\ActivityType; use BookStack\Http\Controllers\Controller; -use Illuminate\Foundation\Auth\SendsPasswordResetEmails; use Illuminate\Http\Request; use Illuminate\Support\Facades\Password; class ForgotPasswordController extends Controller { - /* - |-------------------------------------------------------------------------- - | Password Reset Controller - |-------------------------------------------------------------------------- - | - | This controller is responsible for handling password reset emails and - | includes a trait which assists in sending these notifications from - | your application to your users. Feel free to explore this trait. - | - */ - use SendsPasswordResetEmails; - /** * Create a new controller instance. * @@ -33,6 +20,14 @@ class ForgotPasswordController extends Controller $this->middleware('guard:standard'); } + /** + * Display the form to request a password reset link. + */ + public function showLinkRequestForm() + { + return view('auth.passwords.email'); + } + /** * Send a reset link to the given user. * @@ -49,7 +44,7 @@ class ForgotPasswordController extends Controller // We will send the password reset link to this user. Once we have attempted // to send the link, we will examine the response then see the message we // need to show to the user. Finally, we'll send out a proper response. - $response = $this->broker()->sendResetLink( + $response = Password::broker()->sendResetLink( $request->only('email') ); diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 1d6a36c5b..e16feb079 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -8,31 +8,14 @@ use BookStack\Exceptions\LoginAttemptEmailNeededException; use BookStack\Exceptions\LoginAttemptException; use BookStack\Facades\Activity; use BookStack\Http\Controllers\Controller; -use Illuminate\Foundation\Auth\AuthenticatesUsers; +use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; use Illuminate\Validation\ValidationException; class LoginController extends Controller { - /* - |-------------------------------------------------------------------------- - | Login Controller - |-------------------------------------------------------------------------- - | - | This controller handles authenticating users for the application and - | redirecting them to your home screen. The controller uses a trait - | to conveniently provide its functionality to your applications. - | - */ - use AuthenticatesUsers { - logout as traitLogout; - } - - /** - * Redirection paths. - */ - protected $redirectTo = '/'; - protected $redirectPath = '/'; + use ThrottlesLogins; protected SocialAuthService $socialAuthService; protected LoginService $loginService; @@ -48,21 +31,6 @@ class LoginController extends Controller $this->socialAuthService = $socialAuthService; $this->loginService = $loginService; - - $this->redirectPath = url('/'); - } - - public function username() - { - return config('auth.method') === 'standard' ? 'email' : 'username'; - } - - /** - * Get the needed authorization credentials from the request. - */ - protected function credentials(Request $request) - { - return $request->only('username', 'email', 'password'); } /** @@ -98,29 +66,15 @@ class LoginController extends Controller /** * Handle a login request to the application. - * - * @param \Illuminate\Http\Request $request - * - * @throws \Illuminate\Validation\ValidationException - * - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse */ public function login(Request $request) { $this->validateLogin($request); $username = $request->get($this->username()); - // If the class is using the ThrottlesLogins trait, we can automatically throttle - // the login attempts for this application. We'll key this by the username and - // the IP address of the client making these requests into this application. - if ( - method_exists($this, 'hasTooManyLoginAttempts') && - $this->hasTooManyLoginAttempts($request) - ) { - $this->fireLockoutEvent($request); - + // Check login throttling attempts to see if they've gone over the limit + if ($this->hasTooManyLoginAttempts($request)) { Activity::logFailedLogin($username); - return $this->sendLockoutResponse($request); } @@ -134,24 +88,62 @@ class LoginController extends Controller return $this->sendLoginAttemptExceptionResponse($exception, $request); } - // If the login attempt was unsuccessful we will increment the number of attempts - // to login and redirect the user back to the login form. Of course, when this - // user surpasses their maximum number of attempts they will get locked out. + // On unsuccessful login attempt, Increment login attempts for throttling and log failed login. $this->incrementLoginAttempts($request); - Activity::logFailedLogin($username); - return $this->sendFailedLoginResponse($request); + // Throw validation failure for failed login + throw ValidationException::withMessages([ + $this->username() => [trans('auth.failed')], + ])->redirectTo('/login'); + } + + /** + * Logout user and perform subsequent redirect. + */ + public function logout(Request $request) + { + Auth::guard()->logout(); + $request->session()->invalidate(); + $request->session()->regenerateToken(); + + $redirectUri = $this->shouldAutoInitiate() ? '/login?prevent_auto_init=true' : '/'; + + return redirect($redirectUri); + } + + /** + * Get the expected username input based upon the current auth method. + */ + protected function username(): string + { + return config('auth.method') === 'standard' ? 'email' : 'username'; + } + + /** + * Get the needed authorization credentials from the request. + */ + protected function credentials(Request $request): array + { + return $request->only('username', 'email', 'password'); + } + + /** + * Send the response after the user was authenticated. + * @return RedirectResponse + */ + protected function sendLoginResponse(Request $request) + { + $request->session()->regenerate(); + $this->clearLoginAttempts($request); + + return redirect()->intended('/'); } /** * Attempt to log the user into the application. - * - * @param \Illuminate\Http\Request $request - * - * @return bool */ - protected function attemptLogin(Request $request) + protected function attemptLogin(Request $request): bool { return $this->loginService->attempt( $this->credentials($request), @@ -160,29 +152,12 @@ class LoginController extends Controller ); } - /** - * The user has been authenticated. - * - * @param \Illuminate\Http\Request $request - * @param mixed $user - * - * @return mixed - */ - protected function authenticated(Request $request, $user) - { - return redirect()->intended($this->redirectPath()); - } /** * Validate the user login request. - * - * @param \Illuminate\Http\Request $request - * - * @throws \Illuminate\Validation\ValidationException - * - * @return void + * @throws ValidationException */ - protected function validateLogin(Request $request) + protected function validateLogin(Request $request): void { $rules = ['password' => ['required', 'string']]; $authMethod = config('auth.method'); @@ -216,22 +191,6 @@ class LoginController extends Controller return redirect('/login'); } - /** - * Get the failed login response instance. - * - * @param \Illuminate\Http\Request $request - * - * @throws \Illuminate\Validation\ValidationException - * - * @return \Symfony\Component\HttpFoundation\Response - */ - protected function sendFailedLoginResponse(Request $request) - { - throw ValidationException::withMessages([ - $this->username() => [trans('auth.failed')], - ])->redirectTo('/login'); - } - /** * Update the intended URL location from their previous URL. * Ignores if not from the current app instance or if from certain @@ -271,20 +230,4 @@ class LoginController extends Controller return $autoRedirect && count($socialDrivers) === 0 && in_array($authMethod, ['oidc', 'saml2']); } - - /** - * Logout user and perform subsequent redirect. - * - * @param \Illuminate\Http\Request $request - * - * @return mixed - */ - public function logout(Request $request) - { - $this->traitLogout($request); - - $redirectUri = $this->shouldAutoInitiate() ? '/login?prevent_auto_init=true' : '/'; - - return redirect($redirectUri); - } } diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 15ee78d50..262ca540e 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -5,42 +5,20 @@ namespace BookStack\Http\Controllers\Auth; use BookStack\Auth\Access\LoginService; use BookStack\Auth\Access\RegistrationService; use BookStack\Auth\Access\SocialAuthService; -use BookStack\Auth\User; use BookStack\Exceptions\StoppedAuthenticationException; use BookStack\Exceptions\UserRegistrationException; use BookStack\Http\Controllers\Controller; -use Illuminate\Foundation\Auth\RegistersUsers; +use Illuminate\Contracts\Validation\Validator as ValidatorContract; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Validator; use Illuminate\Validation\Rules\Password; class RegisterController extends Controller { - /* - |-------------------------------------------------------------------------- - | Register Controller - |-------------------------------------------------------------------------- - | - | This controller handles the registration of new users as well as their - | validation and creation. By default this controller uses a trait to - | provide this functionality without requiring any additional code. - | - */ - use RegistersUsers; - protected SocialAuthService $socialAuthService; protected RegistrationService $registrationService; protected LoginService $loginService; - /** - * Where to redirect users after login / registration. - * - * @var string - */ - protected $redirectTo = '/'; - protected $redirectPath = '/'; - /** * Create a new controller instance. */ @@ -55,23 +33,6 @@ class RegisterController extends Controller $this->socialAuthService = $socialAuthService; $this->registrationService = $registrationService; $this->loginService = $loginService; - - $this->redirectTo = url('/'); - $this->redirectPath = url('/'); - } - - /** - * Get a validator for an incoming registration request. - * - * @return \Illuminate\Contracts\Validation\Validator - */ - protected function validator(array $data) - { - return Validator::make($data, [ - 'name' => ['required', 'min:2', 'max:100'], - 'email' => ['required', 'email', 'max:255', 'unique:users'], - 'password' => ['required', Password::default()], - ]); } /** @@ -114,22 +75,18 @@ class RegisterController extends Controller $this->showSuccessNotification(trans('auth.register_success')); - return redirect($this->redirectPath()); + return redirect('/'); } /** - * Create a new user instance after a valid registration. - * - * @param array $data - * - * @return User + * Get a validator for an incoming registration request. */ - protected function create(array $data) + protected function validator(array $data): ValidatorContract { - return User::create([ - 'name' => $data['name'], - 'email' => $data['email'], - 'password' => Hash::make($data['password']), + return Validator::make($data, [ + 'name' => ['required', 'min:2', 'max:100'], + 'email' => ['required', 'email', 'max:255', 'unique:users'], + 'password' => ['required', Password::default()], ]); } } diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php index 9df010736..a9914928e 100644 --- a/app/Http/Controllers/Auth/ResetPasswordController.php +++ b/app/Http/Controllers/Auth/ResetPasswordController.php @@ -3,65 +3,87 @@ namespace BookStack\Http\Controllers\Auth; use BookStack\Actions\ActivityType; +use BookStack\Auth\Access\LoginService; +use BookStack\Auth\User; use BookStack\Http\Controllers\Controller; -use Illuminate\Foundation\Auth\ResetsPasswords; +use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Password; +use Illuminate\Support\Str; +use Illuminate\Validation\Rules\Password as PasswordRule; class ResetPasswordController extends Controller { - /* - |-------------------------------------------------------------------------- - | Password Reset Controller - |-------------------------------------------------------------------------- - | - | This controller is responsible for handling password reset requests - | and uses a simple trait to include this behavior. You're free to - | explore this trait and override any methods you wish to tweak. - | - */ - use ResetsPasswords; + protected LoginService $loginService; - protected $redirectTo = '/'; - - /** - * Create a new controller instance. - * - * @return void - */ - public function __construct() + public function __construct(LoginService $loginService) { $this->middleware('guest'); $this->middleware('guard:standard'); + + $this->loginService = $loginService; + } + + /** + * Display the password reset view for the given token. + * If no token is present, display the link request form. + */ + public function showResetForm(Request $request) + { + $token = $request->route()->parameter('token'); + + return view('auth.passwords.reset')->with( + ['token' => $token, 'email' => $request->email] + ); + } + + /** + * Reset the given user's password. + */ + public function reset(Request $request) + { + $request->validate([ + 'token' => 'required', + 'email' => 'required|email', + 'password' => ['required', 'confirmed', PasswordRule::defaults()], + ]); + + // Here we will attempt to reset the user's password. If it is successful we + // will update the password on an actual user model and persist it to the + // database. Otherwise we will parse the error and return the response. + $credentials = $request->only('email', 'password', 'password_confirmation', 'token'); + $response = Password::broker()->reset($credentials, function (User $user, string $password) { + $user->password = Hash::make($password); + $user->setRememberToken(Str::random(60)); + $user->save(); + + $this->loginService->login($user, auth()->getDefaultDriver()); + }); + + // If the password was successfully reset, we will redirect the user back to + // the application's home authenticated view. If there is an error we can + // redirect them back to where they came from with their error message. + return $response === Password::PASSWORD_RESET + ? $this->sendResetResponse() + : $this->sendResetFailedResponse($request, $response); } /** * Get the response for a successful password reset. - * - * @param Request $request - * @param string $response - * - * @return \Illuminate\Http\Response */ - protected function sendResetResponse(Request $request, $response) + protected function sendResetResponse(): RedirectResponse { - $message = trans('auth.reset_password_success'); - $this->showSuccessNotification($message); + $this->showSuccessNotification(trans('auth.reset_password_success')); $this->logActivity(ActivityType::AUTH_PASSWORD_RESET_UPDATE, user()); - return redirect($this->redirectPath()) - ->with('status', trans($response)); + return redirect('/'); } /** * Get the response for a failed password reset. - * - * @param \Illuminate\Http\Request $request - * @param string $response - * - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse */ - protected function sendResetFailedResponse(Request $request, $response) + protected function sendResetFailedResponse(Request $request, string $response): RedirectResponse { // We show invalid users as invalid tokens as to not leak what // users may exist in the system. diff --git a/app/Http/Controllers/Auth/Saml2Controller.php b/app/Http/Controllers/Auth/Saml2Controller.php index b84483961..b3f8e7601 100644 --- a/app/Http/Controllers/Auth/Saml2Controller.php +++ b/app/Http/Controllers/Auth/Saml2Controller.php @@ -9,7 +9,7 @@ use Illuminate\Support\Str; class Saml2Controller extends Controller { - protected $samlService; + protected Saml2Service $samlService; /** * Saml2Controller constructor. diff --git a/app/Http/Controllers/Auth/SocialController.php b/app/Http/Controllers/Auth/SocialController.php index 1691668a2..9ba4028ec 100644 --- a/app/Http/Controllers/Auth/SocialController.php +++ b/app/Http/Controllers/Auth/SocialController.php @@ -16,9 +16,9 @@ use Laravel\Socialite\Contracts\User as SocialUser; class SocialController extends Controller { - protected $socialAuthService; - protected $registrationService; - protected $loginService; + protected SocialAuthService $socialAuthService; + protected RegistrationService $registrationService; + protected LoginService $loginService; /** * SocialController constructor. @@ -28,7 +28,7 @@ class SocialController extends Controller RegistrationService $registrationService, LoginService $loginService ) { - $this->middleware('guest')->only(['getRegister', 'postRegister']); + $this->middleware('guest')->only(['register']); $this->socialAuthService = $socialAuthService; $this->registrationService = $registrationService; $this->loginService = $loginService; diff --git a/app/Http/Controllers/Auth/ThrottlesLogins.php b/app/Http/Controllers/Auth/ThrottlesLogins.php new file mode 100644 index 000000000..7578ba898 --- /dev/null +++ b/app/Http/Controllers/Auth/ThrottlesLogins.php @@ -0,0 +1,92 @@ +limiter()->tooManyAttempts( + $this->throttleKey($request), + $this->maxAttempts() + ); + } + + /** + * Increment the login attempts for the user. + */ + protected function incrementLoginAttempts(Request $request): void + { + $this->limiter()->hit( + $this->throttleKey($request), + $this->decayMinutes() * 60 + ); + } + + /** + * Redirect the user after determining they are locked out. + * @throws ValidationException + */ + protected function sendLockoutResponse(Request $request): \Symfony\Component\HttpFoundation\Response + { + $seconds = $this->limiter()->availableIn( + $this->throttleKey($request) + ); + + throw ValidationException::withMessages([ + $this->username() => [trans('auth.throttle', [ + 'seconds' => $seconds, + 'minutes' => ceil($seconds / 60), + ])], + ])->status(Response::HTTP_TOO_MANY_REQUESTS); + } + + /** + * Clear the login locks for the given user credentials. + */ + protected function clearLoginAttempts(Request $request): void + { + $this->limiter()->clear($this->throttleKey($request)); + } + + /** + * Get the throttle key for the given request. + */ + protected function throttleKey(Request $request): string + { + return Str::transliterate(Str::lower($request->input($this->username())) . '|' . $request->ip()); + } + + /** + * Get the rate limiter instance. + */ + protected function limiter(): RateLimiter + { + return app(RateLimiter::class); + } + + /** + * Get the maximum number of attempts to allow. + */ + public function maxAttempts(): int + { + return 5; + } + + /** + * Get the number of minutes to throttle for. + */ + public function decayMinutes(): int + { + return 1; + } +} diff --git a/app/Http/Controllers/Auth/UserInviteController.php b/app/Http/Controllers/Auth/UserInviteController.php index 27b20f831..5b3bba6ff 100644 --- a/app/Http/Controllers/Auth/UserInviteController.php +++ b/app/Http/Controllers/Auth/UserInviteController.php @@ -11,12 +11,13 @@ use Exception; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Routing\Redirector; +use Illuminate\Support\Facades\Hash; use Illuminate\Validation\Rules\Password; class UserInviteController extends Controller { - protected $inviteService; - protected $userRepo; + protected UserInviteService $inviteService; + protected UserRepo $userRepo; /** * Create a new controller instance. @@ -66,7 +67,7 @@ class UserInviteController extends Controller } $user = $this->userRepo->getById($userId); - $user->password = bcrypt($request->get('password')); + $user->password = Hash::make($request->get('password')); $user->email_confirmed = true; $user->save(); diff --git a/app/Http/Controllers/BookController.php b/app/Http/Controllers/BookController.php index cc2f6f534..b323ae496 100644 --- a/app/Http/Controllers/BookController.php +++ b/app/Http/Controllers/BookController.php @@ -10,7 +10,6 @@ use BookStack\Entities\Repos\BookRepo; use BookStack\Entities\Tools\BookContents; use BookStack\Entities\Tools\Cloner; use BookStack\Entities\Tools\HierarchyTransformer; -use BookStack\Entities\Tools\PermissionsUpdater; use BookStack\Entities\Tools\ShelfContext; use BookStack\Exceptions\ImageUploadException; use BookStack\Exceptions\NotFoundException; @@ -209,36 +208,6 @@ class BookController extends Controller return redirect('/books'); } - /** - * Show the permissions view. - */ - public function showPermissions(string $bookSlug) - { - $book = $this->bookRepo->getBySlug($bookSlug); - $this->checkOwnablePermission('restrictions-manage', $book); - - return view('books.permissions', [ - 'book' => $book, - ]); - } - - /** - * Set the restrictions for this book. - * - * @throws Throwable - */ - public function permissions(Request $request, PermissionsUpdater $permissionsUpdater, string $bookSlug) - { - $book = $this->bookRepo->getBySlug($bookSlug); - $this->checkOwnablePermission('restrictions-manage', $book); - - $permissionsUpdater->updateFromPermissionsForm($book, $request); - - $this->showSuccessNotification(trans('entities.books_permissions_updated')); - - return redirect($book->getUrl()); - } - /** * Show the view to copy a book. * diff --git a/app/Http/Controllers/BookshelfController.php b/app/Http/Controllers/BookshelfController.php index 2143b876a..3c63be631 100644 --- a/app/Http/Controllers/BookshelfController.php +++ b/app/Http/Controllers/BookshelfController.php @@ -6,7 +6,6 @@ use BookStack\Actions\ActivityQueries; use BookStack\Actions\View; use BookStack\Entities\Models\Book; use BookStack\Entities\Repos\BookshelfRepo; -use BookStack\Entities\Tools\PermissionsUpdater; use BookStack\Entities\Tools\ShelfContext; use BookStack\Exceptions\ImageUploadException; use BookStack\Exceptions\NotFoundException; @@ -207,46 +206,4 @@ class BookshelfController extends Controller return redirect('/shelves'); } - - /** - * Show the permissions view. - */ - public function showPermissions(string $slug) - { - $shelf = $this->shelfRepo->getBySlug($slug); - $this->checkOwnablePermission('restrictions-manage', $shelf); - - return view('shelves.permissions', [ - 'shelf' => $shelf, - ]); - } - - /** - * Set the permissions for this bookshelf. - */ - public function permissions(Request $request, PermissionsUpdater $permissionsUpdater, string $slug) - { - $shelf = $this->shelfRepo->getBySlug($slug); - $this->checkOwnablePermission('restrictions-manage', $shelf); - - $permissionsUpdater->updateFromPermissionsForm($shelf, $request); - - $this->showSuccessNotification(trans('entities.shelves_permissions_updated')); - - return redirect($shelf->getUrl()); - } - - /** - * Copy the permissions of a bookshelf to the child books. - */ - public function copyPermissions(string $slug) - { - $shelf = $this->shelfRepo->getBySlug($slug); - $this->checkOwnablePermission('restrictions-manage', $shelf); - - $updateCount = $this->shelfRepo->copyDownPermissions($shelf); - $this->showSuccessNotification(trans('entities.shelves_copy_permission_success', ['count' => $updateCount])); - - return redirect($shelf->getUrl()); - } } diff --git a/app/Http/Controllers/ChapterController.php b/app/Http/Controllers/ChapterController.php index 6695c2868..4d2bcb2f1 100644 --- a/app/Http/Controllers/ChapterController.php +++ b/app/Http/Controllers/ChapterController.php @@ -9,7 +9,6 @@ use BookStack\Entities\Tools\BookContents; use BookStack\Entities\Tools\Cloner; use BookStack\Entities\Tools\HierarchyTransformer; use BookStack\Entities\Tools\NextPreviousContentLocator; -use BookStack\Entities\Tools\PermissionsUpdater; use BookStack\Exceptions\MoveOperationException; use BookStack\Exceptions\NotFoundException; use BookStack\Exceptions\PermissionsException; @@ -243,38 +242,6 @@ class ChapterController extends Controller return redirect($chapterCopy->getUrl()); } - /** - * Show the Restrictions view. - * - * @throws NotFoundException - */ - public function showPermissions(string $bookSlug, string $chapterSlug) - { - $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); - $this->checkOwnablePermission('restrictions-manage', $chapter); - - return view('chapters.permissions', [ - 'chapter' => $chapter, - ]); - } - - /** - * Set the restrictions for this chapter. - * - * @throws NotFoundException - */ - public function permissions(Request $request, PermissionsUpdater $permissionsUpdater, string $bookSlug, string $chapterSlug) - { - $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); - $this->checkOwnablePermission('restrictions-manage', $chapter); - - $permissionsUpdater->updateFromPermissionsForm($chapter, $request); - - $this->showSuccessNotification(trans('entities.chapters_permissions_success')); - - return redirect($chapter->getUrl()); - } - /** * Convert the chapter to a book. */ diff --git a/app/Http/Controllers/FavouriteController.php b/app/Http/Controllers/FavouriteController.php index f77b04843..e46442a64 100644 --- a/app/Http/Controllers/FavouriteController.php +++ b/app/Http/Controllers/FavouriteController.php @@ -87,7 +87,7 @@ class FavouriteController extends Controller $modelInstance = $model->newQuery() ->where('id', '=', $modelInfo['id']) - ->first(['id', 'name', 'restricted', 'owned_by']); + ->first(['id', 'name', 'owned_by']); $inaccessibleEntity = ($modelInstance instanceof Entity && !userCan('view', $modelInstance)); if (is_null($modelInstance) || $inaccessibleEntity) { diff --git a/app/Http/Controllers/PageController.php b/app/Http/Controllers/PageController.php index 748468b21..9e09aed16 100644 --- a/app/Http/Controllers/PageController.php +++ b/app/Http/Controllers/PageController.php @@ -11,7 +11,6 @@ use BookStack\Entities\Tools\NextPreviousContentLocator; use BookStack\Entities\Tools\PageContent; use BookStack\Entities\Tools\PageEditActivity; use BookStack\Entities\Tools\PageEditorData; -use BookStack\Entities\Tools\PermissionsUpdater; use BookStack\Exceptions\NotFoundException; use BookStack\Exceptions\PermissionsException; use BookStack\References\ReferenceFetcher; @@ -452,37 +451,4 @@ class PageController extends Controller return redirect($pageCopy->getUrl()); } - - /** - * Show the Permissions view. - * - * @throws NotFoundException - */ - public function showPermissions(string $bookSlug, string $pageSlug) - { - $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); - $this->checkOwnablePermission('restrictions-manage', $page); - - return view('pages.permissions', [ - 'page' => $page, - ]); - } - - /** - * Set the permissions for this page. - * - * @throws NotFoundException - * @throws Throwable - */ - public function permissions(Request $request, PermissionsUpdater $permissionsUpdater, string $bookSlug, string $pageSlug) - { - $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); - $this->checkOwnablePermission('restrictions-manage', $page); - - $permissionsUpdater->updateFromPermissionsForm($page, $request); - - $this->showSuccessNotification(trans('entities.pages_permissions_success')); - - return redirect($page->getUrl()); - } } diff --git a/app/Http/Controllers/PermissionsController.php b/app/Http/Controllers/PermissionsController.php new file mode 100644 index 000000000..7d908733b --- /dev/null +++ b/app/Http/Controllers/PermissionsController.php @@ -0,0 +1,174 @@ +permissionsUpdater = $permissionsUpdater; + } + + /** + * Show the Permissions view for a page. + */ + public function showForPage(string $bookSlug, string $pageSlug) + { + $page = Page::getBySlugs($bookSlug, $pageSlug); + $this->checkOwnablePermission('restrictions-manage', $page); + + $this->setPageTitle(trans('entities.pages_permissions')); + return view('pages.permissions', [ + 'page' => $page, + 'data' => new PermissionFormData($page), + ]); + } + + /** + * Set the permissions for a page. + */ + public function updateForPage(Request $request, string $bookSlug, string $pageSlug) + { + $page = Page::getBySlugs($bookSlug, $pageSlug); + $this->checkOwnablePermission('restrictions-manage', $page); + + $this->permissionsUpdater->updateFromPermissionsForm($page, $request); + + $this->showSuccessNotification(trans('entities.pages_permissions_success')); + + return redirect($page->getUrl()); + } + + /** + * Show the Restrictions view for a chapter. + */ + public function showForChapter(string $bookSlug, string $chapterSlug) + { + $chapter = Chapter::getBySlugs($bookSlug, $chapterSlug); + $this->checkOwnablePermission('restrictions-manage', $chapter); + + $this->setPageTitle(trans('entities.chapters_permissions')); + return view('chapters.permissions', [ + 'chapter' => $chapter, + 'data' => new PermissionFormData($chapter), + ]); + } + + /** + * Set the restrictions for a chapter. + */ + public function updateForChapter(Request $request, string $bookSlug, string $chapterSlug) + { + $chapter = Chapter::getBySlugs($bookSlug, $chapterSlug); + $this->checkOwnablePermission('restrictions-manage', $chapter); + + $this->permissionsUpdater->updateFromPermissionsForm($chapter, $request); + + $this->showSuccessNotification(trans('entities.chapters_permissions_success')); + + return redirect($chapter->getUrl()); + } + + /** + * Show the permissions view for a book. + */ + public function showForBook(string $slug) + { + $book = Book::getBySlug($slug); + $this->checkOwnablePermission('restrictions-manage', $book); + + $this->setPageTitle(trans('entities.books_permissions')); + return view('books.permissions', [ + 'book' => $book, + 'data' => new PermissionFormData($book), + ]); + } + + /** + * Set the restrictions for a book. + */ + public function updateForBook(Request $request, string $slug) + { + $book = Book::getBySlug($slug); + $this->checkOwnablePermission('restrictions-manage', $book); + + $this->permissionsUpdater->updateFromPermissionsForm($book, $request); + + $this->showSuccessNotification(trans('entities.books_permissions_updated')); + + return redirect($book->getUrl()); + } + + /** + * Show the permissions view for a shelf. + */ + public function showForShelf(string $slug) + { + $shelf = Bookshelf::getBySlug($slug); + $this->checkOwnablePermission('restrictions-manage', $shelf); + + $this->setPageTitle(trans('entities.shelves_permissions')); + return view('shelves.permissions', [ + 'shelf' => $shelf, + 'data' => new PermissionFormData($shelf), + ]); + } + + /** + * Set the permissions for a shelf. + */ + public function updateForShelf(Request $request, string $slug) + { + $shelf = Bookshelf::getBySlug($slug); + $this->checkOwnablePermission('restrictions-manage', $shelf); + + $this->permissionsUpdater->updateFromPermissionsForm($shelf, $request); + + $this->showSuccessNotification(trans('entities.shelves_permissions_updated')); + + return redirect($shelf->getUrl()); + } + + /** + * Copy the permissions of a bookshelf to the child books. + */ + public function copyShelfPermissionsToBooks(string $slug) + { + $shelf = Bookshelf::getBySlug($slug); + $this->checkOwnablePermission('restrictions-manage', $shelf); + + $updateCount = $this->permissionsUpdater->updateBookPermissionsFromShelf($shelf); + $this->showSuccessNotification(trans('entities.shelves_copy_permission_success', ['count' => $updateCount])); + + return redirect($shelf->getUrl()); + } + + /** + * Get an empty entity permissions form row for the given role. + */ + public function formRowForRole(string $entityType, string $roleId) + { + $this->checkPermissionOr('restrictions-manage-all', fn() => userCan('restrictions-manage-own')); + + $role = Role::query()->findOrFail($roleId); + + return view('form.entity-permissions-row', [ + 'role' => $role, + 'permission' => new EntityPermission(), + 'entityType' => $entityType, + 'inheriting' => false, + ]); + } +} diff --git a/app/Http/Controllers/ReferenceController.php b/app/Http/Controllers/ReferenceController.php index 1daf1818c..b9b3e0eab 100644 --- a/app/Http/Controllers/ReferenceController.php +++ b/app/Http/Controllers/ReferenceController.php @@ -22,8 +22,7 @@ class ReferenceController extends Controller */ public function page(string $bookSlug, string $pageSlug) { - /** @var Page $page */ - $page = Page::visible()->whereSlugs($bookSlug, $pageSlug)->firstOrFail(); + $page = Page::getBySlugs($bookSlug, $pageSlug); $references = $this->referenceFetcher->getPageReferencesToEntity($page); return view('pages.references', [ @@ -37,8 +36,7 @@ class ReferenceController extends Controller */ public function chapter(string $bookSlug, string $chapterSlug) { - /** @var Chapter $chapter */ - $chapter = Chapter::visible()->whereSlugs($bookSlug, $chapterSlug)->firstOrFail(); + $chapter = Chapter::getBySlugs($bookSlug, $chapterSlug); $references = $this->referenceFetcher->getPageReferencesToEntity($chapter); return view('chapters.references', [ @@ -52,7 +50,7 @@ class ReferenceController extends Controller */ public function book(string $slug) { - $book = Book::visible()->where('slug', '=', $slug)->firstOrFail(); + $book = Book::getBySlug($slug); $references = $this->referenceFetcher->getPageReferencesToEntity($book); return view('books.references', [ @@ -66,7 +64,7 @@ class ReferenceController extends Controller */ public function shelf(string $slug) { - $shelf = Bookshelf::visible()->where('slug', '=', $slug)->firstOrFail(); + $shelf = Bookshelf::getBySlug($slug); $references = $this->referenceFetcher->getPageReferencesToEntity($shelf); return view('shelves.references', [ diff --git a/app/Http/Controllers/TagController.php b/app/Http/Controllers/TagController.php index e59580b60..056cc9902 100644 --- a/app/Http/Controllers/TagController.php +++ b/app/Http/Controllers/TagController.php @@ -7,11 +7,8 @@ use Illuminate\Http\Request; class TagController extends Controller { - protected $tagRepo; + protected TagRepo $tagRepo; - /** - * TagController constructor. - */ public function __construct(TagRepo $tagRepo) { $this->tagRepo = $tagRepo; @@ -46,7 +43,7 @@ class TagController extends Controller */ public function getNameSuggestions(Request $request) { - $searchTerm = $request->get('search', null); + $searchTerm = $request->get('search', ''); $suggestions = $this->tagRepo->getNameSuggestions($searchTerm); return response()->json($suggestions); @@ -57,8 +54,8 @@ class TagController extends Controller */ public function getValueSuggestions(Request $request) { - $searchTerm = $request->get('search', null); - $tagName = $request->get('name', null); + $searchTerm = $request->get('search', ''); + $tagName = $request->get('name', ''); $suggestions = $this->tagRepo->getValueSuggestions($searchTerm, $tagName); return response()->json($suggestions); diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 3c1212e32..d0841059b 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,32 +2,44 @@ namespace BookStack\Providers; -use BookStack\Auth\Access\LoginService; +use BookStack\Actions\ActivityLogger; use BookStack\Auth\Access\SocialAuthService; -use BookStack\Entities\BreadcrumbsViewComposer; 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 GuzzleHttp\Client; -use Illuminate\Contracts\Cache\Repository; use Illuminate\Database\Eloquent\Relations\Relation; -use Illuminate\Pagination\Paginator; -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 Psr\Http\Client\ClientInterface as HttpClientInterface; use Whoops\Handler\HandlerInterface; class AppServiceProvider extends ServiceProvider { + /** + * Custom container bindings to register. + * @var string[] + */ + public $bindings = [ + HandlerInterface::class => WhoopsBookStackPrettyHandler::class, + ]; + + /** + * Custom singleton bindings to register. + * @var string[] + */ + public $singletons = [ + 'activity' => ActivityLogger::class, + SettingService::class => SettingService::class, + SocialAuthService::class => SocialAuthService::class, + CspService::class => CspService::class, + ]; + /** * Bootstrap any application services. * @@ -43,11 +55,6 @@ class AppServiceProvider extends ServiceProvider URL::forceScheme($isHttps ? 'https' : 'http'); } - // Custom blade view directives - Blade::directive('icon', function ($expression) { - return ""; - }); - // Allow longer string lengths after upgrade to utf8mb4 Schema::defaultStringLength(191); @@ -58,12 +65,6 @@ class AppServiceProvider extends ServiceProvider 'chapter' => Chapter::class, 'page' => Page::class, ]); - - // View Composers - View::composer('entities.breadcrumbs', BreadcrumbsViewComposer::class); - - // Set paginator to use bootstrap-style pagination - Paginator::useBootstrap(); } /** @@ -73,22 +74,6 @@ 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)); - }); - - $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(); - }); - $this->app->bind(HttpClientInterface::class, function ($app) { return new Client([ 'timeout' => 3, diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index a4022cc50..5e16179ab 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -24,9 +24,7 @@ class AuthServiceProvider extends ServiceProvider { // Password Configuration // Changes here must be reflected in ApiDocsGenerate@getValidationAsString. - Password::defaults(function () { - return Password::min(8); - }); + Password::defaults(fn () => Password::min(8)); // Custom guards Auth::extend('api-token', function ($app, $name, array $config) { diff --git a/app/Providers/BroadcastServiceProvider.php b/app/Providers/BroadcastServiceProvider.php deleted file mode 100644 index 69925e945..000000000 --- a/app/Providers/BroadcastServiceProvider.php +++ /dev/null @@ -1,25 +0,0 @@ -id === (int) $userId; -// }); - } -} diff --git a/app/Providers/CustomFacadeProvider.php b/app/Providers/CustomFacadeProvider.php deleted file mode 100644 index 6ba5632e6..000000000 --- a/app/Providers/CustomFacadeProvider.php +++ /dev/null @@ -1,36 +0,0 @@ -app->singleton('activity', function () { - return $this->app->make(ActivityLogger::class); - }); - - $this->app->singleton('theme', function () { - return $this->app->make(ThemeService::class); - }); - } -} diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 659843ce3..0edc7f09c 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -10,7 +10,7 @@ class EventServiceProvider extends ServiceProvider /** * The event listener mappings for the application. * - * @var array + * @var array> */ protected $listen = [ SocialiteWasCalled::class => [ diff --git a/app/Providers/PaginationServiceProvider.php b/app/Providers/PaginationServiceProvider.php deleted file mode 100644 index 416aa5f34..000000000 --- a/app/Providers/PaginationServiceProvider.php +++ /dev/null @@ -1,35 +0,0 @@ -app['view']; - }); - - Paginator::currentPathResolver(function () { - return url($this->app['request']->path()); - }); - - Paginator::currentPageResolver(function ($pageName = 'page') { - $page = $this->app['request']->input($pageName); - - if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int) $page >= 1) { - return $page; - } - - return 1; - }); - } -} diff --git a/app/Providers/ThemeServiceProvider.php b/app/Providers/ThemeServiceProvider.php index 54c83884a..50c4a5d19 100644 --- a/app/Providers/ThemeServiceProvider.php +++ b/app/Providers/ThemeServiceProvider.php @@ -15,9 +15,8 @@ class ThemeServiceProvider extends ServiceProvider */ public function register() { - $this->app->singleton(ThemeService::class, function ($app) { - return new ThemeService(); - }); + // Register the ThemeService as a singleton + $this->app->singleton(ThemeService::class, fn ($app) => new ThemeService()); } /** @@ -27,6 +26,7 @@ class ThemeServiceProvider extends ServiceProvider */ public function boot() { + // Boot up the theme system $themeService = $this->app->make(ThemeService::class); $themeService->readThemeActions(); $themeService->dispatch(ThemeEvents::APP_BOOT, $this->app); diff --git a/app/Providers/CustomValidationServiceProvider.php b/app/Providers/ValidationRuleServiceProvider.php similarity index 93% rename from app/Providers/CustomValidationServiceProvider.php rename to app/Providers/ValidationRuleServiceProvider.php index ac95099cc..928918dc7 100644 --- a/app/Providers/CustomValidationServiceProvider.php +++ b/app/Providers/ValidationRuleServiceProvider.php @@ -6,7 +6,7 @@ use BookStack\Uploads\ImageService; use Illuminate\Support\Facades\Validator; use Illuminate\Support\ServiceProvider; -class CustomValidationServiceProvider extends ServiceProvider +class ValidationRuleServiceProvider extends ServiceProvider { /** * Register our custom validation rules when the application boots. diff --git a/app/Providers/ViewTweaksServiceProvider.php b/app/Providers/ViewTweaksServiceProvider.php new file mode 100644 index 000000000..f1f1554ae --- /dev/null +++ b/app/Providers/ViewTweaksServiceProvider.php @@ -0,0 +1,31 @@ +"; + }); + } +} diff --git a/app/Search/SearchRunner.php b/app/Search/SearchRunner.php index e36edb06c..cc44e6125 100644 --- a/app/Search/SearchRunner.php +++ b/app/Search/SearchRunner.php @@ -162,7 +162,7 @@ class SearchRunner $entityQuery = $entityModelInstance->newQuery()->scopes('visible'); if ($entityModelInstance instanceof Page) { - $entityQuery->select(array_merge($entityModelInstance::$listAttributes, ['restricted', 'owned_by'])); + $entityQuery->select(array_merge($entityModelInstance::$listAttributes, ['owned_by'])); } else { $entityQuery->select(['*']); } @@ -447,7 +447,7 @@ class SearchRunner protected function filterIsRestricted(EloquentBuilder $query, Entity $model, $input) { - $query->where('restricted', '=', true); + $query->whereHas('permissions'); } protected function filterViewedByMe(EloquentBuilder $query, Entity $model, $input) diff --git a/app/Util/LanguageManager.php b/app/Util/LanguageManager.php index 201bbda3d..ed68f647c 100644 --- a/app/Util/LanguageManager.php +++ b/app/Util/LanguageManager.php @@ -28,6 +28,7 @@ class LanguageManager 'de' => ['iso' => 'de_DE', 'windows' => 'German'], 'de_informal' => ['iso' => 'de_DE', 'windows' => 'German'], 'en' => ['iso' => 'en_GB', 'windows' => 'English'], + 'el' => ['iso' => 'el_GR', 'windows' => 'Greek'], 'es' => ['iso' => 'es_ES', 'windows' => 'Spanish'], 'es_AR' => ['iso' => 'es_AR', 'windows' => 'Spanish'], 'et' => ['iso' => 'et_EE', 'windows' => 'Estonian'], diff --git a/composer.json b/composer.json index 64630833d..59c96ba29 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,6 @@ "laravel/framework": "^8.68", "laravel/socialite": "^5.2", "laravel/tinker": "^2.6", - "laravel/ui": "^3.3", "league/commonmark": "^1.6", "league/flysystem-aws-s3-v3": "^1.0.29", "league/html-to-markdown": "^5.0.0", @@ -44,6 +43,7 @@ "ssddanbrown/htmldiff": "^1.0.2" }, "require-dev": { + "brianium/paratest": "^6.6", "fakerphp/faker": "^1.16", "itsgoingd/clockwork": "^5.1", "mockery/mockery": "^1.4", @@ -73,6 +73,8 @@ "format": "phpcbf", "lint": "phpcs", "test": "phpunit", + "t": "@php artisan test --parallel", + "t-reset": "@php artisan test --recreate-databases", "post-autoload-dump": [ "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", "@php artisan package:discover --ansi" diff --git a/composer.lock b/composer.lock index b807fd577..5ed41c1da 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1d3bd88b99d07b5410ee4b245bece28e", + "content-hash": "1fed6278d440ef18af1ffa6ca7b29166", "packages": [ { "name": "aws/aws-crt-php", @@ -58,16 +58,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.235.1", + "version": "3.238.5", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "2025db05c7dd22ae414857dadd49207f64c2fc74" + "reference": "2f5440652fa7a6f20a1bb15926dd8248c24c733c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/2025db05c7dd22ae414857dadd49207f64c2fc74", - "reference": "2025db05c7dd22ae414857dadd49207f64c2fc74", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/2f5440652fa7a6f20a1bb15926dd8248c24c733c", + "reference": "2f5440652fa7a6f20a1bb15926dd8248c24c733c", "shasum": "" }, "require": { @@ -86,6 +86,7 @@ "aws/aws-php-sns-message-validator": "~1.0", "behat/behat": "~3.0", "composer/composer": "^1.10.22", + "dms/phpunit-arraysubset-asserts": "^0.4.0", "doctrine/cache": "~1.4", "ext-dom": "*", "ext-openssl": "*", @@ -93,10 +94,11 @@ "ext-sockets": "*", "nette/neon": "^2.3", "paragonie/random_compat": ">= 2", - "phpunit/phpunit": "^4.8.35 || ^5.6.3", + "phpunit/phpunit": "^4.8.35 || ^5.6.3 || ^9.5", "psr/cache": "^1.0", "psr/simple-cache": "^1.0", - "sebastian/comparator": "^1.2.3" + "sebastian/comparator": "^1.2.3 || ^4.0", + "yoast/phpunit-polyfills": "^1.0" }, "suggest": { "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", @@ -144,9 +146,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.235.1" + "source": "https://github.com/aws/aws-sdk-php/tree/3.238.5" }, - "time": "2022-09-02T18:18:19+00:00" + "time": "2022-10-14T18:15:06+00:00" }, { "name": "bacon/bacon-qr-code", @@ -559,16 +561,16 @@ }, { "name": "doctrine/dbal", - "version": "3.4.3", + "version": "3.4.5", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "a24b89d663d8f261199bc0a91c48016042ebda85" + "reference": "a5a58773109c0abb13e658c8ccd92aeec8d07f9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/a24b89d663d8f261199bc0a91c48016042ebda85", - "reference": "a24b89d663d8f261199bc0a91c48016042ebda85", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/a5a58773109c0abb13e658c8ccd92aeec8d07f9e", + "reference": "a5a58773109c0abb13e658c8ccd92aeec8d07f9e", "shasum": "" }, "require": { @@ -583,14 +585,14 @@ "require-dev": { "doctrine/coding-standard": "10.0.0", "jetbrains/phpstorm-stubs": "2022.2", - "phpstan/phpstan": "1.8.2", + "phpstan/phpstan": "1.8.3", "phpstan/phpstan-strict-rules": "^1.3", - "phpunit/phpunit": "9.5.21", + "phpunit/phpunit": "9.5.24", "psalm/plugin-phpunit": "0.17.0", "squizlabs/php_codesniffer": "3.7.1", "symfony/cache": "^5.4|^6.0", "symfony/console": "^4.4|^5.4|^6.0", - "vimeo/psalm": "4.24.0" + "vimeo/psalm": "4.27.0" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -650,7 +652,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.4.3" + "source": "https://github.com/doctrine/dbal/tree/3.4.5" }, "funding": [ { @@ -666,7 +668,7 @@ "type": "tidelift" } ], - "time": "2022-08-28T17:26:36+00:00" + "time": "2022-09-23T17:48:57+00:00" }, { "name": "doctrine/deprecations", @@ -713,34 +715,35 @@ }, { "name": "doctrine/event-manager", - "version": "1.1.2", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/event-manager.git", - "reference": "eb2ecf80e3093e8f3c2769ac838e27d8ede8e683" + "reference": "95aa4cb529f1e96576f3fda9f5705ada4056a520" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/event-manager/zipball/eb2ecf80e3093e8f3c2769ac838e27d8ede8e683", - "reference": "eb2ecf80e3093e8f3c2769ac838e27d8ede8e683", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/95aa4cb529f1e96576f3fda9f5705ada4056a520", + "reference": "95aa4cb529f1e96576f3fda9f5705ada4056a520", "shasum": "" }, "require": { + "doctrine/deprecations": "^0.5.3 || ^1", "php": "^7.1 || ^8.0" }, "conflict": { "doctrine/common": "<2.9" }, "require-dev": { - "doctrine/coding-standard": "^9", - "phpstan/phpstan": "~1.4.10 || ^1.5.4", + "doctrine/coding-standard": "^9 || ^10", + "phpstan/phpstan": "~1.4.10 || ^1.8.8", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.22" + "vimeo/psalm": "^4.24" }, "type": "library", "autoload": { "psr-4": { - "Doctrine\\Common\\": "lib/Doctrine/Common" + "Doctrine\\Common\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -784,7 +787,7 @@ ], "support": { "issues": "https://github.com/doctrine/event-manager/issues", - "source": "https://github.com/doctrine/event-manager/tree/1.1.2" + "source": "https://github.com/doctrine/event-manager/tree/1.2.0" }, "funding": [ { @@ -800,32 +803,32 @@ "type": "tidelift" } ], - "time": "2022-07-27T22:18:11+00:00" + "time": "2022-10-12T20:51:15+00:00" }, { "name": "doctrine/inflector", - "version": "2.0.4", + "version": "2.0.5", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "8b7ff3e4b7de6b2c84da85637b59fd2880ecaa89" + "reference": "ade2b3bbfb776f27f0558e26eed43b5d9fe1b392" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/8b7ff3e4b7de6b2c84da85637b59fd2880ecaa89", - "reference": "8b7ff3e4b7de6b2c84da85637b59fd2880ecaa89", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/ade2b3bbfb776f27f0558e26eed43b5d9fe1b392", + "reference": "ade2b3bbfb776f27f0558e26eed43b5d9fe1b392", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^8.2", - "phpstan/phpstan": "^0.12", - "phpstan/phpstan-phpunit": "^0.12", - "phpstan/phpstan-strict-rules": "^0.12", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", - "vimeo/psalm": "^4.10" + "doctrine/coding-standard": "^9", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.3", + "phpunit/phpunit": "^8.5 || ^9.5", + "vimeo/psalm": "^4.25" }, "type": "library", "autoload": { @@ -875,7 +878,7 @@ ], "support": { "issues": "https://github.com/doctrine/inflector/issues", - "source": "https://github.com/doctrine/inflector/tree/2.0.4" + "source": "https://github.com/doctrine/inflector/tree/2.0.5" }, "funding": [ { @@ -891,7 +894,7 @@ "type": "tidelift" } ], - "time": "2021-10-22T20:16:43+00:00" + "time": "2022-09-07T09:01:28+00:00" }, { "name": "doctrine/lexer", @@ -971,24 +974,24 @@ }, { "name": "dompdf/dompdf", - "version": "v2.0.0", + "version": "v2.0.1", "source": { "type": "git", "url": "https://github.com/dompdf/dompdf.git", - "reference": "79573d8b8a141ec8a17312515de8740eed014fa9" + "reference": "c5310df0e22c758c85ea5288175fc6cd777bc085" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/dompdf/zipball/79573d8b8a141ec8a17312515de8740eed014fa9", - "reference": "79573d8b8a141ec8a17312515de8740eed014fa9", + "url": "https://api.github.com/repos/dompdf/dompdf/zipball/c5310df0e22c758c85ea5288175fc6cd777bc085", + "reference": "c5310df0e22c758c85ea5288175fc6cd777bc085", "shasum": "" }, "require": { "ext-dom": "*", "ext-mbstring": "*", "masterminds/html5": "^2.0", - "phenx/php-font-lib": "^0.5.4", - "phenx/php-svg-lib": "^0.3.3 || ^0.4.0", + "phenx/php-font-lib": ">=0.5.4 <1.0.0", + "phenx/php-svg-lib": ">=0.3.3 <1.0.0", "php": "^7.1 || ^8.0" }, "require-dev": { @@ -1019,38 +1022,30 @@ ], "authors": [ { - "name": "Fabien Ménager", - "email": "fabien.menager@gmail.com" - }, - { - "name": "Brian Sweeney", - "email": "eclecticgeek@gmail.com" - }, - { - "name": "Gabriel Bull", - "email": "me@gabrielbull.com" + "name": "The Dompdf Community", + "homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md" } ], "description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter", "homepage": "https://github.com/dompdf/dompdf", "support": { "issues": "https://github.com/dompdf/dompdf/issues", - "source": "https://github.com/dompdf/dompdf/tree/v2.0.0" + "source": "https://github.com/dompdf/dompdf/tree/v2.0.1" }, - "time": "2022-06-21T21:14:57+00:00" + "time": "2022-09-22T13:43:41+00:00" }, { "name": "dragonmantank/cron-expression", - "version": "v3.3.1", + "version": "v3.3.2", "source": { "type": "git", "url": "https://github.com/dragonmantank/cron-expression.git", - "reference": "be85b3f05b46c39bbc0d95f6c071ddff669510fa" + "reference": "782ca5968ab8b954773518e9e49a6f892a34b2a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/be85b3f05b46c39bbc0d95f6c071ddff669510fa", - "reference": "be85b3f05b46c39bbc0d95f6c071ddff669510fa", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/782ca5968ab8b954773518e9e49a6f892a34b2a8", + "reference": "782ca5968ab8b954773518e9e49a6f892a34b2a8", "shasum": "" }, "require": { @@ -1090,7 +1085,7 @@ ], "support": { "issues": "https://github.com/dragonmantank/cron-expression/issues", - "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.1" + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.2" }, "funding": [ { @@ -1098,7 +1093,7 @@ "type": "github" } ], - "time": "2022-01-18T15:43:28+00:00" + "time": "2022-09-10T18:51:20+00:00" }, { "name": "egulias/email-validator", @@ -1792,16 +1787,16 @@ }, { "name": "laravel/framework", - "version": "v8.83.23", + "version": "v8.83.25", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "bdc707f8b9bcad289b24cd182d98ec7480ac4491" + "reference": "b77b908a9426efa41d6286a2ef4c3adbf5398ca1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/bdc707f8b9bcad289b24cd182d98ec7480ac4491", - "reference": "bdc707f8b9bcad289b24cd182d98ec7480ac4491", + "url": "https://api.github.com/repos/laravel/framework/zipball/b77b908a9426efa41d6286a2ef4c3adbf5398ca1", + "reference": "b77b908a9426efa41d6286a2ef4c3adbf5398ca1", "shasum": "" }, "require": { @@ -1961,20 +1956,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2022-07-26T13:30:00+00:00" + "time": "2022-09-30T13:00:40+00:00" }, { "name": "laravel/serializable-closure", - "version": "v1.2.1", + "version": "v1.2.2", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "d78fd36ba031a1a695ea5a406f29996948d7011b" + "reference": "47afb7fae28ed29057fdca37e16a84f90cc62fae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/d78fd36ba031a1a695ea5a406f29996948d7011b", - "reference": "d78fd36ba031a1a695ea5a406f29996948d7011b", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/47afb7fae28ed29057fdca37e16a84f90cc62fae", + "reference": "47afb7fae28ed29057fdca37e16a84f90cc62fae", "shasum": "" }, "require": { @@ -2021,7 +2016,7 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2022-08-26T15:25:27+00:00" + "time": "2022-09-08T13:45:54+00:00" }, { "name": "laravel/socialite", @@ -2160,67 +2155,6 @@ }, "time": "2022-03-23T12:38:24+00:00" }, - { - "name": "laravel/ui", - "version": "v3.4.6", - "source": { - "type": "git", - "url": "https://github.com/laravel/ui.git", - "reference": "65ec5c03f7fee2c8ecae785795b829a15be48c2c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laravel/ui/zipball/65ec5c03f7fee2c8ecae785795b829a15be48c2c", - "reference": "65ec5c03f7fee2c8ecae785795b829a15be48c2c", - "shasum": "" - }, - "require": { - "illuminate/console": "^8.42|^9.0", - "illuminate/filesystem": "^8.42|^9.0", - "illuminate/support": "^8.82|^9.0", - "illuminate/validation": "^8.42|^9.0", - "php": "^7.3|^8.0" - }, - "require-dev": { - "orchestra/testbench": "^6.23|^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - }, - "laravel": { - "providers": [ - "Laravel\\Ui\\UiServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "Laravel\\Ui\\": "src/", - "Illuminate\\Foundation\\Auth\\": "auth-backend/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" - } - ], - "description": "Laravel UI utilities and presets.", - "keywords": [ - "laravel", - "ui" - ], - "support": { - "source": "https://github.com/laravel/ui/tree/v3.4.6" - }, - "time": "2022-05-20T13:38:08+00:00" - }, { "name": "league/commonmark", "version": "1.6.7", @@ -2316,16 +2250,16 @@ }, { "name": "league/flysystem", - "version": "1.1.9", + "version": "1.1.10", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "094defdb4a7001845300334e7c1ee2335925ef99" + "reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/094defdb4a7001845300334e7c1ee2335925ef99", - "reference": "094defdb4a7001845300334e7c1ee2335925ef99", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/3239285c825c152bcc315fe0e87d6b55f5972ed1", + "reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1", "shasum": "" }, "require": { @@ -2398,7 +2332,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/1.1.9" + "source": "https://github.com/thephpleague/flysystem/tree/1.1.10" }, "funding": [ { @@ -2406,7 +2340,7 @@ "type": "other" } ], - "time": "2021-12-09T09:40:50+00:00" + "time": "2022-10-04T09:16:37+00:00" }, { "name": "league/flysystem-aws-s3-v3", @@ -3438,21 +3372,21 @@ }, { "name": "phenx/php-svg-lib", - "version": "0.4.1", + "version": "0.5.0", "source": { "type": "git", "url": "https://github.com/dompdf/php-svg-lib.git", - "reference": "4498b5df7b08e8469f0f8279651ea5de9626ed02" + "reference": "76876c6cf3080bcb6f249d7d59705108166a6685" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/4498b5df7b08e8469f0f8279651ea5de9626ed02", - "reference": "4498b5df7b08e8469f0f8279651ea5de9626ed02", + "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/76876c6cf3080bcb6f249d7d59705108166a6685", + "reference": "76876c6cf3080bcb6f249d7d59705108166a6685", "shasum": "" }, "require": { "ext-mbstring": "*", - "php": "^7.1 || ^7.2 || ^7.3 || ^7.4 || ^8.0", + "php": "^7.1 || ^8.0", "sabberworm/php-css-parser": "^8.4" }, "require-dev": { @@ -3478,9 +3412,9 @@ "homepage": "https://github.com/PhenX/php-svg-lib", "support": { "issues": "https://github.com/dompdf/php-svg-lib/issues", - "source": "https://github.com/dompdf/php-svg-lib/tree/0.4.1" + "source": "https://github.com/dompdf/php-svg-lib/tree/0.5.0" }, - "time": "2022-03-07T12:52:04+00:00" + "time": "2022-09-06T12:16:56+00:00" }, { "name": "phpoption/phpoption", @@ -3559,16 +3493,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.15", + "version": "3.0.16", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "c96e250238e88bf1040e9f7715efab1d6bc7f622" + "reference": "7181378909ed8890be4db53d289faac5b77f8b05" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/c96e250238e88bf1040e9f7715efab1d6bc7f622", - "reference": "c96e250238e88bf1040e9f7715efab1d6bc7f622", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/7181378909ed8890be4db53d289faac5b77f8b05", + "reference": "7181378909ed8890be4db53d289faac5b77f8b05", "shasum": "" }, "require": { @@ -3649,7 +3583,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.15" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.16" }, "funding": [ { @@ -3665,7 +3599,7 @@ "type": "tidelift" } ], - "time": "2022-09-02T17:05:08+00:00" + "time": "2022-09-05T18:03:08+00:00" }, { "name": "pragmarx/google2fa", @@ -5055,16 +4989,16 @@ }, { "name": "symfony/console", - "version": "v5.4.12", + "version": "v5.4.14", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "c072aa8f724c3af64e2c7a96b796a4863d24dba1" + "reference": "984ea2c0f45f42dfed01d2f3987b187467c4b16d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/c072aa8f724c3af64e2c7a96b796a4863d24dba1", - "reference": "c072aa8f724c3af64e2c7a96b796a4863d24dba1", + "url": "https://api.github.com/repos/symfony/console/zipball/984ea2c0f45f42dfed01d2f3987b187467c4b16d", + "reference": "984ea2c0f45f42dfed01d2f3987b187467c4b16d", "shasum": "" }, "require": { @@ -5134,7 +5068,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.12" + "source": "https://github.com/symfony/console/tree/v5.4.14" }, "funding": [ { @@ -5150,7 +5084,7 @@ "type": "tidelift" } ], - "time": "2022-08-17T13:18:05+00:00" + "time": "2022-10-07T08:01:20+00:00" }, { "name": "symfony/css-selector", @@ -5287,16 +5221,16 @@ }, { "name": "symfony/error-handler", - "version": "v5.4.11", + "version": "v5.4.14", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "f75d17cb4769eb38cd5fccbda95cd80a054d35c8" + "reference": "5fe6d42ffeb68b094df8fdbf3acf23f391cc6be0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/f75d17cb4769eb38cd5fccbda95cd80a054d35c8", - "reference": "f75d17cb4769eb38cd5fccbda95cd80a054d35c8", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/5fe6d42ffeb68b094df8fdbf3acf23f391cc6be0", + "reference": "5fe6d42ffeb68b094df8fdbf3acf23f391cc6be0", "shasum": "" }, "require": { @@ -5338,7 +5272,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v5.4.11" + "source": "https://github.com/symfony/error-handler/tree/v5.4.14" }, "funding": [ { @@ -5354,7 +5288,7 @@ "type": "tidelift" } ], - "time": "2022-07-29T07:37:50+00:00" + "time": "2022-10-03T15:15:50+00:00" }, { "name": "symfony/event-dispatcher", @@ -5585,16 +5519,16 @@ }, { "name": "symfony/http-foundation", - "version": "v5.4.12", + "version": "v5.4.14", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "f4bfe9611b113b15d98a43da68ec9b5a00d56791" + "reference": "e7c7b395c3a61d746919c21e915f51f0039c3f75" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f4bfe9611b113b15d98a43da68ec9b5a00d56791", - "reference": "f4bfe9611b113b15d98a43da68ec9b5a00d56791", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e7c7b395c3a61d746919c21e915f51f0039c3f75", + "reference": "e7c7b395c3a61d746919c21e915f51f0039c3f75", "shasum": "" }, "require": { @@ -5641,7 +5575,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.4.12" + "source": "https://github.com/symfony/http-foundation/tree/v5.4.14" }, "funding": [ { @@ -5657,20 +5591,20 @@ "type": "tidelift" } ], - "time": "2022-08-19T07:33:17+00:00" + "time": "2022-10-01T21:59:28+00:00" }, { "name": "symfony/http-kernel", - "version": "v5.4.12", + "version": "v5.4.14", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "37f660fa3bcd78fe4893ce23ebe934618ec099be" + "reference": "6f77fabc1a37c2dceecc6f78cca44772705dc52f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/37f660fa3bcd78fe4893ce23ebe934618ec099be", - "reference": "37f660fa3bcd78fe4893ce23ebe934618ec099be", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/6f77fabc1a37c2dceecc6f78cca44772705dc52f", + "reference": "6f77fabc1a37c2dceecc6f78cca44772705dc52f", "shasum": "" }, "require": { @@ -5753,7 +5687,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v5.4.12" + "source": "https://github.com/symfony/http-kernel/tree/v5.4.14" }, "funding": [ { @@ -5769,20 +5703,20 @@ "type": "tidelift" } ], - "time": "2022-08-26T14:40:40+00:00" + "time": "2022-10-12T07:12:21+00:00" }, { "name": "symfony/mime", - "version": "v5.4.12", + "version": "v5.4.14", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "03876e9c5a36f5b45e7d9a381edda5421eff8a90" + "reference": "1c118b253bb3495d81e95a6e3ec6c2766a98a0c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/03876e9c5a36f5b45e7d9a381edda5421eff8a90", - "reference": "03876e9c5a36f5b45e7d9a381edda5421eff8a90", + "url": "https://api.github.com/repos/symfony/mime/zipball/1c118b253bb3495d81e95a6e3ec6c2766a98a0c4", + "reference": "1c118b253bb3495d81e95a6e3ec6c2766a98a0c4", "shasum": "" }, "require": { @@ -5796,7 +5730,8 @@ "egulias/email-validator": "~3.0.0", "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", - "symfony/mailer": "<4.4" + "symfony/mailer": "<4.4", + "symfony/serializer": "<5.4.14|>=6.0,<6.0.14|>=6.1,<6.1.6" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3.1", @@ -5804,7 +5739,7 @@ "symfony/dependency-injection": "^4.4|^5.0|^6.0", "symfony/property-access": "^4.4|^5.1|^6.0", "symfony/property-info": "^4.4|^5.1|^6.0", - "symfony/serializer": "^5.2|^6.0" + "symfony/serializer": "^5.4.14|~6.0.14|^6.1.6" }, "type": "library", "autoload": { @@ -5836,7 +5771,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.4.12" + "source": "https://github.com/symfony/mime/tree/v5.4.14" }, "funding": [ { @@ -5852,7 +5787,7 @@ "type": "tidelift" } ], - "time": "2022-08-19T14:24:03+00:00" + "time": "2022-10-07T08:01:20+00:00" }, { "name": "symfony/polyfill-ctype", @@ -6908,16 +6843,16 @@ }, { "name": "symfony/string", - "version": "v5.4.12", + "version": "v5.4.14", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "2fc515e512d721bf31ea76bd02fe23ada4640058" + "reference": "089e7237497fae7a9c404d0c3aeb8db3254733e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/2fc515e512d721bf31ea76bd02fe23ada4640058", - "reference": "2fc515e512d721bf31ea76bd02fe23ada4640058", + "url": "https://api.github.com/repos/symfony/string/zipball/089e7237497fae7a9c404d0c3aeb8db3254733e4", + "reference": "089e7237497fae7a9c404d0c3aeb8db3254733e4", "shasum": "" }, "require": { @@ -6974,7 +6909,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.12" + "source": "https://github.com/symfony/string/tree/v5.4.14" }, "funding": [ { @@ -6990,20 +6925,20 @@ "type": "tidelift" } ], - "time": "2022-08-12T17:03:11+00:00" + "time": "2022-10-05T15:16:54+00:00" }, { "name": "symfony/translation", - "version": "v5.4.12", + "version": "v5.4.14", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "42ecc77eb4f229ce2df702a648ec93b8478d76ae" + "reference": "f0ed07675863aa6e3939df8b1bc879450b585cab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/42ecc77eb4f229ce2df702a648ec93b8478d76ae", - "reference": "42ecc77eb4f229ce2df702a648ec93b8478d76ae", + "url": "https://api.github.com/repos/symfony/translation/zipball/f0ed07675863aa6e3939df8b1bc879450b585cab", + "reference": "f0ed07675863aa6e3939df8b1bc879450b585cab", "shasum": "" }, "require": { @@ -7071,7 +7006,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v5.4.12" + "source": "https://github.com/symfony/translation/tree/v5.4.14" }, "funding": [ { @@ -7087,7 +7022,7 @@ "type": "tidelift" } ], - "time": "2022-08-02T15:52:22+00:00" + "time": "2022-10-07T08:01:20+00:00" }, { "name": "symfony/translation-contracts", @@ -7169,16 +7104,16 @@ }, { "name": "symfony/var-dumper", - "version": "v5.4.11", + "version": "v5.4.14", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "b8f306d7b8ef34fb3db3305be97ba8e088fb4861" + "reference": "6894d06145fefebd9a4c7272baa026a1c394a430" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b8f306d7b8ef34fb3db3305be97ba8e088fb4861", - "reference": "b8f306d7b8ef34fb3db3305be97ba8e088fb4861", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/6894d06145fefebd9a4c7272baa026a1c394a430", + "reference": "6894d06145fefebd9a4c7272baa026a1c394a430", "shasum": "" }, "require": { @@ -7238,7 +7173,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.4.11" + "source": "https://github.com/symfony/var-dumper/tree/v5.4.14" }, "funding": [ { @@ -7254,20 +7189,20 @@ "type": "tidelift" } ], - "time": "2022-07-20T13:00:38+00:00" + "time": "2022-10-07T08:01:20+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", - "version": "2.2.4", + "version": "2.2.5", "source": { "type": "git", "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", - "reference": "da444caae6aca7a19c0c140f68c6182e337d5b1c" + "reference": "4348a3a06651827a27d989ad1d13efec6bb49b19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/da444caae6aca7a19c0c140f68c6182e337d5b1c", - "reference": "da444caae6aca7a19c0c140f68c6182e337d5b1c", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/4348a3a06651827a27d989ad1d13efec6bb49b19", + "reference": "4348a3a06651827a27d989ad1d13efec6bb49b19", "shasum": "" }, "require": { @@ -7305,22 +7240,22 @@ "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", "support": { "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", - "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/2.2.4" + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/2.2.5" }, - "time": "2021-12-08T09:12:39+00:00" + "time": "2022-09-12T13:28:28+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v5.4.1", + "version": "v5.5.0", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "264dce589e7ce37a7ba99cb901eed8249fbec92f" + "reference": "1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/264dce589e7ce37a7ba99cb901eed8249fbec92f", - "reference": "264dce589e7ce37a7ba99cb901eed8249fbec92f", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7", + "reference": "1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7", "shasum": "" }, "require": { @@ -7335,15 +7270,19 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.4.1", "ext-filter": "*", - "phpunit/phpunit": "^7.5.20 || ^8.5.21 || ^9.5.10" + "phpunit/phpunit": "^7.5.20 || ^8.5.30 || ^9.5.25" }, "suggest": { "ext-filter": "Required to use the boolean validator." }, "type": "library", "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": true + }, "branch-alias": { - "dev-master": "5.4-dev" + "dev-master": "5.5-dev" } }, "autoload": { @@ -7375,7 +7314,7 @@ ], "support": { "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.4.1" + "source": "https://github.com/vlucas/phpdotenv/tree/v5.5.0" }, "funding": [ { @@ -7387,7 +7326,7 @@ "type": "tidelift" } ], - "time": "2021-12-12T23:22:04+00:00" + "time": "2022-10-16T01:01:54+00:00" }, { "name": "voku/portable-ascii", @@ -7524,17 +7463,109 @@ ], "packages-dev": [ { - "name": "composer/ca-bundle", - "version": "1.3.3", + "name": "brianium/paratest", + "version": "v6.6.4", "source": { "type": "git", - "url": "https://github.com/composer/ca-bundle.git", - "reference": "30897edbfb15e784fe55587b4f73ceefd3c4d98c" + "url": "https://github.com/paratestphp/paratest.git", + "reference": "4ce800dc32fd0292a4f05c00f347142dce1ecdda" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/30897edbfb15e784fe55587b4f73ceefd3c4d98c", - "reference": "30897edbfb15e784fe55587b4f73ceefd3c4d98c", + "url": "https://api.github.com/repos/paratestphp/paratest/zipball/4ce800dc32fd0292a4f05c00f347142dce1ecdda", + "reference": "4ce800dc32fd0292a4f05c00f347142dce1ecdda", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-simplexml": "*", + "jean85/pretty-package-versions": "^2.0.5", + "php": "^7.3 || ^8.0", + "phpunit/php-code-coverage": "^9.2.17", + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-timer": "^5.0.3", + "phpunit/phpunit": "^9.5.24", + "sebastian/environment": "^5.1.4", + "symfony/console": "^5.4.12 || ^6.1.4", + "symfony/process": "^5.4.11 || ^6.1.3" + }, + "require-dev": { + "doctrine/coding-standard": "^10.0.0", + "ext-pcov": "*", + "ext-posix": "*", + "infection/infection": "^0.26.14", + "malukenho/mcbumpface": "^1.1.5", + "squizlabs/php_codesniffer": "^3.7.1", + "symfony/filesystem": "^5.4.12 || ^6.1.4", + "vimeo/psalm": "^4.27.0" + }, + "bin": [ + "bin/paratest", + "bin/paratest.bat", + "bin/paratest_for_phpstorm" + ], + "type": "library", + "autoload": { + "psr-4": { + "ParaTest\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Scaturro", + "email": "scaturrob@gmail.com", + "role": "Developer" + }, + { + "name": "Filippo Tessarotto", + "email": "zoeslam@gmail.com", + "role": "Developer" + } + ], + "description": "Parallel testing for PHP", + "homepage": "https://github.com/paratestphp/paratest", + "keywords": [ + "concurrent", + "parallel", + "phpunit", + "testing" + ], + "support": { + "issues": "https://github.com/paratestphp/paratest/issues", + "source": "https://github.com/paratestphp/paratest/tree/v6.6.4" + }, + "funding": [ + { + "url": "https://github.com/sponsors/Slamdunk", + "type": "github" + }, + { + "url": "https://paypal.me/filippotessarotto", + "type": "paypal" + } + ], + "time": "2022-09-13T10:47:01+00:00" + }, + { + "name": "composer/ca-bundle", + "version": "1.3.4", + "source": { + "type": "git", + "url": "https://github.com/composer/ca-bundle.git", + "reference": "69098eca243998b53eed7a48d82dedd28b447cd5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/69098eca243998b53eed7a48d82dedd28b447cd5", + "reference": "69098eca243998b53eed7a48d82dedd28b447cd5", "shasum": "" }, "require": { @@ -7581,7 +7612,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.3.3" + "source": "https://github.com/composer/ca-bundle/tree/1.3.4" }, "funding": [ { @@ -7597,7 +7628,7 @@ "type": "tidelift" } ], - "time": "2022-07-20T07:14:26+00:00" + "time": "2022-10-12T12:08:29+00:00" }, { "name": "composer/class-map-generator", @@ -7674,16 +7705,16 @@ }, { "name": "composer/composer", - "version": "2.4.1", + "version": "2.4.3", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "777d542e3af65f8e7a66a4d98ce7a697da339414" + "reference": "b34c0e9a93f2cd688c62ce4dfcc69e13b6ce7aa4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/777d542e3af65f8e7a66a4d98ce7a697da339414", - "reference": "777d542e3af65f8e7a66a4d98ce7a697da339414", + "url": "https://api.github.com/repos/composer/composer/zipball/b34c0e9a93f2cd688c62ce4dfcc69e13b6ce7aa4", + "reference": "b34c0e9a93f2cd688c62ce4dfcc69e13b6ce7aa4", "shasum": "" }, "require": { @@ -7713,7 +7744,7 @@ "phpstan/phpstan-deprecation-rules": "^1", "phpstan/phpstan-phpunit": "^1.0", "phpstan/phpstan-strict-rules": "^1", - "phpstan/phpstan-symfony": "^1.1", + "phpstan/phpstan-symfony": "^1.2.10", "symfony/phpunit-bridge": "^6.0" }, "suggest": { @@ -7766,7 +7797,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/composer/issues", - "source": "https://github.com/composer/composer/tree/2.4.1" + "source": "https://github.com/composer/composer/tree/2.4.3" }, "funding": [ { @@ -7782,7 +7813,7 @@ "type": "tidelift" } ], - "time": "2022-08-20T09:44:50+00:00" + "time": "2022-10-14T14:56:41+00:00" }, { "name": "composer/metadata-minifier", @@ -8394,16 +8425,16 @@ }, { "name": "itsgoingd/clockwork", - "version": "v5.1.7", + "version": "v5.1.8", "source": { "type": "git", "url": "https://github.com/itsgoingd/clockwork.git", - "reference": "2cad6c75dc2b96cbfd48c0511bb035a4e328c17f" + "reference": "74ee05a61296aa7298164ef5346f0a568aa6106e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/itsgoingd/clockwork/zipball/2cad6c75dc2b96cbfd48c0511bb035a4e328c17f", - "reference": "2cad6c75dc2b96cbfd48c0511bb035a4e328c17f", + "url": "https://api.github.com/repos/itsgoingd/clockwork/zipball/74ee05a61296aa7298164ef5346f0a568aa6106e", + "reference": "74ee05a61296aa7298164ef5346f0a568aa6106e", "shasum": "" }, "require": { @@ -8450,7 +8481,7 @@ ], "support": { "issues": "https://github.com/itsgoingd/clockwork/issues", - "source": "https://github.com/itsgoingd/clockwork/tree/v5.1.7" + "source": "https://github.com/itsgoingd/clockwork/tree/v5.1.8" }, "funding": [ { @@ -8458,7 +8489,66 @@ "type": "github" } ], - "time": "2022-08-14T21:23:22+00:00" + "time": "2022-09-25T20:21:14+00:00" + }, + { + "name": "jean85/pretty-package-versions", + "version": "2.0.5", + "source": { + "type": "git", + "url": "https://github.com/Jean85/pretty-package-versions.git", + "reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/ae547e455a3d8babd07b96966b17d7fd21d9c6af", + "reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.0.0", + "php": "^7.1|^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.17", + "jean85/composer-provided-replaced-stub-package": "^1.0", + "phpstan/phpstan": "^0.12.66", + "phpunit/phpunit": "^7.5|^8.5|^9.4", + "vimeo/psalm": "^4.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Jean85\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Lai", + "email": "alessandro.lai85@gmail.com" + } + ], + "description": "A library to get pretty versions strings of installed dependencies", + "keywords": [ + "composer", + "package", + "release", + "versions" + ], + "support": { + "issues": "https://github.com/Jean85/pretty-package-versions/issues", + "source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.5" + }, + "time": "2021-10-08T21:21:46+00:00" }, { "name": "justinrainbow/json-schema", @@ -8532,16 +8622,16 @@ }, { "name": "mockery/mockery", - "version": "1.5.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/mockery/mockery.git", - "reference": "c10a5f6e06fc2470ab1822fa13fa2a7380f8fbac" + "reference": "e92dcc83d5a51851baf5f5591d32cb2b16e3684e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/c10a5f6e06fc2470ab1822fa13fa2a7380f8fbac", - "reference": "c10a5f6e06fc2470ab1822fa13fa2a7380f8fbac", + "url": "https://api.github.com/repos/mockery/mockery/zipball/e92dcc83d5a51851baf5f5591d32cb2b16e3684e", + "reference": "e92dcc83d5a51851baf5f5591d32cb2b16e3684e", "shasum": "" }, "require": { @@ -8598,9 +8688,9 @@ ], "support": { "issues": "https://github.com/mockery/mockery/issues", - "source": "https://github.com/mockery/mockery/tree/1.5.0" + "source": "https://github.com/mockery/mockery/tree/1.5.1" }, - "time": "2022-01-20T13:18:17+00:00" + "time": "2022-09-07T15:32:08+00:00" }, { "name": "myclabs/deep-copy", @@ -8959,16 +9049,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.8.4", + "version": "1.8.9", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "eed4c9da531f6ebb4787235b6fb486e2c20f34e5" + "reference": "3a72d9d9f2528fbd50c2d8fcf155fd9f74ade3f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/eed4c9da531f6ebb4787235b6fb486e2c20f34e5", - "reference": "eed4c9da531f6ebb4787235b6fb486e2c20f34e5", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/3a72d9d9f2528fbd50c2d8fcf155fd9f74ade3f2", + "reference": "3a72d9d9f2528fbd50c2d8fcf155fd9f74ade3f2", "shasum": "" }, "require": { @@ -8998,7 +9088,7 @@ ], "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.8.4" + "source": "https://github.com/phpstan/phpstan/tree/1.8.9" }, "funding": [ { @@ -9014,7 +9104,7 @@ "type": "tidelift" } ], - "time": "2022-09-03T13:08:04+00:00" + "time": "2022-10-13T13:40:18+00:00" }, { "name": "phpunit/php-code-coverage", @@ -9336,16 +9426,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.24", + "version": "9.5.25", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "d0aa6097bef9fd42458a9b3c49da32c6ce6129c5" + "reference": "3e6f90ca7e3d02025b1d147bd8d4a89fd4ca8a1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d0aa6097bef9fd42458a9b3c49da32c6ce6129c5", - "reference": "d0aa6097bef9fd42458a9b3c49da32c6ce6129c5", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3e6f90ca7e3d02025b1d147bd8d4a89fd4ca8a1d", + "reference": "3e6f90ca7e3d02025b1d147bd8d4a89fd4ca8a1d", "shasum": "" }, "require": { @@ -9367,14 +9457,14 @@ "phpunit/php-timer": "^5.0.2", "sebastian/cli-parser": "^1.0.1", "sebastian/code-unit": "^1.0.6", - "sebastian/comparator": "^4.0.5", + "sebastian/comparator": "^4.0.8", "sebastian/diff": "^4.0.3", "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.3", + "sebastian/exporter": "^4.0.5", "sebastian/global-state": "^5.0.1", "sebastian/object-enumerator": "^4.0.3", "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^3.1", + "sebastian/type": "^3.2", "sebastian/version": "^3.0.2" }, "suggest": { @@ -9418,7 +9508,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.24" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.25" }, "funding": [ { @@ -9428,9 +9518,13 @@ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" } ], - "time": "2022-08-30T07:42:16+00:00" + "time": "2022-09-25T03:44:45+00:00" }, { "name": "react/promise", @@ -9677,16 +9771,16 @@ }, { "name": "sebastian/comparator", - "version": "4.0.6", + "version": "4.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "55f4261989e546dc112258c7a75935a81a7ce382" + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382", - "reference": "55f4261989e546dc112258c7a75935a81a7ce382", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", "shasum": "" }, "require": { @@ -9739,7 +9833,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6" + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" }, "funding": [ { @@ -9747,7 +9841,7 @@ "type": "github" } ], - "time": "2020-10-26T15:49:45+00:00" + "time": "2022-09-14T12:41:17+00:00" }, { "name": "sebastian/complexity", @@ -9937,16 +10031,16 @@ }, { "name": "sebastian/exporter", - "version": "4.0.4", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9" + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/65e8b7db476c5dd267e65eea9cab77584d3cfff9", - "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", "shasum": "" }, "require": { @@ -10002,7 +10096,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" }, "funding": [ { @@ -10010,7 +10104,7 @@ "type": "github" } ], - "time": "2021-11-11T14:18:36+00:00" + "time": "2022-09-14T06:03:37+00:00" }, { "name": "sebastian/global-state", @@ -10365,16 +10459,16 @@ }, { "name": "sebastian/type", - "version": "3.1.0", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "fb44e1cc6e557418387ad815780360057e40753e" + "reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/fb44e1cc6e557418387ad815780360057e40753e", - "reference": "fb44e1cc6e557418387ad815780360057e40753e", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e", + "reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e", "shasum": "" }, "require": { @@ -10386,7 +10480,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "3.2-dev" } }, "autoload": { @@ -10409,7 +10503,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/3.1.0" + "source": "https://github.com/sebastianbergmann/type/tree/3.2.0" }, "funding": [ { @@ -10417,7 +10511,7 @@ "type": "github" } ], - "time": "2022-08-29T06:55:37+00:00" + "time": "2022-09-12T14:47:03+00:00" }, { "name": "sebastian/version", @@ -10834,16 +10928,16 @@ }, { "name": "symfony/filesystem", - "version": "v5.4.12", + "version": "v5.4.13", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "2d67c1f9a1937406a9be3171b4b22250c0a11447" + "reference": "ac09569844a9109a5966b9438fc29113ce77cf51" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/2d67c1f9a1937406a9be3171b4b22250c0a11447", - "reference": "2d67c1f9a1937406a9be3171b4b22250c0a11447", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/ac09569844a9109a5966b9438fc29113ce77cf51", + "reference": "ac09569844a9109a5966b9438fc29113ce77cf51", "shasum": "" }, "require": { @@ -10878,7 +10972,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.12" + "source": "https://github.com/symfony/filesystem/tree/v5.4.13" }, "funding": [ { @@ -10894,7 +10988,7 @@ "type": "tidelift" } ], - "time": "2022-08-02T13:48:16+00:00" + "time": "2022-09-21T19:53:16+00:00" }, { "name": "theseer/tokenizer", diff --git a/database/migrations/2022_10_07_091406_flatten_entity_permissions_table.php b/database/migrations/2022_10_07_091406_flatten_entity_permissions_table.php new file mode 100644 index 000000000..468f33248 --- /dev/null +++ b/database/migrations/2022_10_07_091406_flatten_entity_permissions_table.php @@ -0,0 +1,105 @@ +pluck('id'); + DB::table('entity_permissions')->whereNotIn('role_id', $roleIds)->delete(); + + // Create new table structure for entity_permissions + Schema::create('new_entity_permissions', function (Blueprint $table) { + $table->id(); + $table->unsignedInteger('entity_id'); + $table->string('entity_type', 25); + $table->unsignedInteger('role_id')->index(); + $table->boolean('view')->default(0); + $table->boolean('create')->default(0); + $table->boolean('update')->default(0); + $table->boolean('delete')->default(0); + + $table->index(['entity_id', 'entity_type']); + }); + + // Migrate existing entity_permission data into new table structure + + $subSelect = function (Builder $query, string $action, string $subAlias) { + $sub = $query->newQuery()->select('action')->from('entity_permissions', $subAlias) + ->whereColumn('a.restrictable_id', '=', $subAlias . '.restrictable_id') + ->whereColumn('a.restrictable_type', '=', $subAlias . '.restrictable_type') + ->whereColumn('a.role_id', '=', $subAlias . '.role_id') + ->where($subAlias . '.action', '=', $action); + return $query->selectRaw("EXISTS({$sub->toSql()})", $sub->getBindings()); + }; + + $query = DB::table('entity_permissions', 'a')->select([ + 'restrictable_id as entity_id', + 'restrictable_type as entity_type', + 'role_id', + 'view' => fn(Builder $query) => $subSelect($query, 'view', 'b'), + 'create' => fn(Builder $query) => $subSelect($query, 'create', 'c'), + 'update' => fn(Builder $query) => $subSelect($query, 'update', 'd'), + 'delete' => fn(Builder $query) => $subSelect($query, 'delete', 'e'), + ])->groupBy('restrictable_id', 'restrictable_type', 'role_id'); + + DB::table('new_entity_permissions')->insertUsing(['entity_id', 'entity_type', 'role_id', 'view', 'create', 'update', 'delete'], $query); + + // Drop old entity_permissions table and replace with new structure + Schema::dropIfExists('entity_permissions'); + Schema::rename('new_entity_permissions', 'entity_permissions'); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // Create old table structure for entity_permissions + Schema::create('old_entity_permissions', function (Blueprint $table) { + $table->increments('id'); + $table->integer('restrictable_id'); + $table->string('restrictable_type', 191); + $table->integer('role_id')->index(); + $table->string('action', 191)->index(); + + $table->index(['restrictable_id', 'restrictable_type']); + }); + + // Convert newer data format to old data format, and insert into old database + + $actionQuery = function (Builder $query, string $action) { + return $query->select([ + 'entity_id as restrictable_id', + 'entity_type as restrictable_type', + 'role_id', + ])->selectRaw("? as action", [$action]) + ->from('entity_permissions') + ->where($action, '=', true); + }; + + $query = $actionQuery(DB::query(), 'view') + ->union(fn(Builder $query) => $actionQuery($query, 'create')) + ->union(fn(Builder $query) => $actionQuery($query, 'update')) + ->union(fn(Builder $query) => $actionQuery($query, 'delete')); + + DB::table('old_entity_permissions')->insertUsing(['restrictable_id', 'restrictable_type', 'role_id', 'action'], $query); + + // Drop new entity_permissions table and replace with old structure + Schema::dropIfExists('entity_permissions'); + Schema::rename('old_entity_permissions', 'entity_permissions'); + } +} diff --git a/database/migrations/2022_10_08_104202_drop_entity_restricted_field.php b/database/migrations/2022_10_08_104202_drop_entity_restricted_field.php new file mode 100644 index 000000000..063f924f2 --- /dev/null +++ b/database/migrations/2022_10_08_104202_drop_entity_restricted_field.php @@ -0,0 +1,93 @@ +select('entity_permissions.id as id') + ->join($table, function (JoinClause $join) use ($table, $morphClass) { + return $join->where($table . '.restricted', '=', 0) + ->on($table . '.id', '=', 'entity_permissions.entity_id'); + })->where('entity_type', '=', $morphClass) + ->pluck('id'); + DB::table('entity_permissions')->whereIn('id', $permissionIds)->delete(); + }; + $deleteInactiveEntityPermissions('pages', 'page'); + $deleteInactiveEntityPermissions('chapters', 'chapter'); + $deleteInactiveEntityPermissions('books', 'book'); + $deleteInactiveEntityPermissions('bookshelves', 'bookshelf'); + + // Migrate restricted=1 entries to new entity_permissions (role_id=0) entries + $defaultEntityPermissionGenQuery = function (Builder $query, string $table, string $morphClass) { + return $query->select(['id as entity_id']) + ->selectRaw('? as entity_type', [$morphClass]) + ->selectRaw('? as `role_id`', [0]) + ->selectRaw('? as `view`', [0]) + ->selectRaw('? as `create`', [0]) + ->selectRaw('? as `update`', [0]) + ->selectRaw('? as `delete`', [0]) + ->from($table) + ->where('restricted', '=', 1); + }; + + $query = $defaultEntityPermissionGenQuery(DB::query(), 'pages', 'page') + ->union(fn(Builder $query) => $defaultEntityPermissionGenQuery($query, 'books', 'book')) + ->union(fn(Builder $query) => $defaultEntityPermissionGenQuery($query, 'chapters', 'chapter')) + ->union(fn(Builder $query) => $defaultEntityPermissionGenQuery($query, 'bookshelves', 'bookshelf')); + + DB::table('entity_permissions')->insertUsing(['entity_id', 'entity_type', 'role_id', 'view', 'create', 'update', 'delete'], $query); + + // Drop restricted columns + $dropRestrictedColumn = fn(Blueprint $table) => $table->dropColumn('restricted'); + Schema::table('pages', $dropRestrictedColumn); + Schema::table('chapters', $dropRestrictedColumn); + Schema::table('books', $dropRestrictedColumn); + Schema::table('bookshelves', $dropRestrictedColumn); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // Create restricted columns + $createRestrictedColumn = fn(Blueprint $table) => $table->boolean('restricted')->index()->default(0); + Schema::table('pages', $createRestrictedColumn); + Schema::table('chapters', $createRestrictedColumn); + Schema::table('books', $createRestrictedColumn); + Schema::table('bookshelves', $createRestrictedColumn); + + // Set restrictions for entities that have a default entity permission assigned + // Note: Possible loss of data where default entity permissions have been configured + $restrictEntities = function (string $table, string $morphClass) { + $toRestrictIds = DB::table('entity_permissions') + ->where('role_id', '=', 0) + ->where('entity_type', '=', $morphClass) + ->pluck('entity_id'); + DB::table($table)->whereIn('id', $toRestrictIds)->update(['restricted' => true]); + }; + $restrictEntities('pages', 'page'); + $restrictEntities('chapters', 'chapter'); + $restrictEntities('books', 'book'); + $restrictEntities('bookshelves', 'bookshelf'); + + // Delete default entity permissions + DB::table('entity_permissions')->where('role_id', '=', 0)->delete(); + } +} diff --git a/dev/api/responses/books-read.json b/dev/api/responses/books-read.json index 7de85addc..8d584f597 100644 --- a/dev/api/responses/books-read.json +++ b/dev/api/responses/books-read.json @@ -17,6 +17,44 @@ "id": 1, "name": "Admin" }, + "contents": [ + { + "id": 50, + "name": "Bridge Structures", + "slug": "bridge-structures", + "book_id": 16, + "created_at": "2021-12-19T15:22:11.000000Z", + "updated_at": "2021-12-21T19:42:29.000000Z", + "url": "https://example.com/books/my-own-book/chapter/bridge-structures", + "type": "chapter", + "pages": [ + { + "id": 42, + "name": "Building Bridges", + "slug": "building-bridges", + "book_id": 16, + "chapter_id": 50, + "draft": false, + "template": false, + "created_at": "2021-12-19T15:22:11.000000Z", + "updated_at": "2022-09-29T13:44:15.000000Z", + "url": "https://example.com/books/my-own-book/page/building-bridges" + } + ] + }, + { + "id": 43, + "name": "Cool Animals", + "slug": "cool-animals", + "book_id": 16, + "chapter_id": 0, + "draft": false, + "template": false, + "created_at": "2021-12-19T18:22:11.000000Z", + "updated_at": "2022-07-29T13:44:15.000000Z", + "url": "https://example.com/books/my-own-book/page/cool-animals" + } + ], "tags": [ { "id": 13, @@ -28,12 +66,12 @@ "cover": { "id": 452, "name": "sjovall_m117hUWMu40.jpg", - "url": "http:\/\/bookstack.local\/uploads\/images\/cover_book\/2020-01\/sjovall_m117hUWMu40.jpg", + "url": "https://example.com/uploads/images/cover_book/2020-01/sjovall_m117hUWMu40.jpg", "created_at": "2020-01-12T14:11:51.000000Z", "updated_at": "2020-01-12T14:11:51.000000Z", "created_by": 1, "updated_by": 1, - "path": "\/uploads\/images\/cover_book\/2020-01\/sjovall_m117hUWMu40.jpg", + "path": "/uploads/images/cover_book/2020-01/sjovall_m117hUWMu40.jpg", "type": "cover_book", "uploaded_to": 16 } diff --git a/dev/docs/components.md b/dev/docs/components.md deleted file mode 100644 index 832765dd6..000000000 --- a/dev/docs/components.md +++ /dev/null @@ -1,99 +0,0 @@ -# JavaScript Components - -This document details the format for JavaScript components in BookStack. This is a really simple class-based setup with a few helpers provided. - -#### Defining a Component in JS - -```js -class Dropdown { - setup() { - this.toggle = this.$refs.toggle; - this.menu = this.$refs.menu; - - this.speed = parseInt(this.$opts.speed); - } -} -``` - -All usage of $refs, $manyRefs and $opts should be done at the top of the `setup` function so any requirements can be easily seen. - -#### Using a Component in HTML - -A component is used like so: - -```html -
- - - -
-``` - -The names will be parsed and new component instance will be created if a matching name is found in the `components/index.js` componentMapping. - -#### Element References - -Within a component you'll often need to refer to other element instances. This can be done like so: - -```html -
- View more -
-``` - -You can then access the span element as `this.$refs.toggle` in your component. - -#### Component Options - -```html -
-
-``` - -Will result with `this.$opts` being: - -```json -{ - "delay": "500", - "show": "" -} -``` - -#### Global Helpers - -There are various global helper libraries which can be used in components: - -```js -// HTTP service -window.$http.get(url, params); -window.$http.post(url, data); -window.$http.put(url, data); -window.$http.delete(url, data); -window.$http.patch(url, data); - -// Global event system -// Emit a global event -window.$events.emit(eventName, eventData); -// Listen to a global event -window.$events.listen(eventName, callback); -// Show a success message -window.$events.success(message); -// Show an error message -window.$events.error(message); -// Show validation errors, if existing, as an error notification -window.$events.showValidationErrors(error); - -// Translator -// Take the given plural text and count to decide on what plural option -// to use, Similar to laravel's trans_choice function but instead -// takes the direction directly instead of a translation key. -window.trans_plural(translationString, count, replacements); - -// Component System -// Parse and initialise any components from the given root el down. -window.components.init(rootEl); -// Get the first active component of the given name -window.components.first(name); -``` \ No newline at end of file diff --git a/dev/docs/development.md b/dev/docs/development.md new file mode 100644 index 000000000..1611de578 --- /dev/null +++ b/dev/docs/development.md @@ -0,0 +1,98 @@ +# Development & Testing + +All development on BookStack is currently done on the `development` branch. +When it's time for a release the `development` 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/) v16.0+ + +## Building CSS & JavaScript Assets + +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: + +``` bash +# Install NPM Dependencies +npm install + +# Build assets for development +npm run build + +# Build and minify assets for production +npm run production + +# Build for dev (With sourcemaps) and watch for changes +npm run dev +``` + +BookStack has many integration tests that use Laravel's built-in testing capabilities which makes use of PHPUnit. There is a `mysql_testing` database defined within the app config which is what is used by PHPUnit. This database is set with the database name, username and password all defined as `bookstack-test`. You will have to create that database and that set of credentials before testing. + +The testing database will also need migrating and seeding beforehand. This can be done by running `composer refresh-test-database`. + +Once done you can run `composer test` in the application root directory to run all tests. Tests can be ran in parallel by running them via `composer t`. This will use Laravel's built-in parallel testing functionality, and attempt to create and seed a database instance for each testing thread. If required these parallel testing instances can be reset, before testing again, by running `composer t-reset`. + +## Code Standards + +PHP code standards are managed by [using PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer). +Static analysis is in place using [PHPStan](https://phpstan.org/) & [Larastan](https://github.com/nunomaduro/larastan). +The below commands can be used to utilise these tools: + +```bash +# Run code linting using PHP_CodeSniffer +composer lint + +# As above, but show rule names in output +composer lint -- -s + +# Auto-fix formatting & lint issues via PHP_CodeSniffer phpcbf +composer format + +# Run static analysis via larastan/phpstan +composer check-static +``` + +If submitting a PR, formatting as per our project standards would help for clarity but don't worry too much about using/understanding these tools as we can always address issues at a later stage when they're picked up by our automated tools. + +## Development using Docker + +This repository ships with a Docker Compose configuration intended for development purposes. It'll build a PHP image with all needed extensions installed and start up a MySQL server and a Node image watching the UI assets. + +To get started, make sure you meet the following requirements: + +- Docker and Docker Compose are installed +- Your user is part of the `docker` group + +If all the conditions are met, you can proceed with the following steps: + +1. **Copy `.env.example` to `.env`**, change `APP_KEY` to a random 32 char string and set `APP_ENV` to `local`. +2. Make sure **port 8080 is unused** *or else* change `DEV_PORT` to a free port on your host. +3. **Run `chgrp -R docker storage`**. The development container will chown the `storage` directory to the `www-data` user inside the container so BookStack can write to it. You need to change the group to your host's `docker` group here to not lose access to the `storage` directory. +4. **Run `docker-compose up`** and wait until the image is built and all database migrations have been done. +5. You can now login with `admin@admin.com` and `password` as password on `localhost:8080` (or another port if specified). + +If needed, You'll be able to run any artisan commands via docker-compose like so: + +```bash +docker-compose run app php artisan list +``` + +The docker-compose setup runs an instance of [MailHog](https://github.com/mailhog/MailHog) and sets environment variables to redirect any BookStack-sent emails to MailHog. You can view this mail via the MailHog web interface on `localhost:8025`. You can change the port MailHog is accessible on by setting a `DEV_MAIL_PORT` environment variable. + +### Running tests + +After starting the general development Docker, migrate & seed the testing database: + + ```bash +# This only needs to be done once +docker-compose run app php artisan migrate --database=mysql_testing +docker-compose run app php artisan db:seed --class=DummyContentSeeder --database=mysql_testing +``` + +Once the database has been migrated & seeded, you can run the tests like so: + + ```bash +docker-compose run app php vendor/bin/phpunit +``` + +### Debugging + +The docker-compose setup ships with Xdebug, which you can listen to on port 9090. +NB : For some editors like Visual Studio Code, you might need to map your workspace folder to the /app folder within the docker container for this to work. diff --git a/dev/docs/javascript-code.md b/dev/docs/javascript-code.md new file mode 100644 index 000000000..3d47a1ad8 --- /dev/null +++ b/dev/docs/javascript-code.md @@ -0,0 +1,138 @@ +# BookStack JavaScript Code + +BookStack is primarily server-side-rendered, but it uses JavaScript sparingly to drive any required dynamic elements. Most JavaScript is applied via a custom, and very thin, component interface to keep code organised and somewhat reusable. + +JavaScript source code can be found in the `resources/js` directory. This gets bundled and transformed by `esbuild`, ending up in the `public/dist` folder for browser use. Read the [Development > "Building CSS & JavaScript Assets"](development.md#building-css-&-javascript-assets) documentation for details on this process. + +## Components + +This section details the format for JavaScript components in BookStack. This is a really simple class-based setup with a few helpers provided. + +### Defining a Component in JS + +```js +class Dropdown { + setup() { + this.container = this.$el; + this.menu = this.$refs.menu; + this.toggles = this.$manyRefs.toggle; + + this.speed = parseInt(this.$opts.speed); + } +} +``` + +All usage of $refs, $manyRefs and $opts should be done at the top of the `setup` function so any requirements can be easily seen. + +Once defined, the component has to be registered for use. This is done in the `resources/js/components/index.js` file. You'll need to import the component class then add it to `componentMapping` object, following the pattern of other components. + +### Using a Component in HTML + +A component is used like so: + +```html +
+ + + +
+``` + +The names will be parsed and new component instance will be created if a matching name is found in the `components/index.js` componentMapping. + +### Element References + +Within a component you'll often need to refer to other element instances. This can be done like so: + +```html +
+ View more +
+``` + +You can then access the span element as `this.$refs.toggle` in your component. + +Multiple elements of the same reference name can be accessed via a `this.$manyRefs` property within your component. For example, all the buttons in the below example could be accessed via `this.$manyRefs.buttons`. + +```html +
+ + + +
+``` + +### Component Options + +```html +
+
+``` + +Will result with `this.$opts` being: + +```json +{ + "delay": "500", + "show": "" +} +``` + +#### Component Properties + +A component has the below shown properties available for use. As mentioned above, most of these should be used within the `setup()` function to make the requirements/dependencies of the component clear. + +```javascript +// The root element that the compontent has been applied to. +this.$el + +// A map of defined element references within the compontent. +// See "Element References" above. +this.$refs + +// A map of defined multi-element references within the compontent. +// See "Element References" above. +this.$manyRefs + +// Options defined for the compontent. +this.$opts +``` + +## Global JavaScript Helpers + +There are various global helper libraries in BookStack which can be accessed via the `window`. The below provides an overview of what's available. + +```js +// HTTP service +window.$http.get(url, params); +window.$http.post(url, data); +window.$http.put(url, data); +window.$http.delete(url, data); +window.$http.patch(url, data); + +// Global event system +// Emit a global event +window.$events.emit(eventName, eventData); +// Listen to a global event +window.$events.listen(eventName, callback); +// Show a success message +window.$events.success(message); +// Show an error message +window.$events.error(message); +// Show validation errors, if existing, as an error notification +window.$events.showValidationErrors(error); + +// Translator +// Take the given plural text and count to decide on what plural option +// to use, Similar to laravel's trans_choice function but instead +// takes the direction directly instead of a translation key. +window.trans_plural(translationString, count, replacements); + +// Component System +// Parse and initialise any components from the given root el down. +window.components.init(rootEl); +// Get the first active component of the given name +window.components.first(name); +``` \ No newline at end of file diff --git a/dev/docs/release-process.md b/dev/docs/release-process.md new file mode 100644 index 000000000..758d6db4c --- /dev/null +++ b/dev/docs/release-process.md @@ -0,0 +1,24 @@ +# Release Versioning & Process + +### BookStack Version Number Scheme + +BookStack releases are each assigned a date-based version number in the format `v.[.]`. 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 are 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/). + +### Release Planning Process + +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. + +### Release Announcements + +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 blog posts (once per week maximum) [at this link](https://updates.bookstackapp.com/signup/bookstack-news-and-updates). + +### Release Technical Process + +Deploying a release, at a high level, simply involves merging the development branch into the release branch before then building & committing any release-only assets. +A helper script [can be found in our](https://github.com/BookStackApp/devops/blob/main/meta-scripts/bookstack-release-steps) devops repo which provides the steps and commands for deploying a new release. \ No newline at end of file diff --git a/readme.md b/readme.md index d0ae1b4f6..b8bd17232 100644 --- a/readme.md +++ b/readme.md @@ -59,131 +59,20 @@ Note: Listed services are not tested, vetted nor supported by the official BookS ## 🛣️ Road Map -Below is a high-level road map view for BookStack to provide a sense of direction of where the project is going. This can change at any point and does not reflect many features and improvements that will also be included as part of the journey along this road map. For more granular detail of what will be included in upcoming releases you can review the project milestones as defined in the "Release Process" section below. +Below is a high-level road map view for BookStack to provide a sense of direction of where the project is going. This can change at any point and does not reflect many features and improvements that will also be included as part of the journey along this road map. For more granular detail of what will be included in upcoming releases you can review the project milestones as defined in our [Release Process](dev/docs/release-process.md) documentation. - **Platform REST API** - *(Most actions implemented, maturing)* - *A REST API covering, at minimum, control of core content models (Books, Chapters, Pages) for automation and platform extension.* -- **Editor Alignment & Review** - *(Done)* - - *Review the page editors with the goal of achieving increased interoperability & feature parity while also considering collaborative editing potential.* - **Permission System Review** - *(In Progress)* - *Improvement in how permissions are applied and a review of the efficiency of the permission & roles system.* -- **Installation & Deployment Process Revamp** - - *Creation of a streamlined & secure process for users to deploy & update BookStack with reduced development requirements (No git or composer requirement).* - -## 🚀 Release Versioning & Process - -BookStack releases are each assigned a date-based version number in the format `v.[.]`. 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 are 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. - -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 blog 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 `development` branch. When it's time for a release the `development` branch is merged into release with built & minified CSS & JS then tagged at its version. Here are the current development requirements: +Please see our [development docs](dev/docs/development.md) for full details regarding work on the BookStack source code. -* [Node.js](https://nodejs.org/en/) v14.0+ +If you're just looking to customize or extend your own BookStack instance, take a look at our [Hacking BookStack documentation page](https://www.bookstackapp.com/docs/admin/hacking-bookstack/) for details on various options to achieve this without altering the BookStack source code. -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: - -``` bash -# Install NPM Dependencies -npm install - -# Build assets for development -npm run build - -# Build and minify assets for production -npm run production - -# Build for dev (With sourcemaps) and watch for changes -npm run dev -``` - -BookStack has many integration tests that use Laravel's built-in testing capabilities which makes use of PHPUnit. There is a `mysql_testing` database defined within the app config which is what is used by PHPUnit. This database is set with the database name, user name and password all defined as `bookstack-test`. You will have to create that database and that set of credentials before testing. - -The testing database will also need migrating and seeding beforehand. This can be done with the following commands: - -``` bash -php artisan migrate --database=mysql_testing -php artisan db:seed --class=DummyContentSeeder --database=mysql_testing -``` - -Once done you can run `composer test` in the application root directory to run all tests. - -### 📜 Code Standards - -PHP code standards are managed by [using PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer). -Static analysis is in place using [PHPStan](https://phpstan.org/) & [Larastan](https://github.com/nunomaduro/larastan). -The below commands can be used to utilise these tools: - -```bash -# Run code linting using PHP_CodeSniffer -composer lint - -# As above, but show rule names in output -composer lint -- -s - -# Auto-fix formatting & lint issues via PHP_CodeSniffer phpcbf -composer format - -# Run static analysis via larastan/phpstan -composer check-static -``` - -If submitting a PR, formatting as per our project standards would help for clarity but don't worry too much about using/understanding these tools as we can always address issues at a later stage when they're picked up by our automated tools. - -### 🐋 Development using Docker - -This repository ships with a Docker Compose configuration intended for development purposes. It'll build a PHP image with all needed extensions installed and start up a MySQL server and a Node image watching the UI assets. - -To get started, make sure you meet the following requirements: - -- Docker and Docker Compose are installed -- Your user is part of the `docker` group - -If all the conditions are met, you can proceed with the following steps: - -1. **Copy `.env.example` to `.env`**, change `APP_KEY` to a random 32 char string and set `APP_ENV` to `local`. -2. Make sure **port 8080 is unused** *or else* change `DEV_PORT` to a free port on your host. -3. **Run `chgrp -R docker storage`**. The development container will chown the `storage` directory to the `www-data` user inside the container so BookStack can write to it. You need to change the group to your host's `docker` group here to not lose access to the `storage` directory. -4. **Run `docker-compose up`** and wait until the image is built and all database migrations have been done. -5. You can now login with `admin@admin.com` and `password` as password on `localhost:8080` (or another port if specified). - -If needed, You'll be able to run any artisan commands via docker-compose like so: - -```bash -docker-compose run app php artisan list -``` - -The docker-compose setup runs an instance of [MailHog](https://github.com/mailhog/MailHog) and sets environment variables to redirect any BookStack-sent emails to MailHog. You can view this mail via the MailHog web interface on `localhost:8025`. You can change the port MailHog is accessible on by setting a `DEV_MAIL_PORT` environment variable. - -#### Running tests - -After starting the general development Docker, migrate & seed the testing database: - - ```bash -# This only needs to be done once -docker-compose run app php artisan migrate --database=mysql_testing -docker-compose run app php artisan db:seed --class=DummyContentSeeder --database=mysql_testing -``` - -Once the database has been migrated & seeded, you can run the tests like so: - - ```bash -docker-compose run app php vendor/bin/phpunit -``` - -#### Debugging - -The docker-compose setup ships with Xdebug, which you can listen to on port 9090. -NB : For some editors like Visual Studio Code, you might need to map your workspace folder to the /app folder within the docker container for this to work. +Details about BookStack's versioning scheme and the general release process [can be found here](dev/docs/release-process.md). ## 🌎 Translations @@ -217,20 +106,18 @@ We want BookStack to remain accessible to as many people as possible. We aim for ## 🖥️ Website, Docs & Blog -The website which contains the project docs & Blog can be found in the [BookStackApp/website](https://github.com/BookStackApp/website) repo. +The website which contains the project docs & blog can be found in the [BookStackApp/website](https://github.com/BookStackApp/website) repo. ## ⚖️ License -The BookStack source is provided under the MIT License. +The BookStack source is provided under the [MIT License](https://github.com/BookStackApp/BookStack/blob/development/LICENSE). The libraries used by, and included with, BookStack are provided under their own licenses and copyright. The licenses for many of our core dependencies can be found in the attribution list below but this is not an exhaustive list of all projects used within BookStack. ## 👪 Attribution -The great people that have worked to build and improve BookStack can [be seen here](https://github.com/BookStackApp/BookStack/graphs/contributors). - -The wonderful people that have provided translations, either through GitHub or via Crowdin [can be seen here](https://github.com/BookStackApp/BookStack/blob/development/.github/translators.txt). +The great people that have worked to build and improve BookStack can [be seen here](https://github.com/BookStackApp/BookStack/graphs/contributors). The wonderful people that have provided translations, either through GitHub or via Crowdin [can be seen here](https://github.com/BookStackApp/BookStack/blob/development/.github/translators.txt). Below are the great open-source projects used to help build BookStack. Note: This is not an exhaustive list of all libraries and projects that would be used in an active BookStack instance. diff --git a/resources/icons/groups.svg b/resources/icons/groups.svg new file mode 100644 index 000000000..c99a6b503 --- /dev/null +++ b/resources/icons/groups.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/icons/role.svg b/resources/icons/role.svg new file mode 100644 index 000000000..e7cad506d --- /dev/null +++ b/resources/icons/role.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/resources/js/code.mjs b/resources/js/code.mjs index eca941f1c..5881e2512 100644 --- a/resources/js/code.mjs +++ b/resources/js/code.mjs @@ -15,6 +15,7 @@ import 'codemirror/mode/lua/lua'; import 'codemirror/mode/markdown/markdown'; import 'codemirror/mode/mllike/mllike'; import 'codemirror/mode/nginx/nginx'; +import 'codemirror/mode/octave/octave'; import 'codemirror/mode/perl/perl'; import 'codemirror/mode/pascal/pascal'; import 'codemirror/mode/php/php'; @@ -65,11 +66,13 @@ const modeMap = { julia: 'text/x-julia', latex: 'text/x-stex', lua: 'lua', + matlab: 'text/x-octave', md: 'markdown', mdown: 'markdown', markdown: 'markdown', ml: 'mllike', nginx: 'nginx', + octave: 'text/x-octave', perl: 'perl', pl: 'perl', powershell: 'powershell', diff --git a/resources/js/components/auto-suggest.js b/resources/js/components/auto-suggest.js index d1c15c00a..80857cbe5 100644 --- a/resources/js/components/auto-suggest.js +++ b/resources/js/components/auto-suggest.js @@ -88,14 +88,12 @@ class AutoSuggest { } const nameFilter = this.getNameFilterIfNeeded(); - const search = this.input.value.slice(0, 3).toLowerCase(); + const search = this.input.value.toLowerCase(); const suggestions = await this.loadSuggestions(search, nameFilter); - let toShow = suggestions.slice(0, 6); - if (search.length > 0) { - toShow = suggestions.filter(val => { - return val.toLowerCase().includes(search); - }).slice(0, 6); - } + + const toShow = suggestions.filter(val => { + return search === '' || val.toLowerCase().startsWith(search); + }).slice(0, 10); this.displaySuggestions(toShow); } @@ -111,6 +109,9 @@ class AutoSuggest { * @returns {Promise} */ async loadSuggestions(search, nameFilter = null) { + // Truncate search to prevent over numerous lookups + search = search.slice(0, 4); + const params = {search, name: nameFilter}; const cacheKey = `${this.url}:${JSON.stringify(params)}`; diff --git a/resources/js/components/entity-permissions-editor.js b/resources/js/components/entity-permissions-editor.js deleted file mode 100644 index a821792a0..000000000 --- a/resources/js/components/entity-permissions-editor.js +++ /dev/null @@ -1,20 +0,0 @@ - -class EntityPermissionsEditor { - - constructor(elem) { - this.permissionsTable = elem.querySelector('[permissions-table]'); - - // Handle toggle all event - this.restrictedCheckbox = elem.querySelector('[name=restricted]'); - this.restrictedCheckbox.addEventListener('change', this.updateTableVisibility.bind(this)); - } - - updateTableVisibility() { - this.permissionsTable.style.display = - this.restrictedCheckbox.checked - ? null - : 'none'; - } -} - -export default EntityPermissionsEditor; \ No newline at end of file diff --git a/resources/js/components/entity-permissions.js b/resources/js/components/entity-permissions.js new file mode 100644 index 000000000..c67c85f19 --- /dev/null +++ b/resources/js/components/entity-permissions.js @@ -0,0 +1,79 @@ +/** + * @extends {Component} + */ +import {htmlToDom} from "../services/dom"; + +class EntityPermissions { + + setup() { + this.container = this.$el; + this.entityType = this.$opts.entityType; + + this.everyoneInheritToggle = this.$refs.everyoneInherit; + this.roleSelect = this.$refs.roleSelect; + this.roleContainer = this.$refs.roleContainer; + + this.setupListeners(); + } + + setupListeners() { + // "Everyone Else" inherit toggle + this.everyoneInheritToggle.addEventListener('change', event => { + const inherit = event.target.checked; + const permissions = document.querySelectorAll('input[name^="permissions[0]["]'); + for (const permission of permissions) { + permission.disabled = inherit; + permission.checked = false; + } + }); + + // Remove role row button click + this.container.addEventListener('click', event => { + const button = event.target.closest('button'); + if (button && button.dataset.roleId) { + this.removeRowOnButtonClick(button) + } + }); + + // Role select change + this.roleSelect.addEventListener('change', event => { + const roleId = this.roleSelect.value; + if (roleId) { + this.addRoleRow(roleId); + } + }); + } + + async addRoleRow(roleId) { + this.roleSelect.disabled = true; + + // Remove option from select + const option = this.roleSelect.querySelector(`option[value="${roleId}"]`); + if (option) { + option.remove(); + } + + // Get and insert new row + const resp = await window.$http.get(`/permissions/form-row/${this.entityType}/${roleId}`); + const row = htmlToDom(resp.data); + this.roleContainer.append(row); + + this.roleSelect.disabled = false; + } + + removeRowOnButtonClick(button) { + const row = button.closest('.content-permissions-row'); + const roleId = button.dataset.roleId; + const roleName = button.dataset.roleName; + + const option = document.createElement('option'); + option.value = roleId; + option.textContent = roleName; + + this.roleSelect.append(option); + row.remove(); + } + +} + +export default EntityPermissions; \ No newline at end of file diff --git a/resources/js/components/index.js b/resources/js/components/index.js index f360e2b0c..5b84edba0 100644 --- a/resources/js/components/index.js +++ b/resources/js/components/index.js @@ -18,7 +18,7 @@ import dropdown from "./dropdown.js" import dropdownSearch from "./dropdown-search.js" import dropzone from "./dropzone.js" import editorToolbox from "./editor-toolbox.js" -import entityPermissionsEditor from "./entity-permissions-editor.js" +import entityPermissions from "./entity-permissions"; import entitySearch from "./entity-search.js" import entitySelector from "./entity-selector.js" import entitySelectorPopup from "./entity-selector-popup.js" @@ -38,6 +38,7 @@ import pageDisplay from "./page-display.js" import pageEditor from "./page-editor.js" import pagePicker from "./page-picker.js" import permissionsTable from "./permissions-table.js" +import pointer from "./pointer.js"; import popup from "./popup.js" import settingAppColorPicker from "./setting-app-color-picker.js" import settingColorPicker from "./setting-color-picker.js" @@ -75,7 +76,7 @@ const componentMapping = { "dropdown-search": dropdownSearch, "dropzone": dropzone, "editor-toolbox": editorToolbox, - "entity-permissions-editor": entityPermissionsEditor, + "entity-permissions": entityPermissions, "entity-search": entitySearch, "entity-selector": entitySelector, "entity-selector-popup": entitySelectorPopup, @@ -95,6 +96,7 @@ const componentMapping = { "page-editor": pageEditor, "page-picker": pagePicker, "permissions-table": permissionsTable, + "pointer": pointer, "popup": popup, "setting-app-color-picker": settingAppColorPicker, "setting-color-picker": settingColorPicker, diff --git a/resources/js/components/page-display.js b/resources/js/components/page-display.js index 88254fd3a..b4f1cca4f 100644 --- a/resources/js/components/page-display.js +++ b/resources/js/components/page-display.js @@ -1,4 +1,3 @@ -import Clipboard from "clipboard/dist/clipboard.min"; import * as DOM from "../services/dom"; import {scrollAndHighlightElement} from "../services/util"; @@ -9,7 +8,6 @@ class PageDisplay { this.pageId = elem.getAttribute('page-display'); window.importVersioned('code').then(Code => Code.highlight()); - this.setupPointer(); this.setupNavHighlighting(); this.setupDetailsCodeBlockRefresh(); @@ -50,108 +48,6 @@ class PageDisplay { } } - setupPointer() { - let pointer = document.getElementById('pointer'); - if (!pointer) { - return; - } - - // Set up pointer - pointer = pointer.parentNode.removeChild(pointer); - const pointerInner = pointer.querySelector('div.pointer'); - - // Instance variables - let pointerShowing = false; - let isSelection = false; - let pointerModeLink = true; - let pointerSectionId = ''; - - // Select all contents on input click - DOM.onChildEvent(pointer, 'input', 'click', (event, input) => { - input.select(); - event.stopPropagation(); - }); - - // Prevent closing pointer when clicked or focused - DOM.onEvents(pointer, ['click', 'focus'], event => { - event.stopPropagation(); - }); - - // Pointer mode toggle - DOM.onChildEvent(pointer, 'span.icon', 'click', (event, icon) => { - event.stopPropagation(); - pointerModeLink = !pointerModeLink; - icon.querySelector('[data-icon="include"]').style.display = (!pointerModeLink) ? 'inline' : 'none'; - icon.querySelector('[data-icon="link"]').style.display = (pointerModeLink) ? 'inline' : 'none'; - updatePointerContent(); - }); - - // Set up clipboard - new Clipboard(pointer.querySelector('button')); - - // Hide pointer when clicking away - DOM.onEvents(document.body, ['click', 'focus'], event => { - if (!pointerShowing || isSelection) return; - pointer = pointer.parentElement.removeChild(pointer); - pointerShowing = false; - }); - - let updatePointerContent = (element) => { - let inputText = pointerModeLink ? window.baseUrl(`/link/${this.pageId}#${pointerSectionId}`) : `{{@${this.pageId}#${pointerSectionId}}}`; - if (pointerModeLink && !inputText.startsWith('http')) { - inputText = window.location.protocol + "//" + window.location.host + inputText; - } - - pointer.querySelector('input').value = inputText; - - // Update anchor if present - const editAnchor = pointer.querySelector('#pointer-edit'); - if (editAnchor && element) { - const editHref = editAnchor.dataset.editHref; - const elementId = element.id; - - // get the first 50 characters. - const queryContent = element.textContent && element.textContent.substring(0, 50); - editAnchor.href = `${editHref}?content-id=${elementId}&content-text=${encodeURIComponent(queryContent)}`; - } - }; - - // Show pointer when selecting a single block of tagged content - DOM.forEach('.page-content [id^="bkmrk"]', bookMarkElem => { - DOM.onEvents(bookMarkElem, ['mouseup', 'keyup'], event => { - event.stopPropagation(); - let selection = window.getSelection(); - if (selection.toString().length === 0) return; - - // Show pointer and set link - pointerSectionId = bookMarkElem.id; - updatePointerContent(bookMarkElem); - - bookMarkElem.parentNode.insertBefore(pointer, bookMarkElem); - pointer.style.display = 'block'; - pointerShowing = true; - isSelection = true; - - // Set pointer to sit near mouse-up position - requestAnimationFrame(() => { - const bookMarkBounds = bookMarkElem.getBoundingClientRect(); - let pointerLeftOffset = (event.pageX - bookMarkBounds.left - 164); - if (pointerLeftOffset < 0) { - pointerLeftOffset = 0 - } - const pointerLeftOffsetPercent = (pointerLeftOffset / bookMarkBounds.width) * 100; - - pointerInner.style.left = pointerLeftOffsetPercent + '%'; - - setTimeout(() => { - isSelection = false; - }, 100); - }); - - }); - }); - } - setupNavHighlighting() { // Check if support is present for IntersectionObserver if (!('IntersectionObserver' in window) || diff --git a/resources/js/components/permissions-table.js b/resources/js/components/permissions-table.js index baad75258..df3c055ca 100644 --- a/resources/js/components/permissions-table.js +++ b/resources/js/components/permissions-table.js @@ -1,22 +1,21 @@ class PermissionsTable { - constructor(elem) { - this.container = elem; + setup() { + this.container = this.$el; // Handle toggle all event - const toggleAll = elem.querySelector('[permissions-table-toggle-all]'); - toggleAll.addEventListener('click', this.toggleAllClick.bind(this)); + for (const toggleAllElem of (this.$manyRefs.toggleAll || [])) { + toggleAllElem.addEventListener('click', this.toggleAllClick.bind(this)); + } // Handle toggle row event - const toggleRowElems = elem.querySelectorAll('[permissions-table-toggle-all-in-row]'); - for (let toggleRowElem of toggleRowElems) { + for (const toggleRowElem of (this.$manyRefs.toggleRow || [])) { toggleRowElem.addEventListener('click', this.toggleRowClick.bind(this)); } // Handle toggle column event - const toggleColumnElems = elem.querySelectorAll('[permissions-table-toggle-all-in-column]'); - for (let toggleColElem of toggleColumnElems) { + for (const toggleColElem of (this.$manyRefs.toggleColumn || [])) { toggleColElem.addEventListener('click', this.toggleColumnClick.bind(this)); } } diff --git a/resources/js/components/pointer.js b/resources/js/components/pointer.js new file mode 100644 index 000000000..d1967acd0 --- /dev/null +++ b/resources/js/components/pointer.js @@ -0,0 +1,131 @@ +import * as DOM from "../services/dom"; +import Clipboard from "clipboard/dist/clipboard.min"; + +/** + * @extends Component + */ +class Pointer { + + setup() { + this.container = this.$el; + this.pageId = this.$opts.pageId; + + // Instance variables + this.showing = false; + this.isSelection = false; + this.pointerModeLink = true; + this.pointerSectionId = ''; + + this.setupListeners(); + + // Set up clipboard + new Clipboard(this.container.querySelector('button')); + } + + setupListeners() { + // Select all contents on input click + DOM.onChildEvent(this.container, 'input', 'click', (event, input) => { + input.select(); + event.stopPropagation(); + }); + + // Prevent closing pointer when clicked or focused + DOM.onEvents(this.container, ['click', 'focus'], event => { + event.stopPropagation(); + }); + + // Pointer mode toggle + DOM.onChildEvent(this.container, 'span.icon', 'click', (event, icon) => { + event.stopPropagation(); + this.pointerModeLink = !this.pointerModeLink; + icon.querySelector('[data-icon="include"]').style.display = (!this.pointerModeLink) ? 'inline' : 'none'; + icon.querySelector('[data-icon="link"]').style.display = (this.pointerModeLink) ? 'inline' : 'none'; + this.updateForTarget(); + }); + + // Hide pointer when clicking away + DOM.onEvents(document.body, ['click', 'focus'], event => { + if (!this.showing || this.isSelection) return; + this.hidePointer(); + }); + + // Show pointer when selecting a single block of tagged content + const pageContent = document.querySelector('.page-content'); + DOM.onEvents(pageContent, ['mouseup', 'keyup'], event => { + event.stopPropagation(); + const targetEl = event.target.closest('[id^="bkmrk"]'); + if (targetEl) { + this.showPointerAtTarget(targetEl, event.pageX); + } + }); + } + + hidePointer() { + this.container.style.display = null; + this.showing = false; + } + + /** + * Move and display the pointer at the given element, targeting the given screen x-position if possible. + * @param {Element} element + * @param {Number} xPosition + */ + showPointerAtTarget(element, xPosition) { + const selection = window.getSelection(); + if (selection.toString().length === 0) return; + + // Show pointer and set link + this.pointerSectionId = element.id; + this.updateForTarget(element); + + this.container.style.display = 'block'; + const targetBounds = element.getBoundingClientRect(); + const pointerBounds = this.container.getBoundingClientRect(); + + const xTarget = Math.min(Math.max(xPosition, targetBounds.left), targetBounds.right); + const xOffset = xTarget - (pointerBounds.width / 2); + const yOffset = (targetBounds.top - pointerBounds.height) - 16; + + this.container.style.left = `${xOffset}px`; + this.container.style.top = `${yOffset}px`; + + this.showing = true; + this.isSelection = true; + + setTimeout(() => { + this.isSelection = false; + }, 100); + + const scrollListener = () => { + this.hidePointer(); + window.removeEventListener('scroll', scrollListener, {passive: true}); + }; + window.addEventListener('scroll', scrollListener, {passive: true}); + } + + /** + * Update the pointer inputs/content for the given target element. + * @param {?Element} element + */ + updateForTarget(element) { + let inputText = this.pointerModeLink ? window.baseUrl(`/link/${this.pageId}#${this.pointerSectionId}`) : `{{@${this.pageId}#${this.pointerSectionId}}}`; + if (this.pointerModeLink && !inputText.startsWith('http')) { + inputText = window.location.protocol + "//" + window.location.host + inputText; + } + + this.container.querySelector('input').value = inputText; + + // Update anchor if present + const editAnchor = this.container.querySelector('#pointer-edit'); + if (editAnchor && element) { + const editHref = editAnchor.dataset.editHref; + const elementId = element.id; + + // get the first 50 characters. + const queryContent = element.textContent && element.textContent.substring(0, 50); + editAnchor.href = `${editHref}?content-id=${elementId}&content-text=${encodeURIComponent(queryContent)}`; + } + } +} + +export default Pointer; \ No newline at end of file diff --git a/resources/js/components/shelf-sort.js b/resources/js/components/shelf-sort.js index 07526716a..30eda5a21 100644 --- a/resources/js/components/shelf-sort.js +++ b/resources/js/components/shelf-sort.js @@ -19,6 +19,7 @@ class ShelfSort { new Sortable(scrollBox, { group: 'shelf-books', ghostClass: 'primary-background-light', + handle: '.handle', animation: 150, onSort: this.onChange.bind(this), }); diff --git a/resources/js/services/dom.js b/resources/js/services/dom.js index 7a7b2c9bc..eb5f6a853 100644 --- a/resources/js/services/dom.js +++ b/resources/js/services/dom.js @@ -117,4 +117,17 @@ export function removeLoading(element) { for (const el of loadingEls) { el.remove(); } +} + +/** + * Convert the given html data into a live DOM element. + * Initiates any components defined in the data. + * @param {String} html + * @returns {Element} + */ +export function htmlToDom(html) { + const wrap = document.createElement('div'); + wrap.innerHTML = html; + window.components.init(wrap); + return wrap.children[0]; } \ No newline at end of file diff --git a/resources/js/wysiwyg/config.js b/resources/js/wysiwyg/config.js index 52c52592c..acf5e1d52 100644 --- a/resources/js/wysiwyg/config.js +++ b/resources/js/wysiwyg/config.js @@ -3,6 +3,7 @@ import {listen as listenForCommonEvents} from "./common-events"; import {scrollToQueryString} from "./scrolling"; import {listenForDragAndPaste} from "./drop-paste-handling"; import {getPrimaryToolbar, registerAdditionalToolbars} from "./toolbars"; +import {registerCustomIcons} from "./icons"; import {getPlugin as getCodeeditorPlugin} from "./plugin-codeeditor"; import {getPlugin as getDrawioPlugin} from "./plugin-drawio"; @@ -255,7 +256,7 @@ export function build(options) { statusbar: false, menubar: false, paste_data_images: false, - extended_valid_elements: 'pre[*],svg[*],div[drawio-diagram],details[*],summary[*],div[*],li[class|checked]', + extended_valid_elements: 'pre[*],svg[*],div[drawio-diagram],details[*],summary[*],div[*],li[class|checked|style]', automatic_uploads: false, custom_elements: 'doc-root,code-block', valid_children: [ @@ -291,6 +292,7 @@ export function build(options) { head.innerHTML += fetchCustomHeadContent(); }, setup(editor) { + registerCustomIcons(editor); registerAdditionalToolbars(editor, options); getSetupCallback(options)(editor); }, diff --git a/resources/js/wysiwyg/icons.js b/resources/js/wysiwyg/icons.js new file mode 100644 index 000000000..2c2457fe1 --- /dev/null +++ b/resources/js/wysiwyg/icons.js @@ -0,0 +1,21 @@ +const icons = { + 'table-delete-column': '', + 'table-delete-row': '', + 'table-insert-column-after': '', + 'table-insert-column-before': '', + 'table-insert-row-above': '', + 'table-insert-row-after': '', + 'table': '', + 'table-delete-table': '', +}; + + +/** + * @param {Editor} editor + */ +export function registerCustomIcons(editor) { + + for (const [name, svg] of Object.entries(icons)) { + editor.ui.registry.addIcon(name, svg); + } +} \ No newline at end of file diff --git a/resources/js/wysiwyg/plugin-codeeditor.js b/resources/js/wysiwyg/plugin-codeeditor.js index b9fc355e1..66441c87e 100644 --- a/resources/js/wysiwyg/plugin-codeeditor.js +++ b/resources/js/wysiwyg/plugin-codeeditor.js @@ -39,16 +39,16 @@ function defineCodeBlockCustomElement(editor) { constructor() { super(); this.attachShadow({mode: 'open'}); - const linkElem = document.createElement('link'); - linkElem.setAttribute('rel', 'stylesheet'); - linkElem.setAttribute('href', window.baseUrl('/dist/styles.css')); + + const stylesToCopy = document.querySelectorAll('link[rel="stylesheet"]:not([media="print"])'); + const copiedStyles = Array.from(stylesToCopy).map(styleEl => styleEl.cloneNode(false)); const cmContainer = document.createElement('div'); cmContainer.style.pointerEvents = 'none'; cmContainer.contentEditable = 'false'; cmContainer.classList.add('CodeMirrorContainer'); - this.shadowRoot.append(linkElem, cmContainer); + this.shadowRoot.append(...copiedStyles, cmContainer); } getLanguage() { @@ -153,6 +153,14 @@ function register(editor, url) { } }); + editor.ui.registry.addButton('editcodeeditor', { + tooltip: 'Edit code block', + icon: 'edit-block', + onAction() { + editor.execCommand('codeeditor'); + } + }); + editor.addCommand('codeeditor', () => { const selectedNode = editor.selection.getNode(); const doc = selectedNode.ownerDocument; @@ -208,6 +216,15 @@ function register(editor, url) { }); }); + editor.ui.registry.addContextToolbar('codeeditor', { + predicate: function (node) { + return node.nodeName.toLowerCase() === 'code-block'; + }, + items: 'editcodeeditor', + position: 'node', + scope: 'node' + }); + editor.on('PreInit', () => { defineCodeBlockCustomElement(editor); }); diff --git a/resources/lang/ar/editor.php b/resources/lang/ar/editor.php index c38b92389..01bad5302 100644 --- a/resources/lang/ar/editor.php +++ b/resources/lang/ar/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Insert/Edit Link', 'insert_horizontal_line' => 'Insert horizontal line', 'insert_code_block' => 'Insert code block', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Insert/edit drawing', 'drawing_manager' => 'Drawing manager', 'insert_media' => 'Insert/edit media', diff --git a/resources/lang/ar/entities.php b/resources/lang/ar/entities.php index 3285b0ad6..e19f5bb74 100644 --- a/resources/lang/ar/entities.php +++ b/resources/lang/ar/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'الأذونات', - 'permissions_intro' => 'عند التفعيل، سوف تأخذ هذه الأذونات أولوية على أي صلاحية أخرى للدور.', - 'permissions_enable' => 'تفعيل الأذونات المخصصة', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'حفظ الأذونات', 'permissions_owner' => 'Owner', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'نتائج البحث', diff --git a/resources/lang/bg/editor.php b/resources/lang/bg/editor.php index c3102868f..c7526f1e9 100644 --- a/resources/lang/bg/editor.php +++ b/resources/lang/bg/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Вмъкни/редактирай връзка', 'insert_horizontal_line' => 'Вмъкни хоризонтална линия', 'insert_code_block' => 'Въведи код', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Вмъкни/редактирай рисунка', 'drawing_manager' => 'Управление на рисунките', 'insert_media' => 'Вмъкни/редактирай мултимедия', diff --git a/resources/lang/bg/entities.php b/resources/lang/bg/entities.php index cbb78dc9e..4d9c926f6 100644 --- a/resources/lang/bg/entities.php +++ b/resources/lang/bg/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Права', - 'permissions_intro' => 'Веднъж добавени, тези права ще вземат приоритет над всички други установени права.', - 'permissions_enable' => 'Разреши уникални права', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Запази права', 'permissions_owner' => 'Собственик', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Резултати от търсенето', diff --git a/resources/lang/bs/editor.php b/resources/lang/bs/editor.php index da7ffcf01..faf351da2 100644 --- a/resources/lang/bs/editor.php +++ b/resources/lang/bs/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Insert/Edit Link', 'insert_horizontal_line' => 'Insert horizontal line', 'insert_code_block' => 'Insert code block', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Insert/edit drawing', 'drawing_manager' => 'Drawing manager', 'insert_media' => 'Insert/edit media', diff --git a/resources/lang/bs/entities.php b/resources/lang/bs/entities.php index f8805effe..3672b148d 100644 --- a/resources/lang/bs/entities.php +++ b/resources/lang/bs/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Dozvole', - 'permissions_intro' => 'Jednom omogućene, ove dozvole imaju prednost nad dozvolama uloge.', - 'permissions_enable' => 'Omogući prilagođena dopuštenja', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Snimi dozvole', 'permissions_owner' => 'Vlasnik', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Rezultati pretrage', diff --git a/resources/lang/ca/editor.php b/resources/lang/ca/editor.php index da7ffcf01..faf351da2 100644 --- a/resources/lang/ca/editor.php +++ b/resources/lang/ca/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Insert/Edit Link', 'insert_horizontal_line' => 'Insert horizontal line', 'insert_code_block' => 'Insert code block', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Insert/edit drawing', 'drawing_manager' => 'Drawing manager', 'insert_media' => 'Insert/edit media', diff --git a/resources/lang/ca/entities.php b/resources/lang/ca/entities.php index b31cbaa93..0736e527a 100644 --- a/resources/lang/ca/entities.php +++ b/resources/lang/ca/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Permisos', - 'permissions_intro' => 'Si els activeu, aquests permisos tindran més prioritat que qualsevol permís de rol.', - 'permissions_enable' => 'Activa els permisos personalitzats', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Desa els permisos', 'permissions_owner' => 'Propietari', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Resultats de la cerca', diff --git a/resources/lang/cs/editor.php b/resources/lang/cs/editor.php index da7ffcf01..faf351da2 100644 --- a/resources/lang/cs/editor.php +++ b/resources/lang/cs/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Insert/Edit Link', 'insert_horizontal_line' => 'Insert horizontal line', 'insert_code_block' => 'Insert code block', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Insert/edit drawing', 'drawing_manager' => 'Drawing manager', 'insert_media' => 'Insert/edit media', diff --git a/resources/lang/cs/entities.php b/resources/lang/cs/entities.php index 34515fd77..0b552346e 100644 --- a/resources/lang/cs/entities.php +++ b/resources/lang/cs/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Oprávnění', - 'permissions_intro' => 'Pokud je povoleno, tato oprávnění budou mít přednost před všemi nastavenými oprávněními role.', - 'permissions_enable' => 'Povolit vlastní oprávnění', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Uložit oprávnění', 'permissions_owner' => 'Vlastník', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Výsledky hledání', diff --git a/resources/lang/cy/editor.php b/resources/lang/cy/editor.php index da7ffcf01..faf351da2 100644 --- a/resources/lang/cy/editor.php +++ b/resources/lang/cy/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Insert/Edit Link', 'insert_horizontal_line' => 'Insert horizontal line', 'insert_code_block' => 'Insert code block', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Insert/edit drawing', 'drawing_manager' => 'Drawing manager', 'insert_media' => 'Insert/edit media', diff --git a/resources/lang/cy/entities.php b/resources/lang/cy/entities.php index 1720801d2..bf6201900 100644 --- a/resources/lang/cy/entities.php +++ b/resources/lang/cy/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Permissions', - 'permissions_intro' => 'Once enabled, These permissions will take priority over any set role permissions.', - 'permissions_enable' => 'Enable Custom Permissions', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Save Permissions', 'permissions_owner' => 'Owner', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Search Results', diff --git a/resources/lang/da/editor.php b/resources/lang/da/editor.php index a0235318b..c925391d5 100644 --- a/resources/lang/da/editor.php +++ b/resources/lang/da/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Indsæt/Rediger Link', 'insert_horizontal_line' => 'Indsæt vandret linje', 'insert_code_block' => 'Indsæt kodeblok', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Indsæt/rediger tegning', 'drawing_manager' => 'Drawing manager', 'insert_media' => 'Indsæt/rediger medie', diff --git a/resources/lang/da/entities.php b/resources/lang/da/entities.php index 365f3e529..22e850d5c 100644 --- a/resources/lang/da/entities.php +++ b/resources/lang/da/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Rettigheder', - 'permissions_intro' => 'Når de er aktiveret, vil disse tilladelser have prioritet over alle indstillede rolletilladelser.', - 'permissions_enable' => 'Aktivér tilpassede tilladelser', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Gem tilladelser', 'permissions_owner' => 'Ejer', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Søgeresultater', diff --git a/resources/lang/de/activities.php b/resources/lang/de/activities.php index e7f18f1e0..0d3f337b7 100644 --- a/resources/lang/de/activities.php +++ b/resources/lang/de/activities.php @@ -48,7 +48,7 @@ return [ 'bookshelf_delete_notification' => 'Regal erfolgreich gelöscht', // Favourites - 'favourite_add_notification' => '":name" wurde zu deinen Favoriten hinzugefügt', + 'favourite_add_notification' => '":name" wurde zu Ihren Favoriten hinzugefügt', 'favourite_remove_notification' => '":name" wurde aus Ihren Favoriten entfernt', // MFA diff --git a/resources/lang/de/auth.php b/resources/lang/de/auth.php index f0433ba5d..f72ef56e3 100644 --- a/resources/lang/de/auth.php +++ b/resources/lang/de/auth.php @@ -35,7 +35,7 @@ return [ 'register_thanks' => 'Vielen Dank für Ihre Registrierung!', 'register_confirm' => 'Bitte prüfen Sie Ihren Posteingang und bestätigen Sie die Registrierung.', 'registrations_disabled' => 'Eine Registrierung ist momentan nicht möglich', - 'registration_email_domain_invalid' => 'Sie können sich mit dieser E-Mail nicht registrieren.', + 'registration_email_domain_invalid' => 'Sie können sich mit dieser E-Mail-Adresse nicht registrieren', 'register_success' => 'Vielen Dank für Ihre Registrierung! Die Daten sind gespeichert und Sie sind angemeldet.', // Login auto-initiation @@ -58,7 +58,7 @@ return [ 'email_confirm_greeting' => 'Danke, dass Sie sich für :appName registriert haben!', 'email_confirm_text' => 'Bitte bestätigen Sie Ihre E-Mail-Adresse, indem Sie auf die Schaltfläche klicken:', 'email_confirm_action' => 'E-Mail-Adresse bestätigen', - 'email_confirm_send_error' => 'Leider konnte die für die Registrierung notwendige E-Mail zur bestätigung Ihrer E-Mail-Adresse nicht versandt werden. Bitte kontaktieren Sie den Systemadministrator!', + 'email_confirm_send_error' => 'Leider konnte die für die Registrierung notwendige E-Mail zur Bestätigung Ihrer E-Mail-Adresse nicht versandt werden. Bitte kontaktieren Sie den Systemadministrator!', 'email_confirm_success' => 'Ihre E-Mail wurde bestätigt! Sie sollten nun in der Lage sein, sich mit dieser E-Mail-Adresse anzumelden.', 'email_confirm_resent' => 'Bestätigungs-E-Mail wurde erneut versendet, bitte überprüfen Sie Ihren Posteingang.', @@ -69,12 +69,12 @@ return [ 'email_not_confirmed_resend_button' => 'Bestätigungs-E-Mail erneut senden', // User Invite - 'user_invite_email_subject' => 'Du wurdest eingeladen :appName beizutreten!', + 'user_invite_email_subject' => 'Sie wurden eingeladen :appName beizutreten!', 'user_invite_email_greeting' => 'Ein Konto wurde für Sie auf :appName erstellt.', 'user_invite_email_text' => 'Klicken Sie auf die Schaltfläche unten, um ein Passwort festzulegen und Zugriff zu erhalten:', 'user_invite_email_action' => 'Account-Passwort festlegen', 'user_invite_page_welcome' => 'Willkommen bei :appName!', - 'user_invite_page_text' => 'Um die Anmeldung abzuschließen und Zugriff auf :appName zu bekommen muss noch ein Passwort festgelegt werden. Dieses wird in Zukunft zum Einloggen benötigt.', + 'user_invite_page_text' => 'Um die Anmeldung abzuschließen und Zugriff auf :appName zu bekommen muss noch ein Passwort festgelegt werden. Dieses wird in Zukunft für die Anmeldung benötigt.', 'user_invite_page_confirm_button' => 'Passwort bestätigen', 'user_invite_success_login' => 'Passwort gesetzt, Sie sollten nun in der Lage sein, sich mit Ihrem Passwort an :appName anzumelden!', diff --git a/resources/lang/de/components.php b/resources/lang/de/components.php index bda1ce376..7036888f4 100644 --- a/resources/lang/de/components.php +++ b/resources/lang/de/components.php @@ -17,7 +17,7 @@ return [ 'image_delete_used' => 'Dieses Bild wird auf den folgenden Seiten benutzt. ', 'image_delete_confirm_text' => 'Möchten Sie dieses Bild wirklich löschen?', 'image_select_image' => 'Bild auswählen', - 'image_dropzone' => 'Ziehen Sie Bilder hierher oder klicken Sie, um ein Bild auszuwählen', + 'image_dropzone' => 'Ziehen Sie Bilder hierher oder klicken Sie hier, um ein Bild auszuwählen', 'images_deleted' => 'Bilder gelöscht', 'image_preview' => 'Bildvorschau', 'image_upload_success' => 'Bild erfolgreich hochgeladen', diff --git a/resources/lang/de/editor.php b/resources/lang/de/editor.php index 2fff8c7ea..2c14b6410 100644 --- a/resources/lang/de/editor.php +++ b/resources/lang/de/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Link einfügen/ändern', 'insert_horizontal_line' => 'Horizontale Linie einfügen', 'insert_code_block' => 'Code-Block einfügen', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Zeichnung einfügen/ändern', 'drawing_manager' => 'Zeichnungsmanager', 'insert_media' => 'Medien einfügen/ändern', diff --git a/resources/lang/de/entities.php b/resources/lang/de/entities.php index f83225ddc..8255cf5a5 100644 --- a/resources/lang/de/entities.php +++ b/resources/lang/de/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Berechtigungen', - 'permissions_intro' => 'Wenn individuelle Berechtigungen aktiviert werden, überschreiben diese Einstellungen durch Rollen zugewiesene Berechtigungen.', - 'permissions_enable' => 'Individuelle Berechtigungen aktivieren', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Berechtigungen speichern', 'permissions_owner' => 'Besitzer', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Suchergebnisse', diff --git a/resources/lang/de/errors.php b/resources/lang/de/errors.php index cedd85ad7..34b0e715f 100644 --- a/resources/lang/de/errors.php +++ b/resources/lang/de/errors.php @@ -6,7 +6,7 @@ return [ // Permissions 'permission' => 'Sie haben keine Zugriffsberechtigung auf die angeforderte Seite.', - 'permissionJson' => 'Sie haben keine Berechtigung, die angeforderte Aktion auszuführen.', + 'permissionJson' => 'Sie haben keine Berechtigung die angeforderte Aktion auszuführen.', // Auth 'error_user_exists_different_creds' => 'Ein Benutzer mit der E-Mail-Adresse :email ist bereits mit anderen Anmeldedaten registriert.', @@ -19,9 +19,9 @@ return [ '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.', 'saml_already_logged_in' => 'Sie sind bereits angemeldet', - 'saml_user_not_registered' => 'Kein Benutzer mit ID :name registriert und die automatische Registrierung ist deaktiviert', + 'saml_user_not_registered' => 'Es ist kein Benutzer mit ID :name registriert und die automatische Registrierung ist deaktiviert', 'saml_no_email_address' => 'Es konnte keine E-Mail-Adresse für diesen Benutzer in den vom externen Authentifizierungssystem zur Verfügung gestellten Daten gefunden werden', - 'saml_invalid_response_id' => 'Die Anfrage vom externen Authentifizierungssystem wird von einem von dieser Anwendung gestarteten Prozess nicht erkannt. Das Zurückgehen nach einem Login könnte dieses Problem verursachen.', + 'saml_invalid_response_id' => 'Die Anfrage vom externen Authentifizierungssystem wird von einem von dieser Anwendung gestarteten Prozess nicht erkannt. Das Zurückgehen nach einer Anmeldung könnte dieses Problem verursachen.', 'saml_fail_authed' => 'Anmeldung mit :system fehlgeschlagen, System konnte keine erfolgreiche Autorisierung bereitstellen', 'oidc_already_logged_in' => 'Bereits angemeldet', 'oidc_user_not_registered' => 'Der Benutzer :name ist nicht registriert und die automatische Registrierung ist deaktiviert', @@ -33,11 +33,11 @@ return [ 'social_account_email_in_use' => 'Die E-Mail-Adresse ":email" ist bereits registriert. Wenn Sie bereits registriert sind, können Sie Ihr :socialAccount-Konto in Ihren Profil-Einstellungen verknüpfen.', 'social_account_existing' => 'Dieses :socialAccount-Konto ist bereits mit Ihrem Profil verknüpft.', 'social_account_already_used_existing' => 'Dieses :socialAccount-Konto wird bereits von einem anderen Benutzer verwendet.', - 'social_account_not_used' => 'Dieses :socialAccount-Konto ist bisher keinem Benutzer zugeordnet. Sie können es in Ihren Profil-Einstellung.', + 'social_account_not_used' => 'Dieses :socialAccount-Konto ist bisher keinem Benutzer zugeordnet. Sie können es in Ihren Profil-Einstellungen zuordnen. ', 'social_account_register_instructions' => 'Wenn Sie bisher keinen Social-Media Konto besitzen, können Sie ein solches Konto mit der :socialAccount Option anlegen.', 'social_driver_not_found' => 'Treiber für Social-Media-Konten nicht gefunden', 'social_driver_not_configured' => 'Ihr :socialAccount-Konto ist nicht korrekt konfiguriert.', - 'invite_token_expired' => 'Dieser Einladungslink ist abgelaufen. Sie können stattdessen versuchen, Ihr Passwort zurückzusetzen.', + 'invite_token_expired' => 'Dieser Einladungslink ist abgelaufen. Sie können stattdessen versuchen Ihr Passwort zurückzusetzen.', // System 'path_not_writable' => 'Die Datei kann nicht in den angegebenen Pfad :filePath hochgeladen werden. Stellen Sie sicher, dass dieser Ordner auf dem Server beschreibbar ist.', @@ -78,7 +78,7 @@ return [ // 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.', + 'cannot_add_comment_to_draft' => 'Sie können 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.', diff --git a/resources/lang/de/settings.php b/resources/lang/de/settings.php index 195593802..5daa11232 100644 --- a/resources/lang/de/settings.php +++ b/resources/lang/de/settings.php @@ -25,8 +25,8 @@ return [ 'app_public_access_toggle' => 'Öffentlichen Zugriff erlauben', 'app_public_viewing' => 'Öffentliche Ansicht erlauben?', 'app_secure_images' => 'Erhöhte Sicherheit für hochgeladene Bilder aktivieren?', - 'app_secure_images_toggle' => 'Aktiviere Bild-Upload höherer Sicherheit', - 'app_secure_images_desc' => 'Aus Leistungsgründen sind alle Bilder öffentlich sichtbar. Diese Option fügt zufällige, schwer zu eratene, Zeichenketten zu Bild-URLs hinzu. Stellen sie sicher, dass Verzeichnisindizes deaktiviert sind, um einen einfachen Zugriff zu verhindern.', + 'app_secure_images_toggle' => 'Aktiviere höhere Sicherheit für Bild-Uploads', + 'app_secure_images_desc' => 'Aus Leistungsgründen sind alle Bilder öffentlich sichtbar. Diese Option fügt zufällige, schwer zu erratende, Zeichenketten zu Bild-URLs hinzu. Stellen Sie sicher, dass Verzeichnisindizes deaktiviert sind, um einen einfachen Zugriff zu verhindern.', 'app_default_editor' => 'Standard-Seiten-Editor', 'app_default_editor_desc' => 'Wählen Sie aus, welcher Editor standardmäßig beim Bearbeiten neuer Seiten verwendet wird. Dies kann auf einer Seitenebene überschrieben werden, wenn es die Berechtigungen erlauben.', 'app_custom_html' => 'Benutzerdefinierter HTML Inhalt', @@ -37,12 +37,12 @@ return [ Größere Bilder werden verkleinert.', 'app_primary_color' => 'Primäre Anwendungsfarbe', 'app_primary_color_desc' => 'Dies sollte ein HEX Wert sein. -Wenn Sie nicht eingeben, wird die Anwendung auf die Standardfarbe zurückgesetzt.', +Wenn Sie nichts eingeben, wird die Anwendung auf die Standardfarbe zurückgesetzt.', 'app_homepage' => 'Startseite der Anwendung', '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::" 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 keine Anmeldung benötigen. Sie können die Bezeichnung "trans::" 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', @@ -70,8 +70,8 @@ Wenn Sie nicht eingeben, wird die Anwendung auf die Standardfarbe zurückgesetzt 'reg_email_confirmation_toggle' => 'Bestätigung per E-Mail erforderlich', 'reg_confirm_email_desc' => 'Falls die Einschränkung für Domains genutzt wird, ist die Bestätigung per E-Mail zwingend erforderlich und der untenstehende Wert wird ignoriert.', 'reg_confirm_restrict_domain' => 'Registrierung auf bestimmte Domains einschränken', - 'reg_confirm_restrict_domain_desc' => 'Fügen sie eine durch Komma getrennte Liste von Domains hinzu, auf die die Registrierung eingeschränkt werden soll. Benutzern wird eine E-Mail gesendet, um ihre E-Mail Adresse zu bestätigen, bevor sie diese Anwendung nutzen können. -Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung ändern.', + 'reg_confirm_restrict_domain_desc' => 'Fügen Sie eine durch Komma getrennte Liste von Domains hinzu, auf die die Registrierung eingeschränkt werden soll. Benutzern wird eine E-Mail gesendet, um ihre E-Mail-Adresse zu bestätigen, bevor diese die Anwendung nutzen können. +Hinweis: Benutzer können ihre E-Mail-Adresse nach erfolgreicher Registrierung ändern.', 'reg_confirm_restrict_domain_placeholder' => 'Keine Einschränkung gesetzt', // Maintenance settings diff --git a/resources/lang/de/validation.php b/resources/lang/de/validation.php index df3995f30..1ca1f458e 100644 --- a/resources/lang/de/validation.php +++ b/resources/lang/de/validation.php @@ -44,7 +44,7 @@ return [ 'numeric' => ':attribute muss größer-gleich :value sein.', 'file' => ':attribute muss mindestens :value Kilobytes groß sein.', 'string' => ':attribute muss mindestens :value Zeichen enthalten.', - 'array' => ':attribute muss :value Elemente oder mehr haben.', + 'array' => ':attribute muss :value oder mehr Elemente haben.', ], 'exists' => ':attribute ist ungültig.', 'image' => ':attribute muss ein Bild sein.', @@ -56,7 +56,7 @@ return [ 'ipv6' => ':attribute muss eine gültige IPv6-Adresse sein.', 'json' => 'Das Attribut muss eine gültige JSON-Zeichenfolge sein.', 'lt' => [ - 'numeric' => ':attribute muss kleiner sein :value sein.', + 'numeric' => ':attribute muss kleiner als :value sein.', 'file' => ':attribute muss kleiner als :value Kilobytes sein.', 'string' => ':attribute muss weniger als :value Zeichen haben.', 'array' => ':attribute muss weniger als :value Elemente haben.', diff --git a/resources/lang/de_informal/activities.php b/resources/lang/de_informal/activities.php index abc2235da..8e3ce7515 100644 --- a/resources/lang/de_informal/activities.php +++ b/resources/lang/de_informal/activities.php @@ -28,7 +28,7 @@ return [ // Books 'book_create' => 'erstellt Buch', 'book_create_notification' => 'Buch erfolgreich erstellt', - 'book_create_from_chapter' => 'umgewandeltes Kapitel zum Buch', + 'book_create_from_chapter' => 'Kapitel zu Buch umgewandelt', 'book_create_from_chapter_notification' => 'Kapitel erfolgreich in ein Buch umgewandelt', 'book_update' => 'aktualisiert Buch', 'book_update_notification' => 'Buch erfolgreich aktualisiert', @@ -38,13 +38,13 @@ return [ 'book_sort_notification' => 'Buch erfolgreich umsortiert', // Bookshelves - 'bookshelf_create' => 'created shelf', + 'bookshelf_create' => 'Regal erstellt', 'bookshelf_create_notification' => 'Regal erfolgreich erstellt', - 'bookshelf_create_from_book' => 'converted book to shelf', + 'bookshelf_create_from_book' => 'Buch zu Regal umgewandelt', 'bookshelf_create_from_book_notification' => 'Buch erfolgreich zu einem Regal umgewandelt', - 'bookshelf_update' => 'updated shelf', + 'bookshelf_update' => 'Regal aktualisiert', 'bookshelf_update_notification' => 'Regal erfolgreich aktualisiert', - 'bookshelf_delete' => 'deleted shelf', + 'bookshelf_delete' => 'Regal gelöscht', 'bookshelf_delete_notification' => 'Regal erfolgreich gelöscht', // Favourites diff --git a/resources/lang/de_informal/auth.php b/resources/lang/de_informal/auth.php index 1954f46ff..9cff7961d 100644 --- a/resources/lang/de_informal/auth.php +++ b/resources/lang/de_informal/auth.php @@ -99,17 +99,17 @@ return [ 'mfa_gen_totp_desc' => 'Um Mehrfach-Faktor-Authentifizierung nutzen zu können, benötigen Sie eine mobile Anwendung, die TOTP unterstützt, wie Google Authenticator, Authy oder Microsoft Authenticator.', 'mfa_gen_totp_scan' => 'Scannen Sie den QR-Code unten mit ihrer bevorzugten Authentifizierungs-App, um loszulegen.', 'mfa_gen_totp_verify_setup' => 'Setup überprüfen', - 'mfa_gen_totp_verify_setup_desc' => 'Überprüfen Sie, dass alles funktioniert, indem Sie einen Code in Ihrer Authentifizierungs-App in das Eingabefeld unten eingeben:', - 'mfa_gen_totp_provide_code_here' => 'Geben Sie hier Ihre App generierten Code ein', + 'mfa_gen_totp_verify_setup_desc' => 'Überprüfe, dass alles funktioniert, indem du einen Code aus deiner Authentifizierungs-App in das Eingabefeld unten eingibst:', + 'mfa_gen_totp_provide_code_here' => 'Gib hier den von der App generierten Code ein', 'mfa_verify_access' => 'Zugriff überprüfen', - 'mfa_verify_access_desc' => 'Ihr Benutzerkonto erfordert, dass Sie Ihre Identität über eine zusätzliche Verifikationsebene bestätigen, bevor Sie den Zugriff gewähren. Überprüfen Sie mit einer Ihrer konfigurierten Methoden, um fortzufahren.', + 'mfa_verify_access_desc' => 'Dein Benutzerkonto erfordert, dass du deine Identität über eine zusätzliche Verifikationsebene bestätigst, bevor du Zugriff erhältst. Verifiziere diese mit einer deiner konfigurierten Methoden, um fortzufahren.', 'mfa_verify_no_methods' => 'Keine Methoden konfiguriert', - 'mfa_verify_no_methods_desc' => 'Es konnten keine Mehrfach-Faktor-Authentifizierungsmethoden für Ihr Konto gefunden werden. Sie müssen mindestens eine Methode einrichten, bevor Sie Zugriff erhalten.', + 'mfa_verify_no_methods_desc' => 'Es konnten keine Multi-Faktor-Authentifizierungsmethoden für dein Konto gefunden werden. Du musst mindestens eine Methode einrichten, bevor du Zugriff erhältst.', 'mfa_verify_use_totp' => 'Mit einer mobilen App verifizieren', - 'mfa_verify_use_backup_codes' => 'Mit einem Backup-Code überprüfen', + 'mfa_verify_use_backup_codes' => 'Mit einem Backup-Code verifizieren', 'mfa_verify_backup_code' => 'Backup-Code', - 'mfa_verify_backup_code_desc' => 'Geben Sie einen Ihrer verbleibenden Backup-Codes unten ein:', + 'mfa_verify_backup_code_desc' => 'Gib einen deiner verbleibenden Backup-Codes unten ein:', 'mfa_verify_backup_code_enter_here' => 'Backup-Code hier eingeben', - 'mfa_verify_totp_desc' => 'Geben Sie den Code ein, der mit Ihrer mobilen App generiert wurde:', - 'mfa_setup_login_notification' => 'Multi-Faktor-Methode konfiguriert. Bitte melden Sie sich jetzt erneut mit der konfigurierten Methode an.', + 'mfa_verify_totp_desc' => 'Gib den Code ein, der mit deiner mobilen App generiert wurde:', + 'mfa_setup_login_notification' => 'Multi-Faktor-Methode konfiguriert. Bitte melde dich jetzt erneut mit der konfigurierten Methode an.', ]; diff --git a/resources/lang/de_informal/common.php b/resources/lang/de_informal/common.php index bb4c28be2..5055c399e 100644 --- a/resources/lang/de_informal/common.php +++ b/resources/lang/de_informal/common.php @@ -77,7 +77,7 @@ return [ 'status_active' => 'Aktiv', 'status_inactive' => 'Inaktiv', 'never' => 'Niemals', - 'none' => 'Nichts', + 'none' => 'Keine', // Header 'header_menu_expand' => 'Header-Menü erweitern', diff --git a/resources/lang/de_informal/editor.php b/resources/lang/de_informal/editor.php index 8551fdfb4..f136579d8 100644 --- a/resources/lang/de_informal/editor.php +++ b/resources/lang/de_informal/editor.php @@ -9,7 +9,7 @@ return [ // General editor terms 'general' => 'Allgemein', 'advanced' => 'Erweitert', - 'none' => 'Keine Auswahl', + 'none' => 'Keine', 'cancel' => 'Abbrechen', 'save' => 'Speichern', 'close' => 'Schließen', @@ -18,9 +18,9 @@ return [ 'left' => 'Links', 'center' => 'Zentriert', 'right' => 'Rechts', - 'top' => 'Nach oben', + 'top' => 'Oben', 'middle' => 'Mittig', - 'bottom' => 'Nach unten', + 'bottom' => 'Unten', 'width' => 'Breite', 'height' => 'Höhe', 'More' => 'Mehr', @@ -66,11 +66,12 @@ return [ 'insert_link_title' => 'Link einfügen/bearbeiten', 'insert_horizontal_line' => 'Horizontale Linie einfügen', 'insert_code_block' => 'Codeblock einfügen', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Zeichnung einfügen/bearbeiten', 'drawing_manager' => 'Zeichnungsmanager', 'insert_media' => 'Medien einfügen/bearbeiten', 'insert_media_title' => 'Medien einfügen/bearbeiten', - 'clear_formatting' => 'Formatierung zurücksetzen', + 'clear_formatting' => 'Formatierung löschen', 'source_code' => 'Quellcode', 'source_code_title' => 'Quellcode', 'fullscreen' => 'Vollbild', @@ -130,8 +131,8 @@ return [ 'cell_border_double' => 'Doppelt', 'cell_border_groove' => 'Rille', 'cell_border_ridge' => 'Erhaben', - 'cell_border_inset' => 'vertiefte Fläche', - 'cell_border_outset' => 'erhabene Fläche', + 'cell_border_inset' => 'Vertiefte Fläche', + 'cell_border_outset' => 'Erhabene Fläche', 'cell_border_none' => 'Keiner', 'cell_border_hidden' => 'Versteckt', @@ -139,7 +140,7 @@ return [ 'source' => 'Quelle', 'alt_desc' => 'Alternative Beschreibung', 'embed' => 'Einbetten', - 'paste_embed' => 'Fügen Sie Ihren Einbettungscode unten ein:', + 'paste_embed' => 'Füge deinen Einbettungscode unten ein:', 'url' => 'URL', 'text_to_display' => 'Anzuzeigender Text', 'title' => 'Titel', @@ -160,7 +161,7 @@ return [ 'editor_tiny_license' => 'Dieser Editor wurde mit :tinyLink erstellt, das unter der MIT-Lizenz zur Verfügung gestellt wird.', 'editor_tiny_license_link' => 'Die Copyright- und Lizenzdetails von TinyMCE findest du hier.', 'save_continue' => 'Seite speichern & fortfahren', - 'callouts_cycle' => '(Drücken Sie weiter, um durch Typen umzuschalten)', + 'callouts_cycle' => '(Drücke weiter, um durch die Typen zu schalten)', 'link_selector' => 'Inhalt verlinken', 'shortcuts' => 'Kürzel', 'shortcut' => 'Kürzel', diff --git a/resources/lang/de_informal/entities.php b/resources/lang/de_informal/entities.php index 2f1c0136c..3d8842874 100644 --- a/resources/lang/de_informal/entities.php +++ b/resources/lang/de_informal/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Berechtigungen', - 'permissions_intro' => 'Wenn benutzerdefinierte Berechtigungen aktiviert werden, überschreiben diese Einstellungen durch Rollen zugewiesene Berechtigungen.', - 'permissions_enable' => 'Benutzerdefinierte Berechtigungen aktivieren', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Berechtigungen speichern', 'permissions_owner' => 'Besitzer', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Suchergebnisse', diff --git a/resources/lang/de_informal/settings.php b/resources/lang/de_informal/settings.php index 9c4af384e..a9aefc8e2 100644 --- a/resources/lang/de_informal/settings.php +++ b/resources/lang/de_informal/settings.php @@ -92,9 +92,9 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'maint_send_test_email_mail_text' => 'Glückwunsch! Da du diese E-Mail Benachrichtigung erhalten hast, scheinen deine E-Mail-Einstellungen korrekt konfiguriert zu sein.', 'maint_recycle_bin_desc' => 'Gelöschte Regale, Bücher, Kapitel & Seiten werden in den Papierkorb verschoben, so dass sie wiederhergestellt oder dauerhaft gelöscht werden können. Ältere Einträge im Papierkorb können, in Abhängigkeit von der Systemkonfiguration, nach einer Weile automatisch entfernt werden.', 'maint_recycle_bin_open' => 'Papierkorb öffnen', - 'maint_regen_references' => 'Regenerate References', - 'maint_regen_references_desc' => 'This action will rebuild the cross-item reference index within the database. This is usually handled automatically but this action can be useful to index old content or content added via unofficial methods.', - 'maint_regen_references_success' => 'Reference index has been regenerated!', + 'maint_regen_references' => 'Verweise neu generieren', + 'maint_regen_references_desc' => 'Diese Aktion wird den Verweisindex innerhalb der Datenbank neu erstellen. Dies wird normalerweise automatisch ausgeführt, aber diese Aktion kann nützlich sein, um alte Inhalte oder Inhalte zu indizieren, die mittels inoffizieller Methoden hinzugefügt wurden.', + 'maint_regen_references_success' => 'Verweisindex wurde neu generiert!', 'maint_timeout_command_note' => 'Hinweis: Die Ausführung dieser Aktion kann einige Zeit in Anspruch nehmen, was in einigen Webumgebungen zu Timeout-Problemen führen kann. Alternativ kann diese Aktion auch mit einem Terminalbefehl ausgeführt werden.', // Recycle Bin diff --git a/resources/lang/el/activities.php b/resources/lang/el/activities.php new file mode 100644 index 000000000..d63de883e --- /dev/null +++ b/resources/lang/el/activities.php @@ -0,0 +1,73 @@ + 'σελίδα που δημιουργήθηκε', + 'page_create_notification' => 'Η σελίδα δημιουργήθηκε με επιτυχία', + 'page_update' => 'ενημερωμένη σελίδα', + 'page_update_notification' => 'Η σελίδα ενημερώθηκε με επιτυχία', + 'page_delete' => 'διαγραμμένη σελίδα', + 'page_delete_notification' => 'Η σελίδα διαγράφηκε επιτυχώς', + 'page_restore' => 'αποκατεστημένη σελίδα', + 'page_restore_notification' => 'Η σελίδα αποκαταστάθηκε με επιτυχία', + 'page_move' => 'Η σελίδα μετακινήθηκε', + + // Chapters + 'chapter_create' => 'δημιουργήθηκε κεφάλαιο', + 'chapter_create_notification' => 'Το κεφάλαιο δημιουργήθηκε με επιτυχία', + 'chapter_update' => 'ενημερωμένο κεφάλαιο', + 'chapter_update_notification' => 'Το κεφάλαιο ενημερώθηκε με επιτυχία', + 'chapter_delete' => 'διαγραμμένο κεφάλαιο', + 'chapter_delete_notification' => 'Το κεφάλαιο διαγράφηκε επιτυχώς', + 'chapter_move' => 'το κεφάλαιο μετακινήθηκε', + + // Books + 'book_create' => 'το βιβλίο δημιουργήθηκε', + 'book_create_notification' => 'Το βιβλίο δημιουργήθηκε με επιτυχία', + 'book_create_from_chapter' => 'Το κεφάλαιο μετατράπηκε επιτυχώς σε βιβλίο', + 'book_create_from_chapter_notification' => 'Το κεφάλαιο μετατράπηκε επιτυχώς σε βιβλίο', + 'book_update' => 'ενημερωμένο βιβλίο', + 'book_update_notification' => 'Το βιβλίο ενημερώθηκε με επιτυχία', + 'book_delete' => 'διαγραμμένο βιβλίο', + 'book_delete_notification' => 'Το βιβλίο διαγράφηκε επιτυχώς', + 'book_sort' => 'ταξινομημένο βιβλίο', + 'book_sort_notification' => 'Το βιβλίο επαναταξινομήθηκε επιτυχώς', + + // Bookshelves + 'bookshelf_create' => 'δημιουργήθηκε ράφι', + 'bookshelf_create_notification' => 'Το ράφι δημιουργήθηκε με επιτυχία', + 'bookshelf_create_from_book' => 'το βιβλίο μετατράπηκε σε ράφι', + 'bookshelf_create_from_book_notification' => 'Το βιβλίο μετατράπηκε σε ράφι επιτυχώς', + 'bookshelf_update' => 'ενημερωμένο ράφι', + 'bookshelf_update_notification' => 'Το ράφι ενημερώθηκε επιτυχώς', + 'bookshelf_delete' => 'διαγραμμένο ράφι', + 'bookshelf_delete_notification' => 'Το ράφι ενημερώθηκε επιτυχώς', + + // Favourites + 'favourite_add_notification' => '":name" προστέθηκε στα αγαπημένα σας', + 'favourite_remove_notification' => '":name" προστέθηκε στα αγαπημένα σας', + + // MFA + 'mfa_setup_method_notification' => 'Η μέθοδος πολλαπλών παραγόντων διαμορφώθηκε επιτυχώς', + 'mfa_remove_method_notification' => 'Η μέθοδος πολλαπλών παραγόντων καταργήθηκε με επιτυχία', + + // Webhooks + 'webhook_create' => 'Το webhook δημιουργήθηκε', + 'webhook_create_notification' => 'Το Webhook δημιουργήθηκε με επιτυχία', + 'webhook_update' => 'ενημερωμένο webhook', + 'webhook_update_notification' => 'Το Webhook ενημερώθηκε με επιτυχία', + 'webhook_delete' => 'διαγραμμένο webhook', + 'webhook_delete_notification' => 'Το Webhook διαγράφηκε επιτυχώς', + + // Users + 'user_update_notification' => 'Ο Χρήστης ενημερώθηκε με επιτυχία', + 'user_delete_notification' => 'Ο Χρήστης αφαιρέθηκε επιτυχώς', + + // Other + 'commented_on' => 'σχολίασε', + 'permissions_update' => 'ενημερωμένα δικαιώματα', +]; diff --git a/resources/lang/el/auth.php b/resources/lang/el/auth.php new file mode 100644 index 000000000..a4cd8e023 --- /dev/null +++ b/resources/lang/el/auth.php @@ -0,0 +1,115 @@ + 'Αυτά τα διαπιστευτήρια δεν ταιριάζουν με τα αρχεία μας.', + 'throttle' => 'Πάρα πολλές προσπάθειες σύνδεσης. Δοκιμάστε ξανά σε :δευτερόλεπτα.', + + // Login & Register + 'sign_up' => 'Εγγραφείτε', + 'log_in' => 'Σύνδεση', + 'log_in_with' => 'Συνδεθείτε με το :socialDriver', + 'sign_up_with' => 'Εγγραφείτε με το :socialDriver', + 'logout' => 'Αποσύνδεση', + + 'name' => 'Όνομα', + 'username' => 'Όνομα χρήστη', + 'email' => 'Email', + 'password' => 'Ο κωδικός σας', + 'password_confirm' => 'Επιβεβαιώστε τον κωδικό σας', + 'password_hint' => 'Πρέπει να αποτελείται από τουλάχιστον 8 χαρακτήρες', + 'forgot_password' => 'Ξεχάσατε τον κωδικό σας;', + 'remember_me' => 'Θυμήσου με', + 'ldap_email_hint' => 'Εισαγάγετε ένα email για χρήση για αυτόν τον λογαριασμό.', + 'create_account' => 'Δημιουργήστε λογαριασμό', + 'already_have_account' => 'Έχετε ήδη λογαριασμό;', + 'dont_have_account' => 'Δεν έχετε λογαριασμό;', + 'social_login' => 'Είσοδος με Social MEdia', + 'social_registration' => 'Εγγραφήμε Social MEdia ', + 'social_registration_text' => 'Εγγραφείτε και συνδεθείτε χρησιμοποιώντας άλλη υπηρεσία.', + + 'register_thanks' => 'Ευχαριστούμε για την εγγραφή!', + 'register_confirm' => 'Ελέγξτε το email σας και κάντε κλικ στο κουμπί επιβεβαίωσης για πρόσβαση στο :appName.', + 'registrations_disabled' => 'Οι εγγραφές είναι προς το παρόν απενεργοποιημένες', + 'registration_email_domain_invalid' => 'Αυτός ο τομέας ηλεκτρονικού ταχυδρομείου δεν έχει πρόσβαση σε αυτήν την εφαρμογή', + 'register_success' => 'Ευχαριστούμε για την εγγραφή! Είστε πλέον εγγεγραμμένοι και συνδεδεμένοι.', + + // Login auto-initiation + 'auto_init_starting' => 'Προσπάθεια Σύνδεσης', + 'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.', + 'auto_init_start_link' => 'Proceed with authentication', + + // Password Reset + 'reset_password' => 'Επαναφορά κωδικού πρόσβασης', + 'reset_password_send_instructions' => 'Εισαγάγετε τη διεύθυνση του email σας παρακάτω και θα σας σταλεί ένα μήνυμα με έναν σύνδεσμο επαναφοράς του κωδικού πρόσβασης.', + 'reset_password_send_button' => 'Αποστολή Συνδέσμου Επαναφοράς', + 'reset_password_sent' => 'Ένας σύνδεσμος επαναφοράς κωδικού πρόσβασης θα αποσταλεί στο :email εάν αυτή η διεύθυνση email βρεθεί στο σύστημα.', + 'reset_password_success' => 'Ο κωδικός πρόσβασής σας επαναφέρθηκε με επιτυχία.', + 'email_reset_subject' => 'Επαναφέρετε τον κωδικό πρόσβασης :appName', + 'email_reset_text' => 'Λαμβάνετε αυτό το μήνυμα ηλεκτρονικού ταχυδρομείου επειδή λάβαμε ένα αίτημα επαναφοράς κωδικού πρόσβασης για τον λογαριασμό σας.', + 'email_reset_not_requested' => 'Εάν δεν ζητήσατε επαναφορά του κωδικού πρόσβασης, δεν απαιτείται καμία περαιτέρω ενέργεια.', + + // Email Confirmation + 'email_confirm_subject' => 'Επιβεβαιώστε το email σας στο :appName', + 'email_confirm_greeting' => 'Ευχαριστούμε για τη συμμετοχή σας στο :appName!', + 'email_confirm_text' => 'Επιβεβαιώστε τη διεύθυνση email σας κάνοντας κλικ στο παρακάτω κουμπί:', + 'email_confirm_action' => 'Επιβεβαίωση διεύθυνσης ηλεκτρονικού ταχυδρομείου', + 'email_confirm_send_error' => 'Απαιτείται επιβεβαίωση μέσω email, αλλά το σύστημα δεν μπόρεσε να στείλει το email. Επικοινωνήστε με τον διαχειριστή για να βεβαιωθείτε ότι το email έχει ρυθμιστεί σωστά.', + 'email_confirm_success' => 'Το email σας επιβεβαιώθηκε! Θα πρέπει τώρα να μπορείτε να συνδεθείτε χρησιμοποιώντας αυτήν τη διεύθυνση email.', + 'email_confirm_resent' => 'Το email επιβεβαίωσης στάλθηκε εκ νέου. Ελέγξτε τα εισερχόμενά σας.', + + 'email_not_confirmed' => 'Η διεύθυνση email δεν επιβεβαιώθηκε', + 'email_not_confirmed_text' => 'Η διεύθυνση email σας δεν έχει ακόμη επιβεβαιωθεί.', + 'email_not_confirmed_click_link' => 'Κάντε κλικ στο σύνδεσμο στο email που στάλθηκε λίγο μετά την εγγραφή σας.', + 'email_not_confirmed_resend' => 'Εάν δεν μπορείτε να βρείτε το email, μπορείτε να στείλετε ξανά το email επιβεβαίωσης υποβάλλοντας την παρακάτω φόρμα.', + 'email_not_confirmed_resend_button' => 'Ξαναστείλτε μήνυμα επιβεβαίωσης', + + // User Invite + 'user_invite_email_subject' => 'Έχετε προσκληθεί να συμμετάσχετε :appName!', + 'user_invite_email_greeting' => 'Έχει δημιουργηθεί ένας λογαριασμός για εσάς στο :appName.', + 'user_invite_email_text' => 'Κάντε κλικ στο κουμπί παρακάτω για να ορίσετε έναν κωδικό πρόσβασης λογαριασμού και να αποκτήσετε πρόσβαση:', + 'user_invite_email_action' => 'Ορισμός κωδικού πρόσβασης λογαριασμού', + 'user_invite_page_welcome' => 'Καλωσόρισες στο :appName!', + 'user_invite_page_text' => 'Για να οριστικοποιήσετε τον λογαριασμό σας και να αποκτήσετε πρόσβαση, πρέπει να ορίσετε έναν κωδικό πρόσβασης που θα χρησιμοποιείται για να συνδεθείτε στο :appName σε μελλοντικές επισκέψεις.', + 'user_invite_page_confirm_button' => 'Επιβεβαίωση Κωδικού', + 'user_invite_success_login' => 'Ορίστηκε κωδικός πρόσβασης, θα πρέπει τώρα να μπορείτε να συνδεθείτε χρησιμοποιώντας τον καθορισμένο κωδικό πρόσβασης για να αποκτήσετε πρόσβαση στο :appName!', + + // Multi-factor Authentication + 'mfa_setup' => 'Ρύθμιση ελέγχου ταυτότητας πολλαπλών παραγόντων', + 'mfa_setup_desc' => 'Ρυθμίστε τον έλεγχο ταυτότητας πολλαπλών παραγόντων ως ένα επιπλέον επίπεδο ασφάλειας για τον λογαριασμό χρήστη σας.', + 'mfa_setup_configured' => 'Έχει ήδη διαμορφωθεί', + 'mfa_setup_reconfigure' => 'Επαναδιαμόρφωση', + 'mfa_setup_remove_confirmation' => 'Είστε βέβαιοι ότι θέλετε να καταργήσετε αυτήν τη μέθοδο ελέγχου ταυτότητας πολλαπλών παραγόντων;', + 'mfa_setup_action' => 'Ρύθμιση', + 'mfa_backup_codes_usage_limit_warning' => 'Έχετε λιγότερους από 5 εφεδρικούς κωδικούς που απομένουν. Δημιουργήστε και αποθηκεύστε ένα νέο σύνολο προτού εξαντληθούν οι κωδικοί για να αποφύγετε τον αποκλεισμό του λογαριασμού σας.', + 'mfa_option_totp_title' => 'Εφαρμογή για κινητό', + 'mfa_option_totp_desc' => 'Για να χρησιμοποιήσετε τον έλεγχο ταυτότητας πολλαπλών παραγόντων, θα χρειαστείτε μια εφαρμογή για κινητά που υποστηρίζει TOTP, όπως το Google Authenticator, το Authy ή το Microsoft Authenticator.', + 'mfa_option_backup_codes_title' => 'Εφεδρικοί κωδικοί', + 'mfa_option_backup_codes_desc' => 'Αποθηκεύστε με ασφάλεια ένα σύνολο εφεδρικών κωδικών μίας χρήσης τους οποίους μπορείτε να εισαγάγετε για να επαληθεύσετε την ταυτότητά σας.', + 'mfa_gen_confirm_and_enable' => 'Επιβεβαίωση και ενεργοποίηση', + 'mfa_gen_backup_codes_title' => 'Ρύθμιση εφεδρικών κωδικών', + 'mfa_gen_backup_codes_desc' => 'Αποθηκεύστε την παρακάτω λίστα κωδικών σε ασφαλές μέρος. Κατά την πρόσβαση στο σύστημα, θα μπορείτε να χρησιμοποιήσετε έναν από τους κωδικούς ως δεύτερο μηχανισμό ελέγχου ταυτότητας.', + 'mfa_gen_backup_codes_download' => 'Λήψη κωδικών', + 'mfa_gen_backup_codes_usage_warning' => 'Κάθε κωδικός μπορεί να χρησιμοποιηθεί μόνο μία φορά', + 'mfa_gen_totp_title' => 'Ρύθμιση εφαρμογής για κινητά', + 'mfa_gen_totp_desc' => 'Για να χρησιμοποιήσετε τον έλεγχο ταυτότητας πολλαπλών παραγόντων, θα χρειαστείτε μια εφαρμογή για κινητά που υποστηρίζει TOTP, όπως το Google Authenticator, το Authy ή το Microsoft Authenticator.', + 'mfa_gen_totp_scan' => 'Σαρώστε τον παρακάτω κωδικό QR χρησιμοποιώντας την προτιμώμενη εφαρμογή ελέγχου ταυτότητας για να ξεκινήσετε.', + 'mfa_gen_totp_verify_setup' => 'Επαληθεύστε τη ρύθμιση', + 'mfa_gen_totp_verify_setup_desc' => 'Επαληθεύστε ότι όλα λειτουργούν εισάγοντας έναν κωδικό, που δημιουργήθηκε στην εφαρμογή ελέγχου ταυτότητας, στο παρακάτω πλαίσιο εισαγωγής:', + 'mfa_gen_totp_provide_code_here' => 'Εισάγετε τον κώδικα που δημιουργήθηκε από την εφαρμογή σας εδώ', + 'mfa_verify_access' => 'Επαλήθευση πρόσβασης', + 'mfa_verify_access_desc' => 'Ο λογαριασμός σας απαιτεί να επιβεβαιώσετε την ταυτότητά σας μέσω ενός πρόσθετου επιπέδου επαλήθευσης προτού σας παραχωρηθεί πρόσβαση. Επαληθεύστε χρησιμοποιώντας μία από τις διαμορφωμένες μεθόδους σας για να συνεχίσετε.', + 'mfa_verify_no_methods' => 'Δεν έχουν διαμορφωθεί μέθοδοι.', + 'mfa_verify_no_methods_desc' => 'Δεν βρέθηκαν μέθοδοι ελέγχου ταυτότητας πολλαπλών παραγόντων για τον λογαριασμό σας. Θα χρειαστεί να ρυθμίσετε τουλάχιστον μία μέθοδο προτού αποκτήσετε πρόσβαση.', + 'mfa_verify_use_totp' => 'Επαληθεύστε χρησιμοποιώντας μια εφαρμογή για κινητά', + 'mfa_verify_use_backup_codes' => 'Επαληθεύστε χρησιμοποιώντας έναν εφεδρικό κωδικό', + 'mfa_verify_backup_code' => 'Εφεδρικός κωδικός', + 'mfa_verify_backup_code_desc' => 'Εισαγάγετε έναν από τους υπόλοιπους εφεδρικούς κωδικούς σας παρακάτω:', + 'mfa_verify_backup_code_enter_here' => 'Εισαγάγετε τον εφεδρικό κωδικό εδώ:', + 'mfa_verify_totp_desc' => 'Εισαγάγετε τον κωδικό, που δημιουργήθηκε χρησιμοποιώντας την εφαρμογή σας για κινητά, παρακάτω:', + 'mfa_setup_login_notification' => 'Η μέθοδος πολλαπλών παραγόντων έχει διαμορφωθεί. Συνδεθείτε ξανά χρησιμοποιώντας τη ρυθμισμένη μέθοδο.', +]; diff --git a/resources/lang/el/common.php b/resources/lang/el/common.php new file mode 100644 index 000000000..9837e53f0 --- /dev/null +++ b/resources/lang/el/common.php @@ -0,0 +1,104 @@ + 'Ακύρωση', + 'confirm' => 'Οκ', + 'back' => 'Πίσω', + 'save' => 'Αποθήκευση', + 'continue' => 'Συνέχεια', + 'select' => 'Επιλογή', + 'toggle_all' => 'Εναλλαγή όλων', + 'more' => 'Περισσότερα..', + + // Form Labels + 'name' => 'Όνομα', + 'description' => 'Περιγραφή', + 'role' => 'Ρόλος', + 'cover_image' => 'Εικόνα εξώφυλλου', + 'cover_image_description' => 'Αυτή η εικόνα πρέπει να είναι περίπου 440x250px.', + + // Actions + 'actions' => 'Ενέργειες', + 'view' => 'Προβολή', + 'view_all' => 'Προβολή όλων', + 'create' => 'Δημιουργία', + 'update' => 'Ενημέρωση', + 'edit' => 'Επεξεργασία', + 'sort' => 'Ταξινόμηση', + 'move' => 'Μετακίνηση', + 'copy' => 'Αντιγραφή', + 'reply' => 'Απάντηση', + 'delete' => 'Διαγραφή', + 'delete_confirm' => 'Επιβεβαίωση Διαγραφής', + 'search' => 'Αναζήτηση', + 'search_clear' => 'Εκκαθάριση Αναζήτησης', + 'reset' => 'Επαναφορά', + 'remove' => 'Αφαίρεση', + 'add' => 'Προσθήκη', + 'configure' => 'Διαμόρφωση', + 'fullscreen' => 'Πλήρης οθόνη', + 'favourite' => 'Αγαπημένα', + 'unfavourite' => 'Αφαίρεση από Αγαπημένα', + 'next' => 'Επόμενη', + 'previous' => 'Προηγούμενη', + 'filter_active' => 'Ενεργό φίλτρο:', + 'filter_clear' => 'Διαγραφή φίλτρου', + 'download' => 'Λήψη', + 'open_in_tab' => 'Άνοιγμα σε Καρτέλα', + + // Sort Options + 'sort_options' => 'Επιλογές ταξινόμησης', + 'sort_direction_toggle' => 'Εναλλαγή κατεύθυνσης ταξινόμησης', + 'sort_ascending' => 'Αύξουσα ταξινόμηση', + 'sort_descending' => 'Ταξινόμηση Φθίνουσα', + 'sort_name' => 'Ονομα', + 'sort_default' => 'Προεπιλογή', + 'sort_created_at' => 'Δημιουργήθηκε', + 'sort_updated_at' => 'Ενημερώθηκε', + + // Misc + 'deleted_user' => 'Διαγραμμένος χρήστης', + 'no_activity' => 'Δεν υπάρχει δραστηριότητα προς εμφάνιση', + 'no_items' => 'Δεν υπάρχουν διαθέσιμα στοιχεία', + 'back_to_top' => 'Επιστροφή στην κορυφή', + 'skip_to_main_content' => 'Μετάβαση στο κύριο περιεχόμενο', + 'toggle_details' => 'Εναλλαγή λεπτομερειών', + 'toggle_thumbnails' => 'Εναλλαγή μικρογραφιών', + 'details' => 'Λεπτομέριες', + 'grid_view' => 'Προβολή σε πλέγμα', + 'list_view' => 'Προβολή σε λίστα', + 'default' => 'Προκαθορισμένο', + 'breadcrumb' => 'Μπάρα πλοήγησης', + 'status' => 'Κατάσταση', + 'status_active' => 'Ενεργός', + 'status_inactive' => 'Αδρανής', + 'never' => 'Ποτέ', + 'none' => 'Κανένας', + + // Header + 'header_menu_expand' => 'Αναπτύξτε το Head Menu', + 'profile_menu' => 'Μενού Προφίλ', + 'view_profile' => 'Προβολή προφίλ', + 'edit_profile' => 'Επεξεργασία προφίλ', + 'dark_mode' => 'Σκουρόχρωμη εμφάνιση', + 'light_mode' => 'Ανοιχτόχρωμη εμφάνιση', + + // Layout tabs + 'tab_info' => 'Πληροφορίες', + 'tab_info_label' => 'Καρτέλα: Εμφάνιση δευτερευουσών πληροφοριών', + 'tab_content' => 'Περιεχόμενο', + 'tab_content_label' => 'Καρτέλα: Εμφάνιση κύριου περιεχομένου', + + // Email Content + 'email_action_help' => 'Εάν αντιμετωπίζετε πρόβλημα κάνοντας κλικ στο κουμπί ":actionText", αντιγράψτε και επικολλήστε την παρακάτω διεύθυνση URL στο πρόγραμμα περιήγησής σας στον ιστό:', + 'email_rights' => 'Ολα τα πνευματικά δικαιώματα διατηρούνται', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Πολιτική Απορρήτου', + 'terms_of_service' => 'Όροι χρήσης', +]; diff --git a/resources/lang/el/components.php b/resources/lang/el/components.php new file mode 100644 index 000000000..c59e93add --- /dev/null +++ b/resources/lang/el/components.php @@ -0,0 +1,34 @@ + 'Επιλογή εικόνας', + 'image_all' => 'Όλες', + 'image_all_title' => 'Δείτε όλες τις εικόνες που υπάρχουν στο Server', + 'image_book_title' => 'Προβολή εικόνων που έχουν μεταφορτωθεί σε αυτό το βιβλίο', + 'image_page_title' => 'Προβολή εικόνων που έχουν δημοσιευτεί σε αυτήν τη σελίδα', + 'image_search_hint' => 'Αναζήτηση με όνομα εικόνας', + 'image_uploaded' => 'Μεταφορτώθηκε :uploadedDate', + 'image_load_more' => 'Φόρτωσε περισσότερα', + 'image_image_name' => 'Όνομα εικόνας', + 'image_delete_used' => 'Αυτή η εικόνα χρησιμοποιείται στις παρακάτω σελίδες.', + 'image_delete_confirm_text' => 'Είστε σίγουροι ότι θέλετε να διαγράψετε αυτήν την εικόνα;', + 'image_select_image' => 'Επιλέξτε Εικόνα', + 'image_dropzone' => 'Σύρτε ή κάντε κλικ εδώ για μεταφόρτωση εικόνων', + 'images_deleted' => 'Οι εικόνες διαγράφηκαν', + 'image_preview' => 'Προεπισκόπηση εικόνας', + 'image_upload_success' => 'Η εικόνα μεταφορτώθηκε με επιτυχία', + 'image_update_success' => 'Τα στοιχεία της εικόνας ενημερώθηκαν με επιτυχία', + 'image_delete_success' => 'Η εικόνα διαγράφηκε επιτυχώς', + 'image_upload_remove' => 'Αφαίρεση', + + // Code Editor + 'code_editor' => 'Επεξεργασία κώδικα', + 'code_language' => 'Γλώσσα κώδικα', + 'code_content' => 'Περιεχόμενο κώδικα', + 'code_session_history' => 'Ιστορικό συνεδρίας', + 'code_save' => 'Αποθήκευση Κώδικα', +]; diff --git a/resources/lang/el/editor.php b/resources/lang/el/editor.php new file mode 100644 index 000000000..0f9489e8b --- /dev/null +++ b/resources/lang/el/editor.php @@ -0,0 +1,172 @@ + 'Γενικά', + 'advanced' => 'Για Προχωρημένους', + 'none' => 'None', + 'cancel' => 'Ακύρωση', + 'save' => 'Αποθήκευση', + 'close' => 'Κλείσιμο', + 'undo' => 'Αναίρεση', + 'redo' => 'Επανάληψη', + 'left' => 'Αριστερά', + 'center' => 'Κέντρο', + 'right' => 'Δεξιά', + 'top' => 'Πάνω', + 'middle' => 'Κέντρο', + 'bottom' => 'Κάτω', + 'width' => 'Πλάτος', + 'height' => 'Ύψος', + 'More' => 'Περισσότερα', + 'select' => 'Επιλέξτε...', + + // Toolbar + 'formats' => 'Μορφοποίηση', + 'header_large' => 'Μεγάλη κεφαλίδα', + 'header_medium' => 'Μεσαία κεφαλίδα', + 'header_small' => 'Μικρή κεφαλίδα', + 'header_tiny' => 'Μικροσκοπική κεφαλίδα', + 'paragraph' => 'Παράγραφος', + 'blockquote' => 'Blockquote', + 'inline_code' => 'Ενσωματωμένος κωδικός', + 'callouts' => 'Επεξηγήσεις', + 'callout_information' => 'Πληροφορίες', + 'callout_success' => 'Επιτυχία', + 'callout_warning' => 'Προειδοποίηση', + 'callout_danger' => 'Κίνδυνος', + 'bold' => 'Έντονη γραφή', + 'italic' => 'Πλάγια γραφή', + 'underline' => 'Υπογράμμιση', + 'strikethrough' => 'Διακριτή διαγραφή', + 'superscript' => 'Εκθέτης', + 'subscript' => 'Δείκτης', + 'text_color' => 'Χρώμα κειμένου', + 'custom_color' => 'Προσαρμογή χρώματος', + 'remove_color' => 'Αφαίρεση χρώματος', + 'background_color' => 'Χρώμα φόντου', + 'align_left' => 'Στοίχιση αριστερά', + 'align_center' => 'Στοίχιση κέντρο', + 'align_right' => 'Στοίχιση δεξιά', + 'align_justify' => 'Πλήρης στοίχιση', + 'list_bullet' => 'Λίστα με κουκκίδες', + 'list_numbered' => 'Λίστα με αρίθμηση', + 'list_task' => 'Λίστα εργασιών', + 'indent_increase' => 'Αύξηση εσοχήςt', + 'indent_decrease' => 'Μείωση εσοχής', + 'table' => 'Πίνακας', + 'insert_image' => 'Εισαγωγή εικόνας', + 'insert_image_title' => 'Εισαγωγή/Επεξεργασία εικόνας', + 'insert_link' => 'Εισαγωγή/επεξεργασία συνδέσμου', + 'insert_link_title' => 'Εισαγωγή/Επεξεργασία συνδέσμου', + 'insert_horizontal_line' => 'Εισαγωγή οριζόντιας γραμμής', + 'insert_code_block' => 'Εισαγωγή μπλοκ κώδικα', + 'edit_code_block' => 'Edit code block', + 'insert_drawing' => 'Εισαγωγή/Επεξεργασία σχεδίου', + 'drawing_manager' => 'Διαχειριστής σχεδίασης', + 'insert_media' => 'Εισαγωγή/Επεξεργασία πολυμέσων', + 'insert_media_title' => 'Εισαγωγή/Επεξεργασία πολυμέσων', + 'clear_formatting' => 'Διαγραφή μορφοποίησης', + 'source_code' => 'Πηγαίος κώδικας', + 'source_code_title' => 'Πηγαίος κώδικας', + 'fullscreen' => 'Πλήρης οθόνη', + 'image_options' => 'Επιλογές εικόνας', + + // Tables + 'table_properties' => 'Ιδιότητες πίνακα', + 'table_properties_title' => 'Ιδιότητες πίνακα', + 'delete_table' => 'Διαγραφή πίνακα', + 'insert_row_before' => 'Εισαγωγή γραμμής πάνω', + 'insert_row_after' => 'Εισαγωγή γραμμής κάτω', + 'delete_row' => 'Διαγραφή γραμμής', + 'insert_column_before' => 'Εισαγωγή στήλης αριστερά', + 'insert_column_after' => 'Εισαγωγή στήλης δεξιά', + 'delete_column' => 'Διαγραφή στήλης', + 'table_cell' => 'Κελί', + 'table_row' => 'Γραμμή', + 'table_column' => 'Στήλη', + 'cell_properties' => 'Ιδιότητες κελιού', + 'cell_properties_title' => 'Ιδιότητες κελιού', + 'cell_type' => 'Τύπος κελιού', + 'cell_type_cell' => 'Κελί', + 'cell_scope' => 'Scope', + 'cell_type_header' => 'Κεφαλίδα κελιού', + 'merge_cells' => 'Συγχώνευση κελιών', + 'split_cell' => 'Διαίρεση κελιού', + 'table_row_group' => 'Ομάδα γραμμών', + 'table_column_group' => 'Ομάδα στηλών', + 'horizontal_align' => 'Οριζόντια στοίχιση', + 'vertical_align' => 'Κάθετη στοίχιση', + 'border_width' => 'Πάχος περιγράμματος', + 'border_style' => 'Στυλ περιγράμματος', + 'border_color' => 'Χρώμα περιγράμματος', + 'row_properties' => 'Ιδιότητες γραμμής', + 'row_properties_title' => 'Ιδιότητες γραμμής', + 'cut_row' => 'Αποκοπή γραμμής', + 'copy_row' => 'Αντιγραφή γραμμής', + 'paste_row_before' => 'Επικόλληση γραμμής πάνω', + 'paste_row_after' => 'Επικόλληση γραμμής κάτω', + 'row_type' => 'Τύπος γραμμής', + 'row_type_header' => 'Κεφαλίδα', + 'row_type_body' => 'Σώμα', + 'row_type_footer' => 'Υποσέλιδο', + 'alignment' => 'Ευθυγράμμιση', + 'cut_column' => 'Αποκοπή στήλης', + 'copy_column' => 'Αντιγραφή στήλης', + 'paste_column_before' => 'Επικόλληση στήλης αριστερά', + 'paste_column_after' => 'Επικόλληση στήλης δεξιά', + 'cell_padding' => 'Περιθώριο κελιών', + 'cell_spacing' => 'Απόσταση κελιών', + 'caption' => 'Τίτλος', + 'show_caption' => 'Εμφάνιση Τίτλου', + 'constrain' => 'Περιορισμός αναλογιών', + 'cell_border_solid' => 'Συμπαγής γραμμή', + 'cell_border_dotted' => 'Γραμμή με κουκκίδες', + 'cell_border_dashed' => 'Διακεκομμένη γραμμή', + 'cell_border_double' => 'Διπλή γραμμή', + 'cell_border_groove' => 'Groove', + 'cell_border_ridge' => 'Κορυφογραμμή', + 'cell_border_inset' => 'Inset', + 'cell_border_outset' => 'Outset', + 'cell_border_none' => 'Χωρίς', + 'cell_border_hidden' => '΄Διαφανές', + + // Images, links, details/summary & embed + 'source' => 'Source', + 'alt_desc' => 'Εναλλακτική περιγραφή', + 'embed' => 'Ενσωματωμένο', + 'paste_embed' => 'Επικολλήστε τον κώδικα ενσωμάτωσης παρακάτω:', + 'url' => 'URL', + 'text_to_display' => 'Κείμενο εμφάνισης', + 'title' => 'Τίτλος', + 'open_link' => 'Άνοιγμα συνδέσμου σε...', + 'open_link_current' => 'Τρέχον παράθυρο', + 'open_link_new' => 'Νέο παράθυρο', + 'insert_collapsible' => 'Εισαγωγή πτυσσόμενου μπλοκ', + 'collapsible_unwrap' => 'Μετατροπή πτυσσόμενου μπλοκ σε παράγραφο', + 'edit_label' => 'Επεξεργασία ετικέτας', + 'toggle_open_closed' => 'Εναλλαγή ανοίγματος/κλεισίματος', + 'collapsible_edit' => 'Επεξεργασία πτυσσόμενου μπλοκ', + 'toggle_label' => 'Εναλλαγή ετικέτας', + + // About view + 'about' => 'Σχετικά', + 'about_title' => 'Σχετικά με τον επεξεργαστή WYSIWYG', + 'editor_license' => 'Άδεια εκδότη και πνευματικά δικαιώματα', + 'editor_tiny_license' => 'Αυτός ο επεξεργαστής έχει δημιουργηθεί χρησιμοποιώντας :tinyLink που παρέχεται με την άδεια MIT.', + 'editor_tiny_license_link' => 'Τα πνευματικά δικαιώματα και τα στοιχεία άδειας χρήσης του TinyMCE μπορείτε να τα βρείτε εδώ.', + 'save_continue' => 'Αποθήκευση σελίδας & Συνέχεια', + 'callouts_cycle' => '(Συνεχίστε να πατάτε για εναλλαγή μεταξύ τύπων)', + 'link_selector' => 'Σύνδεσμος προς το περιεχόμενο', + 'shortcuts' => 'Συντομεύσεις', + 'shortcut' => 'Συντόμευση', + 'shortcuts_intro' => 'Οι ακόλουθες συντομεύσεις είναι διαθέσιμες στο πρόγραμμα επεξεργασίας:', + 'windows_linux' => '(Windows/Linux)', + 'mac' => '(Mac)', + 'description' => 'Περιγραφή', +]; diff --git a/resources/lang/el/entities.php b/resources/lang/el/entities.php new file mode 100644 index 000000000..f9f4aef70 --- /dev/null +++ b/resources/lang/el/entities.php @@ -0,0 +1,382 @@ + 'Δημιουργήθηκε Πρόσφατα', + 'recently_created_pages' => 'Πρόσφατα Δημιουργημένες Σελίδες', + 'recently_updated_pages' => 'Πρόσφατες Ενημερώσεις', + 'recently_created_chapters' => 'Πρόσφατα Δημιουργημένα Κεφάλαια', + 'recently_created_books' => 'Πρόσφατα Δημιουργημένα Βιβλία', + 'recently_created_shelves' => 'Πρόσφατα Δημιουργημένα Ράφια', + 'recently_update' => 'Ενημερώθηκε πρόσφατα', + 'recently_viewed' => 'Πρόσφατα προβεβλημένα', + 'recent_activity' => 'Πρόσφατη Δραστηριότητα', + 'create_now' => 'Δημιουργία ενός τώρα', + 'revisions' => 'Αναθεωρήσεις', + 'meta_revision' => 'Αναθεώρηση #:revisionCount', + 'meta_created' => 'Δημιουργήθηκε :timeLength', + 'meta_created_name' => 'Δημιουργήθηκε :timeLength by :user', + 'meta_updated' => 'Ενημερώθηκε :timeLength', + 'meta_updated_name' => 'Ενημερώθηκε :timeLength by :user', + 'meta_owned_name' => 'Ανήκει στον :user', + 'meta_reference_page_count' => 'Αναφορά σε 1 σελίδα"Αναφερόμενη στο :count σελίδες', + 'entity_select' => 'Επιλογή Οντότητας', + 'entity_select_lack_permission' => 'Δεν έχετε τα απαιτούμενα δικαιώματα για να επιλέξετε αυτό το στοιχείο', + 'images' => 'Εικόνες', + 'my_recent_drafts' => 'Τα πρόσφατα προσχέδιά μου', + 'my_recently_viewed' => 'Είδα πρόσφατα', + 'my_most_viewed_favourites' => 'Συχνά Αγαπημένα', + 'my_favourites' => 'Τα αγαπημένα μου', + 'no_pages_viewed' => 'Δεν έχετε δει καμία σελίδα', + 'no_pages_recently_created' => 'Δεν έχουν δημιουργηθεί πρόσφατα σελίδες', + 'no_pages_recently_updated' => 'Δεν υπάρχουν πρόσφατα ενημερώσεις σελίδων', + 'export' => 'Εξαγωγή', + 'export_html' => 'Αρχείο Web', + 'export_pdf' => 'Αρχείο PDF', + 'export_text' => 'Αρχείο Απλού κειμένου', + 'export_md' => 'Αρχείο Markdown', + + // Permissions and restrictions + 'permissions' => 'Δικαιώματα', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', + 'permissions_save' => 'Αποθήκευση Δικαιωμάτων', + 'permissions_owner' => 'Ιδιοκτήτης / Κάτοχος', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', + + // Search + 'search_results' => 'Αποτελέσματα αναζήτησης', + 'search_total_results_found' => ':count αποτέλεσμα που βρέθηκε:count συνολικά αποτελέσματα που βρέθηκαν', + 'search_clear' => 'Καθαρισμός αναζήτησης', + 'search_no_pages' => 'Καμία σελίδα δεν ταιριάζει με αυτήν την αναζήτηση', + 'search_for_term' => 'Αναζήτηση για :term', + 'search_more' => 'Περισσότερα αποτελέσματα', + 'search_advanced' => 'Προχωρημένη Αναζήτηση', + 'search_terms' => 'Αναζήτηση Όρων', + 'search_content_type' => 'Τύπος περιεχομένου', + 'search_exact_matches' => 'Ακριβείς αντιστοιχίες', + 'search_tags' => 'Αναζητήσεις Ετικετών', + 'search_options' => 'Επιλογές', + 'search_viewed_by_me' => 'Προβλήθηκε από μένα', + 'search_not_viewed_by_me' => 'Δεν προβλήθηκε από εμένα', + 'search_permissions_set' => 'Τα δικαιώματα ορίστηκαν', + 'search_created_by_me' => 'Δημιουργήθηκε από εμένα', + 'search_updated_by_me' => 'Ενημερώθηκε από εμένα', + 'search_owned_by_me' => 'Ανήκει σε μένα', + 'search_date_options' => 'Επιλογές Ημερομηνίας', + 'search_updated_before' => 'Ενημερώθηκε πριν', + 'search_updated_after' => 'Ενημερώθηκε μετά', + 'search_created_before' => 'Δημιουργήθηκε πριν', + 'search_created_after' => 'Δημιουργήθηκε μετά', + 'search_set_date' => 'Ορισμός Ημερομηνίας', + 'search_update' => 'Ενημέρωση Αναζήτησης', + + // Shelves + 'shelf' => 'Ράφι', + 'shelves' => 'Ράφια', + 'x_shelves' => ':count Ράφι|:count Ράφια', + 'shelves_empty' => 'Δεν έχουν δημιουργηθεί ράφια', + 'shelves_create' => 'Δημιουργία νέου ραφιού', + 'shelves_popular' => 'Δημοφιλή Ράφια', + 'shelves_new' => 'Νέα Ράφια', + 'shelves_new_action' => 'Νέο Ράφι', + 'shelves_popular_empty' => 'Τα πιο δημοφιλή ράφια θα εμφανιστούν εδώ.', + 'shelves_new_empty' => 'Τα πιο πρόσφατα ράφια που δημιουργήθηκαν θα εμφανιστούν εδώ.', + 'shelves_save' => 'Αποθήκευση Ραφιού', + 'shelves_books' => 'Βιβλία σε αυτό το Ράφι', + 'shelves_add_books' => 'Διαθέσιμα Βιβλία, για προσθήκη στο Ράφι', + 'shelves_drag_books' => 'Σύρετε εδώ βιβλία της διπλανή λίστας, για να τα προσθέσετε στο Ράφι', + 'shelves_empty_contents' => 'Σε αυτό το Ράφι δεν έχουν εκχωρηθεί βιβλία', + 'shelves_edit_and_assign' => 'Επεξεργαστείτε το Ράφι για να εκχωρήσετε βιβλία', + 'shelves_edit_named' => 'Επεξεργασία Ραφιού :name', + 'shelves_edit' => 'Επεξεργασία Ραφιού', + 'shelves_delete' => 'Διαγραφή Ραφιού', + 'shelves_delete_named' => 'Delete Bookshelf :name', + 'shelves_delete_explain' => "This will delete the bookshelf with the name ':name'. Contained books will not be deleted.", + 'shelves_delete_confirmation' => 'Are you sure you want to delete this bookshelf?', + 'shelves_permissions' => 'Bookshelf Permissions', + 'shelves_permissions_updated' => 'Bookshelf Permissions Updated', + 'shelves_permissions_active' => 'Bookshelf Permissions Active', + 'shelves_permissions_cascade_warning' => 'Permissions on bookshelves do not automatically cascade to contained books. This is because a book can exist on multiple shelves. Permissions can however be copied down to child books using the option found below.', + 'shelves_copy_permissions_to_books' => 'Αντιγραφή δικαιωμάτων στα βιβλία', + 'shelves_copy_permissions' => 'Αντιγραφή Δικαιωμάτων', + 'shelves_copy_permissions_explain' => 'This will apply the current permission settings of this bookshelf to all books contained within. Before activating, ensure any changes to the permissions of this bookshelf have been saved.', + 'shelves_copy_permission_success' => 'Bookshelf permissions copied to :count books', + + // Books + 'book' => 'Βιβλίο', + 'books' => 'Βιβλία', + 'x_books' => ':count Βιβλίο|:count Βιβλία', + 'books_empty' => 'Δεν έχουν δημιουργηθεί βιβλία ακόμα', + 'books_popular' => 'Δημοφιλή Βιβλία', + 'books_recent' => 'Πρόσφατα Βιβλία', + 'books_new' => 'Νέα Βιβλία', + 'books_new_action' => 'Νέο βιβλίο', + 'books_popular_empty' => 'Τα πιο δημοφιλή εμφανίζονται εδώ.', + 'books_new_empty' => 'Θα εμφανιστούν εδώ, αυτά που δημιουργήθηκαν πιο πρόσφατα.', + 'books_create' => 'Δημιουργία νέου βιβλίου', + 'books_delete' => 'Διαγραφή Βιβλίου', + 'books_delete_named' => 'Διαγραφή Βιβλίου :bookname', + 'books_delete_explain' => 'Αυτό θα διαγράψει το βιβλίο με το όνομα \':bookName\'. Όλες οι σελίδες και τα κεφάλαια θα αφαιρεθούν.', + 'books_delete_confirmation' => 'Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτό το βιβλίο;', + 'books_edit' => 'Επεξεργασία Βιβλίου', + 'books_edit_named' => 'Επεξεργασία Βιβλίου :bookname', + 'books_form_book_name' => 'Όνομα Βιβλίου', + 'books_save' => 'Αποθήκευση Βιβλίου', + 'books_permissions' => 'Άδειες Βιβλίου', + 'books_permissions_updated' => 'Τα Δικαιώματα Βιβλίου Ενημερώθηκαν', + 'books_empty_contents' => 'Δεν έχουν δημιουργηθεί σελίδες ή κεφάλαια για αυτό το βιβλίο.', + 'books_empty_create_page' => 'Δημιουργία νέας σελίδας', + 'books_empty_sort_current_book' => 'Ταξινόμηση του τρέχοντος βιβλίου', + 'books_empty_add_chapter' => 'Προσθήκη κεφαλαίου', + 'books_permissions_active' => 'Ενεργά Δικαιώματα ´Βιβλίου', + 'books_search_this' => 'Αναζήτηση σε αυτό το βιβλίο', + 'books_navigation' => 'Πλοήγηση Βιβλίου', + 'books_sort' => 'Ταξινόμηση Περιεχομένων Βιβλίου', + 'books_sort_named' => 'Ταξινόμηση Βιβλίου :bookname', + 'books_sort_name' => 'Ταξινόμηση κατά όνομα', + 'books_sort_created' => 'Ταξινόμηση κατά ημερομηνία δημιουργίας', + 'books_sort_updated' => 'Ταξινόμηση κατά ημερομηνία ενημέρωσης', + 'books_sort_chapters_first' => 'Τα Κεφάλαια Πρώτα', + 'books_sort_chapters_last' => 'Τελευταία Κεφάλαια', + 'books_sort_show_other' => 'Εμφάνιση Άλλων Βιβλίων', + 'books_sort_save' => 'Αποθήκευση Νέας Ταξινόμησης', + 'books_copy' => 'Αντιγραφή Βιβλίου', + 'books_copy_success' => 'Το βιβλίο αντιγράφηκε επιτυχώς', + + // Chapters + 'chapter' => 'Κεφάλαιο', + 'chapters' => 'Κεφάλαια', + 'x_chapters' => ':count Κεφάλαιο:count Κεφάλαια', + 'chapters_popular' => 'Δημοφιλή Κεφάλαια', + 'chapters_new' => 'Νέο Κεφάλαιο', + 'chapters_create' => 'Δημιουργία Νέου Κεφαλαίου', + 'chapters_delete' => 'Διαγραφή Κεφαλαίου', + 'chapters_delete_named' => 'Διαγραφή Κεφαλαίου :chapterName', + 'chapters_delete_explain' => 'Αυτό θα διαγράψει το κεφάλαιο με το όνομα \':chapterName\'. Όλες οι σελίδες που υπάρχουν μέσα σε αυτό το κεφάλαιο θα διαγραφούν επίσης.', + 'chapters_delete_confirm' => 'Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτό το κεφάλαιο;', + 'chapters_edit' => 'Επεξεργασία Κεφαλαίου', + 'chapters_edit_named' => 'Επεξεργασία Κεφαλαίου :chapterName', + 'chapters_save' => 'Αποθήκευση Κεφαλαίου', + 'chapters_move' => 'Μετακίνηση Κεφαλαίου', + 'chapters_move_named' => 'Μετακίνηση Κεφαλαίου :chapterName', + 'chapter_move_success' => 'Το κεφάλαιο μεταφέρθηκε στο:bookName', + 'chapters_copy' => 'Αντιγραφή Κεφαλαίου', + 'chapters_copy_success' => 'Το κεφάλαιο αντιγράφηκε επιτυχώς', + 'chapters_permissions' => 'Δικαιώματα Κεφαλαίου', + 'chapters_empty' => 'Καμία σελίδα δεν βρίσκεται σε αυτό το κεφάλαιο.', + 'chapters_permissions_active' => 'Ενεργά Δικαιώματα Κεφαλαίου', + 'chapters_permissions_success' => 'Τα Δικαιώματα Κεφαλαίου Ενημερώθηκαν', + 'chapters_search_this' => 'Αναζήτηση σε αυτό το κεφάλαιο', + 'chapter_sort_book' => 'Ταξινόμηση Βιβλίου', + + // Pages + 'page' => 'Σελίδα', + 'pages' => 'Σελίδες', + 'x_pages' => ':count Σελίδα:count Σελίδες', + 'pages_popular' => 'Δημοφιλείς Σελίδες', + 'pages_new' => 'Νέα Σελίδα', + 'pages_attachments' => 'Συνημμένα', + 'pages_navigation' => 'Πλοήγηση στη σελίδα', + 'pages_delete' => 'Διαγραφή Σελίδας', + 'pages_delete_named' => 'Διαγραφή Σελίδας :pageName', + 'pages_delete_draft_named' => 'Διαγραφή Προσχέδιας Σελίδας :pageName', + 'pages_delete_draft' => 'Διαγραφή Προσχέδιας Σελίδας', + 'pages_delete_success' => 'Η σελίδα διαγράφηκε', + 'pages_delete_draft_success' => 'Η προσχέδια (πρόχειρη) σελίδα διαγράφηκε', + 'pages_delete_confirm' => 'Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτή τη σελίδα;', + 'pages_delete_draft_confirm' => 'Θέλετε σίγουρα να διαγράψετε την προσχέδια σελίδα;', + 'pages_editing_named' => 'Επεξεργασία Σελίδας :pageName', + 'pages_edit_draft_options' => 'Επιλογές Προσχεδίου', + 'pages_edit_save_draft' => 'Αποθήκευση Προχείρου (Προσχεδίου)', + 'pages_edit_draft' => 'Επεξεργασία Προσχεδίου Σελίδας', + 'pages_editing_draft' => 'Επεξεργασία Προσχεδίου', + 'pages_editing_page' => 'Επεξεργασία Σελίδας', + 'pages_edit_draft_save_at' => 'Το προσχέδιο αποθηκεύτηκε στις ', + 'pages_edit_delete_draft' => 'Διαγραφή Προσχεδίου', + 'pages_edit_discard_draft' => 'Απόρριψη Προσχεδίου', + 'pages_edit_switch_to_markdown' => 'Μετάβαση στον Επεξεργαστή Markdown', + 'pages_edit_switch_to_markdown_clean' => '(Καθαρισμός Περιεχομένου)', + 'pages_edit_switch_to_markdown_stable' => '(Σταθερό Περιεχόμενο)', + 'pages_edit_switch_to_wysiwyg' => 'Εναλλαγή στον επεξεργαστή WYSIWYG', + 'pages_edit_set_changelog' => 'Ορισμός καταγραφής αλλαγών', + 'pages_edit_enter_changelog_desc' => 'Εισάγετε μια σύντομη περιγραφή των αλλαγών που κάνατε', + 'pages_edit_enter_changelog' => 'Εισαγωγή Αρχείου Καταγραφής Αλλαγών', + 'pages_editor_switch_title' => 'Εναλλαγή Επεξεργαστή', + 'pages_editor_switch_are_you_sure' => 'Είστε βέβαιοι ότι θέλετε να αλλάξετε τον επεξεργαστή κειμένου για αυτή τη σελίδα;', + 'pages_editor_switch_consider_following' => 'Λάβετε υπόψη τα ακόλουθα όταν αλλάζετε συντάκτες:', + 'pages_editor_switch_consideration_a' => 'Μόλις αποθηκευτεί, η επιλογή του νέου επεξεργαστή κειμένου θα χρησιμοποιηθεί από τυχόν μελλοντικούς επεξεργαστές, συμπεριλαμβανομένων εκείνων που μπορεί να μην είναι σε θέση να αλλάξουν τον τύπο του επεξεργαστή κειμένου.', + 'pages_editor_switch_consideration_b' => 'Αυτό μπορεί να οδηγήσει σε απώλεια λεπτομερειών και κώδικα σε ορισμένες περιπτώσεις.', + 'pages_editor_switch_consideration_c' => 'Οι αλλαγές ετικετών ή αρχείων καταγραφής, που έγιναν από την τελευταία αποθήκευση, δεν θα συνεχιστούν σε αυτήν την αλλαγή.', + 'pages_save' => 'Αποθήκευση Σελίδας', + 'pages_title' => 'Τίτλος Σελίδας', + 'pages_name' => 'Όνομα Σελίδας', + 'pages_md_editor' => 'Επεξεργαστής', + 'pages_md_preview' => 'Προεπισκόπηση', + 'pages_md_insert_image' => 'Εισαγωγή Εικόνας', + 'pages_md_insert_link' => 'Εισαγωγή/Επεξεργασία συνδέσμου', + 'pages_md_insert_drawing' => 'Εισαγωγή Σχεδίου', + 'pages_not_in_chapter' => 'Η σελίδα δεν είναι σε κεφάλαιο', + 'pages_move' => 'Μετακίνηση Σελίδας', + 'pages_move_success' => 'Η σελίδα μετακινήθηκε στο ":parentName"', + 'pages_copy' => 'Αντιγραφή Σελίδας', + 'pages_copy_desination' => 'Αντιγραφή Προορισμού', + 'pages_copy_success' => 'Η σελίδα αντιγράφηκε επιτυχώς', + 'pages_permissions' => 'Δικαιώματα Σελίδας', + 'pages_permissions_success' => 'Τα δικαιώματα σελίδας ενημερώθηκαν', + 'pages_revision' => 'Αναθεώρηση', + 'pages_revisions' => 'Αναθεωρήσεις Σελίδας', + 'pages_revisions_named' => 'Αναθεωρήσεις σελίδας για :pageName', + 'pages_revision_named' => 'Αναθεώρηση σελίδας για :pageName', + 'pages_revision_restored_from' => 'Επαναφορά από #:id; :summary', + 'pages_revisions_created_by' => 'Δημιουργήθηκε από', + 'pages_revisions_date' => 'Ημερομηνία Αναθεώρησης', + 'pages_revisions_number' => '#', + 'pages_revisions_numbered' => 'Αναθεώρηση #', + 'pages_revisions_numbered_changes' => 'Αναθεώρηση #:id Αλλαγές', + 'pages_revisions_editor' => 'Τύπος Επεξεργαστή', + 'pages_revisions_changelog' => 'Αρχείο καταγραφής αλλαγών', + 'pages_revisions_changes' => 'Αλλαγές', + 'pages_revisions_current' => 'Τρέχουσα Έκδοση', + 'pages_revisions_preview' => 'Προεπισκόπηση', + 'pages_revisions_restore' => 'Επαναφορά', + 'pages_revisions_none' => 'Αυτή η σελίδα δεν έχει αναθεωρήσεις', + 'pages_copy_link' => 'Αντιγραφή Συνδέσμου', + 'pages_edit_content_link' => 'Επεξεργασία Περιεχομένου', + 'pages_permissions_active' => 'Ενεργά Δικαιώματα Σελίδας', + 'pages_initial_revision' => 'Αρχική δημοσίευση', + 'pages_references_update_revision' => 'Αυτόματη ενημέρωση του συστήματος των εσωτερικών συνδέσμων', + 'pages_initial_name' => 'Νέα Σελίδα', + 'pages_editing_draft_notification' => 'Αυτή τη στιγμή επεξεργάζεστε ένα προσχέδιο που αποθηκεύτηκε για τελευταία φορά :timeDiff.', + 'pages_draft_edited_notification' => 'Αυτή η σελίδα έχει ενημερωθεί από εκείνη τη στιγμή. Συνιστάται να απορρίψετε αυτό το προσχέδιο.', + 'pages_draft_page_changed_since_creation' => 'Αυτή η σελίδα έχει ενημερωθεί από τότε που δημιουργήθηκε αυτό το προσχέδιο. Συνιστάται να απορρίψετε αυτό το σχέδιο ή να φροντίσετε να μην αντικαταστήσετε τυχόν αλλαγές σελίδας.', + 'pages_draft_edit_active' => [ + 'start_a' => ':count χρήστες έχουν αρχίσει να επεξεργάζονται αυτή τη σελίδα', + 'start_b' => ':userName έχει ξεκινήσει την επεξεργασία αυτής της σελίδας', + 'time_a' => 'από τότε που η σελίδα ενημερώθηκε τελευταία φορά', + 'time_b' => 'τα τελευταία :mint λεπτά', + 'message' => ':start :time. Προσέξτε να μην αντικαταστήσετε ο ένας τις ενημερώσεις του άλλου!', + ], + 'pages_draft_discarded' => 'Το προσχέδιο απορρίφθηκε, ο επεξεργαστής ενημερώθηκε με το τρέχον περιεχόμενο της σελίδας', + 'pages_specific' => 'Συγκεκριμένη Σελίδα', + 'pages_is_template' => 'Πρότυπο σελίδας', + + // Editor Sidebar + 'page_tags' => 'Ετικέτες Σελίδας', + 'chapter_tags' => 'Ετικέτες Κεφαλαίου', + 'book_tags' => 'Ετικέτες Βιβλίου', + 'shelf_tags' => 'Ετικέτες Ραφιών', + 'tag' => 'Ετικέτα', + 'tags' => 'Ετικέτες', + 'tag_name' => 'Όνομα Ετικέτας', + 'tag_value' => 'Τιμή Ετικέτας (Προαιρετικό)', + 'tags_explain' => "Προσθέστε μερικές ετικέτες για να κατηγοριοποιήσετε καλύτερα το περιεχόμενό σας. \n Μπορείτε να αντιστοιχίσετε μια τιμή σε μια ετικέτα για πιο αναλυτική οργάνωση.", + 'tags_add' => 'Προσθήκη άλλης ετικέτας', + 'tags_remove' => 'Αφαίρεση ετικέτας', + 'tags_usages' => 'Συνολικές χρήσεις ετικετών', + 'tags_assigned_pages' => 'Ανατέθηκε σε σελίδες', + 'tags_assigned_chapters' => 'Ανατέθηκε στα κεφάλαια', + 'tags_assigned_books' => 'Ανατέθηκε σε Βιβλία', + 'tags_assigned_shelves' => 'Ανατέθηκε σε Ράφια', + 'tags_x_unique_values' => ':count μοναδικές τιμές', + 'tags_all_values' => 'Όλες οι τιμές', + 'tags_view_tags' => 'Προβολή Ετικετών', + 'tags_view_existing_tags' => 'Δείτε τις υπάρχουσες ετικέτες', + 'tags_list_empty_hint' => 'Οι ετικέτες μπορούν να εκχωρηθούν μέσω της πλαϊνής μπάρας συντάκτη σελίδας ή κατά την επεξεργασία των λεπτομερειών ενός βιβλίου, κεφαλαίου ή ράφι.', + 'attachments' => 'Συνημμένα', + 'attachments_explain' => 'Ανεβάστε μερικά αρχεία ή επισυνάψτε μερικούς συνδέσμους για να εμφανίσετε στη σελίδα σας. Αυτά είναι ορατά στην πλαϊνή μπάρα σελίδας.', + 'attachments_explain_instant_save' => 'Οι αλλαγές εδώ αποθηκεύονται αμέσως.', + 'attachments_items' => 'Συνημμένα Στοιχεία', + 'attachments_upload' => 'Μεταφόρτωση Αρχείου', + 'attachments_link' => 'Επισύναψη Δεσμού', + 'attachments_set_link' => 'Ορισμός Συνδέσμου', + 'attachments_delete' => 'Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτό το συνημμένο;', + 'attachments_dropzone' => 'Αποθέστε αρχεία ή κάντε κλικ εδώ για να επισυνάψετε ένα αρχείο', + 'attachments_no_files' => 'Δεν έχουν μεταφορτωθεί αρχεία', + 'attachments_explain_link' => 'Μπορείτε να επισυνάψετε έναν σύνδεσμο αν προτιμάτε να μην ανεβάσετε ένα αρχείο. Αυτό μπορεί να είναι ένας σύνδεσμος σε άλλη σελίδα ή ένας σύνδεσμος σε ένα αρχείο στο σύννεφο.', + 'attachments_link_name' => 'Όνομα Συνδέσμου', + 'attachment_link' => 'Σύνδεσμος συνημμένου', + 'attachments_link_url' => 'Σύνδεση σε αρχείο', + 'attachments_link_url_hint' => 'Url του ιστότοπου ή του αρχείου', + 'attach' => 'Επισύναψη', + 'attachments_insert_link' => 'Προσθήκη συνημμένου συνδέσμου στη σελίδα', + 'attachments_edit_file' => 'Επεξεργασία Αρχείου', + 'attachments_edit_file_name' => 'Όνομα Αρχείου', + 'attachments_edit_drop_upload' => 'Ρίξτε αρχεία ή κάντε κλικ εδώ για να ανεβάσετε και να αντικαταστήσετε', + 'attachments_order_updated' => 'Η παραγγελία συνημμένων ενημερώθηκε', + 'attachments_updated_success' => 'Οι λεπτομέρειες συνημμένου ενημερώθηκαν', + 'attachments_deleted' => 'Το συνημμένο διαγράφηκε', + 'attachments_file_uploaded' => 'Το αρχείο μεταφορτώθηκε επιτυχώς', + 'attachments_file_updated' => 'Το αρχείο ενημερώθηκε επιτυχώς', + 'attachments_link_attached' => 'Ο σύνδεσμος συνδέθηκε επιτυχώς στη σελίδα', + 'templates' => 'Πρότυπα', + 'templates_set_as_template' => 'Η σελίδα είναι πρότυπο', + 'templates_explain_set_as_template' => 'Μπορείτε να ορίσετε αυτή τη σελίδα ως πρότυπο, έτσι ώστε τα περιεχόμενά της να χρησιμοποιούνται κατά τη δημιουργία άλλων σελίδων. Άλλοι χρήστες θα μπορούν να χρησιμοποιήσουν αυτό το πρότυπο αν έχουν δικαιώματα προβολής για αυτή τη σελίδα.', + 'templates_replace_content' => 'Αντικατάσταση περιεχομένου σελίδας', + 'templates_append_content' => 'Προσθήκη στο περιεχόμενο της σελίδας', + 'templates_prepend_content' => 'Προεπιλογή στο περιεχόμενο της σελίδας', + + // Profile View + 'profile_user_for_x' => 'Χρήστης για :time', + 'profile_created_content' => 'Δημιουργία Περιεχομένου', + 'profile_not_created_pages' => ':userName δεν έχει δημιουργήσει καμία σελίδα', + 'profile_not_created_chapters' => ':userName δεν έχει δημιουργήσει κεφάλαια', + 'profile_not_created_books' => ':userName δεν έχει δημιουργήσει βιβλία', + 'profile_not_created_shelves' => ':userName δεν έχει δημιουργήσει ράφια', + + // Comments + 'comment' => 'Σχόλιο', + 'comments' => 'Σχόλια', + 'comment_add' => 'Προσθήκη Σχολίου', + 'comment_placeholder' => 'Αφήστε ένα σχόλιο εδώ', + 'comment_count' => '{0} Κανένα σχόλιο{1} 1 Σχόλιο [2,*] :count Σχόλια', + 'comment_save' => 'Αποθήκευση Σχολίου', + 'comment_saving' => 'Αποθήκευση σχολίου...', + 'comment_deleting' => 'Διαγραφή σχολίου...', + 'comment_new' => 'Νέο Σχόλιο', + 'comment_created' => 'σχολίασε :createDiff', + 'comment_updated' => 'Ενημερώθηκε :updateDiff από :username', + 'comment_deleted_success' => 'Σχόλιο διαγράφηκε', + 'comment_created_success' => 'Το σχόλιο προστέθηκε', + 'comment_updated_success' => 'Το σχόλιο ενημερώθηκε', + 'comment_delete_confirm' => 'Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτό το σχόλιο;', + 'comment_in_reply_to' => 'Σε απάντηση στο :commentId', + + // Revision + 'revision_delete_confirm' => 'Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτήν την αναθεώρηση;', + 'revision_restore_confirm' => 'Είστε βέβαιοι ότι θέλετε να επαναφέρετε αυτή την αναθεώρηση; Τα τρέχοντα περιεχόμενα της σελίδας θα αντικατασταθούν.', + 'revision_delete_success' => 'Η Αναθεώρηση διαγράφηκε', + 'revision_cannot_delete_latest' => 'Δεν είναι δυνατή η διαγραφή της τελευταίας αναθεώρησης.', + + // Copy view + 'copy_consider' => 'Παρακαλώ σκεφτείτε τα παρακάτω κατά την αντιγραφή περιεχομένου.', + 'copy_consider_permissions' => 'Οι ρυθμίσεις προσαρμοσμένων δικαιωμάτων δεν θα αντιγραφούν.', + 'copy_consider_owner' => 'Θα γίνετε ο ιδιοκτήτης όλου του αντιγραμμένου περιεχομένου.', + 'copy_consider_images' => 'Τα αρχεία εικόνας σελίδας δεν θα αναπαραχθούν και οι αρχικές εικόνες θα διατηρήσουν τη σχέση τους με τη σελίδα στην οποία είχαν αρχικά μεταφορτωθεί.', + 'copy_consider_attachments' => 'Τα συνημμένα σελίδας δεν θα αντιγραφούν.', + 'copy_consider_access' => 'Μια αλλαγή της θέσης, του ιδιοκτήτη ή των δικαιωμάτων μπορεί να έχει ως αποτέλεσμα το περιεχόμενο αυτό να είναι προσβάσιμο σε χρήστες που προηγουμένως δεν είχαν πρόσβαση.', + + // Conversions + 'convert_to_shelf' => 'Μετατροπή σε ράφι', + 'convert_to_shelf_contents_desc' => 'Μπορείτε να μετατρέψετε αυτό το βιβλίο σε ένα νέο ράφι με το ίδιο περιεχόμενο. Κεφάλαια που περιέχονται σε αυτό το βιβλίο θα μετατραπούν σε νέα βιβλία. Αν αυτό το βιβλίο περιέχει σελίδες που δεν βρίσκονται σε κεφάλαιο, αυτό το βιβλίο θα μετονομαστεί και περιέχει τέτοιες σελίδες, και αυτό το βιβλίο θα γίνει μέρος του νέου ράφι.', + 'convert_to_shelf_permissions_desc' => 'Τυχόν δικαιώματα που ορίζονται σε αυτό το βιβλίο θα αντιγραφούν στο νέο ράφι και σε όλα τα νέα θυγατρικά βιβλία στα οποία δεν επιβάλλονται τα δικά τους δικαιώματα. Λάβετε υπόψη ότι τα δικαιώματα στα ράφια δεν μεταφέρονται αυτόματα σε περιεχόμενο εντός, όπως συμβαίνει για τα βιβλία.', + 'convert_book' => 'Μετατροπή Βιβλίου', + 'convert_book_confirm' => 'Είστε σίγουροι ότι θέλετε να μετατρέψετε αυτό το βιβλίο;', + 'convert_undo_warning' => 'Αυτό δεν μπορεί να αναιρεθεί τόσο εύκολα.', + 'convert_to_book' => 'Μετατροπή σε βιβλίο', + 'convert_to_book_desc' => 'Μπορείτε να μετατρέψετε αυτό το κεφάλαιο σε ένα νέο βιβλίο με το ίδιο περιεχόμενο. Τυχόν δικαιώματα που έχουν οριστεί σε αυτό το κεφάλαιο θα αντιγραφούν στο νέο βιβλίο αλλά τυχόν κληρονομημένα δικαιώματα, από το γονικό βιβλίο, δεν θα αντιγραφούν το οποίο θα μπορούσε να οδηγήσει σε αλλαγή του ελέγχου πρόσβασης.', + 'convert_chapter' => 'Μετατροπή Κεφαλαίου', + 'convert_chapter_confirm' => 'Είστε βέβαιοι ότι θέλετε να μετατρέψετε αυτό το κεφάλαιο;', + + // References + 'references' => 'Αναφορές', + 'references_none' => 'Δεν υπάρχουν αναφορές παρακολούθησης σε αυτό το στοιχείο.', + 'references_to_desc' => 'Παρακάτω εμφανίζονται όλες οι γνωστές σελίδες του συστήματος που συνδέονται με αυτό το στοιχείο.', +]; diff --git a/resources/lang/el/errors.php b/resources/lang/el/errors.php new file mode 100644 index 000000000..6c489d360 --- /dev/null +++ b/resources/lang/el/errors.php @@ -0,0 +1,109 @@ + 'Δεν έχετε δικαίωμα πρόσβασης στη ζητούμενη σελίδα.', + 'permissionJson' => 'Δεν έχετε άδεια να εκτελέσετε την αιτούμενη ενέργεια.', + + // Auth + 'error_user_exists_different_creds' => 'Ένας χρήστης με email :email υπάρχει ήδη αλλά με διαφορετικά διαπιστευτήρια.', + 'email_already_confirmed' => 'Το email έχει ήδη επιβεβαιωθεί, Δοκιμάστε να συνδεθείτε.', + 'email_confirmation_invalid' => 'Αυτό το διακριτικό επιβεβαίωσης δεν είναι έγκυρο ή έχει ήδη χρησιμοποιηθεί, Παρακαλώ δοκιμάστε να εγγραφείτε ξανά.', + 'email_confirmation_expired' => 'Το διακριτικό επιβεβαίωσης έχει λήξει, έχει σταλεί ένα νέο email επιβεβαίωσης.', + 'email_confirmation_awaiting' => 'Η διεύθυνση ηλεκτρονικού ταχυδρομείου για το λογαριασμό που χρησιμοποιείται πρέπει να επιβεβαιωθεί', + 'ldap_fail_anonymous' => 'Η πρόσβαση LDAP απέτυχε με ανώνυμη σύνδεση', + 'ldap_fail_authed' => 'Η πρόσβαση LDAP απέτυχε με τη χρήση δοσμένων λεπτομερειών dn & κωδικού πρόσβασης', + 'ldap_extension_not_installed' => 'Η επέκταση LDAP PHP δεν εγκαταστάθηκε', + 'ldap_cannot_connect' => 'Αδυναμία σύνδεσης στο διακομιστή ldap, η αρχική σύνδεση απέτυχε', + 'saml_already_logged_in' => 'Ήδη συνδεδεμένος', + 'saml_user_not_registered' => 'Ο χρήστης :name δεν είναι εγγεγραμμένος και η αυτόματη εγγραφή είναι απενεργοποιημένη', + 'saml_no_email_address' => 'Δεν ήταν δυνατή η εύρεση μιας διεύθυνσης ηλεκτρονικού ταχυδρομείου, για αυτόν τον χρήστη, στα δεδομένα που παρέχονται από το εξωτερικό σύστημα ελέγχου ταυτότητας', + 'saml_invalid_response_id' => 'Το αίτημα από το εξωτερικό σύστημα ελέγχου ταυτότητας δεν αναγνωρίζεται από μια διαδικασία που ξεκίνησε από αυτή την εφαρμογή. Η πλοήγηση πίσω μετά από μια σύνδεση θα μπορούσε να προκαλέσει αυτό το ζήτημα.', + 'saml_fail_authed' => 'Η σύνδεση με τη χρήση :system απέτυχε, το σύστημα δεν παρείχε επιτυχή εξουσιοδότηση', + 'oidc_already_logged_in' => 'Ήδη συνδεδεμένος', + 'oidc_user_not_registered' => 'Ο χρήστης :name δεν είναι εγγεγραμμένος και η αυτόματη εγγραφή είναι απενεργοποιημένη', + 'oidc_no_email_address' => 'Δεν ήταν δυνατή η εύρεση μιας διεύθυνσης ηλεκτρονικού ταχυδρομείου, για αυτόν τον χρήστη, στα δεδομένα που παρέχονται από το εξωτερικό σύστημα ελέγχου ταυτότητας', + 'oidc_fail_authed' => 'Η σύνδεση με τη χρήση :system απέτυχε, το σύστημα δεν παρείχε επιτυχή εξουσιοδότηση', + 'social_no_action_defined' => 'Καμία ενέργεια δεν ορίστηκε', + 'social_login_bad_response' => "Παρουσιάστηκε σφάλμα κατά τη διάρκεια :socialAccount login: \n:error", + 'social_account_in_use' => 'Αυτός ο λογαριασμός :socialAccount είναι ήδη σε χρήση, Δοκιμάστε να συνδεθείτε μέσω της επιλογής :socialAccount .', + 'social_account_email_in_use' => 'Το email :email είναι ήδη σε χρήση. Αν έχετε ήδη ένα λογαριασμό, μπορείτε να συνδέσετε τον :socialAccount λογαριασμό σας από τις ρυθμίσεις του προφίλ σας.', + 'social_account_existing' => 'Αυτός ο :socialAccount είναι ήδη συνδεδεμένος στο προφίλ σας.', + 'social_account_already_used_existing' => 'Αυτός ο :socialAccount λογαριασμός χρησιμοποιείται ήδη από άλλο χρήστη.', + 'social_account_not_used' => 'Αυτός ο :socialAccount λογαριασμός δεν είναι συνδεδεμένος με κανέναν χρήστη. Παρακαλώ επισυνάψτε τον στις ρυθμίσεις του προφίλ σας. ', + 'social_account_register_instructions' => 'Εάν δεν έχετε ακόμα λογαριασμό, μπορείτε να καταχωρήσετε ένα λογαριασμό χρησιμοποιώντας την επιλογή :socialAccount .', + 'social_driver_not_found' => 'Δεν βρέθηκε κοινωνικός οδηγός', + 'social_driver_not_configured' => 'Οι κοινωνικές ρυθμίσεις του :socialAccount δεν έχουν ρυθμιστεί σωστά.', + 'invite_token_expired' => 'Αυτός ο σύνδεσμος πρόσκλησης έχει λήξει. Αντ\' αυτού μπορείτε να προσπαθήσετε να επαναφέρετε τον κωδικό πρόσβασής σας.', + + // System + 'path_not_writable' => 'Η διαδρομή αρχείου :filePath δεν μπόρεσε να μεταφορτωθεί. Βεβαιωθείτε ότι είναι εγγράψιμη στο διακομιστή.', + 'cannot_get_image_from_url' => 'Αδυναμία λήψης εικόνας από :url', + 'cannot_create_thumbs' => 'Ο διακομιστής δεν μπορεί να δημιουργήσει μικρογραφίες. Παρακαλώ ελέγξτε ότι έχετε την επέκταση GD PHP εγκατεστημένη.', + 'server_upload_limit' => 'Ο διακομιστής δεν επιτρέπει τη μεταφόρτωση αυτού του μεγέθους. Παρακαλώ δοκιμάστε ένα μικρότερο μέγεθος αρχείου.', + 'uploaded' => 'Ο διακομιστής δεν επιτρέπει τη μεταφόρτωση αυτού του μεγέθους. Παρακαλώ δοκιμάστε ένα μικρότερο μέγεθος αρχείου.', + 'image_upload_error' => 'Παρουσιάστηκε σφάλμα κατά το ανέβασμα της εικόνας.', + 'image_upload_type_error' => 'Ο τύπος εικόνας που μεταφορτώθηκε δεν είναι έγκυρος', + 'file_upload_timeout' => 'Το χρονικό όριο μεταφόρτωσης αρχείου έληξε.', + + // Attachments + 'attachment_not_found' => 'Το συνημμένο δεν βρέθηκε', + + // Pages + 'page_draft_autosave_fail' => 'Αποτυχία αποθήκευσης προσχέδιου. Βεβαιωθείτε ότι έχετε σύνδεση στο διαδίκτυο πριν την αποθήκευση αυτής της σελίδας', + 'page_custom_home_deletion' => 'Δεν μπορεί να διαγραφεί μια σελίδα ενώ έχει οριστεί ως αρχική σελίδα', + + // Entities + 'entity_not_found' => 'Η οντότητα δεν βρέθηκε', + 'bookshelf_not_found' => 'Το ράφι δεν βρέθηκε', + 'book_not_found' => 'Το βιβλίο δεν βρέθηκε', + 'page_not_found' => 'Η σελίδα δεν βρέθηκε', + 'chapter_not_found' => 'Το κεφάλαιο δεν βρέθηκε', + 'selected_book_not_found' => 'Το επιλεγμένο βιβλίο δεν βρέθηκε', + 'selected_book_chapter_not_found' => 'Το επιλεγμένο βιβλίο ή κεφάλαιο δεν βρέθηκε', + 'guests_cannot_save_drafts' => 'Οι επισκέπτες δεν μπορούν να αποθηκεύσουν πρόχειρα', + + // Users + 'users_cannot_delete_only_admin' => 'Δεν μπορείτε να διαγράψετε τον μοναδικό διαχειριστή', + 'users_cannot_delete_guest' => 'Δεν μπορείτε να διαγράψετε τον επισκέπτη', + + // Roles + 'role_cannot_be_edited' => 'Αυτός ο ρόλος δεν μπορεί να επεξεργαστεί', + 'role_system_cannot_be_deleted' => 'Αυτός ο ρόλος είναι ρόλος συστήματος και δεν μπορεί να διαγραφεί', + 'role_registration_default_cannot_delete' => 'Αυτός ο ρόλος δεν μπορεί να διαγραφεί ενώ έχει οριστεί ως προεπιλεγμένος ρόλος εγγραφής', + 'role_cannot_remove_only_admin' => 'Αυτός ο χρήστης είναι ο μόνος χρήστης που έχει ανατεθεί στον ρόλο διαχειριστή. Εκχωρήστε τον ρόλο διαχειριστή σε άλλο χρήστη πριν επιχειρήσετε να τον καταργήσετε εδώ.', + + // Comments + 'comment_list' => 'Παρουσιάστηκε σφάλμα κατά την λήψη σχολίων.', + 'cannot_add_comment_to_draft' => 'Δεν μπορείτε να προσθέσετε σχόλια σε ένα προσχέδιο.', + 'comment_add' => 'Παρουσιάστηκε σφάλμα κατά την προσθήκη / ενημέρωση του σχολίου.', + 'comment_delete' => 'Παρουσιάστηκε σφάλμα κατά τη διαγραφή του σχολίου.', + 'empty_comment' => 'Αδυναμία προσθήκης ενός κενού σχολίου.', + + // Error pages + '404_page_not_found' => 'Η Σελίδα δε βρέθηκε', + 'sorry_page_not_found' => 'Λυπούμαστε, Η σελίδα που αναζητάτε δεν βρέθηκε.', + 'sorry_page_not_found_permission_warning' => 'Αν περιμένατε να υπάρχει αυτή η σελίδα, ίσως να μην έχετε δικαίωμα να την δείτε.', + 'image_not_found' => 'Η Εικόνα δεν βρέθηκε', + 'image_not_found_subtitle' => 'Λυπούμαστε, το αρχείο εικόνας που αναζητάτε δεν μπορεί να βρεθεί.', + 'image_not_found_details' => 'Αν περιμένατε να υπάρχει αυτή η εικόνα, ίσως να έχει διαγραφεί.', + 'return_home' => 'Επιστροφή στην αρχική σελίδα', + 'error_occurred' => 'Προέκυψε Ένα Σφάλμα', + 'app_down' => ':appName είναι προσωρινά μη διαθέσιμη', + 'back_soon' => 'Θα υπάρξει σύντομα υποστήριξη.', + + // API errors + 'api_no_authorization_found' => 'Δεν βρέθηκε διακριτικό εξουσιοδότησης κατόπιν αιτήματος', + 'api_bad_authorization_format' => 'Ένα διακριτικό εξουσιοδότησης βρέθηκε κατόπιν αιτήματος, αλλά η μορφή εμφανίστηκε εσφαλμένη', + 'api_user_token_not_found' => 'Δεν βρέθηκε αντίστοιχο διακριτικό API για το παρεχόμενο διακριτικό εξουσιοδότησης', + 'api_incorrect_token_secret' => 'Το μυστικό που παρέχεται για το δεδομένο χρησιμοποιημένο διακριτικό API είναι εσφαλμένο', + 'api_user_no_api_permission' => 'Ο ιδιοκτήτης του χρησιμοποιημένου διακριτικού API δεν έχει άδεια για να κάνει κλήσεις API', + 'api_user_token_expired' => 'Το διακριτικό εξουσιοδότησης που χρησιμοποιείται έχει λήξει', + + // Settings & Maintenance + 'maintenance_test_email_failure' => 'Σφάλμα κατά την αποστολή δοκιμαστικού email:', + +]; diff --git a/resources/lang/el/pagination.php b/resources/lang/el/pagination.php new file mode 100644 index 000000000..061ad3f11 --- /dev/null +++ b/resources/lang/el/pagination.php @@ -0,0 +1,12 @@ + '« Προηγούμενο', + 'next' => 'Επόμενο »', + +]; diff --git a/resources/lang/el/passwords.php b/resources/lang/el/passwords.php new file mode 100644 index 000000000..a56d1d181 --- /dev/null +++ b/resources/lang/el/passwords.php @@ -0,0 +1,15 @@ + 'Ο κωδικός πρόσβασης πρέπει να αποτελείται από τουλάχιστον έξι χαρακτήρες και να ταιριάζει με τον κωδικό επιβεβαίωσης.', + 'user' => "Δεν μπορούμε να βρόυμε κάποιον χρήστη με αυτή τη διεύθυνση e-mail.", + 'token' => 'Το διακριτικό επαναφοράς κωδικού πρόσβασης δεν είναι έγκυρο για αυτή τη διεύθυνση ηλεκτρονικού ταχυδρομείου.', + 'sent' => 'Σας έχουμε στείλει e-mail με τον σύνδεσμο επαναφοράς του κωδικού πρόσβασης!', + 'reset' => 'Ο κωδικός σας έχει επαναφερθεί!', + +]; diff --git a/resources/lang/el/settings.php b/resources/lang/el/settings.php new file mode 100644 index 000000000..0cc0be262 --- /dev/null +++ b/resources/lang/el/settings.php @@ -0,0 +1,315 @@ + 'Ρυθμίσεις', + 'settings_save' => 'Αποθήκευση ρυθμίσεων', + 'settings_save_success' => 'Οι ρυθμίσεις αποθηκεύτηκαν', + 'system_version' => 'Έκδοση εφαρμογής', + 'categories' => 'Κατηγορίες', + + // App Settings + 'app_customization' => 'Προσαρμογή', + 'app_features_security' => 'Χαρακτηριστικά & Ασφάλεια', + 'app_name' => 'Όνομα Εφαρμογής', + 'app_name_desc' => 'Αυτό το όνομα εμφανίζεται στην κεφαλίδα της ιστοσελίδας και σε τυχόν μηνύματα ηλεκτρονικού ταχυδρομείου που αποστέλλονται από το σύστημα.', + 'app_name_header' => 'Εμφάνιση Ονόματος στην κεφαλίδα', + 'app_public_access' => 'Δημόσια Πρόσβαση', + 'app_public_access_desc' => 'Η ενεργοποίηση αυτής της επιλογής θα επιτρέψει στους επισκέπτες, που δεν είναι συνδεδεμένοι, να έχουν πρόσβαση στο περιεχόμενο της εφαρμογής BookStack.', + 'app_public_access_desc_guest' => 'Η πρόσβαση για δημόσιους επισκέπτες μπορεί να ελεγχθεί μέσω του χρήστη "Guest".', + 'app_public_access_toggle' => 'Να επιτρέπεται η δημόσια πρόσβαση', + 'app_public_viewing' => 'Να επιτρέπεται η δημόσια προβολή;', + 'app_secure_images' => 'Μεταφορτώσεις Εικόνων υψηλότερης Ασφάλειας', + 'app_secure_images_toggle' => 'Ενεργοποιήστε τις μεταφορτώσεις Εικόνων υψηλότερης Ασφάλειας', + 'app_secure_images_desc' => 'Για λόγους απόδοσης, όλες οι εικόνες είναι δημόσιες. Αυτή η επιλογή προσθέτει μια τυχαία συμβολοσειρά μπροστά από τις διευθύνσεις URL εικόνων, δύσκολο να τη μαντέψει κάποιος. Βεβαιωθείτε ότι τα ευρετήρια καταλόγου δεν είναι ενεργοποιημένα για να αποτρέψετε την εύκολη πρόσβαση.', + 'app_default_editor' => 'Προεπιλεγμένος Επεξεργαστής σελίδων', + 'app_default_editor_desc' => 'Επιλέξτε ποιο πρόγραμμα επεξεργασίας θα χρησιμοποιείται από προεπιλογή κατά την επεξεργασία νέων σελίδων. Αυτό μπορεί να παρακαμφθεί σε επίπεδο σελίδας όπου το επιτρέπουν τα δικαιώματα.', + 'app_custom_html' => 'Προσαρμοσμένο περιεχόμενο κεφαλίδας HTML', + 'app_custom_html_desc' => 'Οποιοδήποτε περιεχόμενο προστίθεται εδώ θα εισαχθεί στο κάτω μέρος της ενότητας κάθε σελίδας. Αυτό είναι βολικό για την παράκαμψη ή προσθήκη στυλ καθώς και την προσθήκη κώδικα αναλυτικών στοιχείων.', + 'app_custom_html_disabled_notice' => 'Το προσαρμοσμένο περιεχόμενο κεφαλίδας HTML είναι απενεργοποιημένο σε αυτήν τη σελίδα ρυθμίσεων, για να διασφαλιστεί ότι τυχόν αλλαγές που θα πραγματοποιηθούν και θα προκαλέσουν δυσλειτουργία στην ιστοσελίδα σας, μπορούν να επαναφερθούν.', + 'app_logo' => 'Λογότυπο εφαρμογής', + 'app_logo_desc' => 'Αυτή η εικόνα πρέπει να έχει μέγιστο ύψος 43px.
Οι μεγάλες εικόνες θα μειωθούν.', + 'app_primary_color' => 'Βασικό, χρώμα εφαρμογής', + 'app_primary_color_desc' => 'Ορίζει το κύριο χρώμα για την εφαρμογή, συμπεριλαμβανομένων του banner, των κουμπιών και των συνδέσμων.', + 'app_homepage' => 'Αρχική σελίδα εφαρμογής', + 'app_homepage_desc' => 'Επιλέξτε μια προβολή για εμφάνιση στην αρχική σελίδα αντί για την προεπιλεγμένη προβολή. Τα δικαιώματα σελίδων αγνοούνται για επιλεγμένες σελίδες.', + 'app_homepage_select' => 'Επιλέξτε μια σελίδα', + 'app_footer_links' => 'Σύνδεσμοι υποσέλιδου', + 'app_footer_links_desc' => 'Προσθέστε συνδέσμους για εμφάνιση στο υποσέλιδο του ιστότοπου. Αυτά θα εμφανίζονται στο κάτω μέρος των περισσότερων σελίδων, συμπεριλαμβανομένων εκείνων που δεν απαιτούν σύνδεση. Μπορείτε να χρησιμοποιήσετε μια ετικέτα "trans::" για να χρησιμοποιήσετε μεταφράσεις που καθορίζονται από το σύστημα. Για παράδειγμα: Η χρήση του "trans::common.privacy_policy" θα παρέχει το μεταφρασμένο κείμενο "Πολιτική Απορρήτου" και το "trans::common.terms_of_service" θα παρέχει το μεταφρασμένο κείμενο "Όροι Παροχής Υπηρεσιών".', + 'app_footer_links_label' => 'Ετικέτα Συνδέσμου', + 'app_footer_links_url' => 'URL Σύνδεσης', + 'app_footer_links_add' => 'Προσθήκη Συνδέσμου υποσέλιδου', + 'app_disable_comments' => 'Απενεργοποίηση Σχολίων', + 'app_disable_comments_toggle' => 'Απενεργοποίηση Σχολίων', + 'app_disable_comments_desc' => 'Απενεργοποιεί τα σχόλια σε όλες τις σελίδες της εφαρμογής.
Τα υπάρχοντα σχόλια δεν εμφανίζονται.', + + // Color settings + 'content_colors' => 'Χρώματα εφαρμογής', + 'content_colors_desc' => 'Ορίζει τα χρώματα για όλα τα στοιχεία στην ιεραρχία οργάνωσης της ιστοσελίδας.
Συνιστάται η επιλογή χρωμάτων με παρόμοια φωτεινότητα με τα προεπιλεγμένα χρώματα για αναγνωσιμότητα.', + 'bookshelf_color' => 'Χρώμα Ραφιού', + 'book_color' => 'Χρώμα Βιβλίων', + 'chapter_color' => 'Χρώμα Κεφαλαίων Βιβλίων', + 'page_color' => 'Χρώμα Σελίδων', + 'page_draft_color' => 'Χρώμα Πρoσχέδιων Σελίδων (Draft page)', + + // Registration Settings + 'reg_settings' => 'Εγγραφή', + 'reg_enable' => 'Ενεργοποίηση Εγγραφής', + 'reg_enable_toggle' => 'Ενεργοποίηση εγγραφής', + 'reg_enable_desc' => 'Όταν ενεργοποιηθεί η εγγραφή, ο χρήστης θα μπορεί να εγγραφεί ως χρήστης της εφαρμογής. Κατά την εγγραφή τους δίνεται ένας μοναδικός, προεπιλεγμένος ρόλος χρήστη.', + 'reg_default_role' => 'Προεπιλεγμένος ρόλος χρήστη μετά την εγγραφή', + 'reg_enable_external_warning' => 'Η παραπάνω επιλογή αγνοείται όταν ο εξωτερικός έλεγχος ταυτότητας LDAP ή SAML είναι ενεργός. Οι λογαριασμοί χρηστών για μη υπάρχοντα μέλη θα δημιουργηθούν αυτόματα εάν ο έλεγχος ταυτότητας, έναντι του εξωτερικού συστήματος που χρησιμοποιείται, είναι επιτυχής.', + 'reg_email_confirmation' => 'Επιβεβαίωση ηλεκτρονικού ταχυδρομείου', + 'reg_email_confirmation_toggle' => 'Απαιτείται η επιβεβαίωση μέσω email', + 'reg_confirm_email_desc' => 'Εάν χρησιμοποιείται περιορισμός τομέα, τότε θα απαιτείται επιβεβαίωση μέσω email και αυτή η επιλογή θα αγνοηθεί.', + 'reg_confirm_restrict_domain' => 'Περιορισμός Τομέα', + 'reg_confirm_restrict_domain_desc' => 'Εισαγάγετε μια λίστα διαχωρισμένων με κόμματα τομέων email στους οποίους θέλετε να περιορίσετε την εγγραφή. Θα σταλεί στους χρήστες ένα email για να επιβεβαιώσουν τη διεύθυνσή τους πριν τους επιτραπεί να αλληλεπιδράσουν με την εφαρμογή.
Σημειώστε ότι οι χρήστες θα μπορούν να αλλάξουν τις διευθύνσεις email τους μετά την επιτυχή εγγραφή.', + 'reg_confirm_restrict_domain_placeholder' => 'Δε έχουν ρυθμιστεί περιορισμοί ακόμα', + + // Maintenance settings + 'maint' => 'Συντήρηση', + 'maint_image_cleanup' => 'Εκκαθάριση Εικόνων', + 'maint_image_cleanup_desc' => 'Σαρώνει το περιεχόμενο σελίδων και τις αναθεωρήσεις αυτών για να ελέγξει ποιες εικόνες και σχέδια χρησιμοποιούνται αυτήν τη στιγμή και ποιες είναι περιττές. Βεβαιωθείτε ότι έχετε δημιουργήσει ένα πλήρες αντίγραφο της βάση δεδομένων και των εικόνων προτού το εκτελέσετε.', + 'maint_delete_images_only_in_revisions' => 'Διαγράψτε επίσης εικόνες που υπάρχουν μόνο σε παλιές αναθεωρήσεις σελίδων', + 'maint_image_cleanup_run' => 'Εκτέλεση Εκκαθάρισης', + 'maint_image_cleanup_warning' => 'Βρέθηκαν :count δυνητικά αχρησιμοποίητες εικόνες. Είστε βέβαιοι ότι θέλετε να τις διαγράψετε αυτές;', + 'maint_image_cleanup_success' => ':count δυνητικά αχρησιμοποίητες εικόνες βρέθηκαν και διαγράφηκαν!', + 'maint_image_cleanup_nothing_found' => 'Δεν βρέθηκαν αχρησιμοποίητες εικόνες, τίποτα δεν διαγράφηκε!', + 'maint_send_test_email' => 'Στείλτε ένα δοκιμαστικό email', + 'maint_send_test_email_desc' => 'Αυτό στέλνει ένα δοκιμαστικό μήνυμα ηλεκτρονικού ταχυδρομείου στη διεύθυνση email σας που προσδιορίζεται στο προφίλ σας.', + 'maint_send_test_email_run' => 'Αποστολή δοκιμαστικού email', + 'maint_send_test_email_success' => 'Το email στάλθηκε στη διεύθυνση :address', + 'maint_send_test_email_mail_subject' => 'Δοκιμαστικό Email', + 'maint_send_test_email_mail_greeting' => 'Η παράδοση email φαίνεται να λειτουργεί!', + 'maint_send_test_email_mail_text' => 'Συγχαρητήρια! Καθώς λάβατε αυτήν την ειδοποίηση μέσω email, οι ρυθμίσεις email σας φαίνεται να έχουν διαμορφωθεί σωστά.', + 'maint_recycle_bin_desc' => 'Τα διαγραμμένα Ράφια και βιβλία, τα διαγραμμένα κεφάλαια και σελίδες αποστέλλονται στον κάδο ανακύκλωσης, έτσι ώστε να μπορούν να αποκατασταθούν ή να διαγραφούν οριστικά. Τα παλαιότερα αντικείμενα στον κάδο ανακύκλωσης ενδέχεται να αφαιρεθούν αυτόματα μετά από λίγο, ανάλογα με τη διαμόρφωση του συστήματος.', + 'maint_recycle_bin_open' => 'Άνοιγμα Κάδου Ανακύκλωσης', + 'maint_regen_references' => 'Αναδημιουργία Αναφορών', + 'maint_regen_references_desc' => 'Αυτή η ενέργεια θα ξαναχτίσει το ευρετήριο αναφοράς διαστοιχείου μέσα στη βάση δεδομένων. Αυτό συνήθως γίνεται αυτόματα αλλά αυτή η ενέργεια μπορεί να είναι χρήσιμη για το παλιό περιεχόμενο ή περιεχόμενο που προστίθεται μέσω ανεπίσημων μεθόδων.', + 'maint_regen_references_success' => 'Το ευρετήριο αναφοράς αναδημιουργήθηκε!', + 'maint_timeout_command_note' => 'Σημείωση: Αυτή η ενέργεια μπορεί να πάρει χρόνο για να εκτελεστεί, η οποία μπορεί να οδηγήσει σε προβλήματα χρονικού ορίου σε ορισμένα περιβάλλοντα ιστού. Ως εναλλακτική λύση, αυτή η ενέργεια πρέπει να εκτελείται χρησιμοποιώντας μια εντολή τερματικού.', + + // Recycle Bin + 'recycle_bin' => 'Κάδος Ανακύκλωσης', + 'recycle_bin_desc' => 'Εδώ μπορείτε να επαναφέρετε στοιχεία που έχουν διαγραφεί ή να επιλέξετε να τα αφαιρέσετε οριστικά από το σύστημα. Αυτή η λίστα δεν είναι φιλτραρισμένη όπως γίνεται σε παρόμοιες λίστες δραστηριοτήτων στο σύστημα στις οποίες εφαρμόζονται φίλτρα αδειών.', + 'recycle_bin_deleted_item' => 'Διαγραμμένο στοιχείο', + 'recycle_bin_deleted_parent' => 'Γονικό Στοιχείο', + 'recycle_bin_deleted_by' => 'Διαγράφηκε από', + 'recycle_bin_deleted_at' => 'Ημ/νια - Ώρα Διαγραφής', + 'recycle_bin_permanently_delete' => 'Οριστική Διαγραφή', + 'recycle_bin_restore' => 'Επαναφορά', + 'recycle_bin_contents_empty' => 'Ο κάδος ανακύκλωσης είναι επί του παρόντος άδειος', + 'recycle_bin_empty' => 'Αδειάστε τον Κάδο Ανακύκλωσης', + 'recycle_bin_empty_confirm' => 'Αυτό θα καταστρέψει οριστικά όλα τα αντικείμενα στον κάδο ανακύκλωσης, συμπεριλαμβανομένου του περιεχομένου που περιέχεται σε κάθε αντικείμενο. Είστε βέβαιοι ότι θέλετε να αδειάσετε τον κάδο ανακύκλωσης;', + 'recycle_bin_destroy_confirm' => 'Αυτή η ενέργεια θα διαγράψει οριστικά από το σύστημα αυτό το στοιχείο μαζί με τυχόν θυγατρικά, που αναφέρονται παρακάτω. Μετά την επιβεβαίωση της διαγραφής δεν θα μπορείτε να επαναφέρετε αυτό το περιεχόμενο. Είστε βέβαιοι ότι θέλετε να διαγράψετε οριστικά αυτό το στοιχείο;', + 'recycle_bin_destroy_list' => 'Αντικείμενα για καταστροφή', + 'recycle_bin_restore_list' => 'Αντικείμενα για επαναφορά', + 'recycle_bin_restore_confirm' => 'Αυτή η ενέργεια θα επαναφέρει το διαγραμμένο στοιχείο, συμπεριλαμβανομένων τυχόν θυγατρικών στοιχείων, στην αρχική τους θέση. Εάν η αρχική τοποθεσία έχει από τότε διαγραφεί και βρίσκεται τώρα στον κάδο ανακύκλωσης, θα πρέπει επίσης να αποκατασταθεί και το γονικό στοιχείο.', + 'recycle_bin_restore_deleted_parent' => 'Το γονικό στοιχείο αυτού του στοιχείου έχει επίσης διαγραφεί. Αυτά θα παραμείνουν διαγραμμένα μέχρι να αποκατασταθεί και αυτός ο γονέας.', + 'recycle_bin_restore_parent' => 'Επαναφορά Γονέα', + 'recycle_bin_destroy_notification' => 'Διαγράφηκαν :count συνολικά αντικείμενα από τον κάδο ανακύκλωσης.', + 'recycle_bin_restore_notification' => 'Επαναφέρθηκαν :count συνολικά αντικείμενα από τον κάδο ανακύκλωσης.', + + // Audit Log + 'audit' => 'Αρχείο Καταγραφής', + 'audit_desc' => 'Αυτό το αρχείο καταγραφής ελέγχου ενεργειών, εμφανίζει μια λίστα δραστηριοτήτων που παρακολουθούνται στο σύστημα. Αυτή η λίστα δεν είναι φιλτραρισμένη σε αντίθεση με παρόμοιες λίστες δραστηριοτήτων στο σύστημα όπου εφαρμόζονται φίλτρα αδειών.', + 'audit_event_filter' => 'Φίλτρο Συμβάντων', + 'audit_event_filter_no_filter' => 'Χωρίς Φίλτρο', + 'audit_deleted_item' => 'Διαγραμμένο στοιχείο', + 'audit_deleted_item_name' => 'Ονομα: :name', + 'audit_table_user' => 'Χρήστης', + 'audit_table_event' => 'Συμβάν', + 'audit_table_related' => 'Σχετικό Αντικείμενο ή Λεπτομέρεια', + 'audit_table_ip' => 'Διεύθυνση IP', + 'audit_table_date' => 'Ημερομηνία Δραστηριότητας', + 'audit_date_from' => 'Εύρος Ημερομηνίας Από', + 'audit_date_to' => 'Εύρος Ημερομηνίας Έως', + + // Role Settings + 'roles' => 'Ρόλοι', + 'role_user_roles' => 'Ρόλοι Χρηστών', + 'role_create' => 'Δημιουργία νέου ρόλου', + 'role_create_success' => 'Ο Ρόλος δημιουργήθηκε με επιτυχία', + 'role_delete' => 'Διαγραφή Ρόλου', + 'role_delete_confirm' => 'Αυτό θα διαγράψει τον ρόλο με το όνομα \':roleName\'.', + 'role_delete_users_assigned' => 'Σε αυτόν τον ρόλο έχουν εκχωρηθεί :userCount χρήστες. Εάν θέλετε να μετεγκαταστήσετε τους χρήστες από αυτόν τον ρόλο, επιλέξτε έναν νέο ρόλο παρακάτω.', + 'role_delete_no_migration' => "Μην μεταφέρετε χρήστες", + 'role_delete_sure' => 'Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτόν τον ρόλο;', + 'role_delete_success' => 'Ο ρόλος διαγράφηκε επιτυχώς', + 'role_edit' => 'Επεξεργασία Ρόλου', + 'role_details' => 'Λεπτομέρειες Ρόλου', + 'role_name' => 'Όνομα Ρόλου', + 'role_desc' => 'Σύντομη περιγραφή του Ρόλου', + 'role_mfa_enforced' => 'Απαιτεί έλεγχο ταυτότητας πολλαπλών παραγόντων', + 'role_external_auth_id' => 'Εξωτερικά αναγνωριστικά (IDs) ελέγχου ταυτότητας', + 'role_system' => 'Δικαιώματα Συστήματος', + 'role_manage_users' => 'Διαχείριση Χρηστών', + 'role_manage_roles' => 'Διαχείριση Ρόλων και Δικαιωμάτων ρόλων', + 'role_manage_entity_permissions' => 'Διαχειριστείτε όλα τα δικαιώματα βιβλίου, κεφαλαίων και σελίδων', + 'role_manage_own_entity_permissions' => 'Διαχειριστείτε τα δικαιώματα στο δικό σας βιβλίο, κεφάλαιο και σελίδες', + 'role_manage_page_templates' => 'Διαχείριση προτύπων σελίδων', + 'role_access_api' => 'Πρόσβαση στο API του συστήματος', + 'role_manage_settings' => 'Διαχειριστείτε τις ρυθμίσεις του ΑΡΙ', + 'role_export_content' => 'Εξαγωγή περιεχομένου', + 'role_editor_change' => 'Αλλαγή προγράμματος επεξεργασίας σελίδας', + 'role_asset' => 'Δικαιώματα Συστήματος', + 'roles_system_warning' => 'Λάβετε υπόψη ότι η πρόσβαση σε οποιοδήποτε από τις τρεις παραπάνω άδειες (δικαιώματα) μπορεί να επιτρέψει σε έναν χρήστη να αλλάξει τα δικά του προνόμια ή τα προνόμια άλλων στο σύστημα. Εκχωρήστε ρόλους με αυτά τα δικαιώματα μόνο σε αξιόπιστους χρήστες.', + 'role_asset_desc' => 'Αυτά τα δικαιώματα ελέγχουν την προεπιλεγμένη πρόσβαση στα στοιχεία (άδειες) εντός του συστήματος. Τα δικαιώματα σε Βιβλία, Κεφάλαια και Σελίδες θα παρακάμψουν αυτές τις άδειες.', + 'role_asset_admins' => 'Οι διαχειριστές έχουν αυτόματα πρόσβαση σε όλο το περιεχόμενο, αλλά αυτές οι επιλογές ενδέχεται να εμφανίζουν ή να αποκρύπτουν τις επιλογές διεπαφής χρήστη.', + 'role_asset_image_view_note' => 'Αυτό σχετίζεται με την ορατότητα εντός του διαχειριστή εικόνων. Η πραγματική πρόσβαση των μεταφορτωμένων αρχείων εικόνας θα εξαρτηθεί από την επιλογή αποθήκευσης εικόνας συστήματος.', + 'role_all' => 'Ολα', + 'role_own' => 'Τα δικά του', + 'role_controlled_by_asset' => 'Ελέγχονται από το στοιχείο στο οποίο ανεβαίνουν (Ράφια, Βιβλία)', + 'role_save' => 'Αποθήκευση Ρόλου', + 'role_update_success' => 'Ο Ρόλος ενημερώθηκε με επιτυχία', + 'role_users' => 'Χρήστες σε αυτόν τον Ρόλο', + 'role_users_none' => 'Σε κανένα χρήστη δεν έχει ανατεθεί αυτήν τη στιγμή αυτός ο ρόλος.', + + // Users + 'users' => 'Χρήστες', + 'user_profile' => 'Προφίλ Χρήστη', + 'users_add_new' => 'Προσθήκη νέου Χρήστη', + 'users_search' => 'Αναζήτηση Χρηστών', + 'users_latest_activity' => 'Τελευταία Δραστηριότητα', + 'users_details' => 'Στοιχεία χρήστη', + 'users_details_desc' => 'Ορίστε ένα εμφανιζόμενο όνομα και μια διεύθυνση email για αυτόν τον χρήστη. Η διεύθυνση email θα χρησιμοποιηθεί για τη σύνδεση στην εφαρμογή.', + 'users_details_desc_no_email' => 'Ορίστε το όνομα που θα εμφανίζεται για το χρήστη αυτόν, έτσι ώστε να είναι αναγνωρίσιμος από τους υπόλοιπους.', + 'users_role' => 'Ρόλοι χρήστη', + 'users_role_desc' => 'Επιλέξτε σε ποιους ρόλους θα εκχωρηθεί αυτός ο χρήστης. Εάν ένας χρήστης έχει εκχωρηθεί σε πολλούς ρόλους, τα δικαιώματα από αυτούς τους ρόλους θα στοιβάζονται και θα λαμβάνουν όλες τις ικανότητες των ρόλων που έχουν εκχωρηθεί.', + 'users_password' => 'Κωδικός Χρήστη', + 'users_password_desc' => 'Ορίστε έναν κωδικό πρόσβασης που θα χρησιμοποιείται για τη σύνδεση στην εφαρμογή. Αυτός πρέπει να είναι τουλάχιστον 8 χαρακτήρες.', + 'users_send_invite_text' => 'Μπορείτε να επιλέξετε να στείλετε σε αυτόν τον χρήστη ένα email πρόσκλησης που του επιτρέπει να ορίσει τον δικό του κωδικό πρόσβασης. Σε διαφορετική περίπτωση μπορείτε να ορίσετε τον κωδικό πρόσβασής του εσείς.', + 'users_send_invite_option' => 'Αποστολή email πρόσκλησης σε χρήστη', + 'users_external_auth_id' => 'Εξωτερικός έλεγχος ταυτότητας', + 'users_external_auth_id_desc' => 'Αυτό είναι το αναγνωριστικό που χρησιμοποιείται για την αντιστοίχιση αυτού του χρήστη κατά την επικοινωνία με το εξωτερικό σύστημα ελέγχου ταυτότητας.', + 'users_password_warning' => 'Συμπληρώστε τα παρακάτω μόνο αν θέλετε να αλλάξετε τον κωδικό πρόσβασής σας.', + 'users_system_public' => 'Αυτός ο χρήστης αντιπροσωπεύει οποιονδήποτε επισκέπτη που επισκέπτεται τη Βιβλιοθήκη σας. Δεν μπορεί να χρησιμοποιηθεί για τη σύνδεση αλλά εκχωρείται αυτόματα.', + 'users_delete' => 'Διαγραφή Χρήστη', + 'users_delete_named' => 'Διαγραφή χρήστη :userName', + 'users_delete_warning' => 'Αυτό θα διαγράψει πλήρως αυτόν τον χρήστη με το όνομα \':userName\' από το σύστημα.', + 'users_delete_confirm' => 'Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτόν τον χρήστη;', + 'users_migrate_ownership' => 'Μεταφορά ιδιοκτησίας', + 'users_migrate_ownership_desc' => 'Επιλέξτε έναν χρήστη εδώ, εάν θέλετε ένας άλλος χρήστης να γίνει ο κάτοχος όλων των στοιχείων που ανήκουν επί του παρόντος σε αυτόν τον χρήστη.', + 'users_none_selected' => 'Δεν έχει επιλεγεί χρήστης', + 'users_edit' => 'Επεξεργασία Χρήστη', + 'users_edit_profile' => 'Ρυθμίσεις προφίλ', + 'users_avatar' => 'Avatar Χρήστη', + 'users_avatar_desc' => 'Επιλέξτε μια εικόνα που θα αντιπροσωπεύει αυτόν τον χρήστη. Αυτό θα πρέπει να είναι περίπου 256px τετράγωνο.', + 'users_preferred_language' => 'Προτιμώμενη γλώσσα', + 'users_preferred_language_desc' => 'Αυτή η επιλογή θα αλλάξει τη γλώσσα που χρησιμοποιείται για τη διεπαφή χρήστη της εφαρμογής. Αυτό δεν θα επηρεάσει οποιοδήποτε περιεχόμενο που δημιουργήθηκε από χρήστες.', + 'users_social_accounts' => 'Λογαριασμοί Κοινωνικής δικτύωσης ', + 'users_social_accounts_info' => 'Εδώ μπορείτε να συνδέσετε τους άλλους λογαριασμούς σας για ταχύτερη και ευκολότερη σύνδεση. Η αποσύνδεση ενός λογαριασμού εδώ δεν ανακαλεί προηγουμένως εξουσιοδοτημένη πρόσβαση. Ανάκληση πρόσβασης από τις ρυθμίσεις προφίλ σας στον συνδεδεμένο κοινωνικό λογαριασμό.', + 'users_social_connect' => 'Σύνδεση λογαριασμού', + 'users_social_disconnect' => 'Αποσύνδεση λογαριασμού', + 'users_social_connected' => ':socialΛογαριασμός λογαριασμού συνδέθηκε με επιτυχία στο προφίλ σας.', + 'users_social_disconnected' => ':socialΛογαριασμός αποσυνδέθηκε επιτυχώς από το προφίλ σας.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'Δεν έχουν δημιουργηθεί διακριτικά API για αυτόν το χρήστη', + 'users_api_tokens_create' => 'Δημιουργία διακριτικού Api Token', + 'users_api_tokens_expires' => 'Λήγει', + 'users_api_tokens_docs' => 'Τεκμηρίωση API', + 'users_mfa' => 'Έλεγχος Ταυτοτητας Πολλαπλων Παραγοντων', + 'users_mfa_desc' => 'Ρυθμίστε τον έλεγχο ταυτότητας πολλαπλών παραγόντων ως ένα επιπλέον επίπεδο ασφάλειας για τον λογαριασμό χρήστη σας.', + 'users_mfa_x_methods' => ':count μέθοδος έχει ρυθμιστεί:count μέθοδοι', + 'users_mfa_configure' => 'Ρύθμιση Μεθόδων', + + // API Tokens + 'user_api_token_create' => 'Δημιουργία διακριτικού (API Token)', + 'user_api_token_name' => 'Όνομα', + 'user_api_token_name_desc' => 'Δώστε στο διακριτικό σας ένα ευανάγνωστο όνομα ως μελλοντική υπενθύμιση του σκοπού του.', + 'user_api_token_expiry' => 'Ημερομηνία λήξης', + 'user_api_token_expiry_desc' => 'Ορίστε μια ημερομηνία κατά την οποία λήγει αυτό το διακριτικό. Μετά από αυτήν την ημερομηνία, τα αιτήματα που γίνονται με αυτό το διακριτικό δεν θα λειτουργούν πλέον. Αν αφήσετε αυτό το πεδίο κενό, θα οριστεί η λήξη 100 χρόνια στο μέλλον.', + 'user_api_token_create_secret_message' => 'Αμέσως μετά τη δημιουργία αυτού του διακριτικού θα δημιουργηθεί και θα εμφανιστεί ένα "Token ID" & "Token Secret". Το μυστικό(Token Secret) θα εμφανιστεί μόνο μία φορά, επομένως φροντίστε να αντιγράψετε την τιμή σε κάποιο ασφαλές μέρος πριν συνεχίσετε.', + 'user_api_token_create_success' => 'Το διακριτικό API δημιουργήθηκε με επιτυχία', + 'user_api_token_update_success' => 'Το διακριτικό API ενημερώθηκε με επιτυχία', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'Αυτό είναι ένα μη επεξεργάσιμο αναγνωριστικό που δημιουργείται από το σύστημα για αυτό το διακριτικό, το οποίο θα πρέπει να παρέχεται σε αιτήματα API.', + 'user_api_token_secret' => 'Μυστικό Token', + 'user_api_token_secret_desc' => 'Αυτό είναι ένα μυστικό που δημιουργείται από το σύστημα για αυτό το διακριτικό και θα πρέπει να παρέχεται σε αιτήματα API. Αυτό θα εμφανιστεί μόνο μία φορά, επομένως αντιγράψτε αυτήν την τιμή σε κάποιο ασφαλές μέρος.', + 'user_api_token_created' => 'Το Διακριτικό δημιουργήθηκε :timeAgo', + 'user_api_token_updated' => 'Το Διακριτικό ενημερώθηκε :timeAgo', + 'user_api_token_delete' => 'Διαγραφή Διακριτικού', + 'user_api_token_delete_warning' => 'Αυτό θα διαγράψει πλήρως αυτό το διακριτικό API με το όνομα \':tokenName\' από το σύστημα.', + 'user_api_token_delete_confirm' => 'Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτό το διακριτικό API;', + 'user_api_token_delete_success' => 'Το διακριτικό API διαγράφηκε με επιτυχία', + + // Webhooks + 'webhooks' => 'Webhooks', + 'webhooks_create' => 'Δημιουργία νέου Webhook', + 'webhooks_none_created' => 'Δεν έχουν δημιουργηθεί ακόμη webhook.', + 'webhooks_edit' => 'Επεξεργασία Webhook', + 'webhooks_save' => 'Αποθήκευση Webhook', + 'webhooks_details' => 'Λεπτομέρειες Webhook', + 'webhooks_details_desc' => 'Παρέχετε ένα φιλικό προς τον χρήστη όνομα και ένα τελικό σημείο POST ως τοποθεσία για την αποστολή των δεδομένων webhook.', + 'webhooks_events' => 'Συμβάντα Webhook', + 'webhooks_events_desc' => 'Επιλέξτε όλα τα συμβάντα που θα πρέπει να ενεργοποιήσουν αυτό το webhook για κλήση.', + 'webhooks_events_warning' => 'Λάβετε υπόψη ότι αυτά τα συμβάντα θα ενεργοποιηθούν για όλα τα επιλεγμένα συμβάντα, ακόμη και αν εφαρμοστούν προσαρμοσμένα δικαιώματα. Βεβαιωθείτε ότι η χρήση αυτού του webhook δεν θα αποκαλύψει εμπιστευτικό περιεχόμενο.', + 'webhooks_events_all' => 'Όλα τα συμβάντα του συστήματος', + 'webhooks_name' => 'Όνομα Webhook', + 'webhooks_timeout' => 'Χρονικό όριο λήξης αιτήματος Webhook (δευτερόλεπτα)', + 'webhooks_endpoint' => 'Τελικό Σημείο Webhook', + 'webhooks_active' => 'Webhook Ενεργό', + 'webhook_events_table_header' => 'Συμβάντα', + 'webhooks_delete' => 'Διαγραφή Webhook', + 'webhooks_delete_warning' => 'Αυτό θα διαγράψει πλήρως αυτό το webhook, με το όνομα \':webhookName\', από το σύστημα.', + 'webhooks_delete_confirm' => 'Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτό το webhook;', + 'webhooks_format_example' => 'Παράδειγμα μορφής Webhook', + 'webhooks_format_example_desc' => 'Τα δεδομένα Webhook αποστέλλονται ως αίτημα POST στο διαμορφωμένο τελικό σημείο ως JSON ακολουθώντας την παρακάτω μορφή. Οι ιδιότητες "related_item" και "url" είναι προαιρετικές και εξαρτώνται από τον τύπο του συμβάντος που ενεργοποιείται.', + 'webhooks_status' => 'Κατάσταση Webhook', + 'webhooks_last_called' => 'Τελευταία κλήση:', + 'webhooks_last_errored' => 'Τελευταίο σφάλμα:', + 'webhooks_last_error_message' => 'Τελευταίο μήνυμα λάθους:', + + + //! If editing translations files directly please ignore this in all + //! languages apart from en. Content will be auto-copied from en. + //!//////////////////////////////// + 'language_select' => [ + 'en' => 'English', + 'ar' => 'العربية', + 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', + 'cs' => 'Česky', + 'da' => 'Dansk', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'et' => 'Eesti keel', + 'eu' => 'Euskara', + 'fa' => 'فارسی', + 'fr' => 'Français', + 'he' => 'עברית', + 'hr' => 'Hrvatski', + 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', + 'it' => 'Italian', + 'ja' => '日本語', + 'ko' => '한국어', + 'lt' => 'Lietuvių Kalba', + 'lv' => 'Latviešu Valoda', + 'nl' => 'Nederlands', + 'nb' => 'Norsk (Bokmål)', + 'pl' => 'Polski', + 'pt' => 'Português', + 'pt_BR' => 'Português do Brasil', + 'ro' => 'Română', + 'ru' => 'Русский', + 'sk' => 'Slovensky', + 'sl' => 'Slovenščina', + 'sv' => 'Svenska', + 'tr' => 'Türkçe', + 'uk' => 'Українська', + 'vi' => 'Tiếng Việt', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + ], + //!//////////////////////////////// +]; diff --git a/resources/lang/el/validation.php b/resources/lang/el/validation.php new file mode 100644 index 000000000..be96cd0ca --- /dev/null +++ b/resources/lang/el/validation.php @@ -0,0 +1,117 @@ + 'Το :attribute πρέπει να γίνει δεκτό.', + 'active_url' => 'Το :attribute δεν είναι ένα έγκυρο URL.', + 'after' => 'Το :attribute πρέπει να είναι μια ημερομηνία μετά τις :date.', + 'alpha' => 'Το :attribute μπορεί να περιέχει μόνο γράμματα.', + 'alpha_dash' => 'Tο :attribute μπορεί να περιλαμβάνει μόνο γράμματα, αριθμούς, παύλες και κάτω παύλες.', + 'alpha_num' => 'Tο :attribute μπορεί να περιλαμβάνει μόνο γράμματα και αριθμούς.', + 'array' => 'Το :attribute πρέπει να είναι πίνακας.', + 'backup_codes' => 'Ο παρεχόμενος κωδικός δεν είναι έγκυρος ή έχει ήδη χρησιμοποιηθεί.', + 'before' => 'Tο :attribute πρέπει να είναι μια ημερομηνία πριν από :date.', + 'between' => [ + 'numeric' => 'Το :attribute πρέπει να είναι μεταξύ :min και :max.', + 'file' => 'Το :attribute πρέπει να είναι μεταξύ :min και :max kilobytes.', + 'string' => 'Το πεδίο :attribute πρέπει να είναι μεταξύ από :min και :max characters.', + 'array' => 'Το πεδίο :attribute πρέπει να είναι μεταξύ :min και :max αντικείμενα.', + ], + 'boolean' => 'Το πεδίο :attribute πρέπει να είναι σωστό ή λάθος.', + 'confirmed' => 'Η επιβεβαίωση του :attribute δεν ταιριάζει.', + 'date' => 'Το :attribute δεν έχει έγκυρη ημερομηνία.', + 'date_format' => 'Το :attribute δεν ταιριάζει με τη μορφή :format.', + 'different' => 'Τα πεδία :attribute και :other πρέπει να είναι διαφορετικά.', + 'digits' => 'Το πεδίο :attribute πρέπει να είναι :digits ψηφία.', + 'digits_between' => 'To :attribute πρέπει να είναι μεταξύ :min και :max ψηφία.', + 'email' => 'Το πεδίο :attribute πρέπει να είναι μία έγκυρη διεύθυνση E-mail.', + 'ends_with' => 'Το :attribute πρέπει να τελειώνει με μια απο τις ακόλουθες: :values', + 'file' => 'Το :attribute πρέπει να παρέχεται ως έγκυρο αρχείο.', + 'filled' => 'Το πεδίο :attribute είναι υποχρεωτικό.', + 'gt' => [ + 'numeric' => 'Το :attribute πρέπει να είναι μεγαλύτερο από :value.', + 'file' => 'To :attribute πρέπει να είναι μεγαλύτερο από :value kilobytes.', + 'string' => 'Tο :attribute πρέπει να έχει περισσότερους από :value χαρακτήρες.', + 'array' => 'Το :attribute πρέπει να περιέχει περισσότερα από :value αντικείμενα.', + ], + 'gte' => [ + 'numeric' => 'Το :attribute πρέπει να είναι μεγαλύτερο ή ίσο από :value.', + 'file' => 'Το :attribute πρέπει να είναι μεγαλύτερο ή ίσο με :value kilobytes.', + 'string' => 'To :attribute πρέπει να είναι μεγαλύτερο ή ίσο από :value χαρακτήρες.', + 'array' => 'Tο :attribute πρέπει να έχει :value αντικείμενα ή περισσότερα.', + ], + 'exists' => 'Το επιλεγμένο :attribute δεν είναι έγκυρο.', + 'image' => 'Tο :attribute πρέπει να είναι εικόνα.', + 'image_extension' => 'Το πεδίο :attribute πρέπει να έχει μια έγκυρη & υποστηριζόμενη επέκταση εικόνας.', + 'in' => 'Το επιλεγμένο :attribute δεν είναι έγκυρο.', + 'integer' => 'Tο :attribute πρέπει να είναι ακέραιος αριθμός.', + 'ip' => 'Το πεδίο :attribute πρέπει να είναι μία έγκυρη διεύθυνση IP.', + 'ipv4' => 'Tο :attribute πρέπει να είναι μια έγκυρη διεύθυνση IPv4.', + 'ipv6' => 'Tο :attribute πρέπει να είναι μια έγκυρη διεύθυνση IPv6.', + 'json' => 'H :attribute πρεπει να είναι μια έγκυρη συμβολοσειρά JSON.', + 'lt' => [ + 'numeric' => 'Tο :attribute πρέπει να είναι λιγότερο από :value.', + 'file' => 'To :attribute πρέπει να είναι μικρότερο από :value kilobytes.', + 'string' => 'To :attribute πρέπει να είναι μικρότερο από :value kilobytes.', + 'array' => 'Tο :attribute πρέπει να έχει λιγότερα από :value αντικείμενα.', + ], + 'lte' => [ + 'numeric' => 'Το :attribute πρέπει να είναι μικρότερο ή ίσο του :value.', + 'file' => 'Το :attribute πρέπει να είναι μικρότερο ή ίσο του :value kilobytes.', + 'string' => 'Tο :attribute πρέπει να έχει λιγότερους από ή ίδιους :value χαρακτήρες.', + 'array' => 'Tο :attribute δεν πρέπει να έχει περισσότερα από :value αντικείμενα.', + ], + 'max' => [ + 'numeric' => 'Tο :attribute δεν μπορεί να είναι μεγαλύτερο από :max.', + 'file' => 'To :attribute δεν μπορεί να είναι μεγαλύτερο από :max kilobytes.', + 'string' => 'Το :attribute δεν μπορεί να είναι μεγαλύτερο από :max χαρακτήρες.', + 'array' => 'Tο :attribute δεν μπορεί να έχει περισσότερα από :max αντικείμενα.', + ], + 'mimes' => 'Το πεδίο :attribute πρέπει να είναι ένα αρχείου τύπου: :values.', + 'min' => [ + 'numeric' => 'To :attribute πρέπει να είναι τουλάχιστον :min.', + 'file' => 'Το :attribute πρέπει είναι τουλάχιστον :min kilobytes.', + 'string' => 'Το :attribute πρέπει να είναι τουλάχιστον :min χαρακτήρες.', + 'array' => 'To :attribute πρέπει να έχει τουλάχιστον :min αντικείμενα.', + ], + 'not_in' => 'Το επιλεγμένο :attribute δεν είναι έγκυρο.', + 'not_regex' => 'Η μορφή του :attribute δεν είναι έγκυρη.', + 'numeric' => 'To :attribute πρέπει να είναι αριθμός.', + 'regex' => 'Το :attribute έχει μη έγκυρη μορφή.', + 'required' => 'Το πεδίο :attribute είναι υποχρεωτικό.', + 'required_if' => 'To πεδίο :attribute είναι απαραίτητο εκτός αν :other είναι σε :values.', + 'required_with' => 'To πεδίο :attribute είναι απαραίτητο όταν υπάρχουν οι :values.', + 'required_with_all' => 'To πεδίο :attribute είναι απαραίτητο όταν υπάρχουν οι :values.', + 'required_without' => 'To πεδίο :attribute είναι απαραίτητο όταν δεν υπάρχουν οι :values.', + 'required_without_all' => 'To πεδίο :attribute είναι απαραίτητο όταν δεν υπάρχουν καμία από :values.', + 'same' => 'Το πεδίο :attribute και :other πρέπει να είναι ίδια.', + 'safe_url' => 'Ο παρεχόμενος σύνδεσμος μπορεί να μην είναι ασφαλής.', + 'size' => [ + 'numeric' => 'Το :attribute πρέπει να είναι :size.', + 'file' => 'Το :attribute πρέπει να έχει μέγεθος :size kilobytes.', + 'string' => 'Το πεδίο :attribute πρέπει να είναι :size χαρακτήρες.', + 'array' => 'Το πεδίο :attribute πρέπει να περιέχει :size αντικείμενα.', + ], + 'string' => 'Το :attribute πρέπει να είναι συμβολοσειρά.', + 'timezone' => 'Το πεδίο :attribute πρέπει να είναι μία έγκυρη ζώνη ώρας.', + 'totp' => 'Ο παρεχόμενος κωδικός δεν είναι έγκυρος ή έχει λήξει.', + 'unique' => 'Το πεδίο :attribute έχει ήδη χρησιμοποιηθεί.', + 'url' => 'Η μορφή του :attribute δεν είναι έγκυρη.', + 'uploaded' => 'Δεν ήταν δυνατή η αποστολή του αρχείου. Ο διακομιστής ενδέχεται να μην δέχεται αρχεία αυτού του μεγέθους.', + + // Custom validation lines + 'custom' => [ + 'password-confirm' => [ + 'required_with' => 'Απαιτείται επιβεβαίωση κωδικού πρόσβασης', + ], + ], + + // Custom validation attributes + 'attributes' => [], +]; diff --git a/resources/lang/en/editor.php b/resources/lang/en/editor.php index da7ffcf01..faf351da2 100644 --- a/resources/lang/en/editor.php +++ b/resources/lang/en/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Insert/Edit Link', 'insert_horizontal_line' => 'Insert horizontal line', 'insert_code_block' => 'Insert code block', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Insert/edit drawing', 'drawing_manager' => 'Drawing manager', 'insert_media' => 'Insert/edit media', diff --git a/resources/lang/en/entities.php b/resources/lang/en/entities.php index 1720801d2..bf6201900 100644 --- a/resources/lang/en/entities.php +++ b/resources/lang/en/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Permissions', - 'permissions_intro' => 'Once enabled, These permissions will take priority over any set role permissions.', - 'permissions_enable' => 'Enable Custom Permissions', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Save Permissions', 'permissions_owner' => 'Owner', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Search Results', diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index e2a22ee37..1ad271e7c 100755 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -280,6 +280,7 @@ return [ 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', + 'el' => 'ελληνικά', 'es' => 'Español', 'es_AR' => 'Español Argentina', 'et' => 'Eesti keel', diff --git a/resources/lang/es/editor.php b/resources/lang/es/editor.php index 951090a67..ed77927f4 100644 --- a/resources/lang/es/editor.php +++ b/resources/lang/es/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Insertar/Editar enlace', 'insert_horizontal_line' => 'Insertar línea horizontal', 'insert_code_block' => 'Insertar bloque de código', + 'edit_code_block' => 'Editar bloque de código', 'insert_drawing' => 'Insertar/editar dibujo', 'drawing_manager' => 'Gestor de dibujo', 'insert_media' => 'Insertar/editar medios', diff --git a/resources/lang/es/entities.php b/resources/lang/es/entities.php index d7f9e5c4f..2887e2cc6 100644 --- a/resources/lang/es/entities.php +++ b/resources/lang/es/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Permisos', - 'permissions_intro' => 'Una vez habilitado, estos permisos tendrán prioridad por encima de cualquier permiso establecido.', - 'permissions_enable' => 'Habilitar permisos personalizados', + 'permissions_desc' => 'Establezca los permisos aquí para anular los permisos por defecto proporcionados por los roles de usuario.', + 'permissions_book_cascade' => 'Los permisos establecidos en los libros se aplicarán a sus capítulos y páginas, a menos que tengan sus propios permisos definidos.', + 'permissions_chapter_cascade' => 'Los permisos establecidos en los capítulos se aplicarán a sus páginas, a menos que tengan sus propios permisos definidos.', 'permissions_save' => 'Guardar permisos', 'permissions_owner' => 'Propietario', + 'permissions_role_everyone_else' => 'Todos los demás', + 'permissions_role_everyone_else_desc' => 'Establecer permisos para todos los roles sin permisos específicos asignados.', + 'permissions_role_override' => 'Reemplazar permisos para el rol', // Search 'search_results' => 'Resultados de búsqueda', diff --git a/resources/lang/es_AR/editor.php b/resources/lang/es_AR/editor.php index 93d974543..269b9e262 100644 --- a/resources/lang/es_AR/editor.php +++ b/resources/lang/es_AR/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Insertar/Editar Enlace', 'insert_horizontal_line' => 'Insertar línea horizontal', 'insert_code_block' => 'Insertar bloque de código', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Insertar/editar dibujo', 'drawing_manager' => 'Gestor de dibujo', 'insert_media' => 'Insertar/editar media', diff --git a/resources/lang/es_AR/entities.php b/resources/lang/es_AR/entities.php index 9940f3cce..87075ac10 100644 --- a/resources/lang/es_AR/entities.php +++ b/resources/lang/es_AR/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Permisos', - 'permissions_intro' => 'una vez habilitado, Estos permisos tendrán prioridad por encima de cualquier permiso establecido.', - 'permissions_enable' => 'Habilitar permisos custom', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Guardar permisos', 'permissions_owner' => 'Propietario', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Buscar resultados', diff --git a/resources/lang/et/editor.php b/resources/lang/et/editor.php index 631fbf9d3..996cbad90 100644 --- a/resources/lang/et/editor.php +++ b/resources/lang/et/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Sisesta/muuda linki', 'insert_horizontal_line' => 'Sisesta vahejoon', 'insert_code_block' => 'Sisesta koodiplokk', + 'edit_code_block' => 'Muuda koodiplokki', 'insert_drawing' => 'Sisesta/muuda joonist', 'drawing_manager' => 'Jooniste haldur', 'insert_media' => 'Sisesta/muuda meediat', diff --git a/resources/lang/et/entities.php b/resources/lang/et/entities.php index 2f2f7110a..8168b90f6 100644 --- a/resources/lang/et/entities.php +++ b/resources/lang/et/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Õigused', - 'permissions_intro' => 'Kui kohandatud õigused on lubatud, rakendatakse neid eelisjärjekorras, enne rolli õiguseid.', - 'permissions_enable' => 'Luba kohandatud õigused', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Salvesta õigused', 'permissions_owner' => 'Omanik', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Otsingutulemused', diff --git a/resources/lang/eu/editor.php b/resources/lang/eu/editor.php index 2d49d77b0..f951d6292 100644 --- a/resources/lang/eu/editor.php +++ b/resources/lang/eu/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Txertatu/Aldatu esteka', 'insert_horizontal_line' => 'Txertatu linea horizontala', 'insert_code_block' => 'Txertatu kode-blokea', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Txertatu marrazki berria', 'drawing_manager' => 'Marrazki kudeaketa', 'insert_media' => 'Txertatu/aldatu media', diff --git a/resources/lang/eu/entities.php b/resources/lang/eu/entities.php index 0ec16d947..dc96ca17c 100644 --- a/resources/lang/eu/entities.php +++ b/resources/lang/eu/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Baimenak', - 'permissions_intro' => 'Behin hau aktibatuta, baimen hauek lehentasuna izango dute beste edozein rol-engainetik.', - 'permissions_enable' => 'Baimena pertsonalizatuak Gaitu', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Gorde baimenak', 'permissions_owner' => 'Jabea', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Bilaketaren emaitzak', diff --git a/resources/lang/fa/editor.php b/resources/lang/fa/editor.php index fbab475ed..e7071498c 100644 --- a/resources/lang/fa/editor.php +++ b/resources/lang/fa/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'افزودن/ویرایش پیوند', 'insert_horizontal_line' => 'افزودن خط افقی', 'insert_code_block' => 'افزودن بلوک کد', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'افزودن/ویرایش طرح', 'drawing_manager' => 'مدیریت طراحی', 'insert_media' => 'افزودن/ویرایش رسانه', diff --git a/resources/lang/fa/entities.php b/resources/lang/fa/entities.php index 8bbb33d67..416e868c5 100644 --- a/resources/lang/fa/entities.php +++ b/resources/lang/fa/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'مجوزها', - 'permissions_intro' => 'پس از فعال شدن، این مجوزها نسبت به مجوزهای تعیین شده نقش اولویت دارند.', - 'permissions_enable' => 'مجوزهای سفارشی را فعال کنید', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'ذخيره مجوزها', 'permissions_owner' => 'مالک', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'نتایج جستجو', @@ -136,7 +140,7 @@ return [ 'books_search_this' => 'این کتاب را جستجو کنید', 'books_navigation' => 'ناوبری کتاب', 'books_sort' => 'مرتب سازی مطالب کتاب', - 'books_sort_named' => 'مرتب سازی کتاب:bookName', + 'books_sort_named' => 'مرتب‌سازی کتاب:bookName', 'books_sort_name' => 'مرتب سازی بر اساس نام', 'books_sort_created' => 'مرتب سازی بر اساس تاریخ ایجاد', 'books_sort_updated' => 'مرتب سازی بر اساس تاریخ به روز رسانی', diff --git a/resources/lang/fr/editor.php b/resources/lang/fr/editor.php index 81a9b42fa..4c51f5cfe 100644 --- a/resources/lang/fr/editor.php +++ b/resources/lang/fr/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Insérer/Modifier un lien', 'insert_horizontal_line' => 'Insérer une ligne horizontale', 'insert_code_block' => 'Insérer un bloc de code', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Insérer/modifier un dessin', 'drawing_manager' => 'Gestionnaire de dessin', 'insert_media' => 'Insérer/modifier un média', diff --git a/resources/lang/fr/entities.php b/resources/lang/fr/entities.php index 4abd2d050..09b71d7ee 100644 --- a/resources/lang/fr/entities.php +++ b/resources/lang/fr/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Autorisations', - '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_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Enregistrer les permissions', 'permissions_owner' => 'Propriétaire', + 'permissions_role_everyone_else' => 'Tous les autres', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Remplacer les permissions pour le rôle', // Search 'search_results' => 'Résultats de recherche', diff --git a/resources/lang/he/editor.php b/resources/lang/he/editor.php index 659937ecc..6184ec00a 100644 --- a/resources/lang/he/editor.php +++ b/resources/lang/he/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Insert/Edit Link', 'insert_horizontal_line' => 'Insert horizontal line', 'insert_code_block' => 'Insert code block', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Insert/edit drawing', 'drawing_manager' => 'Drawing manager', 'insert_media' => 'Insert/edit media', diff --git a/resources/lang/he/entities.php b/resources/lang/he/entities.php index 1e073b1e4..399a01027 100644 --- a/resources/lang/he/entities.php +++ b/resources/lang/he/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'הרשאות', - 'permissions_intro' => 'ברגע שמסומן, הרשאות אלו יגברו על כל הרשאת תפקיד שקיימת', - 'permissions_enable' => 'הפעל הרשאות מותאמות אישית', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'שמור הרשאות', 'permissions_owner' => 'בעלים', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'תוצאות חיפוש', diff --git a/resources/lang/hr/editor.php b/resources/lang/hr/editor.php index da7ffcf01..faf351da2 100644 --- a/resources/lang/hr/editor.php +++ b/resources/lang/hr/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Insert/Edit Link', 'insert_horizontal_line' => 'Insert horizontal line', 'insert_code_block' => 'Insert code block', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Insert/edit drawing', 'drawing_manager' => 'Drawing manager', 'insert_media' => 'Insert/edit media', diff --git a/resources/lang/hr/entities.php b/resources/lang/hr/entities.php index db7eb45d3..32718562e 100644 --- a/resources/lang/hr/entities.php +++ b/resources/lang/hr/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Dopuštenja', - 'permissions_intro' => 'Jednom postavljene, ove dozvole bit će prioritetne ostalim dopuštenjima.', - 'permissions_enable' => 'Omogući dopuštenje za korištenje', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Spremi dopuštenje', 'permissions_owner' => 'Vlasnik', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Pretraži rezultate', diff --git a/resources/lang/hu/editor.php b/resources/lang/hu/editor.php index d44a83c87..828dea6e1 100644 --- a/resources/lang/hu/editor.php +++ b/resources/lang/hu/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Hivatkozás Beszúrása/Szerkesztése', 'insert_horizontal_line' => 'Vízszintes vonal beszúrása', 'insert_code_block' => 'Kódrészlet beszúrása', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Rajz beszúrása/szerkesztése', 'drawing_manager' => 'Rajzkezelő', 'insert_media' => 'Media beszúrása/szerkesztése', diff --git a/resources/lang/hu/entities.php b/resources/lang/hu/entities.php index 22e4e54c8..55c1524ed 100644 --- a/resources/lang/hu/entities.php +++ b/resources/lang/hu/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Jogosultságok', - 'permissions_intro' => 'Ha engedélyezett, ezek a jogosultságok elsőbbséget élveznek bármely beállított szerepkör jogosultsággal szemben.', - 'permissions_enable' => 'Egyéni jogosultságok engedélyezése', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Jogosultságok mentése', 'permissions_owner' => 'Tulajdonos', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Keresési eredmények', diff --git a/resources/lang/id/editor.php b/resources/lang/id/editor.php index 57a1daa5b..42a7b10c5 100644 --- a/resources/lang/id/editor.php +++ b/resources/lang/id/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Insert/Edit Link', 'insert_horizontal_line' => 'Insert horizontal line', 'insert_code_block' => 'Insert code block', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Insert/edit drawing', 'drawing_manager' => 'Drawing manager', 'insert_media' => 'Insert/edit media', diff --git a/resources/lang/id/entities.php b/resources/lang/id/entities.php index 9c52ddcd8..db2d7f8b9 100644 --- a/resources/lang/id/entities.php +++ b/resources/lang/id/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Izin', - 'permissions_intro' => 'Setelah diaktifkan, izin ini akan menjadi prioritas di atas izin peran yang ditetapkan.', - 'permissions_enable' => 'Aktifkan Izin Kustom', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Simpan Izin', 'permissions_owner' => 'Pemilik', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Hasil Pencarian', diff --git a/resources/lang/it/editor.php b/resources/lang/it/editor.php index 240a540da..39ea9fefb 100644 --- a/resources/lang/it/editor.php +++ b/resources/lang/it/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Inserisci/Modifica Collegamento', 'insert_horizontal_line' => 'Inserisci Riga Orizzontale', 'insert_code_block' => 'Inserisci blocco di codice', + 'edit_code_block' => 'Modifica blocco di codice', 'insert_drawing' => 'Inserisci/Modifica Disegno', 'drawing_manager' => 'Gestore disegni', 'insert_media' => 'Inserisci/modifica media', diff --git a/resources/lang/it/entities.php b/resources/lang/it/entities.php index 7c31412ad..41b792a7d 100755 --- a/resources/lang/it/entities.php +++ b/resources/lang/it/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Permessi', - 'permissions_intro' => 'Una volta abilitati, questi permessi avranno la priorità su tutti gli altri.', - 'permissions_enable' => 'Abilita Permessi Custom', + 'permissions_desc' => 'Imposta qui i permessi per sovrascrivere i permessi predefiniti forniti dai ruoli utente.', + 'permissions_book_cascade' => 'I permessi impostati sui libri si trasmettono automaticamente a cascata ai capitoli e alle pagine figli, a meno che non siano stati definiti permessi propri.', + 'permissions_chapter_cascade' => 'I permessi impostati sui capitoli si trasmettono automaticamente a cascata alle pagine figlie, a meno che non siano stati definiti permessi propri.', 'permissions_save' => 'Salva Permessi', 'permissions_owner' => 'Proprietario', + 'permissions_role_everyone_else' => 'Tutti Gli Altri', + 'permissions_role_everyone_else_desc' => 'Imposta i permessi per tutti i ruoli non specificamente sovrascritti.', + 'permissions_role_override' => 'Sovrascrivere i permessi per il ruolo', // Search 'search_results' => 'Risultati Ricerca', diff --git a/resources/lang/ja/editor.php b/resources/lang/ja/editor.php index 839906e88..0e13bb907 100644 --- a/resources/lang/ja/editor.php +++ b/resources/lang/ja/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'リンクの挿入・編集', 'insert_horizontal_line' => '水平線を挿入', 'insert_code_block' => 'コードブロックを挿入', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => '描画を挿入・編集', 'drawing_manager' => '描画マネージャー', 'insert_media' => 'メディアの挿入・編集', diff --git a/resources/lang/ja/entities.php b/resources/lang/ja/entities.php index fb47fbe7f..ab0774d43 100644 --- a/resources/lang/ja/entities.php +++ b/resources/lang/ja/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => '権限', - 'permissions_intro' => 'この設定は各ユーザの役割よりも優先して適用されます。', - 'permissions_enable' => 'カスタム権限設定を有効にする', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => '権限を保存', 'permissions_owner' => '所有者', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => '検索結果', diff --git a/resources/lang/ko/activities.php b/resources/lang/ko/activities.php index debd373af..ab7a46d0f 100644 --- a/resources/lang/ko/activities.php +++ b/resources/lang/ko/activities.php @@ -38,14 +38,14 @@ return [ 'book_sort_notification' => '책 정렬 바꿈', // Bookshelves - 'bookshelf_create' => 'created shelf', - 'bookshelf_create_notification' => 'Shelf successfully created', - 'bookshelf_create_from_book' => 'converted book to shelf', + 'bookshelf_create' => '책꽃이 만들기', + 'bookshelf_create_notification' => '책꽃이 생성 완료', + 'bookshelf_create_from_book' => '책을 책꽃이로 변환', 'bookshelf_create_from_book_notification' => '책을 책꽂이로 변환했습니다.', - 'bookshelf_update' => 'updated shelf', - 'bookshelf_update_notification' => 'Shelf successfully updated', - 'bookshelf_delete' => 'deleted shelf', - 'bookshelf_delete_notification' => 'Shelf successfully deleted', + 'bookshelf_update' => '책꽃이 업데이트', + 'bookshelf_update_notification' => '책꽃이가 업데이트되었습니다', + 'bookshelf_delete' => '선반 삭제', + 'bookshelf_delete_notification' => '책꽃이가 삭제되었습니다.', // Favourites 'favourite_add_notification' => '":name" 북마크에 추가함', diff --git a/resources/lang/ko/editor.php b/resources/lang/ko/editor.php index 11a164d8c..c86f56bb8 100644 --- a/resources/lang/ko/editor.php +++ b/resources/lang/ko/editor.php @@ -41,7 +41,7 @@ return [ 'callout_warning' => '경고', 'callout_danger' => '위험', 'bold' => '굵게', - 'italic' => '기울임', + 'italic' => '기울임체', 'underline' => '밑줄', 'strikethrough' => '취소선', 'superscript' => '윗첨자', @@ -59,58 +59,59 @@ return [ 'list_task' => '작업 목록', 'indent_increase' => '들여쓰기 증가', 'indent_decrease' => '들여쓰기 감소', - 'table' => 'Table', - 'insert_image' => 'Insert image', - 'insert_image_title' => 'Insert/Edit Image', - 'insert_link' => 'Insert/edit link', - 'insert_link_title' => 'Insert/Edit Link', - 'insert_horizontal_line' => 'Insert horizontal line', - 'insert_code_block' => 'Insert code block', - 'insert_drawing' => 'Insert/edit drawing', - 'drawing_manager' => 'Drawing manager', - 'insert_media' => 'Insert/edit media', - 'insert_media_title' => 'Insert/Edit Media', - 'clear_formatting' => 'Clear formatting', - 'source_code' => 'Source code', - 'source_code_title' => 'Source Code', - 'fullscreen' => 'Fullscreen', - 'image_options' => 'Image options', + 'table' => '테이블', + 'insert_image' => '이미지 삽입', + 'insert_image_title' => '이미지 삽입/수정', + 'insert_link' => '링크 삽입/수정', + 'insert_link_title' => '링크 삽입/수정', + 'insert_horizontal_line' => '수평선 삽입', + 'insert_code_block' => '코드 블럭 삽입', + 'edit_code_block' => 'Edit code block', + 'insert_drawing' => '그리기 삽입/수정', + 'drawing_manager' => '그리기 설정', + 'insert_media' => '미디어 삽입/수정', + 'insert_media_title' => '미디어 삽입/수정', + 'clear_formatting' => '양식 초기화', + 'source_code' => '소스 코드', + 'source_code_title' => '소스 코드', + 'fullscreen' => '전체화면', + 'image_options' => '이미지 옵션', // Tables - 'table_properties' => 'Table properties', - 'table_properties_title' => 'Table Properties', - 'delete_table' => 'Delete table', - 'insert_row_before' => 'Insert row before', - 'insert_row_after' => 'Insert row after', - 'delete_row' => 'Delete row', - 'insert_column_before' => 'Insert column before', - 'insert_column_after' => 'Insert column after', - 'delete_column' => 'Delete column', - 'table_cell' => 'Cell', - 'table_row' => 'Row', - 'table_column' => 'Column', - 'cell_properties' => 'Cell properties', - 'cell_properties_title' => 'Cell Properties', - 'cell_type' => 'Cell type', - 'cell_type_cell' => 'Cell', - 'cell_scope' => 'Scope', - 'cell_type_header' => 'Header cell', - 'merge_cells' => 'Merge cells', - 'split_cell' => 'Split cell', - 'table_row_group' => 'Row Group', - 'table_column_group' => 'Column Group', - 'horizontal_align' => 'Horizontal align', - 'vertical_align' => 'Vertical align', - 'border_width' => 'Border width', - 'border_style' => 'Border style', - 'border_color' => 'Border color', - 'row_properties' => 'Row properties', - 'row_properties_title' => 'Row Properties', - 'cut_row' => 'Cut row', - 'copy_row' => 'Copy row', - 'paste_row_before' => 'Paste row before', - 'paste_row_after' => 'Paste row after', - 'row_type' => 'Row type', + 'table_properties' => '테이블 속성', + 'table_properties_title' => '테이블 속성', + 'delete_table' => '테이블 삭제', + 'insert_row_before' => '앞에 행 추가', + 'insert_row_after' => '뒤에 행 추가', + 'delete_row' => '행 삭제', + 'insert_column_before' => '앞에 열 추가', + 'insert_column_after' => '뒤에 열 추가', + 'delete_column' => '열 삭제', + 'table_cell' => '셀', + 'table_row' => '행', + 'table_column' => '열', + 'cell_properties' => '셀 속성', + 'cell_properties_title' => '셀 속성', + 'cell_type' => '셀 스타일', + 'cell_type_cell' => '셀', + 'cell_scope' => '범위', + 'cell_type_header' => '헤더 셀', + 'merge_cells' => '셀 병합', + 'split_cell' => '셀 분할', + 'table_row_group' => '행 그룹', + 'table_column_group' => '열 그룹', + 'horizontal_align' => '가로 맞춤', + 'vertical_align' => '세로 맞춤', + 'border_width' => '테두리 너비', + 'border_style' => '테두리 스타일', + 'border_color' => '테두리 색', + 'row_properties' => '행 속성', + 'row_properties_title' => '열 속성', + 'cut_row' => '행 자르기', + 'copy_row' => '행 복사', + 'paste_row_before' => '앞에 행 붙여넣기', + 'paste_row_after' => '다음 뒤에 행 붙여넣기', + 'row_type' => '행 타입', 'row_type_header' => '머리글', 'row_type_body' => '본문', 'row_type_footer' => '바닥글', @@ -164,8 +165,8 @@ return [ 'link_selector' => 'Link to content', 'shortcuts' => '단축키', 'shortcut' => '단축키', - 'shortcuts_intro' => 'The following shortcuts are available in the editor:', - 'windows_linux' => '(Windows/Linux)', - 'mac' => '(Mac)', - 'description' => 'Description', + 'shortcuts_intro' => '편집기에서 사용할 수 있는 바로 가기는 다음과 같습니다:', + 'windows_linux' => '(윈도우/리눅스)', + 'mac' => '(맥)', + 'description' => '상세정보', ]; diff --git a/resources/lang/ko/entities.php b/resources/lang/ko/entities.php index 48d043c7e..a3bd3f36f 100644 --- a/resources/lang/ko/entities.php +++ b/resources/lang/ko/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => '권한', - 'permissions_intro' => '한번 허용하면 이 설정은 사용자 권한에 우선합니다.', - 'permissions_enable' => '설정 허용', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => '권한 저장', 'permissions_owner' => '소유자', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => '검색 결과', diff --git a/resources/lang/lt/editor.php b/resources/lang/lt/editor.php index da7ffcf01..faf351da2 100644 --- a/resources/lang/lt/editor.php +++ b/resources/lang/lt/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Insert/Edit Link', 'insert_horizontal_line' => 'Insert horizontal line', 'insert_code_block' => 'Insert code block', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Insert/edit drawing', 'drawing_manager' => 'Drawing manager', 'insert_media' => 'Insert/edit media', diff --git a/resources/lang/lt/entities.php b/resources/lang/lt/entities.php index 8cf9fac83..ec89cef9f 100644 --- a/resources/lang/lt/entities.php +++ b/resources/lang/lt/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Leidimai', - 'permissions_intro' => 'Įgalinus šias teises, pirmenybė bus teikiama visiems nustatytiems vaidmenų leidimams.', - 'permissions_enable' => 'Įgalinti pasirinktus leidimus', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Išsaugoti leidimus', 'permissions_owner' => 'Savininkas', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Ieškoti rezultatų', diff --git a/resources/lang/lv/editor.php b/resources/lang/lv/editor.php index 1a3d75adb..d2fe32acb 100644 --- a/resources/lang/lv/editor.php +++ b/resources/lang/lv/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Ievietot/rediģēt saiti', 'insert_horizontal_line' => 'Ievietot horizontālu līniju', 'insert_code_block' => 'Ievietot koda bloku', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Ievietot/rediģēt zīmējumu', 'drawing_manager' => 'Zīmēšanas pārvaldnieks', 'insert_media' => 'Ievietot/rediģēt mediju', diff --git a/resources/lang/lv/entities.php b/resources/lang/lv/entities.php index 48bd922ed..6c87000a0 100644 --- a/resources/lang/lv/entities.php +++ b/resources/lang/lv/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Atļaujas', - 'permissions_intro' => 'Kolīdz ieslēgtas, šīs atļaujas ņems prioritāti pār jebkurām citām uzstādītajām atļaujām.', - 'permissions_enable' => 'Ieslēgt pielāgotās atļaujas', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Saglabāt atļaujas', 'permissions_owner' => 'Īpašnieks', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Meklēšanas rezultāti', diff --git a/resources/lang/nb/editor.php b/resources/lang/nb/editor.php index da7ffcf01..faf351da2 100644 --- a/resources/lang/nb/editor.php +++ b/resources/lang/nb/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Insert/Edit Link', 'insert_horizontal_line' => 'Insert horizontal line', 'insert_code_block' => 'Insert code block', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Insert/edit drawing', 'drawing_manager' => 'Drawing manager', 'insert_media' => 'Insert/edit media', diff --git a/resources/lang/nb/entities.php b/resources/lang/nb/entities.php index 503708352..39ad6d035 100644 --- a/resources/lang/nb/entities.php +++ b/resources/lang/nb/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Tilganger', - 'permissions_intro' => 'Når disse er tillatt, vil disse tillatelsene ha prioritet over alle angitte rolletillatelser.', - 'permissions_enable' => 'Aktiver egendefinerte tillatelser', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Lagre tillatelser', 'permissions_owner' => 'Eier', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Søkeresultater', diff --git a/resources/lang/nl/editor.php b/resources/lang/nl/editor.php index 01570e726..55b6c95dd 100644 --- a/resources/lang/nl/editor.php +++ b/resources/lang/nl/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Link invoegen/bewerken', 'insert_horizontal_line' => 'Horizontale lijn invoegen', 'insert_code_block' => 'Codeblok invoegen', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Tekening invoegen/bewerken', 'drawing_manager' => 'Beheer tekeningen', 'insert_media' => 'Media invoegen/bewerken', diff --git a/resources/lang/nl/entities.php b/resources/lang/nl/entities.php index 3ee393cdb..94aeefe40 100644 --- a/resources/lang/nl/entities.php +++ b/resources/lang/nl/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Machtigingen', - 'permissions_intro' => 'Wanneer ingeschakeld, zullen deze machtigingen voorrang krijgen op alle ingestelde rol-machtigingen.', - 'permissions_enable' => 'Aangepaste machtigingen aanzetten', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Machtigingen opslaan', 'permissions_owner' => 'Eigenaar', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Zoekresultaten', diff --git a/resources/lang/nl/settings.php b/resources/lang/nl/settings.php index 32784f527..7df1a3c54 100644 --- a/resources/lang/nl/settings.php +++ b/resources/lang/nl/settings.php @@ -161,7 +161,7 @@ return [ 'roles_system_warning' => 'Wees ervan bewust dat toegang tot een van de bovengenoemde drie machtigingen een gebruiker in staat kan stellen zijn eigen machtigingen of de machtigingen van anderen in het systeem kan wijzigen. Wijs alleen rollen toe met deze machtigingen aan vertrouwde gebruikers.', 'role_asset_desc' => 'Deze machtigingen bepalen de standaard toegang tot de assets binnen het systeem. Machtigingen op boeken, hoofdstukken en pagina\'s overschrijven deze instelling.', 'role_asset_admins' => 'Beheerders krijgen automatisch toegang tot alle inhoud, maar deze opties kunnen gebruikersinterface opties tonen of verbergen.', - 'role_asset_image_view_note' => 'This relates to visibility within the image manager. Actual access of uploaded image files will be dependant upon system image storage option.', + 'role_asset_image_view_note' => 'Dit heeft betrekking op de zichtbaarheid binnen de afbeeldingsbeheerder. De werkelijke toegang tot geüploade afbeeldingsbestanden hangt af van de gekozen opslagmethode.', 'role_all' => 'Alles', 'role_own' => 'Eigen', 'role_controlled_by_asset' => 'Gecontroleerd door de asset waar deze is geüpload', diff --git a/resources/lang/pl/activities.php b/resources/lang/pl/activities.php index 77a8337dd..880dc219b 100644 --- a/resources/lang/pl/activities.php +++ b/resources/lang/pl/activities.php @@ -38,14 +38,14 @@ return [ 'book_sort_notification' => 'Książka posortowana pomyślnie', // Bookshelves - 'bookshelf_create' => 'created shelf', - 'bookshelf_create_notification' => 'Shelf successfully created', - 'bookshelf_create_from_book' => 'converted book to shelf', + 'bookshelf_create' => 'utworzył półkę', + 'bookshelf_create_notification' => 'Półka utworzona pomyślnie', + 'bookshelf_create_from_book' => 'skonwertował książkę na półkę', 'bookshelf_create_from_book_notification' => 'Książka została pomyślnie skonwertowana na półkę', - 'bookshelf_update' => 'updated shelf', - 'bookshelf_update_notification' => 'Shelf successfully updated', - 'bookshelf_delete' => 'deleted shelf', - 'bookshelf_delete_notification' => 'Shelf successfully deleted', + 'bookshelf_update' => 'zaktualizował półkę', + 'bookshelf_update_notification' => 'Półka zaktualizowana pomyślnie', + 'bookshelf_delete' => 'usunął półkę', + 'bookshelf_delete_notification' => 'Półka usunięta pomyślnie', // Favourites 'favourite_add_notification' => '":name" został dodany do Twoich ulubionych', diff --git a/resources/lang/pl/editor.php b/resources/lang/pl/editor.php index ea26c636c..ceae014ff 100644 --- a/resources/lang/pl/editor.php +++ b/resources/lang/pl/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Wstaw/Edytuj Link', 'insert_horizontal_line' => 'Wstaw linię poziomą', 'insert_code_block' => 'Wstaw blok kodu', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Wstaw/Edytuj rysunek', 'drawing_manager' => 'Menedżer rysunków', 'insert_media' => 'Wstaw/edytuj multimedia', diff --git a/resources/lang/pl/entities.php b/resources/lang/pl/entities.php index d099a2972..372ae34bf 100644 --- a/resources/lang/pl/entities.php +++ b/resources/lang/pl/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Zaktualizowano :timeLength', 'meta_updated_name' => 'Zaktualizowano :timeLength przez :user', 'meta_owned_name' => 'Właściciel: :user', - 'meta_reference_page_count' => 'Referenced on 1 page|Referenced on :count pages', + 'meta_reference_page_count' => 'Odniesienie na 1 stronie|Odniesienie na :count stronach', 'entity_select' => 'Wybór obiektu', 'entity_select_lack_permission' => 'Nie masz wymaganych uprawnień do wybrania tej pozycji', 'images' => 'Obrazki', @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Uprawnienia', - 'permissions_intro' => 'Jeśli włączone są indywidualne uprawnienia, to te uprawnienia będą miały priorytet względem pozostałych ustawionych uprawnień ról.', - 'permissions_enable' => 'Włącz własne uprawnienia', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Zapisz uprawnienia', 'permissions_owner' => 'Właściciel', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Wyniki wyszukiwania', @@ -91,20 +95,20 @@ return [ 'shelves_drag_books' => 'Przeciągnij książki poniżej, aby dodać je do tej półki', 'shelves_empty_contents' => 'Ta półka nie ma przypisanych żadnych książek', 'shelves_edit_and_assign' => 'Edytuj półkę aby przypisać książki', - 'shelves_edit_named' => 'Edit Shelf :name', - 'shelves_edit' => 'Edit Shelf', - 'shelves_delete' => 'Delete Shelf', - 'shelves_delete_named' => 'Delete Shelf :name', - 'shelves_delete_explain' => "This will delete the shelf with the name ':name'. Contained books will not be deleted.", - 'shelves_delete_confirmation' => 'Are you sure you want to delete this shelf?', - 'shelves_permissions' => 'Shelf Permissions', - 'shelves_permissions_updated' => 'Shelf Permissions Updated', - 'shelves_permissions_active' => 'Shelf Permissions Active', - 'shelves_permissions_cascade_warning' => 'Permissions on shelves 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_edit_named' => 'Edytuj półkę :name', + 'shelves_edit' => 'Edytuj półkę', + 'shelves_delete' => 'Usuń półkę', + 'shelves_delete_named' => 'Usuń półkę :name', + 'shelves_delete_explain' => "Ta operacja usunie półkę o nazwie ':name'. Książki z tej półki nie zostaną usunięte.", + 'shelves_delete_confirmation' => 'Czy jesteś pewien, że chcesz usunąć tę półkę?', + 'shelves_permissions' => 'Uprawnienia półki', + 'shelves_permissions_updated' => 'Uprawnienia półki zostały zaktualizowane', + 'shelves_permissions_active' => 'Uprawnienia półki są aktywne', + 'shelves_permissions_cascade_warning' => 'Uprawnienia na półkach nie są automatycznie nakładane na zawartych w nich książkach. Dzieje się tak dlatego, że książka może istnieć na wielu półkach. Uprawnienia można jednak skopiować do książek podrzędnych, korzystając z opcji znajdującej się poniżej.', 'shelves_copy_permissions_to_books' => 'Skopiuj uprawnienia do książek', 'shelves_copy_permissions' => 'Skopiuj uprawnienia', - 'shelves_copy_permissions_explain' => 'This will apply the current permission settings of this shelf to all books contained within. Before activating, ensure any changes to the permissions of this shelf have been saved.', - 'shelves_copy_permission_success' => 'Shelf permissions copied to :count books', + 'shelves_copy_permissions_explain' => 'To spowoduje zastosowanie obecnych ustawień uprawnień tej półki na wszystkich książkach w niej zawartych. Przed aktywacją upewnij się, że wszelkie zmiany w uprawnieniach tej półki zostały zapisane.', + 'shelves_copy_permission_success' => 'Uprawnienia półki zostały skopiowane do :count książek', // Books 'book' => 'Książka', @@ -248,7 +252,7 @@ return [ 'pages_edit_content_link' => 'Edytuj zawartość', 'pages_permissions_active' => 'Uprawnienia strony są aktywne', 'pages_initial_revision' => 'Pierwsze wydanie', - 'pages_references_update_revision' => 'System auto-update of internal links', + 'pages_references_update_revision' => 'Automatyczna aktualizacja wewnętrznych linków', 'pages_initial_name' => 'Nowa strona', 'pages_editing_draft_notification' => 'Edytujesz obecnie wersję roboczą, która była ostatnio zapisana :timeDiff.', 'pages_draft_edited_notification' => 'Od tego czasu ta strona była zmieniana. Zalecane jest odrzucenie tej wersji roboczej.', @@ -372,7 +376,7 @@ return [ 'convert_chapter_confirm' => 'Czy na pewno chcesz skonwertować ten rozdział?', // References - 'references' => 'References', - 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references' => 'Odniesienia', + 'references_none' => 'Brak śledzonych odwołań do tego elementu.', + 'references_to_desc' => 'Poniżej znajdują się wszystkie znane strony w systemie, które odnoszą się do tego elementu.', ]; diff --git a/resources/lang/pl/errors.php b/resources/lang/pl/errors.php index b80a5f223..e493705b5 100644 --- a/resources/lang/pl/errors.php +++ b/resources/lang/pl/errors.php @@ -58,7 +58,7 @@ return [ // Entities 'entity_not_found' => 'Nie znaleziono obiektu', - 'bookshelf_not_found' => 'Shelf not found', + 'bookshelf_not_found' => 'Nie znaleziono półki', 'book_not_found' => 'Nie znaleziono książki', 'page_not_found' => 'Nie znaleziono strony', 'chapter_not_found' => 'Nie znaleziono rozdziału', diff --git a/resources/lang/pl/settings.php b/resources/lang/pl/settings.php index fd3d89bfc..99b13bcc7 100644 --- a/resources/lang/pl/settings.php +++ b/resources/lang/pl/settings.php @@ -81,7 +81,7 @@ return [ 'maint_image_cleanup_success' => ':count potencjalnie nieużywane obrazki zostały znalezione i usunięte!', 'maint_image_cleanup_nothing_found' => 'Nie znaleziono żadnych nieużywanych obrazków. Nic nie zostało usunięte!', 'maint_send_test_email' => 'Wyślij testową wiadomość e-mail', - 'maint_send_test_email_desc' => 'Ta opcje wyśle wiadomość testową na adres e-mail podany w Twoim profilu', + 'maint_send_test_email_desc' => 'Ta opcja wyśle wiadomość testową na adres e-mail podany w Twoim profilu.', 'maint_send_test_email_run' => 'Wyślij testową wiadomość e-mail', 'maint_send_test_email_success' => 'E-mail wysłany na adres :address', 'maint_send_test_email_mail_subject' => 'E-mail testowy', @@ -89,10 +89,10 @@ return [ 'maint_send_test_email_mail_text' => 'Gratulacje! Otrzymałeś tego e-maila więc Twoje ustawienia poczty elektronicznej wydają się być prawidłowo skonfigurowane.', 'maint_recycle_bin_desc' => 'Usunięte półki, książki, rozdziały i strony są wysyłane do kosza, aby mogły zostać przywrócone lub trwale usunięte. Starsze przedmioty w koszu mogą zostać automatycznie usunięte po pewnym czasie w zależności od konfiguracji systemu.', 'maint_recycle_bin_open' => 'Otwórz kosz', - 'maint_regen_references' => 'Regenerate References', - 'maint_regen_references_desc' => 'This action will rebuild the cross-item reference index within the database. This is usually handled automatically but this action can be useful to index old content or content added via unofficial methods.', - 'maint_regen_references_success' => 'Reference index has been regenerated!', - 'maint_timeout_command_note' => 'Note: This action can take time to run, which can lead to timeout issues in some web environments. As an alternative, this action be performed using a terminal command.', + 'maint_regen_references' => 'Zregeneruj odniesienia', + 'maint_regen_references_desc' => 'Ta akcja przebuduje bazodanowy indeks referencji między pozycjami. Zazwyczaj jest to obsługiwane automatycznie, jednak ta akcja wciąż może być przydatna do indeksowania starej zawartości, lub dodanej nieoficjalnymi metodami.', + 'maint_regen_references_success' => 'Indeks referencji został zregenerowany!', + 'maint_timeout_command_note' => 'Uwaga: Ta akcja potrzebuje czasu na wykonanie, co może prowadzić do problemów z limitami czasu utrzymywania połączenia w niektórych środowiskach webowych. Alternatywnie ta akcja może być wykonana z użyciem polecenia terminalowego.', // Recycle Bin 'recycle_bin' => 'Kosz', @@ -161,7 +161,7 @@ return [ 'roles_system_warning' => 'Pamiętaj, że dostęp do trzech powyższych uprawnień może pozwolić użytkownikowi na zmianę własnych uprawnień lub uprawnień innych osób w systemie. Przypisz tylko role z tymi uprawnieniami do zaufanych użytkowników.', 'role_asset_desc' => 'Te ustawienia kontrolują zarządzanie zasobami systemu. Uprawnienia książek, rozdziałów i stron nadpisują te ustawienia.', 'role_asset_admins' => 'Administratorzy mają automatycznie dostęp do wszystkich treści, ale te opcję mogą być pokazywać lub ukrywać opcje interfejsu użytkownika.', - 'role_asset_image_view_note' => 'This relates to visibility within the image manager. Actual access of uploaded image files will be dependant upon system image storage option.', + 'role_asset_image_view_note' => 'To odnosi się do widoczności w ramach menedżera obrazów. Rzeczywista możliwość dostępu do przesłanych plików obrazów będzie zależeć od systemowej opcji przechowywania obrazów.', 'role_all' => 'Wszyscy', 'role_own' => 'Własne', 'role_controlled_by_asset' => 'Kontrolowane przez zasób, do którego zostały udostępnione', diff --git a/resources/lang/pt/editor.php b/resources/lang/pt/editor.php index 51e99e8e3..2bf383e0d 100644 --- a/resources/lang/pt/editor.php +++ b/resources/lang/pt/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Inserir/Editar link', 'insert_horizontal_line' => 'Inserir linha horizontal', 'insert_code_block' => 'Inserir código fonte', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Inserir/editar desenho', 'drawing_manager' => 'Gestor de desenho', 'insert_media' => 'Inserir/editar mídia', diff --git a/resources/lang/pt/entities.php b/resources/lang/pt/entities.php index 37399d78f..bc4ef6ba8 100644 --- a/resources/lang/pt/entities.php +++ b/resources/lang/pt/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Permissões', - 'permissions_intro' => 'Uma vez ativadas, estas permissões terão prioridade sobre quaisquer outro conjunto de permissões.', - 'permissions_enable' => 'Ativar Permissões Personalizadas', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Guardar Permissões', 'permissions_owner' => 'Proprietário', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Resultado(s) da Pesquisa', diff --git a/resources/lang/pt_BR/activities.php b/resources/lang/pt_BR/activities.php index 427648312..3debcc4e6 100644 --- a/resources/lang/pt_BR/activities.php +++ b/resources/lang/pt_BR/activities.php @@ -6,7 +6,7 @@ return [ // Pages - 'page_create' => 'criou a página', + 'page_create' => 'página criada', 'page_create_notification' => 'Página criada com sucesso', 'page_update' => 'atualizou a página', 'page_update_notification' => 'Página atualizada com sucesso', @@ -38,14 +38,14 @@ return [ 'book_sort_notification' => 'Livro reordenado com sucesso', // Bookshelves - 'bookshelf_create' => 'created shelf', - 'bookshelf_create_notification' => 'Shelf successfully created', - 'bookshelf_create_from_book' => 'converted book to shelf', + 'bookshelf_create' => 'prateleira criada', + 'bookshelf_create_notification' => 'Prateleira criada com sucesso', + 'bookshelf_create_from_book' => 'livro convertido em estante', 'bookshelf_create_from_book_notification' => 'Capítulo convertido com sucesso em um livro', - 'bookshelf_update' => 'updated shelf', - 'bookshelf_update_notification' => 'Shelf successfully updated', - 'bookshelf_delete' => 'deleted shelf', - 'bookshelf_delete_notification' => 'Shelf successfully deleted', + 'bookshelf_update' => 'prateleira atualizada', + 'bookshelf_update_notification' => 'Prateleira atualizada com sucesso', + 'bookshelf_delete' => 'prateleira excluída', + 'bookshelf_delete_notification' => 'Prateleira excluída com sucesso', // Favourites 'favourite_add_notification' => '":name" foi adicionada aos seus favoritos', diff --git a/resources/lang/pt_BR/auth.php b/resources/lang/pt_BR/auth.php index 17ebcb16e..60812af0f 100644 --- a/resources/lang/pt_BR/auth.php +++ b/resources/lang/pt_BR/auth.php @@ -39,9 +39,9 @@ return [ 'register_success' => 'Obrigado por se cadastrar! Você agora encontra-se cadastrado(a) e logado(a).', // Login auto-initiation - 'auto_init_starting' => 'Attempting Login', - 'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.', - 'auto_init_start_link' => 'Proceed with authentication', + 'auto_init_starting' => 'Tentando fazer login', + 'auto_init_starting_desc' => 'Estamos entrando em contato com seu sistema de autenticação para iniciar o processo de login. Se não houver progresso após 5 segundos, você pode tentar clicar no link abaixo.', + 'auto_init_start_link' => 'Prossiga com a autenticação', // Password Reset 'reset_password' => 'Redefinir Senha', diff --git a/resources/lang/pt_BR/editor.php b/resources/lang/pt_BR/editor.php index aaf233a6f..c0f0d406b 100644 --- a/resources/lang/pt_BR/editor.php +++ b/resources/lang/pt_BR/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Inserir/Editar link', 'insert_horizontal_line' => 'Insert horizontal line', 'insert_code_block' => 'Inserir o bloco de endereço', + 'edit_code_block' => 'Editar bloco de código', 'insert_drawing' => 'Inserir/editar desenho', 'drawing_manager' => 'Gerente de desenho', 'insert_media' => 'Inserir/editar mídia', @@ -157,7 +158,7 @@ return [ 'about' => 'Sobre o editor', 'about_title' => 'Sobre o Editor WYSIWYG', 'editor_license' => 'Licença do Editor e Direitos Autorais', - 'editor_tiny_license' => 'This editor is built using :tinyLink which is provided under the MIT license.', + 'editor_tiny_license' => 'Este editor é construído usando :tinyLink que é fornecido sob a licença MIT.', 'editor_tiny_license_link' => 'Os dados relativos aos direitos de autor e à licença do TinyMCE podem ser encontrados aqui.', 'save_continue' => 'Salvar e continuar', 'callouts_cycle' => '(Continue pressionando para alternar através de tipos)', diff --git a/resources/lang/pt_BR/entities.php b/resources/lang/pt_BR/entities.php index fbede6da7..68f95c420 100644 --- a/resources/lang/pt_BR/entities.php +++ b/resources/lang/pt_BR/entities.php @@ -23,9 +23,9 @@ return [ 'meta_updated' => 'Atualizado :timeLength', 'meta_updated_name' => 'Atualizado :timeLength por :user', 'meta_owned_name' => 'De :user', - 'meta_reference_page_count' => 'Referenced on 1 page|Referenced on :count pages', + 'meta_reference_page_count' => 'Referenciado em 1 página|Referenciado em :count pages', 'entity_select' => 'Seleção de Entidade', - 'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item', + 'entity_select_lack_permission' => 'Você não tem as permissões necessárias para selecionar este item', 'images' => 'Imagens', 'my_recent_drafts' => 'Meus Rascunhos Recentes', 'my_recently_viewed' => 'Visualizados por mim Recentemente', @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Permissões', - 'permissions_intro' => 'Uma vez habilitadas, estas permissões terão prioridade sobre outro conjunto de permissões.', - 'permissions_enable' => 'Habilitar Permissões Customizadas', + 'permissions_desc' => 'Defina as permissões aqui para substituir as permissões padrão fornecidas pelas funções do usuário.', + 'permissions_book_cascade' => 'As permissões definidas em livros serão automaticamente em cascata para capítulos e páginas filho, a menos que tenham suas próprias permissões definidas.', + 'permissions_chapter_cascade' => 'As permissões definidas nos capítulos serão automaticamente em cascata para as páginas filhas, a menos que tenham suas próprias permissões definidas.', 'permissions_save' => 'Salvar Permissões', 'permissions_owner' => 'Proprietário', + 'permissions_role_everyone_else' => 'Todos os outros', + 'permissions_role_everyone_else_desc' => 'Defina permissões para todas as funções não especificamente substituídas.', + 'permissions_role_override' => 'Substituir permissões para função', // Search 'search_results' => 'Resultado(s) da Pesquisa', @@ -88,23 +92,23 @@ return [ 'shelves_save' => 'Salvar Prateleira', 'shelves_books' => 'Livros nesta prateleira', 'shelves_add_books' => 'Adicionar livros a esta prateleira', - 'shelves_drag_books' => 'Drag books below to add them to this shelf', + 'shelves_drag_books' => 'Arraste os livros abaixo para adicioná-los a esta estante', 'shelves_empty_contents' => 'Esta prateleira não possui livros atribuídos a ela', 'shelves_edit_and_assign' => 'Editar prateleira para atribuir livros', - 'shelves_edit_named' => 'Edit Shelf :name', - 'shelves_edit' => 'Edit Shelf', - 'shelves_delete' => 'Delete Shelf', - 'shelves_delete_named' => 'Delete Shelf :name', - 'shelves_delete_explain' => "This will delete the shelf with the name ':name'. Contained books will not be deleted.", - 'shelves_delete_confirmation' => 'Are you sure you want to delete this shelf?', - 'shelves_permissions' => 'Shelf Permissions', - 'shelves_permissions_updated' => 'Shelf Permissions Updated', - 'shelves_permissions_active' => 'Shelf Permissions Active', - 'shelves_permissions_cascade_warning' => 'Permissions on shelves 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_edit_named' => 'Editar estante :name', + 'shelves_edit' => 'Editar prateleira', + 'shelves_delete' => 'Excluir prateleira', + 'shelves_delete_named' => 'Excluir estante :name', + 'shelves_delete_explain' => "Isso excluirá a estante com o nome ':name'. Os livros contidos não serão excluídos.", + 'shelves_delete_confirmation' => 'Tem certeza de que deseja excluir esta prateleira?', + 'shelves_permissions' => 'Permissões de prateleira', + 'shelves_permissions_updated' => 'Permissões de prateleira atualizadas', + 'shelves_permissions_active' => 'Permissões de prateleira ativas', + 'shelves_permissions_cascade_warning' => 'As permissões nas prateleiras não são automaticamente em cascata para os livros contidos. Isso ocorre porque um livro pode existir em várias prateleiras. No entanto, as permissões podem ser copiadas para livros filhos usando a opção encontrada abaixo.', 'shelves_copy_permissions_to_books' => 'Copiar Permissões para Livros', 'shelves_copy_permissions' => 'Copiar Permissões', - 'shelves_copy_permissions_explain' => 'This will apply the current permission settings of this shelf to all books contained within. Before activating, ensure any changes to the permissions of this shelf have been saved.', - 'shelves_copy_permission_success' => 'Shelf permissions copied to :count books', + 'shelves_copy_permissions_explain' => 'Isso aplicará as configurações de permissão atuais desta estante a todos os livros contidos nela. Antes de ativar, verifique se todas as alterações nas permissões desta prateleira foram salvas.', + 'shelves_copy_permission_success' => 'Permissões de prateleira copiadas para :count books', // Books 'book' => 'Livro', @@ -171,7 +175,7 @@ return [ 'chapters_permissions_active' => 'Permissões de Capítulo Ativas', 'chapters_permissions_success' => 'Permissões de Capítulo Atualizadas', 'chapters_search_this' => 'Pesquisar neste Capítulo', - 'chapter_sort_book' => 'Sort Book', + 'chapter_sort_book' => 'Classificar livro', // Pages 'page' => 'Página', @@ -248,7 +252,7 @@ return [ 'pages_edit_content_link' => 'Editar Conteúdo', 'pages_permissions_active' => 'Permissões de Página Ativas', 'pages_initial_revision' => 'Publicação Inicial', - 'pages_references_update_revision' => 'System auto-update of internal links', + 'pages_references_update_revision' => 'Atualização automática do sistema de links internos', 'pages_initial_name' => 'Nova Página', 'pages_editing_draft_notification' => 'Você está atualmente editando um rascunho que foi salvo da última vez em :timeDiff.', 'pages_draft_edited_notification' => 'Essa página foi atualizada desde então. É recomendado que você descarte esse rascunho.', @@ -360,19 +364,19 @@ return [ 'copy_consider_access' => 'Uma alteração de localização, proprietário ou permissões pode resultar em que este conteúdo seja acessível para aqueles previamente sem acesso.', // Conversions - 'convert_to_shelf' => 'Convert to Shelf', - 'convert_to_shelf_contents_desc' => 'You can convert this book to a new shelf with the same contents. Chapters contained within this book will be converted to new books. If this book contains any pages, that are not in a chapter, this book will be renamed and contain such pages, and this book will become part of the new shelf.', - 'convert_to_shelf_permissions_desc' => 'Any permissions set on this book will be copied to the new shelf and to all new child books that don\'t have their own permissions enforced. Note that permissions on shelves do not auto-cascade to content within, as they do for books.', - 'convert_book' => 'Convert Book', - 'convert_book_confirm' => 'Are you sure you want to convert this book?', - 'convert_undo_warning' => 'This cannot be as easily undone.', - 'convert_to_book' => 'Convert to Book', - 'convert_to_book_desc' => 'You can convert this chapter to a new book with the same contents. Any permissions set on this chapter will be copied to the new book but any inherited permissions, from the parent book, will not be copied which could lead to a change of access control.', - 'convert_chapter' => 'Convert Chapter', - 'convert_chapter_confirm' => 'Are you sure you want to convert this chapter?', + 'convert_to_shelf' => 'Converter para estante', + 'convert_to_shelf_contents_desc' => 'Você pode converter este livro em uma nova estante com o mesmo conteúdo. Os capítulos contidos neste livro serão convertidos em novos livros. Se este livro contiver quaisquer páginas que não estejam em um capítulo, este livro será renomeado e conterá tais páginas, e este livro se tornará parte da nova estante.', + 'convert_to_shelf_permissions_desc' => 'Todas as permissões definidas neste livro serão copiadas para a nova estante e para todos os novos livros filhos que não tiverem suas próprias permissões aplicadas. Observe que as permissões nas estantes não se propagam automaticamente para o conteúdo, como acontece com os livros.', + 'convert_book' => 'Converter Livro', + 'convert_book_confirm' => 'Tem certeza de que deseja converter este livro?', + 'convert_undo_warning' => 'Isso não pode ser desfeito tão facilmente.', + 'convert_to_book' => 'Converter em livro', + 'convert_to_book_desc' => 'Você pode converter este capítulo em um novo livro com o mesmo conteúdo. Quaisquer permissões definidas neste capítulo serão copiadas para o novo livro, mas quaisquer permissões herdadas, do livro pai, não serão copiadas, o que pode levar a uma alteração do controle de acesso.', + 'convert_chapter' => 'Converter capítulo', + 'convert_chapter_confirm' => 'Tem certeza de que deseja converter este capítulo?', // References - 'references' => 'References', - 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references' => 'Referências', + 'references_none' => 'Não há referências rastreadas para este item.', + 'references_to_desc' => 'Abaixo estão todas as páginas conhecidas no sistema que vinculam a este item.', ]; diff --git a/resources/lang/pt_BR/errors.php b/resources/lang/pt_BR/errors.php index afa0b3962..54b6c9fd5 100644 --- a/resources/lang/pt_BR/errors.php +++ b/resources/lang/pt_BR/errors.php @@ -58,7 +58,7 @@ return [ // Entities 'entity_not_found' => 'Entidade não encontrada', - 'bookshelf_not_found' => 'Shelf not found', + 'bookshelf_not_found' => 'Prateleira não encontrada', 'book_not_found' => 'Livro não encontrado', 'page_not_found' => 'Página não encontrada', 'chapter_not_found' => 'Capítulo não encontrado', diff --git a/resources/lang/pt_BR/settings.php b/resources/lang/pt_BR/settings.php index 5d5a5f61d..5f6294846 100644 --- a/resources/lang/pt_BR/settings.php +++ b/resources/lang/pt_BR/settings.php @@ -89,10 +89,10 @@ return [ 'maint_send_test_email_mail_text' => 'Parabéns! Já que você recebeu esta notificação, suas opções de e-mail parecem estar configuradas corretamente.', 'maint_recycle_bin_desc' => 'Prateleiras, livros, capítulos e páginas deletados são mandados para a lixeira podendo assim ser restaurados ou excluídos permanentemente. Itens mais antigos da lixeira podem vir a ser automaticamente removidos da lixeira após um tempo dependendo da configuração do sistema.', 'maint_recycle_bin_open' => 'Abrir Lixeira', - 'maint_regen_references' => 'Regenerate References', - 'maint_regen_references_desc' => 'This action will rebuild the cross-item reference index within the database. This is usually handled automatically but this action can be useful to index old content or content added via unofficial methods.', - 'maint_regen_references_success' => 'Reference index has been regenerated!', - 'maint_timeout_command_note' => 'Note: This action can take time to run, which can lead to timeout issues in some web environments. As an alternative, this action be performed using a terminal command.', + 'maint_regen_references' => 'Regenerar referências', + 'maint_regen_references_desc' => 'Essa ação reconstruirá o índice de referência entre itens no banco de dados. Isso geralmente é tratado automaticamente, mas essa ação pode ser útil para indexar conteúdo antigo ou adicionado por métodos não oficiais.', + 'maint_regen_references_success' => 'O índice de referência foi regenerado!', + 'maint_timeout_command_note' => 'Observação: essa ação pode levar algum tempo para ser executada, o que pode levar a problemas de tempo limite em alguns ambientes da Web. Como alternativa, esta ação pode ser executada usando um comando de terminal.', // Recycle Bin 'recycle_bin' => 'Lixeira', @@ -161,7 +161,7 @@ return [ 'roles_system_warning' => 'Esteja ciente de que o acesso a qualquer uma das três permissões acima pode permitir que um usuário altere seus próprios privilégios ou privilégios de outros usuários no sistema. Apenas atribua cargos com essas permissões para usuários confiáveis.', 'role_asset_desc' => 'Essas permissões controlam o acesso padrão para os ativos dentro do sistema. Permissões em Livros, Capítulos e Páginas serão sobrescritas por essas permissões.', 'role_asset_admins' => 'Administradores recebem automaticamente acesso a todo o conteúdo, mas essas opções podem mostrar ou ocultar as opções da Interface de Usuário.', - 'role_asset_image_view_note' => 'This relates to visibility within the image manager. Actual access of uploaded image files will be dependant upon system image storage option.', + 'role_asset_image_view_note' => 'Isso está relacionado à visibilidade no gerenciador de imagens. O acesso real dos arquivos de imagem carregados dependerá da opção de armazenamento de imagem do sistema.', 'role_all' => 'Todos', 'role_own' => 'Próprio', 'role_controlled_by_asset' => 'Controlado pelos ativos nos quais o upload foi realizado', @@ -215,7 +215,7 @@ return [ 'users_api_tokens_docs' => 'Documentação da API', 'users_mfa' => 'Autenticação de Múltiplos Fatores', 'users_mfa_desc' => 'A autenticação multi-fator adiciona outra camada de segurança à sua conta.', - 'users_mfa_x_methods' => ':count método configurado):count métodos configurados', + 'users_mfa_x_methods' => ':count método configurado|:count métodos configurados', 'users_mfa_configure' => 'Configurar Métodos', // API Tokens diff --git a/resources/lang/ro/editor.php b/resources/lang/ro/editor.php index 384d93212..eef26658f 100644 --- a/resources/lang/ro/editor.php +++ b/resources/lang/ro/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Inserare/Editare link', 'insert_horizontal_line' => 'Inserează linie orizontală', 'insert_code_block' => 'Inserează bloc de cod', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Inserare/editare desen', 'drawing_manager' => 'Manager de desene', 'insert_media' => 'Inserare/editare media', diff --git a/resources/lang/ro/entities.php b/resources/lang/ro/entities.php index 5822c3233..fec396602 100644 --- a/resources/lang/ro/entities.php +++ b/resources/lang/ro/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Permisiuni', - 'permissions_intro' => 'Odată activat, aceste permisiuni vor avea prioritate față de toate permisiunile de rol stabilite.', - 'permissions_enable' => 'Activare permisiuni personalizate', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Salvează permisiuni', 'permissions_owner' => 'Proprietar', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Rezultatele căutării', diff --git a/resources/lang/ro/settings.php b/resources/lang/ro/settings.php index fd11ed99d..b9e104c41 100644 --- a/resources/lang/ro/settings.php +++ b/resources/lang/ro/settings.php @@ -89,10 +89,10 @@ return [ 'maint_send_test_email_mail_text' => 'Felicitări! Deoarece ai primit această notificare prin e-mail, setările de e-mail par să fie configurate corespunzător.', 'maint_recycle_bin_desc' => 'Rafturile, cărțile, capitole și paginile șterse se trimit la coșul de gunoi pentru a putea fi restaurate sau șterse definitiv. Elementele mai vechi din coșul de gunoi pot fi eliminate automat după o vreme, în funcție de configurația sistemului.', 'maint_recycle_bin_open' => 'Deschide coșul de gunoi', - 'maint_regen_references' => 'Regenerate References', - 'maint_regen_references_desc' => 'This action will rebuild the cross-item reference index within the database. This is usually handled automatically but this action can be useful to index old content or content added via unofficial methods.', - 'maint_regen_references_success' => 'Reference index has been regenerated!', - 'maint_timeout_command_note' => 'Note: This action can take time to run, which can lead to timeout issues in some web environments. As an alternative, this action be performed using a terminal command.', + 'maint_regen_references' => 'Regenerează referințe', + 'maint_regen_references_desc' => 'Această acțiune va reconstrui indexul de referință al elementului încrucișat în baza de date. Acest lucru este de obicei manipulat automat, dar această acțiune poate fi utilă pentru a indexa conținutul vechi sau conținutul adăugat prin metode neoficiale.', + 'maint_regen_references_success' => 'Indicele de referință a fost regenerat!', + 'maint_timeout_command_note' => 'Notă: Această acțiune necesită timp pentru a funcționa, ceea ce poate duce la apariția unor probleme în unele medii web. Ca alternativă, această acțiune trebuie efectuată utilizând o comandă din terminal.', // Recycle Bin 'recycle_bin' => 'Coș de gunoi', @@ -161,7 +161,7 @@ return [ 'roles_system_warning' => 'Fi conștient de faptul că accesul la oricare dintre cele trei permisiuni de mai sus poate permite unui utilizator să își modifice propriile privilegii sau privilegiile altor persoane din sistem. Atribuie doar roluri cu aceste permisiuni utilizatorilor de încredere.', 'role_asset_desc' => 'Aceste permisiuni controlează accesul implicit la activele din sistem. Permisiunile pe Cărți, Capitole și Pagini vor suprascrie aceste permisiuni.', 'role_asset_admins' => 'Administratorilor li se acordă automat acces la tot conținutul, dar aceste opțiuni pot afișa sau ascunde opțiunile UI.', - 'role_asset_image_view_note' => 'This relates to visibility within the image manager. Actual access of uploaded image files will be dependant upon system image storage option.', + 'role_asset_image_view_note' => 'Acest lucru se referă la vizibilitatea în managerul de imagini. Accesul efectiv al fișierelor de imagine încărcate va depinde de opțiunea de stocare a imaginilor din sistem.', 'role_all' => 'Tot', 'role_own' => 'Propriu', 'role_controlled_by_asset' => 'Controlat de activele pe care sunt încărcate', diff --git a/resources/lang/ru/editor.php b/resources/lang/ru/editor.php index d39eb5682..12399e3b4 100644 --- a/resources/lang/ru/editor.php +++ b/resources/lang/ru/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Вставить/Редактировать ссылку', 'insert_horizontal_line' => 'Вставить горизонтальную линию', 'insert_code_block' => 'Вставить блок кода', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Вставить/редактировать схему', 'drawing_manager' => 'Менеджер схем', 'insert_media' => 'Вставить/редактировать медиафайл', diff --git a/resources/lang/ru/entities.php b/resources/lang/ru/entities.php index d195a3d5c..2121f5a8c 100644 --- a/resources/lang/ru/entities.php +++ b/resources/lang/ru/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Разрешения', - 'permissions_intro' => 'После включения опции эти разрешения будут иметь приоритет над любыми установленными разрешениями роли.', - 'permissions_enable' => 'Включение пользовательских разрешений', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Сохранить разрешения', 'permissions_owner' => 'Владелец', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Результаты поиска', diff --git a/resources/lang/sk/editor.php b/resources/lang/sk/editor.php index da7ffcf01..faf351da2 100644 --- a/resources/lang/sk/editor.php +++ b/resources/lang/sk/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Insert/Edit Link', 'insert_horizontal_line' => 'Insert horizontal line', 'insert_code_block' => 'Insert code block', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Insert/edit drawing', 'drawing_manager' => 'Drawing manager', 'insert_media' => 'Insert/edit media', diff --git a/resources/lang/sk/entities.php b/resources/lang/sk/entities.php index 88e052a22..c64756761 100644 --- a/resources/lang/sk/entities.php +++ b/resources/lang/sk/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Oprávnenia', - 'permissions_intro' => 'Ak budú tieto oprávnenia povolené, budú mať prioritu pred oprávneniami roly.', - 'permissions_enable' => 'Povoliť vlastné oprávnenia', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Uložiť oprávnenia', 'permissions_owner' => 'Vlastník', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Výsledky hľadania', diff --git a/resources/lang/sl/editor.php b/resources/lang/sl/editor.php index da7ffcf01..faf351da2 100644 --- a/resources/lang/sl/editor.php +++ b/resources/lang/sl/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Insert/Edit Link', 'insert_horizontal_line' => 'Insert horizontal line', 'insert_code_block' => 'Insert code block', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Insert/edit drawing', 'drawing_manager' => 'Drawing manager', 'insert_media' => 'Insert/edit media', diff --git a/resources/lang/sl/entities.php b/resources/lang/sl/entities.php index 6e6d89734..2a6c721cb 100644 --- a/resources/lang/sl/entities.php +++ b/resources/lang/sl/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Dovoljenja', - 'permissions_intro' => 'V trenutku, ko bodo omogočena, bodo imela ta dovoljenja prednost pred dovoljenji za določanje vlog.', - 'permissions_enable' => 'Omogoči dovoljenja po meri', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Shrani dovoljenja', 'permissions_owner' => 'Lastnik', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Rezultati iskanja', diff --git a/resources/lang/sv/activities.php b/resources/lang/sv/activities.php index 1d913b799..f730bf5ae 100644 --- a/resources/lang/sv/activities.php +++ b/resources/lang/sv/activities.php @@ -7,65 +7,65 @@ return [ // Pages 'page_create' => 'skapade sidan', - 'page_create_notification' => 'Page successfully created', + 'page_create_notification' => 'Sidan har skapats', 'page_update' => 'uppdaterade sidan', - 'page_update_notification' => 'Page successfully updated', + 'page_update_notification' => 'Sidan har uppdaterats', 'page_delete' => 'tog bort sidan', - 'page_delete_notification' => 'Page successfully deleted', + 'page_delete_notification' => 'Sidan har tagits bort', 'page_restore' => 'återställde sidan', - 'page_restore_notification' => 'Page successfully restored', + 'page_restore_notification' => 'Sidan har återställts', 'page_move' => 'flyttade sidan', // Chapters 'chapter_create' => 'skapade kapitlet', - 'chapter_create_notification' => 'Chapter successfully created', + 'chapter_create_notification' => 'Kapitlet har skapats', 'chapter_update' => 'uppdaterade kapitlet', - 'chapter_update_notification' => 'Chapter successfully updated', + 'chapter_update_notification' => 'Kapitlet har uppdaterats', 'chapter_delete' => 'tog bort kapitlet', - 'chapter_delete_notification' => 'Chapter successfully deleted', + 'chapter_delete_notification' => 'Kapitlet har tagits bort', 'chapter_move' => 'flyttade kapitlet', // Books 'book_create' => 'skapade boken', - 'book_create_notification' => 'Book successfully created', - 'book_create_from_chapter' => 'converted chapter to book', - 'book_create_from_chapter_notification' => 'Chapter successfully converted to a book', + 'book_create_notification' => 'Boken har skapats', + 'book_create_from_chapter' => 'konverterade kapitel till bok', + 'book_create_from_chapter_notification' => 'Kapitlet har konverterats till en bok', 'book_update' => 'uppdaterade boken', - 'book_update_notification' => 'Book successfully updated', + 'book_update_notification' => 'Boken har uppdaterats', 'book_delete' => 'tog bort boken', - 'book_delete_notification' => 'Book successfully deleted', + 'book_delete_notification' => 'Boken har tagits bort', 'book_sort' => 'sorterade boken', - 'book_sort_notification' => 'Book successfully re-sorted', + 'book_sort_notification' => 'Boken har sorterats om', // Bookshelves - 'bookshelf_create' => 'created shelf', - 'bookshelf_create_notification' => 'Shelf successfully created', - 'bookshelf_create_from_book' => 'converted book to shelf', - 'bookshelf_create_from_book_notification' => 'Book successfully converted to a shelf', - 'bookshelf_update' => 'updated shelf', - 'bookshelf_update_notification' => 'Shelf successfully updated', - 'bookshelf_delete' => 'deleted shelf', - 'bookshelf_delete_notification' => 'Shelf successfully deleted', + 'bookshelf_create' => 'skapade hylla', + 'bookshelf_create_notification' => 'Hyllan har skapats', + 'bookshelf_create_from_book' => 'konverterade bok till hylla', + 'bookshelf_create_from_book_notification' => 'Boken har konverterats till en hylla', + 'bookshelf_update' => 'uppdaterade hyllan', + 'bookshelf_update_notification' => 'Hyllan har uppdaterats', + 'bookshelf_delete' => 'raderade hyllan', + 'bookshelf_delete_notification' => 'Hyllan har tagits bort', // Favourites 'favourite_add_notification' => '":name" har lagts till i dina favoriter', 'favourite_remove_notification' => '":name" har tagits bort från dina favoriter', // MFA - 'mfa_setup_method_notification' => 'Multi-factor method successfully configured', - 'mfa_remove_method_notification' => 'Multi-factor method successfully removed', + 'mfa_setup_method_notification' => 'Multifaktor-metod har konfigurerats', + 'mfa_remove_method_notification' => 'Multifaktor-metod har tagits bort', // Webhooks - 'webhook_create' => 'created webhook', - 'webhook_create_notification' => 'Webhook successfully created', - 'webhook_update' => 'updated webhook', - 'webhook_update_notification' => 'Webhook successfully updated', - 'webhook_delete' => 'deleted webhook', - 'webhook_delete_notification' => 'Webhook successfully deleted', + 'webhook_create' => 'skapade webhook', + 'webhook_create_notification' => 'Webhook har skapats', + 'webhook_update' => 'uppdaterade webhook', + 'webhook_update_notification' => 'Webhook har uppdaterats', + 'webhook_delete' => 'raderade webhook', + 'webhook_delete_notification' => 'Webhook har tagits bort', // Users - 'user_update_notification' => 'User successfully updated', - 'user_delete_notification' => 'User successfully removed', + 'user_update_notification' => 'Användaren har uppdaterats', + 'user_delete_notification' => 'Användaren har tagits bort', // Other 'commented_on' => 'kommenterade', diff --git a/resources/lang/sv/auth.php b/resources/lang/sv/auth.php index 849918cdc..a456c7d21 100644 --- a/resources/lang/sv/auth.php +++ b/resources/lang/sv/auth.php @@ -21,7 +21,7 @@ return [ 'email' => 'E-post', 'password' => 'Lösenord', 'password_confirm' => 'Bekräfta lösenord', - 'password_hint' => 'Must be at least 8 characters', + 'password_hint' => 'Måste vara minst 8 tecken', 'forgot_password' => 'Glömt lösenord?', 'remember_me' => 'Kom ihåg mig', 'ldap_email_hint' => 'Vänligen ange en e-postadress att använda till kontot.', @@ -39,9 +39,9 @@ return [ 'register_success' => 'Tack för din registrering! Du är nu registerad och inloggad.', // Login auto-initiation - 'auto_init_starting' => 'Attempting Login', - 'auto_init_starting_desc' => 'We\'re contacting your authentication system to start the login process. If there\'s no progress after 5 seconds you can try clicking the link below.', - 'auto_init_start_link' => 'Proceed with authentication', + 'auto_init_starting' => 'Försöker Logga In', + 'auto_init_starting_desc' => 'Vi kontaktar ditt autentiseringssystem för att starta inloggningsprocessen. Om inget händer efter 5 sekunder kan du prova att klicka på länken nedan.', + 'auto_init_start_link' => 'Fortsätt med autentisering', // Password Reset 'reset_password' => 'Återställ lösenord', @@ -59,7 +59,7 @@ return [ 'email_confirm_text' => 'Vänligen bekräfta din e-postadress genom att klicka på knappen nedan:', 'email_confirm_action' => 'Bekräfta e-post', 'email_confirm_send_error' => 'E-posten behöver bekräftas men systemet kan inte skicka mail. Kontakta adminstratören för att kontrollera att allt är konfigurerat korrekt.', - 'email_confirm_success' => 'Your email has been confirmed! You should now be able to login using this email address.', + 'email_confirm_success' => 'Din e-postadress har bekräftats! Du bör nu kunna logga in med denna e-postadress.', 'email_confirm_resent' => 'Bekräftelsemailet har skickats på nytt, kolla din mail', 'email_not_confirmed' => 'E-posadress ej bekräftad', @@ -76,40 +76,40 @@ return [ 'user_invite_page_welcome' => 'Välkommen till :appName!', 'user_invite_page_text' => 'För att slutföra ditt konto och få åtkomst måste du ange ett lösenord som kommer att användas för att logga in på :appName vid framtida besök.', 'user_invite_page_confirm_button' => 'Bekräfta lösenord', - 'user_invite_success_login' => 'Password set, you should now be able to login using your set password to access :appName!', + 'user_invite_success_login' => 'Lösenord inställt, du bör nu kunna logga in med ditt inställda lösenord för att komma åt :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' => 'Konfigurera multifaktorsautentisering', + 'mfa_setup_desc' => 'Konfigurera multifaktorsautentisering som ett extra skydd för ditt konto.', + 'mfa_setup_configured' => 'Redan konfigurerad', + 'mfa_setup_reconfigure' => 'Omkonfigurera', + 'mfa_setup_remove_confirmation' => 'Är du säker på att du vill ta bort denna multifaktorautentiseringsmetod?', 'mfa_setup_action' => 'Setup', - 'mfa_backup_codes_usage_limit_warning' => 'You have less than 5 backup codes remaining, Please generate and store a new set before you run out of codes to prevent being locked out of your account.', - 'mfa_option_totp_title' => 'Mobile App', - 'mfa_option_totp_desc' => 'To use multi-factor authentication you\'ll need a mobile application that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator.', - 'mfa_option_backup_codes_title' => 'Backup Codes', - 'mfa_option_backup_codes_desc' => 'Securely store a set of one-time-use backup codes which you can enter to verify your identity.', - 'mfa_gen_confirm_and_enable' => 'Confirm and Enable', - 'mfa_gen_backup_codes_title' => 'Backup Codes Setup', - 'mfa_gen_backup_codes_desc' => 'Store the below list of codes in a safe place. When accessing the system you\'ll be able to use one of the codes as a second authentication mechanism.', - 'mfa_gen_backup_codes_download' => 'Download Codes', - 'mfa_gen_backup_codes_usage_warning' => 'Each code can only be used once', - 'mfa_gen_totp_title' => 'Mobile App Setup', - 'mfa_gen_totp_desc' => 'To use multi-factor authentication you\'ll need a mobile application that supports TOTP such as Google Authenticator, Authy or Microsoft Authenticator.', - 'mfa_gen_totp_scan' => 'Scan the QR code below using your preferred authentication app to get started.', - 'mfa_gen_totp_verify_setup' => 'Verify Setup', - 'mfa_gen_totp_verify_setup_desc' => 'Verify that all is working by entering a code, generated within your authentication app, in the input box below:', - 'mfa_gen_totp_provide_code_here' => 'Provide your app generated code here', - 'mfa_verify_access' => 'Verify Access', - 'mfa_verify_access_desc' => 'Your user account requires you to confirm your identity via an additional level of verification before you\'re granted access. Verify using one of your configured methods to continue.', - 'mfa_verify_no_methods' => 'No Methods Configured', - 'mfa_verify_no_methods_desc' => 'No multi-factor authentication methods could be found for your account. You\'ll need to set up at least one method before you gain access.', - 'mfa_verify_use_totp' => 'Verify using a mobile app', - 'mfa_verify_use_backup_codes' => 'Verify using a backup code', - 'mfa_verify_backup_code' => 'Backup Code', - 'mfa_verify_backup_code_desc' => 'Enter one of your remaining backup codes below:', - 'mfa_verify_backup_code_enter_here' => 'Enter backup code here', - 'mfa_verify_totp_desc' => 'Enter the code, generated using your mobile app, below:', - 'mfa_setup_login_notification' => 'Multi-factor method configured, Please now login again using the configured method.', + 'mfa_backup_codes_usage_limit_warning' => 'Du har mindre än 5 reservkoder kvar, Vänligen generera och lagra en nya innan du får slut på koder för att förhindra att du inte kommer åt ditt konto.', + 'mfa_option_totp_title' => 'Mobilapp', + 'mfa_option_totp_desc' => 'För att använda multifaktorautentisering behöver du en mobil app som stöder TOTP så som Google Authenticator, Authy eller Microsoft Authenticator.', + 'mfa_option_backup_codes_title' => 'Reservkoder', + 'mfa_option_backup_codes_desc' => 'Lagra säkert en uppsättning engångsreservkoder som du kan ange för att verifiera din identitet.', + 'mfa_gen_confirm_and_enable' => 'Bekräfta och aktivera', + 'mfa_gen_backup_codes_title' => 'Konfiguration av reservkoder', + 'mfa_gen_backup_codes_desc' => 'Spara nedanstående koder på en säker plats. När du använder systemet kommer du att kunna använda en av koderna som en andra autentiseringsmekanism.', + 'mfa_gen_backup_codes_download' => 'Ladda ner koder', + 'mfa_gen_backup_codes_usage_warning' => 'Varje kod kan endast användas en gång', + 'mfa_gen_totp_title' => 'Konfiguration av mobilapp', + 'mfa_gen_totp_desc' => 'För att använda multifaktorautentisering behöver du en mobil app som stöder TOTP så som Google Authenticator, Authy eller Microsoft Authenticator.', + 'mfa_gen_totp_scan' => 'Skanna QR-koden nedan med din föredragna autentiseringsapp för att komma igång.', + 'mfa_gen_totp_verify_setup' => 'Verifiera konfiguration', + 'mfa_gen_totp_verify_setup_desc' => 'Kontrollera att allt fungerar genom att ange en kod, genererad i din autentiseringsapp, i rutan nedan:', + 'mfa_gen_totp_provide_code_here' => 'Ange din appgenererade kod här', + 'mfa_verify_access' => 'Verifiera åtkomst', + 'mfa_verify_access_desc' => 'Ditt användarkonto kräver att du bekräftar din identitet via en ytterligare verifieringsmetod innan du får tillgång. Verifiera genom en av dina konfigurerade metoder för att fortsätta.', + 'mfa_verify_no_methods' => 'Inga metoder konfigurerade', + 'mfa_verify_no_methods_desc' => 'Inga multifaktorautentiseringsmetoder kunde hittas för ditt konto. Du måste konfigurera minst en metod innan du får tillgång.', + 'mfa_verify_use_totp' => 'Verifiera med en mobilapp', + 'mfa_verify_use_backup_codes' => 'Verifiera med en reservkod', + 'mfa_verify_backup_code' => 'Reservkod', + 'mfa_verify_backup_code_desc' => 'Ange en av dina återstående reservkoder nedan:', + 'mfa_verify_backup_code_enter_here' => 'Ange reservkod här', + 'mfa_verify_totp_desc' => 'Ange koden, som genereras med din mobilapp, nedan:', + 'mfa_setup_login_notification' => 'Multifaktormetod konfigurerad, Logga nu in igen med den konfigurerade metoden.', ]; diff --git a/resources/lang/sv/common.php b/resources/lang/sv/common.php index 3f920500d..cc81b71d8 100644 --- a/resources/lang/sv/common.php +++ b/resources/lang/sv/common.php @@ -39,16 +39,16 @@ return [ 'reset' => 'Återställ', 'remove' => 'Radera', 'add' => 'Lägg till', - 'configure' => 'Configure', + 'configure' => 'Konfigurera', 'fullscreen' => 'Helskärm', 'favourite' => 'Favorit', 'unfavourite' => 'Ta bort favorit', 'next' => 'Nästa', 'previous' => 'Föregående', - 'filter_active' => 'Active Filter:', - 'filter_clear' => 'Clear Filter', - 'download' => 'Download', - 'open_in_tab' => 'Open in Tab', + 'filter_active' => 'Aktivt filter:', + 'filter_clear' => 'Rensa filter', + 'download' => 'Ladda ner', + 'open_in_tab' => 'Öppna i flik', // Sort Options 'sort_options' => 'Sorteringsalternativ', @@ -65,7 +65,7 @@ return [ 'no_activity' => 'Ingen aktivitet att visa', 'no_items' => 'Inga tillgängliga föremål', 'back_to_top' => 'Tillbaka till toppen', - 'skip_to_main_content' => 'Skip to main content', + 'skip_to_main_content' => 'Hoppa till huvudinnehåll', 'toggle_details' => 'Växla detaljer', 'toggle_thumbnails' => 'Växla miniatyrer', 'details' => 'Information', @@ -74,10 +74,10 @@ return [ 'default' => 'Förvald', 'breadcrumb' => 'Brödsmula', 'status' => 'Status', - 'status_active' => 'Active', + 'status_active' => 'Aktiv', 'status_inactive' => 'Inaktiv', - 'never' => 'Never', - 'none' => 'None', + 'never' => 'Aldrig', + 'none' => 'Inga', // Header 'header_menu_expand' => 'Expandera sidhuvudsmenyn', diff --git a/resources/lang/sv/editor.php b/resources/lang/sv/editor.php index da7ffcf01..8acc84a4b 100644 --- a/resources/lang/sv/editor.php +++ b/resources/lang/sv/editor.php @@ -7,165 +7,166 @@ */ return [ // General editor terms - 'general' => 'General', - 'advanced' => 'Advanced', - 'none' => 'None', - 'cancel' => 'Cancel', - 'save' => 'Save', - 'close' => 'Close', - 'undo' => 'Undo', - 'redo' => 'Redo', - 'left' => 'Left', - 'center' => 'Center', - 'right' => 'Right', - 'top' => 'Top', - 'middle' => 'Middle', - 'bottom' => 'Bottom', - 'width' => 'Width', - 'height' => 'Height', - 'More' => 'More', - 'select' => 'Select...', + 'general' => 'Allmän', + 'advanced' => 'Avancerad', + 'none' => 'Inga', + 'cancel' => 'Avbryt', + 'save' => 'Spara', + 'close' => 'Stäng', + 'undo' => 'Ångra', + 'redo' => 'Gör om', + 'left' => 'Vänster', + 'center' => 'Mitten', + 'right' => 'Höger', + 'top' => 'Topp', + 'middle' => 'Mitt', + 'bottom' => 'Botten', + 'width' => 'Bredd', + 'height' => 'Höjd', + 'More' => 'Mer', + 'select' => 'Välj...', // Toolbar - 'formats' => 'Formats', - 'header_large' => 'Large Header', - 'header_medium' => 'Medium Header', - 'header_small' => 'Small Header', - 'header_tiny' => 'Tiny Header', - 'paragraph' => 'Paragraph', - 'blockquote' => 'Blockquote', - 'inline_code' => 'Inline code', - 'callouts' => 'Callouts', + 'formats' => 'Format', + 'header_large' => 'Stor rubrik', + 'header_medium' => 'Mellanstor rubrik', + 'header_small' => 'Mindre rubrik', + 'header_tiny' => 'Liten rubrik', + 'paragraph' => 'Paragraf', + 'blockquote' => 'Blockcitat', + 'inline_code' => 'Inline-kod', + 'callouts' => 'Anslag', 'callout_information' => 'Information', 'callout_success' => 'Success', - 'callout_warning' => 'Warning', - 'callout_danger' => 'Danger', - 'bold' => 'Bold', - 'italic' => 'Italic', - 'underline' => 'Underline', - 'strikethrough' => 'Strikethrough', - 'superscript' => 'Superscript', - 'subscript' => 'Subscript', - 'text_color' => 'Text color', - 'custom_color' => 'Custom color', - 'remove_color' => 'Remove color', - 'background_color' => 'Background color', - 'align_left' => 'Align left', - 'align_center' => 'Align center', - 'align_right' => 'Align right', - 'align_justify' => 'Justify', - 'list_bullet' => 'Bullet list', - 'list_numbered' => 'Numbered list', - 'list_task' => 'Task list', - 'indent_increase' => 'Increase indent', - 'indent_decrease' => 'Decrease indent', - 'table' => 'Table', - 'insert_image' => 'Insert image', - 'insert_image_title' => 'Insert/Edit Image', - 'insert_link' => 'Insert/edit link', - 'insert_link_title' => 'Insert/Edit Link', - 'insert_horizontal_line' => 'Insert horizontal line', - 'insert_code_block' => 'Insert code block', - 'insert_drawing' => 'Insert/edit drawing', - 'drawing_manager' => 'Drawing manager', - 'insert_media' => 'Insert/edit media', - 'insert_media_title' => 'Insert/Edit Media', - 'clear_formatting' => 'Clear formatting', - 'source_code' => 'Source code', - 'source_code_title' => 'Source Code', - 'fullscreen' => 'Fullscreen', - 'image_options' => 'Image options', + 'callout_warning' => 'Varning', + 'callout_danger' => 'Fara', + 'bold' => 'Fetstil', + 'italic' => 'Kursiv', + 'underline' => 'Understruken', + 'strikethrough' => 'Genomstruken', + 'superscript' => 'Upphöjd', + 'subscript' => 'Nedsänkt', + 'text_color' => 'Textfärg', + 'custom_color' => 'Anpassad färg', + 'remove_color' => 'Ta bort färg', + 'background_color' => 'Bakgrundsfärg', + 'align_left' => 'Vänsterjustera', + 'align_center' => 'Centrera', + 'align_right' => 'Högerjustera', + 'align_justify' => 'Marginaljustera', + 'list_bullet' => 'Punktlista', + 'list_numbered' => 'Numrerad lista', + 'list_task' => 'Checklista', + 'indent_increase' => 'Öka indrag', + 'indent_decrease' => 'Minska indrag', + 'table' => 'Tabell', + 'insert_image' => 'Infoga bild', + 'insert_image_title' => 'Infoga/redigera bild', + 'insert_link' => 'Infoga/redigera länk', + 'insert_link_title' => 'Infoga/redigera länk', + 'insert_horizontal_line' => 'Infoga horisontell linje', + 'insert_code_block' => 'Infoga kodblock', + 'edit_code_block' => 'Redigera kodblock', + 'insert_drawing' => 'Infoga/redigera ritning', + 'drawing_manager' => 'Ritningshanterare', + 'insert_media' => 'Infoga/redigera media', + 'insert_media_title' => 'Infoga/redigera media', + 'clear_formatting' => 'Rensa formatering', + 'source_code' => 'Källkod', + 'source_code_title' => 'Källkod', + 'fullscreen' => 'Helskärm', + 'image_options' => 'Bildalternativ', // Tables - 'table_properties' => 'Table properties', - 'table_properties_title' => 'Table Properties', - 'delete_table' => 'Delete table', - 'insert_row_before' => 'Insert row before', - 'insert_row_after' => 'Insert row after', - 'delete_row' => 'Delete row', - 'insert_column_before' => 'Insert column before', - 'insert_column_after' => 'Insert column after', - 'delete_column' => 'Delete column', + 'table_properties' => 'Tabellegenskaper', + 'table_properties_title' => 'Tabellegenskaper', + 'delete_table' => 'Ta bort tabell', + 'insert_row_before' => 'Infoga rad före', + 'insert_row_after' => 'Infoga rad efter', + 'delete_row' => 'Ta bort rad', + 'insert_column_before' => 'Infoga kolumn före', + 'insert_column_after' => 'Infoga kolumn efter', + 'delete_column' => 'Ta bort kolumn', 'table_cell' => 'Cell', - 'table_row' => 'Row', - 'table_column' => 'Column', - 'cell_properties' => 'Cell properties', - 'cell_properties_title' => 'Cell Properties', - 'cell_type' => 'Cell type', + 'table_row' => 'Rad', + 'table_column' => 'Kolumn', + 'cell_properties' => 'Cellegenskaper', + 'cell_properties_title' => 'Cellegenskaper', + 'cell_type' => 'Celltyp', 'cell_type_cell' => 'Cell', - 'cell_scope' => 'Scope', - 'cell_type_header' => 'Header cell', - 'merge_cells' => 'Merge cells', - 'split_cell' => 'Split cell', - 'table_row_group' => 'Row Group', - 'table_column_group' => 'Column Group', - 'horizontal_align' => 'Horizontal align', - 'vertical_align' => 'Vertical align', - 'border_width' => 'Border width', - 'border_style' => 'Border style', - 'border_color' => 'Border color', - 'row_properties' => 'Row properties', - 'row_properties_title' => 'Row Properties', - 'cut_row' => 'Cut row', - 'copy_row' => 'Copy row', - 'paste_row_before' => 'Paste row before', - 'paste_row_after' => 'Paste row after', - 'row_type' => 'Row type', - 'row_type_header' => 'Header', - 'row_type_body' => 'Body', - 'row_type_footer' => 'Footer', - 'alignment' => 'Alignment', - 'cut_column' => 'Cut column', - 'copy_column' => 'Copy column', - 'paste_column_before' => 'Paste column before', - 'paste_column_after' => 'Paste column after', + 'cell_scope' => 'Omfattning', + 'cell_type_header' => 'Rubrikcell', + 'merge_cells' => 'Sammanfoga celler', + 'split_cell' => 'Dela cell', + 'table_row_group' => 'Radgrupp', + 'table_column_group' => 'Kolumngrupp', + 'horizontal_align' => 'Horisontell justering', + 'vertical_align' => 'Vertikal justering', + 'border_width' => 'Kantbredd', + 'border_style' => 'Kantstil', + 'border_color' => 'Kantfärg', + 'row_properties' => 'Radegenskaper', + 'row_properties_title' => 'Radegenskaper', + 'cut_row' => 'Klipp rad', + 'copy_row' => 'Kopiera rad', + 'paste_row_before' => 'Infoga rad före', + 'paste_row_after' => 'Klistra in rad efter', + 'row_type' => 'Radtyp', + 'row_type_header' => 'Rubrik', + 'row_type_body' => 'Brödtext', + 'row_type_footer' => 'Sidfot', + 'alignment' => 'Justering', + 'cut_column' => 'Klipp kolumn', + 'copy_column' => 'Kopiera kolumn', + 'paste_column_before' => 'Infoga kolumn före', + 'paste_column_after' => 'Infoga kolumn före', 'cell_padding' => 'Cell padding', 'cell_spacing' => 'Cell spacing', 'caption' => 'Caption', 'show_caption' => 'Show caption', - 'constrain' => 'Constrain proportions', + 'constrain' => 'Begränsa proportioner', 'cell_border_solid' => 'Solid', - 'cell_border_dotted' => 'Dotted', - 'cell_border_dashed' => 'Dashed', - 'cell_border_double' => 'Double', + 'cell_border_dotted' => 'Punktad', + 'cell_border_dashed' => 'Streckad', + 'cell_border_double' => 'Dubbel', 'cell_border_groove' => 'Groove', 'cell_border_ridge' => 'Ridge', - 'cell_border_inset' => 'Inset', - 'cell_border_outset' => 'Outset', - 'cell_border_none' => 'None', - 'cell_border_hidden' => 'Hidden', + 'cell_border_inset' => 'Infälld', + 'cell_border_outset' => 'Utfälld', + 'cell_border_none' => 'Ingen', + 'cell_border_hidden' => 'Dold', // Images, links, details/summary & embed - 'source' => 'Source', - 'alt_desc' => 'Alternative description', - 'embed' => 'Embed', - 'paste_embed' => 'Paste your embed code below:', + 'source' => 'Källa', + 'alt_desc' => 'Alternativ beskrivning', + 'embed' => 'Bädda in', + 'paste_embed' => 'Klistra in din inbäddningskod nedan:', 'url' => 'URL', - 'text_to_display' => 'Text to display', - 'title' => 'Title', - 'open_link' => 'Open link in...', - 'open_link_current' => 'Current window', - 'open_link_new' => 'New window', - 'insert_collapsible' => 'Insert collapsible block', - 'collapsible_unwrap' => 'Unwrap', - 'edit_label' => 'Edit label', - 'toggle_open_closed' => 'Toggle open/closed', - 'collapsible_edit' => 'Edit collapsible block', - 'toggle_label' => 'Toggle label', + 'text_to_display' => 'Text som ska visas', + 'title' => 'Titel', + 'open_link' => 'Öppna länk i...', + 'open_link_current' => 'Aktuellt fönster', + 'open_link_new' => 'Nytt fönster', + 'insert_collapsible' => 'Infoga hopfällbart block', + 'collapsible_unwrap' => 'Expandera', + 'edit_label' => 'Redigera etikett', + 'toggle_open_closed' => 'Växla mellan öppen/stängd', + 'collapsible_edit' => 'Redigera hopfällbart block', + 'toggle_label' => 'Visa eller dölj etikett', // About view 'about' => 'About the editor', - 'about_title' => 'About the WYSIWYG Editor', + 'about_title' => 'Om WYSIWYG redigeraren', 'editor_license' => 'Editor License & Copyright', - 'editor_tiny_license' => 'This editor is built using :tinyLink which is provided under the MIT license.', - 'editor_tiny_license_link' => 'The copyright and license details of TinyMCE can be found here.', - 'save_continue' => 'Save Page & Continue', - 'callouts_cycle' => '(Keep pressing to toggle through types)', + 'editor_tiny_license' => 'Denna redigerare är byggd med :tinyLink som tillhandahålls under MIT licensen.', + 'editor_tiny_license_link' => 'Upphovsrätten och licensuppgifterna för TinyMCE hittar du här.', + 'save_continue' => 'Spara & Fortsätt', + 'callouts_cycle' => '(Fortsätt trycka för att växla mellan typer)', 'link_selector' => 'Link to content', - 'shortcuts' => 'Shortcuts', - 'shortcut' => 'Shortcut', - 'shortcuts_intro' => 'The following shortcuts are available in the editor:', + 'shortcuts' => 'Genvägar', + 'shortcut' => 'Genväg', + 'shortcuts_intro' => 'Följande genvägar finns i redigeraren:', 'windows_linux' => '(Windows/Linux)', 'mac' => '(Mac)', - 'description' => 'Description', + 'description' => 'Beskrivning', ]; diff --git a/resources/lang/sv/entities.php b/resources/lang/sv/entities.php index afa94c9ed..74957a9e4 100644 --- a/resources/lang/sv/entities.php +++ b/resources/lang/sv/entities.php @@ -23,7 +23,7 @@ return [ 'meta_updated' => 'Uppdaterad :timeLength', 'meta_updated_name' => 'Uppdaterad :timeLength av :user', 'meta_owned_name' => 'Ägs av :user', - 'meta_reference_page_count' => 'Referenced on 1 page|Referenced on :count pages', + 'meta_reference_page_count' => 'Referas till på en sida|Refereras till på :count sidor', 'entity_select' => 'Välj enhet', 'entity_select_lack_permission' => 'You don\'t have the required permissions to select this item', 'images' => 'Bilder', @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Rättigheter', - 'permissions_intro' => 'Dessa rättigheter kommer att överskrida eventuella rollbaserade rättigheter.', - 'permissions_enable' => 'Aktivera anpassade rättigheter', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Spara rättigheter', 'permissions_owner' => 'Ägare', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Sökresultat', @@ -352,27 +356,27 @@ return [ 'revision_cannot_delete_latest' => 'Det går inte att ta bort den senaste versionen.', // Copy view - 'copy_consider' => 'Please consider the below when copying content.', - 'copy_consider_permissions' => 'Custom permission settings will not be copied.', - 'copy_consider_owner' => 'You will become the owner of all copied content.', - 'copy_consider_images' => 'Page image files will not be duplicated & the original images will retain their relation to the page they were originally uploaded to.', - 'copy_consider_attachments' => 'Page attachments will not be copied.', - 'copy_consider_access' => 'A change of location, owner or permissions may result in this content being accessible to those previously without access.', + 'copy_consider' => 'Tänk på nedan när du kopierar innehåll.', + 'copy_consider_permissions' => 'Anpassade behörighetsinställningar kommer inte att kopieras.', + 'copy_consider_owner' => 'Du kommer att bli ägare till allt kopierat innehåll.', + 'copy_consider_images' => 'Bildfiler för sidan kommer inte att dupliceras och de ursprungliga bilderna kommer att behålla sin relation till den sida de ursprungligen laddades upp till.', + 'copy_consider_attachments' => 'Sidans bifogade filer kommer inte att kopieras.', + 'copy_consider_access' => 'Ändring av plats, ägare eller behörigheter kan leda till att detta innehåll blir tillgängligt för dem som tidigare inte haft åtkomst.', // Conversions - 'convert_to_shelf' => 'Convert to Shelf', - 'convert_to_shelf_contents_desc' => 'You can convert this book to a new shelf with the same contents. Chapters contained within this book will be converted to new books. If this book contains any pages, that are not in a chapter, this book will be renamed and contain such pages, and this book will become part of the new shelf.', - 'convert_to_shelf_permissions_desc' => 'Any permissions set on this book will be copied to the new shelf and to all new child books that don\'t have their own permissions enforced. Note that permissions on shelves do not auto-cascade to content within, as they do for books.', - 'convert_book' => 'Convert Book', - 'convert_book_confirm' => 'Are you sure you want to convert this book?', - 'convert_undo_warning' => 'This cannot be as easily undone.', - 'convert_to_book' => 'Convert to Book', - 'convert_to_book_desc' => 'You can convert this chapter to a new book with the same contents. Any permissions set on this chapter will be copied to the new book but any inherited permissions, from the parent book, will not be copied which could lead to a change of access control.', - 'convert_chapter' => 'Convert Chapter', - 'convert_chapter_confirm' => 'Are you sure you want to convert this chapter?', + 'convert_to_shelf' => 'Konvertera till hylla', + 'convert_to_shelf_contents_desc' => 'Du kan konvertera denna bok till en ny hylla med samma innehåll. Kapitlen inom denna bok konverteras till nya böcker. Om denna bok innehåller sidor som inte är i ett kapitel så kommer denna bok att döpas om och innehålla dessa sidor. Denna bok blir då en del av den nya hyllan.', + 'convert_to_shelf_permissions_desc' => 'Alla behörigheter som ställs in på denna bok kommer att kopieras till den nya hyllan och till alla nya underböcker som inte har egna behörigheter applicerade. Observera att behörigheter på hyllor inte automatisk ärvs av innehåll inom hyllan, så som med böcker.', + 'convert_book' => 'Konvertera bok', + 'convert_book_confirm' => 'Är du säker på att du vill konvertera boken?', + 'convert_undo_warning' => 'Detta kan inte ångras lika lätt.', + 'convert_to_book' => 'Konvertera till bok', + 'convert_to_book_desc' => 'Du kan konvertera detta kapitel till en ny bok med samma innehåll. Eventuella behörigheter som angetts på detta kapitel kommer att kopieras till den nya boken men ärvda behörigheter från föräldraboken kommer inte att kopieras vilket kan leda till skillnader i åtkomsten.', + 'convert_chapter' => 'Konvertera kapitel', + 'convert_chapter_confirm' => 'Är du säker på att du vill konvertera det här kapitlet?', // References - 'references' => 'References', - 'references_none' => 'There are no tracked references to this item.', - 'references_to_desc' => 'Shown below are all the known pages in the system that link to this item.', + 'references' => 'Referenser', + 'references_none' => 'Det finns inga referenser kopplade till detta objekt.', + 'references_to_desc' => 'Nedan visas alla kända sidor i systemet som länkar till detta objekt.', ]; diff --git a/resources/lang/sv/errors.php b/resources/lang/sv/errors.php index 482fbc21f..dfd13f25d 100644 --- a/resources/lang/sv/errors.php +++ b/resources/lang/sv/errors.php @@ -23,10 +23,10 @@ return [ 'saml_no_email_address' => 'Kunde inte hitta en e-postadress för den här användaren i data som tillhandahålls av det externa autentiseringssystemet', 'saml_invalid_response_id' => 'En begäran från det externa autentiseringssystemet känns inte igen av en process som startats av denna applikation. Att navigera bakåt efter en inloggning kan orsaka detta problem.', 'saml_fail_authed' => 'Inloggning med :system misslyckades, systemet godkände inte auktoriseringen', - 'oidc_already_logged_in' => 'Already logged in', - 'oidc_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', - 'oidc_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', - 'oidc_fail_authed' => 'Login using :system failed, system did not provide successful authorization', + 'oidc_already_logged_in' => 'Redan inloggad', + 'oidc_user_not_registered' => 'Användaren :name är inte registrerad och automatisk registrering är inaktiverad', + 'oidc_no_email_address' => 'Kunde inte hitta en e-postadress för den här användaren i den data som tillhandahölls av det externa autentiseringssystemet', + 'oidc_fail_authed' => 'Inloggning med :system misslyckades, systemet presenterade inte en godkänd auktorisering', 'social_no_action_defined' => 'Ingen åtgärd definierad', 'social_login_bad_response' => "Ett fel inträffade vid inloggning genom :socialAccount: \n:error", 'social_account_in_use' => 'Detta konto från :socialAccount används redan. Testa att logga in med :socialAccount istället.', @@ -58,7 +58,7 @@ return [ // Entities 'entity_not_found' => 'Innehållet hittades inte', - 'bookshelf_not_found' => 'Shelf not found', + 'bookshelf_not_found' => 'Hyllan hittades inte', 'book_not_found' => 'Boken hittades inte', 'page_not_found' => 'Sidan hittades inte', 'chapter_not_found' => 'Kapitlet hittades inte', diff --git a/resources/lang/sv/settings.php b/resources/lang/sv/settings.php index f27605454..cc4a280be 100644 --- a/resources/lang/sv/settings.php +++ b/resources/lang/sv/settings.php @@ -10,8 +10,8 @@ return [ 'settings' => 'Inställningar', 'settings_save' => 'Spara inställningar', 'settings_save_success' => 'Inställningarna har sparats', - 'system_version' => 'System Version', - 'categories' => 'Categories', + 'system_version' => 'Systemversion', + 'categories' => 'Kategorier', // App Settings 'app_customization' => 'Sidanpassning', @@ -27,8 +27,8 @@ return [ 'app_secure_images' => 'Aktivera högre säkerhet för bilduppladdningar?', 'app_secure_images_toggle' => 'Aktivera säkrare bilduppladdningar', 'app_secure_images_desc' => 'Av prestandaskäl är alla bilder publika. Det här alternativet lägger till en slumpmässig, svårgissad sträng framför alla bild-URL:er. Se till att kataloglistning inte är aktivt för att förhindra åtkomst.', - 'app_default_editor' => 'Default Page Editor', - 'app_default_editor_desc' => 'Select which editor will be used by default when editing new pages. This can be overridden at a page level where permissions allow.', + 'app_default_editor' => 'Standard sidredigerare', + 'app_default_editor_desc' => 'Välj vilken redigerare som ska användas som standard vid redigering av nya sidor. Detta kan ändras enskilt för sidor som tillåter det.', 'app_custom_html' => 'Egen HTML i ', 'app_custom_html_desc' => 'Eventuellt innehåll i det här fältet placeras längst ner i -sektionen på varje sida. Detta är användbart för att skriva över stilmaller eller lägga in spårningskoder.', 'app_custom_html_disabled_notice' => 'Anpassat innehåll i HTML-huvud är inaktiverat på denna inställningssida för att säkerställa att eventuella ändringar som påverkar funktionaliteten kan återställas.', @@ -89,16 +89,16 @@ return [ 'maint_send_test_email_mail_text' => 'Grattis! Eftersom du fick detta e-postmeddelande verkar dina e-postinställningar vara korrekt konfigurerade.', 'maint_recycle_bin_desc' => 'Borttagna hyllor, böcker, kapitel & sidor skickas till papperskorgen så att de kan återställas eller raderas permanent. Äldre objekt i papperskorgen kan automatiskt tas bort efter ett tag beroende på systemkonfiguration.', 'maint_recycle_bin_open' => 'Öppna papperskorgen', - 'maint_regen_references' => 'Regenerate References', - 'maint_regen_references_desc' => 'This action will rebuild the cross-item reference index within the database. This is usually handled automatically but this action can be useful to index old content or content added via unofficial methods.', - 'maint_regen_references_success' => 'Reference index has been regenerated!', - 'maint_timeout_command_note' => 'Note: This action can take time to run, which can lead to timeout issues in some web environments. As an alternative, this action be performed using a terminal command.', + 'maint_regen_references' => 'Regenerera referenser', + 'maint_regen_references_desc' => 'Den här åtgärden kommer att bygga om referensindex för kopplade objekt i databasen. Detta hanteras vanligtvis automatiskt, men denna åtgärd kan vara användbar för att indexera gammalt innehåll eller innehåll som lagts till via inofficiella metoder.', + 'maint_regen_references_success' => 'Referensindex har regenererats!', + 'maint_timeout_command_note' => 'Obs: Denna åtgärd kan ta tid att köra, vilket kan leda till timeoutproblem i vissa webbmiljöer. Som ett alternativ kan denna åtgärd utföras med ett terminalkommando.', // Recycle Bin 'recycle_bin' => 'Papperskorgen', 'recycle_bin_desc' => 'Här kan du återställa objekt som har tagits bort eller välja att permanent ta bort dem från systemet. Denna lista är ofiltrerad till skillnad från liknande aktivitetslistor i systemet där behörighetsfilter tillämpas.', 'recycle_bin_deleted_item' => 'Raderat objekt', - 'recycle_bin_deleted_parent' => 'Parent', + 'recycle_bin_deleted_parent' => 'Överordnad', 'recycle_bin_deleted_by' => 'Borttagen av', 'recycle_bin_deleted_at' => 'Tid för borttagning', 'recycle_bin_permanently_delete' => 'Radera permanent', @@ -111,7 +111,7 @@ return [ 'recycle_bin_restore_list' => 'Objekt som ska återställas', 'recycle_bin_restore_confirm' => 'Denna åtgärd kommer att återställa det raderade objektet, inklusive alla underordnade element, till deras ursprungliga plats. Om den ursprungliga platsen har tagits bort sedan dess, och är nu i papperskorgen, kommer det överordnade objektet också att behöva återställas.', 'recycle_bin_restore_deleted_parent' => 'Föräldern till det här objektet har också tagits bort. Dessa kommer att förbli raderade tills den förälder är återställd.', - 'recycle_bin_restore_parent' => 'Restore Parent', + 'recycle_bin_restore_parent' => 'Återställ överordnad', 'recycle_bin_destroy_notification' => 'Raderade :count totala objekt från papperskorgen.', 'recycle_bin_restore_notification' => 'Återställt :count totala objekt från papperskorgen.', @@ -125,7 +125,7 @@ return [ 'audit_table_user' => 'Användare', 'audit_table_event' => 'Händelse', 'audit_table_related' => 'Relaterat objekt eller detalj', - 'audit_table_ip' => 'IP Address', + 'audit_table_ip' => 'IP-adress', 'audit_table_date' => 'Datum för senaste aktiviteten', 'audit_date_from' => 'Datumintervall från', 'audit_date_to' => 'Datumintervall till', @@ -145,7 +145,7 @@ return [ 'role_details' => 'Om rollen', 'role_name' => 'Rollens namn', 'role_desc' => 'Kort beskrivning av rollen', - 'role_mfa_enforced' => 'Requires Multi-Factor Authentication', + 'role_mfa_enforced' => 'Kräver multifaktorsautentisering', 'role_external_auth_id' => 'Externa autentiserings-ID:n', 'role_system' => 'Systemrättigheter', 'role_manage_users' => 'Hanter användare', @@ -155,13 +155,13 @@ return [ 'role_manage_page_templates' => 'Hantera mallar', 'role_access_api' => 'Åtkomst till systemets API', 'role_manage_settings' => 'Hantera appinställningar', - 'role_export_content' => 'Export content', - 'role_editor_change' => 'Change page editor', + 'role_export_content' => 'Exportera innehåll', + 'role_editor_change' => 'Ändra sidredigerare', 'role_asset' => 'Tillgång till innehåll', 'roles_system_warning' => 'Var medveten om att åtkomst till någon av ovanstående tre behörigheter kan tillåta en användare att ändra sina egna rättigheter eller andras rättigheter i systemet. Tilldela endast roller med dessa behörigheter till betrodda användare.', 'role_asset_desc' => 'Det här är standardinställningarna för allt innehåll i systemet. Eventuella anpassade rättigheter på böcker, kapitel och sidor skriver över dessa inställningar.', 'role_asset_admins' => 'Administratörer har automatisk tillgång till allt innehåll men dessa alternativ kan visa och dölja vissa gränssnittselement', - 'role_asset_image_view_note' => 'This relates to visibility within the image manager. Actual access of uploaded image files will be dependant upon system image storage option.', + 'role_asset_image_view_note' => 'Detta avser synlighet inom bildhanteraren. Faktisk åtkomst för uppladdade bildfiler kommer att bero på alternativ för bildlagring.', 'role_all' => 'Alla', 'role_own' => 'Egna', 'role_controlled_by_asset' => 'Kontrolleras av den sida de laddas upp till', @@ -182,7 +182,7 @@ return [ 'users_role' => 'Användarroller', 'users_role_desc' => 'Välj vilka roller den här användaren ska tilldelas. Om en användare har tilldelats flera roller kommer behörigheterna från dessa roller att staplas och de kommer att få alla rättigheter i de tilldelade rollerna.', 'users_password' => 'Användarlösenord', - 'users_password_desc' => 'Set a password used to log-in to the application. This must be at least 8 characters long.', + 'users_password_desc' => 'Ange ett lösenord som ska användas för att logga in på sidan. Lösenordet måste vara minst 8 tecken långt.', 'users_send_invite_text' => 'Du kan välja att skicka denna användare ett e-postmeddelande som tillåter dem att ställa in sitt eget lösenord, eller så kan du ställa in deras lösenord själv.', 'users_send_invite_option' => 'Skicka e-post med inbjudan', 'users_external_auth_id' => 'Externt ID för autentisering', @@ -213,10 +213,10 @@ return [ 'users_api_tokens_create' => 'Skapa token', 'users_api_tokens_expires' => 'Förfaller', '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' => 'Multifaktorautentisering', + 'users_mfa_desc' => 'Konfigurera multifaktorsautentisering som ett extra skydd för ditt konto.', + 'users_mfa_x_methods' => ':count metod konfigurerad|:count metoder konfigurerade', + 'users_mfa_configure' => 'Konfigurera metoder', // API Tokens 'user_api_token_create' => 'Skapa API-nyckel', @@ -241,11 +241,11 @@ return [ // Webhooks 'webhooks' => 'Webhooks', - 'webhooks_create' => 'Create New Webhook', - 'webhooks_none_created' => 'No webhooks have yet been created.', - 'webhooks_edit' => 'Edit Webhook', - 'webhooks_save' => 'Save Webhook', - 'webhooks_details' => 'Webhook Details', + 'webhooks_create' => 'Skapa ny webhook', + 'webhooks_none_created' => 'Inga webhooks har skapats än.', + 'webhooks_edit' => 'Redigera webhook', + 'webhooks_save' => 'Spara webhook', + 'webhooks_details' => 'Webhook-detaljer', 'webhooks_details_desc' => 'Provide a user friendly name and a POST endpoint as a location for the webhook data to be sent to.', 'webhooks_events' => 'Webhook Events', 'webhooks_events_desc' => 'Select all the events that should trigger this webhook to be called.', diff --git a/resources/lang/sv/validation.php b/resources/lang/sv/validation.php index 2d7f1da9a..b9c609f48 100644 --- a/resources/lang/sv/validation.php +++ b/resources/lang/sv/validation.php @@ -15,7 +15,7 @@ return [ 'alpha_dash' => ':attribute får bara innehålla bokstäver, siffror och bindestreck.', 'alpha_num' => ':attribute får bara innehålla bokstäver och siffror.', 'array' => ':attribute måste vara en array.', - 'backup_codes' => 'The provided code is not valid or has already been used.', + 'backup_codes' => 'Den angivna koden är inte giltig eller har redan använts.', 'before' => ':attribute måste vara före :date.', 'between' => [ 'numeric' => ':attribute måste vara mellan :min och :max.', @@ -32,7 +32,7 @@ return [ 'digits_between' => ':attribute måste vara mellan :min och :max siffror.', 'email' => ':attribute måste vara en giltig e-postadress.', 'ends_with' => ':attribute måste sluta med något av följande: :values', - 'file' => 'The :attribute must be provided as a valid file.', + 'file' => ':attribute måste anges som en giltig fil.', 'filled' => ':attribute är obligatoriskt.', 'gt' => [ 'numeric' => ':attribute måste vara större än :value.', @@ -100,7 +100,7 @@ return [ ], 'string' => ':attribute måste vara en sträng.', 'timezone' => ':attribute måste vara en giltig tidszon.', - 'totp' => 'The provided code is not valid or has expired.', + 'totp' => 'Den angivna koden är inte giltig eller har löpt ut.', 'unique' => ':attribute är upptaget', 'url' => 'Formatet på :attribute är ogiltigt.', 'uploaded' => 'Filen kunde inte laddas upp. Servern kanske inte tillåter filer med denna storlek.', diff --git a/resources/lang/tr/editor.php b/resources/lang/tr/editor.php index d5a413880..7324de26a 100644 --- a/resources/lang/tr/editor.php +++ b/resources/lang/tr/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Bağlantı Ekle/Düzenle', 'insert_horizontal_line' => 'Yatay çizgi ekle', 'insert_code_block' => 'Kod bloğu ekle', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Çizim ekle/düzenle', 'drawing_manager' => 'Çizim yöneticisi', 'insert_media' => 'Medya ekle/düzenle', diff --git a/resources/lang/tr/entities.php b/resources/lang/tr/entities.php index 30cd221e3..e361b3c00 100644 --- a/resources/lang/tr/entities.php +++ b/resources/lang/tr/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'İzinler', - 'permissions_intro' => 'Etkinleştirildikten sonra bu izinler, diğer bütün izinlerden öncelikli olacaktır.', - 'permissions_enable' => 'Özelleştirilmiş Yetkileri Etkinleştir', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'İzinleri Kaydet', 'permissions_owner' => 'Sahip', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Arama Sonuçları', diff --git a/resources/lang/uk/editor.php b/resources/lang/uk/editor.php index 68eb372ba..2c71dc628 100644 --- a/resources/lang/uk/editor.php +++ b/resources/lang/uk/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Вставити/редагувати посилання', 'insert_horizontal_line' => 'Вставити горизонтальну лінію', 'insert_code_block' => 'Вставити блок коду', + 'edit_code_block' => 'Редагування код блоку', 'insert_drawing' => 'Вставити/редагувати малюнок', 'drawing_manager' => 'Диспетчер малювання', 'insert_media' => 'Вставити/редагувати медіа', diff --git a/resources/lang/uk/entities.php b/resources/lang/uk/entities.php index a1f43c7dd..3db380b15 100644 --- a/resources/lang/uk/entities.php +++ b/resources/lang/uk/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Дозволи', - 'permissions_intro' => 'Після ввімкнення ці дозволи будуть мати вищий пріоритет ніж інші дозволи ролей.', - 'permissions_enable' => 'Увімкнути спеціальні дозволи', + 'permissions_desc' => 'Встановіть тут дозволи, щоб перевизначити права за замовчуванням, які надаються ролями користувачів.', + 'permissions_book_cascade' => 'Дозволи, встановлені на книги будуть автоматично каскадом до дитячих глав та сторінок, якщо вони не матимуть свої дозволи.', + 'permissions_chapter_cascade' => 'Дозволи, встановлені для глав будуть автоматично каскадом на дочірні сторінки, якщо вони не матимуть своїх прав.', 'permissions_save' => 'Зберегти дозволи', 'permissions_owner' => 'Власник', + 'permissions_role_everyone_else' => 'Всі інші', + 'permissions_role_everyone_else_desc' => 'Встановити дозвіл для всіх ролей не спеціально перевизначений.', + 'permissions_role_override' => 'Змінити права доступу для ролі', // Search 'search_results' => 'Результати пошуку', diff --git a/resources/lang/uz/editor.php b/resources/lang/uz/editor.php index da7ffcf01..faf351da2 100644 --- a/resources/lang/uz/editor.php +++ b/resources/lang/uz/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Insert/Edit Link', 'insert_horizontal_line' => 'Insert horizontal line', 'insert_code_block' => 'Insert code block', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Insert/edit drawing', 'drawing_manager' => 'Drawing manager', 'insert_media' => 'Insert/edit media', diff --git a/resources/lang/uz/entities.php b/resources/lang/uz/entities.php index 7ca01e145..b747a7f67 100644 --- a/resources/lang/uz/entities.php +++ b/resources/lang/uz/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Huquqlar', - 'permissions_intro' => 'Once enabled, These permissions will take priority over any set role permissions.', - 'permissions_enable' => 'Enable Custom Permissions', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Save Permissions', 'permissions_owner' => 'Egasi', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Qidiruv natijalari', diff --git a/resources/lang/vi/editor.php b/resources/lang/vi/editor.php index da7ffcf01..faf351da2 100644 --- a/resources/lang/vi/editor.php +++ b/resources/lang/vi/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Insert/Edit Link', 'insert_horizontal_line' => 'Insert horizontal line', 'insert_code_block' => 'Insert code block', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Insert/edit drawing', 'drawing_manager' => 'Drawing manager', 'insert_media' => 'Insert/edit media', diff --git a/resources/lang/vi/entities.php b/resources/lang/vi/entities.php index a8cc8b58e..32a4653c4 100644 --- a/resources/lang/vi/entities.php +++ b/resources/lang/vi/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => 'Quyền', - 'permissions_intro' => 'Một khi được bật, các quyền này sẽ được ưu tiên trên hết tất cả các quyền hạn khác.', - 'permissions_enable' => 'Bật quyền hạn tùy chỉnh', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => 'Lưu quyền hạn', 'permissions_owner' => 'Chủ sở hữu', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => 'Kết quả Tìm kiếm', diff --git a/resources/lang/zh_CN/editor.php b/resources/lang/zh_CN/editor.php index 14dc443f0..7d384b92e 100644 --- a/resources/lang/zh_CN/editor.php +++ b/resources/lang/zh_CN/editor.php @@ -66,6 +66,7 @@ return [ 'insert_link_title' => '插入/编辑链接', 'insert_horizontal_line' => '插入水平线', 'insert_code_block' => '插入代码块', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => '插入/编辑绘图', 'drawing_manager' => '绘图管理器', 'insert_media' => '插入/编辑媒体', diff --git a/resources/lang/zh_CN/entities.php b/resources/lang/zh_CN/entities.php index 02b39f371..363b993cc 100644 --- a/resources/lang/zh_CN/entities.php +++ b/resources/lang/zh_CN/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => '权限', - 'permissions_intro' => '本设置优先于每个用户角色本身所具有的权限。', - 'permissions_enable' => '启用自定义权限', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => '保存权限', 'permissions_owner' => '拥有者', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => '搜索结果', diff --git a/resources/lang/zh_TW/activities.php b/resources/lang/zh_TW/activities.php index d2e6e06b1..a131f4a6c 100644 --- a/resources/lang/zh_TW/activities.php +++ b/resources/lang/zh_TW/activities.php @@ -28,8 +28,8 @@ return [ // Books 'book_create' => '已建立書本', 'book_create_notification' => '書本已建立成功', - 'book_create_from_chapter' => 'converted chapter to book', - 'book_create_from_chapter_notification' => 'Chapter successfully converted to a book', + 'book_create_from_chapter' => '將章節轉爲書籍', + 'book_create_from_chapter_notification' => '章節已轉換爲書籍', 'book_update' => '已更新書本', 'book_update_notification' => '書本已更新成功', 'book_delete' => '已刪除書本', @@ -38,14 +38,14 @@ return [ 'book_sort_notification' => '書本已重新排序成功', // Bookshelves - 'bookshelf_create' => 'created shelf', - 'bookshelf_create_notification' => 'Shelf successfully created', - 'bookshelf_create_from_book' => 'converted book to shelf', - 'bookshelf_create_from_book_notification' => 'Book successfully converted to a shelf', - 'bookshelf_update' => 'updated shelf', - 'bookshelf_update_notification' => 'Shelf successfully updated', - 'bookshelf_delete' => 'deleted shelf', - 'bookshelf_delete_notification' => 'Shelf successfully deleted', + 'bookshelf_create' => '已建立書棧', + 'bookshelf_create_notification' => '書棧已創建', + 'bookshelf_create_from_book' => '將書籍轉爲書棧', + 'bookshelf_create_from_book_notification' => '章節已轉爲書籍', + 'bookshelf_update' => '更新書棧', + 'bookshelf_update_notification' => '書棧已更新', + 'bookshelf_delete' => '刪除書棧', + 'bookshelf_delete_notification' => '書棧已刪除', // Favourites 'favourite_add_notification' => '":name" 已加入到你的最愛', diff --git a/resources/lang/zh_TW/editor.php b/resources/lang/zh_TW/editor.php index da7ffcf01..efefc15bc 100644 --- a/resources/lang/zh_TW/editor.php +++ b/resources/lang/zh_TW/editor.php @@ -7,47 +7,47 @@ */ return [ // General editor terms - 'general' => 'General', + 'general' => '通用', 'advanced' => 'Advanced', - 'none' => 'None', - 'cancel' => 'Cancel', - 'save' => 'Save', - 'close' => 'Close', - 'undo' => 'Undo', - 'redo' => 'Redo', - 'left' => 'Left', - 'center' => 'Center', - 'right' => 'Right', - 'top' => 'Top', - 'middle' => 'Middle', - 'bottom' => 'Bottom', - 'width' => 'Width', - 'height' => 'Height', - 'More' => 'More', - 'select' => 'Select...', + 'none' => '無', + 'cancel' => '取消', + 'save' => '保存', + 'close' => '關閉', + 'undo' => '復原', + 'redo' => '重做', + 'left' => '左側', + 'center' => '置中', + 'right' => '右側', + 'top' => '上方', + 'middle' => '中間', + 'bottom' => '底端', + 'width' => '寬度', + 'height' => '高度', + 'More' => '更多', + 'select' => '選擇...', // Toolbar - 'formats' => 'Formats', - 'header_large' => 'Large Header', - 'header_medium' => 'Medium Header', - 'header_small' => 'Small Header', + 'formats' => '格式', + 'header_large' => '大標題', + 'header_medium' => '中標題', + 'header_small' => '小標題', 'header_tiny' => 'Tiny Header', - 'paragraph' => 'Paragraph', - 'blockquote' => 'Blockquote', - 'inline_code' => 'Inline code', - 'callouts' => 'Callouts', - 'callout_information' => 'Information', - 'callout_success' => 'Success', - 'callout_warning' => 'Warning', - 'callout_danger' => 'Danger', - 'bold' => 'Bold', - 'italic' => 'Italic', - 'underline' => 'Underline', - 'strikethrough' => 'Strikethrough', - 'superscript' => 'Superscript', - 'subscript' => 'Subscript', - 'text_color' => 'Text color', - 'custom_color' => 'Custom color', + 'paragraph' => '段落', + 'blockquote' => '引用塊', + 'inline_code' => '行內程式碼', + 'callouts' => '圖說文字', + 'callout_information' => '資訊', + 'callout_success' => '成功', + 'callout_warning' => '警告', + 'callout_danger' => '危險', + 'bold' => '粗體', + 'italic' => '斜體', + 'underline' => '底線', + 'strikethrough' => '刪除線', + 'superscript' => '上標', + 'subscript' => '下標', + 'text_color' => '文本顏色', + 'custom_color' => '自訂顏色', 'remove_color' => 'Remove color', 'background_color' => 'Background color', 'align_left' => 'Align left', @@ -56,9 +56,9 @@ return [ 'align_justify' => 'Justify', 'list_bullet' => 'Bullet list', 'list_numbered' => 'Numbered list', - 'list_task' => 'Task list', - 'indent_increase' => 'Increase indent', - 'indent_decrease' => 'Decrease indent', + 'list_task' => '任務清單', + 'indent_increase' => '增加縮進', + 'indent_decrease' => '減少縮進', 'table' => 'Table', 'insert_image' => 'Insert image', 'insert_image_title' => 'Insert/Edit Image', @@ -66,6 +66,7 @@ return [ 'insert_link_title' => 'Insert/Edit Link', 'insert_horizontal_line' => 'Insert horizontal line', 'insert_code_block' => 'Insert code block', + 'edit_code_block' => 'Edit code block', 'insert_drawing' => 'Insert/edit drawing', 'drawing_manager' => 'Drawing manager', 'insert_media' => 'Insert/edit media', @@ -111,9 +112,9 @@ return [ 'paste_row_before' => 'Paste row before', 'paste_row_after' => 'Paste row after', 'row_type' => 'Row type', - 'row_type_header' => 'Header', - 'row_type_body' => 'Body', - 'row_type_footer' => 'Footer', + 'row_type_header' => '頁眉', + 'row_type_body' => '正文', + 'row_type_footer' => '页脚', 'alignment' => 'Alignment', 'cut_column' => 'Cut column', 'copy_column' => 'Copy column', @@ -136,11 +137,11 @@ return [ 'cell_border_hidden' => 'Hidden', // Images, links, details/summary & embed - 'source' => 'Source', + 'source' => '來源', 'alt_desc' => 'Alternative description', 'embed' => 'Embed', 'paste_embed' => 'Paste your embed code below:', - 'url' => 'URL', + 'url' => '網址', 'text_to_display' => 'Text to display', 'title' => 'Title', 'open_link' => 'Open link in...', @@ -148,7 +149,7 @@ return [ 'open_link_new' => 'New window', 'insert_collapsible' => 'Insert collapsible block', 'collapsible_unwrap' => 'Unwrap', - 'edit_label' => 'Edit label', + 'edit_label' => '編輯標記', 'toggle_open_closed' => 'Toggle open/closed', 'collapsible_edit' => 'Edit collapsible block', 'toggle_label' => 'Toggle label', diff --git a/resources/lang/zh_TW/entities.php b/resources/lang/zh_TW/entities.php index 574227287..a9a8c89c3 100644 --- a/resources/lang/zh_TW/entities.php +++ b/resources/lang/zh_TW/entities.php @@ -42,10 +42,14 @@ return [ // Permissions and restrictions 'permissions' => '權限', - 'permissions_intro' => '一旦啟用,這些權限將優先於任何設定的角色權限。', - 'permissions_enable' => '啟用自訂權限', + 'permissions_desc' => 'Set permissions here to override the default permissions provided by user roles.', + 'permissions_book_cascade' => 'Permissions set on books will automatically cascade to child chapters and pages, unless they have their own permissions defined.', + 'permissions_chapter_cascade' => 'Permissions set on chapters will automatically cascade to child pages, unless they have their own permissions defined.', 'permissions_save' => '儲存權限', 'permissions_owner' => '擁有者', + 'permissions_role_everyone_else' => 'Everyone Else', + 'permissions_role_everyone_else_desc' => 'Set permissions for all roles not specifically overridden.', + 'permissions_role_override' => 'Override permissions for role', // Search 'search_results' => '搜尋結果', diff --git a/resources/lang/zh_TW/errors.php b/resources/lang/zh_TW/errors.php index c6644dd1c..b1735038d 100644 --- a/resources/lang/zh_TW/errors.php +++ b/resources/lang/zh_TW/errors.php @@ -58,7 +58,7 @@ return [ // Entities 'entity_not_found' => '找不到實體', - 'bookshelf_not_found' => 'Shelf not found', + 'bookshelf_not_found' => '未找到書棧', 'book_not_found' => '找不到書本', 'page_not_found' => '找不到頁面', 'chapter_not_found' => '找不到章節', diff --git a/resources/lang/zh_TW/settings.php b/resources/lang/zh_TW/settings.php index 1f523e760..cb6950835 100644 --- a/resources/lang/zh_TW/settings.php +++ b/resources/lang/zh_TW/settings.php @@ -10,8 +10,8 @@ return [ 'settings' => '設定', 'settings_save' => '儲存設定', 'settings_save_success' => '設定已儲存', - 'system_version' => 'System Version', - 'categories' => 'Categories', + 'system_version' => '系統版本', + 'categories' => '分類', // App Settings 'app_customization' => '自訂', @@ -27,8 +27,8 @@ return [ 'app_secure_images' => '更高安全性的圖片上傳', 'app_secure_images_toggle' => '啟用更高安全性的圖片上傳', 'app_secure_images_desc' => '因為效能因素,所有圖片都是公開的。此選項會在圖片的網址前加入一串隨機且難以猜測的字串。確保未啟用目錄索引,讓直接進入變得更困難。', - 'app_default_editor' => 'Default Page Editor', - 'app_default_editor_desc' => 'Select which editor will be used by default when editing new pages. This can be overridden at a page level where permissions allow.', + 'app_default_editor' => '預設頁面編輯器', + 'app_default_editor_desc' => '选择编辑新页面时默认使用的编辑器。这可以在权限允许的页面级别被覆盖。', 'app_custom_html' => '自訂 HTML 標題內容', 'app_custom_html_desc' => '此處加入的任何內容都將插入到每個頁面的 部分的底部,這對於覆蓋樣式或加入分析程式碼很方便。', 'app_custom_html_disabled_notice' => '在此設定頁面上停用了自訂 HTML 標題內容,以確保任何重大變更都能被還原。', @@ -156,7 +156,7 @@ return [ 'role_access_api' => '存取系統 API', 'role_manage_settings' => '管理應用程式設定', 'role_export_content' => '匯出內容', - 'role_editor_change' => 'Change page editor', + 'role_editor_change' => '重設頁面編輯器', 'role_asset' => '資源權限', 'roles_system_warning' => '請注意,有上述三項權限中的任一項的使用者都可以更改自己或系統中其他人的權限。有這些權限的角色只應分配給受信任的使用者。', 'role_asset_desc' => '對系統內資源的預設權限將由這裡的權限控制。若有單獨設定在書本、章節和頁面上的權限,將會覆寫這裡的權限設定。', @@ -250,7 +250,7 @@ return [ 'webhooks_events' => 'Webhook Events', 'webhooks_events_desc' => 'Select all the events that should trigger this webhook to be called.', 'webhooks_events_warning' => 'Keep in mind that these events will be triggered for all selected events, even if custom permissions are applied. Ensure that use of this webhook won\'t expose confidential content.', - 'webhooks_events_all' => 'All system events', + 'webhooks_events_all' => '全部系統活動', 'webhooks_name' => 'Webhook 名稱', 'webhooks_timeout' => 'Webhook Request Timeout (Seconds)', 'webhooks_endpoint' => 'Webhook Endpoint', diff --git a/resources/sass/_buttons.scss b/resources/sass/_buttons.scss index 714dfc42c..fb3af06e8 100644 --- a/resources/sass/_buttons.scss +++ b/resources/sass/_buttons.scss @@ -48,9 +48,10 @@ button { .button.outline { background-color: transparent; - @include lightDark(color, #666, #aaa); + @include lightDark(color, #666, #AAA); fill: currentColor; - border: 1px solid #CCC; + border: 1px solid; + @include lightDark(border-color, #CCC, #666); &:hover, &:focus, &:active { border: 1px solid #CCC; box-shadow: none; @@ -109,12 +110,23 @@ button { display: block; } -.button.icon { +.button.icon, .icon-button { .svg-icon { margin-inline-end: 0; } } +.icon-button { + text-align: center; + border: 1px solid transparent; +} +.icon-button:hover { + background-color: rgba(0, 0, 0, 0.05); + border-radius: 4px; + @include lightDark(border-color, #DDD, #444); + cursor: pointer; +} + .button.svg { display: flex; align-items: center; diff --git a/resources/sass/_components.scss b/resources/sass/_components.scss index c00f57954..9fdd5a611 100644 --- a/resources/sass/_components.scss +++ b/resources/sass/_components.scss @@ -798,11 +798,35 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group { max-width: 500px; } -.permissions-table [permissions-table-toggle-all-in-row] { - display: none; +.content-permissions { + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1); } -.permissions-table tr:hover [permissions-table-toggle-all-in-row] { - display: inline; +.content-permissions-row { + border: 1.5px solid; + @include lightDark(border-color, #E2E2E2, #444); + border-bottom-width: 0; + label { + padding-bottom: 0; + } + &:hover { + @include lightDark(background-color, #F2F2F2, #333); + } +} +.content-permissions-row:first-child { + border-radius: 4px 4px 0 0; +} +.content-permissions-row:last-child { + border-radius: 0 0 4px 4px; + border-bottom-width: 1.5px; +} +.content-permissions-row:first-child:last-child { + border-radius: 4px; +} +.content-permissions-row-toggle-all { + visibility: hidden; +} +.content-permissions-row:hover .content-permissions-row-toggle-all { + visibility: visible; } .template-item { @@ -857,7 +881,8 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group { gap: $-s; line-height: normal; .svg-icon { - height: 16px; + height: 26px; + width: 26px; margin: 0; } .avatar { @@ -879,10 +904,11 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group { white-space: nowrap; } .dropdown-search-toggle-select-caret { - font-size: 1.5rem; line-height: 0; margin-left: auto; margin-top: -2px; + display: flex; + align-items: center; } .dropdown-search-dropdown { diff --git a/resources/sass/_forms.scss b/resources/sass/_forms.scss index 7025aa898..7e0f72355 100644 --- a/resources/sass/_forms.scss +++ b/resources/sass/_forms.scss @@ -207,8 +207,8 @@ select { -moz-appearance: none; appearance: none; background: url("data:image/svg+xml;utf8,"); - background-size: 12px; - background-position: calc(100% - 20px) 70%; + background-size: 10px 12px; + background-position: calc(100% - 20px) 64%; background-repeat: no-repeat; @include rtl { @@ -266,6 +266,15 @@ input[type=color] { background-color: rgba(0, 0, 0, 0.05); opacity: 0.8; } + input[type=checkbox][disabled] ~ * { + opacity: 0.8; + cursor: not-allowed; + } + input[type=checkbox][disabled] ~ .custom-checkbox { + border-color: #999; + color: #999 !important; + background: #f2f2f2; + } } .toggle-switch-list { .toggle-switch { diff --git a/resources/sass/_layout.scss b/resources/sass/_layout.scss index 2cd57d496..cfb8397c9 100644 --- a/resources/sass/_layout.scss +++ b/resources/sass/_layout.scss @@ -158,8 +158,8 @@ body.flexbox { } } -.gap-m { - gap: $-m; +.flex-none { + flex: none; } .justify-flex-start { diff --git a/resources/sass/_pages.scss b/resources/sass/_pages.scss index 3ceec61d0..eeb51ebb5 100755 --- a/resources/sass/_pages.scss +++ b/resources/sass/_pages.scss @@ -182,7 +182,7 @@ body.tox-fullscreen, body.markdown-fullscreen { // Page content pointers .pointer-container { - position: relative; + position: fixed; display: none; left: 0; z-index: 10; @@ -196,11 +196,8 @@ body.tox-fullscreen, body.markdown-fullscreen { padding: $-s $-s; border-radius: 4px; box-shadow: 0 0 12px 1px rgba(0, 0, 0, 0.1); - position: absolute; - top: -60px; @include lightDark(background-color, #fff, #333); width: 275px; - z-index: 55; &.is-page-editable { width: 328px; diff --git a/resources/sass/_spacing.scss b/resources/sass/_spacing.scss index 40217de9b..14f8918dc 100644 --- a/resources/sass/_spacing.scss +++ b/resources/sass/_spacing.scss @@ -29,4 +29,16 @@ } } @include spacing('margin', 'm'); -@include spacing('padding', 'p'); \ No newline at end of file +@include spacing('padding', 'p'); + +@each $sizeLetter, $size in $spacing { + .gap-#{$sizeLetter} { + gap: $size !important; + } + .gap-x-#{$sizeLetter} { + column-gap: $size !important; + } + .gap-y-#{$sizeLetter} { + row-gap: $size !important; + } +} diff --git a/resources/sass/styles.scss b/resources/sass/styles.scss index 65eee866d..ab97466a5 100644 --- a/resources/sass/styles.scss +++ b/resources/sass/styles.scss @@ -246,26 +246,40 @@ $btt-size: 40px; border-radius: 3px; min-height: 20px; @include lightDark(background-color, #EEE, #000); - .scroll-box-item { +} +.scroll-box-item { + border-bottom: 1px solid; + border-top: 1px solid; + @include lightDark(border-color, #DDD, #000); + margin-top: -1px; + @include lightDark(background-color, #FFF, #222); + display: flex; + padding: 1px; + &:last-child { + border-bottom: 0; + } + &:hover { + cursor: pointer; + @include lightDark(background-color, #f8f8f8, #333); + } + .handle { + color: #AAA; + cursor: grab; + } + .handle svg { + margin: 0; + } + > * { padding: $-xs $-m; - border-bottom: 1px solid; - border-top: 1px solid; - @include lightDark(border-color, #DDD, #000); - margin-top: -1px; - @include lightDark(background-color, #FFF, #222); - display: flex; - gap: $-xs; - &:last-child { - border-bottom: 0; - } - &:hover { - cursor: pointer; - @include lightDark(background-color, #f8f8f8, #333); - } - .handle { - color: #AAA; - cursor: grab; - } + } + .handle + * { + padding-left: 0; + } + &:hover .handle { + @include lightDark(color, #444, #FFF); + } + a:hover { + text-decoration: none; } } diff --git a/resources/views/api-docs/parts/getting-started.blade.php b/resources/views/api-docs/parts/getting-started.blade.php index 76da73e45..7358b5cd7 100644 --- a/resources/views/api-docs/parts/getting-started.blade.php +++ b/resources/views/api-docs/parts/getting-started.blade.php @@ -53,10 +53,19 @@
  • application/json
  • -
  • application/x-www-form-urlencoded
  • -
  • multipart/form-data
  • +
  • application/x-www-form-urlencoded*
  • +
  • multipart/form-data*
+

+ + * Form requests currently only work for POST requests due to how PHP handles request data. + If you need to use these formats for PUT or DELETE requests you can work around this limitation by + using a POST request and providing a "_method" parameter with the value equal to + PUT or DELETE. + +

+

Regardless of format chosen, ensure you set a Content-Type header on requests so that the system can correctly parse your request data. The API is primarily designed to be interfaced using JSON, since responses are always in JSON format, hence examples in this documentation will be shown as JSON. diff --git a/resources/views/books/permissions.blade.php b/resources/views/books/permissions.blade.php index d72042d42..2e43338cd 100644 --- a/resources/views/books/permissions.blade.php +++ b/resources/views/books/permissions.blade.php @@ -14,9 +14,8 @@ ]]) -

-

{{ trans('entities.books_permissions') }}

- @include('form.entity-permissions', ['model' => $book]) +
+ @include('form.entity-permissions', ['model' => $book, 'title' => trans('entities.books_permissions')])
diff --git a/resources/views/books/show.blade.php b/resources/views/books/show.blade.php index 76a4a6005..b95b69d1b 100644 --- a/resources/views/books/show.blade.php +++ b/resources/views/books/show.blade.php @@ -71,7 +71,7 @@
{{ trans('common.details') }}
diff --git a/resources/views/chapters/show.blade.php b/resources/views/chapters/show.blade.php index 1ae2d6847..b3496eae2 100644 --- a/resources/views/chapters/show.blade.php +++ b/resources/views/chapters/show.blade.php @@ -69,7 +69,7 @@