diff --git a/.env.example.complete b/.env.example.complete index e3dbdb857..a42054b6b 100644 --- a/.env.example.complete +++ b/.env.example.complete @@ -195,6 +195,7 @@ LDAP_DN=false LDAP_PASS=false LDAP_USER_FILTER=false LDAP_VERSION=false +LDAP_START_TLS=false LDAP_TLS_INSECURE=false LDAP_ID_ATTRIBUTE=uid LDAP_EMAIL_ATTRIBUTE=mail @@ -245,10 +246,15 @@ AVATAR_URL= DRAWIO=true # Default item listing view -# Used for public visitors and user's without a preference -# Can be 'list' or 'grid' +# Used for public visitors and user's without a preference. +# Can be 'list' or 'grid'. APP_VIEWS_BOOKS=list APP_VIEWS_BOOKSHELVES=grid +APP_VIEWS_BOOKSHELF=grid + +# Use dark mode by default +# Will be overriden by any user/session preference. +APP_DEFAULT_DARK_MODE=false # Page revision limit # Number of page revisions to keep in the system before deleting old revisions. diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 7646f0687..b0ef05b8f 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -5,6 +5,7 @@ on: branches: - master - release + - gh_actions_update pull_request: branches: - '*' @@ -13,13 +14,19 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 strategy: matrix: - php: [7.2, 7.4] + php: ['7.3', '7.4', '8.0'] steps: - uses: actions/checkout@v1 + - name: Setup PHP + uses: shivammathur/setup-php@b7d1d9c9a92d8d8463ce36d7f60da34d461724f8 + with: + php-version: ${{ matrix.php }} + extensions: gd, mbstring, json, curl, xml, mysql, ldap + - name: Get Composer Cache Directory id: composer-cache run: | @@ -38,7 +45,7 @@ jobs: - name: Setup Database run: | mysql -uroot -proot -e 'CREATE DATABASE IF NOT EXISTS `bookstack-test`;' - mysql -uroot -proot -e "CREATE USER 'bookstack-test'@'localhost' IDENTIFIED BY 'bookstack-test';" + mysql -uroot -proot -e "CREATE USER 'bookstack-test'@'localhost' IDENTIFIED WITH mysql_native_password BY 'bookstack-test';" mysql -uroot -proot -e "GRANT ALL ON \`bookstack-test\`.* TO 'bookstack-test'@'localhost';" mysql -uroot -proot -e 'FLUSH PRIVILEGES;' diff --git a/.github/workflows/test-migrations.yml b/.github/workflows/test-migrations.yml index bff6f70d1..34aaf9c3f 100644 --- a/.github/workflows/test-migrations.yml +++ b/.github/workflows/test-migrations.yml @@ -5,6 +5,7 @@ on: branches: - master - release + - gh_actions_update pull_request: branches: - '*' @@ -13,13 +14,19 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 strategy: matrix: - php: [7.2, 7.4] + php: ['7.3', '7.4', '8.0'] steps: - uses: actions/checkout@v1 + - name: Setup PHP + uses: shivammathur/setup-php@b7d1d9c9a92d8d8463ce36d7f60da34d461724f8 + with: + php-version: ${{ matrix.php }} + extensions: gd, mbstring, json, curl, xml, mysql, ldap + - name: Get Composer Cache Directory id: composer-cache run: | @@ -38,7 +45,7 @@ jobs: - name: Create database & user run: | mysql -uroot -proot -e 'CREATE DATABASE IF NOT EXISTS `bookstack-test`;' - mysql -uroot -proot -e "CREATE USER 'bookstack-test'@'localhost' IDENTIFIED BY 'bookstack-test';" + mysql -uroot -proot -e "CREATE USER 'bookstack-test'@'localhost' IDENTIFIED WITH mysql_native_password BY 'bookstack-test';" mysql -uroot -proot -e "GRANT ALL ON \`bookstack-test\`.* TO 'bookstack-test'@'localhost';" mysql -uroot -proot -e 'FLUSH PRIVILEGES;' diff --git a/app/Actions/Activity.php b/app/Actions/Activity.php index 9d256c9b2..c8590f0b2 100644 --- a/app/Actions/Activity.php +++ b/app/Actions/Activity.php @@ -6,6 +6,7 @@ use BookStack\Auth\User; use BookStack\Entities\Models\Entity; use BookStack\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Support\Str; /** @@ -23,7 +24,7 @@ class Activity extends Model /** * Get the entity for this activity. */ - public function entity() + public function entity(): MorphTo { if ($this->entity_type === '') { $this->entity_type = null; diff --git a/app/Actions/ActivityService.php b/app/Actions/ActivityService.php index b2a35fd2a..73f827e70 100644 --- a/app/Actions/ActivityService.php +++ b/app/Actions/ActivityService.php @@ -78,7 +78,7 @@ class ActivityService public function latest(int $count = 20, int $page = 0): array { $activityList = $this->permissionService - ->filterRestrictedEntityRelations($this->activity, 'activities', 'entity_id', 'entity_type') + ->filterRestrictedEntityRelations($this->activity->newQuery(), 'activities', 'entity_id', 'entity_type') ->orderBy('created_at', 'desc') ->with(['user', 'entity']) ->skip($count * $page) @@ -131,7 +131,7 @@ class ActivityService public function userActivity(User $user, int $count = 20, int $page = 0): array { $activityList = $this->permissionService - ->filterRestrictedEntityRelations($this->activity, 'activities', 'entity_id', 'entity_type') + ->filterRestrictedEntityRelations($this->activity->newQuery(), 'activities', 'entity_id', 'entity_type') ->orderBy('created_at', 'desc') ->where('user_id', '=', $user->id) ->skip($count * $page) diff --git a/app/Actions/ActivityType.php b/app/Actions/ActivityType.php index 216f61249..ec02bed25 100644 --- a/app/Actions/ActivityType.php +++ b/app/Actions/ActivityType.php @@ -48,4 +48,4 @@ class ActivityType const AUTH_PASSWORD_RESET_UPDATE = 'auth_password_reset_update'; const AUTH_LOGIN = 'auth_login'; const AUTH_REGISTER = 'auth_register'; -} \ No newline at end of file +} diff --git a/app/Actions/TagRepo.php b/app/Actions/TagRepo.php index f58589ccd..c80e8abe3 100644 --- a/app/Actions/TagRepo.php +++ b/app/Actions/TagRepo.php @@ -26,7 +26,9 @@ class TagRepo */ public function getNameSuggestions(?string $searchTerm): Collection { - $query = $this->tag->select('*', DB::raw('count(*) as count'))->groupBy('name'); + $query = $this->tag->newQuery() + ->select('*', DB::raw('count(*) as count')) + ->groupBy('name'); if ($searchTerm) { $query = $query->where('name', 'LIKE', $searchTerm . '%')->orderBy('name', 'desc'); @@ -45,7 +47,9 @@ class TagRepo */ public function getValueSuggestions(?string $searchTerm, ?string $tagName): Collection { - $query = $this->tag->select('*', DB::raw('count(*) as count'))->groupBy('value'); + $query = $this->tag->newQuery() + ->select('*', DB::raw('count(*) as count')) + ->groupBy('value'); if ($searchTerm) { $query = $query->where('value', 'LIKE', $searchTerm . '%')->orderBy('value', 'desc'); diff --git a/app/Actions/ViewService.php b/app/Actions/ViewService.php index 51a60d96e..f04384536 100644 --- a/app/Actions/ViewService.php +++ b/app/Actions/ViewService.php @@ -65,7 +65,7 @@ class ViewService { $skipCount = $count * $page; $query = $this->permissionService - ->filterRestrictedEntityRelations($this->view, 'views', 'viewable_id', 'viewable_type', $action) + ->filterRestrictedEntityRelations($this->view->newQuery(), 'views', 'viewable_id', 'viewable_type', $action) ->select('*', 'viewable_id', 'viewable_type', DB::raw('SUM(views) as view_count')) ->groupBy('viewable_id', 'viewable_type') ->orderBy('view_count', 'desc'); diff --git a/app/Api/ApiDocsGenerator.php b/app/Api/ApiDocsGenerator.php index 2953647bb..8b520eda2 100644 --- a/app/Api/ApiDocsGenerator.php +++ b/app/Api/ApiDocsGenerator.php @@ -142,5 +142,4 @@ class ApiDocsGenerator ]; }); } - -} \ No newline at end of file +} diff --git a/app/Api/ApiTokenGuard.php b/app/Api/ApiTokenGuard.php index e0a50ebe3..59ab72f4e 100644 --- a/app/Api/ApiTokenGuard.php +++ b/app/Api/ApiTokenGuard.php @@ -163,4 +163,4 @@ class ApiTokenGuard implements Guard { $this->user = null; } -} \ No newline at end of file +} diff --git a/app/Auth/Access/Guards/ExternalBaseSessionGuard.php b/app/Auth/Access/Guards/ExternalBaseSessionGuard.php index 9a0c691c8..b133754d8 100644 --- a/app/Auth/Access/Guards/ExternalBaseSessionGuard.php +++ b/app/Auth/Access/Guards/ExternalBaseSessionGuard.php @@ -299,5 +299,4 @@ class ExternalBaseSessionGuard implements StatefulGuard return $this; } - } diff --git a/app/Auth/Access/Guards/LdapSessionGuard.php b/app/Auth/Access/Guards/LdapSessionGuard.php index 652141c0c..cabbfbbcb 100644 --- a/app/Auth/Access/Guards/LdapSessionGuard.php +++ b/app/Auth/Access/Guards/LdapSessionGuard.php @@ -5,14 +5,12 @@ namespace BookStack\Auth\Access\Guards; use BookStack\Auth\Access\LdapService; use BookStack\Auth\Access\RegistrationService; use BookStack\Auth\User; -use BookStack\Auth\UserRepo; use BookStack\Exceptions\LdapException; use BookStack\Exceptions\LoginAttemptException; use BookStack\Exceptions\LoginAttemptEmailNeededException; use BookStack\Exceptions\UserRegistrationException; use Illuminate\Contracts\Auth\UserProvider; use Illuminate\Contracts\Session\Session; -use Illuminate\Support\Facades\Hash; use Illuminate\Support\Str; class LdapSessionGuard extends ExternalBaseSessionGuard @@ -23,13 +21,13 @@ class LdapSessionGuard extends ExternalBaseSessionGuard /** * LdapSessionGuard constructor. */ - public function __construct($name, + public function __construct( + $name, UserProvider $provider, Session $session, LdapService $ldapService, RegistrationService $registrationService - ) - { + ) { $this->ldapService = $ldapService; parent::__construct($name, $provider, $session, $registrationService); } @@ -119,5 +117,4 @@ class LdapSessionGuard extends ExternalBaseSessionGuard return $this->registrationService->registerUser($details, null, false); } - } diff --git a/app/Auth/Access/Guards/Saml2SessionGuard.php b/app/Auth/Access/Guards/Saml2SessionGuard.php index 68683bb43..044c2f383 100644 --- a/app/Auth/Access/Guards/Saml2SessionGuard.php +++ b/app/Auth/Access/Guards/Saml2SessionGuard.php @@ -34,5 +34,4 @@ class Saml2SessionGuard extends ExternalBaseSessionGuard { return false; } - } diff --git a/app/Auth/Access/Ldap.php b/app/Auth/Access/Ldap.php index 6b7bd9b9b..352231df5 100644 --- a/app/Auth/Access/Ldap.php +++ b/app/Auth/Access/Ldap.php @@ -31,6 +31,14 @@ class Ldap return ldap_set_option($ldapConnection, $option, $value); } + /** + * Start TLS on the given LDAP connection. + */ + public function startTls($ldapConnection): bool + { + return ldap_start_tls($ldapConnection); + } + /** * Set the version number for the given ldap connection. * @param $ldapConnection diff --git a/app/Auth/Access/LdapService.php b/app/Auth/Access/LdapService.php index 92234edcf..a438c0984 100644 --- a/app/Auth/Access/LdapService.php +++ b/app/Auth/Access/LdapService.php @@ -85,9 +85,9 @@ class LdapService extends ExternalAuthService $userCn = $this->getUserResponseProperty($user, 'cn', null); $formatted = [ - 'uid' => $this->getUserResponseProperty($user, $idAttr, $user['dn']), - 'name' => $this->getUserResponseProperty($user, $displayNameAttr, $userCn), - 'dn' => $user['dn'], + 'uid' => $this->getUserResponseProperty($user, $idAttr, $user['dn']), + 'name' => $this->getUserResponseProperty($user, $displayNameAttr, $userCn), + 'dn' => $user['dn'], 'email' => $this->getUserResponseProperty($user, $emailAttr, null), ]; @@ -187,8 +187,8 @@ class LdapService extends ExternalAuthService throw new LdapException(trans('errors.ldap_extension_not_installed')); } - // Check if TLS_INSECURE is set. The handle is set to NULL due to the nature of - // the LDAP_OPT_X_TLS_REQUIRE_CERT option. It can only be set globally and not per handle. + // Disable certificate verification. + // This option works globally and must be set before a connection is created. if ($this->config['tls_insecure']) { $this->ldap->setOption(null, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_NEVER); } @@ -205,6 +205,14 @@ class LdapService extends ExternalAuthService $this->ldap->setVersion($ldapConnection, $this->config['version']); } + // Start and verify TLS if it's enabled + if ($this->config['start_tls']) { + $started = $this->ldap->startTls($ldapConnection); + if (!$started) { + throw new LdapException('Could not start TLS connection'); + } + } + $this->ldapConnection = $ldapConnection; return $this->ldapConnection; } diff --git a/app/Auth/Access/RegistrationService.php b/app/Auth/Access/RegistrationService.php index 2aff6c37d..68b17771d 100644 --- a/app/Auth/Access/RegistrationService.php +++ b/app/Auth/Access/RegistrationService.php @@ -6,6 +6,8 @@ use BookStack\Auth\User; use BookStack\Auth\UserRepo; use BookStack\Exceptions\UserRegistrationException; use BookStack\Facades\Activity; +use BookStack\Facades\Theme; +use BookStack\Theming\ThemeEvents; use Exception; class RegistrationService @@ -71,6 +73,7 @@ class RegistrationService } Activity::add(ActivityType::AUTH_REGISTER, $socialAccount ?? $newUser); + Theme::dispatch(ThemeEvents::AUTH_REGISTER, $socialAccount ? $socialAccount->driver : auth()->getDefaultDriver(), $newUser); // Start email confirmation flow if required if ($this->emailConfirmationService->confirmationRequired() && !$emailConfirmed) { @@ -83,7 +86,6 @@ class RegistrationService $message = trans('auth.email_confirm_send_error'); throw new UserRegistrationException($message, '/register/confirm'); } - } return $newUser; @@ -109,5 +111,4 @@ class RegistrationService throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), $redirect); } } - -} \ No newline at end of file +} diff --git a/app/Auth/Access/Saml2Service.php b/app/Auth/Access/Saml2Service.php index 0316ff976..105853997 100644 --- a/app/Auth/Access/Saml2Service.php +++ b/app/Auth/Access/Saml2Service.php @@ -6,6 +6,8 @@ use BookStack\Exceptions\JsonDebugException; use BookStack\Exceptions\SamlException; use BookStack\Exceptions\UserRegistrationException; use BookStack\Facades\Activity; +use BookStack\Facades\Theme; +use BookStack\Theming\ThemeEvents; use Exception; use Illuminate\Support\Str; use OneLogin\Saml2\Auth; @@ -375,6 +377,7 @@ class Saml2Service extends ExternalAuthService auth()->login($user); Activity::add(ActivityType::AUTH_LOGIN, "saml2; {$user->logDescriptor()}"); + Theme::dispatch(ThemeEvents::AUTH_LOGIN, 'saml2', $user); return $user; } } diff --git a/app/Auth/Access/SocialAuthService.php b/app/Auth/Access/SocialAuthService.php index b0383a938..7c8b66ea5 100644 --- a/app/Auth/Access/SocialAuthService.php +++ b/app/Auth/Access/SocialAuthService.php @@ -2,21 +2,23 @@ use BookStack\Actions\ActivityType; use BookStack\Auth\SocialAccount; -use BookStack\Auth\UserRepo; +use BookStack\Auth\User; use BookStack\Exceptions\SocialDriverNotConfigured; use BookStack\Exceptions\SocialSignInAccountNotUsed; use BookStack\Exceptions\UserRegistrationException; use BookStack\Facades\Activity; +use BookStack\Facades\Theme; +use BookStack\Theming\ThemeEvents; +use Illuminate\Support\Facades\Event; use Illuminate\Support\Str; use Laravel\Socialite\Contracts\Factory as Socialite; use Laravel\Socialite\Contracts\Provider; use Laravel\Socialite\Contracts\User as SocialUser; +use SocialiteProviders\Manager\SocialiteWasCalled; use Symfony\Component\HttpFoundation\RedirectResponse; class SocialAuthService { - - protected $userRepo; protected $socialite; protected $socialAccount; @@ -25,14 +27,11 @@ class SocialAuthService /** * SocialAuthService constructor. */ - public function __construct(UserRepo $userRepo, Socialite $socialite, SocialAccount $socialAccount) + public function __construct(Socialite $socialite) { - $this->userRepo = $userRepo; $this->socialite = $socialite; - $this->socialAccount = $socialAccount; } - /** * Start the social login path. * @throws SocialDriverNotConfigured @@ -60,11 +59,11 @@ class SocialAuthService public function handleRegistrationCallback(string $socialDriver, SocialUser $socialUser): SocialUser { // Check social account has not already been used - if ($this->socialAccount->where('driver_id', '=', $socialUser->getId())->exists()) { - throw new UserRegistrationException(trans('errors.social_account_in_use', ['socialAccount'=>$socialDriver]), '/login'); + if (SocialAccount::query()->where('driver_id', '=', $socialUser->getId())->exists()) { + throw new UserRegistrationException(trans('errors.social_account_in_use', ['socialAccount' => $socialDriver]), '/login'); } - if ($this->userRepo->getByEmail($socialUser->getEmail())) { + if (User::query()->where('email', '=', $socialUser->getEmail())->exists()) { $email = $socialUser->getEmail(); throw new UserRegistrationException(trans('errors.error_user_exists_different_creds', ['email' => $email]), '/login'); } @@ -91,7 +90,7 @@ class SocialAuthService $socialId = $socialUser->getId(); // Get any attached social accounts or users - $socialAccount = $this->socialAccount->where('driver_id', '=', $socialId)->first(); + $socialAccount = SocialAccount::query()->where('driver_id', '=', $socialId)->first(); $isLoggedIn = auth()->check(); $currentUser = user(); $titleCaseDriver = Str::title($socialDriver); @@ -101,14 +100,15 @@ class SocialAuthService if (!$isLoggedIn && $socialAccount !== null) { auth()->login($socialAccount->user); Activity::add(ActivityType::AUTH_LOGIN, $socialAccount); + Theme::dispatch(ThemeEvents::AUTH_LOGIN, $socialDriver, $socialAccount->user); return redirect()->intended('/'); } // When a user is logged in but the social account does not exist, // Create the social account and attach it to the user & redirect to the profile page. if ($isLoggedIn && $socialAccount === null) { - $this->fillSocialAccount($socialDriver, $socialUser); - $currentUser->socialAccounts()->save($this->socialAccount); + $account = $this->newSocialAccount($socialDriver, $socialUser); + $currentUser->socialAccounts()->save($account); session()->flash('success', trans('settings.users_social_connected', ['socialAccount' => $titleCaseDriver])); return redirect($currentUser->getEditUrl()); } @@ -130,7 +130,7 @@ class SocialAuthService if (setting('registration-enabled') && config('auth.method') !== 'ldap' && config('auth.method') !== 'saml2') { $message .= trans('errors.social_account_register_instructions', ['socialAccount' => $titleCaseDriver]); } - + throw new SocialSignInAccountNotUsed($message, '/login'); } @@ -207,21 +207,19 @@ class SocialAuthService /** * Fill and return a SocialAccount from the given driver name and SocialUser. */ - public function fillSocialAccount(string $socialDriver, SocialUser $socialUser): SocialAccount + public function newSocialAccount(string $socialDriver, SocialUser $socialUser): SocialAccount { - $this->socialAccount->fill([ - 'driver' => $socialDriver, + return new SocialAccount([ + 'driver' => $socialDriver, 'driver_id' => $socialUser->getId(), - 'avatar' => $socialUser->getAvatar() + 'avatar' => $socialUser->getAvatar() ]); - return $this->socialAccount; } /** * Detach a social account from a user. - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ - public function detachSocialAccount(string $socialDriver) + public function detachSocialAccount(string $socialDriver): void { user()->socialAccounts()->where('driver', '=', $socialDriver)->delete(); } @@ -242,4 +240,20 @@ class SocialAuthService return $driver; } + + /** + * Add a custom socialite driver to be used. + * Driver name should be lower_snake_case. + * Config array should mirror the structure of a service + * within the `Config/services.php` file. + * Handler should be a Class@method handler to the SocialiteWasCalled event. + */ + public function addSocialDriver(string $driverName, array $config, string $socialiteHandler) + { + $this->validSocialDrivers[] = $driverName; + config()->set('services.' . $driverName, $config); + config()->set('services.' . $driverName . '.redirect', url('/login/service/' . $driverName . '/callback')); + config()->set('services.' . $driverName . '.name', $config['name'] ?? $driverName); + Event::listen(SocialiteWasCalled::class, $socialiteHandler); + } } diff --git a/app/Auth/Permissions/PermissionService.php b/app/Auth/Permissions/PermissionService.php index 89c8a5fbb..c5bdc8070 100644 --- a/app/Auth/Permissions/PermissionService.php +++ b/app/Auth/Permissions/PermissionService.php @@ -1,25 +1,33 @@ db = $db; - $this->jointPermission = $jointPermission; - $this->entityPermission = $entityPermission; - $this->role = $role; - $this->entityProvider = $entityProvider; } /** * Set the database connection - * @param Connection $connection */ public function setConnection(Connection $connection) { @@ -76,81 +57,63 @@ class PermissionService /** * Prepare the local entity cache and ensure it's empty - * @param \BookStack\Entities\Models\Entity[] $entities + * @param Entity[] $entities */ - protected function readyEntityCache($entities = []) + protected function readyEntityCache(array $entities = []) { $this->entityCache = []; foreach ($entities as $entity) { - $type = $entity->getType(); - if (!isset($this->entityCache[$type])) { - $this->entityCache[$type] = collect(); + $class = get_class($entity); + if (!isset($this->entityCache[$class])) { + $this->entityCache[$class] = collect(); } - $this->entityCache[$type]->put($entity->id, $entity); + $this->entityCache[$class]->put($entity->id, $entity); } } /** * Get a book via ID, Checks local cache - * @param $bookId - * @return Book */ - protected function getBook($bookId) + protected function getBook(int $bookId): ?Book { - if (isset($this->entityCache['book']) && $this->entityCache['book']->has($bookId)) { - return $this->entityCache['book']->get($bookId); + if (isset($this->entityCache[Book::class]) && $this->entityCache[Book::class]->has($bookId)) { + return $this->entityCache[Book::class]->get($bookId); } - $book = $this->entityProvider->book->find($bookId); - if ($book === null) { - $book = false; - } - - return $book; + return Book::query()->withTrashed()->find($bookId); } /** * Get a chapter via ID, Checks local cache - * @param $chapterId - * @return \BookStack\Entities\Models\Book */ - protected function getChapter($chapterId) + protected function getChapter(int $chapterId): ?Chapter { - if (isset($this->entityCache['chapter']) && $this->entityCache['chapter']->has($chapterId)) { - return $this->entityCache['chapter']->get($chapterId); + if (isset($this->entityCache[Chapter::class]) && $this->entityCache[Chapter::class]->has($chapterId)) { + return $this->entityCache[Chapter::class]->get($chapterId); } - $chapter = $this->entityProvider->chapter->find($chapterId); - if ($chapter === null) { - $chapter = false; - } - - return $chapter; + return Chapter::query() + ->withTrashed() + ->find($chapterId); } /** - * Get the roles for the current user; - * @return array|bool + * Get the roles for the current logged in user. */ - protected function getRoles() + protected function getCurrentUserRoles(): array { - if ($this->userRoles !== false) { + if (!is_null($this->userRoles)) { return $this->userRoles; } - $roles = []; - if (auth()->guest()) { - $roles[] = $this->role->getSystemRole('public')->id; - return $roles; + $this->userRoles = [Role::getSystemRole('public')->id]; + } else { + $this->userRoles = $this->currentUser()->roles->pluck('id')->values()->all(); } - - foreach ($this->currentUser()->roles as $role) { - $roles[] = $role->id; - } - return $roles; + return $this->userRoles; } /** @@ -158,59 +121,57 @@ class PermissionService */ public function buildJointPermissions() { - $this->jointPermission->truncate(); + JointPermission::query()->truncate(); $this->readyEntityCache(); // Get all roles (Should be the most limited dimension) - $roles = $this->role->with('permissions')->get()->all(); + $roles = Role::query()->with('permissions')->get()->all(); // Chunk through all books - $this->bookFetchQuery()->chunk(5, function ($books) use ($roles) { + $this->bookFetchQuery()->chunk(5, function (EloquentCollection $books) use ($roles) { $this->buildJointPermissionsForBooks($books, $roles); }); // Chunk through all bookshelves - $this->entityProvider->bookshelf->newQuery()->withTrashed()->select(['id', 'restricted', 'owned_by']) - ->chunk(50, function ($shelves) use ($roles) { + Bookshelf::query()->withTrashed()->select(['id', 'restricted', 'owned_by']) + ->chunk(50, function (EloquentCollection $shelves) use ($roles) { $this->buildJointPermissionsForShelves($shelves, $roles); }); } /** * Get a query for fetching a book with it's children. - * @return QueryBuilder */ - protected function bookFetchQuery() + protected function bookFetchQuery(): Builder { - return $this->entityProvider->book->withTrashed()->newQuery() - ->select(['id', 'restricted', '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']); - }]); + return Book::query()->withTrashed() + ->select(['id', 'restricted', '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']); + } + ]); } /** - * @param Collection $shelves - * @param array $roles - * @param bool $deleteOld - * @throws \Throwable + * Build joint permissions for the given shelf and role combinations. + * @throws Throwable */ - protected function buildJointPermissionsForShelves($shelves, $roles, $deleteOld = false) + protected function buildJointPermissionsForShelves(EloquentCollection $shelves, array $roles, bool $deleteOld = false) { if ($deleteOld) { $this->deleteManyJointPermissionsForEntities($shelves->all()); } - $this->createManyJointPermissions($shelves, $roles); + $this->createManyJointPermissions($shelves->all(), $roles); } /** - * Build joint permissions for an array of books - * @param Collection $books - * @param array $roles - * @param bool $deleteOld + * Build joint permissions for the given book and role combinations. + * @throws Throwable */ - protected function buildJointPermissionsForBooks($books, $roles, $deleteOld = false) + protected function buildJointPermissionsForBooks(EloquentCollection $books, array $roles, bool $deleteOld = false) { $entities = clone $books; @@ -227,55 +188,53 @@ class PermissionService if ($deleteOld) { $this->deleteManyJointPermissionsForEntities($entities->all()); } - $this->createManyJointPermissions($entities, $roles); + $this->createManyJointPermissions($entities->all(), $roles); } /** * Rebuild the entity jointPermissions for a particular entity. - * @param \BookStack\Entities\Models\Entity $entity - * @throws \Throwable + * @throws Throwable */ public function buildJointPermissionsForEntity(Entity $entity) { $entities = [$entity]; - if ($entity->isA('book')) { + if ($entity instanceof Book) { $books = $this->bookFetchQuery()->where('id', '=', $entity->id)->get(); - $this->buildJointPermissionsForBooks($books, $this->role->newQuery()->get(), true); + $this->buildJointPermissionsForBooks($books, Role::query()->get()->all(), true); return; } + /** @var BookChild $entity */ if ($entity->book) { $entities[] = $entity->book; } - if ($entity->isA('page') && $entity->chapter_id) { + if ($entity instanceof Page && $entity->chapter_id) { $entities[] = $entity->chapter; } - if ($entity->isA('chapter')) { + if ($entity instanceof Chapter) { foreach ($entity->pages as $page) { $entities[] = $page; } } - $this->buildJointPermissionsForEntities(collect($entities)); + $this->buildJointPermissionsForEntities($entities); } /** * Rebuild the entity jointPermissions for a collection of entities. - * @param Collection $entities - * @throws \Throwable + * @throws Throwable */ - public function buildJointPermissionsForEntities(Collection $entities) + public function buildJointPermissionsForEntities(array $entities) { - $roles = $this->role->newQuery()->get(); - $this->deleteManyJointPermissionsForEntities($entities->all()); + $roles = Role::query()->get()->values()->all(); + $this->deleteManyJointPermissionsForEntities($entities); $this->createManyJointPermissions($entities, $roles); } /** * Build the entity jointPermissions for a particular role. - * @param Role $role */ public function buildJointPermissionForRole(Role $role) { @@ -288,7 +247,7 @@ class PermissionService }); // Chunk through all bookshelves - $this->entityProvider->bookshelf->newQuery()->select(['id', 'restricted', 'owned_by']) + Bookshelf::query()->select(['id', 'restricted', 'owned_by']) ->chunk(50, function ($shelves) use ($roles) { $this->buildJointPermissionsForShelves($shelves, $roles); }); @@ -296,7 +255,6 @@ class PermissionService /** * Delete the entity jointPermissions attached to a particular role. - * @param Role $role */ public function deleteJointPermissionsForRole(Role $role) { @@ -312,13 +270,13 @@ class PermissionService $roleIds = array_map(function ($role) { return $role->id; }, $roles); - $this->jointPermission->newQuery()->whereIn('role_id', $roleIds)->delete(); + JointPermission::query()->whereIn('role_id', $roleIds)->delete(); } /** * Delete the entity jointPermissions for a particular entity. * @param Entity $entity - * @throws \Throwable + * @throws Throwable */ public function deleteJointPermissionsForEntity(Entity $entity) { @@ -327,10 +285,10 @@ class PermissionService /** * Delete all of the entity jointPermissions for a list of entities. - * @param \BookStack\Entities\Models\Entity[] $entities - * @throws \Throwable + * @param Entity[] $entities + * @throws Throwable */ - protected function deleteManyJointPermissionsForEntities($entities) + protected function deleteManyJointPermissionsForEntities(array $entities) { if (count($entities) === 0) { return; @@ -352,19 +310,19 @@ class PermissionService } /** - * Create & Save entity jointPermissions for many entities and jointPermissions. - * @param Collection $entities - * @param array $roles - * @throws \Throwable + * Create & Save entity jointPermissions for many entities and roles. + * @param Entity[] $entities + * @param Role[] $roles + * @throws Throwable */ - protected function createManyJointPermissions($entities, $roles) + protected function createManyJointPermissions(array $entities, array $roles) { $this->readyEntityCache($entities); $jointPermissions = []; // Fetch Entity Permissions and create a mapping of entity restricted statuses $entityRestrictedMap = []; - $permissionFetch = $this->entityPermission->newQuery(); + $permissionFetch = EntityPermission::query(); foreach ($entities as $entity) { $entityRestrictedMap[$entity->getMorphClass() . ':' . $entity->id] = boolval($entity->getRawAttribute('restricted')); $permissionFetch->orWhere(function ($query) use ($entity) { @@ -408,16 +366,14 @@ class PermissionService /** * Get the actions related to an entity. - * @param \BookStack\Entities\Models\Entity $entity - * @return array */ - protected function getActions(Entity $entity) + protected function getActions(Entity $entity): array { $baseActions = ['view', 'update', 'delete']; - if ($entity->isA('chapter') || $entity->isA('book')) { + if ($entity instanceof Chapter || $entity instanceof Book) { $baseActions[] = 'page-create'; } - if ($entity->isA('book')) { + if ($entity instanceof Book) { $baseActions[] = 'chapter-create'; } return $baseActions; @@ -426,14 +382,8 @@ class PermissionService /** * Create entity permission data for an entity and role * for a particular action. - * @param Entity $entity - * @param Role $role - * @param string $action - * @param array $permissionMap - * @param array $rolePermissionMap - * @return array */ - protected function createJointPermissionData(Entity $entity, Role $role, $action, $permissionMap, $rolePermissionMap) + protected function createJointPermissionData(Entity $entity, Role $role, string $action, array $permissionMap, array $rolePermissionMap): array { $permissionPrefix = (strpos($action, '-') === false ? ($entity->getType() . '-') : '') . $action; $roleHasPermission = isset($rolePermissionMap[$role->getRawAttribute('id') . ':' . $permissionPrefix . '-all']); @@ -450,7 +400,7 @@ class PermissionService return $this->createJointPermissionDataArray($entity, $role, $action, $hasAccess, $hasAccess); } - if ($entity->isA('book') || $entity->isA('bookshelf')) { + if ($entity instanceof Book || $entity instanceof Bookshelf) { return $this->createJointPermissionDataArray($entity, $role, $action, $roleHasPermission, $roleHasPermissionOwn); } @@ -460,7 +410,7 @@ class PermissionService $hasPermissiveAccessToParents = !$book->restricted; // For pages with a chapter, Check if explicit permissions are set on the Chapter - if ($entity->isA('page') && $entity->chapter_id !== 0 && $entity->chapter_id !== '0') { + if ($entity instanceof Page && intval($entity->chapter_id) !== 0) { $chapter = $this->getChapter($entity->chapter_id); $hasPermissiveAccessToParents = $hasPermissiveAccessToParents && !$chapter->restricted; if ($chapter->restricted) { @@ -479,38 +429,27 @@ class PermissionService /** * Check for an active restriction in an entity map. - * @param $entityMap - * @param Entity $entity - * @param Role $role - * @param $action - * @return bool */ - protected function mapHasActiveRestriction($entityMap, Entity $entity, Role $role, $action) + protected function mapHasActiveRestriction(array $entityMap, Entity $entity, Role $role, string $action): bool { $key = $entity->getMorphClass() . ':' . $entity->getRawAttribute('id') . ':' . $role->getRawAttribute('id') . ':' . $action; - return isset($entityMap[$key]) ? $entityMap[$key] : false; + return $entityMap[$key] ?? false; } /** * Create an array of data with the information of an entity jointPermissions. * Used to build data for bulk insertion. - * @param \BookStack\Entities\Models\Entity $entity - * @param Role $role - * @param $action - * @param $permissionAll - * @param $permissionOwn - * @return array */ - protected function createJointPermissionDataArray(Entity $entity, Role $role, $action, $permissionAll, $permissionOwn) + protected function createJointPermissionDataArray(Entity $entity, Role $role, string $action, bool $permissionAll, bool $permissionOwn): array { return [ - 'role_id' => $role->getRawAttribute('id'), - 'entity_id' => $entity->getRawAttribute('id'), - 'entity_type' => $entity->getMorphClass(), - 'action' => $action, - 'has_permission' => $permissionAll, + 'role_id' => $role->getRawAttribute('id'), + 'entity_id' => $entity->getRawAttribute('id'), + 'entity_type' => $entity->getMorphClass(), + 'action' => $action, + 'has_permission' => $permissionAll, 'has_permission_own' => $permissionOwn, - 'owned_by' => $entity->getRawAttribute('owned_by') + 'owned_by' => $entity->getRawAttribute('owned_by'), ]; } @@ -524,55 +463,47 @@ class PermissionService $baseQuery = $ownable->newQuery()->where('id', '=', $ownable->id); $action = end($explodedPermission); - $this->currentAction = $action; + $user = $this->currentUser(); $nonJointPermissions = ['restrictions', 'image', 'attachment', 'comment']; // Handle non entity specific jointPermissions if (in_array($explodedPermission[0], $nonJointPermissions)) { - $allPermission = $this->currentUser() && $this->currentUser()->can($permission . '-all'); - $ownPermission = $this->currentUser() && $this->currentUser()->can($permission . '-own'); - $this->currentAction = 'view'; + $allPermission = $user && $user->can($permission . '-all'); + $ownPermission = $user && $user->can($permission . '-own'); $ownerField = ($ownable instanceof Entity) ? 'owned_by' : 'created_by'; - $isOwner = $this->currentUser() && $this->currentUser()->id === $ownable->$ownerField; + $isOwner = $user && $user->id === $ownable->$ownerField; return ($allPermission || ($isOwner && $ownPermission)); } // Handle abnormal create jointPermissions if ($action === 'create') { - $this->currentAction = $permission; + $action = $permission; } - $q = $this->entityRestrictionQuery($baseQuery)->count() > 0; + $hasAccess = $this->entityRestrictionQuery($baseQuery, $action)->count() > 0; $this->clean(); - return $q; + return $hasAccess; } /** * Checks if a user has the given permission for any items in the system. * Can be passed an entity instance to filter on a specific type. - * @param string $permission - * @param string $entityClass - * @return bool */ - public function checkUserHasPermissionOnAnything(string $permission, string $entityClass = null) + public function checkUserHasPermissionOnAnything(string $permission, ?string $entityClass = null): bool { $userRoleIds = $this->currentUser()->roles()->select('id')->pluck('id')->toArray(); $userId = $this->currentUser()->id; - $permissionQuery = $this->db->table('joint_permissions') + $permissionQuery = JointPermission::query() ->where('action', '=', $permission) ->whereIn('role_id', $userRoleIds) - ->where(function ($query) use ($userId) { - $query->where('has_permission', '=', 1) - ->orWhere(function ($query2) use ($userId) { - $query2->where('has_permission_own', '=', 1) - ->where('owned_by', '=', $userId); - }); + ->where(function (Builder $query) use ($userId) { + $this->addJointHasPermissionCheck($query, $userId); }); if (!is_null($entityClass)) { - $entityInstance = app()->make($entityClass); + $entityInstance = app($entityClass); $permissionQuery = $permissionQuery->where('entity_type', '=', $entityInstance->getMorphClass()); } @@ -581,46 +512,22 @@ class PermissionService return $hasPermission; } - /** - * Check if an entity has restrictions set on itself or its - * parent tree. - * @param \BookStack\Entities\Models\Entity $entity - * @param $action - * @return bool|mixed - */ - public function checkIfRestrictionsSet(Entity $entity, $action) - { - $this->currentAction = $action; - if ($entity->isA('page')) { - return $entity->restricted || ($entity->chapter && $entity->chapter->restricted) || $entity->book->restricted; - } elseif ($entity->isA('chapter')) { - return $entity->restricted || $entity->book->restricted; - } elseif ($entity->isA('book')) { - return $entity->restricted; - } - } - /** * The general query filter to remove all entities * that the current user does not have access to. - * @param $query - * @return mixed */ - protected function entityRestrictionQuery($query) + protected function entityRestrictionQuery(Builder $query, string $action): Builder { - $q = $query->where(function ($parentQuery) { - $parentQuery->whereHas('jointPermissions', function ($permissionQuery) { - $permissionQuery->whereIn('role_id', $this->getRoles()) - ->where('action', '=', $this->currentAction) - ->where(function ($query) { - $query->where('has_permission', '=', true) - ->orWhere(function ($query) { - $query->where('has_permission_own', '=', true) - ->where('owned_by', '=', $this->currentUser()->id); - }); + $q = $query->where(function ($parentQuery) use ($action) { + $parentQuery->whereHas('jointPermissions', function ($permissionQuery) use ($action) { + $permissionQuery->whereIn('role_id', $this->getCurrentUserRoles()) + ->where('action', '=', $action) + ->where(function (Builder $query) { + $this->addJointHasPermissionCheck($query, $this->currentUser()->id); }); }); }); + $this->clean(); return $q; } @@ -634,14 +541,10 @@ class PermissionService $this->clean(); return $query->where(function (Builder $parentQuery) use ($ability) { $parentQuery->whereHas('jointPermissions', function (Builder $permissionQuery) use ($ability) { - $permissionQuery->whereIn('role_id', $this->getRoles()) + $permissionQuery->whereIn('role_id', $this->getCurrentUserRoles()) ->where('action', '=', $ability) ->where(function (Builder $query) { - $query->where('has_permission', '=', true) - ->orWhere(function (Builder $query) { - $query->where('has_permission_own', '=', true) - ->where('owned_by', '=', $this->currentUser()->id); - }); + $this->addJointHasPermissionCheck($query, $this->currentUser()->id); }); }); }); @@ -651,7 +554,7 @@ class PermissionService * Extend the given page query to ensure draft items are not visible * unless created by the given user. */ - public function enforceDraftVisiblityOnQuery(Builder $query): Builder + public function enforceDraftVisibilityOnQuery(Builder $query): Builder { return $query->where(function (Builder $query) { $query->where('draft', '=', false) @@ -663,109 +566,89 @@ class PermissionService } /** - * Add restrictions for a generic entity - * @param string $entityType - * @param Builder|\BookStack\Entities\Models\Entity $query - * @param string $action - * @return Builder + * Add restrictions for a generic entity. */ - public function enforceEntityRestrictions($entityType, $query, $action = 'view') + public function enforceEntityRestrictions(Entity $entity, Builder $query, string $action = 'view'): Builder { - if (strtolower($entityType) === 'page') { + if ($entity instanceof Page) { // Prevent drafts being visible to others. - $query = $query->where(function ($query) { - $query->where('draft', '=', false) - ->orWhere(function ($query) { - $query->where('draft', '=', true) - ->where('owned_by', '=', $this->currentUser()->id); - }); - }); + $this->enforceDraftVisibilityOnQuery($query); } - $this->currentAction = $action; - return $this->entityRestrictionQuery($query); + return $this->entityRestrictionQuery($query, $action); } /** * Filter items that have entities set as a polymorphic relation. - * @param $query - * @param string $tableName - * @param string $entityIdColumn - * @param string $entityTypeColumn - * @param string $action - * @return QueryBuilder */ - public function filterRestrictedEntityRelations($query, $tableName, $entityIdColumn, $entityTypeColumn, $action = 'view') + public function filterRestrictedEntityRelations(Builder $query, string $tableName, string $entityIdColumn, string $entityTypeColumn, string $action = 'view'): Builder { - - $this->currentAction = $action; $tableDetails = ['tableName' => $tableName, 'entityIdColumn' => $entityIdColumn, 'entityTypeColumn' => $entityTypeColumn]; - $q = $query->where(function ($query) use ($tableDetails) { - $query->whereExists(function ($permissionQuery) use (&$tableDetails) { + $q = $query->where(function ($query) use ($tableDetails, $action) { + $query->whereExists(function ($permissionQuery) use (&$tableDetails, $action) { $permissionQuery->select('id')->from('joint_permissions') ->whereRaw('joint_permissions.entity_id=' . $tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn']) ->whereRaw('joint_permissions.entity_type=' . $tableDetails['tableName'] . '.' . $tableDetails['entityTypeColumn']) - ->where('action', '=', $this->currentAction) - ->whereIn('role_id', $this->getRoles()) - ->where(function ($query) { - $query->where('has_permission', '=', true)->orWhere(function ($query) { - $query->where('has_permission_own', '=', true) - ->where('owned_by', '=', $this->currentUser()->id); - }); + ->where('action', '=', $action) + ->whereIn('role_id', $this->getCurrentUserRoles()) + ->where(function (QueryBuilder $query) { + $this->addJointHasPermissionCheck($query, $this->currentUser()->id); }); }); }); + $this->clean(); return $q; } /** * Add conditions to a query to filter the selection to related entities - * where permissions are granted. - * @param $entityType - * @param $query - * @param $tableName - * @param $entityIdColumn - * @return mixed + * where view permissions are granted. */ - public function filterRelatedEntity($entityType, $query, $tableName, $entityIdColumn) + public function filterRelatedEntity(string $entityClass, Builder $query, string $tableName, string $entityIdColumn): Builder { - $this->currentAction = 'view'; $tableDetails = ['tableName' => $tableName, 'entityIdColumn' => $entityIdColumn]; + $morphClass = app($entityClass)->getMorphClass(); - $pageMorphClass = $this->entityProvider->get($entityType)->getMorphClass(); - - $q = $query->where(function ($query) use ($tableDetails, $pageMorphClass) { - $query->where(function ($query) use (&$tableDetails, $pageMorphClass) { - $query->whereExists(function ($permissionQuery) use (&$tableDetails, $pageMorphClass) { + $q = $query->where(function ($query) use ($tableDetails, $morphClass) { + $query->where(function ($query) use (&$tableDetails, $morphClass) { + $query->whereExists(function ($permissionQuery) use (&$tableDetails, $morphClass) { $permissionQuery->select('id')->from('joint_permissions') ->whereRaw('joint_permissions.entity_id=' . $tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn']) - ->where('entity_type', '=', $pageMorphClass) - ->where('action', '=', $this->currentAction) - ->whereIn('role_id', $this->getRoles()) - ->where(function ($query) { - $query->where('has_permission', '=', true)->orWhere(function ($query) { - $query->where('has_permission_own', '=', true) - ->where('owned_by', '=', $this->currentUser()->id); - }); + ->where('entity_type', '=', $morphClass) + ->where('action', '=', 'view') + ->whereIn('role_id', $this->getCurrentUserRoles()) + ->where(function (QueryBuilder $query) { + $this->addJointHasPermissionCheck($query, $this->currentUser()->id); }); }); })->orWhere($tableDetails['entityIdColumn'], '=', 0); }); $this->clean(); - return $q; } /** - * Get the current user - * @return \BookStack\Auth\User + * Add the query for checking the given user id has permission + * within the join_permissions table. + * @param QueryBuilder|Builder $query */ - private function currentUser() + protected function addJointHasPermissionCheck($query, int $userIdToCheck) { - if ($this->currentUserModel === false) { + $query->where('has_permission', '=', true)->orWhere(function ($query) use ($userIdToCheck) { + $query->where('has_permission_own', '=', true) + ->where('owned_by', '=', $userIdToCheck); + }); + } + + /** + * Get the current user + */ + private function currentUser(): User + { + if (is_null($this->currentUserModel)) { $this->currentUserModel = user(); } @@ -775,10 +658,9 @@ class PermissionService /** * Clean the cached user elements. */ - private function clean() + private function clean(): void { - $this->currentUserModel = false; - $this->userRoles = false; - $this->isAdminUser = null; + $this->currentUserModel = null; + $this->userRoles = null; } } diff --git a/app/Auth/User.php b/app/Auth/User.php index 9d7eaa72e..9855ab4e7 100644 --- a/app/Auth/User.php +++ b/app/Auth/User.php @@ -1,7 +1,9 @@ first(); + static::$defaultUser = static::query()->where('system_name', '=', 'public')->first(); return static::$defaultUser; } /** * Check if the user is the default public user. - * @return bool */ - public function isDefault() + public function isDefault(): bool { return $this->system_name === 'public'; } @@ -115,12 +117,10 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon /** * Check if the user has a role. - * @param $role - * @return mixed */ - public function hasSystemRole($role) + public function hasSystemRole(string $roleSystemName): bool { - return $this->roles->pluck('system_name')->contains($role); + return $this->roles->pluck('system_name')->contains($roleSystemName); } /** @@ -184,9 +184,8 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon /** * Get the social account associated with this user. - * @return HasMany */ - public function socialAccounts() + public function socialAccounts(): HasMany { return $this->hasMany(SocialAccount::class); } @@ -207,11 +206,9 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon } /** - * Returns the user's avatar, - * @param int $size - * @return string + * Returns a URL to the user's avatar */ - public function getAvatar($size = 50) + public function getAvatar(int $size = 50): string { $default = url('/user_avatar.png'); $imageId = $this->image_id; @@ -229,9 +226,8 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon /** * Get the avatar for the user. - * @return BelongsTo */ - public function avatar() + public function avatar(): BelongsTo { return $this->belongsTo(Image::class, 'image_id'); } @@ -271,15 +267,13 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon */ public function getProfileUrl(): string { - return url('/user/' . $this->id); + return url('/user/' . $this->slug); } /** * Get a shortened version of the user's name. - * @param int $chars - * @return string */ - public function getShortName($chars = 8) + public function getShortName(int $chars = 8): string { if (mb_strlen($this->name) <= $chars) { return $this->name; @@ -310,4 +304,13 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon { return "({$this->id}) {$this->name}"; } + + /** + * @inheritDoc + */ + public function refreshSlug(): string + { + $this->slug = app(SlugGenerator::class)->generate($this); + return $this->slug; + } } diff --git a/app/Auth/UserRepo.php b/app/Auth/UserRepo.php index 29a0ebc14..e437ff1e3 100644 --- a/app/Auth/UserRepo.php +++ b/app/Auth/UserRepo.php @@ -45,6 +45,14 @@ class UserRepo return User::query()->findOrFail($id); } + /** + * Get a user by their slug. + */ + public function getBySlug(string $slug): User + { + return User::query()->where('slug', '=', $slug)->firstOrFail(); + } + /** * Get all the users with their permissions. */ @@ -159,7 +167,13 @@ class UserRepo 'email_confirmed' => $emailConfirmed, 'external_auth_id' => $data['external_auth_id'] ?? '', ]; - return User::query()->forceCreate($details); + + $user = new User(); + $user->forceFill($details); + $user->refreshSlug(); + $user->save(); + + return $user; } /** diff --git a/app/Config/app.php b/app/Config/app.php index 762845e9f..065845f96 100755 --- a/app/Config/app.php +++ b/app/Config/app.php @@ -19,13 +19,6 @@ return [ // private configuration variables so should remain disabled in public. 'debug' => env('APP_DEBUG', false), - // Set the default view type for various lists. Can be overridden by user preferences. - // These will be used for public viewers and users that have not set a preference. - 'views' => [ - 'books' => env('APP_VIEWS_BOOKS', 'list'), - 'bookshelves' => env('APP_VIEWS_BOOKSHELVES', 'grid'), - ], - // The number of revisions to keep in the database. // Once this limit is reached older revisions will be deleted. // If set to false then a limit will not be enforced. @@ -63,7 +56,7 @@ return [ 'locale' => env('APP_LANG', 'en'), // Locales available - 'locales' => ['en', 'ar', 'bg', 'cs', 'da', 'de', 'de_informal', 'es', 'es_AR', 'fa', 'fr', 'he', 'hu', 'it', 'ja', 'ko', 'nl', 'nb', 'pt', 'pt_BR', 'sk', 'sl', 'sv', 'pl', 'ru', 'th', 'tr', 'uk', 'vi', 'zh_CN', 'zh_TW',], + 'locales' => ['en', 'ar', 'bg', 'bs', 'ca', 'cs', 'da', 'de', 'de_informal', 'es', 'es_AR', 'fa', 'fr', 'he', 'hu', 'id', 'it', 'ja', 'ko', 'lv', 'nl', 'nb', 'pt', 'pt_BR', 'sk', 'sl', 'sv', 'pl', 'ru', 'th', 'tr', 'uk', 'vi', 'zh_CN', 'zh_TW',], // Application Fallback Locale 'fallback_locale' => 'en', @@ -122,6 +115,7 @@ return [ BookStack\Providers\TranslationServiceProvider::class, // BookStack custom service providers + BookStack\Providers\ThemeServiceProvider::class, BookStack\Providers\AuthServiceProvider::class, BookStack\Providers\AppServiceProvider::class, BookStack\Providers\BroadcastServiceProvider::class, @@ -190,10 +184,10 @@ return [ // Custom BookStack 'Activity' => BookStack\Facades\Activity::class, - 'Setting' => BookStack\Facades\Setting::class, 'Views' => BookStack\Facades\Views::class, 'Images' => BookStack\Facades\Images::class, 'Permissions' => BookStack\Facades\Permissions::class, + 'Theme' => BookStack\Facades\Theme::class, ], diff --git a/app/Config/services.php b/app/Config/services.php index fcde621d2..699339614 100644 --- a/app/Config/services.php +++ b/app/Config/services.php @@ -132,6 +132,7 @@ return [ 'group_attribute' => env('LDAP_GROUP_ATTRIBUTE', 'memberOf'), 'remove_from_groups' => env('LDAP_REMOVE_FROM_GROUPS', false), 'tls_insecure' => env('LDAP_TLS_INSECURE', false), + 'start_tls' => env('LDAP_START_TLS', false), ], ]; diff --git a/app/Config/session.php b/app/Config/session.php index 571836bd2..c750e1ef9 100644 --- a/app/Config/session.php +++ b/app/Config/session.php @@ -59,7 +59,7 @@ return [ // The session cookie path determines the path for which the cookie will // be regarded as available. Typically, this will be the root path of // your application but you are free to change this when necessary. - 'path' => '/', + 'path' => '/' . (explode('/', env('APP_URL', ''), 4)[3] ?? ''), // Session Cookie Domain // Here you may change the domain of the cookie used to identify a session diff --git a/app/Config/setting-defaults.php b/app/Config/setting-defaults.php index d84c0c264..879c636bc 100644 --- a/app/Config/setting-defaults.php +++ b/app/Config/setting-defaults.php @@ -24,4 +24,12 @@ return [ 'app-custom-head' => false, 'registration-enabled' => false, + // User-level default settings + 'user' => [ + 'dark-mode-enabled' => env('APP_DEFAULT_DARK_MODE', false), + 'bookshelves_view_type' => env('APP_VIEWS_BOOKSHELVES', 'grid'), + 'bookshelf_view_type' =>env('APP_VIEWS_BOOKSHELF', 'grid'), + 'books_view_type' => env('APP_VIEWS_BOOKS', 'grid'), + ], + ]; diff --git a/app/Console/Commands/UpdateUrl.php b/app/Console/Commands/UpdateUrl.php index b95e277d1..2a1688468 100644 --- a/app/Console/Commands/UpdateUrl.php +++ b/app/Console/Commands/UpdateUrl.php @@ -4,6 +4,7 @@ namespace BookStack\Console\Commands; use Illuminate\Console\Command; use Illuminate\Database\Connection; +use Illuminate\Support\Facades\DB; class UpdateUrl extends Command { @@ -60,22 +61,50 @@ class UpdateUrl extends Command "attachments" => ["path"], "pages" => ["html", "text", "markdown"], "images" => ["url"], + "settings" => ["value"], "comments" => ["html", "text"], ]; foreach ($columnsToUpdateByTable as $table => $columns) { foreach ($columns as $column) { - $changeCount = $this->db->table($table)->update([ - $column => $this->db->raw("REPLACE({$column}, '{$oldUrl}', '{$newUrl}')") - ]); + $changeCount = $this->replaceValueInTable($table, $column, $oldUrl, $newUrl); $this->info("Updated {$changeCount} rows in {$table}->{$column}"); } } + $jsonColumnsToUpdateByTable = [ + "settings" => ["value"], + ]; + + foreach ($jsonColumnsToUpdateByTable as $table => $columns) { + foreach ($columns as $column) { + $oldJson = trim(json_encode($oldUrl), '"'); + $newJson = trim(json_encode($newUrl), '"'); + $changeCount = $this->replaceValueInTable($table, $column, $oldJson, $newJson); + $this->info("Updated {$changeCount} JSON encoded rows in {$table}->{$column}"); + } + } + $this->info("URL update procedure complete."); + $this->info('============================================================================'); + $this->info('Be sure to run "php artisan cache:clear" to clear any old URLs in the cache.'); + $this->info('============================================================================'); return 0; } + /** + * Perform a find+replace operations in the provided table and column. + * Returns the count of rows changed. + */ + protected function replaceValueInTable(string $table, string $column, string $oldUrl, string $newUrl): int + { + $oldQuoted = $this->db->getPdo()->quote($oldUrl); + $newQuoted = $this->db->getPdo()->quote($newUrl); + return $this->db->table($table)->update([ + $column => $this->db->raw("REPLACE({$column}, {$oldQuoted}, {$newQuoted})") + ]); + } + /** * Warn the user of the dangers of this operation. * Returns a boolean indicating if they've accepted the warnings. diff --git a/app/Entities/Models/BookChild.php b/app/Entities/Models/BookChild.php index 8b968cc8b..c73fa3959 100644 --- a/app/Entities/Models/BookChild.php +++ b/app/Entities/Models/BookChild.php @@ -1,8 +1,5 @@ pages as $page) { + foreach ($this->pages()->withTrashed()->get() as $page) { $page->changeBook($newBookId); } } diff --git a/app/Entities/Models/Entity.php b/app/Entities/Models/Entity.php index c6b2468b0..d4b477304 100644 --- a/app/Entities/Models/Entity.php +++ b/app/Entities/Models/Entity.php @@ -9,6 +9,7 @@ use BookStack\Auth\Permissions\JointPermission; use BookStack\Entities\Tools\SearchIndex; use BookStack\Entities\Tools\SlugGenerator; use BookStack\Facades\Permissions; +use BookStack\Interfaces\Sluggable; use BookStack\Model; use BookStack\Traits\HasCreatorAndUpdater; use BookStack\Traits\HasOwner; @@ -37,7 +38,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @method static Builder withLastView() * @method static Builder withViewCount() */ -abstract class Entity extends Model +abstract class Entity extends Model implements Sluggable { use SoftDeletes; use HasCreatorAndUpdater; @@ -289,11 +290,11 @@ abstract class Entity extends Model } /** - * Generate and set a new URL slug for this model. + * @inheritdoc */ public function refreshSlug(): string { - $this->slug = (new SlugGenerator)->generate($this); + $this->slug = app(SlugGenerator::class)->generate($this); return $this->slug; } } diff --git a/app/Entities/Models/Page.php b/app/Entities/Models/Page.php index 739927aff..7e397894d 100644 --- a/app/Entities/Models/Page.php +++ b/app/Entities/Models/Page.php @@ -40,7 +40,7 @@ class Page extends BookChild */ public function scopeVisible(Builder $query): Builder { - $query = Permissions::enforceDraftVisiblityOnQuery($query); + $query = Permissions::enforceDraftVisibilityOnQuery($query); return parent::scopeVisible($query); } diff --git a/app/Entities/Repos/PageRepo.php b/app/Entities/Repos/PageRepo.php index 4c59db468..6a4eaeb15 100644 --- a/app/Entities/Repos/PageRepo.php +++ b/app/Entities/Repos/PageRepo.php @@ -177,25 +177,24 @@ class PageRepo // Hold the old details to compare later $oldHtml = $page->html; $oldName = $page->name; + $oldMarkdown = $page->markdown; $this->updateTemplateStatusAndContentFromInput($page, $input); $this->baseRepo->update($page, $input); // Update with new details $page->revision_count++; - - if (setting('app-editor') !== 'markdown') { - $page->markdown = ''; - } - $page->save(); // Remove all update drafts for this user & page. $this->getUserDraftQuery($page)->delete(); // Save a revision after updating - $summary = $input['summary'] ?? null; - if ($oldHtml !== $input['html'] || $oldName !== $input['name'] || $summary !== null) { + $summary = trim($input['summary'] ?? ""); + $htmlChanged = isset($input['html']) && $input['html'] !== $oldHtml; + $nameChanged = isset($input['name']) && $input['name'] !== $oldName; + $markdownChanged = isset($input['markdown']) && $input['markdown'] !== $oldMarkdown; + if ($htmlChanged || $nameChanged || $markdownChanged || $summary) { $this->savePageRevision($page, $summary); } @@ -224,10 +223,6 @@ class PageRepo { $revision = new PageRevision($page->getAttributes()); - if (setting('app-editor') !== 'markdown') { - $revision->markdown = ''; - } - $revision->page_id = $page->id; $revision->slug = $page->slug; $revision->book_slug = $page->book->slug; @@ -290,7 +285,13 @@ class PageRepo $page->fill($revision->toArray()); $content = new PageContent($page); - $content->setNewHTML($revision->html); + + if (!empty($revision->markdown)) { + $content->setNewMarkdown($revision->markdown); + } else { + $content->setNewHTML($revision->html); + } + $page->updated_by = user()->id; $page->refreshSlug(); $page->save(); diff --git a/app/Entities/Tools/Markdown/CustomStrikeThroughExtension.php b/app/Entities/Tools/Markdown/CustomStrikeThroughExtension.php index cb8b0ffc2..d4984ef08 100644 --- a/app/Entities/Tools/Markdown/CustomStrikeThroughExtension.php +++ b/app/Entities/Tools/Markdown/CustomStrikeThroughExtension.php @@ -13,4 +13,4 @@ class CustomStrikeThroughExtension implements ExtensionInterface $environment->addDelimiterProcessor(new StrikethroughDelimiterProcessor()); $environment->addInlineRenderer(Strikethrough::class, new CustomStrikethroughRenderer()); } -} \ No newline at end of file +} diff --git a/app/Entities/Tools/Markdown/CustomStrikethroughRenderer.php b/app/Entities/Tools/Markdown/CustomStrikethroughRenderer.php index 4371fb84c..7de95c263 100644 --- a/app/Entities/Tools/Markdown/CustomStrikethroughRenderer.php +++ b/app/Entities/Tools/Markdown/CustomStrikethroughRenderer.php @@ -21,4 +21,4 @@ class CustomStrikethroughRenderer implements InlineRendererInterface return new HtmlElement('s', $inline->getData('attributes', []), $htmlRenderer->renderInlines($inline->children())); } -} \ No newline at end of file +} diff --git a/app/Entities/Tools/PageContent.php b/app/Entities/Tools/PageContent.php index 62982f4ad..82499cdf2 100644 --- a/app/Entities/Tools/PageContent.php +++ b/app/Entities/Tools/PageContent.php @@ -2,6 +2,8 @@ use BookStack\Entities\Models\Page; use BookStack\Entities\Tools\Markdown\CustomStrikeThroughExtension; +use BookStack\Facades\Theme; +use BookStack\Theming\ThemeEvents; use DOMDocument; use DOMNodeList; use DOMXPath; @@ -53,6 +55,7 @@ class PageContent $environment->addExtension(new TableExtension()); $environment->addExtension(new TaskListExtension()); $environment->addExtension(new CustomStrikeThroughExtension()); + $environment = Theme::dispatch(ThemeEvents::COMMONMARK_ENVIRONMENT_CONFIGURE, $environment) ?? $environment; $converter = new CommonMarkConverter([], $environment); return $converter->convertToHtml($markdown); } diff --git a/app/Entities/Tools/SearchOptions.php b/app/Entities/Tools/SearchOptions.php index 60e3a9b78..6c03c57a6 100644 --- a/app/Entities/Tools/SearchOptions.php +++ b/app/Entities/Tools/SearchOptions.php @@ -137,5 +137,4 @@ class SearchOptions return $string; } - -} \ No newline at end of file +} diff --git a/app/Entities/Tools/SearchRunner.php b/app/Entities/Tools/SearchRunner.php index acfe8d956..fc127f906 100644 --- a/app/Entities/Tools/SearchRunner.php +++ b/app/Entities/Tools/SearchRunner.php @@ -1,6 +1,7 @@ permissionService->enforceEntityRestrictions($entityType, $entitySelect, $action); + return $this->permissionService->enforceEntityRestrictions($entity, $entitySelect, $action); } /** @@ -270,24 +271,29 @@ class SearchRunner protected function filterCreatedBy(EloquentBuilder $query, Entity $model, $input) { - if (!is_numeric($input) && $input !== 'me') { - return; + $userSlug = $input === 'me' ? user()->slug : trim($input); + $user = User::query()->where('slug', '=', $userSlug)->first(['id']); + if ($user) { + $query->where('created_by', '=', $user->id); } - if ($input === 'me') { - $input = user()->id; - } - $query->where('created_by', '=', $input); } protected function filterUpdatedBy(EloquentBuilder $query, Entity $model, $input) { - if (!is_numeric($input) && $input !== 'me') { - return; + $userSlug = $input === 'me' ? user()->slug : trim($input); + $user = User::query()->where('slug', '=', $userSlug)->first(['id']); + if ($user) { + $query->where('updated_by', '=', $user->id); } - if ($input === 'me') { - $input = user()->id; + } + + protected function filterOwnedBy(EloquentBuilder $query, Entity $model, $input) + { + $userSlug = $input === 'me' ? user()->slug : trim($input); + $user = User::query()->where('slug', '=', $userSlug)->first(['id']); + if ($user) { + $query->where('owned_by', '=', $user->id); } - $query->where('updated_by', '=', $input); } protected function filterInName(EloquentBuilder $query, Entity $model, $input) diff --git a/app/Entities/Tools/SlugGenerator.php b/app/Entities/Tools/SlugGenerator.php index 7075bc72c..4501279f2 100644 --- a/app/Entities/Tools/SlugGenerator.php +++ b/app/Entities/Tools/SlugGenerator.php @@ -1,6 +1,7 @@ formatNameAsSlug($entity->name); - while ($this->slugInUse($slug, $entity)) { - $slug .= '-' . substr(md5(rand(1, 500)), 0, 3); + $slug = $this->formatNameAsSlug($model->name); + while ($this->slugInUse($slug, $model)) { + $slug .= '-' . Str::random(3); } return $slug; } @@ -35,16 +36,16 @@ class SlugGenerator * Check if a slug is already in-use for this * type of model within the same parent. */ - protected function slugInUse(string $slug, Entity $entity): bool + protected function slugInUse(string $slug, Sluggable $model): bool { - $query = $entity->newQuery()->where('slug', '=', $slug); + $query = $model->newQuery()->where('slug', '=', $slug); - if ($entity instanceof BookChild) { - $query->where('book_id', '=', $entity->book_id); + if ($model instanceof BookChild) { + $query->where('book_id', '=', $model->book_id); } - if ($entity->id) { - $query->where('id', '!=', $entity->id); + if ($model->id) { + $query->where('id', '!=', $model->id); } return $query->count() > 0; diff --git a/app/Entities/Tools/TrashCan.php b/app/Entities/Tools/TrashCan.php index d2447ec68..df98fd318 100644 --- a/app/Entities/Tools/TrashCan.php +++ b/app/Entities/Tools/TrashCan.php @@ -273,11 +273,11 @@ class TrashCan $count++; }; - if ($entity->isA('chapter') || $entity->isA('book')) { + if ($entity instanceof Chapter || $entity instanceof Book) { $entity->pages()->withTrashed()->withCount('deletions')->get()->each($restoreAction); } - if ($entity->isA('book')) { + if ($entity instanceof Book) { $entity->chapters()->withTrashed()->withCount('deletions')->get()->each($restoreAction); } @@ -286,19 +286,20 @@ class TrashCan /** * Destroy the given entity. + * @throws Exception */ protected function destroyEntity(Entity $entity): int { - if ($entity->isA('page')) { + if ($entity instanceof Page) { return $this->destroyPage($entity); } - if ($entity->isA('chapter')) { + if ($entity instanceof Chapter) { return $this->destroyChapter($entity); } - if ($entity->isA('book')) { + if ($entity instanceof Book) { return $this->destroyBook($entity); } - if ($entity->isA('shelf')) { + if ($entity instanceof Bookshelf) { return $this->destroyShelf($entity); } } diff --git a/app/Exceptions/ApiAuthException.php b/app/Exceptions/ApiAuthException.php index cc68ba8cf..36ea8be9d 100644 --- a/app/Exceptions/ApiAuthException.php +++ b/app/Exceptions/ApiAuthException.php @@ -2,6 +2,7 @@ namespace BookStack\Exceptions; -class ApiAuthException extends UnauthorizedException { +class ApiAuthException extends UnauthorizedException +{ -} \ No newline at end of file +} diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 57078522b..196897164 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -3,9 +3,7 @@ namespace BookStack\Exceptions; use Exception; -use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Auth\AuthenticationException; -use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -16,36 +14,42 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class Handler extends ExceptionHandler { /** - * A list of the exception types that should not be reported. + * A list of the exception types that are not reported. * * @var array */ protected $dontReport = [ - AuthorizationException::class, - HttpException::class, - ModelNotFoundException::class, - ValidationException::class, NotFoundException::class, ]; /** - * Report or log an exception. - * This is a great spot to send exceptions to Sentry, Bugsnag, etc. + * A list of the inputs that are never flashed for validation exceptions. + * + * @var array + */ + protected $dontFlash = [ + 'password', + 'password_confirmation', + ]; + + /** + * Report or log an exception. + * + * @param Exception $exception + * @return void * - * @param \Exception $e - * @return mixed * @throws Exception */ - public function report(Exception $e) + public function report(Exception $exception) { - return parent::report($e); + parent::report($exception); } /** * Render an exception into an HTTP response. * * @param \Illuminate\Http\Request $request - * @param \Exception $e + * @param Exception $e * @return \Illuminate\Http\Response */ public function render($request, Exception $e) @@ -117,11 +121,8 @@ class Handler extends ExceptionHandler /** * Check the exception chain to compare against the original exception type. - * @param Exception $e - * @param $type - * @return bool */ - protected function isExceptionType(Exception $e, $type) + protected function isExceptionType(Exception $e, string $type): bool { do { if (is_a($e, $type)) { @@ -133,10 +134,8 @@ class Handler extends ExceptionHandler /** * Get original exception message. - * @param Exception $e - * @return string */ - protected function getOriginalMessage(Exception $e) + protected function getOriginalMessage(Exception $e): string { do { $message = $e->getMessage(); diff --git a/app/Exceptions/JsonDebugException.php b/app/Exceptions/JsonDebugException.php index 6314533ce..e155579d6 100644 --- a/app/Exceptions/JsonDebugException.php +++ b/app/Exceptions/JsonDebugException.php @@ -22,4 +22,4 @@ class JsonDebugException extends Exception { return response()->json($this->data); } -} \ No newline at end of file +} diff --git a/app/Exceptions/NotFoundException.php b/app/Exceptions/NotFoundException.php index af85ee4c9..94a405415 100644 --- a/app/Exceptions/NotFoundException.php +++ b/app/Exceptions/NotFoundException.php @@ -5,7 +5,6 @@ class NotFoundException extends PrettyException /** * NotFoundException constructor. - * @param string $message */ public function __construct($message = 'Item not found') { diff --git a/app/Exceptions/UnauthorizedException.php b/app/Exceptions/UnauthorizedException.php index 525b431c7..a13ba3a55 100644 --- a/app/Exceptions/UnauthorizedException.php +++ b/app/Exceptions/UnauthorizedException.php @@ -14,4 +14,4 @@ class UnauthorizedException extends Exception { parent::__construct($message, $code); } -} \ No newline at end of file +} diff --git a/app/Facades/Setting.php b/app/Facades/Theme.php similarity index 81% rename from app/Facades/Setting.php rename to app/Facades/Theme.php index 80feef89b..9b96e2ed2 100644 --- a/app/Facades/Setting.php +++ b/app/Facades/Theme.php @@ -2,7 +2,7 @@ use Illuminate\Support\Facades\Facade; -class Setting extends Facade +class Theme extends Facade { /** * Get the registered name of the component. @@ -11,6 +11,6 @@ class Setting extends Facade */ protected static function getFacadeAccessor() { - return 'setting'; + return 'theme'; } } diff --git a/app/Http/Controllers/Api/ApiController.php b/app/Http/Controllers/Api/ApiController.php index 0a3d89453..f143ea5cd 100644 --- a/app/Http/Controllers/Api/ApiController.php +++ b/app/Http/Controllers/Api/ApiController.php @@ -27,4 +27,4 @@ abstract class ApiController extends Controller { return $this->rules; } -} \ No newline at end of file +} diff --git a/app/Http/Controllers/Api/ApiDocsController.php b/app/Http/Controllers/Api/ApiDocsController.php index 80e86e101..c63ca698c 100644 --- a/app/Http/Controllers/Api/ApiDocsController.php +++ b/app/Http/Controllers/Api/ApiDocsController.php @@ -25,5 +25,4 @@ class ApiDocsController extends ApiController $docs = ApiDocsGenerator::generateConsideringCache(); return response()->json($docs); } - } diff --git a/app/Http/Controllers/Api/BookApiController.php b/app/Http/Controllers/Api/BookApiController.php index 1b9bddbb1..81ac9c7aa 100644 --- a/app/Http/Controllers/Api/BookApiController.php +++ b/app/Http/Controllers/Api/BookApiController.php @@ -91,4 +91,4 @@ class BookApiController extends ApiController $this->bookRepo->destroy($book); return response('', 204); } -} \ No newline at end of file +} diff --git a/app/Http/Controllers/Api/BookshelfApiController.php b/app/Http/Controllers/Api/BookshelfApiController.php index 57461fce5..4ce93defa 100644 --- a/app/Http/Controllers/Api/BookshelfApiController.php +++ b/app/Http/Controllers/Api/BookshelfApiController.php @@ -112,4 +112,4 @@ class BookshelfApiController extends ApiController $this->bookshelfRepo->destroy($shelf); return response('', 204); } -} \ No newline at end of file +} diff --git a/app/Http/Controllers/AuditLogController.php b/app/Http/Controllers/AuditLogController.php index eb6eecc94..f73ee4a20 100644 --- a/app/Http/Controllers/AuditLogController.php +++ b/app/Http/Controllers/AuditLogController.php @@ -20,6 +20,7 @@ class AuditLogController extends Controller 'sort' => $request->get('sort', 'created_at'), 'date_from' => $request->get('date_from', ''), 'date_to' => $request->get('date_to', ''), + 'user' => $request->get('user', ''), ]; $query = Activity::query() @@ -34,6 +35,9 @@ class AuditLogController extends Controller if ($listDetails['event']) { $query->where('type', '=', $listDetails['event']); } + if ($listDetails['user']) { + $query->where('user_id', '=', $listDetails['user']); + } if ($listDetails['date_from']) { $query->where('created_at', '>=', $listDetails['date_from']); diff --git a/app/Http/Controllers/Auth/ConfirmEmailController.php b/app/Http/Controllers/Auth/ConfirmEmailController.php index bffeb5f61..6e6a0e779 100644 --- a/app/Http/Controllers/Auth/ConfirmEmailController.php +++ b/app/Http/Controllers/Auth/ConfirmEmailController.php @@ -2,12 +2,15 @@ namespace BookStack\Http\Controllers\Auth; +use BookStack\Actions\ActivityType; use BookStack\Auth\Access\EmailConfirmationService; use BookStack\Auth\UserRepo; use BookStack\Exceptions\ConfirmationEmailException; use BookStack\Exceptions\UserTokenExpiredException; use BookStack\Exceptions\UserTokenNotFoundException; +use BookStack\Facades\Theme; use BookStack\Http\Controllers\Controller; +use BookStack\Theming\ThemeEvents; use Exception; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; @@ -80,6 +83,8 @@ class ConfirmEmailController extends Controller $user->save(); auth()->login($user); + Theme::dispatch(ThemeEvents::AUTH_LOGIN, auth()->getDefaultDriver(), $user); + $this->logActivity(ActivityType::AUTH_LOGIN, $user); $this->showSuccessNotification(trans('auth.email_confirm_success')); $this->emailConfirmationService->deleteByUser($user); diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 1252e6217..01255f466 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -7,7 +7,9 @@ use BookStack\Actions\ActivityType; use BookStack\Auth\Access\SocialAuthService; use BookStack\Exceptions\LoginAttemptEmailNeededException; use BookStack\Exceptions\LoginAttemptException; +use BookStack\Facades\Theme; use BookStack\Http\Controllers\Controller; +use BookStack\Theming\ThemeEvents; use Illuminate\Foundation\Auth\AuthenticatesUsers; use Illuminate\Http\Request; @@ -150,6 +152,7 @@ class LoginController extends Controller } } + Theme::dispatch(ThemeEvents::AUTH_LOGIN, auth()->getDefaultDriver(), $user); $this->logActivity(ActivityType::AUTH_LOGIN, $user); return redirect()->intended($this->redirectPath()); } @@ -195,5 +198,4 @@ class LoginController extends Controller return redirect('/login'); } - } diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index e3d22264d..7d7d8732b 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -2,11 +2,14 @@ namespace BookStack\Http\Controllers\Auth; +use BookStack\Actions\ActivityType; use BookStack\Auth\Access\RegistrationService; use BookStack\Auth\Access\SocialAuthService; use BookStack\Auth\User; use BookStack\Exceptions\UserRegistrationException; +use BookStack\Facades\Theme; use BookStack\Http\Controllers\Controller; +use BookStack\Theming\ThemeEvents; use Illuminate\Foundation\Auth\RegistersUsers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash; @@ -93,6 +96,8 @@ class RegisterController extends Controller try { $user = $this->registrationService->registerUser($userData); auth()->login($user); + Theme::dispatch(ThemeEvents::AUTH_LOGIN, auth()->getDefaultDriver(), $user); + $this->logActivity(ActivityType::AUTH_LOGIN, $user); } catch (UserRegistrationException $exception) { if ($exception->getMessage()) { $this->showErrorNotification($exception->getMessage()); @@ -117,5 +122,4 @@ class RegisterController extends Controller 'password' => Hash::make($data['password']), ]); } - } diff --git a/app/Http/Controllers/Auth/Saml2Controller.php b/app/Http/Controllers/Auth/Saml2Controller.php index 8a3bf065e..dc7814c4b 100644 --- a/app/Http/Controllers/Auth/Saml2Controller.php +++ b/app/Http/Controllers/Auth/Saml2Controller.php @@ -82,5 +82,4 @@ class Saml2Controller extends Controller return redirect()->intended(); } - } diff --git a/app/Http/Controllers/Auth/SocialController.php b/app/Http/Controllers/Auth/SocialController.php index 0c53c9233..447f0afc9 100644 --- a/app/Http/Controllers/Auth/SocialController.php +++ b/app/Http/Controllers/Auth/SocialController.php @@ -2,16 +2,17 @@ namespace BookStack\Http\Controllers\Auth; +use BookStack\Actions\ActivityType; use BookStack\Auth\Access\RegistrationService; use BookStack\Auth\Access\SocialAuthService; use BookStack\Exceptions\SocialDriverNotConfigured; use BookStack\Exceptions\SocialSignInAccountNotUsed; use BookStack\Exceptions\SocialSignInException; use BookStack\Exceptions\UserRegistrationException; +use BookStack\Facades\Theme; use BookStack\Http\Controllers\Controller; -use Illuminate\Http\RedirectResponse; +use BookStack\Theming\ThemeEvents; use Illuminate\Http\Request; -use Illuminate\Routing\Redirector; use Illuminate\Support\Str; use Laravel\Socialite\Contracts\User as SocialUser; @@ -31,12 +32,11 @@ class SocialController extends Controller $this->registrationService = $registrationService; } - /** * Redirect to the relevant social site. - * @throws \BookStack\Exceptions\SocialDriverNotConfigured + * @throws SocialDriverNotConfigured */ - public function getSocialLogin(string $socialDriver) + public function login(string $socialDriver) { session()->put('social-callback', 'login'); return $this->socialAuthService->startLogIn($socialDriver); @@ -47,7 +47,7 @@ class SocialController extends Controller * @throws SocialDriverNotConfigured * @throws UserRegistrationException */ - public function socialRegister(string $socialDriver) + public function register(string $socialDriver) { $this->registrationService->ensureRegistrationAllowed(); session()->put('social-callback', 'register'); @@ -60,7 +60,7 @@ class SocialController extends Controller * @throws SocialDriverNotConfigured * @throws UserRegistrationException */ - public function socialCallback(Request $request, string $socialDriver) + public function callback(Request $request, string $socialDriver) { if (!session()->has('social-callback')) { throw new SocialSignInException(trans('errors.social_no_action_defined'), '/login'); @@ -99,7 +99,7 @@ class SocialController extends Controller /** * Detach a social account from a user. */ - public function detachSocialAccount(string $socialDriver) + public function detach(string $socialDriver) { $this->socialAuthService->detachSocialAccount($socialDriver); session()->flash('success', trans('settings.users_social_disconnected', ['socialAccount' => Str::title($socialDriver)])); @@ -113,7 +113,7 @@ class SocialController extends Controller protected function socialRegisterCallback(string $socialDriver, SocialUser $socialUser) { $socialUser = $this->socialAuthService->handleRegistrationCallback($socialDriver, $socialUser); - $socialAccount = $this->socialAuthService->fillSocialAccount($socialDriver, $socialUser); + $socialAccount = $this->socialAuthService->newSocialAccount($socialDriver, $socialUser); $emailVerified = $this->socialAuthService->driverAutoConfirmEmailEnabled($socialDriver); // Create an array of the user data to create a new user instance @@ -130,6 +130,8 @@ class SocialController extends Controller $user = $this->registrationService->registerUser($userData, $socialAccount, $emailVerified); auth()->login($user); + Theme::dispatch(ThemeEvents::AUTH_LOGIN, $socialDriver, $user); + $this->logActivity(ActivityType::AUTH_LOGIN, $user); $this->showSuccessNotification(trans('auth.register_success')); return redirect('/'); diff --git a/app/Http/Controllers/Auth/UserInviteController.php b/app/Http/Controllers/Auth/UserInviteController.php index 926458fa6..ab7452248 100644 --- a/app/Http/Controllers/Auth/UserInviteController.php +++ b/app/Http/Controllers/Auth/UserInviteController.php @@ -2,11 +2,14 @@ namespace BookStack\Http\Controllers\Auth; +use BookStack\Actions\ActivityType; use BookStack\Auth\Access\UserInviteService; use BookStack\Auth\UserRepo; use BookStack\Exceptions\UserTokenExpiredException; use BookStack\Exceptions\UserTokenNotFoundException; +use BookStack\Facades\Theme; use BookStack\Http\Controllers\Controller; +use BookStack\Theming\ThemeEvents; use Exception; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; @@ -68,6 +71,8 @@ class UserInviteController extends Controller $user->save(); auth()->login($user); + Theme::dispatch(ThemeEvents::AUTH_LOGIN, auth()->getDefaultDriver(), $user); + $this->logActivity(ActivityType::AUTH_LOGIN, $user); $this->showSuccessNotification(trans('auth.user_invite_success', ['appName' => setting('app-name')])); $this->inviteService->deleteByUser($user); diff --git a/app/Http/Controllers/BookController.php b/app/Http/Controllers/BookController.php index 3d695ba85..59c205d0a 100644 --- a/app/Http/Controllers/BookController.php +++ b/app/Http/Controllers/BookController.php @@ -30,7 +30,7 @@ class BookController extends Controller */ public function index() { - $view = setting()->getForCurrentUser('books_view_type', config('app.views.books')); + $view = setting()->getForCurrentUser('books_view_type'); $sort = setting()->getForCurrentUser('books_sort', 'name'); $order = setting()->getForCurrentUser('books_sort_order', 'asc'); diff --git a/app/Http/Controllers/BookshelfController.php b/app/Http/Controllers/BookshelfController.php index 32c22e185..8574c1b48 100644 --- a/app/Http/Controllers/BookshelfController.php +++ b/app/Http/Controllers/BookshelfController.php @@ -32,7 +32,7 @@ class BookshelfController extends Controller */ public function index() { - $view = setting()->getForCurrentUser('bookshelves_view_type', config('app.views.bookshelves', 'grid')); + $view = setting()->getForCurrentUser('bookshelves_view_type'); $sort = setting()->getForCurrentUser('bookshelves_sort', 'name'); $order = setting()->getForCurrentUser('bookshelves_sort_order', 'asc'); $sortOptions = [ @@ -103,7 +103,7 @@ class BookshelfController extends Controller Views::add($shelf); $this->entityContextManager->setShelfContext($shelf->id); - $view = setting()->getForCurrentUser('bookshelf_view_type', config('app.views.books')); + $view = setting()->getForCurrentUser('bookshelf_view_type'); $this->setPageTitle($shelf->getShortName()); return view('shelves.show', [ diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 479d5ac15..034dfa524 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -159,6 +159,6 @@ abstract class Controller extends BaseController */ protected function getImageValidationRules(): string { - return 'image_extension|no_double_extension|mimes:jpeg,png,gif,webp'; + return 'image_extension|mimes:jpeg,png,gif,webp'; } } diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index 3258f4369..31736e1b0 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -56,7 +56,7 @@ class HomeController extends Controller // Add required list ordering & sorting for books & shelves views. if ($homepageOption === 'bookshelves' || $homepageOption === 'books') { $key = $homepageOption; - $view = setting()->getForCurrentUser($key . '_view_type', config('app.views.' . $key)); + $view = setting()->getForCurrentUser($key . '_view_type'); $sort = setting()->getForCurrentUser($key . '_sort', 'name'); $order = setting()->getForCurrentUser($key . '_sort_order', 'asc'); diff --git a/app/Http/Controllers/SearchController.php b/app/Http/Controllers/SearchController.php index 21ebea378..bb824fd9b 100644 --- a/app/Http/Controllers/SearchController.php +++ b/app/Http/Controllers/SearchController.php @@ -1,9 +1,6 @@ where('user_id', '=', $user->id)->where('id', '=', $tokenId)->firstOrFail(); return [$user, $token]; } - } diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 92e1cd8b7..d797552f1 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -5,10 +5,13 @@ use BookStack\Auth\Access\SocialAuthService; use BookStack\Auth\Access\UserInviteService; use BookStack\Auth\User; use BookStack\Auth\UserRepo; +use BookStack\Exceptions\ImageUploadException; use BookStack\Exceptions\UserUpdateException; use BookStack\Uploads\ImageRepo; +use Exception; use Illuminate\Http\Request; use Illuminate\Support\Str; +use Illuminate\Validation\ValidationException; class UserController extends Controller { @@ -61,7 +64,7 @@ class UserController extends Controller /** * Store a newly created user in storage. * @throws UserUpdateException - * @throws \Illuminate\Validation\ValidationException + * @throws ValidationException */ public function store(Request $request) { @@ -90,6 +93,7 @@ class UserController extends Controller $user->external_auth_id = $request->get('external_auth_id'); } + $user->refreshSlug(); $user->save(); if ($sendInvite) { @@ -132,8 +136,8 @@ class UserController extends Controller /** * Update the specified user in storage. * @throws UserUpdateException - * @throws \BookStack\Exceptions\ImageUploadException - * @throws \Illuminate\Validation\ValidationException + * @throws ImageUploadException + * @throws ValidationException */ public function update(Request $request, int $id) { @@ -157,6 +161,11 @@ class UserController extends Controller $user->email = $request->get('email'); } + // Refresh the slug if the user's name has changed + if ($user->isDirty('name')) { + $user->refreshSlug(); + } + // Role updates if (userCan('users-manage') && $request->filled('roles')) { $roles = $request->get('roles'); @@ -216,7 +225,7 @@ class UserController extends Controller /** * Remove the specified user from storage. - * @throws \Exception + * @throws Exception */ public function destroy(Request $request, int $id) { @@ -243,25 +252,6 @@ class UserController extends Controller return redirect('/settings/users'); } - /** - * Show the user profile page - */ - public function showProfilePage($id) - { - $user = $this->userRepo->getById($id); - - $userActivity = $this->userRepo->getActivity($user); - $recentlyCreated = $this->userRepo->getRecentlyCreated($user, 5); - $assetCounts = $this->userRepo->getAssetCounts($user); - - return view('users.profile', [ - 'user' => $user, - 'activity' => $userActivity, - 'recentlyCreated' => $recentlyCreated, - 'assetCounts' => $assetCounts - ]); - } - /** * Update the user's preferred book-list display setting. */ diff --git a/app/Http/Controllers/UserProfileController.php b/app/Http/Controllers/UserProfileController.php new file mode 100644 index 000000000..95e68cb07 --- /dev/null +++ b/app/Http/Controllers/UserProfileController.php @@ -0,0 +1,25 @@ +getBySlug($slug); + + $userActivity = $repo->getActivity($user); + $recentlyCreated = $repo->getRecentlyCreated($user, 5); + $assetCounts = $repo->getAssetCounts($user); + + return view('users.profile', [ + 'user' => $user, + 'activity' => $userActivity, + 'recentlyCreated' => $recentlyCreated, + 'assetCounts' => $assetCounts + ]); + } +} diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 075c98ec7..694036ab4 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -28,6 +28,7 @@ class Kernel extends HttpKernel \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \BookStack\Http\Middleware\VerifyCsrfToken::class, + \BookStack\Http\Middleware\RunThemeActions::class, \BookStack\Http\Middleware\Localization::class, ], 'api' => [ diff --git a/app/Http/Middleware/ChecksForEmailConfirmation.php b/app/Http/Middleware/ChecksForEmailConfirmation.php index 4b1732810..cbf55040a 100644 --- a/app/Http/Middleware/ChecksForEmailConfirmation.php +++ b/app/Http/Middleware/ChecksForEmailConfirmation.php @@ -33,4 +33,4 @@ trait ChecksForEmailConfirmation return false; } -} \ No newline at end of file +} diff --git a/app/Http/Middleware/Localization.php b/app/Http/Middleware/Localization.php index 597d28365..cd084746c 100644 --- a/app/Http/Middleware/Localization.php +++ b/app/Http/Middleware/Localization.php @@ -18,6 +18,8 @@ class Localization protected $localeMap = [ 'ar' => 'ar', 'bg' => 'bg_BG', + 'bs' => 'bs_BA', + 'ca' => 'ca', 'da' => 'da_DK', 'de' => 'de_DE', 'de_informal' => 'de_DE', @@ -26,13 +28,15 @@ class Localization 'es_AR' => 'es_AR', 'fr' => 'fr_FR', 'he' => 'he_IL', + 'id' => 'id_ID', 'it' => 'it_IT', 'ja' => 'ja', 'ko' => 'ko_KR', + 'lv' => 'lv_LV', 'nl' => 'nl_NL', 'nb' => 'nb_NO', 'pl' => 'pl_PL', - 'pt' => 'pl_PT', + 'pt' => 'pt_PT', 'pt_BR' => 'pt_BR', 'ru' => 'ru', 'sk' => 'sk_SK', diff --git a/app/Http/Middleware/RunThemeActions.php b/app/Http/Middleware/RunThemeActions.php new file mode 100644 index 000000000..d995f1445 --- /dev/null +++ b/app/Http/Middleware/RunThemeActions.php @@ -0,0 +1,29 @@ +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)); + }); } } diff --git a/app/Providers/CustomFacadeProvider.php b/app/Providers/CustomFacadeProvider.php index b4158187c..f203f0fda 100644 --- a/app/Providers/CustomFacadeProvider.php +++ b/app/Providers/CustomFacadeProvider.php @@ -5,7 +5,7 @@ namespace BookStack\Providers; use BookStack\Actions\ActivityService; use BookStack\Actions\ViewService; use BookStack\Auth\Permissions\PermissionService; -use BookStack\Settings\SettingService; +use BookStack\Theming\ThemeService; use BookStack\Uploads\ImageService; use Illuminate\Support\ServiceProvider; @@ -36,10 +36,6 @@ class CustomFacadeProvider extends ServiceProvider return $this->app->make(ViewService::class); }); - $this->app->singleton('setting', function () { - return $this->app->make(SettingService::class); - }); - $this->app->singleton('images', function () { return $this->app->make(ImageService::class); }); @@ -47,5 +43,9 @@ class CustomFacadeProvider extends ServiceProvider $this->app->singleton('permissions', function () { return $this->app->make(PermissionService::class); }); + + $this->app->singleton('theme', function () { + return $this->app->make(ThemeService::class); + }); } } diff --git a/app/Providers/CustomValidationServiceProvider.php b/app/Providers/CustomValidationServiceProvider.php index 4a5272b40..b668a4cd2 100644 --- a/app/Providers/CustomValidationServiceProvider.php +++ b/app/Providers/CustomValidationServiceProvider.php @@ -18,11 +18,6 @@ class CustomValidationServiceProvider extends ServiceProvider return in_array(strtolower($value->getClientOriginalExtension()), $validImageExtensions); }); - Validator::extend('no_double_extension', function ($attribute, $value, $parameters, $validator) { - $uploadName = $value->getClientOriginalName(); - return substr_count($uploadName, '.') < 2; - }); - Validator::extend('safe_url', function ($attribute, $value, $parameters, $validator) { $cleanLinkName = strtolower(trim($value)); $isJs = strpos($cleanLinkName, 'javascript:') === 0; diff --git a/app/Providers/ThemeServiceProvider.php b/app/Providers/ThemeServiceProvider.php new file mode 100644 index 000000000..c41a15af0 --- /dev/null +++ b/app/Providers/ThemeServiceProvider.php @@ -0,0 +1,34 @@ +app->singleton(ThemeService::class, function ($app) { + return new ThemeService; + }); + } + + /** + * Bootstrap services. + * + * @return void + */ + public function boot() + { + $themeService = $this->app->make(ThemeService::class); + $themeService->readThemeActions(); + $themeService->dispatch(ThemeEvents::APP_BOOT, $this->app); + } +} diff --git a/app/Providers/TranslationServiceProvider.php b/app/Providers/TranslationServiceProvider.php index 9ff607afe..b7fb9b117 100644 --- a/app/Providers/TranslationServiceProvider.php +++ b/app/Providers/TranslationServiceProvider.php @@ -17,5 +17,4 @@ class TranslationServiceProvider extends BaseProvider return new FileLoader($app['files'], $app['path.lang']); }); } - -} \ No newline at end of file +} diff --git a/app/Settings/SettingService.php b/app/Settings/SettingService.php index 042ae7aa4..310e0ccff 100644 --- a/app/Settings/SettingService.php +++ b/app/Settings/SettingService.php @@ -29,9 +29,9 @@ class SettingService * Gets a setting from the database, * If not found, Returns default, Which is false by default. */ - public function get(string $key, $default = false) + public function get(string $key, $default = null) { - if ($default === false) { + if (is_null($default)) { $default = config('setting-defaults.' . $key, false); } @@ -57,8 +57,12 @@ class SettingService /** * Get a user-specific setting from the database or cache. */ - public function getUser(User $user, string $key, $default = false) + public function getUser(User $user, string $key, $default = null) { + if (is_null($default)) { + $default = config('setting-defaults.user.' . $key, false); + } + if ($user->isDefault()) { return $this->getFromSession($key, $default); } @@ -68,7 +72,7 @@ class SettingService /** * Get a value for the current logged-in user. */ - public function getForCurrentUser(string $key, $default = false) + public function getForCurrentUser(string $key, $default = null) { return $this->getUser(user(), $key, $default); } @@ -172,7 +176,7 @@ class SettingService */ protected function formatArrayValue(array $value): string { - $values = collect($value)->values()->filter(function(array $item) { + $values = collect($value)->values()->filter(function (array $item) { return count(array_filter($item)) > 0; }); return json_encode($values); diff --git a/app/Theming/ThemeEvents.php b/app/Theming/ThemeEvents.php new file mode 100644 index 000000000..56e1fba1c --- /dev/null +++ b/app/Theming/ThemeEvents.php @@ -0,0 +1,73 @@ +listeners[$event])) { + $this->listeners[$event] = []; + } + + $this->listeners[$event][] = $action; + } + + /** + * Dispatch the given event name. + * Runs any registered listeners for that event name, + * passing all additional variables to the listener action. + * + * If a callback returns a non-null value, this method will + * stop and return that value itself. + * @return mixed + */ + public function dispatch(string $event, ...$args) + { + foreach ($this->listeners[$event] ?? [] as $action) { + $result = call_user_func_array($action, $args); + if (!is_null($result)) { + return $result; + } + } + return null; + } + + /** + * Read any actions from the set theme path if the 'functions.php' file exists. + */ + public function readThemeActions() + { + $themeActionsFile = theme_path('functions.php'); + if (file_exists($themeActionsFile)) { + require $themeActionsFile; + } + } + + /** + * @see SocialAuthService::addSocialDriver + */ + public function addSocialDriver(string $driverName, array $config, string $socialiteHandler) + { + $socialAuthService = app()->make(SocialAuthService::class); + $socialAuthService->addSocialDriver($driverName, $config, $socialiteHandler); + } +} \ No newline at end of file diff --git a/app/Traits/HasCreatorAndUpdater.php b/app/Traits/HasCreatorAndUpdater.php index ad6c3035f..ace1fa12c 100644 --- a/app/Traits/HasCreatorAndUpdater.php +++ b/app/Traits/HasCreatorAndUpdater.php @@ -24,5 +24,4 @@ trait HasCreatorAndUpdater { return $this->belongsTo(User::class, 'updated_by'); } - } diff --git a/app/Traits/HasOwner.php b/app/Traits/HasOwner.php index 9d1eb3df7..ff4b8c18e 100644 --- a/app/Traits/HasOwner.php +++ b/app/Traits/HasOwner.php @@ -15,5 +15,4 @@ trait HasOwner { return $this->belongsTo(User::class, 'owned_by'); } - } diff --git a/app/Translation/FileLoader.php b/app/Translation/FileLoader.php index f0f895da5..0b4a93de6 100644 --- a/app/Translation/FileLoader.php +++ b/app/Translation/FileLoader.php @@ -27,4 +27,4 @@ class FileLoader extends BaseLoader return $this->loadNamespaced($locale, $group, $namespace); } -} \ No newline at end of file +} diff --git a/app/Uploads/ImageRepo.php b/app/Uploads/ImageRepo.php index b4d743b73..e6f766824 100644 --- a/app/Uploads/ImageRepo.php +++ b/app/Uploads/ImageRepo.php @@ -70,8 +70,7 @@ class ImageRepo int $uploadedTo = null, string $search = null, callable $whereClause = null - ): array - { + ): array { $imageQuery = $this->image->newQuery()->where('type', '=', strtolower($type)); if ($uploadedTo !== null) { @@ -83,7 +82,7 @@ class ImageRepo } // Filter by page access - $imageQuery = $this->restrictionService->filterRelatedEntity('page', $imageQuery, 'images', 'uploaded_to'); + $imageQuery = $this->restrictionService->filterRelatedEntity(Page::class, $imageQuery, 'images', 'uploaded_to'); if ($whereClause !== null) { $imageQuery = $imageQuery->where($whereClause); @@ -102,8 +101,7 @@ class ImageRepo int $pageSize = 24, int $uploadedTo = null, string $search = null - ): array - { + ): array { $contextPage = $this->page->findOrFail($uploadedTo); $parentFilter = null; diff --git a/app/Uploads/ImageService.php b/app/Uploads/ImageService.php index 92c3994a7..02fe2e8ef 100644 --- a/app/Uploads/ImageService.php +++ b/app/Uploads/ImageService.php @@ -139,7 +139,7 @@ class ImageService $name = str_replace(' ', '-', $name); $nameParts = explode('.', $name); $extension = array_pop($nameParts); - $name = implode('.', $nameParts); + $name = implode('-', $nameParts); $name = Str::slug($name); if (strlen($name) === 0) { diff --git a/app/Uploads/UserAvatars.php b/app/Uploads/UserAvatars.php index b3b9d5951..f1509bbb8 100644 --- a/app/Uploads/UserAvatars.php +++ b/app/Uploads/UserAvatars.php @@ -97,5 +97,4 @@ class UserAvatars return $url; } - -} \ No newline at end of file +} diff --git a/app/helpers.php b/app/helpers.php index c090bfd05..c1d72b91d 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -79,9 +79,9 @@ function userCanOnAny(string $permission, string $entityClass = null): bool /** * Helper to access system settings. - * @return bool|string|SettingService + * @return mixed|SettingService */ -function setting(string $key = null, $default = false) +function setting(string $key = null, $default = null) { $settingService = resolve(SettingService::class); diff --git a/composer.json b/composer.json index df2439f85..3e604b8fd 100644 --- a/composer.json +++ b/composer.json @@ -5,25 +5,25 @@ "license": "MIT", "type": "project", "require": { - "php": "^7.2.5", + "php": "^7.3|^8.0", "ext-curl": "*", "ext-dom": "*", "ext-gd": "*", "ext-json": "*", "ext-mbstring": "*", "ext-xml": "*", - "barryvdh/laravel-dompdf": "^0.8.7", + "barryvdh/laravel-dompdf": "^0.9.0", "barryvdh/laravel-snappy": "^0.4.8", - "doctrine/dbal": "^2.9", + "doctrine/dbal": "^2.12.1", "facade/ignition": "^1.16.4", "fideloper/proxy": "^4.4.1", "intervention/image": "^2.5.1", - "laravel/framework": "^6.20.12", + "laravel/framework": "^6.20.16", "laravel/socialite": "^5.1", "league/commonmark": "^1.5", "league/flysystem-aws-s3-v3": "^1.0.29", "nunomaduro/collision": "^3.1", - "onelogin/php-saml": "^3.3", + "onelogin/php-saml": "^4.0", "predis/predis": "^1.1.6", "socialiteproviders/discord": "^4.1", "socialiteproviders/gitlab": "^4.1", @@ -36,10 +36,10 @@ "require-dev": { "barryvdh/laravel-debugbar": "^3.5.1", "barryvdh/laravel-ide-helper": "^2.8.2", - "fakerphp/faker": "^1.9.1", + "fakerphp/faker": "^1.13.0", "laravel/browser-kit-testing": "^5.2", "mockery/mockery": "^1.3.3", - "phpunit/phpunit": "^8.0", + "phpunit/phpunit": "^9.5.3", "squizlabs/php_codesniffer": "^3.5.8" }, "autoload": { @@ -87,7 +87,7 @@ "preferred-install": "dist", "sort-packages": true, "platform": { - "php": "7.2.5" + "php": "7.3.0" } }, "extra": { diff --git a/composer.lock b/composer.lock index d959ed97e..0a14f0d77 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "df6e5d5d5debaaeab590da55c7d50ec2", + "content-hash": "b26d29958d84c91b164a8234d1a7e9e9", "packages": [ { "name": "aws/aws-sdk-php", - "version": "3.172.3", + "version": "3.175.0", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "14fd73f12fc70d5f48e034f5dfc33136136adb61" + "reference": "31baa9e0c4330f01eb74b8a7ef086e9d34f8391e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/14fd73f12fc70d5f48e034f5dfc33136136adb61", - "reference": "14fd73f12fc70d5f48e034f5dfc33136136adb61", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/31baa9e0c4330f01eb74b8a7ef086e9d34f8391e", + "reference": "31baa9e0c4330f01eb74b8a7ef086e9d34f8391e", "shasum": "" }, "require": { @@ -25,9 +25,9 @@ "ext-pcre": "*", "ext-simplexml": "*", "guzzlehttp/guzzle": "^5.3.3|^6.2.1|^7.0", - "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.4.1", - "mtdowling/jmespath.php": "^2.5", + "guzzlehttp/promises": "^1.4.0", + "guzzlehttp/psr7": "^1.7.0", + "mtdowling/jmespath.php": "^2.6", "php": ">=5.5" }, "require-dev": { @@ -92,33 +92,33 @@ "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.172.3" + "source": "https://github.com/aws/aws-sdk-php/tree/3.175.0" }, - "time": "2021-01-28T19:14:55+00:00" + "time": "2021-03-19T18:13:22+00:00" }, { "name": "barryvdh/laravel-dompdf", - "version": "v0.8.7", + "version": "v0.9.0", "source": { "type": "git", "url": "https://github.com/barryvdh/laravel-dompdf.git", - "reference": "30310e0a675462bf2aa9d448c8dcbf57fbcc517d" + "reference": "5b99e1f94157d74e450f4c97e8444fcaffa2144b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/30310e0a675462bf2aa9d448c8dcbf57fbcc517d", - "reference": "30310e0a675462bf2aa9d448c8dcbf57fbcc517d", + "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/5b99e1f94157d74e450f4c97e8444fcaffa2144b", + "reference": "5b99e1f94157d74e450f4c97e8444fcaffa2144b", "shasum": "" }, "require": { - "dompdf/dompdf": "^0.8", + "dompdf/dompdf": "^1", "illuminate/support": "^5.5|^6|^7|^8", - "php": ">=7" + "php": "^7.1 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "0.8-dev" + "dev-master": "0.9-dev" }, "laravel": { "providers": [ @@ -152,7 +152,7 @@ ], "support": { "issues": "https://github.com/barryvdh/laravel-dompdf/issues", - "source": "https://github.com/barryvdh/laravel-dompdf/tree/master" + "source": "https://github.com/barryvdh/laravel-dompdf/tree/v0.9.0" }, "funding": [ { @@ -160,7 +160,7 @@ "type": "github" } ], - "time": "2020-09-07T11:50:18+00:00" + "time": "2020-12-27T12:05:53+00:00" }, { "name": "barryvdh/laravel-snappy", @@ -329,33 +329,32 @@ }, { "name": "doctrine/dbal", - "version": "2.10.4", + "version": "2.12.1", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "47433196b6390d14409a33885ee42b6208160643" + "reference": "adce7a954a1c2f14f85e94aed90c8489af204086" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/47433196b6390d14409a33885ee42b6208160643", - "reference": "47433196b6390d14409a33885ee42b6208160643", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/adce7a954a1c2f14f85e94aed90c8489af204086", + "reference": "adce7a954a1c2f14f85e94aed90c8489af204086", "shasum": "" }, "require": { "doctrine/cache": "^1.0", "doctrine/event-manager": "^1.0", "ext-pdo": "*", - "php": "^7.2" + "php": "^7.3 || ^8" }, "require-dev": { "doctrine/coding-standard": "^8.1", "jetbrains/phpstorm-stubs": "^2019.1", - "nikic/php-parser": "^4.4", "phpstan/phpstan": "^0.12.40", - "phpunit/phpunit": "^8.5.5", + "phpunit/phpunit": "^9.4", "psalm/plugin-phpunit": "^0.10.0", "symfony/console": "^2.0.5|^3.0|^4.0|^5.0", - "vimeo/psalm": "^3.14.2" + "vimeo/psalm": "^3.17.2" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -366,8 +365,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.10.x-dev", - "dev-develop": "3.0.x-dev" + "dev-master": "4.0.x-dev" } }, "autoload": { @@ -422,7 +420,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/2.10.4" + "source": "https://github.com/doctrine/dbal/tree/2.12.1" }, "funding": [ { @@ -438,7 +436,7 @@ "type": "tidelift" } ], - "time": "2020-09-12T21:20:41+00:00" + "time": "2020-11-14T20:26:58+00:00" }, { "name": "doctrine/event-manager", @@ -711,16 +709,16 @@ }, { "name": "dompdf/dompdf", - "version": "v0.8.6", + "version": "v1.0.2", "source": { "type": "git", "url": "https://github.com/dompdf/dompdf.git", - "reference": "db91d81866c69a42dad1d2926f61515a1e3f42c5" + "reference": "8768448244967a46d6e67b891d30878e0e15d25c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/dompdf/zipball/db91d81866c69a42dad1d2926f61515a1e3f42c5", - "reference": "db91d81866c69a42dad1d2926f61515a1e3f42c5", + "url": "https://api.github.com/repos/dompdf/dompdf/zipball/8768448244967a46d6e67b891d30878e0e15d25c", + "reference": "8768448244967a46d6e67b891d30878e0e15d25c", "shasum": "" }, "require": { @@ -728,11 +726,11 @@ "ext-mbstring": "*", "phenx/php-font-lib": "^0.5.2", "phenx/php-svg-lib": "^0.3.3", - "php": "^7.1" + "php": "^7.1 || ^8.0" }, "require-dev": { "mockery/mockery": "^1.3", - "phpunit/phpunit": "^7.5", + "phpunit/phpunit": "^7.5 || ^8 || ^9", "squizlabs/php_codesniffer": "^3.5" }, "suggest": { @@ -777,9 +775,9 @@ "homepage": "https://github.com/dompdf/dompdf", "support": { "issues": "https://github.com/dompdf/dompdf/issues", - "source": "https://github.com/dompdf/dompdf/tree/master" + "source": "https://github.com/dompdf/dompdf/tree/v1.0.2" }, - "time": "2020-08-30T22:54:22+00:00" + "time": "2021-01-08T14:18:52+00:00" }, { "name": "dragonmantank/cron-expression", @@ -915,16 +913,16 @@ }, { "name": "facade/flare-client-php", - "version": "1.3.7", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/facade/flare-client-php.git", - "reference": "fd688d3c06658f2b3b5f7bb19f051ee4ddf02492" + "reference": "ef0f5bce23b30b32d98fd9bb49c6fa37b40eb546" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/flare-client-php/zipball/fd688d3c06658f2b3b5f7bb19f051ee4ddf02492", - "reference": "fd688d3c06658f2b3b5f7bb19f051ee4ddf02492", + "url": "https://api.github.com/repos/facade/flare-client-php/zipball/ef0f5bce23b30b32d98fd9bb49c6fa37b40eb546", + "reference": "ef0f5bce23b30b32d98fd9bb49c6fa37b40eb546", "shasum": "" }, "require": { @@ -968,7 +966,7 @@ ], "support": { "issues": "https://github.com/facade/flare-client-php/issues", - "source": "https://github.com/facade/flare-client-php/tree/1.3.7" + "source": "https://github.com/facade/flare-client-php/tree/1.4.0" }, "funding": [ { @@ -976,20 +974,20 @@ "type": "github" } ], - "time": "2020-10-21T16:02:39+00:00" + "time": "2021-02-16T12:42:06+00:00" }, { "name": "facade/ignition", - "version": "1.16.4", + "version": "1.16.15", "source": { "type": "git", "url": "https://github.com/facade/ignition.git", - "reference": "1da1705e7f6b24ed45af05461463228da424e14f" + "reference": "b6aea4a99303d9d32afd486a285162a89af8a8a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/ignition/zipball/1da1705e7f6b24ed45af05461463228da424e14f", - "reference": "1da1705e7f6b24ed45af05461463228da424e14f", + "url": "https://api.github.com/repos/facade/ignition/zipball/b6aea4a99303d9d32afd486a285162a89af8a8a3", + "reference": "b6aea4a99303d9d32afd486a285162a89af8a8a3", "shasum": "" }, "require": { @@ -1052,29 +1050,29 @@ "issues": "https://github.com/facade/ignition/issues", "source": "https://github.com/facade/ignition" }, - "time": "2020-10-30T13:40:01+00:00" + "time": "2021-02-15T10:21:49+00:00" }, { "name": "facade/ignition-contracts", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/facade/ignition-contracts.git", - "reference": "aeab1ce8b68b188a43e81758e750151ad7da796b" + "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/ignition-contracts/zipball/aeab1ce8b68b188a43e81758e750151ad7da796b", - "reference": "aeab1ce8b68b188a43e81758e750151ad7da796b", + "url": "https://api.github.com/repos/facade/ignition-contracts/zipball/3c921a1cdba35b68a7f0ccffc6dffc1995b18267", + "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.3|^8.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.14", - "phpunit/phpunit": "^7.5|^8.0", - "vimeo/psalm": "^3.12" + "friendsofphp/php-cs-fixer": "^v2.15.8", + "phpunit/phpunit": "^9.3.11", + "vimeo/psalm": "^3.17.1" }, "type": "library", "autoload": { @@ -1103,9 +1101,9 @@ ], "support": { "issues": "https://github.com/facade/ignition-contracts/issues", - "source": "https://github.com/facade/ignition-contracts/tree/1.0.1" + "source": "https://github.com/facade/ignition-contracts/tree/1.0.2" }, - "time": "2020-07-14T10:10:28+00:00" + "time": "2020-10-16T08:27:54+00:00" }, { "name": "fideloper/proxy", @@ -1167,16 +1165,16 @@ }, { "name": "filp/whoops", - "version": "2.9.2", + "version": "2.11.0", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "df7933820090489623ce0be5e85c7e693638e536" + "reference": "f6e14679f948d8a5cfb866fa7065a30c66bd64d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/df7933820090489623ce0be5e85c7e693638e536", - "reference": "df7933820090489623ce0be5e85c7e693638e536", + "url": "https://api.github.com/repos/filp/whoops/zipball/f6e14679f948d8a5cfb866fa7065a30c66bd64d3", + "reference": "f6e14679f948d8a5cfb866fa7065a30c66bd64d3", "shasum": "" }, "require": { @@ -1226,7 +1224,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.9.2" + "source": "https://github.com/filp/whoops/tree/2.11.0" }, "funding": [ { @@ -1234,7 +1232,7 @@ "type": "github" } ], - "time": "2021-01-24T12:00:00+00:00" + "time": "2021-03-19T12:00:00+00:00" }, { "name": "guzzlehttp/guzzle", @@ -1340,16 +1338,16 @@ }, { "name": "guzzlehttp/promises", - "version": "1.4.0", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "60d379c243457e073cff02bc323a2a86cb355631" + "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/60d379c243457e073cff02bc323a2a86cb355631", - "reference": "60d379c243457e073cff02bc323a2a86cb355631", + "url": "https://api.github.com/repos/guzzle/promises/zipball/8e7d04f1f6450fef59366c399cfad4b9383aa30d", + "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d", "shasum": "" }, "require": { @@ -1389,9 +1387,9 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/1.4.0" + "source": "https://github.com/guzzle/promises/tree/1.4.1" }, - "time": "2020-09-30T07:37:28+00:00" + "time": "2021-03-07T09:25:29+00:00" }, { "name": "guzzlehttp/psr7", @@ -1542,104 +1540,6 @@ }, "time": "2019-11-02T09:15:47+00:00" }, - { - "name": "jakub-onderka/php-console-color", - "version": "v0.2", - "source": { - "type": "git", - "url": "https://github.com/JakubOnderka/PHP-Console-Color.git", - "reference": "d5deaecff52a0d61ccb613bb3804088da0307191" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/d5deaecff52a0d61ccb613bb3804088da0307191", - "reference": "d5deaecff52a0d61ccb613bb3804088da0307191", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "jakub-onderka/php-code-style": "1.0", - "jakub-onderka/php-parallel-lint": "1.0", - "jakub-onderka/php-var-dump-check": "0.*", - "phpunit/phpunit": "~4.3", - "squizlabs/php_codesniffer": "1.*" - }, - "type": "library", - "autoload": { - "psr-4": { - "JakubOnderka\\PhpConsoleColor\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-2-Clause" - ], - "authors": [ - { - "name": "Jakub Onderka", - "email": "jakub.onderka@gmail.com" - } - ], - "support": { - "issues": "https://github.com/JakubOnderka/PHP-Console-Color/issues", - "source": "https://github.com/JakubOnderka/PHP-Console-Color/tree/master" - }, - "abandoned": "php-parallel-lint/php-console-color", - "time": "2018-09-29T17:23:10+00:00" - }, - { - "name": "jakub-onderka/php-console-highlighter", - "version": "v0.4", - "source": { - "type": "git", - "url": "https://github.com/JakubOnderka/PHP-Console-Highlighter.git", - "reference": "9f7a229a69d52506914b4bc61bfdb199d90c5547" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Highlighter/zipball/9f7a229a69d52506914b4bc61bfdb199d90c5547", - "reference": "9f7a229a69d52506914b4bc61bfdb199d90c5547", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "jakub-onderka/php-console-color": "~0.2", - "php": ">=5.4.0" - }, - "require-dev": { - "jakub-onderka/php-code-style": "~1.0", - "jakub-onderka/php-parallel-lint": "~1.0", - "jakub-onderka/php-var-dump-check": "~0.1", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~1.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "JakubOnderka\\PhpConsoleHighlighter\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jakub Onderka", - "email": "acci@acci.cz", - "homepage": "http://www.acci.cz/" - } - ], - "description": "Highlight PHP code in terminal", - "support": { - "issues": "https://github.com/JakubOnderka/PHP-Console-Highlighter/issues", - "source": "https://github.com/JakubOnderka/PHP-Console-Highlighter/tree/master" - }, - "abandoned": "php-parallel-lint/php-console-highlighter", - "time": "2018-09-29T18:48:56+00:00" - }, { "name": "knplabs/knp-snappy", "version": "v1.2.1", @@ -1712,16 +1612,16 @@ }, { "name": "laravel/framework", - "version": "v6.20.15", + "version": "v6.20.19", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "b42c2d845cdd827ac5a53cacf16af4a0b5dd8be1" + "reference": "c25308a00c7bbd38401a6254ab403146da9cfd69" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/b42c2d845cdd827ac5a53cacf16af4a0b5dd8be1", - "reference": "b42c2d845cdd827ac5a53cacf16af4a0b5dd8be1", + "url": "https://api.github.com/repos/laravel/framework/zipball/c25308a00c7bbd38401a6254ab403146da9cfd69", + "reference": "c25308a00c7bbd38401a6254ab403146da9cfd69", "shasum": "" }, "require": { @@ -1861,20 +1761,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2021-01-26T14:39:47+00:00" + "time": "2021-03-16T14:18:55+00:00" }, { "name": "laravel/socialite", - "version": "v5.1.3", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/laravel/socialite.git", - "reference": "2e6beafe911a09f2300353c102d882e9d63f1f72" + "reference": "8d25d574b4f2005411c0b9cb527ef5e745c1b07d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/socialite/zipball/2e6beafe911a09f2300353c102d882e9d63f1f72", - "reference": "2e6beafe911a09f2300353c102d882e9d63f1f72", + "url": "https://api.github.com/repos/laravel/socialite/zipball/8d25d574b4f2005411c0b9cb527ef5e745c1b07d", + "reference": "8d25d574b4f2005411c0b9cb527ef5e745c1b07d", "shasum": "" }, "require": { @@ -1930,7 +1830,7 @@ "issues": "https://github.com/laravel/socialite/issues", "source": "https://github.com/laravel/socialite" }, - "time": "2021-01-05T17:02:09+00:00" + "time": "2021-03-02T16:50:47+00:00" }, { "name": "league/commonmark", @@ -2469,16 +2369,16 @@ }, { "name": "nesbot/carbon", - "version": "2.44.0", + "version": "2.46.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "e6ef33cb1f67a4bed831ed6d0f7e156739a5d8cd" + "reference": "2fd2c4a77d58a4e95234c8a61c5df1f157a91bf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/e6ef33cb1f67a4bed831ed6d0f7e156739a5d8cd", - "reference": "e6ef33cb1f67a4bed831ed6d0f7e156739a5d8cd", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/2fd2c4a77d58a4e95234c8a61c5df1f157a91bf4", + "reference": "2fd2c4a77d58a4e95234c8a61c5df1f157a91bf4", "shasum": "" }, "require": { @@ -2558,26 +2458,26 @@ "type": "tidelift" } ], - "time": "2021-01-26T20:46:41+00:00" + "time": "2021-02-24T17:30:44+00:00" }, { "name": "nunomaduro/collision", - "version": "v3.1.0", + "version": "v3.2.0", "source": { "type": "git", "url": "https://github.com/nunomaduro/collision.git", - "reference": "88b58b5bd9bdcc54756480fb3ce87234696544ee" + "reference": "f7c45764dfe4ba5f2618d265a6f1f9c72732e01d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/88b58b5bd9bdcc54756480fb3ce87234696544ee", - "reference": "88b58b5bd9bdcc54756480fb3ce87234696544ee", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/f7c45764dfe4ba5f2618d265a6f1f9c72732e01d", + "reference": "f7c45764dfe4ba5f2618d265a6f1f9c72732e01d", "shasum": "" }, "require": { "filp/whoops": "^2.1.4", - "jakub-onderka/php-console-highlighter": "0.3.*|0.4.*", - "php": "^7.1 || ^8.0", + "php": "^7.2.5 || ^8.0", + "php-parallel-lint/php-console-highlighter": "0.5.*", "symfony/console": "~2.8|~3.3|~4.0" }, "require-dev": { @@ -2638,38 +2538,39 @@ "type": "patreon" } ], - "time": "2020-10-29T16:05:21+00:00" + "time": "2021-02-11T09:01:42+00:00" }, { "name": "onelogin/php-saml", - "version": "3.5.1", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/onelogin/php-saml.git", - "reference": "593aca859b67d607923fe50d8ad7315373f5b6dd" + "reference": "f30f5062f3653c4d2082892d207f4dc3e577d979" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/onelogin/php-saml/zipball/593aca859b67d607923fe50d8ad7315373f5b6dd", - "reference": "593aca859b67d607923fe50d8ad7315373f5b6dd", + "url": "https://api.github.com/repos/onelogin/php-saml/zipball/f30f5062f3653c4d2082892d207f4dc3e577d979", + "reference": "f30f5062f3653c4d2082892d207f4dc3e577d979", "shasum": "" }, "require": { - "php": ">=5.4", + "php": ">=7.3", "robrichards/xmlseclibs": ">=3.1.1" }, "require-dev": { - "pdepend/pdepend": "^2.5.0", - "php-coveralls/php-coveralls": "^1.0.2 || ^2.0", - "phploc/phploc": "^2.1 || ^3.0 || ^4.0", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1", - "sebastian/phpcpd": "^2.0 || ^3.0 || ^4.0", - "squizlabs/php_codesniffer": "^3.1.1" + "pdepend/pdepend": "^2.8.0", + "php-coveralls/php-coveralls": "^2.0", + "phploc/phploc": "^4.0 || ^5.0 || ^6.0 || ^7.0", + "phpunit/phpunit": "^9.5", + "sebastian/phpcpd": "^4.0 || ^5.0 || ^6.0 ", + "squizlabs/php_codesniffer": "^3.5.8" }, "suggest": { "ext-curl": "Install curl lib to be able to use the IdPMetadataParser for parsing remote XMLs", - "ext-gettext": "Install gettext and php5-gettext libs to handle translations", - "ext-openssl": "Install openssl lib in order to handle with x509 certs (require to support sign and encryption)" + "ext-dom": "Install xml lib", + "ext-openssl": "Install openssl lib in order to handle with x509 certs (require to support sign and encryption)", + "ext-zlib": "Install zlib" }, "type": "library", "autoload": { @@ -2693,7 +2594,7 @@ "issues": "https://github.com/onelogin/php-saml/issues", "source": "https://github.com/onelogin/php-saml/" }, - "time": "2020-12-03T20:08:41+00:00" + "time": "2021-03-02T10:19:19+00:00" }, { "name": "opis/closure", @@ -2895,6 +2796,108 @@ }, "time": "2019-09-11T20:02:13+00:00" }, + { + "name": "php-parallel-lint/php-console-color", + "version": "v0.3", + "source": { + "type": "git", + "url": "https://github.com/php-parallel-lint/PHP-Console-Color.git", + "reference": "b6af326b2088f1ad3b264696c9fd590ec395b49e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-parallel-lint/PHP-Console-Color/zipball/b6af326b2088f1ad3b264696c9fd590ec395b49e", + "reference": "b6af326b2088f1ad3b264696c9fd590ec395b49e", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "replace": { + "jakub-onderka/php-console-color": "*" + }, + "require-dev": { + "php-parallel-lint/php-code-style": "1.0", + "php-parallel-lint/php-parallel-lint": "1.0", + "php-parallel-lint/php-var-dump-check": "0.*", + "phpunit/phpunit": "~4.3", + "squizlabs/php_codesniffer": "1.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "JakubOnderka\\PhpConsoleColor\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Jakub Onderka", + "email": "jakub.onderka@gmail.com" + } + ], + "support": { + "issues": "https://github.com/php-parallel-lint/PHP-Console-Color/issues", + "source": "https://github.com/php-parallel-lint/PHP-Console-Color/tree/master" + }, + "time": "2020-05-14T05:47:14+00:00" + }, + { + "name": "php-parallel-lint/php-console-highlighter", + "version": "v0.5", + "source": { + "type": "git", + "url": "https://github.com/php-parallel-lint/PHP-Console-Highlighter.git", + "reference": "21bf002f077b177f056d8cb455c5ed573adfdbb8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-parallel-lint/PHP-Console-Highlighter/zipball/21bf002f077b177f056d8cb455c5ed573adfdbb8", + "reference": "21bf002f077b177f056d8cb455c5ed573adfdbb8", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.4.0", + "php-parallel-lint/php-console-color": "~0.2" + }, + "replace": { + "jakub-onderka/php-console-highlighter": "*" + }, + "require-dev": { + "php-parallel-lint/php-code-style": "~1.0", + "php-parallel-lint/php-parallel-lint": "~1.0", + "php-parallel-lint/php-var-dump-check": "~0.1", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "JakubOnderka\\PhpConsoleHighlighter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jakub Onderka", + "email": "acci@acci.cz", + "homepage": "http://www.acci.cz/" + } + ], + "description": "Highlight PHP code in terminal", + "support": { + "issues": "https://github.com/php-parallel-lint/PHP-Console-Highlighter/issues", + "source": "https://github.com/php-parallel-lint/PHP-Console-Highlighter/tree/master" + }, + "time": "2020-05-13T07:37:49+00:00" + }, { "name": "phpoption/phpoption", "version": "1.7.5", @@ -3045,27 +3048,22 @@ }, { "name": "psr/container", - "version": "1.0.0", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=7.2.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, "autoload": { "psr-4": { "Psr\\Container\\": "src/" @@ -3078,7 +3076,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common Container Interface (PHP FIG PSR-11)", @@ -3092,9 +3090,9 @@ ], "support": { "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/master" + "source": "https://github.com/php-fig/container/tree/1.1.1" }, - "time": "2017-02-14T16:28:37+00:00" + "time": "2021-03-05T17:36:06+00:00" }, { "name": "psr/http-client", @@ -3798,16 +3796,16 @@ }, { "name": "socialiteproviders/okta", - "version": "4.1.0", + "version": "4.1.1", "source": { "type": "git", "url": "https://github.com/SocialiteProviders/Okta.git", - "reference": "60f88b8e8c88508889c61346af83290131b72fe7" + "reference": "e3ef9f23c7d2f86b3b16a174b82333cf4e2459e8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/SocialiteProviders/Okta/zipball/60f88b8e8c88508889c61346af83290131b72fe7", - "reference": "60f88b8e8c88508889c61346af83290131b72fe7", + "url": "https://api.github.com/repos/SocialiteProviders/Okta/zipball/e3ef9f23c7d2f86b3b16a174b82333cf4e2459e8", + "reference": "e3ef9f23c7d2f86b3b16a174b82333cf4e2459e8", "shasum": "" }, "require": { @@ -3833,9 +3831,9 @@ ], "description": "Okta OAuth2 Provider for Laravel Socialite", "support": { - "source": "https://github.com/SocialiteProviders/Okta/tree/4.1.0" + "source": "https://github.com/SocialiteProviders/Okta/tree/4.1.1" }, - "time": "2020-12-01T23:10:59+00:00" + "time": "2021-01-12T23:51:01+00:00" }, { "name": "socialiteproviders/slack", @@ -3973,20 +3971,20 @@ }, { "name": "swiftmailer/swiftmailer", - "version": "v6.2.5", + "version": "v6.2.7", "source": { "type": "git", "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "698a6a9f54d7eb321274de3ad19863802c879fb7" + "reference": "15f7faf8508e04471f666633addacf54c0ab5933" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/698a6a9f54d7eb321274de3ad19863802c879fb7", - "reference": "698a6a9f54d7eb321274de3ad19863802c879fb7", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/15f7faf8508e04471f666633addacf54c0ab5933", + "reference": "15f7faf8508e04471f666633addacf54c0ab5933", "shasum": "" }, "require": { - "egulias/email-validator": "^2.0", + "egulias/email-validator": "^2.0|^3.1", "php": ">=7.0.0", "symfony/polyfill-iconv": "^1.0", "symfony/polyfill-intl-idn": "^1.10", @@ -4032,7 +4030,7 @@ ], "support": { "issues": "https://github.com/swiftmailer/swiftmailer/issues", - "source": "https://github.com/swiftmailer/swiftmailer/tree/v6.2.5" + "source": "https://github.com/swiftmailer/swiftmailer/tree/v6.2.7" }, "funding": [ { @@ -4044,20 +4042,20 @@ "type": "tidelift" } ], - "time": "2021-01-12T09:35:59+00:00" + "time": "2021-03-09T12:30:35+00:00" }, { "name": "symfony/console", - "version": "v4.4.19", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "24026c44fc37099fa145707fecd43672831b837a" + "reference": "c98349bda966c70d6c08b4cd8658377c94166492" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/24026c44fc37099fa145707fecd43672831b837a", - "reference": "24026c44fc37099fa145707fecd43672831b837a", + "url": "https://api.github.com/repos/symfony/console/zipball/c98349bda966c70d6c08b4cd8658377c94166492", + "reference": "c98349bda966c70d6c08b4cd8658377c94166492", "shasum": "" }, "require": { @@ -4117,7 +4115,7 @@ "description": "Eases the creation of beautiful and testable command line interfaces", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/console/tree/v4.4.19" + "source": "https://github.com/symfony/console/tree/v4.4.20" }, "funding": [ { @@ -4133,11 +4131,11 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-02-22T18:44:15+00:00" }, { "name": "symfony/css-selector", - "version": "v4.4.19", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", @@ -4182,7 +4180,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v4.4.19" + "source": "https://github.com/symfony/css-selector/tree/v4.4.20" }, "funding": [ { @@ -4202,16 +4200,16 @@ }, { "name": "symfony/debug", - "version": "v4.4.19", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "af4987aa4a5630e9615be9d9c3ed1b0f24ca449c" + "reference": "157bbec4fd773bae53c5483c50951a5530a2cc16" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/af4987aa4a5630e9615be9d9c3ed1b0f24ca449c", - "reference": "af4987aa4a5630e9615be9d9c3ed1b0f24ca449c", + "url": "https://api.github.com/repos/symfony/debug/zipball/157bbec4fd773bae53c5483c50951a5530a2cc16", + "reference": "157bbec4fd773bae53c5483c50951a5530a2cc16", "shasum": "" }, "require": { @@ -4251,7 +4249,7 @@ "description": "Provides tools to ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/debug/tree/v4.4.19" + "source": "https://github.com/symfony/debug/tree/v4.4.20" }, "funding": [ { @@ -4267,7 +4265,7 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-01-28T16:54:48+00:00" }, { "name": "symfony/deprecation-contracts", @@ -4338,16 +4336,16 @@ }, { "name": "symfony/error-handler", - "version": "v4.4.19", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "d603654eaeb713503bba3e308b9e748e5a6d3f2e" + "reference": "a191550d46b73a527b9d244f185fef439d41cf15" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/d603654eaeb713503bba3e308b9e748e5a6d3f2e", - "reference": "d603654eaeb713503bba3e308b9e748e5a6d3f2e", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/a191550d46b73a527b9d244f185fef439d41cf15", + "reference": "a191550d46b73a527b9d244f185fef439d41cf15", "shasum": "" }, "require": { @@ -4387,7 +4385,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/v4.4.19" + "source": "https://github.com/symfony/error-handler/tree/v4.4.20" }, "funding": [ { @@ -4403,11 +4401,11 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-02-11T08:19:35+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v4.4.19", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", @@ -4470,7 +4468,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.19" + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.20" }, "funding": [ { @@ -4569,16 +4567,16 @@ }, { "name": "symfony/finder", - "version": "v4.4.19", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "25d79cfccfc12e84e7a63a248c3f0720fdd92db6" + "reference": "2543795ab1570df588b9bbd31e1a2bd7037b94f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/25d79cfccfc12e84e7a63a248c3f0720fdd92db6", - "reference": "25d79cfccfc12e84e7a63a248c3f0720fdd92db6", + "url": "https://api.github.com/repos/symfony/finder/zipball/2543795ab1570df588b9bbd31e1a2bd7037b94f6", + "reference": "2543795ab1570df588b9bbd31e1a2bd7037b94f6", "shasum": "" }, "require": { @@ -4610,7 +4608,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v4.4.19" + "source": "https://github.com/symfony/finder/tree/v4.4.20" }, "funding": [ { @@ -4626,7 +4624,7 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-02-12T10:48:09+00:00" }, { "name": "symfony/http-client-contracts", @@ -4709,16 +4707,16 @@ }, { "name": "symfony/http-foundation", - "version": "v4.4.19", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "8888741b633f6c3d1e572b7735ad2cae3e03f9c5" + "reference": "02d968647fe61b2f419a8dc70c468a9d30a48d3a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/8888741b633f6c3d1e572b7735ad2cae3e03f9c5", - "reference": "8888741b633f6c3d1e572b7735ad2cae3e03f9c5", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/02d968647fe61b2f419a8dc70c468a9d30a48d3a", + "reference": "02d968647fe61b2f419a8dc70c468a9d30a48d3a", "shasum": "" }, "require": { @@ -4757,7 +4755,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v4.4.19" + "source": "https://github.com/symfony/http-foundation/tree/v4.4.20" }, "funding": [ { @@ -4773,20 +4771,20 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-02-25T17:11:33+00:00" }, { "name": "symfony/http-kernel", - "version": "v4.4.19", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "07ea794a327d7c8c5d76e3058fde9fec6a711cb4" + "reference": "4f36548465489f293b05406f1770492f6efb8adb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/07ea794a327d7c8c5d76e3058fde9fec6a711cb4", - "reference": "07ea794a327d7c8c5d76e3058fde9fec6a711cb4", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/4f36548465489f293b05406f1770492f6efb8adb", + "reference": "4f36548465489f293b05406f1770492f6efb8adb", "shasum": "" }, "require": { @@ -4812,7 +4810,7 @@ "psr/log-implementation": "1.0" }, "require-dev": { - "psr/cache": "~1.0", + "psr/cache": "^1.0|^2.0|^3.0", "symfony/browser-kit": "^4.3|^5.0", "symfony/config": "^3.4|^4.0|^5.0", "symfony/console": "^3.4|^4.0", @@ -4861,7 +4859,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/v4.4.19" + "source": "https://github.com/symfony/http-kernel/tree/v4.4.20" }, "funding": [ { @@ -4877,20 +4875,20 @@ "type": "tidelift" } ], - "time": "2021-01-27T13:50:53+00:00" + "time": "2021-03-04T18:00:27+00:00" }, { "name": "symfony/mime", - "version": "v5.2.2", + "version": "v5.2.5", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "37bade585ea100d235c031b258eff93b5b6bb9a9" + "reference": "554ba128f1955038b45db5e1fa7e93bfc683b139" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/37bade585ea100d235c031b258eff93b5b6bb9a9", - "reference": "37bade585ea100d235c031b258eff93b5b6bb9a9", + "url": "https://api.github.com/repos/symfony/mime/zipball/554ba128f1955038b45db5e1fa7e93bfc683b139", + "reference": "554ba128f1955038b45db5e1fa7e93bfc683b139", "shasum": "" }, "require": { @@ -4901,12 +4899,13 @@ "symfony/polyfill-php80": "^1.15" }, "conflict": { + "egulias/email-validator": "~3.0.0", "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "symfony/mailer": "<4.4" }, "require-dev": { - "egulias/email-validator": "^2.1.10", + "egulias/email-validator": "^2.1.10|^3.1", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", "symfony/dependency-injection": "^4.4|^5.0", "symfony/property-access": "^4.4|^5.1", @@ -4943,7 +4942,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.2.2" + "source": "https://github.com/symfony/mime/tree/v5.2.5" }, "funding": [ { @@ -4959,11 +4958,11 @@ "type": "tidelift" } ], - "time": "2021-01-25T14:08:25+00:00" + "time": "2021-03-07T16:08:20+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -5022,7 +5021,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1" }, "funding": [ { @@ -5042,16 +5041,16 @@ }, { "name": "symfony/polyfill-iconv", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-iconv.git", - "reference": "b34bfb8c4c22650ac080d2662ae3502e5f2f4ae6" + "reference": "06fb361659649bcfd6a208a0f1fcaf4e827ad342" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/b34bfb8c4c22650ac080d2662ae3502e5f2f4ae6", - "reference": "b34bfb8c4c22650ac080d2662ae3502e5f2f4ae6", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/06fb361659649bcfd6a208a0f1fcaf4e827ad342", + "reference": "06fb361659649bcfd6a208a0f1fcaf4e827ad342", "shasum": "" }, "require": { @@ -5102,7 +5101,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-iconv/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-iconv/tree/v1.22.1" }, "funding": [ { @@ -5118,20 +5117,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-01-22T09:19:47+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "0eb8293dbbcd6ef6bf81404c9ce7d95bcdf34f44" + "reference": "2d63434d922daf7da8dd863e7907e67ee3031483" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/0eb8293dbbcd6ef6bf81404c9ce7d95bcdf34f44", - "reference": "0eb8293dbbcd6ef6bf81404c9ce7d95bcdf34f44", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/2d63434d922daf7da8dd863e7907e67ee3031483", + "reference": "2d63434d922daf7da8dd863e7907e67ee3031483", "shasum": "" }, "require": { @@ -5189,7 +5188,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.22.1" }, "funding": [ { @@ -5205,20 +5204,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-01-22T09:19:47+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "6e971c891537eb617a00bb07a43d182a6915faba" + "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/6e971c891537eb617a00bb07a43d182a6915faba", - "reference": "6e971c891537eb617a00bb07a43d182a6915faba", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/43a0283138253ed1d48d352ab6d0bdb3f809f248", + "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248", "shasum": "" }, "require": { @@ -5273,7 +5272,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.1" }, "funding": [ { @@ -5289,20 +5288,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T17:09:11+00:00" + "time": "2021-01-22T09:19:47+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "f377a3dd1fde44d37b9831d68dc8dea3ffd28e13" + "reference": "5232de97ee3b75b0360528dae24e73db49566ab1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/f377a3dd1fde44d37b9831d68dc8dea3ffd28e13", - "reference": "f377a3dd1fde44d37b9831d68dc8dea3ffd28e13", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/5232de97ee3b75b0360528dae24e73db49566ab1", + "reference": "5232de97ee3b75b0360528dae24e73db49566ab1", "shasum": "" }, "require": { @@ -5353,7 +5352,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.22.1" }, "funding": [ { @@ -5369,11 +5368,11 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-01-22T09:19:47+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", @@ -5429,7 +5428,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.1" }, "funding": [ { @@ -5449,7 +5448,7 @@ }, { "name": "symfony/polyfill-php73", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", @@ -5508,7 +5507,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.22.1" }, "funding": [ { @@ -5528,7 +5527,7 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", @@ -5591,7 +5590,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.1" }, "funding": [ { @@ -5611,7 +5610,7 @@ }, { "name": "symfony/process", - "version": "v4.4.19", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/process.git", @@ -5652,7 +5651,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v4.4.19" + "source": "https://github.com/symfony/process/tree/v4.4.20" }, "funding": [ { @@ -5672,16 +5671,16 @@ }, { "name": "symfony/routing", - "version": "v4.4.19", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "87529f6e305c7acb162840d1ea57922038072425" + "reference": "69919991c845b34626664ddc9b3aef9d09d2a5df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/87529f6e305c7acb162840d1ea57922038072425", - "reference": "87529f6e305c7acb162840d1ea57922038072425", + "url": "https://api.github.com/repos/symfony/routing/zipball/69919991c845b34626664ddc9b3aef9d09d2a5df", + "reference": "69919991c845b34626664ddc9b3aef9d09d2a5df", "shasum": "" }, "require": { @@ -5740,7 +5739,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v4.4.19" + "source": "https://github.com/symfony/routing/tree/v4.4.20" }, "funding": [ { @@ -5756,7 +5755,7 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-02-22T15:37:04+00:00" }, { "name": "symfony/service-contracts", @@ -5839,16 +5838,16 @@ }, { "name": "symfony/translation", - "version": "v4.4.19", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "e1d0c67167a553556d9f974b5fa79c2448df317a" + "reference": "2271b6d577018a7dea75a9162a08ac84f8234deb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/e1d0c67167a553556d9f974b5fa79c2448df317a", - "reference": "e1d0c67167a553556d9f974b5fa79c2448df317a", + "url": "https://api.github.com/repos/symfony/translation/zipball/2271b6d577018a7dea75a9162a08ac84f8234deb", + "reference": "2271b6d577018a7dea75a9162a08ac84f8234deb", "shasum": "" }, "require": { @@ -5863,7 +5862,7 @@ "symfony/yaml": "<3.4" }, "provide": { - "symfony/translation-implementation": "1.0" + "symfony/translation-implementation": "1.0|2.0" }, "require-dev": { "psr/log": "~1.0", @@ -5907,7 +5906,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v4.4.19" + "source": "https://github.com/symfony/translation/tree/v4.4.20" }, "funding": [ { @@ -5923,7 +5922,7 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-02-26T13:53:48+00:00" }, { "name": "symfony/translation-contracts", @@ -6005,7 +6004,7 @@ }, { "name": "symfony/var-dumper", - "version": "v4.4.19", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", @@ -6074,7 +6073,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v4.4.19" + "source": "https://github.com/symfony/var-dumper/tree/v4.4.20" }, "funding": [ { @@ -6521,16 +6520,16 @@ }, { "name": "composer/composer", - "version": "2.0.9", + "version": "2.0.11", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "591c2c155cac0d2d7f34af41d3b1e29bcbfc685e" + "reference": "a5a5632da0b1c2d6fa9a3b65f1f4e90d1f04abb9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/591c2c155cac0d2d7f34af41d3b1e29bcbfc685e", - "reference": "591c2c155cac0d2d7f34af41d3b1e29bcbfc685e", + "url": "https://api.github.com/repos/composer/composer/zipball/a5a5632da0b1c2d6fa9a3b65f1f4e90d1f04abb9", + "reference": "a5a5632da0b1c2d6fa9a3b65f1f4e90d1f04abb9", "shasum": "" }, "require": { @@ -6598,7 +6597,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/composer/issues", - "source": "https://github.com/composer/composer/tree/2.0.9" + "source": "https://github.com/composer/composer/tree/2.0.11" }, "funding": [ { @@ -6614,7 +6613,7 @@ "type": "tidelift" } ], - "time": "2021-01-27T15:09:27+00:00" + "time": "2021-02-24T13:57:23+00:00" }, { "name": "composer/semver", @@ -7213,30 +7212,33 @@ }, { "name": "mockery/mockery", - "version": "1.3.3", + "version": "1.4.3", "source": { "type": "git", "url": "https://github.com/mockery/mockery.git", - "reference": "60fa2f67f6e4d3634bb4a45ff3171fa52215800d" + "reference": "d1339f64479af1bee0e82a0413813fe5345a54ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/60fa2f67f6e4d3634bb4a45ff3171fa52215800d", - "reference": "60fa2f67f6e4d3634bb4a45ff3171fa52215800d", + "url": "https://api.github.com/repos/mockery/mockery/zipball/d1339f64479af1bee0e82a0413813fe5345a54ea", + "reference": "d1339f64479af1bee0e82a0413813fe5345a54ea", "shasum": "" }, "require": { "hamcrest/hamcrest-php": "^2.0.1", "lib-pcre": ">=7.0", - "php": ">=5.6.0" + "php": "^7.3 || ^8.0" + }, + "conflict": { + "phpunit/phpunit": "<8.0" }, "require-dev": { - "phpunit/phpunit": "^5.7.10|^6.5|^7.5|^8.5|^9.3" + "phpunit/phpunit": "^8.5 || ^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "1.4.x-dev" } }, "autoload": { @@ -7276,9 +7278,9 @@ ], "support": { "issues": "https://github.com/mockery/mockery/issues", - "source": "https://github.com/mockery/mockery/tree/1.3.3" + "source": "https://github.com/mockery/mockery/tree/1.4.3" }, - "time": "2020-08-11T18:10:21+00:00" + "time": "2021-02-24T09:51:49+00:00" }, { "name": "myclabs/deep-copy", @@ -7338,6 +7340,62 @@ ], "time": "2020-11-13T09:40:50+00:00" }, + { + "name": "nikic/php-parser", + "version": "v4.10.4", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c6d052fc58cb876152f89f532b95a8d7907e7f0e", + "reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.10.4" + }, + "time": "2020-12-20T10:01:03+00:00" + }, { "name": "phar-io/manifest", "version": "2.0.1", @@ -7400,16 +7458,16 @@ }, { "name": "phar-io/version", - "version": "3.0.4", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "e4782611070e50613683d2b9a57730e9a3ba5451" + "reference": "bae7c545bef187884426f042434e561ab1ddb182" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/e4782611070e50613683d2b9a57730e9a3ba5451", - "reference": "e4782611070e50613683d2b9a57730e9a3ba5451", + "url": "https://api.github.com/repos/phar-io/version/zipball/bae7c545bef187884426f042434e561ab1ddb182", + "reference": "bae7c545bef187884426f042434e561ab1ddb182", "shasum": "" }, "require": { @@ -7445,9 +7503,9 @@ "description": "Library for handling version information and constraints", "support": { "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.0.4" + "source": "https://github.com/phar-io/version/tree/3.1.0" }, - "time": "2020-12-13T23:18:30+00:00" + "time": "2021-02-23T14:00:09+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -7609,16 +7667,16 @@ }, { "name": "phpspec/prophecy", - "version": "1.12.2", + "version": "1.13.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "245710e971a030f42e08f4912863805570f23d39" + "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/245710e971a030f42e08f4912863805570f23d39", - "reference": "245710e971a030f42e08f4912863805570f23d39", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/be1996ed8adc35c3fd795488a653f4b518be70ea", + "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea", "shasum": "" }, "require": { @@ -7670,46 +7728,50 @@ ], "support": { "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/1.12.2" + "source": "https://github.com/phpspec/prophecy/tree/1.13.0" }, - "time": "2020-12-19T10:15:11+00:00" + "time": "2021-03-17T13:42:18+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "7.0.14", + "version": "9.2.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "bb7c9a210c72e4709cdde67f8b7362f672f2225c" + "reference": "f3e026641cc91909d421802dd3ac7827ebfd97e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/bb7c9a210c72e4709cdde67f8b7362f672f2225c", - "reference": "bb7c9a210c72e4709cdde67f8b7362f672f2225c", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f3e026641cc91909d421802dd3ac7827ebfd97e1", + "reference": "f3e026641cc91909d421802dd3ac7827ebfd97e1", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-xmlwriter": "*", - "php": ">=7.2", - "phpunit/php-file-iterator": "^2.0.2", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^3.1.1 || ^4.0", - "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^4.2.2", - "sebastian/version": "^2.0.1", - "theseer/tokenizer": "^1.1.3" + "nikic/php-parser": "^4.10.2", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" }, "require-dev": { - "phpunit/phpunit": "^8.2.2" + "phpunit/phpunit": "^9.3" }, "suggest": { - "ext-xdebug": "^2.7.2" + "ext-pcov": "*", + "ext-xdebug": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "7.0-dev" + "dev-master": "9.2-dev" } }, "autoload": { @@ -7737,7 +7799,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/7.0.14" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.5" }, "funding": [ { @@ -7745,32 +7807,32 @@ "type": "github" } ], - "time": "2020-12-02T13:39:03+00:00" + "time": "2020-11-28T06:44:49+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "2.0.3", + "version": "3.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "4b49fb70f067272b659ef0174ff9ca40fdaa6357" + "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/4b49fb70f067272b659ef0174ff9ca40fdaa6357", - "reference": "4b49fb70f067272b659ef0174ff9ca40fdaa6357", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/aa4be8575f26070b100fccb67faabb28f21f66f8", + "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^8.5" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -7797,7 +7859,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/2.0.3" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.5" }, "funding": [ { @@ -7805,26 +7867,97 @@ "type": "github" } ], - "time": "2020-11-30T08:25:21+00:00" + "time": "2020-09-28T05:57:25+00:00" }, { - "name": "phpunit/php-text-template", - "version": "1.2.1", + "name": "phpunit/php-invoker", + "version": "3.1.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, "autoload": { "classmap": [ "src/" @@ -7848,34 +7981,40 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1" + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" }, - "time": "2015-06-21T13:50:34+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" }, { "name": "phpunit/php-timer", - "version": "2.1.3", + "version": "5.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662" + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/2454ae1765516d20c4ffe103d85a58a9a3bd5662", - "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^8.5" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -7901,7 +8040,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/2.1.3" + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" }, "funding": [ { @@ -7909,80 +8048,20 @@ "type": "github" } ], - "time": "2020-11-30T08:20:02+00:00" - }, - { - "name": "phpunit/php-token-stream", - "version": "3.1.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "472b687829041c24b25f475e14c2f38a09edf1c2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/472b687829041c24b25f475e14c2f38a09edf1c2", - "reference": "472b687829041c24b25f475e14c2f38a09edf1c2", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", - "source": "https://github.com/sebastianbergmann/php-token-stream/tree/3.1.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "abandoned": true, - "time": "2020-11-30T08:38:46+00:00" + "time": "2020-10-26T13:16:10+00:00" }, { "name": "phpunit/phpunit", - "version": "8.5.14", + "version": "9.5.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "c25f79895d27b6ecd5abfa63de1606b786a461a3" + "reference": "27241ac75fc37ecf862b6e002bf713b6566cbe41" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c25f79895d27b6ecd5abfa63de1606b786a461a3", - "reference": "c25f79895d27b6ecd5abfa63de1606b786a461a3", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/27241ac75fc37ecf862b6e002bf713b6566cbe41", + "reference": "27241ac75fc37ecf862b6e002bf713b6566cbe41", "shasum": "" }, "require": { @@ -7993,32 +8072,35 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.0", + "myclabs/deep-copy": "^1.10.1", "phar-io/manifest": "^2.0.1", "phar-io/version": "^3.0.2", - "php": ">=7.2", - "phpspec/prophecy": "^1.10.3", - "phpunit/php-code-coverage": "^7.0.12", - "phpunit/php-file-iterator": "^2.0.2", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^2.1.2", - "sebastian/comparator": "^3.0.2", - "sebastian/diff": "^3.0.2", - "sebastian/environment": "^4.2.3", - "sebastian/exporter": "^3.1.2", - "sebastian/global-state": "^3.0.0", - "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^2.0.1", - "sebastian/type": "^1.1.3", - "sebastian/version": "^2.0.1" + "php": ">=7.3", + "phpspec/prophecy": "^1.12.1", + "phpunit/php-code-coverage": "^9.2.3", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.5", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.3", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^2.3", + "sebastian/version": "^3.0.2" }, "require-dev": { - "ext-pdo": "*" + "ext-pdo": "*", + "phpspec/prophecy-phpunit": "^2.0.1" }, "suggest": { "ext-soap": "*", - "ext-xdebug": "*", - "phpunit/php-invoker": "^2.0.0" + "ext-xdebug": "*" }, "bin": [ "phpunit" @@ -8026,12 +8108,15 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "8.5-dev" + "dev-master": "9.5-dev" } }, "autoload": { "classmap": [ "src/" + ], + "files": [ + "src/Framework/Assert/Functions.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -8054,7 +8139,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/8.5.14" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.3" }, "funding": [ { @@ -8066,7 +8151,7 @@ "type": "github" } ], - "time": "2021-01-17T07:37:30+00:00" + "time": "2021-03-17T07:30:34+00:00" }, { "name": "react/promise", @@ -8119,29 +8204,141 @@ "time": "2020-05-12T15:16:56+00:00" }, { - "name": "sebastian/code-unit-reverse-lookup", - "version": "1.0.2", + "name": "sebastian/cli-parser", + "version": "1.0.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619" + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/1de8cd5c010cb153fcd68b8d0f64606f523f7619", - "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", "shasum": "" }, "require": { - "php": ">=5.6" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^8.5" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" } }, "autoload": { @@ -8163,7 +8360,7 @@ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "support": { "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2" + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" }, "funding": [ { @@ -8171,34 +8368,34 @@ "type": "github" } ], - "time": "2020-11-30T08:15:22+00:00" + "time": "2020-09-28T05:30:19+00:00" }, { "name": "sebastian/comparator", - "version": "3.0.3", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "1071dfcef776a57013124ff35e1fc41ccd294758" + "reference": "55f4261989e546dc112258c7a75935a81a7ce382" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1071dfcef776a57013124ff35e1fc41ccd294758", - "reference": "1071dfcef776a57013124ff35e1fc41ccd294758", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382", + "reference": "55f4261989e546dc112258c7a75935a81a7ce382", "shasum": "" }, "require": { - "php": ">=7.1", - "sebastian/diff": "^3.0", - "sebastian/exporter": "^3.1" + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^8.5" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -8237,7 +8434,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6" }, "funding": [ { @@ -8245,33 +8442,90 @@ "type": "github" } ], - "time": "2020-11-30T08:04:30+00:00" + "time": "2020-10-26T15:49:45+00:00" }, { - "name": "sebastian/diff", - "version": "3.0.3", + "name": "sebastian/complexity", + "version": "2.0.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211" + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/14f72dd46eaf2f2293cbe79c93cc0bc43161a211", - "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", "shasum": "" }, "require": { - "php": ">=7.1" + "nikic/php-parser": "^4.7", + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^7.5 || ^8.0", - "symfony/process": "^2 || ^3.3 || ^4" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:52:27+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" } }, "autoload": { @@ -8303,7 +8557,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" }, "funding": [ { @@ -8311,27 +8565,27 @@ "type": "github" } ], - "time": "2020-11-30T07:59:04+00:00" + "time": "2020-10-26T13:10:38+00:00" }, { "name": "sebastian/environment", - "version": "4.2.4", + "version": "5.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0" + "reference": "388b6ced16caa751030f6a69e588299fa09200ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/d47bbbad83711771f167c72d4e3f25f7fcc1f8b0", - "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac", + "reference": "388b6ced16caa751030f6a69e588299fa09200ac", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^7.5" + "phpunit/phpunit": "^9.3" }, "suggest": { "ext-posix": "*" @@ -8339,7 +8593,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "5.1-dev" } }, "autoload": { @@ -8366,7 +8620,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/4.2.4" + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.3" }, "funding": [ { @@ -8374,34 +8628,34 @@ "type": "github" } ], - "time": "2020-11-30T07:53:42+00:00" + "time": "2020-09-28T05:52:38+00:00" }, { "name": "sebastian/exporter", - "version": "3.1.3", + "version": "4.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "6b853149eab67d4da22291d36f5b0631c0fd856e" + "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/6b853149eab67d4da22291d36f5b0631c0fd856e", - "reference": "6b853149eab67d4da22291d36f5b0631c0fd856e", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/d89cc98761b8cb5a1a235a6b703ae50d34080e65", + "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65", "shasum": "" }, "require": { - "php": ">=7.0", - "sebastian/recursion-context": "^3.0" + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" }, "require-dev": { "ext-mbstring": "*", - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -8443,7 +8697,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/3.1.3" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.3" }, "funding": [ { @@ -8451,30 +8705,30 @@ "type": "github" } ], - "time": "2020-11-30T07:47:53+00:00" + "time": "2020-09-28T05:24:23+00:00" }, { "name": "sebastian/global-state", - "version": "3.0.1", + "version": "5.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "474fb9edb7ab891665d3bfc6317f42a0a150454b" + "reference": "a90ccbddffa067b51f574dea6eb25d5680839455" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/474fb9edb7ab891665d3bfc6317f42a0a150454b", - "reference": "474fb9edb7ab891665d3bfc6317f42a0a150454b", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/a90ccbddffa067b51f574dea6eb25d5680839455", + "reference": "a90ccbddffa067b51f574dea6eb25d5680839455", "shasum": "" }, "require": { - "php": ">=7.2", - "sebastian/object-reflector": "^1.1.1", - "sebastian/recursion-context": "^3.0" + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^8.0" + "phpunit/phpunit": "^9.3" }, "suggest": { "ext-uopz": "*" @@ -8482,7 +8736,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -8507,7 +8761,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/3.0.1" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.2" }, "funding": [ { @@ -8515,34 +8769,91 @@ "type": "github" } ], - "time": "2020-11-30T07:43:24+00:00" + "time": "2020-10-26T15:55:19+00:00" }, { - "name": "sebastian/object-enumerator", - "version": "3.0.4", + "name": "sebastian/lines-of-code", + "version": "1.0.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2" + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", - "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", "shasum": "" }, "require": { - "php": ">=7.0", - "sebastian/object-reflector": "^1.1.1", - "sebastian/recursion-context": "^3.0" + "nikic/php-parser": "^4.6", + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-28T06:42:11+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" } }, "autoload": { @@ -8564,7 +8875,7 @@ "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "support": { "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/3.0.4" + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" }, "funding": [ { @@ -8572,32 +8883,32 @@ "type": "github" } ], - "time": "2020-11-30T07:40:27+00:00" + "time": "2020-10-26T13:12:34+00:00" }, { "name": "sebastian/object-reflector", - "version": "1.1.2", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d" + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", - "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", "shasum": "" }, "require": { - "php": ">=7.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -8619,7 +8930,7 @@ "homepage": "https://github.com/sebastianbergmann/object-reflector/", "support": { "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/1.1.2" + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" }, "funding": [ { @@ -8627,32 +8938,32 @@ "type": "github" } ], - "time": "2020-11-30T07:37:18+00:00" + "time": "2020-10-26T13:14:26+00:00" }, { "name": "sebastian/recursion-context", - "version": "3.0.1", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb" + "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/367dcba38d6e1977be014dc4b22f47a484dac7fb", - "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172", + "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172", "shasum": "" }, "require": { - "php": ">=7.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -8682,7 +8993,7 @@ "homepage": "http://www.github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/3.0.1" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4" }, "funding": [ { @@ -8690,29 +9001,32 @@ "type": "github" } ], - "time": "2020-11-30T07:34:24+00:00" + "time": "2020-10-26T13:17:30+00:00" }, { "name": "sebastian/resource-operations", - "version": "2.0.2", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3" + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/31d35ca87926450c44eae7e2611d45a7a65ea8b3", - "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -8734,7 +9048,7 @@ "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/2.0.2" + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" }, "funding": [ { @@ -8742,32 +9056,32 @@ "type": "github" } ], - "time": "2020-11-30T07:30:19+00:00" + "time": "2020-09-28T06:45:17+00:00" }, { "name": "sebastian/type", - "version": "1.1.4", + "version": "2.3.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "0150cfbc4495ed2df3872fb31b26781e4e077eb4" + "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/0150cfbc4495ed2df3872fb31b26781e4e077eb4", - "reference": "0150cfbc4495ed2df3872fb31b26781e4e077eb4", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/81cd61ab7bbf2de744aba0ea61fae32f721df3d2", + "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2", "shasum": "" }, "require": { - "php": ">=7.2" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^8.2" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "2.3-dev" } }, "autoload": { @@ -8790,7 +9104,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/1.1.4" + "source": "https://github.com/sebastianbergmann/type/tree/2.3.1" }, "funding": [ { @@ -8798,29 +9112,29 @@ "type": "github" } ], - "time": "2020-11-30T07:25:11+00:00" + "time": "2020-10-26T13:18:59+00:00" }, { "name": "sebastian/version", - "version": "2.0.1", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + "reference": "c6c1022351a901512170118436c764e473f6de8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", "shasum": "" }, "require": { - "php": ">=5.6" + "php": ">=7.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -8843,9 +9157,15 @@ "homepage": "https://github.com/sebastianbergmann/version", "support": { "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/master" + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" }, - "time": "2016-10-03T07:35:21+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" }, { "name": "seld/jsonlint", @@ -9016,16 +9336,16 @@ }, { "name": "symfony/dom-crawler", - "version": "v4.4.19", + "version": "v4.4.20", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "21032c566558255e551d23f4a516434c9e3a9a78" + "reference": "be133557f1b0e6672367325b508e65da5513a311" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/21032c566558255e551d23f4a516434c9e3a9a78", - "reference": "21032c566558255e551d23f4a516434c9e3a9a78", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/be133557f1b0e6672367325b508e65da5513a311", + "reference": "be133557f1b0e6672367325b508e65da5513a311", "shasum": "" }, "require": { @@ -9069,7 +9389,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v4.4.19" + "source": "https://github.com/symfony/dom-crawler/tree/v4.4.20" }, "funding": [ { @@ -9085,20 +9405,20 @@ "type": "tidelift" } ], - "time": "2021-01-27T09:09:26+00:00" + "time": "2021-02-14T12:29:41+00:00" }, { "name": "symfony/filesystem", - "version": "v5.2.2", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "262d033b57c73e8b59cd6e68a45c528318b15038" + "reference": "710d364200997a5afde34d9fe57bd52f3cc1e108" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/262d033b57c73e8b59cd6e68a45c528318b15038", - "reference": "262d033b57c73e8b59cd6e68a45c528318b15038", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/710d364200997a5afde34d9fe57bd52f3cc1e108", + "reference": "710d364200997a5afde34d9fe57bd52f3cc1e108", "shasum": "" }, "require": { @@ -9131,7 +9451,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.2.2" + "source": "https://github.com/symfony/filesystem/tree/v5.2.4" }, "funding": [ { @@ -9147,7 +9467,7 @@ "type": "tidelift" } ], - "time": "2021-01-27T10:01:46+00:00" + "time": "2021-02-12T10:38:38+00:00" }, { "name": "theseer/tokenizer", @@ -9201,30 +9521,35 @@ }, { "name": "webmozart/assert", - "version": "1.9.1", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", - "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0 || ^8.0", + "php": "^7.2 || ^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<3.9.1" + "vimeo/psalm": "<4.6.1 || 4.6.2" }, "require-dev": { - "phpunit/phpunit": "^4.8.36 || ^7.5.13" + "phpunit/phpunit": "^8.5.13" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, "autoload": { "psr-4": { "Webmozart\\Assert\\": "src/" @@ -9248,9 +9573,9 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.9.1" + "source": "https://github.com/webmozarts/assert/tree/1.10.0" }, - "time": "2020-07-08T17:02:28+00:00" + "time": "2021-03-09T10:59:23+00:00" } ], "aliases": [], @@ -9259,7 +9584,7 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": "^7.2.5", + "php": "^7.3|^8.0", "ext-curl": "*", "ext-dom": "*", "ext-gd": "*", @@ -9269,7 +9594,7 @@ }, "platform-dev": [], "platform-overrides": { - "php": "7.2.5" + "php": "7.3.0" }, "plugin-api-version": "2.0.0" } diff --git a/database/factories/ModelFactory.php b/database/factories/ModelFactory.php index 405e5fcf4..722f68a7c 100644 --- a/database/factories/ModelFactory.php +++ b/database/factories/ModelFactory.php @@ -12,9 +12,11 @@ */ $factory->define(\BookStack\Auth\User::class, function ($faker) { + $name = $faker->name; return [ - 'name' => $faker->name, + 'name' => $name, 'email' => $faker->email, + 'slug' => \Illuminate\Support\Str::slug($name . '-' . \Illuminate\Support\Str::random(5)), 'password' => Str::random(10), 'remember_token' => Str::random(10), 'email_confirmed' => 1 diff --git a/database/migrations/2021_03_08_215138_add_user_slug.php b/database/migrations/2021_03_08_215138_add_user_slug.php new file mode 100644 index 000000000..906e06b95 --- /dev/null +++ b/database/migrations/2021_03_08_215138_add_user_slug.php @@ -0,0 +1,50 @@ +string('slug', 250); + }); + + $slugMap = []; + DB::table('users')->cursor()->each(function ($user) use (&$slugMap) { + $userSlug = Str::slug($user->name); + while (isset($slugMap[$userSlug])) { + $userSlug = Str::slug($user->name . Str::random(4)); + } + $slugMap[$userSlug] = true; + + DB::table('users') + ->where('id', $user->id) + ->update(['slug' => $userSlug]); + }); + + Schema::table('users', function (Blueprint $table) { + $table->unique('slug'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('slug'); + }); + } +} diff --git a/dev/docker/Dockerfile b/dev/docker/Dockerfile index 8816615cf..b55ec9e0a 100644 --- a/dev/docker/Dockerfile +++ b/dev/docker/Dockerfile @@ -1,12 +1,12 @@ -FROM php:7.3-apache +FROM php:7.4-apache ENV APACHE_DOCUMENT_ROOT /app/public WORKDIR /app RUN apt-get update -y \ - && apt-get install -y git zip unzip libtidy-dev libpng-dev libldap2-dev libxml++2.6-dev wait-for-it \ + && apt-get install -y git zip unzip libpng-dev libldap2-dev wait-for-it \ && docker-php-ext-configure ldap --with-libdir=lib/x86_64-linux-gnu \ - && docker-php-ext-install pdo pdo_mysql tidy dom xml mbstring gd ldap \ + && docker-php-ext-install pdo_mysql gd ldap \ && a2enmod rewrite \ && sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf \ && sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf \ diff --git a/dev/docs/logical-theme-system.md b/dev/docs/logical-theme-system.md new file mode 100644 index 000000000..fc8e6646f --- /dev/null +++ b/dev/docs/logical-theme-system.md @@ -0,0 +1,98 @@ +# Logical Theme System + +BookStack allows logical customization via the theme system which enables you to add, or extend, functionality within the PHP side of the system without needing to alter the core application files. + +WARNING: This system is currently in alpha so may incur changes. Once we've gathered some feedback on usage we'll look to removing this warning. This system will be considered semi-stable in the future. The `Theme::` system will be kept maintained but specific customizations or deeper app/framework usage using this system will not be supported nor considered in any way stable. Customizations using this system should be checked after updates. + +## Getting Started + +This makes use of the theme system. Create a folder for your theme within your BookStack `themes` directory. As an example we'll use `my_theme`, so we'd create a `themes/my_theme` folder. +You'll need to tell BookStack to use your theme via the `APP_THEME` option in your `.env` file. For example: `APP_THEME=my_theme`. + +Within your theme folder create a `functions.php` file. BookStack will look for this and run it during app boot-up. Within this file you can use the `Theme` facade API, described below, to hook into certain app events. + +## `Theme` Facade API + +Below details the public methods of the `Theme` facade that are considered stable: + +### `Theme::listen` + +This method listens to a system event and runs the given action when that event occurs. The arguments passed to the action depend on the event. Event names are exposed as static properties on the `\BookStack\Theming\ThemeEvents` class. + +It is possible to listen to a single event using multiple actions. When dispatched, BookStack will loop over and run each action for that event. +If an action returns a non-null value then BookStack will stop cycling through actions at that point and make use of the non-null return value if possible (Depending on the event). + +**Arguments** +- string $event +- callable $action + +**Example** + +```php +Theme::listen( + \BookStack\Theming\ThemeEvents::AUTH_LOGIN, + function($service, $user) { + \Log::info("Login by {$user->name} via {$service}"); + } +); +``` + +### `Theme::addSocialDriver` + +This method allows you to register a custom social authentication driver within the system. This is primarily intended to use with [Socialite Providers](https://socialiteproviders.com/). + +**Arguments** +- string $driverName +- array $config +- string $socialiteHandler + +**Example** + +*See "Custom Socialite Service Example" below.* + +## Available Events + +All available events dispatched by BookStack are exposed as static properties on the `\BookStack\Theming\ThemeEvents` class, which can be found within the file `app/Theming/ThemeEvents.php` relative to your root BookStack folder. Alternatively, the events for the latest release can be [seen on GitHub here](https://github.com/BookStackApp/BookStack/blob/release/app/Theming/ThemeEvents.php). + +The comments above each constant with the `ThemeEvents.php` file describe the dispatch conditions of the event, in addition to the arguments the action will receive. The comments may also describe any ways the return value of the action may be used. + +## Example `functions.php` file + +```php +name}"); +}); + +// Adds a `/info` public URL endpoint that emits php debug details +Theme::listen(ThemeEvents::APP_BOOT, function($app) { + \Route::get('info', function() { + phpinfo(); // Don't do this on a production instance! + }); +}); +``` + +## Custom Socialite Service Example + +The below shows an example of adding a custom reddit socialite service to BookStack. +BookStack exposes a helper function for this via `Theme::addSocialDriver` which sets the required config and event listeners in the platform. + +The require statements reference composer installed dependencies within the theme folder. They are required manually since they are not auto-loaded like other app files due to being outside the main BookStack dependency list. + +```php +require "vendor/socialiteproviders/reddit/Provider.php"; +require "vendor/socialiteproviders/reddit/RedditExtendSocialite.php"; + +Theme::listen(ThemeEvents::APP_BOOT, function($app) { + Theme::addSocialDriver('reddit', [ + 'client_id' => 'abc123', + 'client_secret' => 'def456789', + 'name' => 'Reddit', + ], '\SocialiteProviders\Reddit\RedditExtendSocialite@handle'); +}); +``` \ No newline at end of file diff --git a/dev/docs/visual-theme-system.md b/dev/docs/visual-theme-system.md new file mode 100644 index 000000000..058bd2823 --- /dev/null +++ b/dev/docs/visual-theme-system.md @@ -0,0 +1,31 @@ +# Visual Theme System + +BookStack allows visual customization via the theme system which enables you to extensively customize views, translation text & icons. + +This theme system itself is maintained and supported but usages of this system, including the files you are able to override, are not considered stable and may change upon any update. You should test any customizations made after updates. + +## Getting Started + +This makes use of the theme system. Create a folder for your theme within your BookStack `themes` directory. As an example we'll use `my_theme`, so we'd create a `themes/my_theme` folder. +You'll need to tell BookStack to use your theme via the `APP_THEME` option in your `.env` file. For example: `APP_THEME=my_theme`. + +## Customizing View Files + +Content placed in your `themes//` folder will override the original view files found in the `resources/views` folder. These files are typically [Laravel Blade](https://laravel.com/docs/6.x/blade) files. + +## Customizing Icons + +SVG files placed in a `themes//icons` folder will override any icons of the same name within `resources/icons`. You'd typically want to follow the format convention of the existing icons, where no XML deceleration is included and no width & height attributes are set, to ensure optimal compatibility. + +## Customizing Text Content + +Folders with PHP translation files placed in a `themes//lang` folder will override translations defined within the `resources/lang` folder. Custom translations are merged with the original files so you only need to override the select translations you want to override, you don't need to copy the whole original file. Note that you'll need to include the language folder. + +As an example, Say I wanted to change 'Search' to 'Find'; Within a `themes//lang/en/common.php` file I'd set the following: + +```php + 'find', +]; +``` \ No newline at end of file diff --git a/phpcs.xml b/phpcs.xml index ccde28033..8d5157d9e 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -1,9 +1,12 @@ - + + The coding standard for BookStack. - app + + ./app */migrations/* */tests/* + \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml index 3bcedfb42..75c89ec33 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,5 +1,7 @@ - - - - ./tests/ - - - - - app/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + app/ + + + + + ./tests/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/readme.md b/readme.md index d4cccf0d6..a039b108c 100644 --- a/readme.md +++ b/readme.md @@ -4,7 +4,8 @@ [![license](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/BookStackApp/BookStack/blob/master/LICENSE) [![Crowdin](https://badges.crowdin.net/bookstack/localized.svg)](https://crowdin.com/project/bookstack) [![Build Status](https://github.com/BookStackApp/BookStack/workflows/phpunit/badge.svg)](https://github.com/BookStackApp/BookStack/actions) -[![Discord](https://img.shields.io/static/v1?label=Chat&message=Discord&color=738adb&logo=discord)](https://discord.gg/ztkBqR2) +[![Discord](https://img.shields.io/static/v1?label=chat&message=discord&color=738adb&logo=discord)](https://discord.gg/ztkBqR2) +[![Repo Stats](https://img.shields.io/static/v1?label=GitHub+project&message=stats&color=f27e3f)](https://gh-stats.bookstackapp.com/) A platform for storing and organising information and documentation. Details for BookStack can be found on the official website at https://www.bookstackapp.com/. @@ -133,7 +134,7 @@ Feel free to create issues to request new features or to report bugs & problems. Pull requests are welcome. Unless a small tweak or language update, It may be best to open the pull request early or create an issue for your intended change to discuss how it will fit in to the project and plan out the merge. Just because a feature request exists, or is tagged, does not mean that feature would be accepted into the core project. -Pull requests should be created from the `master` branch since they will be merged back into `master` once done. Please do not build from or request a merge into the `release` branch as this is only for publishing releases. If you are looking to alter CSS or JavaScript content please edit the source files found in `resources/assets`. Any CSS or JS files within `public` are built from these source files and therefore should not be edited directly. +Pull requests should be created from the `master` branch since they will be merged back into `master` once done. Please do not build from or request a merge into the `release` branch as this is only for publishing releases. If you are looking to alter CSS or JavaScript content please edit the source files found in `resources/`. Any CSS or JS files within `public` are built from these source files and therefore should not be edited directly. The project's code of conduct [can be found here](https://github.com/BookStackApp/BookStack/blob/master/.github/CODE_OF_CONDUCT.md). @@ -181,3 +182,5 @@ These are the great open-source projects used to help build BookStack: * [WKHTMLtoPDF](http://wkhtmltopdf.org/index.html) * [diagrams.net](https://github.com/jgraph/drawio) * [OneLogin's SAML PHP Toolkit](https://github.com/onelogin/php-saml) +* [League/CommonMark](https://commonmark.thephpleague.com/) +* [League/Flysystem](https://flysystem.thephpleague.com) diff --git a/resources/js/components/entity-selector.js b/resources/js/components/entity-selector.js index 58879a20c..6d9d06f86 100644 --- a/resources/js/components/entity-selector.js +++ b/resources/js/components/entity-selector.js @@ -1,22 +1,32 @@ +import {onChildEvent} from "../services/dom"; +/** + * Entity Selector + * @extends {Component} + */ class EntitySelector { - constructor(elem) { - this.elem = elem; + setup() { + this.elem = this.$el; + this.entityTypes = this.$opts.entityTypes || 'page,book,chapter'; + this.entityPermission = this.$opts.entityPermission || 'view'; + + this.input = this.$refs.input; + this.searchInput = this.$refs.search; + this.loading = this.$refs.loading; + this.resultsContainer = this.$refs.results; + this.addButton = this.$refs.add; + this.search = ''; this.lastClick = 0; this.selectedItemData = null; - const entityTypes = elem.hasAttribute('entity-types') ? elem.getAttribute('entity-types') : 'page,book,chapter'; - const entityPermission = elem.hasAttribute('entity-permission') ? elem.getAttribute('entity-permission') : 'view'; - this.searchUrl = window.baseUrl(`/ajax/search/entities?types=${encodeURIComponent(entityTypes)}&permission=${encodeURIComponent(entityPermission)}`); - - this.input = elem.querySelector('[entity-selector-input]'); - this.searchInput = elem.querySelector('[entity-selector-search]'); - this.loading = elem.querySelector('[entity-selector-loading]'); - this.resultsContainer = elem.querySelector('[entity-selector-results]'); - this.addButton = elem.querySelector('[entity-selector-add-button]'); + this.setupListeners(); + this.showLoading(); + this.initialLoad(); + } + setupListeners() { this.elem.addEventListener('click', this.onClick.bind(this)); let lastSearch = 0; @@ -42,8 +52,39 @@ class EntitySelector { }); } - this.showLoading(); - this.initialLoad(); + // Keyboard navigation + onChildEvent(this.$el, '[data-entity-type]', 'keydown', (e, el) => { + if (e.ctrlKey && e.code === 'Enter') { + const form = this.$el.closest('form'); + if (form) { + form.submit(); + e.preventDefault(); + return; + } + } + + if (e.code === 'ArrowDown') { + this.focusAdjacent(true); + } + if (e.code === 'ArrowUp') { + this.focusAdjacent(false); + } + }); + + this.searchInput.addEventListener('keydown', e => { + if (e.code === 'ArrowDown') { + this.focusAdjacent(true); + } + }) + } + + focusAdjacent(forward = true) { + const items = Array.from(this.resultsContainer.querySelectorAll('[data-entity-type]')); + const selectedIndex = items.indexOf(document.activeElement); + const newItem = items[selectedIndex+ (forward ? 1 : -1)] || items[0]; + if (newItem) { + newItem.focus(); + } } showLoading() { @@ -57,15 +98,19 @@ class EntitySelector { } initialLoad() { - window.$http.get(this.searchUrl).then(resp => { + window.$http.get(this.searchUrl()).then(resp => { this.resultsContainer.innerHTML = resp.data; this.hideLoading(); }) } + searchUrl() { + return `/ajax/search/entities?types=${encodeURIComponent(this.entityTypes)}&permission=${encodeURIComponent(this.entityPermission)}`; + } + searchEntities(searchTerm) { this.input.value = ''; - let url = `${this.searchUrl}&term=${encodeURIComponent(searchTerm)}`; + const url = `${this.searchUrl()}&term=${encodeURIComponent(searchTerm)}`; window.$http.get(url).then(resp => { this.resultsContainer.innerHTML = resp.data; this.hideLoading(); @@ -73,8 +118,8 @@ class EntitySelector { } isDoubleClick() { - let now = Date.now(); - let answer = now - this.lastClick < 300; + const now = Date.now(); + const answer = now - this.lastClick < 300; this.lastClick = now; return answer; } @@ -123,8 +168,8 @@ class EntitySelector { } unselectAll() { - let selected = this.elem.querySelectorAll('.selected'); - for (let selectedElem of selected) { + const selected = this.elem.querySelectorAll('.selected'); + for (const selectedElem of selected) { selectedElem.classList.remove('selected', 'primary-background'); } this.selectedItemData = null; diff --git a/resources/js/components/markdown-editor.js b/resources/js/components/markdown-editor.js index bd107f2bf..78581ec44 100644 --- a/resources/js/components/markdown-editor.js +++ b/resources/js/components/markdown-editor.js @@ -22,7 +22,6 @@ class MarkdownEditor { this.displayStylesLoaded = false; this.input = this.elem.querySelector('textarea'); - this.htmlInput = this.elem.querySelector('input[name=html]'); this.cm = code.markdownEditor(this.input); this.onMarkdownScroll = this.onMarkdownScroll.bind(this); @@ -125,7 +124,6 @@ class MarkdownEditor { // Set body content this.displayDoc.body.className = 'page-content'; this.displayDoc.body.innerHTML = html; - this.htmlInput.value = html; // Copy styles from page head and set custom styles for editor this.loadStylesIntoDisplay(); diff --git a/resources/js/components/user-select.js b/resources/js/components/user-select.js index 477c11d6b..c2c1f97c3 100644 --- a/resources/js/components/user-select.js +++ b/resources/js/components/user-select.js @@ -13,9 +13,11 @@ class UserSelect { } selectUser(event, userEl) { + event.preventDefault(); const id = userEl.getAttribute('data-id'); this.input.value = id; this.userInfoContainer.innerHTML = userEl.innerHTML; + this.input.dispatchEvent(new Event('change', {bubbles: true})); this.hide(); } diff --git a/resources/js/components/wysiwyg-editor.js b/resources/js/components/wysiwyg-editor.js index 41b2273e2..a6ab54218 100644 --- a/resources/js/components/wysiwyg-editor.js +++ b/resources/js/components/wysiwyg-editor.js @@ -212,7 +212,7 @@ function codePlugin() { showPopup(editor); }); - editor.on('SetContent', function () { + function parseCodeMirrorInstances() { // Recover broken codemirror instances $('.CodeMirrorContainer').filter((index ,elem) => { @@ -231,6 +231,17 @@ function codePlugin() { Code.wysiwygView(elem); }); }); + } + + editor.on('init', function() { + // Parse code mirror instances on init, but delay a little so this runs after + // initial styles are fetched into the editor. + parseCodeMirrorInstances(); + // Parsed code mirror blocks when content is set but wait before setting this handler + // to avoid any init 'SetContent' events. + setTimeout(() => { + editor.on('SetContent', parseCodeMirrorInstances); + }, 200); }); }); diff --git a/resources/js/services/code.js b/resources/js/services/code.js index e2aca1aad..5727cd2b7 100644 --- a/resources/js/services/code.js +++ b/resources/js/services/code.js @@ -238,9 +238,7 @@ function wysiwygView(elem) { theme: getTheme(), readOnly: true }); - setTimeout(() => { - cm.refresh(); - }, 300); + return {wrap: newWrap, editor: cm}; } diff --git a/resources/lang/ar/common.php b/resources/lang/ar/common.php index 57d0b2dbd..70a93e27f 100644 --- a/resources/lang/ar/common.php +++ b/resources/lang/ar/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'إذا واجهتكم مشكلة بضغط زر ":actionText" فبإمكانكم نسخ الرابط أدناه ولصقه بالمتصفح:', 'email_rights' => 'جميع الحقوق محفوظة', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privacy Policy', + 'terms_of_service' => 'Terms of Service', ]; diff --git a/resources/lang/ar/settings.php b/resources/lang/ar/settings.php index f55451ff6..20789d842 100755 --- a/resources/lang/ar/settings.php +++ b/resources/lang/ar/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'الصفحة الرئيسية للتطبيق', 'app_homepage_desc' => 'الرجاء اختيار صفحة لتصبح الصفحة الرئيسية بدل من الافتراضية. سيتم تجاهل جميع الأذونات الخاصة بالصفحة المختارة.', 'app_homepage_select' => 'اختر صفحة', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', 'app_disable_comments' => 'تعطيل التعليقات', 'app_disable_comments_toggle' => 'تعطيل التعليقات', 'app_disable_comments_desc' => 'تعطيل التعليقات على جميع الصفحات داخل التطبيق. التعليقات الموجودة من الأصل لن تكون ظاهرة.', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/ar/validation.php b/resources/lang/ar/validation.php index d0b17460b..3c03f2efd 100644 --- a/resources/lang/ar/validation.php +++ b/resources/lang/ar/validation.php @@ -78,7 +78,6 @@ return [ 'string' => 'يجب أن يكون :attribute على الأقل :min حرف / حروف.', 'array' => 'يجب أن يحتوي :attribute على :min عنصر / عناصر كحد أدنى.', ], - 'no_double_extension' => 'يجب أن يكون للسمة: امتداد ملف واحد فقط.', 'not_in' => ':attribute المحدد غير صالح.', 'not_regex' => 'صيغة السمة: غير صالحة.', 'numeric' => 'يجب أن يكون :attribute رقم.', diff --git a/resources/lang/bg/common.php b/resources/lang/bg/common.php index 99930ddf4..b98072925 100644 --- a/resources/lang/bg/common.php +++ b/resources/lang/bg/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'Ако имате проблеми с бутона ":actionText" по-горе, копирайте и поставете URL адреса по-долу в уеб браузъра си:', 'email_rights' => 'Всички права запазени', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privacy Policy', + 'terms_of_service' => 'Terms of Service', ]; diff --git a/resources/lang/bg/settings.php b/resources/lang/bg/settings.php index dcfe44b3a..5fb24056e 100644 --- a/resources/lang/bg/settings.php +++ b/resources/lang/bg/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'Application Homepage', 'app_homepage_desc' => 'Select a view to show on the homepage instead of the default view. Page permissions are ignored for selected pages.', 'app_homepage_select' => 'Select a page', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', 'app_disable_comments' => 'Disable Comments', 'app_disable_comments_toggle' => 'Disable comments', 'app_disable_comments_desc' => 'Disables comments across all pages in the application.
Existing comments are not shown.', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/bg/validation.php b/resources/lang/bg/validation.php index 578ea999f..4031de2ae 100644 --- a/resources/lang/bg/validation.php +++ b/resources/lang/bg/validation.php @@ -78,7 +78,6 @@ return [ 'string' => 'The :attribute must be at least :min characters.', 'array' => 'The :attribute must have at least :min items.', ], - 'no_double_extension' => 'The :attribute must only have a single file extension.', 'not_in' => 'The selected :attribute is invalid.', 'not_regex' => 'The :attribute format is invalid.', 'numeric' => 'The :attribute must be a number.', diff --git a/resources/lang/bs/activities.php b/resources/lang/bs/activities.php new file mode 100644 index 000000000..a9c7bfb52 --- /dev/null +++ b/resources/lang/bs/activities.php @@ -0,0 +1,49 @@ + 'je kreirao/la stranicu', + 'page_create_notification' => 'Stranica Uspješno Kreirana', + 'page_update' => 'je ažurirao/la stranicu', + 'page_update_notification' => 'Stranica Uspješno Ažurirana', + 'page_delete' => 'je izbrisao/la stranicu', + 'page_delete_notification' => 'Stranica Uspješno Izbrisana', + 'page_restore' => 'je vratio/la stranicu', + 'page_restore_notification' => 'Stranica Uspješno Vraćena', + 'page_move' => 'je premjestio/la stranicu', + + // Chapters + 'chapter_create' => 'je kreirao/la poglavlje', + 'chapter_create_notification' => 'Poglavlje Uspješno Kreirano', + 'chapter_update' => 'je ažurirao/la poglavlje', + 'chapter_update_notification' => 'Poglavlje Uspješno Ažurirano', + 'chapter_delete' => 'je izbrisao/la poglavlje', + 'chapter_delete_notification' => 'Poglavlje Uspješno Izbrisano', + 'chapter_move' => 'je premjestio/la poglavlje', + + // Books + 'book_create' => 'je kreirao/la knjigu', + 'book_create_notification' => 'Knjiga Uspješno Kreirana', + 'book_update' => 'je ažurirao/la knjigu', + 'book_update_notification' => 'Knjiga Uspješno Ažurirana', + 'book_delete' => 'je izbrisao/la knjigu', + 'book_delete_notification' => 'Knjiga Uspješno Izbrisana', + 'book_sort' => 'je sortirao/la knjigu', + 'book_sort_notification' => 'Knjiga Uspješno Ponovno Sortirana', + + // Bookshelves + 'bookshelf_create' => 'je kreirao/la Policu za knjige', + 'bookshelf_create_notification' => 'Polica za knjige Uspješno Kreirana', + 'bookshelf_update' => 'je ažurirao/la policu za knjige', + 'bookshelf_update_notification' => 'Polica za knjige Uspješno Ažurirana', + 'bookshelf_delete' => 'je izbrisao/la policu za knjige', + 'bookshelf_delete_notification' => 'Polica za knjige Uspješno Izbrisana', + + // Other + 'commented_on' => 'je komentarisao/la na', + 'permissions_update' => 'je ažurirao/la dozvole', +]; diff --git a/resources/lang/bs/auth.php b/resources/lang/bs/auth.php new file mode 100644 index 000000000..526a8612f --- /dev/null +++ b/resources/lang/bs/auth.php @@ -0,0 +1,77 @@ + 'Ovi pristupni podaci se ne slažu sa našom evidencijom.', + 'throttle' => 'Preveliki broj pokušaja prijave. Molimo vas da pokušate ponovo za :seconds sekundi.', + + // Login & Register + 'sign_up' => 'Registruj se', + 'log_in' => 'Prijavi se', + 'log_in_with' => 'Prijavi se sa :socialDriver', + 'sign_up_with' => 'Registruj se sa :socialDriver', + 'logout' => 'Odjavi se', + + 'name' => 'Ime', + 'username' => 'Korisničko ime', + 'email' => 'E-mail', + 'password' => 'Lozinka', + 'password_confirm' => 'Potvrdi lozinku', + 'password_hint' => 'Mora imati više od 7 karaktera', + 'forgot_password' => 'Zaboravljena lozinka?', + 'remember_me' => 'Zapamti me', + 'ldap_email_hint' => 'Unesite e-mail koji će se koristiti za ovaj račun.', + 'create_account' => 'Napravi račun', + 'already_have_account' => 'Već imate račun?', + 'dont_have_account' => 'Nemate korisnički račun?', + 'social_login' => 'Prijava preko društvene mreže', + 'social_registration' => 'Registracija pomoću društvene mreže', + 'social_registration_text' => 'Registruj i prijavi se koristeći drugi servis.', + + 'register_thanks' => 'Hvala na registraciji!', + 'register_confirm' => 'Provjerite vašu e-mail adresu i pritisnite dugme za potvrdu da bi dobili pristup :appName.', + 'registrations_disabled' => 'Registracije su trenutno onemogućene', + 'registration_email_domain_invalid' => 'Ta e-mail domena nema pristup ovoj aplikaciji', + 'register_success' => 'Hvala na registraciji! Sada ste registrovani i prijavljeni.', + + + // Password Reset + 'reset_password' => 'Resetuj Lozinku', + 'reset_password_send_instructions' => 'Unesite vašu e-mail adresu ispod i na nju ćemo vam poslati e-mail sa linkom za promjenu lozinke.', + 'reset_password_send_button' => 'Pošalji link za promjenu', + 'reset_password_sent' => 'Link za promjenu lozinke će biti poslan na :email ako ta adresa postoji u sistemu.', + 'reset_password_success' => 'Vaša lozinka je uspješno promijenjena.', + 'email_reset_subject' => 'Resetujte vašu lozinku od :appName', + 'email_reset_text' => 'Primate ovaj e-mail jer smo dobili zahtjev za promjenu lozinke za vaš račun.', + 'email_reset_not_requested' => 'Ako niste zahtijevali promjenu lozinke ne trebate ništa više uraditi.', + + + // Email Confirmation + 'email_confirm_subject' => 'Potvrdite vaš e-mail na :appName', + 'email_confirm_greeting' => 'Hvala na pristupanju :appName!', + 'email_confirm_text' => 'Potvrdite vašu e-mail adresu pritiskom na dugme ispod:', + 'email_confirm_action' => 'Potvrdi e-mail', + 'email_confirm_send_error' => 'Potvrda e-maila je obavezna ali sistem nije mogao poslati e-mail. Kontaktirajte administratora da biste bili sigurni da je e-mail postavljen ispravno.', + 'email_confirm_success' => 'Vaš e-mail je potvrđen!', + 'email_confirm_resent' => 'E-mail za potvrdu je ponovno poslan. Provjerite vaš e-mail.', + + 'email_not_confirmed' => 'E-mail adresa nije potvrđena', + 'email_not_confirmed_text' => 'Vaša e-mail adresa nije još potvrđena.', + 'email_not_confirmed_click_link' => 'Kliknite na link u e-mailu koji vam je poslan nakon što ste se registrovali.', + 'email_not_confirmed_resend' => 'Ako ne možete naći e-mail možete ponovno poslati e-mail za potvrdu tako što ćete ispuniti formu ispod.', + 'email_not_confirmed_resend_button' => 'Ponovno pošalji e-mail za potvrdu', + + // User Invite + 'user_invite_email_subject' => 'Pozvani ste da se pridružite :appName!', + 'user_invite_email_greeting' => 'Račun je napravljen za vas na :appName.', + 'user_invite_email_text' => 'Pritisnite dugme ispod da niste postavili lozinku vašeg računa i tako dobili pristup:', + 'user_invite_email_action' => 'Postavi lozinku računa', + 'user_invite_page_welcome' => 'Dobrodošli na :appName!', + 'user_invite_page_text' => 'Da biste završili vaš račun i dobili pristup morate postaviti lozinku koju ćete koristiti da se prijavite na :appName tokom budućih posjeta.', + 'user_invite_page_confirm_button' => 'Potvrdi lozinku', + 'user_invite_success' => 'Lozinka postavljena, sada imate pristup :sppName!' +]; \ No newline at end of file diff --git a/resources/lang/bs/common.php b/resources/lang/bs/common.php new file mode 100644 index 000000000..a0a60f113 --- /dev/null +++ b/resources/lang/bs/common.php @@ -0,0 +1,85 @@ + 'Otkaži', + 'confirm' => 'Potvrdi', + 'back' => 'Nazad', + 'save' => 'Spremi', + 'continue' => 'Nastavi', + 'select' => 'Odaberi', + 'toggle_all' => 'Prebaci sve', + 'more' => 'Više', + + // Form Labels + 'name' => 'Ime', + 'description' => 'Opis', + 'role' => 'Uloga', + 'cover_image' => 'Naslovna slika', + 'cover_image_description' => 'Ova slika treba biti približno 440x250px.', + + // Actions + 'actions' => 'Akcije', + 'view' => 'Prikaz', + 'view_all' => 'Prikaži sve', + 'create' => 'Kreiraj', + 'update' => 'Ažuriraj', + 'edit' => 'Uredi', + 'sort' => 'Sortiraj', + 'move' => 'Pomjeri', + 'copy' => 'Kopiraj', + 'reply' => 'Odgovori', + 'delete' => 'Izbriši', + 'delete_confirm' => 'Potvrdi brisanje', + 'search' => 'Traži', + 'search_clear' => 'Očisti pretragu', + 'reset' => 'Resetuj', + 'remove' => 'Ukloni', + 'add' => 'Dodaj', + 'fullscreen' => 'Prikaz preko čitavog ekrana', + + // Sort Options + 'sort_options' => 'Opcije sortiranja', + 'sort_direction_toggle' => 'Prebacivanje smjera sortiranja', + 'sort_ascending' => 'Sortiraj uzlazno', + 'sort_descending' => 'Sortiraj silazno', + 'sort_name' => 'Ime', + 'sort_created_at' => 'Datum kreiranja', + 'sort_updated_at' => 'Datum ažuriranja', + + // Misc + 'deleted_user' => 'Obrisani korisnik', + 'no_activity' => 'Nema aktivnosti za prikazivanje', + 'no_items' => 'Nema dostupnih stavki', + 'back_to_top' => 'Povratak na vrh', + 'toggle_details' => 'Vidi detalje', + 'toggle_thumbnails' => 'Vidi prikaze slika', + 'details' => 'Detalji', + 'grid_view' => 'Prikaz rešetke', + 'list_view' => 'Prikaz liste', + 'default' => 'Početne postavke', + 'breadcrumb' => 'Navigacijske stavke', + + // Header + 'profile_menu' => 'Meni profila', + 'view_profile' => 'Pogledaj profil', + 'edit_profile' => 'Izmjeni profil', + 'dark_mode' => 'Tamni način rada', + 'light_mode' => 'Svijetli način rada', + + // Layout tabs + 'tab_info' => 'Informacije', + 'tab_content' => 'Sadržaj', + + // Email Content + 'email_action_help' => 'Ukoliko imate poteškoća sa pritiskom na ":actionText" dugme, kopirajte i zaljepite URL koji se nalazi ispod u vaš web pretraživač:', + 'email_rights' => 'Sva prava pridržana', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Pravila o privatnosti', + 'terms_of_service' => 'Uslovi korištenja', +]; diff --git a/resources/lang/bs/components.php b/resources/lang/bs/components.php new file mode 100644 index 000000000..d40a95a9e --- /dev/null +++ b/resources/lang/bs/components.php @@ -0,0 +1,34 @@ + 'Biraj sliku', + 'image_all' => 'Sve', + 'image_all_title' => 'Pogledaj sve slike', + 'image_book_title' => 'Pogledaj slike prenesene u ovu knjigu', + 'image_page_title' => 'Pogledaj slike prenesene na ovu stranicu', + 'image_search_hint' => 'Traži po nazivu slike', + 'image_uploaded' => 'Preneseno :uploadedDate', + 'image_load_more' => 'Učitaj još', + 'image_image_name' => 'Naziv slike', + 'image_delete_used' => 'Ova slika se koristi na stranicama prikazanim ispod.', + 'image_delete_confirm_text' => 'Jeste li sigurni da želite obrisati ovu sliku?', + 'image_select_image' => 'Odaberi sliku', + 'image_dropzone' => 'Ostavi slike ili pritisnite ovdje da ih prenesete', + 'images_deleted' => 'Slike su izbrisane', + 'image_preview' => 'Pregled Slike', + 'image_upload_success' => 'Slika uspješno učitana', + 'image_update_success' => 'Detalji slike uspješno ažurirani', + 'image_delete_success' => 'Slika uspješno izbrisana', + 'image_upload_remove' => 'Ukloni', + + // Code Editor + 'code_editor' => 'Uredi Kod', + 'code_language' => 'Jezik koda', + 'code_content' => 'Sadržaj Koda', + 'code_session_history' => 'Historija Sesije', + 'code_save' => 'Snimi Kod', +]; diff --git a/resources/lang/bs/entities.php b/resources/lang/bs/entities.php new file mode 100644 index 000000000..7a3558b8b --- /dev/null +++ b/resources/lang/bs/entities.php @@ -0,0 +1,319 @@ + 'Nedavno napravljen', + 'recently_created_pages' => 'Nedavno napravljene stranice', + 'recently_updated_pages' => 'Nedavno ažurirane stranice', + 'recently_created_chapters' => 'Nedavno napravljena poglavlja', + 'recently_created_books' => 'Nedavno napravljene knjige', + 'recently_created_shelves' => 'Nedavno napravljene police', + 'recently_update' => 'Nedavno ažurirana', + 'recently_viewed' => 'Nedavno pogledana', + 'recent_activity' => 'Nedavna aktivnost', + 'create_now' => 'Napravi jednu sada', + 'revisions' => 'Promjene', + 'meta_revision' => 'Promjena #:revisionCount', + 'meta_created' => 'Napravljena :timeLength', + 'meta_created_name' => 'Napravljena :timeLength od :user', + 'meta_updated' => 'Ažurirana :timeLength', + 'meta_updated_name' => 'Ažurirana :timeLength od :user', + 'meta_owned_name' => 'Vlasnik je :user', + 'entity_select' => 'Odaberi entitet', + 'images' => 'Slike', + 'my_recent_drafts' => 'Moje nedavne skice', + 'my_recently_viewed' => 'Moji nedavni pregledi', + 'no_pages_viewed' => 'Niste pogledali nijednu stranicu', + 'no_pages_recently_created' => 'Nijedna stranica nije napravljena nedavno', + 'no_pages_recently_updated' => 'Niijedna stranica nije ažurirana nedavno', + 'export' => 'Izvezi', + 'export_html' => 'Sadržani web fajl', + 'export_pdf' => 'PDF fajl', + 'export_text' => 'Plain Text fajl', + + // 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_save' => 'Snimi dozvole', + 'permissions_owner' => 'Vlasnik', + + // Search + 'search_results' => 'Rezultati pretrage', + 'search_total_results_found' => ':count rezultata je nađeno|:count ukupno rezultata je nađeno', + 'search_clear' => 'Očisti pretragu', + 'search_no_pages' => 'Nijedna stranica nije nađena', + 'search_for_term' => 'Traži :term', + 'search_more' => 'Više rezultata', + 'search_advanced' => 'Napredna pretraga', + 'search_terms' => 'Pojmovi za pretragu', + 'search_content_type' => 'Vrsta sadržaja', + 'search_exact_matches' => 'Tačna podudaranja', + 'search_tags' => 'Pretraga oznaka', + 'search_options' => 'Opcije', + 'search_viewed_by_me' => 'Ja sam pogledao/la', + 'search_not_viewed_by_me' => 'Nisam pogledao/la', + 'search_permissions_set' => 'Dozvole', + 'search_created_by_me' => 'Ja sam napravio/la', + 'search_updated_by_me' => 'Ja sam ažurirao/la', + 'search_date_options' => 'Opcije datuma', + 'search_updated_before' => 'Ažurirano prije', + 'search_updated_after' => 'Ažurirano nakon', + 'search_created_before' => 'Kreirano prije', + 'search_created_after' => 'Kreirano nakon', + 'search_set_date' => 'Postavi datum', + 'search_update' => 'Ažuriraj pretragu', + + // Shelves + 'shelf' => 'Polica', + 'shelves' => 'Police', + 'x_shelves' => ':count Polica|:count Police', + 'shelves_long' => 'Police za knjige', + 'shelves_empty' => 'Niti jedna polica nije kreirana', + 'shelves_create' => 'Kreiraj novu policu', + 'shelves_popular' => 'Popularne police', + 'shelves_new' => 'Nove police', + 'shelves_new_action' => 'Nova polica', + 'shelves_popular_empty' => 'Najpopularnije police će se pojaviti ovdje.', + 'shelves_new_empty' => 'Najnovije police će se pojaviti ovdje.', + 'shelves_save' => 'Spremi policu', + 'shelves_books' => 'Knjige na ovoj polici', + 'shelves_add_books' => 'Dodaj knjige na ovu policu', + 'shelves_drag_books' => 'Prenesi knjige ovdje da bi ih dodao/la na ovu policu', + 'shelves_empty_contents' => 'Ova polica nema knjiga koje su postavljene na nju', + 'shelves_edit_and_assign' => 'Uredi policu da bi dodao/la knjige', + 'shelves_edit_named' => 'Uredi :name police za knjige', + 'shelves_edit' => 'Uredi policu za knjige', + 'shelves_delete' => 'Izbriši policu za knjige', + 'shelves_delete_named' => 'Izbriši policu za knjige :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_copy_permissions_to_books' => 'Copy Permissions to Books', + 'shelves_copy_permissions' => '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' => 'Book', + 'books' => 'Books', + 'x_books' => ':count Book|:count Books', + 'books_empty' => 'No books have been created', + 'books_popular' => 'Popular Books', + 'books_recent' => 'Recent Books', + 'books_new' => 'New Books', + 'books_new_action' => 'New Book', + 'books_popular_empty' => 'The most popular books will appear here.', + 'books_new_empty' => 'The most recently created books will appear here.', + 'books_create' => 'Create New Book', + 'books_delete' => 'Delete Book', + 'books_delete_named' => 'Delete Book :bookName', + 'books_delete_explain' => 'Ovo će izbrisati knjigu naziva \':bookName\'. Sve stranice i poglavlja će biti uklonjene.', + 'books_delete_confirmation' => 'Jeste li sigurni da želite izbrisati ovu knjigu?', + 'books_edit' => 'Uredi knjigu', + 'books_edit_named' => 'Uredi knjigu :bookName', + 'books_form_book_name' => 'Naziv knjige', + 'books_save' => 'Spremi knjigu', + 'books_permissions' => 'Dozvole knjige', + 'books_permissions_updated' => 'Dozvole knjige su ažurirane', + 'books_empty_contents' => 'Za ovu knjigu nisu napravljene ni stranice ni poglavlja.', + 'books_empty_create_page' => 'Napravi novu stranicu', + 'books_empty_sort_current_book' => 'Sortiraj trenutnu knjigu', + 'books_empty_add_chapter' => 'Dodaj poglavlje', + 'books_permissions_active' => 'Dozvole za knjigu su aktivne', + 'books_search_this' => 'Pretraži ovu knjigu', + 'books_navigation' => 'Navigacija knjige', + 'books_sort' => 'Sortiraj sadržaj knjige', + 'books_sort_named' => 'Sortiraj knjigu :bookName', + 'books_sort_name' => 'Sortiraj po imenu', + 'books_sort_created' => 'Sortiraj po datumu kreiranja', + 'books_sort_updated' => 'Sortiraj po datumu ažuriranja', + 'books_sort_chapters_first' => 'Poglavlja prva', + 'books_sort_chapters_last' => 'Poglavlja zadnja', + 'books_sort_show_other' => 'Prikaži druge knjige', + 'books_sort_save' => 'Spremi trenutni poredak', + + // Chapters + 'chapter' => 'Poglavlje', + 'chapters' => 'Poglavlja', + 'x_chapters' => ':count Poglavlje|:count Poglavlja', + 'chapters_popular' => 'Popularna poglavlja', + 'chapters_new' => 'Novo poglavlje', + 'chapters_create' => 'Napravi novo poglavlje', + 'chapters_delete' => 'Izbriši poglavlje', + 'chapters_delete_named' => 'Izbriši poglavlje :chapterName', + 'chapters_delete_explain' => 'Ovo će izbrisati poglavlje naziva \':chapterName\'. Sve stranice koje postoje u ovom poglavlju će također biti izbrisane.', + 'chapters_delete_confirm' => 'Jeste li sigurni da želite izbrisati ovo poglavlje?', + 'chapters_edit' => 'Uredi poglavlje', + 'chapters_edit_named' => 'Uredi poglavlje :chapterName', + 'chapters_save' => 'Spremi poglavlje', + 'chapters_move' => 'Premjesti poglavlje', + 'chapters_move_named' => 'Premjesti poglavlje :chapterName', + 'chapter_move_success' => 'Poglavlje premješteno u :bookName', + 'chapters_permissions' => 'Dozvole poglavlja', + 'chapters_empty' => 'U ovom poglavlju trenutno nema stranica.', + 'chapters_permissions_active' => 'Dozvole za poglavlje su aktivne', + 'chapters_permissions_success' => 'Dozvole za poglavlje su ažurirane', + 'chapters_search_this' => 'Pretražuj ovo poglavlje', + + // Pages + 'page' => 'Stranica', + 'pages' => 'Stranice', + 'x_pages' => ':count Stranica|:count Stranice', + 'pages_popular' => 'Popularne stranice', + 'pages_new' => 'Nova stranica', + 'pages_attachments' => 'Attachments', + 'pages_navigation' => 'Page Navigation', + 'pages_delete' => 'Delete Page', + 'pages_delete_named' => 'Delete Page :pageName', + 'pages_delete_draft_named' => 'Delete Draft Page :pageName', + 'pages_delete_draft' => 'Delete Draft Page', + 'pages_delete_success' => 'Page deleted', + 'pages_delete_draft_success' => 'Draft page deleted', + 'pages_delete_confirm' => 'Are you sure you want to delete this page?', + 'pages_delete_draft_confirm' => 'Are you sure you want to delete this draft page?', + 'pages_editing_named' => 'Editing Page :pageName', + 'pages_edit_draft_options' => 'Draft Options', + 'pages_edit_save_draft' => 'Save Draft', + 'pages_edit_draft' => 'Edit Page Draft', + 'pages_editing_draft' => 'Editing Draft', + 'pages_editing_page' => 'Editing Page', + 'pages_edit_draft_save_at' => 'Draft saved at ', + 'pages_edit_delete_draft' => 'Delete Draft', + 'pages_edit_discard_draft' => 'Discard Draft', + 'pages_edit_set_changelog' => 'Set Changelog', + 'pages_edit_enter_changelog_desc' => 'Enter a brief description of the changes you\'ve made', + 'pages_edit_enter_changelog' => 'Enter Changelog', + 'pages_save' => 'Save Page', + 'pages_title' => 'Page Title', + 'pages_name' => 'Page Name', + 'pages_md_editor' => 'Editor', + 'pages_md_preview' => 'Preview', + 'pages_md_insert_image' => 'Insert Image', + 'pages_md_insert_link' => 'Insert Entity Link', + 'pages_md_insert_drawing' => 'Insert Drawing', + 'pages_not_in_chapter' => 'Page is not in a chapter', + 'pages_move' => 'Move Page', + 'pages_move_success' => 'Page moved to ":parentName"', + 'pages_copy' => 'Copy Page', + 'pages_copy_desination' => 'Copy Destination', + 'pages_copy_success' => 'Page successfully copied', + 'pages_permissions' => 'Page Permissions', + 'pages_permissions_success' => 'Page permissions updated', + 'pages_revision' => 'Revision', + 'pages_revisions' => 'Page Revisions', + 'pages_revisions_named' => 'Page Revisions for :pageName', + 'pages_revision_named' => 'Page Revision for :pageName', + 'pages_revision_restored_from' => 'Restored from #:id; :summary', + 'pages_revisions_created_by' => 'Created By', + 'pages_revisions_date' => 'Revision Date', + 'pages_revisions_number' => '#', + 'pages_revisions_numbered' => 'Revision #:id', + 'pages_revisions_numbered_changes' => 'Revision #:id Changes', + 'pages_revisions_changelog' => 'Changelog', + 'pages_revisions_changes' => 'Changes', + 'pages_revisions_current' => 'Trenutna verzija', + 'pages_revisions_preview' => 'Pregled', + 'pages_revisions_restore' => 'Vrati', + 'pages_revisions_none' => 'Ova stranica nema promjena', + 'pages_copy_link' => 'Iskopiraj link', + 'pages_edit_content_link' => 'Uredi sadržaj', + 'pages_permissions_active' => 'Dozvole za stranicu su aktivne', + 'pages_initial_revision' => 'Prvo izdavanje', + 'pages_initial_name' => 'Nova stranica', + 'pages_editing_draft_notification' => 'Trenutno uređujete skicu koja je posljednji put snimljena :timeDiff.', + 'pages_draft_edited_notification' => 'Ova stranica je ažurirana nakon tog vremena. Preporučujemo da odbacite ovu skicu.', + 'pages_draft_edit_active' => [ + 'start_a' => ':count korisnika je počelo sa uređivanjem ove stranice', + 'start_b' => ':userName je počeo/la sa uređivanjem ove stranice', + 'time_a' => 'od kada je stranica posljednji put ažurirana', + 'time_b' => 'u posljednjih :minCount minuta', + 'message' => ':start :time. Pazite da jedni drugima ne prepišete promjene!', + ], + 'pages_draft_discarded' => 'Skica je odbačena, uređivač je ažuriran sa trenutnim sadržajem stranice', + 'pages_specific' => 'Specifična stranica', + 'pages_is_template' => 'Predložak stranice', + + // Editor Sidebar + 'page_tags' => 'Oznake stranice', + 'chapter_tags' => 'Oznake poglavlja', + 'book_tags' => 'Oznake knjige', + 'shelf_tags' => 'Oznake police', + 'tag' => 'Oznaka', + 'tags' => 'Oznake', + 'tag_name' => 'Naziv oznake', + 'tag_value' => 'Vrijednost oznake (nije obavezno)', + 'tags_explain' => "Dodaj nekoliko oznaka da bi sadržaj bio bolje kategorisan. \n Možeš dodati vrijednost oznaci za dublju organizaciju.", + 'tags_add' => 'Dodaj još jednu oznaku', + 'tags_remove' => 'Ukloni ovu oznaku', + 'attachments' => 'Prilozi', + 'attachments_explain' => 'Učitajte fajlove ili priložite poveznice da bi ih prikazali na stranici. Oni su onda vidljivi u navigaciji sa strane.', + 'attachments_explain_instant_save' => 'Sve promjene se snimaju odmah.', + 'attachments_items' => 'Priložene stavke', + 'attachments_upload' => 'Učitaj fajl', + 'attachments_link' => 'Zakači link', + 'attachments_set_link' => 'Postavi link', + 'attachments_delete' => 'Jeste li sigurni da želite obrisati ovaj prilog?', + 'attachments_dropzone' => 'Spustite fajlove ili pritisnite ovdje da priložite fajl', + 'attachments_no_files' => 'Niti jedan fajl nije prenesen', + 'attachments_explain_link' => 'Možete zakačiti link ako ne želite učitati fajl. To može biti link druge stranice ili link za fajl u oblaku.', + 'attachments_link_name' => 'Naziv linka', + 'attachment_link' => 'Link poveznice', + 'attachments_link_url' => 'Link do fajla', + 'attachments_link_url_hint' => 'Url stranice ili fajla', + 'attach' => 'Zakači', + 'attachments_insert_link' => 'Dodaj priloženi link na stranicu', + 'attachments_edit_file' => 'Uredi fajl', + 'attachments_edit_file_name' => 'Naziv fajla', + 'attachments_edit_drop_upload' => 'Spusti fajlove ili pritisni ovdje da učitaš i prepišeš', + 'attachments_order_updated' => 'Attachment order updated', + 'attachments_updated_success' => 'Attachment details updated', + 'attachments_deleted' => 'Attachment deleted', + 'attachments_file_uploaded' => 'File successfully uploaded', + 'attachments_file_updated' => 'File successfully updated', + 'attachments_link_attached' => 'Link successfully attached to page', + 'templates' => 'Templates', + 'templates_set_as_template' => 'Page is a template', + 'templates_explain_set_as_template' => 'You can set this page as a template so its contents be utilized when creating other pages. Other users will be able to use this template if they have view permissions for this page.', + 'templates_replace_content' => 'Replace page content', + 'templates_append_content' => 'Append to page content', + 'templates_prepend_content' => 'Prepend to page content', + + // Profile View + 'profile_user_for_x' => 'User for :time', + 'profile_created_content' => 'Created Content', + 'profile_not_created_pages' => ':userName has not created any pages', + 'profile_not_created_chapters' => ':userName has not created any chapters', + 'profile_not_created_books' => ':userName has not created any books', + 'profile_not_created_shelves' => ':userName has not created any shelves', + + // Comments + 'comment' => 'Comment', + 'comments' => 'Comments', + 'comment_add' => 'Add Comment', + 'comment_placeholder' => 'Leave a comment here', + 'comment_count' => '{0} No Comments|{1} 1 Comment|[2,*] :count Comments', + 'comment_save' => 'Save Comment', + 'comment_saving' => 'Saving comment...', + 'comment_deleting' => 'Deleting comment...', + 'comment_new' => 'New Comment', + 'comment_created' => 'commented :createDiff', + 'comment_updated' => 'Updated :updateDiff by :username', + 'comment_deleted_success' => 'Comment deleted', + 'comment_created_success' => 'Comment added', + 'comment_updated_success' => 'Comment updated', + 'comment_delete_confirm' => 'Are you sure you want to delete this comment?', + 'comment_in_reply_to' => 'In reply to :commentId', + + // Revision + 'revision_delete_confirm' => 'Are you sure you want to delete this revision?', + 'revision_restore_confirm' => 'Are you sure you want to restore this revision? The current page contents will be replaced.', + 'revision_delete_success' => 'Revision deleted', + 'revision_cannot_delete_latest' => 'Cannot delete the latest revision.' +]; \ No newline at end of file diff --git a/resources/lang/bs/errors.php b/resources/lang/bs/errors.php new file mode 100644 index 000000000..aa16c1177 --- /dev/null +++ b/resources/lang/bs/errors.php @@ -0,0 +1,102 @@ + 'Nemate ovlaštenje da pristupite ovoj stranici.', + 'permissionJson' => 'Nemate ovlaštenje da izvršite tu akciju.', + + // Auth + 'error_user_exists_different_creds' => 'Korisnik sa e-mailom :email već postoji ali sa različitim podacima.', + 'email_already_confirmed' => 'E-mail je već potvrđen, pokušajte se prijaviti.', + 'email_confirmation_invalid' => 'Ovaj token za potvrdu nije ispravan ili je već iskorišten, molimo vas pokušajte se registrovati ponovno.', + 'email_confirmation_expired' => 'Ovaj token za potvrdu je istekao, novi e-mail za potvrdu je poslan.', + 'email_confirmation_awaiting' => 'E-mail adresa za račun koji se koristi mora biti potvrđena', + 'ldap_fail_anonymous' => 'LDAP pristup nije uspio koristeći anonimno povezivanje', + 'ldap_fail_authed' => 'LDAP pristup nije uspio koristeći date detalje lozinke i dn', + 'ldap_extension_not_installed' => 'LDAP PHP ekstenzija nije instalirana', + 'ldap_cannot_connect' => 'Nije se moguće povezati sa ldap serverom, incijalna konekcija nije uspjela', + 'saml_already_logged_in' => 'Već prijavljeni', + 'saml_user_not_registered' => 'Korisnik :user nije registrovan i automatska registracija je onemogućena', + 'saml_no_email_address' => 'E-mail adresa za ovog korisnika nije nađena u podacima dobijenim od eksternog autentifikacijskog sistema', + 'saml_invalid_response_id' => 'Proces, koji je pokrenula ova aplikacija, nije prepoznao zahtjev od eksternog sistema za autentifikaciju. Navigacija nazad nakon prijave može uzrokovati ovaj problem.', + 'saml_fail_authed' => 'Prijava koristeći :system nije uspjela, sistem nije obezbijedio uspješnu autorizaciju', + 'social_no_action_defined' => 'Nema definisane akcije', + 'social_login_bad_response' => "Došlo je do greške prilikom prijave preko :socialAccount :\n:error", + 'social_account_in_use' => 'Ovaj :socialAccount račun se već koristi, pokušajte se prijaviti putem :socialAccount opcije.', + 'social_account_email_in_use' => 'E-mail :email se već koristi. Ako već imate račun možete povezati vaš :socialAccount račun u postavkama profila.', + 'social_account_existing' => 'Ovaj :socialAccount je već povezan sa vašim profilom.', + 'social_account_already_used_existing' => 'Drugi korisnik već koristi ovaj :socialAccount.', + 'social_account_not_used' => 'Ovaj :socialAccount nije povezan ni sa jednim korisnikom. Povežite ga u postavkama profila. ', + 'social_account_register_instructions' => 'Ako još uvijek nemate račun, možete se registrovati koristeći :socialAccount opciju.', + 'social_driver_not_found' => 'Driver društvene mreže nije pronađen', + 'social_driver_not_configured' => 'Vaše :socialAccount postavke nisu konfigurisane ispravno.', + 'invite_token_expired' => 'Pozivni link je istekao. Možete umjesto toga pokušati da resetujete lozinku.', + + // System + 'path_not_writable' => 'Na putanju fajla :filePath se ne može učitati. Potvrdite da je omogućeno pisanje na server.', + 'cannot_get_image_from_url' => 'Nije moguće dobiti sliku sa :url', + 'cannot_create_thumbs' => 'Server ne može kreirati sličice. Provjerite da imate instaliranu GD PHP ekstenziju.', + 'server_upload_limit' => 'Server ne dopušta učitavanja ove veličine. Pokušajte sa manjom veličinom fajla.', + 'uploaded' => 'Server ne dopušta učitavanja ove veličine. Pokušajte sa manjom veličinom fajla.', + 'image_upload_error' => 'Desila se greška prilikom učitavanja slike', + 'image_upload_type_error' => 'Vrsta slike koja se učitava je neispravna', + 'file_upload_timeout' => 'Vrijeme učitavanja fajla je isteklo.', + + // Attachments + 'attachment_not_found' => 'Prilog nije pronađen', + + // Pages + 'page_draft_autosave_fail' => 'Snimanje skice nije uspjelo. Provjerite da ste povezani na internet prije snimanja ove stranice', + 'page_custom_home_deletion' => 'Stranicu nije moguće izbrisati dok se koristi kao početna stranica', + + // Entities + 'entity_not_found' => 'Entitet nije pronađen', + 'bookshelf_not_found' => 'Polica za knjige nije pronađena', + 'book_not_found' => 'Knjiga nije pronađena', + 'page_not_found' => 'Stranica nije pronađena', + 'chapter_not_found' => 'Poglavlje nije pronađeno', + 'selected_book_not_found' => 'Odabrana knjiga nije pronađena', + 'selected_book_chapter_not_found' => 'Odabrana knjiga ili poglavlje nije pronađeno', + 'guests_cannot_save_drafts' => 'Gosti ne mogu snimati skice', + + // Users + 'users_cannot_delete_only_admin' => 'Ne možete izbrisati jedinog administratora', + 'users_cannot_delete_guest' => 'Ne možete izbrisati gost korisnika', + + // Roles + 'role_cannot_be_edited' => 'Ova uloga ne može biti mijenjana', + 'role_system_cannot_be_deleted' => 'Ova uloga je sistemska uloga i ne može biti izbrisana', + 'role_registration_default_cannot_delete' => 'Ova uloga ne može biti izbrisana dok je postavljena kao osnovna registracijska uloga', + 'role_cannot_remove_only_admin' => 'Ovaj korisnik je jedini korisnik sa ulogom administratora. Postavite ulogu administratora drugom korisniku prije nego je uklonite ovdje.', + + // Comments + 'comment_list' => 'Desila se greška prilikom dobavljanja komentara.', + 'cannot_add_comment_to_draft' => 'Ne možete dodati komentare na skicu.', + 'comment_add' => 'Desila se greška prilikom dodavanja / ažuriranja komentara.', + 'comment_delete' => 'Desila se greška prilikom brisanja komentara.', + 'empty_comment' => 'Nemoguće dodati prazan komentar.', + + // Error pages + '404_page_not_found' => 'Stranica nije pronađena', + 'sorry_page_not_found' => 'Stranica koju ste tražili nije pronađena.', + 'sorry_page_not_found_permission_warning' => 'Ako ste očekivali da ova stranica postoji, možda nemate privilegije da joj pristupite.', + 'return_home' => 'Nazad na početnu stranu', + 'error_occurred' => 'Desila se greška', + 'app_down' => ':appName trenutno nije u funkciji', + 'back_soon' => 'Biti će uskoro u funkciji.', + + // API errors + 'api_no_authorization_found' => 'Na zahtjevu nije pronađen token za autorizaciju', + 'api_bad_authorization_format' => 'Token za autorizaciju je pronađen u zahtjevu ali je format neispravan', + 'api_user_token_not_found' => 'Nije pronađen odgovarajući API token za pruženi token autorizacije', + 'api_incorrect_token_secret' => 'Tajni ključ naveden za dati korišteni API token nije tačan', + 'api_user_no_api_permission' => 'Vlasnik korištenog API tokena nema dozvolu za upućivanje API poziva', + 'api_user_token_expired' => 'Autorizacijski token je istekao', + + // Settings & Maintenance + 'maintenance_test_email_failure' => 'Došlo je do greške prilikom slanja testnog e-maila:', + +]; diff --git a/resources/lang/bs/pagination.php b/resources/lang/bs/pagination.php new file mode 100644 index 000000000..a8d1417c5 --- /dev/null +++ b/resources/lang/bs/pagination.php @@ -0,0 +1,12 @@ + '« Prethodna', + 'next' => 'Sljedeća »', + +]; diff --git a/resources/lang/bs/passwords.php b/resources/lang/bs/passwords.php new file mode 100644 index 000000000..0383e8af0 --- /dev/null +++ b/resources/lang/bs/passwords.php @@ -0,0 +1,15 @@ + 'Lozinke moraju sadržavati najmanje osam karaktera i podudarati se sa potvrdom lozinke.', + 'user' => "Ne možemo naći korisnika sa tom e-mail adresom.", + 'token' => 'Token za poništavanje lozinke nije validan za ovu e-mail adresu.', + 'sent' => 'Poslali smo link za poništavanje vaše lozinke na e-mail!', + 'reset' => 'Vaša lozinka je resetovana!', + +]; diff --git a/resources/lang/bs/settings.php b/resources/lang/bs/settings.php new file mode 100644 index 000000000..ab7f15322 --- /dev/null +++ b/resources/lang/bs/settings.php @@ -0,0 +1,266 @@ + 'Settings', + 'settings_save' => 'Save Settings', + 'settings_save_success' => 'Settings saved', + + // App Settings + 'app_customization' => 'Customization', + 'app_features_security' => 'Features & Security', + 'app_name' => 'Application Name', + 'app_name_desc' => 'This name is shown in the header and in any system-sent emails.', + 'app_name_header' => 'Show name in header', + 'app_public_access' => 'Public Access', + 'app_public_access_desc' => 'Enabling this option will allow visitors, that are not logged-in, to access content in your BookStack instance.', + 'app_public_access_desc_guest' => 'Access for public visitors can be controlled through the "Guest" user.', + 'app_public_access_toggle' => 'Allow public access', + 'app_public_viewing' => 'Allow public viewing?', + 'app_secure_images' => 'Higher Security Image Uploads', + 'app_secure_images_toggle' => 'Enable higher security image uploads', + 'app_secure_images_desc' => 'For performance reasons, all images are public. This option adds a random, hard-to-guess string in front of image urls. Ensure directory indexes are not enabled to prevent easy access.', + 'app_editor' => 'Page Editor', + 'app_editor_desc' => 'Select which editor will be used by all users to edit pages.', + 'app_custom_html' => 'Custom HTML Head Content', + 'app_custom_html_desc' => 'Any content added here will be inserted into the bottom of the section of every page. This is handy for overriding styles or adding analytics code.', + 'app_custom_html_disabled_notice' => 'Custom HTML head content is disabled on this settings page to ensure any breaking changes can be reverted.', + 'app_logo' => 'Application Logo', + 'app_logo_desc' => 'This image should be 43px in height.
Large images will be scaled down.', + 'app_primary_color' => 'Application Primary Color', + 'app_primary_color_desc' => 'Sets the primary color for the application including the banner, buttons, and links.', + 'app_homepage' => 'Application Homepage', + 'app_homepage_desc' => 'Select a view to show on the homepage instead of the default view. Page permissions are ignored for selected pages.', + 'app_homepage_select' => 'Select a page', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', + 'app_disable_comments' => 'Disable Comments', + 'app_disable_comments_toggle' => 'Disable comments', + 'app_disable_comments_desc' => 'Disables comments across all pages in the application.
Existing comments are not shown.', + + // Color settings + 'content_colors' => 'Content Colors', + 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'bookshelf_color' => 'Shelf Color', + 'book_color' => 'Book Color', + 'chapter_color' => 'Chapter Color', + 'page_color' => 'Page Color', + 'page_draft_color' => 'Page Draft Color', + + // Registration Settings + 'reg_settings' => 'Registration', + 'reg_enable' => 'Enable Registration', + 'reg_enable_toggle' => 'Enable registration', + 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', + 'reg_default_role' => 'Default user role after registration', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', + 'reg_email_confirmation' => 'Email Confirmation', + 'reg_email_confirmation_toggle' => 'Require email confirmation', + 'reg_confirm_email_desc' => 'If domain restriction is used then email confirmation will be required and this option will be ignored.', + 'reg_confirm_restrict_domain' => 'Domain Restriction', + 'reg_confirm_restrict_domain_desc' => 'Enter a comma separated list of email domains you would like to restrict registration to. Users will be sent an email to confirm their address before being allowed to interact with the application.
Note that users will be able to change their email addresses after successful registration.', + 'reg_confirm_restrict_domain_placeholder' => 'No restriction set', + + // Maintenance settings + 'maint' => 'Maintenance', + 'maint_image_cleanup' => 'Cleanup Images', + 'maint_image_cleanup_desc' => "Scans page & revision content to check which images and drawings are currently in use and which images are redundant. Ensure you create a full database and image backup before running this.", + 'maint_delete_images_only_in_revisions' => 'Also delete images that only exist in old page revisions', + 'maint_image_cleanup_run' => 'Run Cleanup', + 'maint_image_cleanup_warning' => ':count potentially unused images were found. Are you sure you want to delete these images?', + 'maint_image_cleanup_success' => ':count potentially unused images found and deleted!', + 'maint_image_cleanup_nothing_found' => 'No unused images found, Nothing deleted!', + 'maint_send_test_email' => 'Send a Test Email', + 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', + 'maint_send_test_email_run' => 'Send test email', + 'maint_send_test_email_success' => 'Email sent to :address', + 'maint_send_test_email_mail_subject' => 'Test Email', + 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', + 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', + 'maint_recycle_bin_desc' => 'Deleted shelves, books, chapters & pages are sent to the recycle bin so they can be restored or permanently deleted. Older items in the recycle bin may be automatically removed after a while depending on system configuration.', + 'maint_recycle_bin_open' => 'Open Recycle Bin', + + // Recycle Bin + 'recycle_bin' => 'Recycle Bin', + 'recycle_bin_desc' => 'Here you can restore items that have been deleted or choose to permanently remove them from the system. This list is unfiltered unlike similar activity lists in the system where permission filters are applied.', + 'recycle_bin_deleted_item' => 'Deleted Item', + 'recycle_bin_deleted_by' => 'Deleted By', + 'recycle_bin_deleted_at' => 'Deletion Time', + 'recycle_bin_permanently_delete' => 'Permanently Delete', + 'recycle_bin_restore' => 'Restore', + 'recycle_bin_contents_empty' => 'The recycle bin is currently empty', + 'recycle_bin_empty' => 'Empty Recycle Bin', + 'recycle_bin_empty_confirm' => 'This will permanently destroy all items in the recycle bin including content contained within each item. Are you sure you want to empty the recycle bin?', + 'recycle_bin_destroy_confirm' => 'This action will permanently delete this item, along with any child elements listed below, from the system and you will not be able to restore this content. Are you sure you want to permanently delete this item?', + 'recycle_bin_destroy_list' => 'Items to be Destroyed', + 'recycle_bin_restore_list' => 'Items to be Restored', + 'recycle_bin_restore_confirm' => 'This action will restore the deleted item, including any child elements, to their original location. If the original location has since been deleted, and is now in the recycle bin, the parent item will also need to be restored.', + 'recycle_bin_restore_deleted_parent' => 'The parent of this item has also been deleted. These will remain deleted until that parent is also restored.', + 'recycle_bin_destroy_notification' => 'Deleted :count total items from the recycle bin.', + 'recycle_bin_restore_notification' => 'Restored :count total items from the recycle bin.', + + // Audit Log + 'audit' => 'Audit Log', + 'audit_desc' => 'This audit log displays a list of activities tracked in the system. This list is unfiltered unlike similar activity lists in the system where permission filters are applied.', + 'audit_event_filter' => 'Event Filter', + 'audit_event_filter_no_filter' => 'No Filter', + 'audit_deleted_item' => 'Deleted Item', + 'audit_deleted_item_name' => 'Name: :name', + 'audit_table_user' => 'User', + 'audit_table_event' => 'Event', + 'audit_table_related' => 'Related Item or Detail', + 'audit_table_date' => 'Activity Date', + 'audit_date_from' => 'Date Range From', + 'audit_date_to' => 'Date Range To', + + // Role Settings + 'roles' => 'Roles', + 'role_user_roles' => 'User Roles', + 'role_create' => 'Create New Role', + 'role_create_success' => 'Role successfully created', + 'role_delete' => 'Delete Role', + 'role_delete_confirm' => 'This will delete the role with the name \':roleName\'.', + 'role_delete_users_assigned' => 'This role has :userCount users assigned to it. If you would like to migrate the users from this role select a new role below.', + 'role_delete_no_migration' => "Don't migrate users", + 'role_delete_sure' => 'Are you sure you want to delete this role?', + 'role_delete_success' => 'Role successfully deleted', + 'role_edit' => 'Edit Role', + 'role_details' => 'Role Details', + 'role_name' => 'Role Name', + 'role_desc' => 'Short Description of Role', + 'role_external_auth_id' => 'External Authentication IDs', + 'role_system' => 'System Permissions', + 'role_manage_users' => 'Manage users', + 'role_manage_roles' => 'Manage roles & role permissions', + 'role_manage_entity_permissions' => 'Manage all book, chapter & page permissions', + 'role_manage_own_entity_permissions' => 'Manage permissions on own book, chapter & pages', + 'role_manage_page_templates' => 'Manage page templates', + 'role_access_api' => 'Access system API', + 'role_manage_settings' => 'Manage app settings', + 'role_asset' => 'Asset Permissions', + 'roles_system_warning' => 'Be aware that access to any of the above three permissions can allow a user to alter their own privileges or the privileges of others in the system. Only assign roles with these permissions to trusted users.', + 'role_asset_desc' => 'These permissions control default access to the assets within the system. Permissions on Books, Chapters and Pages will override these permissions.', + 'role_asset_admins' => 'Admins are automatically given access to all content but these options may show or hide UI options.', + 'role_all' => 'All', + 'role_own' => 'Own', + 'role_controlled_by_asset' => 'Controlled by the asset they are uploaded to', + 'role_save' => 'Save Role', + 'role_update_success' => 'Role successfully updated', + 'role_users' => 'Users in this role', + 'role_users_none' => 'No users are currently assigned to this role', + + // Users + 'users' => 'Users', + 'user_profile' => 'User Profile', + 'users_add_new' => 'Add New User', + 'users_search' => 'Search Users', + 'users_latest_activity' => 'Latest Activity', + 'users_details' => 'User Details', + 'users_details_desc' => 'Set a display name and an email address for this user. The email address will be used for logging into the application.', + 'users_details_desc_no_email' => 'Set a display name for this user so others can recognise them.', + 'users_role' => 'User Roles', + 'users_role_desc' => 'Select which roles this user will be assigned to. If a user is assigned to multiple roles the permissions from those roles will stack and they will receive all abilities of the assigned roles.', + 'users_password' => 'User Password', + 'users_password_desc' => 'Set a password used to log-in to the application. This must be at least 6 characters long.', + 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', + 'users_send_invite_option' => 'Send user invite email', + 'users_external_auth_id' => 'External Authentication ID', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', + 'users_password_warning' => 'Only fill the below if you would like to change your password.', + 'users_system_public' => 'This user represents any guest users that visit your instance. It cannot be used to log in but is assigned automatically.', + 'users_delete' => 'Delete User', + 'users_delete_named' => 'Delete user :userName', + 'users_delete_warning' => 'This will fully delete this user with the name \':userName\' from the system.', + 'users_delete_confirm' => 'Are you sure you want to delete this user?', + 'users_migrate_ownership' => 'Migrate Ownership', + 'users_migrate_ownership_desc' => 'Select a user here if you want another user to become the owner of all items currently owned by this user.', + 'users_none_selected' => 'No user selected', + 'users_delete_success' => 'User successfully removed', + 'users_edit' => 'Edit User', + 'users_edit_profile' => 'Edit Profile', + 'users_edit_success' => 'User successfully updated', + 'users_avatar' => 'User Avatar', + 'users_avatar_desc' => 'Select an image to represent this user. This should be approx 256px square.', + 'users_preferred_language' => 'Preferred Language', + 'users_preferred_language_desc' => 'This option will change the language used for the user-interface of the application. This will not affect any user-created content.', + 'users_social_accounts' => 'Social Accounts', + 'users_social_accounts_info' => 'Here you can connect your other accounts for quicker and easier login. Disconnecting an account here does not revoke previously authorized access. Revoke access from your profile settings on the connected social account.', + 'users_social_connect' => 'Connect Account', + 'users_social_disconnect' => 'Disconnect Account', + 'users_social_connected' => ':socialAccount account was successfully attached to your profile.', + 'users_social_disconnected' => ':socialAccount account was successfully disconnected from your profile.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token created :timeAgo', + 'user_api_token_updated' => 'Token updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', + + //! 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', + 'fr' => 'Français', + 'he' => 'עברית', + 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', + 'it' => 'Italian', + 'ja' => '日本語', + 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', + 'nl' => 'Nederlands', + 'nb' => 'Norsk (Bokmål)', + 'pl' => 'Polski', + 'pt' => 'Português', + 'pt_BR' => 'Português do Brasil', + '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/bs/validation.php b/resources/lang/bs/validation.php new file mode 100644 index 000000000..aa75dbf93 --- /dev/null +++ b/resources/lang/bs/validation.php @@ -0,0 +1,115 @@ + ':attribute mora biti prihvaćen.', + 'active_url' => ':attribute nije ispravan URL.', + 'after' => ':attribute mora biti datum nakon :date.', + 'alpha' => ':attribute može sadržavati samo slova.', + 'alpha_dash' => ':attribute može sadržavati samo slova, brojeve, crtice i donje crtice.', + 'alpha_num' => ':attribute može sadržavati samo slova i brojeve.', + 'array' => ':attribute mora biti niz.', + 'before' => ':attribute mora biti datum prije :date.', + 'between' => [ + 'numeric' => ':attribute mora biti između :min i :max.', + 'file' => ':attribute mora biti između :min i :max kilobajta.', + 'string' => ':attribute mora biti između :min i :max karaktera.', + 'array' => ':attribute mora imati između :min i :max stavki.', + ], + 'boolean' => ':attribute polje mora biti tačno ili netačno.', + 'confirmed' => ':attribute potvrda se ne slaže.', + 'date' => ':attribute nije ispravan datum.', + 'date_format' => ':attribute ne odgovara formatu :format.', + 'different' => ':attribute i :other moraju biti različiti.', + 'digits' => ':attribute mora imati :digits brojeve.', + 'digits_between' => ':attribute mora imati između :min i :max brojeva.', + 'email' => ':attribute mora biti ispravna e-mail adresa.', + 'ends_with' => ':attribute mora završavati sa jednom od sljedećih: :values', + 'filled' => 'Polje :attribute je obavezno.', + 'gt' => [ + 'numeric' => ':attribute mora biti veći od :value.', + 'file' => ':attribute mota biti veći od :value kilobajta.', + 'string' => ':attribute mora imati više od :value karaktera.', + 'array' => ':attribute mora imati više od :value stavki.', + ], + 'gte' => [ + 'numeric' => ':attribute mora biti veći od ili jednak :value.', + 'file' => ':attribute mora imati više od ili jednako :value kilobajta.', + 'string' => ':attribute mora imati više od ili jednako :value karaktera.', + 'array' => ':attribute mora imati :value stavki ili više.', + ], + 'exists' => 'Odabrani :attribute je neispravan.', + 'image' => ':attribute mora biti slika.', + 'image_extension' => ':attribute mora imati ispravnu i podržanu ekstenziju slike.', + 'in' => 'Odabrani :attribute je neispravan.', + 'integer' => ':attribute mora biti integer.', + 'ip' => ':attribute mora biti ispravna IP adresa.', + 'ipv4' => ':attribute mora biti ispravna IPv4 adresa.', + 'ipv6' => ':attribute mora biti ispravna IPv6 adresa.', + 'json' => ':attribute mora biti ispravan JSON string.', + 'lt' => [ + 'numeric' => ':attribute mora biti manji od :value.', + 'file' => ':attribute mora imati manje od :value kilobajta.', + 'string' => ':attribute mora imati manje od :value karaktera.', + 'array' => ':attribute mora imati manje od :value stavki.', + ], + 'lte' => [ + 'numeric' => ':attribute mora imati vrijednost manju od ili jednaku :value.', + 'file' => ':attribute mora imati manje od ili jednako :value kilobajta.', + 'string' => ':attribute mora imati manje od ili jednako :value karaktera.', + 'array' => ':attribute ne smije imati više od :value stavki.', + ], + 'max' => [ + 'numeric' => ':attribute ne može biti veći od :max.', + 'file' => ':attribute ne može imati više od :max kilobajta.', + 'string' => ':attribute ne može imati više od :max karaktera.', + 'array' => ':attribute ne može imati više od :max stavki.', + ], + 'mimes' => ':attribute mora biti fajl vrste: values.', + 'min' => [ + 'numeric' => ':attribute mora biti najmanje :min.', + 'file' => ':attribute mora imati najmanje :min kilobajta.', + 'string' => ':attribute mora imati najmanje :min karaktera.', + 'array' => ':attribute mora imati najmanje :min stavki.', + ], + 'no_double_extension' => ':attribute mora imati samo jednu fajl ekstenziju.', + 'not_in' => 'Odabrani :attribute je neispravan.', + 'not_regex' => 'Format :attribute je neispravan.', + 'numeric' => ':attribute mora biti broj.', + 'regex' => 'Format :attribute je neispravan.', + 'required' => 'Polje :attribute je obavezno.', + 'required_if' => 'Polje :attribute je obavezno kada :other ima vrijednost :value.', + 'required_with' => 'Polje :attribute je obavezno kada su prisutne :values.', + 'required_with_all' => 'Polje :attribute je obavezno kada su prisutne :values.', + 'required_without' => 'Polje :attribute je obavezno kada :values nisu prisutne.', + 'required_without_all' => 'Polje :attribute je obavezno kada nijedno od :values nije prisutno.', + 'same' => ':attribute i :other se moraju poklapati.', + 'safe_url' => 'Navedeni link možda nije siguran.', + 'size' => [ + 'numeric' => ':attribute mora biti :size.', + 'file' => ':attribute mora imati :size kilobajta.', + 'string' => ':attribute mora imati :size karaktera.', + 'array' => ':attribute mora sadržavati :size stavki.', + ], + 'string' => ':attribute mora biti string.', + 'timezone' => ':attribute mora biti ispravna zona.', + 'unique' => ':attribute je zauzet.', + 'url' => 'Format :attribute je neispravan.', + 'uploaded' => 'Fajl nije učitan. Server ne prihvata fajlove ove veličine.', + + // Custom validation lines + 'custom' => [ + 'password-confirm' => [ + 'required_with' => 'Zahtijeva se potvrda lozinke', + ], + ], + + // Custom validation attributes + 'attributes' => [], +]; diff --git a/resources/lang/ca/activities.php b/resources/lang/ca/activities.php new file mode 100644 index 000000000..38e4d4eb5 --- /dev/null +++ b/resources/lang/ca/activities.php @@ -0,0 +1,49 @@ + 'ha creat la pàgina', + 'page_create_notification' => 'Pàgina creada correctament', + 'page_update' => 'ha actualitzat la pàgina', + 'page_update_notification' => 'Pàgina actualitzada correctament', + 'page_delete' => 'ha suprimit una pàgina', + 'page_delete_notification' => 'Pàgina suprimida correctament', + 'page_restore' => 'ha restaurat la pàgina', + 'page_restore_notification' => 'Pàgina restaurada correctament', + 'page_move' => 'ha mogut la pàgina', + + // Chapters + 'chapter_create' => 'ha creat el capítol', + 'chapter_create_notification' => 'Capítol creat correctament', + 'chapter_update' => 'ha actualitzat el capítol', + 'chapter_update_notification' => 'Capítol actualitzat correctament', + 'chapter_delete' => 'ha suprimit un capítol', + 'chapter_delete_notification' => 'Capítol suprimit correctament', + 'chapter_move' => 'ha mogut el capítol', + + // Books + 'book_create' => 'ha creat el llibre', + 'book_create_notification' => 'Llibre creat correctament', + 'book_update' => 'ha actualitzat el llibre', + 'book_update_notification' => 'Llibre actualitzat correctament', + 'book_delete' => 'ha suprimit un llibre', + 'book_delete_notification' => 'Llibre suprimit correctament', + 'book_sort' => 'ha ordenat el llibre', + 'book_sort_notification' => 'Llibre reordenat correctament', + + // Bookshelves + 'bookshelf_create' => 'ha creat el prestatge', + 'bookshelf_create_notification' => 'Prestatge creat correctament', + 'bookshelf_update' => 'ha actualitzat el prestatge', + 'bookshelf_update_notification' => 'Prestatge actualitzat correctament', + 'bookshelf_delete' => 'ha suprimit un prestatge', + 'bookshelf_delete_notification' => 'Prestatge suprimit correctament', + + // Other + 'commented_on' => 'ha comentat a', + 'permissions_update' => 'ha actualitzat els permisos', +]; diff --git a/resources/lang/ca/auth.php b/resources/lang/ca/auth.php new file mode 100644 index 000000000..e6d15e898 --- /dev/null +++ b/resources/lang/ca/auth.php @@ -0,0 +1,77 @@ + 'Les credencials no coincideixen amb les que tenim emmagatzemades.', + 'throttle' => 'Massa intents d\'iniciar la sessió. Torneu-ho a provar d\'aquí a :seconds segons.', + + // Login & Register + 'sign_up' => 'Registra-m\'hi', + 'log_in' => 'Inicia la sessió', + 'log_in_with' => 'Inicia la sessió amb :socialDriver', + 'sign_up_with' => 'Registra-m\'hi amb :socialDriver', + 'logout' => 'Tanca la sessió', + + 'name' => 'Nom', + 'username' => 'Nom d\'usuari', + 'email' => 'Adreça electrònica', + 'password' => 'Contrasenya', + 'password_confirm' => 'Confirmeu la contrasenya', + 'password_hint' => 'Cal que tingui més de 7 caràcters', + 'forgot_password' => 'Heu oblidat la contrasenya?', + 'remember_me' => 'Recorda\'m', + 'ldap_email_hint' => 'Introduïu una adreça electrònica per a aquest compte.', + 'create_account' => 'Crea el compte', + 'already_have_account' => 'Ja teniu un compte?', + 'dont_have_account' => 'No teniu cap compte?', + 'social_login' => 'Inici de sessió social', + 'social_registration' => 'Registre social', + 'social_registration_text' => 'Registreu-vos i inicieu la sessió fent servir un altre servei.', + + 'register_thanks' => 'Gràcies per registrar-vos!', + 'register_confirm' => 'Reviseu el vostre correu electrònic i feu clic al botó de confirmació per a accedir a :appName.', + 'registrations_disabled' => 'Actualment, els registres estan desactivats', + 'registration_email_domain_invalid' => 'Aquest domini de correu electrònic no té accés a aquesta aplicació', + 'register_success' => 'Gràcies per registrar-vos! Ja us hi heu registrat i heu iniciat la sessió.', + + + // Password Reset + 'reset_password' => 'Restableix la contrasenya', + 'reset_password_send_instructions' => 'Introduïu la vostra adreça electrònica a continuació i us enviarem un correu electrònic amb un enllaç per a restablir la contrasenya.', + 'reset_password_send_button' => 'Envia l\'enllaç de restabliment', + 'reset_password_sent' => 'S\'enviarà un enllaç per a restablir la contrasenya a :email, si es troba aquesta adreça al sistema.', + 'reset_password_success' => 'La vostra contrasenya s\'ha restablert correctament.', + 'email_reset_subject' => 'Restabliu la contrasenya a :appName', + 'email_reset_text' => 'Rebeu aquest correu electrònic perquè heu rebut una petició de restabliment de contrasenya per al vostre compte.', + 'email_reset_not_requested' => 'Si no heu demanat restablir la contrasenya, no cal que prengueu cap acció.', + + + // Email Confirmation + 'email_confirm_subject' => 'Confirmeu la vostra adreça electrònica a :appName', + 'email_confirm_greeting' => 'Gràcies per unir-vos a :appName!', + 'email_confirm_text' => 'Confirmeu la vostra adreça electrònica fent clic al botó a continuació:', + 'email_confirm_action' => 'Confirma el correu', + 'email_confirm_send_error' => 'Cal confirmar l\'adreça electrònica, però el sistema no ha pogut enviar el correu electrònic. Poseu-vos en contacte amb l\'administrador perquè s\'asseguri que el correu electrònic està ben configurat.', + 'email_confirm_success' => 'S\'ha confirmat el vostre correu electrònic!', + 'email_confirm_resent' => 'S\'ha tornat a enviar el correu electrònic de confirmació. Reviseu la vostra safata d\'entrada.', + + 'email_not_confirmed' => 'Adreça electrònica no confirmada', + 'email_not_confirmed_text' => 'La vostra adreça electrònica encara no està confirmada.', + 'email_not_confirmed_click_link' => 'Feu clic a l\'enllaç del correu electrònic que us vam enviar poc després que us registréssiu.', + 'email_not_confirmed_resend' => 'Si no podeu trobar el correu, podeu tornar a enviar el correu electrònic de confirmació enviant el formulari a continuació.', + 'email_not_confirmed_resend_button' => 'Torna a enviar el correu de confirmació', + + // User Invite + 'user_invite_email_subject' => 'Us han convidat a unir-vos a :appName!', + 'user_invite_email_greeting' => 'Us hem creat un compte en el vostre nom a :appName.', + 'user_invite_email_text' => 'Feu clic al botó a continuació per a definir una contrasenya per al compte i obtenir-hi accés:', + 'user_invite_email_action' => 'Defineix una contrasenya per al compte', + 'user_invite_page_welcome' => 'Us donem la benvinguda a :appName!', + 'user_invite_page_text' => 'Per a enllestir el vostre compte i obtenir-hi accés, cal que definiu una contrasenya, que es farà servir per a iniciar la sessió a :appName en futures visites.', + 'user_invite_page_confirm_button' => 'Confirma la contrasenya', + 'user_invite_success' => 'S\'ha establert la contrasenya, ara ja teniu accés a :appName!' +]; \ No newline at end of file diff --git a/resources/lang/ca/common.php b/resources/lang/ca/common.php new file mode 100644 index 000000000..ddf92f3cb --- /dev/null +++ b/resources/lang/ca/common.php @@ -0,0 +1,85 @@ + 'Cancel·la', + 'confirm' => 'D\'acord', + 'back' => 'Endarrere', + 'save' => 'Desa', + 'continue' => 'Continua', + 'select' => 'Selecciona', + 'toggle_all' => 'Commuta-ho tot', + 'more' => 'Més', + + // Form Labels + 'name' => 'Nom', + 'description' => 'Descripció', + 'role' => 'Rol', + 'cover_image' => 'Imatge de portada', + 'cover_image_description' => 'Aquesta imatge hauria de fer aproximadament 440x250 px.', + + // Actions + 'actions' => 'Accions', + 'view' => 'Visualitza', + 'view_all' => 'Visualitza-ho tot', + 'create' => 'Crea', + 'update' => 'Actualitza', + 'edit' => 'Edita', + 'sort' => 'Ordena', + 'move' => 'Mou', + 'copy' => 'Copia', + 'reply' => 'Respon', + 'delete' => 'Suprimeix', + 'delete_confirm' => 'Confirma la supressió', + 'search' => 'Cerca', + 'search_clear' => 'Esborra la cerca', + 'reset' => 'Reinicialitza', + 'remove' => 'Elimina', + 'add' => 'Afegeix', + 'fullscreen' => 'Pantalla completa', + + // Sort Options + 'sort_options' => 'Opcions d\'ordenació', + 'sort_direction_toggle' => 'Commuta la direcció de l\'ordenació', + 'sort_ascending' => 'Ordre ascendent', + 'sort_descending' => 'Ordre descendent', + 'sort_name' => 'Nom', + 'sort_created_at' => 'Data de creació', + 'sort_updated_at' => 'Data d\'actualització', + + // Misc + 'deleted_user' => 'Usuari eliminat', + 'no_activity' => 'No hi ha activitat', + 'no_items' => 'No hi ha cap element', + 'back_to_top' => 'Torna a dalt', + 'toggle_details' => 'Commuta els detalls', + 'toggle_thumbnails' => 'Commuta les miniatures', + 'details' => 'Detalls', + 'grid_view' => 'Visualització en graella', + 'list_view' => 'Visualització en llista', + 'default' => 'Per defecte', + 'breadcrumb' => 'Ruta de navegació', + + // Header + 'profile_menu' => 'Menú del perfil', + 'view_profile' => 'Mostra el perfil', + 'edit_profile' => 'Edita el perfil', + 'dark_mode' => 'Mode fosc', + 'light_mode' => 'Mode clar', + + // Layout tabs + 'tab_info' => 'Informació', + 'tab_content' => 'Contingut', + + // Email Content + 'email_action_help' => 'Si teniu problemes per fer clic al botó ":actionText", copieu i enganxeu l\'URL següent al vostre navegador web:', + 'email_rights' => 'Tots els drets reservats', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Política de privadesa', + 'terms_of_service' => 'Condicions del servei', +]; diff --git a/resources/lang/ca/components.php b/resources/lang/ca/components.php new file mode 100644 index 000000000..d96582da7 --- /dev/null +++ b/resources/lang/ca/components.php @@ -0,0 +1,34 @@ + 'Selecciona una imatge', + 'image_all' => 'Totes', + 'image_all_title' => 'Mostra totes les imatges', + 'image_book_title' => 'Mostra les imatges pujades a aquest llibre', + 'image_page_title' => 'Mostra les imatges pujades a aquesta pàgina', + 'image_search_hint' => 'Cerca per nom d\'imatge', + 'image_uploaded' => 'Pujada :uploadedDate', + 'image_load_more' => 'Carrega\'n més', + 'image_image_name' => 'Nom de la imatge', + 'image_delete_used' => 'Aquesta imatge s\'utilitza a les pàgines següents.', + 'image_delete_confirm_text' => 'Segur que voleu suprimir aquesta imatge?', + 'image_select_image' => 'Selecciona una imatge', + 'image_dropzone' => 'Arrossegueu imatges o feu clic aquí per a pujar-les', + 'images_deleted' => 'Imatges suprimides', + 'image_preview' => 'Previsualització de la imatge', + 'image_upload_success' => 'Imatge pujada correctament', + 'image_update_success' => 'Detalls de la imatge actualitzats correctament', + 'image_delete_success' => 'Imatge suprimida correctament', + 'image_upload_remove' => 'Suprimeix', + + // Code Editor + 'code_editor' => 'Edita el codi', + 'code_language' => 'Llenguatge del codi', + 'code_content' => 'Contingut del codi', + 'code_session_history' => 'Historial de la sessió', + 'code_save' => 'Desa el codi', +]; diff --git a/resources/lang/ca/entities.php b/resources/lang/ca/entities.php new file mode 100644 index 000000000..bcb1b8679 --- /dev/null +++ b/resources/lang/ca/entities.php @@ -0,0 +1,319 @@ + 'Creat fa poc', + 'recently_created_pages' => 'Pàgines creades fa poc', + 'recently_updated_pages' => 'Pàgines actualitzades fa poc', + 'recently_created_chapters' => 'Capítols creats fa poc', + 'recently_created_books' => 'Llibres creats fa poc', + 'recently_created_shelves' => 'Prestatges creats fa poc', + 'recently_update' => 'Actualitzat fa poc', + 'recently_viewed' => 'Vist fa poc', + 'recent_activity' => 'Activitat recent', + 'create_now' => 'Crea\'n ara', + 'revisions' => 'Revisions', + 'meta_revision' => 'Revisió núm. :revisionCount', + 'meta_created' => 'Creat :timeLength', + 'meta_created_name' => 'Creat :timeLength per :user', + 'meta_updated' => 'Actualitzat :timeLength', + 'meta_updated_name' => 'Actualitzat :timeLength per :user', + 'meta_owned_name' => 'Propietat de :user', + 'entity_select' => 'Selecciona una entitat', + 'images' => 'Imatges', + 'my_recent_drafts' => 'Els vostres esborranys recents', + 'my_recently_viewed' => 'Les vostres visualitzacions recents', + 'no_pages_viewed' => 'No heu vist cap pàgina', + 'no_pages_recently_created' => 'No s\'ha creat cap pàgina fa poc', + 'no_pages_recently_updated' => 'No s\'ha actualitzat cap pàgina fa poc', + 'export' => 'Exporta', + 'export_html' => 'Fitxer web independent', + 'export_pdf' => 'Fitxer PDF', + 'export_text' => 'Fitxer de text sense format', + + // 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_save' => 'Desa els permisos', + 'permissions_owner' => 'Propietari', + + // Search + 'search_results' => 'Resultats de la cerca', + 'search_total_results_found' => 'S\'ha trobat :count resultat en total|S\'han trobat :count resultats en total', + 'search_clear' => 'Esborra la cerca', + 'search_no_pages' => 'La cerca no coincideix amb cap pàgina', + 'search_for_term' => 'Cerca :term', + 'search_more' => 'Més resultats', + 'search_advanced' => 'Cerca avançada', + 'search_terms' => 'Termes de la cerca', + 'search_content_type' => 'Tipus de contingut', + 'search_exact_matches' => 'Coincidències exactes', + 'search_tags' => 'Cerca d\'etiquetes', + 'search_options' => 'Opcions', + 'search_viewed_by_me' => 'Visualitzat per mi', + 'search_not_viewed_by_me' => 'No visualitzat per mi', + 'search_permissions_set' => 'Amb permisos definits', + 'search_created_by_me' => 'Creat per mi', + 'search_updated_by_me' => 'Actualitzat per mi', + 'search_date_options' => 'Opcions de dates', + 'search_updated_before' => 'Actualitzat abans de', + 'search_updated_after' => 'Actualitzat després de', + 'search_created_before' => 'Creat abans de', + 'search_created_after' => 'Creat després de', + 'search_set_date' => 'Defineix una data', + 'search_update' => 'Actualitza la cerca', + + // Shelves + 'shelf' => 'Prestatge', + 'shelves' => 'Prestatges', + 'x_shelves' => ':count prestatge|:count prestatges', + 'shelves_long' => 'Prestatges', + 'shelves_empty' => 'No hi ha cap prestatge creat', + 'shelves_create' => 'Crea un prestatge nou', + 'shelves_popular' => 'Prestatges populars', + 'shelves_new' => 'Prestatges nous', + 'shelves_new_action' => 'Prestatge nou', + 'shelves_popular_empty' => 'Aquí apareixeran els prestatges més populars.', + 'shelves_new_empty' => 'Aquí apareixeran els prestatges creats fa poc.', + 'shelves_save' => 'Desa el prestatge', + 'shelves_books' => 'Llibres en aquest prestatge', + 'shelves_add_books' => 'Afegeix llibres a aquest prestatge', + 'shelves_drag_books' => 'Arrossegueu llibres aquí per a afegir-los a aquest prestatge', + 'shelves_empty_contents' => 'Aquest prestatge no té cap llibre assignat', + 'shelves_edit_and_assign' => 'Editeu el prestatge per a assignar-hi llibres', + 'shelves_edit_named' => 'Edita el prestatge :name', + 'shelves_edit' => 'Edita el prestatge', + 'shelves_delete' => 'Suprimeix el prestatge', + 'shelves_delete_named' => 'Suprimeix el prestatge :name', + 'shelves_delete_explain' => "Se suprimirà el prestatge amb el nom ':name'. Els llibres que contingui no se suprimiran.", + 'shelves_delete_confirmation' => 'Segur que voleu suprimir aquest prestatge?', + 'shelves_permissions' => 'Permisos del prestatge', + 'shelves_permissions_updated' => 'S\'han actualitzat els permisos del prestatge', + 'shelves_permissions_active' => 'S\'han activat els permisos del prestatge', + 'shelves_copy_permissions_to_books' => 'Copia els permisos als llibres', + 'shelves_copy_permissions' => 'Copia els permisos', + 'shelves_copy_permissions_explain' => 'Això aplicarà la configuració de permisos actual d\'aquest prestatge a tots els llibres que contingui. Abans d\'activar-ho, assegureu-vos que hàgiu desat qualsevol canvi als permisos d\'aquest prestatge.', + 'shelves_copy_permission_success' => 'S\'han copiat els permisos del prestatge a :count llibres', + + // Books + 'book' => 'Llibre', + 'books' => 'Llibres', + 'x_books' => ':count llibre|:count llibres', + 'books_empty' => 'No hi ha cap llibre creat', + 'books_popular' => 'Llibres populars', + 'books_recent' => 'Llibres recents', + 'books_new' => 'Llibres nous', + 'books_new_action' => 'Llibre nou', + 'books_popular_empty' => 'Aquí apareixeran els llibres més populars.', + 'books_new_empty' => 'Aquí apareixeran els llibres creats fa poc.', + 'books_create' => 'Crea un llibre nou', + 'books_delete' => 'Suprimeix el llibre', + 'books_delete_named' => 'Suprimeix el llibre :bookName', + 'books_delete_explain' => 'Se suprimirà el llibre amb el nom \':bookName\'. Se\'n suprimiran les pàgines i els capítols.', + 'books_delete_confirmation' => 'Segur que voleu suprimir aquest llibre?', + 'books_edit' => 'Edita el llibre', + 'books_edit_named' => 'Edita el llibre :bookName', + 'books_form_book_name' => 'Nom del llibre', + 'books_save' => 'Desa el llibre', + 'books_permissions' => 'Permisos del llibre', + 'books_permissions_updated' => 'S\'han actualitzat els permisos del llibre', + 'books_empty_contents' => 'No hi ha cap pàgina ni cap capítol creat en aquest llibre.', + 'books_empty_create_page' => 'Crea una pàgina nova', + 'books_empty_sort_current_book' => 'Ordena el llibre actual', + 'books_empty_add_chapter' => 'Afegeix un capítol', + 'books_permissions_active' => 'S\'han activat els permisos del llibre', + 'books_search_this' => 'Cerca en aquest llibre', + 'books_navigation' => 'Navegació pel llibre', + 'books_sort' => 'Ordena el contingut del llibre', + 'books_sort_named' => 'Ordena el llibre :bookName', + 'books_sort_name' => 'Ordena per nom', + 'books_sort_created' => 'Ordena per data de creació', + 'books_sort_updated' => 'Ordena per data d\'actualització', + 'books_sort_chapters_first' => 'Els capítols al principi', + 'books_sort_chapters_last' => 'Els capítols al final', + 'books_sort_show_other' => 'Mostra altres llibres', + 'books_sort_save' => 'Desa l\'ordre nou', + + // Chapters + 'chapter' => 'Capítol', + 'chapters' => 'Capítols', + 'x_chapters' => ':count capítol|:count capítols', + 'chapters_popular' => 'Capítols populars', + 'chapters_new' => 'Capítol nou', + 'chapters_create' => 'Crea un capítol nou', + 'chapters_delete' => 'Suprimeix el capítol', + 'chapters_delete_named' => 'Suprimeix el capítol :chapterName', + 'chapters_delete_explain' => 'Se suprimirà el capítol amb el nom \':chapterName\'. Totes les pàgines que contingui també se suprimiran.', + 'chapters_delete_confirm' => 'Segur que voleu suprimir aquest capítol?', + 'chapters_edit' => 'Edita el capítol', + 'chapters_edit_named' => 'Edita el capítol :chapterName', + 'chapters_save' => 'Desa el capítol', + 'chapters_move' => 'Mou el capítol', + 'chapters_move_named' => 'Mou el capítol :chapterName', + 'chapter_move_success' => 'S\'ha mogut el capítol a :bookName', + 'chapters_permissions' => 'Permisos del capítol', + 'chapters_empty' => 'De moment, aquest capítol no conté cap pàgina.', + 'chapters_permissions_active' => 'S\'han activat els permisos del capítol', + 'chapters_permissions_success' => 'S\'han actualitzat els permisos del capítol', + 'chapters_search_this' => 'Cerca en aquest capítol', + + // Pages + 'page' => 'Pàgina', + 'pages' => 'Pàgines', + 'x_pages' => ':count pàgina|:count pàgines', + 'pages_popular' => 'Pàgines populars', + 'pages_new' => 'Pàgina nova', + 'pages_attachments' => 'Adjuncions', + 'pages_navigation' => 'Navegació per la pàgina', + 'pages_delete' => 'Suprimeix la pàgina', + 'pages_delete_named' => 'Suprimeix la pàgina :pageName', + 'pages_delete_draft_named' => 'Suprimeix l\'esborrany de pàgina :pageName', + 'pages_delete_draft' => 'Suprimeix l\'esborrany de pàgina', + 'pages_delete_success' => 'S\'ha suprimit la pàgina', + 'pages_delete_draft_success' => 'S\'ha suprimit l\'esborrany de pàgina', + 'pages_delete_confirm' => 'Segur que voleu suprimir aquesta pàgina?', + 'pages_delete_draft_confirm' => 'Segur que voleu suprimir aquest esborrany de pàgina?', + 'pages_editing_named' => 'Esteu editant :pageName', + 'pages_edit_draft_options' => 'Opcions d\'esborrany', + 'pages_edit_save_draft' => 'Desa l\'esborrany', + 'pages_edit_draft' => 'Edita l\'esborrany de pàgina', + 'pages_editing_draft' => 'Esteu editant l\'esborrany', + 'pages_editing_page' => 'Esteu editant la pàgina', + 'pages_edit_draft_save_at' => 'Esborrany desat ', + 'pages_edit_delete_draft' => 'Suprimeix l\'esborrany', + 'pages_edit_discard_draft' => 'Descarta l\'esborrany', + 'pages_edit_set_changelog' => 'Defineix el registre de canvis', + 'pages_edit_enter_changelog_desc' => 'Introduïu una breu descripció dels canvis que heu fet', + 'pages_edit_enter_changelog' => 'Introduïu un registre de canvis', + 'pages_save' => 'Desa la pàgina', + 'pages_title' => 'Títol de la pàgina', + 'pages_name' => 'Nom de la pàgina', + 'pages_md_editor' => 'Editor', + 'pages_md_preview' => 'Previsualització', + 'pages_md_insert_image' => 'Insereix una imatge', + 'pages_md_insert_link' => 'Insereix un enllaç a una entitat', + 'pages_md_insert_drawing' => 'Insereix un diagrama', + 'pages_not_in_chapter' => 'La pàgina no pertany a cap capítol', + 'pages_move' => 'Mou la pàgina', + 'pages_move_success' => 'S\'ha mogut la pàgina a ":parentName"', + 'pages_copy' => 'Copia la pàgina', + 'pages_copy_desination' => 'Destinació de la còpia', + 'pages_copy_success' => 'Pàgina copiada correctament', + 'pages_permissions' => 'Permisos de la pàgina', + 'pages_permissions_success' => 'S\'han actualitzat els permisos de la pàgina', + 'pages_revision' => 'Revisió', + 'pages_revisions' => 'Revisions de la pàgina', + 'pages_revisions_named' => 'Revisions de la pàgina :pageName', + 'pages_revision_named' => 'Revisió de la pàgina :pageName', + 'pages_revision_restored_from' => 'Restaurada de núm. :id; :summary', + 'pages_revisions_created_by' => 'Creada per', + 'pages_revisions_date' => 'Data de la revisió', + 'pages_revisions_number' => 'Núm. ', + 'pages_revisions_numbered' => 'Revisió núm. :id', + 'pages_revisions_numbered_changes' => 'Canvis de la revisió núm. :id', + 'pages_revisions_changelog' => 'Registre de canvis', + 'pages_revisions_changes' => 'Canvis', + 'pages_revisions_current' => 'Versió actual', + 'pages_revisions_preview' => 'Previsualitza', + 'pages_revisions_restore' => 'Restaura', + 'pages_revisions_none' => 'Aquesta pàgina no té cap revisió', + 'pages_copy_link' => 'Copia l\'enllaç', + 'pages_edit_content_link' => 'Edita el contingut', + 'pages_permissions_active' => 'S\'han activat els permisos de la pàgina', + 'pages_initial_revision' => 'Publicació inicial', + 'pages_initial_name' => 'Pàgina nova', + 'pages_editing_draft_notification' => 'Esteu editant un esborrany que es va desar per darrer cop :timeDiff.', + 'pages_draft_edited_notification' => 'Aquesta pàgina s\'ha actualitzat d\'ençà d\'aleshores. Us recomanem que descarteu aquest esborrany.', + 'pages_draft_edit_active' => [ + 'start_a' => ':count usuaris han començat a editar aquesta pàgina', + 'start_b' => ':userName ha començat a editar aquesta pàgina', + 'time_a' => 'd\'ençà que la pàgina es va actualitzar per darrer cop', + 'time_b' => 'en els darrers :minCount minuts', + 'message' => ':start :time. Aneu amb compte de no trepitjar-vos les actualitzacions entre vosaltres!', + ], + 'pages_draft_discarded' => 'S\'ha descartat l\'esborrany, l\'editor s\'ha actualitzat amb el contingut actual de la pàgina', + 'pages_specific' => 'Una pàgina específica', + 'pages_is_template' => 'Plantilla de pàgina', + + // Editor Sidebar + 'page_tags' => 'Etiquetes de la pàgina', + 'chapter_tags' => 'Etiquetes del capítol', + 'book_tags' => 'Etiquetes del llibre', + 'shelf_tags' => 'Etiquetes del prestatge', + 'tag' => 'Etiqueta', + 'tags' => 'Etiquetes', + 'tag_name' => 'Nom de l\'etiqueta', + 'tag_value' => 'Valor de l\'etiqueta (opcional)', + 'tags_explain' => "Afegiu etiquetes per a categoritzar millor el contingut. \n Podeu assignar un valor a cada etiqueta per a una organització més detallada.", + 'tags_add' => 'Afegeix una altra etiqueta', + 'tags_remove' => 'Elimina aquesta etiqueta', + 'attachments' => 'Adjuncions', + 'attachments_explain' => 'Pugeu fitxers o adjunteu enllaços per a mostrar-los a la pàgina. Són visibles a la barra lateral de la pàgina.', + 'attachments_explain_instant_save' => 'Els canvis fets aquí es desen instantàniament.', + 'attachments_items' => 'Elements adjunts', + 'attachments_upload' => 'Puja un fitxer', + 'attachments_link' => 'Adjunta un enllaç', + 'attachments_set_link' => 'Defineix l\'enllaç', + 'attachments_delete' => 'Seguir que voleu suprimir aquesta adjunció?', + 'attachments_dropzone' => 'Arrossegueu fitxers o feu clic aquí per a adjuntar un fitxer', + 'attachments_no_files' => 'No s\'ha pujat cap fitxer', + 'attachments_explain_link' => 'Podeu adjuntar un enllaç si preferiu no pujar un fitxer. Pot ser un enllaç a una altra pàgina o un enllaç a un fitxer al núvol.', + 'attachments_link_name' => 'Nom de l\'enllaç', + 'attachment_link' => 'Enllaç de l\'adjunció', + 'attachments_link_url' => 'Enllaç al fitxer', + 'attachments_link_url_hint' => 'URL del lloc o fitxer', + 'attach' => 'Adjunta', + 'attachments_insert_link' => 'Afegeix un enllaç de l\'adjunció a la pàgina', + 'attachments_edit_file' => 'Edita el fitxer', + 'attachments_edit_file_name' => 'Nom del fitxer', + 'attachments_edit_drop_upload' => 'Arrossegueu fitxers o feu clic aquí per a pujar-los i sobreescriure\'ls', + 'attachments_order_updated' => 'S\'ha actualitzat l\'ordre de les adjuncions', + 'attachments_updated_success' => 'S\'han actualitzat els detalls de les adjuncions', + 'attachments_deleted' => 'S\'ha suprimit l\'adjunció', + 'attachments_file_uploaded' => 'Fitxer pujat correctament', + 'attachments_file_updated' => 'Fitxer actualitzat correctament', + 'attachments_link_attached' => 'Enllaç adjuntat a la pàgina correctament', + 'templates' => 'Plantilles', + 'templates_set_as_template' => 'La pàgina és una plantilla', + 'templates_explain_set_as_template' => 'Podeu definir aquesta pàgina com a plantilla perquè el seu contingut es pugui fer servir en crear altres pàgines. Els altres usuaris podran fer servir la plantilla si tenen permís per a veure aquesta pàgina.', + 'templates_replace_content' => 'Substitueix el contingut de la pàgina', + 'templates_append_content' => 'Afegeix al final del contingut de la pàgina', + 'templates_prepend_content' => 'Afegeix al principi del contingut de la pàgina', + + // Profile View + 'profile_user_for_x' => 'Usuari fa :time', + 'profile_created_content' => 'Contingut creat', + 'profile_not_created_pages' => ':userName no ha creat cap pàgina', + 'profile_not_created_chapters' => ':userName no ha creat cap capítol', + 'profile_not_created_books' => ':userName no ha creat cap llibre', + 'profile_not_created_shelves' => ':userName no ha creat cap prestatge', + + // Comments + 'comment' => 'Comentari', + 'comments' => 'Comentaris', + 'comment_add' => 'Afegeix un comentari', + 'comment_placeholder' => 'Deixeu un comentari aquí', + 'comment_count' => '{0} Sense comentaris|{1} 1 comentari|[2,*] :count comentaris', + 'comment_save' => 'Desa el comentari', + 'comment_saving' => 'S\'està desant el comentari...', + 'comment_deleting' => 'S\'està suprimint el comentari...', + 'comment_new' => 'Comentari nou', + 'comment_created' => 'ha comentat :createDiff', + 'comment_updated' => 'Actualitzat :updateDiff per :username', + 'comment_deleted_success' => 'Comentari suprimit', + 'comment_created_success' => 'Comentari afegit', + 'comment_updated_success' => 'Comentari actualitzat', + 'comment_delete_confirm' => 'Segur que voleu suprimir aquest comentari?', + 'comment_in_reply_to' => 'En resposta a :commentId', + + // Revision + 'revision_delete_confirm' => 'Segur que voleu suprimir aquesta revisió?', + 'revision_restore_confirm' => 'Segur que voleu restaurar aquesta revisió? Se substituirà el contingut de la pàgina actual.', + 'revision_delete_success' => 'S\'ha suprimit la revisió', + 'revision_cannot_delete_latest' => 'No es pot suprimir la darrera revisió.' +]; \ No newline at end of file diff --git a/resources/lang/ca/errors.php b/resources/lang/ca/errors.php new file mode 100644 index 000000000..22b8d542c --- /dev/null +++ b/resources/lang/ca/errors.php @@ -0,0 +1,102 @@ + 'No teniu permís per a accedir a la pàgina sol·licitada.', + 'permissionJson' => 'No teniu permís per a executar l\'acció sol·licitada.', + + // Auth + 'error_user_exists_different_creds' => 'Ja hi ha un usuari amb l\'adreça electrònica :email però amb credencials diferents.', + 'email_already_confirmed' => 'L\'adreça electrònica ja està confirmada. Proveu d\'iniciar la sessió.', + 'email_confirmation_invalid' => 'Aquest testimoni de confirmació no és vàlid o ja ha estat utilitzat. Proveu de tornar-vos a registrar.', + 'email_confirmation_expired' => 'El testimoni de confirmació ha caducat. S\'ha enviat un nou correu electrònic de confirmació.', + 'email_confirmation_awaiting' => 'Cal confirmar l\'adreça electrònica del compte que utilitzeu', + 'ldap_fail_anonymous' => 'L\'accés a l\'LDAP ha fallat fent servir un lligam anònim', + 'ldap_fail_authed' => 'L\'accés a l\'LDAP ha fallat fent servir els detalls de DN i contrasenya proporcionats', + 'ldap_extension_not_installed' => 'L\'extensió de l\'LDAP de PHP no està instal·lada', + 'ldap_cannot_connect' => 'No s\'ha pogut connectar amb el servidor de l\'LDAP, la connexió inicial ha fallat', + 'saml_already_logged_in' => 'Ja heu iniciat la sessió', + 'saml_user_not_registered' => 'L\'usuari :name no està registrat i els registres automàtics estan desactivats', + 'saml_no_email_address' => 'No s\'ha pogut trobar cap adreça electrònica, per a aquest usuari, en les dades proporcionades pel sistema d\'autenticació extern', + 'saml_invalid_response_id' => 'La petició del sistema d\'autenticació extern no és reconeguda per un procés iniciat per aquesta aplicació. Aquest problema podria ser causat per navegar endarrere després d\'iniciar la sessió.', + 'saml_fail_authed' => 'L\'inici de sessió fent servir :system ha fallat, el sistema no ha proporcionat una autorització satisfactòria', + 'social_no_action_defined' => 'No hi ha cap acció definida', + 'social_login_bad_response' => "S'ha rebut un error mentre s'iniciava la sessió amb :socialAccount: \n:error", + 'social_account_in_use' => 'Aquest compte de :socialAccount ja està en ús, proveu d\'iniciar la sessió mitjançant l\'opció de :socialAccount.', + 'social_account_email_in_use' => 'L\'adreça electrònica :email ja està en ús. Si ja teniu un compte, podeu connectar-hi el vostre compte de :socialAccount a la configuració del vostre perfil.', + 'social_account_existing' => 'Aquest compte de :socialAccount ja està associat al vostre perfil.', + 'social_account_already_used_existing' => 'Aquest compte de :socialAccount ja el fa servir un altre usuari.', + 'social_account_not_used' => 'Aquest compte de :socialAccount no està associat a cap usuari. Associeu-lo a la configuració del vostre perfil. ', + 'social_account_register_instructions' => 'Si encara no teniu cap compte, podeu registrar-vos fent servir l\'opció de :socialAccount.', + 'social_driver_not_found' => 'No s\'ha trobat el controlador social', + 'social_driver_not_configured' => 'La configuració social de :socialAccount no és correcta.', + 'invite_token_expired' => 'Aquest enllaç d\'invitació ha caducat. Podeu provar de restablir la contrasenya del vostre compte.', + + // System + 'path_not_writable' => 'No s\'ha pogut pujar al camí del fitxer :filePath. Assegureu-vos que el servidor hi té permisos d\'escriptura.', + 'cannot_get_image_from_url' => 'No s\'ha pogut obtenir la imatge de :url', + 'cannot_create_thumbs' => 'El servidor no pot crear miniatures. Reviseu que tingueu instal·lada l\'extensió GD del PHP.', + 'server_upload_limit' => 'El servidor no permet pujades d\'aquesta mida. Proveu-ho amb una mida de fitxer més petita.', + 'uploaded' => 'El servidor no permet pujades d\'aquesta mida. Proveu-ho amb una mida de fitxer més petita.', + 'image_upload_error' => 'S\'ha produït un error en pujar la imatge', + 'image_upload_type_error' => 'El tipus d\'imatge que heu pujat no és vàlid', + 'file_upload_timeout' => 'La pujada del fitxer ha superat el temps màxim d\'espera.', + + // Attachments + 'attachment_not_found' => 'No s\'ha trobat l\'adjunció', + + // Pages + 'page_draft_autosave_fail' => 'No s\'ha pogut desar l\'esborrany. Assegureu-vos que tingueu connexió a Internet abans de desar la pàgina', + 'page_custom_home_deletion' => 'No es pot suprimir una pàgina mentre estigui definida com a pàgina d\'inici', + + // Entities + 'entity_not_found' => 'No s\'ha trobat l\'entitat', + 'bookshelf_not_found' => 'No s\'ha trobat el prestatge', + 'book_not_found' => 'No s\'ha trobat el llibre', + 'page_not_found' => 'No s\'ha trobat la pàgina', + 'chapter_not_found' => 'No s\'ha trobat el capítol', + 'selected_book_not_found' => 'No s\'ha trobat el llibre seleccionat', + 'selected_book_chapter_not_found' => 'No s\'ha trobat el llibre o el capítol seleccionat', + 'guests_cannot_save_drafts' => 'Els convidats no poden desar esborranys', + + // Users + 'users_cannot_delete_only_admin' => 'No podeu suprimir l\'únic administrador', + 'users_cannot_delete_guest' => 'No podeu suprimir l\'usuari convidat', + + // Roles + 'role_cannot_be_edited' => 'Aquest rol no es pot editar', + 'role_system_cannot_be_deleted' => 'Aquest rol és un rol del sistema i no es pot suprimir', + 'role_registration_default_cannot_delete' => 'No es pot suprimir aquest rol mentre estigui definit com a rol per defecte dels registres', + 'role_cannot_remove_only_admin' => 'Aquest usuari és l\'únic usuari assignat al rol d\'administrador. Assigneu el rol d\'administrador a un altre usuari abans de provar de suprimir aquest.', + + // Comments + 'comment_list' => 'S\'ha produït un error en obtenir els comentaris.', + 'cannot_add_comment_to_draft' => 'No podeu afegir comentaris a un esborrany.', + 'comment_add' => 'S\'ha produït un error en afegir o actualitzar el comentari.', + 'comment_delete' => 'S\'ha produït un error en suprimir el comentari.', + 'empty_comment' => 'No podeu afegir un comentari buit.', + + // Error pages + '404_page_not_found' => 'No s\'ha trobat la pàgina', + 'sorry_page_not_found' => 'No hem pogut trobar la pàgina que cerqueu.', + 'sorry_page_not_found_permission_warning' => 'Si esperàveu que existís, és possible que no tingueu permisos per a veure-la.', + 'return_home' => 'Torna a l\'inici', + 'error_occurred' => 'S\'ha produït un error', + 'app_down' => ':appName està fora de servei en aquests moments', + 'back_soon' => 'Tornarà a estar disponible aviat.', + + // API errors + 'api_no_authorization_found' => 'No s\'ha trobat cap testimoni d\'autorització a la petició', + 'api_bad_authorization_format' => 'S\'ha trobat un testimoni d\'autorització a la petició però el format sembla erroni', + 'api_user_token_not_found' => 'No s\'ha trobat cap testimoni d\'API per al testimoni d\'autorització proporcionat', + 'api_incorrect_token_secret' => 'El secret proporcionat per al testimoni d\'API proporcionat és incorrecte', + 'api_user_no_api_permission' => 'El propietari del testimoni d\'API utilitzat no té permís per a fer crides a l\'API', + 'api_user_token_expired' => 'El testimoni d\'autorització utilitzat ha caducat', + + // Settings & Maintenance + 'maintenance_test_email_failure' => 'S\'ha produït un error en enviar un correu electrònic de prova:', + +]; diff --git a/resources/lang/ca/pagination.php b/resources/lang/ca/pagination.php new file mode 100644 index 000000000..f05a8b369 --- /dev/null +++ b/resources/lang/ca/pagination.php @@ -0,0 +1,12 @@ + '« Anterior', + 'next' => 'Següent »', + +]; diff --git a/resources/lang/ca/passwords.php b/resources/lang/ca/passwords.php new file mode 100644 index 000000000..1fb771fe9 --- /dev/null +++ b/resources/lang/ca/passwords.php @@ -0,0 +1,15 @@ + 'Les contrasenyes han de tenir com a mínim vuit caràcters i la confirmació ha de coincidir.', + 'user' => "No s'ha trobat cap usuari amb aquesta adreça electrònica.", + 'token' => 'El testimoni de reinicialització de la contrasenya no és vàlid per a aquesta adreça electrònica.', + 'sent' => 'Us hem enviat un enllaç per a restablir la contrasenya!', + 'reset' => 'S\'ha restablert la vostra contrasenya!', + +]; diff --git a/resources/lang/ca/settings.php b/resources/lang/ca/settings.php new file mode 100755 index 000000000..6ce3b1903 --- /dev/null +++ b/resources/lang/ca/settings.php @@ -0,0 +1,266 @@ + 'Configuració', + 'settings_save' => 'Desa la configuració', + 'settings_save_success' => 'S\'ha desat la configuració', + + // App Settings + 'app_customization' => 'Personalització', + 'app_features_security' => 'Funcionalitats i seguretat', + 'app_name' => 'Nom de l\'aplicació', + 'app_name_desc' => 'Aquest nom es mostra a la capçalera i en tots els correus electrònics enviats pel sistema.', + 'app_name_header' => 'Mostra el nom a la capçalera', + 'app_public_access' => 'Accés públic', + 'app_public_access_desc' => 'Si activeu aquesta opció, es permetrà que els visitants que no hagin iniciat la sessió accedeixin al contingut de la vostra instància del BookStack.', + 'app_public_access_desc_guest' => 'Podeu controlar l\'accés dels visitants públics amb l\'usuari "Convidat".', + 'app_public_access_toggle' => 'Permet l\'accés públic', + 'app_public_viewing' => 'Voleu permetre la visualització pública?', + 'app_secure_images' => 'Pujades d\'imatges amb més seguretat', + 'app_secure_images_toggle' => 'Activa les pujades d\'imatges amb més seguretat', + 'app_secure_images_desc' => 'Per motius de rendiment, totes les imatges són públiques. Aquesta opció afegeix una cadena aleatòria i difícil d\'endevinar al davant dels URL d\'imatges. Assegureu-vos que els índexs de directoris no estiguin activats per a evitar-hi l\'accés de manera fàcil.', + 'app_editor' => 'Editor de pàgines', + 'app_editor_desc' => 'Seleccioneu quin editor faran servir tots els usuaris per a editar les pàgines.', + 'app_custom_html' => 'Contingut personalitzat a la capçalera HTML', + 'app_custom_html_desc' => 'Aquí podeu afegir contingut que s\'inserirà a la part final de la secció de cada pàgina. És útil per a sobreescriure estils o afegir-hi codi d\'analítiques.', + 'app_custom_html_disabled_notice' => 'El contingut personalitzat a la capçalera HTML es desactiva en aquesta pàgina de la configuració per a assegurar que qualsevol canvi que trenqui el web es pugui desfer.', + 'app_logo' => 'Logo de l\'aplicació', + 'app_logo_desc' => 'Aquesta imatge hauria de tenir 43 px d\'alçada.
Les imatges grosses es reduiran.', + 'app_primary_color' => 'Color primari de l\'aplicació', + 'app_primary_color_desc' => 'Defineix el color primari de l\'aplicació, incloent-hi la part superior, els botons i els enllaços.', + 'app_homepage' => 'Pàgina d\'inici de l\'aplicació', + 'app_homepage_desc' => 'Seleccioneu la visualització que es mostrarà a la pàgina d\'inici en lloc de la visualització per defecte. Els permisos de pàgines s\'ignoraran per a les pàgines seleccionades.', + 'app_homepage_select' => 'Selecciona una pàgina', + 'app_footer_links' => 'Enllaços al peu de pàgina', + 'app_footer_links_desc' => 'Afegiu enllaços que es mostraran al peu de pàgina del lloc. Es mostraran a la part inferior de la majoria de pàgines, incloent-hi les que no requereixen iniciar la sessió. Podeu utilitzar l\'etiqueta "trans::" per a fer servir traduccions definides pel sistema. Per exemple, si feu servir "trans::common.privacy_policy", es mostrarà el text traduït "Política de privadesa", i amb "trans::common.terms_of_service" es mostrarà el text traduït "Condicions del servei".', + 'app_footer_links_label' => 'Etiqueta de l\'enllaç', + 'app_footer_links_url' => 'URL de l\'enllaç', + 'app_footer_links_add' => 'Afegeix un enllaç al peu de pàgina', + 'app_disable_comments' => 'Desactiva els comentaris', + 'app_disable_comments_toggle' => 'Desactiva els comentaris', + 'app_disable_comments_desc' => 'Desactiva els comentaris a totes les pàgines de l\'aplicació.
Els comentaris existents no es mostraran.', + + // Color settings + 'content_colors' => 'Colors del contingut', + 'content_colors_desc' => 'Defineix els colors de tots els elements de la jerarquia d\'organització de pàgines. És recomanable triar colors amb una brillantor semblant als colors per defecte per a mantenir-ne la llegibilitat.', + 'bookshelf_color' => 'Color dels prestatges', + 'book_color' => 'Color dels llibres', + 'chapter_color' => 'Color dels capítols', + 'page_color' => 'Color de les pàgines', + 'page_draft_color' => 'Color dels esborranys de pàgines', + + // Registration Settings + 'reg_settings' => 'Registre', + 'reg_enable' => 'Activa el registre d\'usuaris', + 'reg_enable_toggle' => 'Activa el registre d\'usuaris', + 'reg_enable_desc' => 'Si els registres estan activats, els usuaris podran registrar-se ells mateixos com a usuaris de l\'aplicació. Un cop registrats, se\'ls assigna un únic rol d\'usuari per defecte.', + 'reg_default_role' => 'Rol d\'usuari per defecte en registrar-se', + 'reg_enable_external_warning' => 'L\'opció anterior s\'ignora quan hi ha activada l\'autenticació SAML o LDAP externa. Els comptes d\'usuari de membres inexistents es creada automàticament si l\'autenticació contra el sistema extern és satisfactòria.', + 'reg_email_confirmation' => 'Confirmació de correu electrònic', + 'reg_email_confirmation_toggle' => 'Requereix la confirmació per correu electrònic', + 'reg_confirm_email_desc' => 'Si s\'utilitza la restricció de dominis, serà obligatòria la confirmació per correu electrònic, i s\'ignorarà aquesta opció.', + 'reg_confirm_restrict_domain' => 'Restricció de dominis', + 'reg_confirm_restrict_domain_desc' => 'Introduïu una llista separada per comes de dominis de correu electrònic als quals voleu restringir els registres. S\'enviarà un correu electrònic als usuaris perquè confirmin la seva adreça abans de permetre\'ls interactuar amb l\'aplicació.
Tingueu en compte que els usuaris podran canviar les seves adreces electròniques després de registrar-se correctament.', + 'reg_confirm_restrict_domain_placeholder' => 'No hi ha cap restricció', + + // Maintenance settings + 'maint' => 'Manteniment', + 'maint_image_cleanup' => 'Neteja les imatges', + 'maint_image_cleanup_desc' => "Escaneja el contingut de les pàgines i les revisions per a comprovar quines imatges i diagrames estan en ús actualment i quines imatges són redundants. Assegureu-vos de crear una còpia de seguretat completa de la base de dades i de les imatges abans d'executar això.", + 'maint_delete_images_only_in_revisions' => 'Suprimeix també les imatges que només existeixin en revisions antigues de pàgines', + 'maint_image_cleanup_run' => 'Executa la neteja', + 'maint_image_cleanup_warning' => 'S\'han trobat :count imatges potencialment no utilitzades. Segur que voleu suprimir aquestes imatges?', + 'maint_image_cleanup_success' => 'S\'han trobat i suprimit :count imatges potencialment no utilitzades!', + 'maint_image_cleanup_nothing_found' => 'No s\'ha trobat cap imatge no utilitzada, i no s\'ha suprimit res!', + 'maint_send_test_email' => 'Envia un correu electrònic de prova', + 'maint_send_test_email_desc' => 'Envia un correu electrònic de prova a l\'adreça electrònica que hàgiu especificat al perfil.', + 'maint_send_test_email_run' => 'Envia el correu electrònic de prova', + 'maint_send_test_email_success' => 'S\'ha enviat el correu electrònic a :address', + 'maint_send_test_email_mail_subject' => 'Correu electrònic de prova', + 'maint_send_test_email_mail_greeting' => 'El lliurament de correus electrònics sembla que funciona!', + 'maint_send_test_email_mail_text' => 'Enhorabona! Com que heu rebut aquesta notificació per correu electrònic, la vostra configuració del correu electrònic sembla que està ben configurada.', + 'maint_recycle_bin_desc' => 'Els prestatges, llibres, capítols i pàgines eliminats s\'envien a la paperera de reciclatge perquè es puguin restaurar o suprimir de manera permanent. Pot ser que els elements més antics de la paperera de reciclatge se suprimeixin automàticament després d\'un temps, depenent de la configuració del sistema.', + 'maint_recycle_bin_open' => 'Obre la paperera de reciclatge', + + // Recycle Bin + 'recycle_bin' => 'Paperera de reciclatge', + 'recycle_bin_desc' => 'Aquí podeu restaurar els elements que hàgiu suprimit o triar suprimir-los del sistema de manera permanent. Aquesta llista no té cap filtre, al contrari que altres llistes d\'activitat similars en què es tenen en compte els filtres de permisos.', + 'recycle_bin_deleted_item' => 'Element suprimit', + 'recycle_bin_deleted_by' => 'Suprimit per', + 'recycle_bin_deleted_at' => 'Moment de la supressió', + 'recycle_bin_permanently_delete' => 'Suprimeix permanentment', + 'recycle_bin_restore' => 'Restaura', + 'recycle_bin_contents_empty' => 'La paperera de reciclatge és buida', + 'recycle_bin_empty' => 'Buida la paperera de reciclatge', + 'recycle_bin_empty_confirm' => 'Se suprimiran de manera permanent tots els elements de la paperera de reciclatge, incloent-hi el contingut dins de cada element. Segur que voleu buidar la paperera de reciclatge?', + 'recycle_bin_destroy_confirm' => 'Aquesta acció suprimirà del sistema de manera permanent aquest element, juntament amb tots els elements fills que es llisten a sota, i no podreu restaurar aquest contingut. Segur que voleu suprimir de manera permanent aquest element?', + 'recycle_bin_destroy_list' => 'Elements que es destruiran', + 'recycle_bin_restore_list' => 'Elements que es restauraran', + 'recycle_bin_restore_confirm' => 'Aquesta acció restaurarà l\'element suprimit, incloent-hi tots els elements fills, a la seva ubicació original. Si la ubicació original ha estat suprimida, i ara és a la paperera de reciclatge, caldrà que també en restaureu l\'element pare.', + 'recycle_bin_restore_deleted_parent' => 'El pare d\'aquest element també ha estat suprimit. L\'element es mantindrà suprimit fins que el pare també es restauri.', + 'recycle_bin_destroy_notification' => 'S\'han suprimit :count elements en total de la paperera de reciclatge.', + 'recycle_bin_restore_notification' => 'S\'han restaurat :count elements en total de la paperera de reciclatge.', + + // Audit Log + 'audit' => 'Registre d\'auditoria', + 'audit_desc' => 'Aquest registre d\'auditoria mostra una llista d\'activitats registrades al sistema. Aquesta llista no té cap filtre, al contrari que altres llistes d\'activitat similars en què es tenen en compte els filtres de permisos.', + 'audit_event_filter' => 'Filtre d\'esdeveniments', + 'audit_event_filter_no_filter' => 'Sense filtre', + 'audit_deleted_item' => 'Element suprimit', + 'audit_deleted_item_name' => 'Nom: :name', + 'audit_table_user' => 'Usuari', + 'audit_table_event' => 'Esdeveniment', + 'audit_table_related' => 'Element relacionat o detall', + 'audit_table_date' => 'Data de l\'activitat', + 'audit_date_from' => 'Rang de dates a partir de', + 'audit_date_to' => 'Rang de rates fins a', + + // Role Settings + 'roles' => 'Rols', + 'role_user_roles' => 'Rols d\'usuari', + 'role_create' => 'Crea un rol nou', + 'role_create_success' => 'Rol creat correctament', + 'role_delete' => 'Suprimeix el rol', + 'role_delete_confirm' => 'Se suprimirà el rol amb el nom \':roleName\'.', + 'role_delete_users_assigned' => 'Aquest rol té :userCount usuaris assignats. Si voleu migrar els usuaris d\'aquest rol, seleccioneu un rol nou a continuació.', + 'role_delete_no_migration' => "No migris els usuaris", + 'role_delete_sure' => 'Segur que voleu suprimir aquest rol?', + 'role_delete_success' => 'Rol suprimit correctament', + 'role_edit' => 'Edita el rol', + 'role_details' => 'Detalls del rol', + 'role_name' => 'Nom del rol', + 'role_desc' => 'Descripció curta del rol', + 'role_external_auth_id' => 'Identificadors d\'autenticació externa', + 'role_system' => 'Permisos del sistema', + 'role_manage_users' => 'Gestiona usuaris', + 'role_manage_roles' => 'Gestiona rols i permisos de rols', + 'role_manage_entity_permissions' => 'Gestiona els permisos de tots els llibres, capítols i pàgines', + 'role_manage_own_entity_permissions' => 'Gestiona els permisos dels llibres, capítols i pàgines propis', + 'role_manage_page_templates' => 'Gestiona les plantilles de pàgines', + 'role_access_api' => 'Accedeix a l\'API del sistema', + 'role_manage_settings' => 'Gestiona la configuració de l\'aplicació', + 'role_asset' => 'Permisos de recursos', + 'roles_system_warning' => 'Tingueu en compte que l\'accés a qualsevol dels tres permisos de dalt pot permetre que un usuari alteri els seus propis permisos o els privilegis d\'altres usuaris del sistema. Assigneu rols amb aquests permisos només a usuaris de confiança.', + 'role_asset_desc' => 'Aquests permisos controlen l\'accés per defecte als recursos del sistema. Els permisos de llibres, capítols i pàgines tindran més importància que aquests permisos.', + 'role_asset_admins' => 'Els administradors tenen accés automàticament a tot el contingut, però aquestes opcions poden mostrar o amagar opcions de la interfície d\'usuari.', + 'role_all' => 'Tot', + 'role_own' => 'Propi', + 'role_controlled_by_asset' => 'Controlat pel recurs en què es pugen', + 'role_save' => 'Desa el rol', + 'role_update_success' => 'Rol actualitzat correctament', + 'role_users' => 'Usuaris amb aquest rol', + 'role_users_none' => 'Ara mateix no hi ha cap usuari assignat a aquest rol', + + // Users + 'users' => 'Usuaris', + 'user_profile' => 'Perfil de l\'usuari', + 'users_add_new' => 'Afegeix un usuari nou', + 'users_search' => 'Cerca usuaris', + 'users_latest_activity' => 'Darrera activitat', + 'users_details' => 'Detalls de l\'usuari', + 'users_details_desc' => 'Definiu un nom públic i una adreça electrònica per a aquest usuari. L\'adreça electrònica es farà servir per a iniciar la sessió a l\'aplicació.', + 'users_details_desc_no_email' => 'Definiu un nom públic per a aquest usuari perquè els altres el puguin reconèixer.', + 'users_role' => 'Rols de l\'usuari', + 'users_role_desc' => 'Seleccioneu a quins rols s\'assignarà l\'usuari. Si un usuari s\'assigna a múltiples rols, els permisos dels rols s\'acumularan i l\'usuari rebrà tots els permisos dels rols assignats.', + 'users_password' => 'Contrasenya de l\'usuari', + 'users_password_desc' => 'Definiu una contrasenya per a iniciar la sessió a l\'aplicació. Cal que tingui un mínim de 6 caràcters.', + 'users_send_invite_text' => 'Podeu elegir enviar un correu d\'invitació a aquest usuari, la qual cosa li permetrà definir la seva contrasenya, o podeu definir-li una contrasenya vós.', + 'users_send_invite_option' => 'Envia un correu d\'invitació a l\'usuari', + 'users_external_auth_id' => 'Identificador d\'autenticació extern', + 'users_external_auth_id_desc' => 'Aquest és l\'identificador que s\'utilitza per a enllaçar aquest usuari en comunicar amb el sistema d\'autenticació extern.', + 'users_password_warning' => 'Ompliu-ho només si voleu canviar la vostra contrasenya.', + 'users_system_public' => 'Aquest usuari representa qualsevol usuari convidat que visita la vostra instància. No es pot fer servir per a iniciar la sessió però s\'assigna automàticament.', + 'users_delete' => 'Suprimeix l\'usuari', + 'users_delete_named' => 'Suprimeix l\'usuari :userName', + 'users_delete_warning' => 'Se suprimirà completament del sistema l\'usuari amb el nom \':userName\'.', + 'users_delete_confirm' => 'Segur que voleu suprimir aquest usuari?', + 'users_migrate_ownership' => 'Migra l\'autoria', + 'users_migrate_ownership_desc' => 'Seleccioneu un usuari si voleu que un altre usuari esdevingui el propietari de tots els elements que ara són propietat d\'aquest usuari.', + 'users_none_selected' => 'No hi ha cap usuari seleccionat', + 'users_delete_success' => 'Usuari suprimit correctament', + 'users_edit' => 'Edita l\'usuari', + 'users_edit_profile' => 'Edita el perfil', + 'users_edit_success' => 'Usuari actualitzat correctament', + 'users_avatar' => 'Avatar de l\'usuari', + 'users_avatar_desc' => 'Seleccioneu una imatge que representi aquest usuari. Hauria de ser un quadrat d\'aproximadament 256 px.', + 'users_preferred_language' => 'Llengua preferida', + 'users_preferred_language_desc' => 'Aquesta opció canviarà la llengua utilitzada a la interfície d\'usuari de l\'aplicació. No afectarà el contingut creat pels usuaris.', + 'users_social_accounts' => 'Comptes socials', + 'users_social_accounts_info' => 'Aquí podeu connectar altres comptes per a un inici de sessió més ràpid i còmode. Si desconnecteu un compte aquí, no en revoqueu l\'accés d\'autorització donat amb anterioritat. Revoqueu-hi l\'accés a la configuració del perfil del compte social que hàgiu connectat.', + 'users_social_connect' => 'Connecta un compte', + 'users_social_disconnect' => 'Desconnecta el compte', + 'users_social_connected' => 'El compte de :socialAccount s\'ha associat correctament al vostre perfil.', + 'users_social_disconnected' => 'El compte de :socialAccount s\'ha desassociat correctament del vostre perfil.', + 'users_api_tokens' => 'Testimonis d\'API', + 'users_api_tokens_none' => 'No s\'ha creat cap testimoni d\'API per a aquest usuari', + 'users_api_tokens_create' => 'Crea un testimoni', + 'users_api_tokens_expires' => 'Caducitat', + 'users_api_tokens_docs' => 'Documentació de l\'API', + + // API Tokens + 'user_api_token_create' => 'Crea un testimoni d\'API', + 'user_api_token_name' => 'Nom', + 'user_api_token_name_desc' => 'Poseu un nom llegible al vostre testimoni com a recordatori futur del propòsit al qual el voleu destinar.', + 'user_api_token_expiry' => 'Data de caducitat', + 'user_api_token_expiry_desc' => 'Definiu una data en què aquest testimoni caducarà. Després d\'aquesta data, les peticions fetes amb aquest testimoni deixaran de funcionar. Si deixeu aquest camp en blanc, es definirà una caducitat d\'aquí a 100 anys..', + 'user_api_token_create_secret_message' => 'Just després de crear aquest testimoni, es generaran i es mostraran un "Identificador del testimoni" i un "Secret del testimoni". El secret només es mostrarà una única vegada, assegureu-vos de copiar-lo a un lloc segur abans de continuar.', + 'user_api_token_create_success' => 'Testimoni d\'API creat correctament', + 'user_api_token_update_success' => 'Testimoni d\'API actualitzat correctament', + 'user_api_token' => 'Testimoni d\'API', + 'user_api_token_id' => 'Identificador del testimoni', + 'user_api_token_id_desc' => 'Aquest identificador és generat pel sistema per a aquest testimoni i no és editable, caldrà que el proporcioneu a les peticions a l\'API.', + 'user_api_token_secret' => 'Secret del testimoni', + 'user_api_token_secret_desc' => 'Aquest secret és generat pel sistema per a aquest testimoni, caldrà que el proporcioneu a les peticions a l\'API. Només es mostrarà aquesta única vegada, assegureu-vos de copiar-lo a un lloc segur.', + 'user_api_token_created' => 'Testimoni creat :timeAgo', + 'user_api_token_updated' => 'Testimoni actualitzat :timeAgo', + 'user_api_token_delete' => 'Suprimeix el testimoni', + 'user_api_token_delete_warning' => 'Se suprimirà completament del sistema aquest testimoni d\'API amb el nom \':tokenName\'.', + 'user_api_token_delete_confirm' => 'Segur que voleu suprimir aquest testimoni d\'API?', + 'user_api_token_delete_success' => 'Testimoni d\'API suprimit correctament', + + //! 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', + 'fr' => 'Français', + 'he' => 'עברית', + 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', + 'it' => 'Italian', + 'ja' => '日本語', + 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', + 'nl' => 'Nederlands', + 'nb' => 'Norsk (Bokmål)', + 'pl' => 'Polski', + 'pt' => 'Português', + 'pt_BR' => 'Português do Brasil', + '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/ca/validation.php b/resources/lang/ca/validation.php new file mode 100644 index 000000000..163bb6ad4 --- /dev/null +++ b/resources/lang/ca/validation.php @@ -0,0 +1,115 @@ + 'Cal que accepteu el camp :attribute.', + 'active_url' => 'El camp :attribute no és un URL vàlid.', + 'after' => 'El camp :attribute ha de ser una data posterior a :date.', + 'alpha' => 'El camp :attribute només pot contenir lletres.', + 'alpha_dash' => 'El camp :attribute només pot contenir lletres, números, guions i guions baixos.', + 'alpha_num' => 'El camp :attribute només pot contenir lletres i números.', + 'array' => 'El camp :attribute ha de ser un vector.', + 'before' => 'El camp :attribute ha de ser una data anterior a :date.', + 'between' => [ + 'numeric' => 'El camp :attribute ha d\'estar entre :min i :max.', + 'file' => 'El camp :attribute ha de tenir entre :min i :max kilobytes.', + 'string' => 'El camp :attribute ha de tenir entre :min i :max caràcters.', + 'array' => 'El camp :attribute ha de tenir entre :min i :max elements.', + ], + 'boolean' => 'El camp :attribute ha de ser cert o fals.', + 'confirmed' => 'La confirmació del camp :attribute no coincideix.', + 'date' => 'El camp :attribute no és una data vàlida.', + 'date_format' => 'El camp :attribute no coincideix amb el format :format.', + 'different' => 'Els camps :attribute i :other han de ser diferents.', + 'digits' => 'El camp :attribute ha de tenir :digits dígits.', + 'digits_between' => 'El camp :attribute ha de tenir entre :min i :max dígits.', + 'email' => 'El camp :attribute ha de ser una adreça electrònica vàlida.', + 'ends_with' => 'El camp :attribute ha d\'acabar amb un dels següents valors: :values', + 'filled' => 'El camp :attribute és obligatori.', + 'gt' => [ + 'numeric' => 'El camp :attribute ha de ser més gran que :value.', + 'file' => 'El camp :attribute ha de tenir més de :value kilobytes.', + 'string' => 'El camp :attribute ha de tenir més de :value caràcters.', + 'array' => 'El camp :attribute ha de tenir més de :value elements.', + ], + 'gte' => [ + 'numeric' => 'El camp :attribute ha de ser més gran o igual que :value.', + 'file' => 'El camp :attribute ha de tenir :value kilobytes o més.', + 'string' => 'El camp :attribute ha de tenir :value caràcters o més.', + 'array' => 'El camp :attribute ha de tenir :value elements o més.', + ], + 'exists' => 'El camp :attribute no és vàlid.', + 'image' => 'El camp :attribute ha de ser una imatge.', + 'image_extension' => 'El camp :attribute ha de tenir una extensió d\'imatge vàlida i suportada.', + 'in' => 'El camp :attribute seleccionat no és vàlid.', + 'integer' => 'El camp :attribute ha de ser un enter.', + 'ip' => 'El camp :attribute ha de ser una adreça IP vàlida.', + 'ipv4' => 'El camp :attribute ha de ser una adreça IPv4 vàlida.', + 'ipv6' => 'El camp :attribute ha de ser una adreça IPv6 vàlida.', + 'json' => 'El camp :attribute ha de ser una cadena JSON vàlida.', + 'lt' => [ + 'numeric' => 'El camp :attribute ha de ser menor que :value.', + 'file' => 'El camp :attribute ha de tenir menys de :value kilobytes.', + 'string' => 'El camp :attribute ha de tenir menys de :value caràcters.', + 'array' => 'El camp :attribute ha de tenir menys de :value elements.', + ], + 'lte' => [ + 'numeric' => 'El camp :attribute ha de ser més petit o igual que :value.', + 'file' => 'El camp :attribute ha de tenir :value kilobytes o menys.', + 'string' => 'El camp :attribute ha de tenir :value caràcters o menys.', + 'array' => 'El camp :attribute ha de tenir :value elements o menys.', + ], + 'max' => [ + 'numeric' => 'El camp :attribute no pot ser més gran que :max.', + 'file' => 'El camp :attribute no pot tenir més de :max kilobytes.', + 'string' => 'El camp :attribute no pot tenir més de :max caràcters.', + 'array' => 'El camp :attribute no pot tenir més de :max elements.', + ], + 'mimes' => 'El camp :attribute ha de ser un fitxer del tipus: :values.', + 'min' => [ + 'numeric' => 'El camp :attribute no pot ser més petit que :min.', + 'file' => 'El camp :attribute no pot tenir menys de :min kilobytes.', + 'string' => 'El camp :attribute no pot tenir menys de :min caràcters.', + 'array' => 'El camp :attribute no pot tenir menys de :min elements.', + ], + 'no_double_extension' => 'El camp :attribute només pot tenir una única extensió de fitxer.', + 'not_in' => 'El camp :attribute seleccionat no és vàlid.', + 'not_regex' => 'El format del camp :attribute no és vàlid.', + 'numeric' => 'El camp :attribute ha de ser un número.', + 'regex' => 'El format del camp :attribute no és vàlid.', + 'required' => 'El camp :attribute és obligatori.', + 'required_if' => 'El camp :attribute és obligatori quan :other és :value.', + 'required_with' => 'El camp :attribute és obligatori quan hi ha aquest valor: :values.', + 'required_with_all' => 'El camp :attribute és obligatori quan hi ha algun d\'aquests valors: :values.', + 'required_without' => 'El camp :attribute és obligatori quan no hi ha aquest valor: :values.', + 'required_without_all' => 'El camp :attribute és obligatori quan no hi ha cap d\'aquests valors: :values.', + 'same' => 'Els camps :attribute i :other han de coincidir.', + 'safe_url' => 'L\'enllaç proporcionat podria no ser segur.', + 'size' => [ + 'numeric' => 'El camp :attribute ha de ser :size.', + 'file' => 'El camp :attribute ha de tenir :size kilobytes.', + 'string' => 'El camp :attribute ha de tenir :size caràcters.', + 'array' => 'El camp :attribute ha de contenir :size elements.', + ], + 'string' => 'El camp :attribute ha de ser una cadena.', + 'timezone' => 'El camp :attribute ha de ser una zona vàlida.', + 'unique' => 'El camp :attribute ja està ocupat.', + 'url' => 'El format del camp :attribute no és vàlid.', + 'uploaded' => 'No s\'ha pogut pujar el fitxer. És possible que el servidor no accepti fitxers d\'aquesta mida.', + + // Custom validation lines + 'custom' => [ + 'password-confirm' => [ + 'required_with' => 'Cal la confirmació de la contrasenya', + ], + ], + + // Custom validation attributes + 'attributes' => [], +]; diff --git a/resources/lang/cs/common.php b/resources/lang/cs/common.php index 342610f5d..018faa1ba 100644 --- a/resources/lang/cs/common.php +++ b/resources/lang/cs/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'Pokud se vám nedaří kliknout na tlačítko „:actionText“, zkopírujte a vložte níže uvedenou URL do vašeho webového prohlížeče:', 'email_rights' => 'Všechna práva vyhrazena', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privacy Policy', + 'terms_of_service' => 'Terms of Service', ]; diff --git a/resources/lang/cs/settings.php b/resources/lang/cs/settings.php index 80aa6dc38..1dc4000aa 100644 --- a/resources/lang/cs/settings.php +++ b/resources/lang/cs/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'Úvodní stránka aplikace', 'app_homepage_desc' => 'Vyberte si zobrazení, které se použije jako úvodní stránka. U zvolených stránek bude ignorováno jejich oprávnění.', 'app_homepage_select' => 'Zvolte stránku', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', 'app_disable_comments' => 'Vypnutí komentářů', 'app_disable_comments_toggle' => 'Vypnout komentáře', 'app_disable_comments_desc' => 'Vypne komentáře napříč všemi stránkami.
Existující komentáře se přestanou zobrazovat.', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/cs/validation.php b/resources/lang/cs/validation.php index a84397349..1a94b9e24 100644 --- a/resources/lang/cs/validation.php +++ b/resources/lang/cs/validation.php @@ -78,7 +78,6 @@ return [ 'string' => ':attribute musí být delší než :min znaků.', 'array' => ':attribute musí obsahovat více než :min prvků.', ], - 'no_double_extension' => ':attribute musí obsahovat pouze jednu příponu souboru.', 'not_in' => 'Zvolená hodnota pro :attribute je neplatná.', 'not_regex' => ':attribute musí být regulární výraz.', 'numeric' => ':attribute musí být číslo.', diff --git a/resources/lang/da/common.php b/resources/lang/da/common.php index dbd76d03c..4aa652c73 100644 --- a/resources/lang/da/common.php +++ b/resources/lang/da/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'Hvis du har problemer med at trykke på ":actionText" knappen, prøv at kopiere og indsætte linket herunder ind i din webbrowser:', 'email_rights' => 'Alle rettigheder forbeholdes', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privacy Policy', + 'terms_of_service' => 'Terms of Service', ]; diff --git a/resources/lang/da/settings.php b/resources/lang/da/settings.php index 80ebcb123..e680f3afc 100644 --- a/resources/lang/da/settings.php +++ b/resources/lang/da/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'Programforside', 'app_homepage_desc' => 'Vælg en visning, der skal vises på startsiden i stedet for standardvisningen. Sidetilladelser ignoreres for valgte sider.', 'app_homepage_select' => 'Vælg en side', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', 'app_disable_comments' => 'Deaktiver kommentarer', 'app_disable_comments_toggle' => 'Deaktiver kommentar', 'app_disable_comments_desc' => 'Deaktiverer kommentarer på tværs af alle sider i applikationen.
Eksisterende kommentarer vises ikke.', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'Hebraisk', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/da/validation.php b/resources/lang/da/validation.php index 7647132ca..d4564c571 100644 --- a/resources/lang/da/validation.php +++ b/resources/lang/da/validation.php @@ -78,7 +78,6 @@ return [ 'string' => ':attribute skal mindst være :min tegn.', 'array' => ':attribute skal have mindst :min elementer.', ], - 'no_double_extension' => ':attribute må kun indeholde én filtype.', 'not_in' => 'Den valgte :attribute er ikke gyldig.', 'not_regex' => ':attribute-formatet er ugyldigt.', 'numeric' => ':attribute skal være et tal.', diff --git a/resources/lang/de/common.php b/resources/lang/de/common.php index fc44a9250..1730a9470 100644 --- a/resources/lang/de/common.php +++ b/resources/lang/de/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'Sollte es beim Anklicken der Schaltfläche ":action_text" Probleme geben, öffnen Sie folgende URL in Ihrem Browser:', 'email_rights' => 'Alle Rechte vorbehalten', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Datenschutzbestimmungen', + 'terms_of_service' => 'Allgemeine Geschäftsbedingungen', ]; diff --git a/resources/lang/de/entities.php b/resources/lang/de/entities.php index 2ea11a6cf..fc3c06cc3 100644 --- a/resources/lang/de/entities.php +++ b/resources/lang/de/entities.php @@ -22,14 +22,14 @@ return [ 'meta_created_name' => 'Erstellt: :timeLength von :user', 'meta_updated' => 'Zuletzt aktualisiert: :timeLength', 'meta_updated_name' => 'Zuletzt aktualisiert: :timeLength von :user', - 'meta_owned_name' => 'Owned by :user', + 'meta_owned_name' => 'Im Besitz von :user', 'entity_select' => 'Eintrag auswählen', 'images' => 'Bilder', 'my_recent_drafts' => 'Meine kürzlichen Entwürfe', 'my_recently_viewed' => 'Kürzlich von mir angesehen', - 'no_pages_viewed' => 'Sie haben bisher keine Seiten angesehen.', - 'no_pages_recently_created' => 'Sie haben bisher keine Seiten angelegt.', - 'no_pages_recently_updated' => 'Sie haben bisher keine Seiten aktualisiert.', + 'no_pages_viewed' => 'Sie haben bisher keine Seiten angesehen', + 'no_pages_recently_created' => 'Sie haben bisher keine Seiten angelegt', + 'no_pages_recently_updated' => 'Sie haben bisher keine Seiten aktualisiert', 'export' => 'Exportieren', 'export_html' => 'HTML-Datei', 'export_pdf' => 'PDF-Datei', @@ -40,7 +40,7 @@ return [ 'permissions_intro' => 'Wenn individuelle Berechtigungen aktiviert werden, überschreiben diese Einstellungen durch Rollen zugewiesene Berechtigungen.', 'permissions_enable' => 'Individuelle Berechtigungen aktivieren', 'permissions_save' => 'Berechtigungen speichern', - 'permissions_owner' => 'Owner', + 'permissions_owner' => 'Besitzer', // Search 'search_results' => 'Suchergebnisse', @@ -210,7 +210,7 @@ return [ 'pages_revisions' => 'Seitenversionen', 'pages_revisions_named' => 'Seitenversionen von ":pageName"', 'pages_revision_named' => 'Seitenversion von ":pageName"', - 'pages_revision_restored_from' => 'Restored from #:id; :summary', + 'pages_revision_restored_from' => 'Wiederhergestellt von #:id; :summary', 'pages_revisions_created_by' => 'Erstellt von', 'pages_revisions_date' => 'Versionsdatum', 'pages_revisions_number' => '#', diff --git a/resources/lang/de/settings.php b/resources/lang/de/settings.php index 60d4361d9..7fff1a75d 100644 --- a/resources/lang/de/settings.php +++ b/resources/lang/de/settings.php @@ -39,6 +39,11 @@ Wenn Sie nicht 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' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated 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', 'app_disable_comments' => 'Kommentare deaktivieren', 'app_disable_comments_toggle' => 'Kommentare deaktivieren', 'app_disable_comments_desc' => 'Deaktiviert Kommentare über alle Seiten in der Anwendung. Vorhandene Kommentare werden nicht angezeigt.', @@ -71,7 +76,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'maint' => 'Wartung', 'maint_image_cleanup' => 'Bilder bereinigen', 'maint_image_cleanup_desc' => "Überprüft Seiten- und Versionsinhalte auf ungenutzte und mehrfach vorhandene Bilder. Erstellen Sie vor dem Start ein Backup Ihrer Datenbank und Bilder.", - 'maint_delete_images_only_in_revisions' => 'Also delete images that only exist in old page revisions', + 'maint_delete_images_only_in_revisions' => 'Lösche auch Bilder, die nur in alten Seitenüberarbeitungen vorhanden sind', 'maint_image_cleanup_run' => 'Reinigung starten', 'maint_image_cleanup_warning' => ':count eventuell unbenutze Bilder wurden gefunden. Möchten Sie diese Bilder löschen?', 'maint_image_cleanup_success' => ':count eventuell unbenutze Bilder wurden gefunden und gelöscht.', @@ -178,10 +183,10 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'users_delete_named' => 'Benutzer ":userName" löschen', 'users_delete_warning' => 'Der Benutzer ":userName" wird aus dem System gelöscht.', 'users_delete_confirm' => 'Sind Sie sicher, dass Sie diesen Benutzer löschen möchten?', - 'users_migrate_ownership' => 'Migrate Ownership', - 'users_migrate_ownership_desc' => 'Select a user here if you want another user to become the owner of all items currently owned by this user.', - 'users_none_selected' => 'No user selected', - 'users_delete_success' => 'User successfully removed', + 'users_migrate_ownership' => 'Besitz migrieren', + 'users_migrate_ownership_desc' => 'Wählen Sie hier einen Benutzer, wenn Sie möchten, dass ein anderer Benutzer der Besitzer aller Einträge wird, die diesem Benutzer derzeit gehören.', + 'users_none_selected' => 'Kein Benutzer ausgewählt', + 'users_delete_success' => 'Benutzer erfolgreich entfernt', 'users_edit' => 'Benutzer bearbeiten', 'users_edit_profile' => 'Profil bearbeiten', 'users_edit_success' => 'Benutzer erfolgreich aktualisisert', @@ -229,6 +234,8 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bulgarisch', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Dänisch', 'de' => 'Deutsch (Sie)', @@ -238,12 +245,15 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'fr' => 'Français', 'he' => 'Hebräisch', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/de/validation.php b/resources/lang/de/validation.php index 8b1febc85..50f8a76a3 100644 --- a/resources/lang/de/validation.php +++ b/resources/lang/de/validation.php @@ -78,7 +78,6 @@ return [ 'string' => ':attribute muss mindestens :min Zeichen lang sein.', 'array' => ':attribute muss mindesten :min Elemente enthalten.', ], - 'no_double_extension' => ':attribute darf nur eine gültige Dateiendung', 'not_in' => ':attribute ist ungültig.', 'not_regex' => ':attribute ist kein valides Format.', 'numeric' => ':attribute muss eine Zahl sein.', diff --git a/resources/lang/de_informal/activities.php b/resources/lang/de_informal/activities.php index 01c54bf4f..50bc29646 100644 --- a/resources/lang/de_informal/activities.php +++ b/resources/lang/de_informal/activities.php @@ -45,5 +45,5 @@ return [ // Other 'commented_on' => 'kommentiert', - 'permissions_update' => 'hat die Berechtigungen aktualisiert', + 'permissions_update' => 'aktualisierte Berechtigungen', ]; diff --git a/resources/lang/de_informal/common.php b/resources/lang/de_informal/common.php index c18f786f6..31a11f40a 100644 --- a/resources/lang/de_informal/common.php +++ b/resources/lang/de_informal/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'Sollte es beim Anklicken der Schaltfläche ":action_text" Probleme geben, öffne die folgende URL in Deinem Browser:', 'email_rights' => 'Alle Rechte vorbehalten', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Datenschutzbestimmungen', + 'terms_of_service' => 'Allgemeine Geschäftsbedingungen', ]; diff --git a/resources/lang/de_informal/entities.php b/resources/lang/de_informal/entities.php index b89932473..fefad0cc1 100644 --- a/resources/lang/de_informal/entities.php +++ b/resources/lang/de_informal/entities.php @@ -22,7 +22,7 @@ return [ 'meta_created_name' => 'Erstellt: :timeLength von :user', 'meta_updated' => 'Zuletzt aktualisiert: :timeLength', 'meta_updated_name' => 'Zuletzt aktualisiert: :timeLength von :user', - 'meta_owned_name' => 'Owned by :user', + 'meta_owned_name' => 'Im Besitz von :user', 'entity_select' => 'Eintrag auswählen', 'images' => 'Bilder', 'my_recent_drafts' => 'Meine kürzlichen Entwürfe', @@ -40,7 +40,7 @@ return [ 'permissions_intro' => 'Wenn individuelle Berechtigungen aktiviert werden, überschreiben diese Einstellungen durch Rollen zugewiesene Berechtigungen.', 'permissions_enable' => 'Individuelle Berechtigungen aktivieren', 'permissions_save' => 'Berechtigungen speichern', - 'permissions_owner' => 'Owner', + 'permissions_owner' => 'Besitzer', // Search 'search_results' => 'Suchergebnisse', @@ -148,7 +148,7 @@ return [ 'chapters_create' => 'Neues Kapitel anlegen', 'chapters_delete' => 'Kapitel entfernen', 'chapters_delete_named' => 'Kapitel ":chapterName" entfernen', - 'chapters_delete_explain' => 'Dies löscht das Kapitel mit dem Namen \':chapterName\'. Alle Seiten, die innerhalb dieses Kapitels existieren, werden ebenfalls gelöscht.', + 'chapters_delete_explain' => 'Hiermit löschen Sie das Kapitel mit dem Namen \':chapterName\'. Alle Seiten, die innerhalb dieses Kapitels existieren, werden ebenfalls gelöscht.', 'chapters_delete_confirm' => 'Bist Du sicher, dass Du dieses Kapitel löschen möchtest?', 'chapters_edit' => 'Kapitel bearbeiten', 'chapters_edit_named' => 'Kapitel ":chapterName" bearbeiten', @@ -210,7 +210,7 @@ return [ 'pages_revisions' => 'Seitenversionen', 'pages_revisions_named' => 'Seitenversionen von ":pageName"', 'pages_revision_named' => 'Seitenversion von ":pageName"', - 'pages_revision_restored_from' => 'Restored from #:id; :summary', + 'pages_revision_restored_from' => 'Wiederhergestellt von #:id; :summary', 'pages_revisions_created_by' => 'Erstellt von', 'pages_revisions_date' => 'Versionsdatum', 'pages_revisions_number' => '#', @@ -268,7 +268,7 @@ return [ 'attachments_link_url' => 'Link zu einer Datei', 'attachments_link_url_hint' => 'URL einer Seite oder Datei', 'attach' => 'Hinzufügen', - 'attachments_insert_link' => 'Link zum Anhang auf Seite einfügen', + 'attachments_insert_link' => 'Anhangslink zur Seite hinzufügen', 'attachments_edit_file' => 'Datei bearbeiten', 'attachments_edit_file_name' => 'Dateiname', 'attachments_edit_drop_upload' => 'Ziehe Dateien hierher, um diese hochzuladen und zu überschreiben', diff --git a/resources/lang/de_informal/settings.php b/resources/lang/de_informal/settings.php index d0caef9ee..0315857f2 100644 --- a/resources/lang/de_informal/settings.php +++ b/resources/lang/de_informal/settings.php @@ -39,6 +39,11 @@ Wenn Du nichts eingibst, wird die Anwendung auf die Standardfarbe zurückgesetzt 'app_homepage' => 'Startseite der Anwendung', 'app_homepage_desc' => 'Wähle 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' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated 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', 'app_disable_comments' => 'Kommentare deaktivieren', 'app_disable_comments_toggle' => 'Kommentare deaktivieren', 'app_disable_comments_desc' => 'Deaktiviert Kommentare über alle Seiten in der Anwendung. Vorhandene Kommentare werden nicht angezeigt.', @@ -71,7 +76,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'maint' => 'Wartung', 'maint_image_cleanup' => 'Bilder bereinigen', 'maint_image_cleanup_desc' => "Überprüft Seiten- und Versionsinhalte auf ungenutzte und mehrfach vorhandene Bilder. Erstelle vor dem Start ein Backup Deiner Datenbank und Bilder.", - 'maint_delete_images_only_in_revisions' => 'Also delete images that only exist in old page revisions', + 'maint_delete_images_only_in_revisions' => 'Lösche auch Bilder, die nur in alten Seitenüberarbeitungen vorhanden sind', 'maint_image_cleanup_run' => 'Reinigung starten', 'maint_image_cleanup_warning' => ':count eventuell unbenutze Bilder wurden gefunden. Möchtest Du diese Bilder löschen?', 'maint_image_cleanup_success' => ':count eventuell unbenutze Bilder wurden gefunden und gelöscht.', @@ -83,38 +88,38 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'maint_send_test_email_mail_subject' => 'Test E-Mail', 'maint_send_test_email_mail_greeting' => 'E-Mail-Versand scheint zu funktionieren!', '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 Gegenstände im Papierkorb können, in Abhängigkeit von der Systemkonfiguration, nach einer Weile automatisch entfernt werden.', + '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', // Recycle Bin 'recycle_bin' => 'Papierkorb', - 'recycle_bin_desc' => 'Hier können Sie gelöschte Elemente wiederherstellen oder sie dauerhaft aus dem System entfernen. Diese Liste ist nicht gefiltert, im Gegensatz zu ähnlichen Aktivitätslisten im System, wo Berechtigungsfilter angewendet werden.', - 'recycle_bin_deleted_item' => 'Gelöschtes Element', + 'recycle_bin_desc' => 'Hier können Sie gelöschte Einträge wiederherstellen oder sie dauerhaft aus dem System entfernen. Diese Liste ist nicht gefiltert, im Gegensatz zu ähnlichen Aktivitätslisten im System, wo Berechtigungsfilter angewendet werden.', + 'recycle_bin_deleted_item' => 'Gelöschter Eintrag', 'recycle_bin_deleted_by' => 'Gelöscht von', 'recycle_bin_deleted_at' => 'Löschzeitpunkt', 'recycle_bin_permanently_delete' => 'Dauerhaft löschen', 'recycle_bin_restore' => 'Wiederherstellen', 'recycle_bin_contents_empty' => 'Der Papierkorb ist derzeit leer', 'recycle_bin_empty' => 'Papierkorb leeren', - 'recycle_bin_empty_confirm' => 'Dies wird alle Gegenstände im Papierkorb dauerhaft entfernen, einschließlich der Inhalte, die darin enthalten sind. Sind Sie sicher, dass Sie den Papierkorb leeren möchten?', - 'recycle_bin_destroy_confirm' => 'Diese Aktion wird dieses Element zusammen mit allen unten aufgeführten Unterelementen dauerhaft aus dem System löschen und Sie werden nicht in der Lage sein, diesen Inhalt wiederherzustellen. Sind Sie sicher, dass Sie dieses Element endgültig löschen möchten?', - 'recycle_bin_destroy_list' => 'Zu löschende Elemente', - 'recycle_bin_restore_list' => 'Zu wiederherzustellende Elemente', - 'recycle_bin_restore_confirm' => 'Mit dieser Aktion wird das gelöschte Element einschließlich aller untergeordneten Elemente an seinen ursprünglichen Ort wiederherstellen. Wenn der ursprüngliche Ort gelöscht wurde und sich nun im Papierkorb befindet, muss auch das übergeordnete Element wiederhergestellt werden.', - 'recycle_bin_restore_deleted_parent' => 'Das übergeordnete Elements wurde ebenfalls gelöscht. Dieses Element wird weiterhin als gelöscht zählen, bis auch das übergeordnete Element wiederhergestellt wurde.', - 'recycle_bin_destroy_notification' => ':count Elemente wurden aus dem Papierkorb gelöscht.', - 'recycle_bin_restore_notification' => ':count Elemente wurden aus dem Papierkorb wiederhergestellt.', + 'recycle_bin_empty_confirm' => 'Dies wird alle Einträge im Papierkorb dauerhaft entfernen, einschließlich der Inhalte, die darin enthalten sind. Sind Sie sicher, dass Sie den Papierkorb leeren möchten?', + 'recycle_bin_destroy_confirm' => 'Diese Aktion wird diesen Eintrag zusammen mit allen unten aufgeführten Untereinträgen dauerhaft aus dem System löschen und Sie werden nicht in der Lage sein, diesen Inhalt wiederherzustellen. Sind Sie sicher, dass Sie diesen Eintrag endgültig löschen möchten?', + 'recycle_bin_destroy_list' => 'Zu löschende Einträge', + 'recycle_bin_restore_list' => 'Wiederherzustellende Einträge', + 'recycle_bin_restore_confirm' => 'Mit dieser Aktion wird der gelöschte Eintrag einschließlich aller untergeordneten Einträge an seinen ursprünglichen Ort wiederherstellen. Wenn der ursprüngliche Ort gelöscht wurde und sich nun im Papierkorb befindet, muss auch der übergeordnete Eintrag wiederhergestellt werden.', + 'recycle_bin_restore_deleted_parent' => 'Der übergeordnete Eintrag wurde ebenfalls gelöscht. Dieser Eintrag wird weiterhin als gelöscht zählen, bis auch der übergeordnete Eintrag wiederhergestellt wurde.', + 'recycle_bin_destroy_notification' => ':count Einträge wurden aus dem Papierkorb gelöscht.', + 'recycle_bin_restore_notification' => ':count Einträge wurden aus dem Papierkorb wiederhergestellt.', // Audit Log - 'audit' => 'Audit-Protokoll', + 'audit' => 'Änderungsprotokoll', 'audit_desc' => 'Dieses Audit-Protokoll zeigt eine Liste der Aktivitäten an, welche vom System protokolliert werden. Im Gegensatz zu den anderen Aktivitätslisten im System, bei denen Berechtigungen angewendet werden, ist diese Liste ungefiltert.', 'audit_event_filter' => 'Ereignisfilter', 'audit_event_filter_no_filter' => 'Kein Filter', - 'audit_deleted_item' => 'Gelöschtes Objekt', + 'audit_deleted_item' => 'Gelöschtes Element', 'audit_deleted_item_name' => 'Name: :name', 'audit_table_user' => 'Benutzer', 'audit_table_event' => 'Ereignis', - 'audit_table_related' => 'Verknüpftes Element oder Detail', + 'audit_table_related' => 'Verknüpfter Eintrag oder Detail', 'audit_table_date' => 'Aktivitätsdatum', 'audit_date_from' => 'Zeitraum von', 'audit_date_to' => 'Zeitraum bis', @@ -178,10 +183,10 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'users_delete_named' => 'Benutzer ":userName" löschen', 'users_delete_warning' => 'Der Benutzer ":userName" wird aus dem System gelöscht.', 'users_delete_confirm' => 'Bist Du sicher, dass Du diesen Benutzer löschen möchtest?', - 'users_migrate_ownership' => 'Migrate Ownership', - 'users_migrate_ownership_desc' => 'Select a user here if you want another user to become the owner of all items currently owned by this user.', - 'users_none_selected' => 'No user selected', - 'users_delete_success' => 'User successfully removed', + 'users_migrate_ownership' => 'Besitz migrieren', + 'users_migrate_ownership_desc' => 'Wählen Sie hier einen Benutzer, wenn Sie möchten, dass ein anderer Benutzer der Besitzer aller Einträge wird, die diesem Benutzer derzeit gehören.', + 'users_none_selected' => 'Kein Benutzer ausgewählt', + 'users_delete_success' => 'Benutzer erfolgreich entfernt', 'users_edit' => 'Benutzer bearbeiten', 'users_edit_profile' => 'Profil bearbeiten', 'users_edit_success' => 'Benutzer erfolgreich aktualisisert', @@ -229,6 +234,8 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bulgarisch', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Dänisch', 'de' => 'Deutsch (Sie)', @@ -238,12 +245,15 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/de_informal/validation.php b/resources/lang/de_informal/validation.php index 24c1e8add..42456da6e 100644 --- a/resources/lang/de_informal/validation.php +++ b/resources/lang/de_informal/validation.php @@ -78,7 +78,6 @@ return [ 'string' => ':attribute muss mindestens :min Zeichen lang sein.', 'array' => ':attribute muss mindesten :min Elemente enthalten.', ], - 'no_double_extension' => ':attribute darf nur eine gültige Dateiendung', 'not_in' => ':attribute ist ungültig.', 'not_regex' => ':attribute ist kein gültiges Format.', 'numeric' => ':attribute muss eine Zahl sein.', diff --git a/resources/lang/en/entities.php b/resources/lang/en/entities.php index 6c0980fab..1661bae57 100644 --- a/resources/lang/en/entities.php +++ b/resources/lang/en/entities.php @@ -60,6 +60,7 @@ return [ 'search_permissions_set' => 'Permissions set', 'search_created_by_me' => 'Created by me', 'search_updated_by_me' => 'Updated by me', + 'search_owned_by_me' => 'Owned by me', 'search_date_options' => 'Date Options', 'search_updated_before' => 'Updated before', 'search_updated_after' => 'Updated after', @@ -316,4 +317,4 @@ return [ 'revision_restore_confirm' => 'Are you sure you want to restore this revision? The current page contents will be replaced.', 'revision_delete_success' => 'Revision deleted', 'revision_cannot_delete_latest' => 'Cannot delete the latest revision.' -]; \ No newline at end of file +]; diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index bd55668a2..ab7f15322 100755 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -231,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', @@ -240,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/en/validation.php b/resources/lang/en/validation.php index 578ea999f..4031de2ae 100644 --- a/resources/lang/en/validation.php +++ b/resources/lang/en/validation.php @@ -78,7 +78,6 @@ return [ 'string' => 'The :attribute must be at least :min characters.', 'array' => 'The :attribute must have at least :min items.', ], - 'no_double_extension' => 'The :attribute must only have a single file extension.', 'not_in' => 'The selected :attribute is invalid.', 'not_regex' => 'The :attribute format is invalid.', 'numeric' => 'The :attribute must be a number.', diff --git a/resources/lang/es/common.php b/resources/lang/es/common.php index 9c6575a53..64b73e27c 100644 --- a/resources/lang/es/common.php +++ b/resources/lang/es/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'Si está teniendo problemas clicando en el botón ":actionText", copie y pegue la siguiente URL en su navegador web:', 'email_rights' => 'Todos los derechos reservados', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Política de privacidad', + 'terms_of_service' => 'Términos de Servicio', ]; diff --git a/resources/lang/es/settings.php b/resources/lang/es/settings.php index d6488eded..d6a208b8c 100644 --- a/resources/lang/es/settings.php +++ b/resources/lang/es/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'Página de inicio', 'app_homepage_desc' => 'Elija la vista que se mostrará en la página de inicio en lugar de la vista predeterminada. Se ignorarán los permisos de la página seleccionada.', 'app_homepage_select' => 'Elija una página', + 'app_footer_links' => 'Enlaces de pie de página', + 'app_footer_links_desc' => 'Añade enlaces para mostrar dentro del pie de página del sitio. Estos se mostrarán en la parte inferior de la mayoría de las páginas, incluyendo aquellas que no requieren estar registrado. Puede utilizar una etiqueta de "trans::" para utilizar traducciones definidas por el sistema. Por ejemplo: el uso de "trans::common.privacy_policy" proporcionará el texto traducido "Política de privacidad" y "trans::common.terms_of_service" proporcionará el texto traducido "Términos de servicio".', + 'app_footer_links_label' => 'Etiqueta del enlace', + 'app_footer_links_url' => 'Dirección URL del enlace', + 'app_footer_links_add' => 'Añadir enlace al pie de página', 'app_disable_comments' => 'Deshabilitar Comentarios', 'app_disable_comments_toggle' => 'Deshabilitar comentarios', 'app_disable_comments_desc' => 'Deshabilita los comentarios en todas las páginas de la aplicación.
Los comentarios existentes no se muestran.', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Danés', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/es/validation.php b/resources/lang/es/validation.php index f6f9a1ee1..450e92375 100644 --- a/resources/lang/es/validation.php +++ b/resources/lang/es/validation.php @@ -78,7 +78,6 @@ return [ 'string' => 'El :attribute debe ser al menos :min caracteres.', 'array' => 'El :attribute debe tener como mínimo :min items.', ], - 'no_double_extension' => 'El :attribute solo debe tener una extensión de archivo.', 'not_in' => 'El :attribute seleccionado es inválio.', 'not_regex' => 'El formato de :attribute es inválido.', 'numeric' => 'El :attribute debe ser numérico.', diff --git a/resources/lang/es_AR/common.php b/resources/lang/es_AR/common.php index c6bef56bc..f4f712fcc 100644 --- a/resources/lang/es_AR/common.php +++ b/resources/lang/es_AR/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'Si está teniendo problemas haga click en el botón ":actionText", copie y pegue la siguiente URL en su navegador web:', 'email_rights' => 'Todos los derechos reservados', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Política de privacidad', + 'terms_of_service' => 'Términos de Servicio', ]; diff --git a/resources/lang/es_AR/entities.php b/resources/lang/es_AR/entities.php index 093641a36..7a6a51e55 100644 --- a/resources/lang/es_AR/entities.php +++ b/resources/lang/es_AR/entities.php @@ -148,7 +148,7 @@ return [ 'chapters_create' => 'Crear nuevo capítulo', 'chapters_delete' => 'Borrar capítulo', 'chapters_delete_named' => 'Borrar capítulo :chapterName', - 'chapters_delete_explain' => 'Esto eliminará el capítulo con el nombre \':chapterName\'. También se eliminarán todas las páginas que existen dentro de este capítulo.', + 'chapters_delete_explain' => 'Esta acción eliminará el capítulo con el nombre \':chapterName\'. Todas las páginas que existen dentro del capítulo también se eliminarán.', 'chapters_delete_confirm' => '¿Está seguro de borrar este capítulo?', 'chapters_edit' => 'Editar capítulo', 'chapters_edit_named' => 'Editar capítulo :chapterName', @@ -210,7 +210,7 @@ return [ 'pages_revisions' => 'Revisiones de página', 'pages_revisions_named' => 'Revisiones de página para :pageName', 'pages_revision_named' => 'Revisión de ágina para :pageName', - 'pages_revision_restored_from' => 'Restaurado de #:id; :summary', + 'pages_revision_restored_from' => 'Restaurado desde #:id; :summary', 'pages_revisions_created_by' => 'Creado por', 'pages_revisions_date' => 'Fecha de revisión', 'pages_revisions_number' => '#', diff --git a/resources/lang/es_AR/settings.php b/resources/lang/es_AR/settings.php index 8ab094183..0c3277ba9 100644 --- a/resources/lang/es_AR/settings.php +++ b/resources/lang/es_AR/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'Página de inicio de la Aplicación', 'app_homepage_desc' => 'Seleccione una página de inicio para mostrar en lugar de la vista por defecto. Se ignoran los permisos de página para las páginas seleccionadas.', 'app_homepage_select' => 'Seleccione una página', + 'app_footer_links' => 'Enlaces de pie de página', + 'app_footer_links_desc' => 'Añade enlaces para mostrar dentro del pie de página del sitio. Estos se mostrarán en la parte inferior de la mayoría de las páginas, incluyendo aquellas que no requieren estar registrado. Puede utilizar una etiqueta de "trans::" para utilizar traducciones definidas por el sistema. Por ejemplo: el uso de "trans::common.privacy_policy" proporcionará el texto traducido "Política de privacidad" y "trans::common.terms_of_service" proporcionará el texto traducido "Términos de servicio".', + 'app_footer_links_label' => 'Etiqueta del enlace', + 'app_footer_links_url' => 'Dirección URL del enlace', + 'app_footer_links_add' => 'Añadir enlace al pie de página', 'app_disable_comments' => 'Deshabilitar comentarios', 'app_disable_comments_toggle' => 'Deshabilitar comentarios', 'app_disable_comments_desc' => 'Deshabilitar comentarios en todas las páginas de la aplicación. Los comentarios existentes no se muestran.', @@ -227,6 +232,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Danés', 'de' => 'Deutsch (Sie)', @@ -236,12 +243,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/es_AR/validation.php b/resources/lang/es_AR/validation.php index 7afd2bb46..c3f5d83dd 100644 --- a/resources/lang/es_AR/validation.php +++ b/resources/lang/es_AR/validation.php @@ -78,7 +78,6 @@ return [ 'string' => ':attribute debe ser al menos :min caracteres.', 'array' => ':attribute debe tener como mínimo :min items.', ], - 'no_double_extension' => 'El :attribute debe tener una única extensión de archivo.', 'not_in' => ':attribute seleccionado es inválido.', 'not_regex' => 'El formato de :attribute es inválido.', 'numeric' => ':attribute debe ser numérico.', @@ -90,7 +89,7 @@ return [ 'required_without' => ':attribute es requerido cuando no se encuentre entre los valores :values.', 'required_without_all' => ':attribute es requerido cuando ninguno de los valores :values están presentes.', 'same' => ':attribute y :other deben coincidir.', - 'safe_url' => 'El enlace proporcionado puede no ser seguro.', + 'safe_url' => 'El enlace provisto puede ser inseguro.', 'size' => [ 'numeric' => ':attribute debe ser :size.', 'file' => ':attribute debe ser :size kilobytes.', diff --git a/resources/lang/fa/activities.php b/resources/lang/fa/activities.php index 4cac54b2a..fe937b061 100644 --- a/resources/lang/fa/activities.php +++ b/resources/lang/fa/activities.php @@ -45,4 +45,5 @@ return [ // Other 'commented_on' => 'commented on', + 'permissions_update' => 'updated permissions', ]; diff --git a/resources/lang/fa/common.php b/resources/lang/fa/common.php index e87bd11a5..e048db90f 100644 --- a/resources/lang/fa/common.php +++ b/resources/lang/fa/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'If you’re having trouble clicking the ":actionText" button, copy and paste the URL below into your web browser:', 'email_rights' => 'All rights reserved', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privacy Policy', + 'terms_of_service' => 'Terms of Service', ]; diff --git a/resources/lang/fa/entities.php b/resources/lang/fa/entities.php index f64867a56..6c0980fab 100644 --- a/resources/lang/fa/entities.php +++ b/resources/lang/fa/entities.php @@ -22,6 +22,7 @@ return [ 'meta_created_name' => 'Created :timeLength by :user', 'meta_updated' => 'Updated :timeLength', 'meta_updated_name' => 'Updated :timeLength by :user', + 'meta_owned_name' => 'Owned by :user', 'entity_select' => 'Entity Select', 'images' => 'Images', 'my_recent_drafts' => 'My Recent Drafts', @@ -39,6 +40,7 @@ return [ 'permissions_intro' => 'Once enabled, These permissions will take priority over any set role permissions.', 'permissions_enable' => 'Enable Custom Permissions', 'permissions_save' => 'Save Permissions', + 'permissions_owner' => 'Owner', // Search 'search_results' => 'Search Results', @@ -146,7 +148,7 @@ return [ 'chapters_create' => 'Create New Chapter', 'chapters_delete' => 'Delete Chapter', 'chapters_delete_named' => 'Delete Chapter :chapterName', - 'chapters_delete_explain' => 'This will delete the chapter with the name \':chapterName\'. All pages will be removed and added directly to the parent book.', + 'chapters_delete_explain' => 'This will delete the chapter with the name \':chapterName\'. All pages that exist within this chapter will also be deleted.', 'chapters_delete_confirm' => 'Are you sure you want to delete this chapter?', 'chapters_edit' => 'Edit Chapter', 'chapters_edit_named' => 'Edit Chapter :chapterName', @@ -208,6 +210,7 @@ return [ 'pages_revisions' => 'Page Revisions', 'pages_revisions_named' => 'Page Revisions for :pageName', 'pages_revision_named' => 'Page Revision for :pageName', + 'pages_revision_restored_from' => 'Restored from #:id; :summary', 'pages_revisions_created_by' => 'Created By', 'pages_revisions_date' => 'Revision Date', 'pages_revisions_number' => '#', diff --git a/resources/lang/fa/settings.php b/resources/lang/fa/settings.php index 2bd314cf0..ab7f15322 100644 --- a/resources/lang/fa/settings.php +++ b/resources/lang/fa/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'Application Homepage', 'app_homepage_desc' => 'Select a view to show on the homepage instead of the default view. Page permissions are ignored for selected pages.', 'app_homepage_select' => 'Select a page', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', 'app_disable_comments' => 'Disable Comments', 'app_disable_comments_toggle' => 'Disable comments', 'app_disable_comments_desc' => 'Disables comments across all pages in the application.
Existing comments are not shown.', @@ -68,7 +73,7 @@ return [ 'maint' => 'Maintenance', 'maint_image_cleanup' => 'Cleanup Images', 'maint_image_cleanup_desc' => "Scans page & revision content to check which images and drawings are currently in use and which images are redundant. Ensure you create a full database and image backup before running this.", - 'maint_image_cleanup_ignore_revisions' => 'Ignore images in revisions', + 'maint_delete_images_only_in_revisions' => 'Also delete images that only exist in old page revisions', 'maint_image_cleanup_run' => 'Run Cleanup', 'maint_image_cleanup_warning' => ':count potentially unused images were found. Are you sure you want to delete these images?', 'maint_image_cleanup_success' => ':count potentially unused images found and deleted!', @@ -80,6 +85,27 @@ return [ 'maint_send_test_email_mail_subject' => 'Test Email', 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', + 'maint_recycle_bin_desc' => 'Deleted shelves, books, chapters & pages are sent to the recycle bin so they can be restored or permanently deleted. Older items in the recycle bin may be automatically removed after a while depending on system configuration.', + 'maint_recycle_bin_open' => 'Open Recycle Bin', + + // Recycle Bin + 'recycle_bin' => 'Recycle Bin', + 'recycle_bin_desc' => 'Here you can restore items that have been deleted or choose to permanently remove them from the system. This list is unfiltered unlike similar activity lists in the system where permission filters are applied.', + 'recycle_bin_deleted_item' => 'Deleted Item', + 'recycle_bin_deleted_by' => 'Deleted By', + 'recycle_bin_deleted_at' => 'Deletion Time', + 'recycle_bin_permanently_delete' => 'Permanently Delete', + 'recycle_bin_restore' => 'Restore', + 'recycle_bin_contents_empty' => 'The recycle bin is currently empty', + 'recycle_bin_empty' => 'Empty Recycle Bin', + 'recycle_bin_empty_confirm' => 'This will permanently destroy all items in the recycle bin including content contained within each item. Are you sure you want to empty the recycle bin?', + 'recycle_bin_destroy_confirm' => 'This action will permanently delete this item, along with any child elements listed below, from the system and you will not be able to restore this content. Are you sure you want to permanently delete this item?', + 'recycle_bin_destroy_list' => 'Items to be Destroyed', + 'recycle_bin_restore_list' => 'Items to be Restored', + 'recycle_bin_restore_confirm' => 'This action will restore the deleted item, including any child elements, to their original location. If the original location has since been deleted, and is now in the recycle bin, the parent item will also need to be restored.', + 'recycle_bin_restore_deleted_parent' => 'The parent of this item has also been deleted. These will remain deleted until that parent is also restored.', + 'recycle_bin_destroy_notification' => 'Deleted :count total items from the recycle bin.', + 'recycle_bin_restore_notification' => 'Restored :count total items from the recycle bin.', // Audit Log 'audit' => 'Audit Log', @@ -90,7 +116,7 @@ return [ 'audit_deleted_item_name' => 'Name: :name', 'audit_table_user' => 'User', 'audit_table_event' => 'Event', - 'audit_table_item' => 'Related Item', + 'audit_table_related' => 'Related Item or Detail', 'audit_table_date' => 'Activity Date', 'audit_date_from' => 'Date Range From', 'audit_date_to' => 'Date Range To', @@ -136,6 +162,7 @@ return [ 'user_profile' => 'User Profile', 'users_add_new' => 'Add New User', 'users_search' => 'Search Users', + 'users_latest_activity' => 'Latest Activity', 'users_details' => 'User Details', 'users_details_desc' => 'Set a display name and an email address for this user. The email address will be used for logging into the application.', 'users_details_desc_no_email' => 'Set a display name for this user so others can recognise them.', @@ -153,7 +180,10 @@ return [ 'users_delete_named' => 'Delete user :userName', 'users_delete_warning' => 'This will fully delete this user with the name \':userName\' from the system.', 'users_delete_confirm' => 'Are you sure you want to delete this user?', - 'users_delete_success' => 'Users successfully removed', + 'users_migrate_ownership' => 'Migrate Ownership', + 'users_migrate_ownership_desc' => 'Select a user here if you want another user to become the owner of all items currently owned by this user.', + 'users_none_selected' => 'No user selected', + 'users_delete_success' => 'User successfully removed', 'users_edit' => 'Edit User', 'users_edit_profile' => 'Edit Profile', 'users_edit_success' => 'User successfully updated', @@ -179,7 +209,7 @@ return [ 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', 'user_api_token_expiry' => 'Expiry Date', 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', - 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', 'user_api_token_create_success' => 'API token successfully created', 'user_api_token_update_success' => 'API token successfully updated', 'user_api_token' => 'API Token', @@ -187,8 +217,8 @@ return [ 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', 'user_api_token_secret' => 'Token Secret', 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', - 'user_api_token_created' => 'Token Created :timeAgo', - 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_created' => 'Token created :timeAgo', + 'user_api_token_updated' => 'Token updated :timeAgo', 'user_api_token_delete' => 'Delete Token', 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', @@ -200,6 +230,9 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', @@ -209,11 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', + 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/fa/validation.php b/resources/lang/fa/validation.php index 76b57a2a3..4031de2ae 100644 --- a/resources/lang/fa/validation.php +++ b/resources/lang/fa/validation.php @@ -78,7 +78,6 @@ return [ 'string' => 'The :attribute must be at least :min characters.', 'array' => 'The :attribute must have at least :min items.', ], - 'no_double_extension' => 'The :attribute must only have a single file extension.', 'not_in' => 'The selected :attribute is invalid.', 'not_regex' => 'The :attribute format is invalid.', 'numeric' => 'The :attribute must be a number.', @@ -90,6 +89,7 @@ return [ 'required_without' => 'The :attribute field is required when :values is not present.', 'required_without_all' => 'The :attribute field is required when none of :values are present.', 'same' => 'The :attribute and :other must match.', + 'safe_url' => 'The provided link may not be safe.', 'size' => [ 'numeric' => 'The :attribute must be :size.', 'file' => 'The :attribute must be :size kilobytes.', diff --git a/resources/lang/fr/common.php b/resources/lang/fr/common.php index 6571db60c..641b6af9c 100644 --- a/resources/lang/fr/common.php +++ b/resources/lang/fr/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'Si vous rencontrez des problèmes pour cliquer sur le bouton ":actionText", copiez et collez l\'adresse ci-dessous dans votre navigateur :', 'email_rights' => 'Tous droits réservés', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Politique de confidentialité', + 'terms_of_service' => 'Conditions d\'utilisation', ]; diff --git a/resources/lang/fr/settings.php b/resources/lang/fr/settings.php index 89e2f0ca5..ee1c8472d 100644 --- a/resources/lang/fr/settings.php +++ b/resources/lang/fr/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'Page d\'accueil de l\'application', 'app_homepage_desc' => 'Choisissez une page à afficher sur la page d\'accueil au lieu de la vue par défaut. Les permissions sont ignorées pour les pages sélectionnées.', 'app_homepage_select' => 'Choisissez une page', + 'app_footer_links' => 'Liens de pied de page', + 'app_footer_links_desc' => 'Ajoutez des liens dans le pied de page du site. Ils seront affichés en bas de la plupart des pages, incluant celles qui ne nécesittent pas de connexion. Vous pouvez utiliser l\'étiquette "trans::" pour utiliser les traductions définies par le système. Par exemple, utiliser "trans::common.privacy_policy" fournira la traduction de "Politique de Confidentalité" et "trans::common.terms_of_service" fournira la traduction de "Conditions d\'utilisation".', + 'app_footer_links_label' => 'Libellé du lien', + 'app_footer_links_url' => 'URL du lien', + 'app_footer_links_add' => 'Ajouter un lien en pied de page', 'app_disable_comments' => 'Désactiver les commentaires', 'app_disable_comments_toggle' => 'Désactiver les commentaires', 'app_disable_comments_desc' => 'Désactive les commentaires sur toutes les pages de l\'application. Les commentaires existants ne sont pas affichés.', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bulgare', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Danois', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'Hébreu', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norvegien', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/fr/validation.php b/resources/lang/fr/validation.php index 60d8d34ac..684404f42 100644 --- a/resources/lang/fr/validation.php +++ b/resources/lang/fr/validation.php @@ -78,7 +78,6 @@ return [ 'string' => ':attribute doit contenir au moins :min caractères.', 'array' => ':attribute doit contenir au moins :min éléments.', ], - 'no_double_extension' => ':attribute ne doit avoir qu\'une seule extension de fichier.', 'not_in' => 'L\'attribut sélectionné :attribute est invalide.', 'not_regex' => ':attribute a un format invalide.', 'numeric' => ':attribute doit être un nombre.', diff --git a/resources/lang/he/common.php b/resources/lang/he/common.php index 8a6311abd..0cfb9b3fa 100644 --- a/resources/lang/he/common.php +++ b/resources/lang/he/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'אם לא ניתן ללחות על כפתור ״:actionText״, יש להעתיק ולהדביק את הכתובת למטה אל דפדפן האינטרנט שלך:', 'email_rights' => 'כל הזכויות שמורות', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privacy Policy', + 'terms_of_service' => 'Terms of Service', ]; diff --git a/resources/lang/he/components.php b/resources/lang/he/components.php index 84ff7c310..48f7aa2d2 100644 --- a/resources/lang/he/components.php +++ b/resources/lang/he/components.php @@ -15,7 +15,7 @@ return [ 'image_load_more' => 'טען עוד', 'image_image_name' => 'שם התמונה', 'image_delete_used' => 'תמונה זו בשימוש בדפים שמתחת', - 'image_delete_confirm_text' => 'Are you sure you want to delete this image?', + 'image_delete_confirm_text' => 'האם את/ה בטוח/ה שברצונך למחוק את התמונה הזו?', 'image_select_image' => 'בחר תמונה', 'image_dropzone' => 'גרור תמונות או לחץ כאן להעלאה', 'images_deleted' => 'התמונות נמחקו', @@ -29,6 +29,6 @@ return [ 'code_editor' => 'ערוך קוד', 'code_language' => 'שפת הקוד', 'code_content' => 'תוכן הקוד', - 'code_session_history' => 'Session History', + 'code_session_history' => 'היסטורית ה-Session', 'code_save' => 'שמור קוד', ]; diff --git a/resources/lang/he/passwords.php b/resources/lang/he/passwords.php index 17fad68d5..a94d7c30b 100644 --- a/resources/lang/he/passwords.php +++ b/resources/lang/he/passwords.php @@ -6,10 +6,10 @@ */ return [ - 'password' => 'הסיסמא חייבת להיות בעלת 6 תווים ולהתאים לאימות', - 'user' => "לא ניתן למצוא משתמש עם המייל שסופק", - 'token' => 'The password reset token is invalid for this email address.', - 'sent' => 'נשלח אליך אי-מייל עם קישור לאיפוס הסיסמא', - 'reset' => 'איפוס הסיסמא הושלם בהצלחה!', + 'password' => 'הסיסמה חייבת להיות בעלת 8 תווים לפחות ולהתאים לאימות.', + 'user' => "לא נמצא משתמש עם כתובת דוא\"ל זו.", + 'token' => 'אסימון איפוס הסיסמה לא תקף עבור כתובת דוא"ל זו.', + 'sent' => 'שלחנו לך דוא"ל עם קישור לאיפוס הסיסמה!', + 'reset' => 'איפוס הסיסמה הושלם בהצלחה!', ]; diff --git a/resources/lang/he/settings.php b/resources/lang/he/settings.php index a0632d061..b7ce52769 100755 --- a/resources/lang/he/settings.php +++ b/resources/lang/he/settings.php @@ -37,18 +37,23 @@ return [ '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', - 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', - 'bookshelf_color' => 'Shelf Color', - 'book_color' => 'Book Color', - 'chapter_color' => 'Chapter Color', - 'page_color' => 'Page Color', - 'page_draft_color' => 'Page Draft Color', + 'content_colors' => 'צבעי התוכן', + 'content_colors_desc' => 'מגדיר צבעים לכל האלמנטים בהיררכיה הארגונית של הדף. לחווית קריאה מיטבית, מומלץ לבחור צבעים בבהירות הדומה לצבעי ברירת המחדל.', + 'bookshelf_color' => 'צבע המדף', + 'book_color' => 'צבע הספר', + 'chapter_color' => 'צבע הפרק', + 'page_color' => 'צבע העמוד', + 'page_draft_color' => 'צבע טיוטת העמוד', // Registration Settings 'reg_settings' => 'הרשמה', @@ -56,7 +61,7 @@ return [ 'reg_enable_toggle' => 'אפשר להרשם', 'reg_enable_desc' => 'כאשר אפשר להרשם משתמשים יוכלו להכנס באופן עצמאי. בעת ההרשמה המשתמש יקבל הרשאה יחידה כברירת מחדל.', 'reg_default_role' => 'הרשאה כברירת מחדל', - 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', + 'reg_enable_external_warning' => 'האפשרות לעיל חסרת השפעה כאשר מתבצע שימוש באותנטיקציה חיצונית מסוג LDAP או SAML. חשבונות משתמש לחברים לא קיימים יווצרו באופן אוטומטי במידה ואותנטיקציה, הנוגדת את המערכת החיצונית בשימוש, מצליחה.', 'reg_email_confirmation' => 'אימות כתובת אי-מייל', 'reg_email_confirmation_toggle' => 'יש לאמת את כתובת המייל', 'reg_confirm_email_desc' => 'אם מופעלת הגבלה לדומיין ספציפי אז אימות המייל לא יבוצע', @@ -68,53 +73,53 @@ return [ 'maint' => 'תחזוקה', 'maint_image_cleanup' => 'ניקוי תמונות', 'maint_image_cleanup_desc' => "סורק את הדפים והגרסאות על מנת למצוא אילו תמונות לא בשימוש. יש לוודא גיבוי מלא של מסד הנתונים והתמונות לפני הרצה", - 'maint_delete_images_only_in_revisions' => 'Also delete images that only exist in old page revisions', + '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' => 'Send a Test Email', - 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', - 'maint_send_test_email_run' => 'Send test email', - 'maint_send_test_email_success' => 'Email sent to :address', - 'maint_send_test_email_mail_subject' => 'Test Email', - 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', - 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', - 'maint_recycle_bin_desc' => 'Deleted shelves, books, chapters & pages are sent to the recycle bin so they can be restored or permanently deleted. Older items in the recycle bin may be automatically removed after a while depending on system configuration.', - 'maint_recycle_bin_open' => 'Open Recycle Bin', + 'maint_send_test_email' => 'שלח דוא"ל ניסיוני', + 'maint_send_test_email_desc' => 'שולח דוא"ל ניסיוני לכתובת הדוא"ל המצוינת בפרופיל שלך.', + 'maint_send_test_email_run' => 'שלח דוא"ל ניסיוני', + 'maint_send_test_email_success' => 'דוא"ל נשלח לכתובת :address', + 'maint_send_test_email_mail_subject' => 'דוא"ל ניסיוני', + 'maint_send_test_email_mail_greeting' => 'נראה ששליחת דוא"ל עובדת!', + 'maint_send_test_email_mail_text' => 'ברכות! מאחר וקיבלת התראת דוא"ל זו, נראה שהגדרות הדוא"ל שלך הוגדרו כמו שצריך.', + 'maint_recycle_bin_desc' => 'מדפים, ספרים, פרקים חדשים שנמחקו נשלחים לסל המיחזור, כדי שתוכלו לאחזר אותם או למחוק אותם לצמיתות. ייתכן שפריטים ישנים יותר בסל המיחזור יימחקו באופן אוטומטי לאחר זמן-מה, בהסתמך על הגדרות המערכת.', + 'maint_recycle_bin_open' => 'פתח את סל המיחזור', // Recycle Bin - 'recycle_bin' => 'Recycle Bin', - 'recycle_bin_desc' => 'Here you can restore items that have been deleted or choose to permanently remove them from the system. This list is unfiltered unlike similar activity lists in the system where permission filters are applied.', - 'recycle_bin_deleted_item' => 'Deleted Item', - 'recycle_bin_deleted_by' => 'Deleted By', - 'recycle_bin_deleted_at' => 'Deletion Time', - 'recycle_bin_permanently_delete' => 'Permanently Delete', - 'recycle_bin_restore' => 'Restore', - 'recycle_bin_contents_empty' => 'The recycle bin is currently empty', - 'recycle_bin_empty' => 'Empty Recycle Bin', - 'recycle_bin_empty_confirm' => 'This will permanently destroy all items in the recycle bin including content contained within each item. Are you sure you want to empty the recycle bin?', - 'recycle_bin_destroy_confirm' => 'This action will permanently delete this item, along with any child elements listed below, from the system and you will not be able to restore this content. Are you sure you want to permanently delete this item?', - 'recycle_bin_destroy_list' => 'Items to be Destroyed', - 'recycle_bin_restore_list' => 'Items to be Restored', - 'recycle_bin_restore_confirm' => 'This action will restore the deleted item, including any child elements, to their original location. If the original location has since been deleted, and is now in the recycle bin, the parent item will also need to be restored.', - 'recycle_bin_restore_deleted_parent' => 'The parent of this item has also been deleted. These will remain deleted until that parent is also restored.', - 'recycle_bin_destroy_notification' => 'Deleted :count total items from the recycle bin.', - 'recycle_bin_restore_notification' => 'Restored :count total items from the recycle bin.', + 'recycle_bin' => 'סל המיחזור', + 'recycle_bin_desc' => 'כאן תוכלו לאחזר פריטים שנמחקו או לבחור למחוק אותם מהמערכת לצמיתות. רשימה זו לא מסוננת, בשונה מרשימות פעילות דומות במערכת, בהן מוחלים מסנני הרשאות.', + 'recycle_bin_deleted_item' => 'פריט שנמחק', + '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_destroy_notification' => 'נמחקו בסה"כ :count פריטים מסל המיחזור.', + 'recycle_bin_restore_notification' => 'אוחזרו בסה"כ :count פריטים מסל המיחזור.', // Audit Log - 'audit' => 'Audit Log', - 'audit_desc' => 'This audit log displays a list of activities tracked in the system. This list is unfiltered unlike similar activity lists in the system where permission filters are applied.', - 'audit_event_filter' => 'Event Filter', - 'audit_event_filter_no_filter' => 'No Filter', - 'audit_deleted_item' => 'Deleted Item', - 'audit_deleted_item_name' => 'Name: :name', - 'audit_table_user' => 'User', - 'audit_table_event' => 'Event', - 'audit_table_related' => 'Related Item or Detail', - 'audit_table_date' => 'Activity Date', - 'audit_date_from' => 'Date Range From', - 'audit_date_to' => 'Date Range To', + '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_date' => 'זמן הפעילות', + 'audit_date_from' => 'טווח תאריכים החל מ...', + 'audit_date_to' => 'טווח תאריכים עד ל...', // Role Settings 'roles' => 'תפקידים', @@ -131,17 +136,17 @@ return [ 'role_details' => 'פרטי תפקיד', 'role_name' => 'שם התפקיד', 'role_desc' => 'תיאור קצר של התפקיד', - 'role_external_auth_id' => 'External Authentication IDs', + 'role_external_auth_id' => 'ID-י אותנטיקציה חיצוניים', 'role_system' => 'הרשאות מערכת', 'role_manage_users' => 'ניהול משתמשים', 'role_manage_roles' => 'ניהול תפקידים והרשאות תפקידים', 'role_manage_entity_permissions' => 'נהל הרשאות ספרים, פרקים ודפים', 'role_manage_own_entity_permissions' => 'נהל הרשאות על ספרים, פרקים ודפים בבעלותך', - 'role_manage_page_templates' => 'Manage page templates', - 'role_access_api' => 'Access system API', + 'role_manage_page_templates' => 'נהל תבניות דפים', + 'role_access_api' => 'גש ל-API המערכת', 'role_manage_settings' => 'ניהול הגדרות יישום', 'role_asset' => 'הרשאות משאבים', - 'roles_system_warning' => 'Be aware that access to any of the above three permissions can allow a user to alter their own privileges or the privileges of others in the system. Only assign roles with these permissions to trusted users.', + 'roles_system_warning' => 'שימו לב לכך שגישה לכל אחת משלושת ההרשאות הנ"ל יכולה לאפשר למשתמש לשנות את הפריווילגיות שלהם או של אחרים במערכת. הגדירו תפקידים להרשאות אלה למשתמשים בהם אתם בוטחים בלבד.', 'role_asset_desc' => 'הרשאות אלו שולטות בגישת ברירת המחדל למשאבים בתוך המערכת. הרשאות של ספרים, פרקים ודפים יגברו על הרשאות אלו.', 'role_asset_admins' => 'מנהלים מקבלים הרשאה מלאה לכל התוכן אך אפשרויות אלו עלולות להציג או להסתיר אפשרויות בממשק', 'role_all' => 'הכל', @@ -157,7 +162,7 @@ return [ 'user_profile' => 'פרופיל משתמש', 'users_add_new' => 'הוסף משתמש חדש', 'users_search' => 'חפש משתמשים', - 'users_latest_activity' => 'Latest Activity', + 'users_latest_activity' => 'פעילות אחרונה', 'users_details' => 'פרטי משתמש', 'users_details_desc' => 'הגדר שם לתצוגה ומייל עבור משתמש זה. כתובת המייל תשמש על מנת להתחבר למערכת', 'users_details_desc_no_email' => 'הגדר שם לתצוגה כדי שאחרים יוכלו לזהות', @@ -165,8 +170,8 @@ return [ 'users_role_desc' => 'בחר אילו תפקידים ישויכו למשתמש זה. אם המשתמש משוייך למספר תפקידים, ההרשאות יהיו כלל ההרשאות של כל התפקידים', 'users_password' => 'סיסמא', 'users_password_desc' => 'הגדר סיסמא עבור גישה למערכת. על הסיסמא להיות באורך של 5 תווים לפחות', - 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', - 'users_send_invite_option' => 'Send user invite email', + 'users_send_invite_text' => 'תוכלו לבחור לשלוח למשתמש זה דוא"ל הזמנה, המאפשר להם להגדיר סיסמה משלהם. אחרת, תוכלו להגדיר את סיסמתם בעצמכם.', + 'users_send_invite_option' => 'שלח דוא"ל הזמנה למשתמש', 'users_external_auth_id' => 'זיהוי חיצוני - ID', 'users_external_auth_id_desc' => 'זיהוי זה יהיה בשימוש מול מערכת ה LDAP שלך', 'users_password_warning' => 'יש למלא רק אם ברצונך לשנות את הסיסמא.', @@ -175,10 +180,10 @@ return [ 'users_delete_named' => 'מחק משתמש :userName', 'users_delete_warning' => 'פעולה זו תמחק את המשתמש \':userName\' מהמערכת', 'users_delete_confirm' => 'האם ברצונך למחוק משתמש זה?', - 'users_migrate_ownership' => 'Migrate Ownership', - 'users_migrate_ownership_desc' => 'Select a user here if you want another user to become the owner of all items currently owned by this user.', - 'users_none_selected' => 'No user selected', - 'users_delete_success' => 'User successfully removed', + 'users_migrate_ownership' => 'העבר בעלות', + 'users_migrate_ownership_desc' => 'בחרו משתמש כאן במידה ואתם מעוניינים שמשתמש אחר יהפוך לבעלים של כל הפריטים שכרגע בבעלות משתמש זה.', + 'users_none_selected' => 'לא נבחר משתמש', + 'users_delete_success' => 'משתמש נמחק בהצלחה', 'users_edit' => 'עריכת משתמש', 'users_edit_profile' => 'עריכת פרופיל', 'users_edit_success' => 'המשתמש עודכן בהצלחה', @@ -192,32 +197,32 @@ return [ 'users_social_disconnect' => 'ניתוק חשבון', 'users_social_connected' => 'חשבון :socialAccount חובר בהצלחה לחשבון שלך', 'users_social_disconnected' => ':socialAccount נותק בהצלחה מהחשבון שלך', - 'users_api_tokens' => 'API Tokens', - 'users_api_tokens_none' => 'No API tokens have been created for this user', - 'users_api_tokens_create' => 'Create Token', - 'users_api_tokens_expires' => 'Expires', - 'users_api_tokens_docs' => 'API Documentation', + 'users_api_tokens' => 'אסימוני API', + 'users_api_tokens_none' => 'לא נוצרו אסימוני API למשתמש זה', + 'users_api_tokens_create' => 'צור אסימון', + 'users_api_tokens_expires' => 'פג', + 'users_api_tokens_docs' => 'תיעוד API', // API Tokens - 'user_api_token_create' => 'Create API Token', - 'user_api_token_name' => 'Name', - 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', - 'user_api_token_expiry' => 'Expiry Date', - 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', - 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', - 'user_api_token_create_success' => 'API token successfully created', - 'user_api_token_update_success' => 'API token successfully updated', - 'user_api_token' => 'API Token', - 'user_api_token_id' => 'Token ID', - 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', - 'user_api_token_secret' => 'Token Secret', - 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', - 'user_api_token_created' => 'Token created :timeAgo', - 'user_api_token_updated' => 'Token updated :timeAgo', - 'user_api_token_delete' => 'Delete Token', - 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', - 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', - 'user_api_token_delete_success' => 'API token successfully deleted', + 'user_api_token_create' => 'צור אסימון API', + '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' => 'מיד לאחר יצירת אסימון זה, יווצרו ויוצגו "ID אסימון" ו"סוד אסימון". הסוד יוצג פעם אחת בלבד, לכן וודאו להעתיק את הערך למקום שמור ובטוח לפני שתמשיכו הלאה.', + 'user_api_token_create_success' => 'אסימון API נוצר בהצלחה', + 'user_api_token_update_success' => 'אסימון API עודכן בהצלחה', + 'user_api_token' => 'אסימון API', + 'user_api_token_id' => 'ID האסימון', + 'user_api_token_id_desc' => 'זהו מזהה בלתי ניתן לעריכה לאסימון זה הנוצר על ידי המערכת, אשר יסופק בבקשות API.', + 'user_api_token_secret' => 'סוד האסימון', + '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 נמחק בהצלחה', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/he/validation.php b/resources/lang/he/validation.php index 7c02735ca..8a18ca27a 100644 --- a/resources/lang/he/validation.php +++ b/resources/lang/he/validation.php @@ -78,7 +78,6 @@ return [ 'string' => 'שדה :attribute חייב להיות לפחות :min תווים.', 'array' => 'שדה :attribute חייב להיות לפחות :min פריטים.', ], - 'no_double_extension' => 'השדה :attribute חייב להיות בעל סיומת קובץ אחת בלבד.', 'not_in' => 'בחירת ה-:attribute אינה תקפה.', 'not_regex' => 'The :attribute format is invalid.', 'numeric' => 'שדה :attribute חייב להיות מספר.', diff --git a/resources/lang/hu/common.php b/resources/lang/hu/common.php index 5070adccd..d95b17629 100644 --- a/resources/lang/hu/common.php +++ b/resources/lang/hu/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'Probléma esetén a lenti ":actionText" gombra kell kattintani, majd ki kell másolni a lenti webcímet és be kell illeszteni egy böngészőbe:', 'email_rights' => 'Minden jog fenntartva', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privacy Policy', + 'terms_of_service' => 'Terms of Service', ]; diff --git a/resources/lang/hu/settings.php b/resources/lang/hu/settings.php index 9b148a61e..ba748aafe 100644 --- a/resources/lang/hu/settings.php +++ b/resources/lang/hu/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'Alkalmazás kezdőlapja', 'app_homepage_desc' => 'A kezdőlapon az alapértelmezés szerinti nézet helyett megjelenő nézet kiválasztása. A kiválasztott oldalakon figyelmen kívül lesznek hagyva az oldal engedélyek.', 'app_homepage_select' => 'Egy oldal kiválasztása', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', 'app_disable_comments' => 'Megjegyzések letiltása', 'app_disable_comments_toggle' => 'Megjegyzések letiltása', 'app_disable_comments_desc' => 'Megjegyzések letiltása az alkalmazás összes oldalán.
A már létező megjegyzések el lesznek rejtve.', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/hu/validation.php b/resources/lang/hu/validation.php index 7c378e983..d82e32632 100644 --- a/resources/lang/hu/validation.php +++ b/resources/lang/hu/validation.php @@ -78,7 +78,6 @@ return [ 'string' => ':attribute legalább :min karakter kell legyen.', 'array' => ':attribute legalább :min elem kell legyen.', ], - 'no_double_extension' => ':attribute csak egy fájlkiterjesztéssel rendelkezhet.', 'not_in' => 'A kiválasztott :attribute érvénytelen.', 'not_regex' => ':attribute formátuma érvénytelen.', 'numeric' => ':attribute szám kell legyen.', diff --git a/resources/lang/id/activities.php b/resources/lang/id/activities.php new file mode 100644 index 000000000..e0bce478a --- /dev/null +++ b/resources/lang/id/activities.php @@ -0,0 +1,49 @@ + 'halaman dibuat', + 'page_create_notification' => 'Halaman Berhasil dibuat', + 'page_update' => 'halaman diupdate', + 'page_update_notification' => 'Berhasil mengupdate halaman', + 'page_delete' => 'halaman dihapus', + 'page_delete_notification' => 'Berhasil menghapus halaman', + 'page_restore' => 'halaman telah dipulihkan', + 'page_restore_notification' => 'Berhasil memulihkan halaman', + 'page_move' => 'halaman dipindahkan', + + // Chapters + 'chapter_create' => 'membuat bab', + 'chapter_create_notification' => 'Bab berhasil dibuat', + 'chapter_update' => 'bab diperbaharui', + 'chapter_update_notification' => 'Bab berhasil diupdate', + 'chapter_delete' => 'hapus bab', + 'chapter_delete_notification' => 'Bab berhasil dihapus', + 'chapter_move' => 'bab dipindahkan', + + // Books + 'book_create' => 'membuat buku', + 'book_create_notification' => 'Buku berhasil dibuat', + 'book_update' => 'update buku', + 'book_update_notification' => 'Buku berhasil diupdate', + 'book_delete' => 'hapus buku', + 'book_delete_notification' => 'Buku berhasil dihapus', + 'book_sort' => 'urutkan buku', + 'book_sort_notification' => 'Buku berhasil diurutkan', + + // Bookshelves + 'bookshelf_create' => 'membuat rak', + 'bookshelf_create_notification' => 'Rak berhasil dibuat', + 'bookshelf_update' => 'update rak', + 'bookshelf_update_notification' => 'Rak berhasil diupdate', + 'bookshelf_delete' => 'hapus rak', + 'bookshelf_delete_notification' => 'Rak berhasil dihapus', + + // Other + 'commented_on' => 'berkomentar pada', + 'permissions_update' => 'perbaharui izin', +]; diff --git a/resources/lang/id/auth.php b/resources/lang/id/auth.php new file mode 100644 index 000000000..0fc965dae --- /dev/null +++ b/resources/lang/id/auth.php @@ -0,0 +1,77 @@ + 'Kredensial tidak cocok dengan catatan kami.', + 'throttle' => 'Terlalu banyak upaya masuk. Silahkan mencoba lagi dalam :seconds detik.', + + // Login & Register + 'sign_up' => 'Daftar', + 'log_in' => 'Gabung', + 'log_in_with' => 'Masuk dengan :socialDriver', + 'sign_up_with' => 'Daftar dengan :socialDriver', + 'logout' => 'Keluar', + + 'name' => 'Nama', + 'username' => 'Nama Pengguna', + 'email' => 'Email', + 'password' => 'Kata Sandi', + 'password_confirm' => 'Konfirmasi Kata Sandi', + 'password_hint' => 'Harus lebih dari 7 karakter', + 'forgot_password' => 'Lupa Password?', + 'remember_me' => 'Ingat saya', + 'ldap_email_hint' => 'Harap masukkan email yang akan digunakan untuk akun ini.', + 'create_account' => 'Membuat Akun', + 'already_have_account' => 'Sudah punya akun?', + 'dont_have_account' => 'Tidak punya akun?', + 'social_login' => 'Masuk dengan sosial media', + 'social_registration' => 'Daftar dengan sosial media', + 'social_registration_text' => 'Daftar dan masuk menggunakan layanan lain.', + + 'register_thanks' => 'Terima kasih telah mendaftar!', + 'register_confirm' => 'Silakan periksa email Anda dan klik tombol konfirmasi untuk mengakses :appName.', + 'registrations_disabled' => 'Pendaftaran saat ini dinonaktifkan', + 'registration_email_domain_invalid' => 'Domain email tersebut tidak memiliki akses ke aplikasi ini', + 'register_success' => 'Terima kasih telah mendaftar! Anda sekarang terdaftar dan masuk.', + + + // Password Reset + 'reset_password' => 'Atur ulang kata sandi', + 'reset_password_send_instructions' => 'Masukkan email Anda di bawah ini dan Anda akan dikirimi email dengan tautan pengaturan ulang kata sandi.', + 'reset_password_send_button' => 'Kirim Tautan Atur Ulang', + 'reset_password_sent' => 'Tautan pengaturan ulang kata sandi akan dikirim ke :email jika alamat email ditemukan di sistem.', + 'reset_password_success' => 'Kata sandi Anda telah berhasil diatur ulang.', + 'email_reset_subject' => 'Atur ulang kata sandi :appName anda', + 'email_reset_text' => 'Anda menerima email ini karena kami menerima permintaan pengaturan ulang kata sandi untuk akun Anda.', + 'email_reset_not_requested' => 'Jika Anda tidak meminta pengaturan ulang kata sandi, tidak ada tindakan lebih lanjut yang diperlukan.', + + + // Email Confirmation + 'email_confirm_subject' => 'Konfirmasikan email Anda di :appName', + 'email_confirm_greeting' => 'Terima kasih telah bergabung :appName!', + 'email_confirm_text' => 'Silakan konfirmasi alamat email Anda dengan mengklik tombol di bawah ini:', + 'email_confirm_action' => 'Konfirmasi email', + 'email_confirm_send_error' => 'Konfirmasi email diperlukan tetapi sistem tidak dapat mengirim email. Hubungi admin untuk memastikan email disiapkan dengan benar.', + 'email_confirm_success' => 'Email Anda telah dikonfirmasi!', + 'email_confirm_resent' => 'Email konfirmasi dikirim ulang, Harap periksa kotak masuk Anda.', + + 'email_not_confirmed' => 'Alamat Email Tidak Dikonfirmasi', + 'email_not_confirmed_text' => 'Alamat email Anda belum dikonfirmasi.', + 'email_not_confirmed_click_link' => 'Silakan klik link di email yang dikirimkan segera setelah Anda mendaftar.', + 'email_not_confirmed_resend' => 'Jika Anda tidak dapat menemukan email tersebut, Anda dapat mengirim ulang email konfirmasi dengan mengirimkan formulir di bawah ini.', + 'email_not_confirmed_resend_button' => 'Mengirimkan kembali email konfirmasi', + + // User Invite + 'user_invite_email_subject' => 'Anda telah diundang untuk bergabung di :appName!', + 'user_invite_email_greeting' => 'Sebuah akun telah dibuat untuk Anda di :appName.', + 'user_invite_email_text' => 'Klik tombol di bawah untuk mengatur kata sandi akun dan mendapatkan akses:', + 'user_invite_email_action' => 'Atur Kata Sandi Akun', + 'user_invite_page_welcome' => 'Selamat datang di :appName!', + 'user_invite_page_text' => 'Untuk menyelesaikan akun Anda dan mendapatkan akses, Anda perlu mengatur kata sandi yang akan digunakan untuk masuk ke :appName pada kunjungan berikutnya.', + 'user_invite_page_confirm_button' => 'Konfirmasi Kata sandi', + 'user_invite_success' => 'Atur kata sandi, Anda sekarang memiliki akses ke :appName!' +]; \ No newline at end of file diff --git a/resources/lang/id/common.php b/resources/lang/id/common.php new file mode 100644 index 000000000..b0a6ee38d --- /dev/null +++ b/resources/lang/id/common.php @@ -0,0 +1,85 @@ + 'Batalkan', + 'confirm' => 'Konfirmasi', + 'back' => 'Kembali', + 'save' => 'Simpan', + 'continue' => 'Selanjutnya', + 'select' => 'Pilih', + 'toggle_all' => 'Alihkan semua', + 'more' => 'Lebih', + + // Form Labels + 'name' => 'Nama', + 'description' => 'Deskripsi', + 'role' => 'Wewenang', + 'cover_image' => 'Sampul Gambar', + 'cover_image_description' => 'Gambar ini harus berukuran kira-kira 440x250 piksel.', + + // Actions + 'actions' => 'Tindakan', + 'view' => 'Melihat', + 'view_all' => 'Lihat Semua', + 'create' => 'Buat', + 'update' => 'Perbaharui', + 'edit' => 'Sunting', + 'sort' => 'Sortir', + 'move' => 'Pindahkan', + 'copy' => 'Salin', + 'reply' => 'Balasan', + 'delete' => 'Hapus', + 'delete_confirm' => 'Konfirmasi Penghapusan', + 'search' => 'Cari', + 'search_clear' => 'Hapus Pencarian', + 'reset' => 'Setel Ulang', + 'remove' => 'Hapus', + 'add' => 'Tambah', + 'fullscreen' => 'Layar Penuh', + + // Sort Options + 'sort_options' => 'Sortir Pilihan', + 'sort_direction_toggle' => 'Urutkan Arah Toggle', + 'sort_ascending' => 'Sortir Naik', + 'sort_descending' => 'Urutkan Menurun', + 'sort_name' => 'Nama', + 'sort_created_at' => 'Tanggal dibuat', + 'sort_updated_at' => 'Tanggal diperbaharui', + + // Misc + 'deleted_user' => 'Pengguna terhapus', + 'no_activity' => 'Tidak ada aktifitas untuk ditampilkan', + 'no_items' => 'Tidak ada item yang tersedia', + 'back_to_top' => 'Kembali ke atas', + 'toggle_details' => 'Detail Toggle', + 'toggle_thumbnails' => 'Alihkan Gambar Mini', + 'details' => 'Detail', + 'grid_view' => 'Tampilan bergaris', + 'list_view' => 'Daftar Tampilan', + 'default' => 'Default', + 'breadcrumb' => 'Breadcrumb', + + // Header + 'profile_menu' => 'Profile Menu', + 'view_profile' => 'Tampilkan profil', + 'edit_profile' => 'Sunting Profil', + 'dark_mode' => 'Mode Gelap', + 'light_mode' => 'Mode Cahaya', + + // Layout tabs + 'tab_info' => 'Informasi', + 'tab_content' => 'Konten', + + // Email Content + 'email_action_help' => 'Jika Anda mengalami masalah saat mengklik tombol ":actionText", salin dan tempel URL di bawah ini ke browser web Anda:', + 'email_rights' => 'Seluruh hak cipta', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Rahasia pribadi', + 'terms_of_service' => 'Persyaratan Layanan', +]; diff --git a/resources/lang/id/components.php b/resources/lang/id/components.php new file mode 100644 index 000000000..309e93141 --- /dev/null +++ b/resources/lang/id/components.php @@ -0,0 +1,34 @@ + 'Pilih Gambar', + 'image_all' => 'Semua', + 'image_all_title' => 'Lihat semua gambar', + 'image_book_title' => 'Lihat gambar yang diunggah ke buku ini', + 'image_page_title' => 'Lihat gambar yang diunggah ke halaman ini', + 'image_search_hint' => 'Cari berdasarkan nama gambar', + 'image_uploaded' => 'Diunggah :uploadedDate', + 'image_load_more' => 'Muat lebih banyak', + 'image_image_name' => 'Muat lebih banyak', + 'image_delete_used' => 'Gambar ini digunakan untuk halaman dibawah ini.', + 'image_delete_confirm_text' => 'Anda yakin ingin menghapus gambar ini?', + 'image_select_image' => 'Pilih gambar', + 'image_dropzone' => 'Lepaskan gambar atau klik di sini untuk mengunggah', + 'images_deleted' => 'Gambar Dihapus', + 'image_preview' => 'Pratinjau Gambar', + 'image_upload_success' => 'Gambar berhasil diunggah', + 'image_update_success' => 'Detail gambar berhasil diperbarui', + 'image_delete_success' => 'Gambar berhasil dihapus', + 'image_upload_remove' => 'Menghapus', + + // Code Editor + 'code_editor' => 'Edit Kode', + 'code_language' => 'Bahasa Kode', + 'code_content' => 'Konten Kode', + 'code_session_history' => 'Konten Kode', + 'code_save' => 'Simpan Kode', +]; diff --git a/resources/lang/id/entities.php b/resources/lang/id/entities.php new file mode 100644 index 000000000..d06bf9bee --- /dev/null +++ b/resources/lang/id/entities.php @@ -0,0 +1,319 @@ + 'Baru saja dibuat', + 'recently_created_pages' => 'Halaman baru saja dibuat', + 'recently_updated_pages' => 'Halaman baru saja diperbaharui', + 'recently_created_chapters' => 'Bab baru saja dibuat', + 'recently_created_books' => 'Buku baru saja dibuat', + 'recently_created_shelves' => 'Rak baru saja dibuat', + 'recently_update' => 'Baru saja diperbaharui', + 'recently_viewed' => 'Baru saja dilihat', + 'recent_activity' => 'Aktivitas Terbaru', + 'create_now' => 'Buat Sekarang', + 'revisions' => 'Revisi', + 'meta_revision' => 'Revisi #:revisionCount', + 'meta_created' => 'Dibuat :timeLength', + 'meta_created_name' => 'Dibuat :timeLength oleh :user', + 'meta_updated' => 'Diperbaharui :timeLength', + 'meta_updated_name' => 'Diperbaharui :timeLength oleh :user', + 'meta_owned_name' => 'Dimiliki oleh :user', + 'entity_select' => 'Pilihan Entitas', + 'images' => 'Gambar-gambar', + 'my_recent_drafts' => 'Draf Terbaru Saya', + 'my_recently_viewed' => 'Baru saja saya lihat', + 'no_pages_viewed' => 'Anda belum melihat halaman apa pun', + 'no_pages_recently_created' => 'Tidak ada halaman yang baru saja dibuat', + 'no_pages_recently_updated' => 'Tidak ada halaman yang baru-baru ini diperbarui', + 'export' => 'Ekspor', + 'export_html' => 'File Web Berisi', + 'export_pdf' => 'Dokumen PDF', + 'export_text' => 'Dokumen Teks Biasa', + + // 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_save' => 'Simpan Izin', + 'permissions_owner' => 'Pemilik', + + // Search + 'search_results' => 'Hasil Pencarian', + 'search_total_results_found' => ':count hasil hitung ditemukan |:count hasil hitung total tang di temukan', + 'search_clear' => 'Bersihkan pencarian', + 'search_no_pages' => 'Tidak ada halaman yang cocok dengan pencarian ini', + 'search_for_term' => 'Pencarian untuk :term', + 'search_more' => 'Hasil lebih', + 'search_advanced' => 'Pencarian Lanjutan', + 'search_terms' => 'Cari Istilah', + 'search_content_type' => 'Tipe Konten', + 'search_exact_matches' => 'Pertandingan Persis', + 'search_tags' => 'Pencarian Tag', + 'search_options' => 'Pilihan', + 'search_viewed_by_me' => 'Dilihat oleh saya', + 'search_not_viewed_by_me' => 'Tidak dilihat oleh saya', + 'search_permissions_set' => 'Izin ditetapkan', + 'search_created_by_me' => 'Dibuat oleh saya', + 'search_updated_by_me' => 'Diperbaharui oleh saya', + 'search_date_options' => 'Opsi Tanggal', + 'search_updated_before' => 'Diperbaharui sebelum', + 'search_updated_after' => 'Diperbaharui setelah', + 'search_created_before' => 'Dibuat sebelum', + 'search_created_after' => 'Dibuat setelah', + 'search_set_date' => 'Atur Tanggal', + 'search_update' => 'Perbaharui pencarian', + + // Shelves + 'shelf' => 'Rak', + 'shelves' => 'Rak', + 'x_shelves' => ':count Rak|:count Rak', + 'shelves_long' => 'Rak Buku', + 'shelves_empty' => 'Tidak ada rak yang dibuat', + 'shelves_create' => 'Buat Rak baru', + 'shelves_popular' => 'Rak Terpopuler', + 'shelves_new' => 'Rak Baru', + 'shelves_new_action' => 'Rak Baru', + 'shelves_popular_empty' => 'Rak paling populer akan muncul di sini.', + 'shelves_new_empty' => 'Rak yang paling baru dibuat akan muncul di sini.', + 'shelves_save' => 'Simpan Rak', + 'shelves_books' => 'Buku di rak ini', + 'shelves_add_books' => 'Tambahkan buku ke rak ini', + 'shelves_drag_books' => 'Tarik buku ke sini untuk menambahkannya ke rak ini', + 'shelves_empty_contents' => 'Rak ini tidak memiliki buku yang ditugaskan padanya', + 'shelves_edit_and_assign' => 'Edit rak untuk menetapkan buku', + 'shelves_edit_named' => 'Edit Rak Buku :name', + 'shelves_edit' => 'Edit Rak Buku', + 'shelves_delete' => 'Hapus rak buku', + 'shelves_delete_named' => 'Hapus rak buku :name', + 'shelves_delete_explain' => "Ini akan menghapus rak buku dengan nama ':name'. Buku yang berisi tidak akan dihapus.", + 'shelves_delete_confirmation' => 'Apakah Anda yakin ingin menghapus rak buku ini?', + 'shelves_permissions' => 'Izin Rak Buku', + 'shelves_permissions_updated' => 'Izin Rak Buku Diperbarui', + 'shelves_permissions_active' => 'Izin Rak Buku Aktif', + 'shelves_copy_permissions_to_books' => 'Salin Izin ke Buku', + 'shelves_copy_permissions' => 'Salin Izin', + 'shelves_copy_permissions_explain' => 'Ini akan menerapkan setelan izin rak buku ini saat ini ke semua buku yang ada di dalamnya. Sebelum mengaktifkan, pastikan setiap perubahan pada izin rak buku ini telah disimpan.', + 'shelves_copy_permission_success' => 'Izin rak buku disalin ke :count buku', + + // Books + 'book' => 'Buku', + 'books' => 'Semua Buku', + 'x_books' => ':count Buku|:count Semua Buku', + 'books_empty' => 'Tidak ada buku yang telah dibuat', + 'books_popular' => 'Buku Populer', + 'books_recent' => 'Buku Terbaru', + 'books_new' => 'Buku baru', + 'books_new_action' => 'Buku baru', + 'books_popular_empty' => 'Buku paling populer akan muncul di sini.', + 'books_new_empty' => 'The most recently created books will appear here.', + 'books_create' => 'Buat Buku Baru', + 'books_delete' => 'Hapus Buku', + 'books_delete_named' => 'Hapus buku :bookName', + 'books_delete_explain' => 'Ini akan menghapus buku dengan nama \': bookName\'. Semua halaman dan bab akan dihapus.', + 'books_delete_confirmation' => 'Apakah Anda yakin ingin menghapus buku ini?', + 'books_edit' => 'Edit Buku', + 'books_edit_named' => 'Edit Buku :bookName', + 'books_form_book_name' => 'Nama Buku', + 'books_save' => 'Simpan Buku', + 'books_permissions' => 'Izin Buku', + 'books_permissions_updated' => 'Izin Buku Diperbarui', + 'books_empty_contents' => 'Tidak ada halaman atau bab yang telah dibuat untuk buku ini.', + 'books_empty_create_page' => 'Buat halaman baru', + 'books_empty_sort_current_book' => 'Sortir buku saat ini', + 'books_empty_add_chapter' => 'Tambahkan satu bab', + 'books_permissions_active' => 'Izin Buku Aktif', + 'books_search_this' => 'Cari buku ini', + 'books_navigation' => 'Navigasi Buku', + 'books_sort' => 'Sortir Isi Buku', + 'books_sort_named' => 'Sortir Buku :bookName', + 'books_sort_name' => 'Diurutkan berdasarkan nama', + 'books_sort_created' => 'Urutkan berdasarkan Tanggal Dibuat', + 'books_sort_updated' => 'Urutkan berdasarkan Tanggal Diperbarui', + 'books_sort_chapters_first' => 'Bab Pertama', + 'books_sort_chapters_last' => 'Bab Terakhir', + 'books_sort_show_other' => 'Tunjukkan Buku Lain', + 'books_sort_save' => 'Simpan Pesanan Baru', + + // Chapters + 'chapter' => 'Bab', + 'chapters' => 'Bab', + 'x_chapters' => ':count Bab |:count Bab', + 'chapters_popular' => 'Bab Populer', + 'chapters_new' => 'Bab Baru', + 'chapters_create' => 'Buat Bab Baru', + 'chapters_delete' => 'Hapur Bab', + 'chapters_delete_named' => 'Hapus bab dengan nama :chapterName', + 'chapters_delete_explain' => 'Ini akan menghapus chapter dengan nama \':chapterName\'. Semua halaman yang ada dalam bab ini juga akan dihapus.', + 'chapters_delete_confirm' => 'Anda yakin ingin menghapus bab ini?', + 'chapters_edit' => 'Edit Bab', + 'chapters_edit_named' => 'Edit Bab :chapterName', + 'chapters_save' => 'Simpan Bab', + 'chapters_move' => 'Pindahkan Bab', + 'chapters_move_named' => 'Pindahkan Bab :chapterName', + 'chapter_move_success' => 'Bab dipindahkan ke :bookName', + 'chapters_permissions' => 'Izin Bab', + 'chapters_empty' => 'Saat ini tidak ada halaman dalam bab ini.', + 'chapters_permissions_active' => 'Izin Bab Aktif', + 'chapters_permissions_success' => 'Izin Bab Diperbarui', + 'chapters_search_this' => 'Cari bab ini', + + // Pages + 'page' => 'Halaman', + 'pages' => 'Semua Halaman', + 'x_pages' => ':count Halaman|:count Semua Halaman', + 'pages_popular' => 'Halaman Populer', + 'pages_new' => 'Lembaran baru', + 'pages_attachments' => 'Lampiran', + 'pages_navigation' => 'Halaman Navigasi', + 'pages_delete' => 'Hapus Halaman', + 'pages_delete_named' => 'Hapus Halaman :pageName', + 'pages_delete_draft_named' => 'Hapus Halaman Draf :pageName', + 'pages_delete_draft' => 'Hapus Halaman Draf', + 'pages_delete_success' => 'Halaman dihapus', + 'pages_delete_draft_success' => 'Halaman draf dihapus', + 'pages_delete_confirm' => 'Anda yakin ingin menghapus halaman ini?', + 'pages_delete_draft_confirm' => 'Anda yakin ingin menghapus halaman draf ini?', + 'pages_editing_named' => 'Mengedit Halaman :pageName', + 'pages_edit_draft_options' => 'Opsi Draf', + 'pages_edit_save_draft' => 'Simpan Draf', + 'pages_edit_draft' => 'Edit Halaman Draf', + 'pages_editing_draft' => 'Mengedit Draf', + 'pages_editing_page' => 'Mengedit Draf', + 'pages_edit_draft_save_at' => 'Draf disimpan pada ', + 'pages_edit_delete_draft' => 'Hapus Draf', + 'pages_edit_discard_draft' => 'Buang Draf', + 'pages_edit_set_changelog' => 'Setel Changelog', + 'pages_edit_enter_changelog_desc' => 'Masukkan deskripsi singkat tentang perubahan yang Anda buat', + 'pages_edit_enter_changelog' => 'Masuk ke Changelog', + 'pages_save' => 'Simpan Halaman', + 'pages_title' => 'Judul Halaman', + 'pages_name' => 'Nama Halaman', + 'pages_md_editor' => 'Editor', + 'pages_md_preview' => 'Pratinjau', + 'pages_md_insert_image' => 'Sisipkan Gambar', + 'pages_md_insert_link' => 'Sisipkan Tautan Entitas', + 'pages_md_insert_drawing' => 'Sisipkan Gambar', + 'pages_not_in_chapter' => 'Halaman tidak dalam satu bab', + 'pages_move' => 'Pindahkan Halaman', + 'pages_move_success' => 'Halaman dipindahkan ke ":parentName"', + 'pages_copy' => 'Salin Halaman', + 'pages_copy_desination' => 'Salin Tujuan', + 'pages_copy_success' => 'Halaman berhasil disalin', + 'pages_permissions' => 'Izin Halaman', + 'pages_permissions_success' => 'Izin halaman diperbarui', + 'pages_revision' => 'Revisi', + 'pages_revisions' => 'Revisi Halaman', + 'pages_revisions_named' => 'Revisi Halaman untuk :pageName', + 'pages_revision_named' => 'Revisi Halaman untuk :pageName', + 'pages_revision_restored_from' => 'Dipulihkan dari #:id; :summary', + 'pages_revisions_created_by' => 'Dibuat Oleh', + 'pages_revisions_date' => 'Tanggal Revisi', + 'pages_revisions_number' => '#', + 'pages_revisions_numbered' => 'Revisi #:id', + 'pages_revisions_numbered_changes' => 'Revisi #:id Berubah', + 'pages_revisions_changelog' => 'Changelog', + 'pages_revisions_changes' => 'Perubahan', + 'pages_revisions_current' => 'Versi sekarang', + 'pages_revisions_preview' => 'Pratinjau', + 'pages_revisions_restore' => 'Mengembalikan', + 'pages_revisions_none' => 'Halaman ini tidak memiliki revisi', + 'pages_copy_link' => 'Salin tautan', + 'pages_edit_content_link' => 'Edit Konten', + 'pages_permissions_active' => 'Izin Halaman Aktif', + 'pages_initial_revision' => 'Penerbitan awal', + 'pages_initial_name' => 'Halaman Baru', + 'pages_editing_draft_notification' => 'Anda sedang mengedit draf yang terakhir disimpan :timeDiff.', + 'pages_draft_edited_notification' => 'Halaman ini telah diperbarui sejak saat itu. Anda disarankan untuk membuang draf ini.', + 'pages_draft_edit_active' => [ + 'start_a' => ':count pengguna sudah mulai mengedit halaman ini', + 'start_b' => ':userName sudah mulai mengedit halaman ini', + 'time_a' => 'perubahan di sini disimpan secara instan', + 'time_b' => 'di akhir :minCount menit', + 'message' => ':start :time. Berhati-hatilah untuk tidak menimpa pembaruan satu sama lain!', + ], + 'pages_draft_discarded' => 'Draf dibuang, Editor telah diperbarui dengan konten halaman saat ini', + 'pages_specific' => 'Halaman Tertentu', + 'pages_is_template' => 'Template Halaman', + + // Editor Sidebar + 'page_tags' => 'Halaman Tag', + 'chapter_tags' => 'Bab Tag', + 'book_tags' => 'Tag Buku', + 'shelf_tags' => 'Tag Rak', + 'tag' => 'Tag', + 'tags' => 'Semua Tag', + 'tag_name' => 'Nama Tag', + 'tag_value' => 'Nilai Tag (opsional)', + 'tags_explain' => "Tambahkan beberapa tag untuk mengkategorikan konten Anda dengan lebih baik.\n Anda dapat menetapkan nilai ke tag untuk pengaturan yang lebih mendalam.", + 'tags_add' => 'Tambahkan tag lain', + 'tags_remove' => 'Hapus tag ini', + 'attachments' => 'Lampiran', + 'attachments_explain' => 'Unggah beberapa file atau lampirkan beberapa tautan untuk ditampilkan di laman Anda. Ini terlihat di sidebar halaman.', + 'attachments_explain_instant_save' => 'Perubahan di sini disimpan secara instan.', + 'attachments_items' => 'Item Terlampir', + 'attachments_upload' => 'Unggah File', + 'attachments_link' => 'Lampirkan Tautan', + 'attachments_set_link' => 'Setel Tautan', + 'attachments_delete' => 'Anda yakin ingin menghapus lampiran ini?', + 'attachments_dropzone' => 'Jatuhkan file atau klik di sini untuk melampirkan file', + 'attachments_no_files' => 'Tidak ada file yang telah diunggah', + 'attachments_explain_link' => 'Anda dapat melampirkan link jika Anda memilih untuk tidak mengupload file. Ini bisa berupa tautan ke halaman lain atau tautan ke file di cloud.', + 'attachments_link_name' => 'Nama Tautan', + 'attachment_link' => 'Lampiran Tautan', + 'attachments_link_url' => 'Tautan ke file', + 'attachments_link_url_hint' => 'Url situs atau file', + 'attach' => 'Melampirkan', + 'attachments_insert_link' => 'Tambahkan Tautan Lampiran ke Halaman', + 'attachments_edit_file' => 'Edit File', + 'attachments_edit_file_name' => 'Nama file', + 'attachments_edit_drop_upload' => 'Lepaskan file atau klik di sini untuk mengupload dan menimpa', + 'attachments_order_updated' => 'Urutan lampiran diperbarui', + 'attachments_updated_success' => 'Detail lampiran diperbarui', + 'attachments_deleted' => 'Lampiran dihapus', + 'attachments_file_uploaded' => 'File berhasil diunggah', + 'attachments_file_updated' => 'File berhasil diperbarui', + 'attachments_link_attached' => 'Tautan berhasil dilampirkan ke halaman', + 'templates' => 'Template', + 'templates_set_as_template' => 'Halaman adalah template', + 'templates_explain_set_as_template' => 'Anda dapat mengatur halaman ini sebagai template sehingga isinya dapat digunakan saat membuat halaman lain. Pengguna lain akan dapat menggunakan template ini jika mereka memiliki izin melihat halaman ini.', + 'templates_replace_content' => 'Ganti Halaman Konten', + 'templates_append_content' => 'Tambahkan ke halaman konten', + 'templates_prepend_content' => 'Tambahkan ke halaman konten', + + // Profile View + 'profile_user_for_x' => 'Pengguna untuk :time', + 'profile_created_content' => 'Konten yang Dibuat', + 'profile_not_created_pages' => ':userName belum membuat halaman apa pun', + 'profile_not_created_chapters' => ':userName belum membuat bab apa pun', + 'profile_not_created_books' => ':userName belum membuat buku apa pun', + 'profile_not_created_shelves' => ':userName belum membuat rak apa pun', + + // Comments + 'comment' => 'Komentar', + 'comments' => 'Komentar', + 'comment_add' => 'Tambah Komentar', + 'comment_placeholder' => 'Tinggalkan komentar disini', + 'comment_count' => '{0} Tidak ada komentar |{1} 1 Komentar |[2,*] :count Komentar', + 'comment_save' => 'Simpan Komentar', + 'comment_saving' => 'Menyimpan Komentar...', + 'comment_deleting' => 'Menghapus Komentar...', + 'comment_new' => 'Komentar Baru', + 'comment_created' => 'dikomentari oleh :createDiff', + 'comment_updated' => 'Diperbarui :updateDiff oleh :username', + 'comment_deleted_success' => 'Komentar telah dihapus', + 'comment_created_success' => 'Komentar telah di tambahkan', + 'comment_updated_success' => 'Komentar Telah diperbaharui', + 'comment_delete_confirm' => 'Anda yakin ingin menghapus komentar ini?', + 'comment_in_reply_to' => 'Sebagai balasan untuk :commentId', + + // Revision + 'revision_delete_confirm' => 'Anda yakin ingin menghapus revisi ini?', + 'revision_restore_confirm' => 'Apakah Anda yakin ingin memulihkan revisi ini? Konten halaman saat ini akan diganti.', + 'revision_delete_success' => 'Revisi dihapus', + 'revision_cannot_delete_latest' => 'Tidak dapat menghapus revisi terakhir.' +]; \ No newline at end of file diff --git a/resources/lang/id/errors.php b/resources/lang/id/errors.php new file mode 100644 index 000000000..ec3564ece --- /dev/null +++ b/resources/lang/id/errors.php @@ -0,0 +1,102 @@ + 'Anda tidak memiliki izin untuk mengakses halaman yang diminta.', + 'permissionJson' => 'Anda tidak memiliki izin untuk melakukan tindakan yang diminta.', + + // Auth + 'error_user_exists_different_creds' => 'Pengguna dengan email :email sudah ada tetapi dengan kredensial berbeda.', + 'email_already_confirmed' => 'Email telah dikonfirmasi, Coba masuk.', + 'email_confirmation_invalid' => 'Token konfirmasi ini tidak valid atau telah digunakan, Silakan coba mendaftar lagi.', + 'email_confirmation_expired' => 'Token konfirmasi telah kedaluwarsa, Email konfirmasi baru telah dikirim.', + 'email_confirmation_awaiting' => 'Alamat email untuk akun yang digunakan perlu dikonfirmasi', + 'ldap_fail_anonymous' => 'Akses LDAP gagal menggunakan pengikatan anonim', + 'ldap_fail_authed' => 'Akses LDAP gagal menggunakan detail dn & sandi yang diberikan', + 'ldap_extension_not_installed' => 'Ekstensi LDAP PHP tidak terpasang', + 'ldap_cannot_connect' => 'Tidak dapat terhubung ke server ldap, Koneksi awal gagal', + 'saml_already_logged_in' => 'Telah masuk', + 'saml_user_not_registered' => 'Pengguna :name tidak terdaftar dan pendaftaran otomatis dinonaktifkan', + 'saml_no_email_address' => 'Tidak dapat menemukan alamat email untuk pengguna ini dalam data yang diberikan oleh sistem autentikasi eksternal', + 'saml_invalid_response_id' => 'Permintaan dari sistem otentikasi eksternal tidak dikenali oleh proses yang dimulai oleh aplikasi ini. Menavigasi kembali setelah masuk dapat menyebabkan masalah ini.', + 'saml_fail_authed' => 'Login menggunakan :system gagal, sistem tidak memberikan otorisasi yang berhasil', + 'social_no_action_defined' => 'Tidak ada tindakan yang ditentukan', + 'social_login_bad_response' => "Kesalahan diterima selama :socialAccount :\n:error", + 'social_account_in_use' => 'Ini:socialAccount sudah digunakan, Coba masuk melalui opsi :socialAccount.', + 'social_account_email_in_use' => 'Email :email sudah digunakan. Jika Anda sudah memiliki akun, Anda dapat menghubungkan :socialAccount Anda dari pengaturan profil Anda.', + 'social_account_existing' => 'Akun ini :socialAccount sudah dilampirkan ke profil Anda.', + 'social_account_already_used_existing' => 'Akun ini :socialAccount sudah digunakan oleh pengguna lain.', + 'social_account_not_used' => 'Akun :socialAccount tidak ditautkan ke pengguna mana pun. Harap lampirkan di pengaturan profil Anda. ', + 'social_account_register_instructions' => 'Jika Anda belum memiliki akun, Anda dapat mendaftarkan akun menggunakan opsi :socialAccount.', + 'social_driver_not_found' => 'Pengemudi sosial tidak ditemukan', + 'social_driver_not_configured' => 'Pengaturan sosial :socialAccount Anda tidak dikonfigurasi dengan benar.', + 'invite_token_expired' => 'Tautan undangan ini telah kedaluwarsa. Sebagai gantinya, Anda dapat mencoba mengatur ulang kata sandi akun Anda.', + + // System + 'path_not_writable' => 'Jalur file :filePath tidak dapat diunggah ke. Pastikan itu dapat ditulis ke server.', + 'cannot_get_image_from_url' => 'Tidak bisa mendapatkan gambar dari :url', + 'cannot_create_thumbs' => 'Server tidak dapat membuat thumbnail. Harap periksa apakah Anda telah memasang ekstensi GD PHP.', + 'server_upload_limit' => 'Server tidak mengizinkan unggahan dengan ukuran ini. Harap coba ukuran file yang lebih kecil.', + 'uploaded' => 'Server tidak mengizinkan unggahan dengan ukuran ini. Harap coba ukuran file yang lebih kecil.', + 'image_upload_error' => 'Terjadi kesalahan saat mengupload gambar', + 'image_upload_type_error' => 'Jenis gambar yang diunggah tidak valid', + 'file_upload_timeout' => 'Waktu unggah file telah habis.', + + // Attachments + 'attachment_not_found' => 'Lampiran tidak ditemukan', + + // Pages + 'page_draft_autosave_fail' => 'Gagal menyimpan draf. Pastikan Anda memiliki koneksi internet sebelum menyimpan halaman ini', + 'page_custom_home_deletion' => 'Tidak dapat menghapus halaman saat disetel sebagai beranda', + + // Entities + 'entity_not_found' => 'Entitas tidak ditemukan', + 'bookshelf_not_found' => 'Rak buku tidak ditemukan', + 'book_not_found' => 'Buku tidak ditemukan', + 'page_not_found' => 'Halaman tidak ditemukan', + 'chapter_not_found' => 'Bab tidak ditemukan', + 'selected_book_not_found' => 'Buku yang dipilih tidak ditemukan', + 'selected_book_chapter_not_found' => 'Buku atau Bab yang dipilih tidak ditemukan', + 'guests_cannot_save_drafts' => 'Tamu tidak dapat menyimpan Draf', + + // Users + 'users_cannot_delete_only_admin' => 'Anda tidak dapat menghapus satu-satunya admin', + 'users_cannot_delete_guest' => 'Anda tidak dapat menghapus pengguna tamu', + + // Roles + 'role_cannot_be_edited' => 'Peran ini tidak dapat diedit', + 'role_system_cannot_be_deleted' => 'Peran ini adalah peran sistem dan tidak dapat dihapus', + 'role_registration_default_cannot_delete' => 'Peran ini tidak dapat dihapus jika disetel sebagai peran pendaftaran default', + 'role_cannot_remove_only_admin' => 'Pengguna ini adalah satu-satunya pengguna yang ditetapkan ke peran administrator. Tetapkan peran administrator untuk pengguna lain sebelum mencoba untuk menghapusnya di sini.', + + // Comments + 'comment_list' => 'Terjadi kesalahan saat mengambil komentar.', + 'cannot_add_comment_to_draft' => 'Anda tidak dapat menambahkan komentar ke draf.', + 'comment_add' => 'Terjadi kesalahan saat menambahkan / memperbarui komentar.', + 'comment_delete' => 'Terjadi kesalahan saat menghapus komentar.', + 'empty_comment' => 'Tidak dapat menambahkan komentar kosong.', + + // Error pages + '404_page_not_found' => 'Halaman tidak ditemukan', + 'sorry_page_not_found' => 'Maaf, Halaman yang Anda cari tidak dapat ditemukan.', + 'sorry_page_not_found_permission_warning' => 'Jika Anda mengharapkan halaman ini ada, Anda mungkin tidak memiliki izin untuk melihatnya.', + 'return_home' => 'Kembali ke home', + 'error_occurred' => 'Terjadi kesalahan', + 'app_down' => ':appName sedang down sekarang', + 'back_soon' => 'Ini akan segera kembali.', + + // API errors + 'api_no_authorization_found' => 'Tidak ada token otorisasi yang ditemukan pada permintaan tersebut', + 'api_bad_authorization_format' => 'Token otorisasi ditemukan pada permintaan tetapi formatnya salah', + 'api_user_token_not_found' => 'Tidak ditemukan token API yang cocok untuk token otorisasi yang diberikan', + 'api_incorrect_token_secret' => 'Rahasia yang diberikan untuk token API bekas yang diberikan salah', + 'api_user_no_api_permission' => 'Pemilik token API yang digunakan tidak memiliki izin untuk melakukan panggilan API', + 'api_user_token_expired' => 'Token otorisasi yang digunakan telah kedaluwarsa', + + // Settings & Maintenance + 'maintenance_test_email_failure' => 'Kesalahan dilempar saat mengirim email uji:', + +]; diff --git a/resources/lang/id/pagination.php b/resources/lang/id/pagination.php new file mode 100644 index 000000000..4898c7419 --- /dev/null +++ b/resources/lang/id/pagination.php @@ -0,0 +1,12 @@ + '« Sebelumnya', + 'next' => 'Lanjut »', + +]; diff --git a/resources/lang/id/passwords.php b/resources/lang/id/passwords.php new file mode 100644 index 000000000..3ee2e4d57 --- /dev/null +++ b/resources/lang/id/passwords.php @@ -0,0 +1,15 @@ + 'Kata sandi harus setidaknya delapan karakter dan sesuai dengan konfirmasi.', + 'user' => "Kami tidak dapat menemukan pengguna dengan alamat email tersebut.", + 'token' => 'Token setel ulang sandi tidak valid untuk alamat email ini.', + 'sent' => 'Kami telah mengirimkan email tautan pengaturan ulang kata sandi Anda!', + 'reset' => 'Kata sandi Anda telah disetel ulang!', + +]; diff --git a/resources/lang/id/settings.php b/resources/lang/id/settings.php new file mode 100644 index 000000000..6a9e83c88 --- /dev/null +++ b/resources/lang/id/settings.php @@ -0,0 +1,266 @@ + 'Pengaturan', + 'settings_save' => 'Simpan Pengaturan', + 'settings_save_success' => 'Pengaturan disimpan', + + // App Settings + 'app_customization' => 'Kustomisasi', + 'app_features_security' => 'Fitur & Keamanan', + 'app_name' => 'Nama aplikasi', + 'app_name_desc' => 'Nama ini ditampilkan di tajuk dan di semua email yang dikirim oleh sistem.', + 'app_name_header' => 'Tampilkan nama di header', + 'app_public_access' => 'Akses publik', + 'app_public_access_desc' => 'Mengaktifkan opsi ini akan memungkinkan pengunjung, yang tidak masuk, untuk mengakses konten dalam contoh BookStack Anda.', + 'app_public_access_desc_guest' => 'Akses untuk pengunjung umum dapat dikontrol melalui pengguna "Tamu".', + 'app_public_access_toggle' => 'Izinkan akses publik', + 'app_public_viewing' => 'Izinkan tontonan publik?', + 'app_secure_images' => 'Unggahan Gambar Keamanan Lebih Tinggi', + 'app_secure_images_toggle' => 'Aktifkan unggahan gambar dengan keamanan lebih tinggi', + 'app_secure_images_desc' => 'Untuk alasan performa, semua gambar bersifat publik. Opsi ini menambahkan string acak yang sulit ditebak di depan url gambar. Pastikan indeks direktori tidak diaktifkan untuk mencegah akses mudah.', + 'app_editor' => 'Halaman Editor', + 'app_editor_desc' => 'Pilih editor mana yang akan digunakan oleh semua pengguna untuk mengedit halaman.', + 'app_custom_html' => 'Kustom Konten HTML Head', + 'app_custom_html_desc' => 'Konten apa pun yang ditambahkan di sini akan dimasukkan ke bagian bawah bagian dari setiap halaman. Ini berguna untuk mengganti gaya atau menambahkan kode analitik.', + 'app_custom_html_disabled_notice' => 'Kustom konten HTML Head dinonaktifkan pada halaman pengaturan ini untuk memastikan setiap perubahan yang mengganggu dapat dikembalikan.', + 'app_logo' => 'Logo Aplikasi', + 'app_logo_desc' => 'Gambar ini seharusnya memiliki ketinggian 43px Gambar besar akan diperkecil.', + 'app_primary_color' => 'Warna Utama Aplikasi', + 'app_primary_color_desc' => 'Menyetel warna utama untuk aplikasi termasuk spanduk, tombol, dan tautan.', + 'app_homepage' => 'Beranda Aplikasi', + 'app_homepage_desc' => 'Pilih tampilan untuk ditampilkan di beranda alih-alih tampilan default. Izin halaman diabaikan untuk halaman yang dipilih.', + 'app_homepage_select' => 'Pilih halaman', + 'app_footer_links' => 'Link Footer', + 'app_footer_links_desc' => 'Tambahkan link untuk ditampilkan dalam footer situs. Ini akan ditampilkan di bagian bawah kebanyakan halaman, termasuk yang tidak memerlukan login. Anda dapat menggunakan label "trans::" untuk menggunakan terjemahan yang ditentukan sistem. Sebagai contoh: Menggunakan "trans::common.privacy_policy" akan memberikan teks terjemahan "Privacy Policy" dan akan memberikan teks "Terms of Service".terjemahan trans::common.terms_of_service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Tambahkan Link Footer', + 'app_disable_comments' => 'Nonaktifkan Komentar', + 'app_disable_comments_toggle' => 'Nonaktifkan komentar', + 'app_disable_comments_desc' => 'Menonaktifkan komentar di semua halaman dalam aplikasi.
Komentar yang ada tidak ditampilkan.', + + // Color settings + 'content_colors' => 'Warna Konten', + 'content_colors_desc' => 'Menyetel warna untuk semua elemen dalam hierarki organisasi halaman. Disarankan memilih warna dengan kecerahan yang mirip dengan warna default agar mudah dibaca.', + 'bookshelf_color' => 'Warna Rak', + 'book_color' => 'Warna Buku', + 'chapter_color' => 'Warna Bab', + 'page_color' => 'Warna Halaman', + 'page_draft_color' => 'Warna Halaman Draf', + + // Registration Settings + 'reg_settings' => 'Pendaftaran', + 'reg_enable' => 'Aktifkan Pendaftaran', + 'reg_enable_toggle' => 'Aktifkan Pendaftaran', + 'reg_enable_desc' => 'Saat pendaftaran diaktifkan, pengguna akan dapat mendaftar sendiri sebagai pengguna aplikasi. Setelah pendaftaran, mereka diberi peran pengguna default tunggal.', + 'reg_default_role' => 'Peran pengguna default setelah pendaftaran', + 'reg_enable_external_warning' => 'Opsi di atas diabaikan saat otentikasi LDAP atau SAML eksternal aktif. Akun pengguna untuk anggota yang tidak ada akan dibuat secara otomatis jika otentikasi, terhadap sistem eksternal yang digunakan, berhasil.', + 'reg_email_confirmation' => 'Konfirmasi email', + 'reg_email_confirmation_toggle' => 'Memerlukan konfirmasi email', + 'reg_confirm_email_desc' => 'Jika batasan domain digunakan maka konfirmasi email akan diperlukan dan opsi ini akan diabaikan.', + 'reg_confirm_restrict_domain' => 'Pembatasan Domain', + 'reg_confirm_restrict_domain_desc' => 'Masukkan daftar domain email yang dipisahkan dengan koma yang ingin Anda batasi pendaftarannya. Pengguna akan dikirimi email untuk mengonfirmasi alamat mereka sebelum diizinkan untuk berinteraksi dengan aplikasi.
Perhatikan bahwa pengguna akan dapat mengubah alamat email mereka setelah pendaftaran berhasil.', + 'reg_confirm_restrict_domain_placeholder' => 'Tidak ada batasan yang ditetapkan', + + // Maintenance settings + 'maint' => 'Pemeliharaan', + 'maint_image_cleanup' => 'Gambar Bersihkan', + 'maint_image_cleanup_desc' => "Pindai halaman & konten revisi untuk memeriksa gambar dan gambar mana yang saat ini digunakan dan gambar mana yang berlebihan. Pastikan Anda membuat database lengkap dan cadangan gambar sebelum menjalankan ini.", + 'maint_delete_images_only_in_revisions' => 'Hapus juga gambar yang hanya ada di revisi halaman lama', + 'maint_image_cleanup_run' => 'Jalankan Pembersihan', + 'maint_image_cleanup_warning' => ':count ditemukan gambar yang berpotensi tidak digunakan. Anda yakin ingin menghapus gambar-gambar ini?', + 'maint_image_cleanup_success' => ':count gambar yang mungkin tidak digunakan ditemukan dan dihapus!', + 'maint_image_cleanup_nothing_found' => 'Tidak ada gambar yang tidak digunakan ditemukan, Tidak ada yang dihapus!', + 'maint_send_test_email' => 'Kirim Email Tes', + 'maint_send_test_email_desc' => 'Ini mengirimkan email percobaan ke alamat email Anda yang ditentukan di profil Anda.', + 'maint_send_test_email_run' => 'Kirim email tes', + 'maint_send_test_email_success' => 'Email dikirim ke :address', + 'maint_send_test_email_mail_subject' => 'Uji Email', + 'maint_send_test_email_mail_greeting' => 'Pengiriman email sepertinya berhasil!', + 'maint_send_test_email_mail_text' => 'Selamat! Saat Anda menerima pemberitahuan email ini, pengaturan email Anda tampaknya telah dikonfigurasi dengan benar.', + 'maint_recycle_bin_desc' => 'Rak, buku, bab & halaman yang dihapus dikirim ke recycle bin sehingga dapat dipulihkan atau dihapus secara permanen. Item lama di recycle bin dapat dihapus secara otomatis setelah beberapa saat tergantung pada konfigurasi sistem.', + 'maint_recycle_bin_open' => 'Buka Tempat Sampah', + + // Recycle Bin + 'recycle_bin' => 'Tempat Sampah', + 'recycle_bin_desc' => 'Di sini Anda dapat memulihkan item yang telah dihapus atau memilih untuk menghapusnya secara permanen dari sistem. Daftar ini tidak difilter, tidak seperti daftar aktivitas serupa di sistem tempat filter izin diterapkan.', + 'recycle_bin_deleted_item' => 'Item yang Dihapus', + 'recycle_bin_deleted_by' => 'Dihapus Oleh', + 'recycle_bin_deleted_at' => 'Waktu Penghapusan', + 'recycle_bin_permanently_delete' => 'Hapus Permanen', + 'recycle_bin_restore' => 'Mengembalikan', + 'recycle_bin_contents_empty' => 'Hapus Secara Permanen', + 'recycle_bin_empty' => 'Kosongkan Tempat Sampah', + 'recycle_bin_empty_confirm' => 'Ini akan menghancurkan secara permanen semua item di tempat sampah termasuk konten yang ada di dalam setiap item. Anda yakin ingin mengosongkan tempat sampah?', + 'recycle_bin_destroy_confirm' => 'Tindakan ini akan menghapus item ini secara permanen, bersama dengan elemen turunan apa pun yang tercantum di bawah, dari sistem dan Anda tidak akan dapat memulihkan konten ini. Anda yakin ingin menghapus item ini secara permanen?', + 'recycle_bin_destroy_list' => 'Item yang akan Dihancurkan', + 'recycle_bin_restore_list' => 'Item yang akan Dipulihkan', + 'recycle_bin_restore_confirm' => 'Tindakan ini akan memulihkan item yang dihapus, termasuk semua elemen anak, ke lokasi aslinya. Jika lokasi asli telah dihapus, dan sekarang berada di keranjang sampah, item induk juga perlu dipulihkan.', + 'recycle_bin_restore_deleted_parent' => 'Induk item ini juga telah dihapus. Ini akan tetap dihapus sampai induknya juga dipulihkan.', + 'recycle_bin_destroy_notification' => 'Total :count item dari tempat sampah.', + 'recycle_bin_restore_notification' => 'Total :count item yang dipulihkan dari tempat sampah.', + + // Audit Log + 'audit' => 'Log Audit', + 'audit_desc' => 'Log audit ini menampilkan daftar aktivitas yang dilacak dalam sistem. Daftar ini tidak difilter, tidak seperti daftar aktivitas serupa di sistem tempat filter izin diterapkan.', + 'audit_event_filter' => 'Filter Peristiwa', + 'audit_event_filter_no_filter' => 'Tanpa Filter', + 'audit_deleted_item' => 'Item yang Dihapus', + 'audit_deleted_item_name' => 'Nama :name', + 'audit_table_user' => 'Pengguna', + 'audit_table_event' => 'Peristiwa', + 'audit_table_related' => 'Item atau Detail Terkait', + 'audit_table_date' => 'Tanggal Kegiatan', + 'audit_date_from' => 'Rentang Tanggal Dari', + 'audit_date_to' => 'Rentang Tanggal Sampai', + + // Role Settings + 'roles' => 'Peran', + 'role_user_roles' => 'Peran Pengguna', + 'role_create' => 'Buat Peran Baru', + 'role_create_success' => 'Peran berhasil dibuat', + 'role_delete' => 'Hapus Peran', + 'role_delete_confirm' => 'Ini akan menghapus peran dengan nama \':roleName\'.', + 'role_delete_users_assigned' => 'Peran ini memiliki :userCount pengguna yang ditugaskan padanya. Jika Anda ingin memindahkan pengguna dari peran ini pilih peran baru di bawah.', + 'role_delete_no_migration' => "Jangan migrasikan pengguna", + 'role_delete_sure' => 'Anda yakin ingin menghapus peran ini?', + 'role_delete_success' => 'Peran berhasil dihapus', + 'role_edit' => 'Edit Peran', + 'role_details' => 'Detail Peran', + 'role_name' => 'Nama peran', + 'role_desc' => 'Deskripsi Singkat Peran', + 'role_external_auth_id' => 'Otentikasi Eksternal IDs', + 'role_system' => 'Izin Sistem', + 'role_manage_users' => 'Kelola pengguna', + 'role_manage_roles' => 'Kelola peran & izin peran', + 'role_manage_entity_permissions' => 'Kelola semua izin buku, bab & halaman', + 'role_manage_own_entity_permissions' => 'Kelola izin di buku, bab & halaman sendiri', + 'role_manage_page_templates' => 'Kelola template halaman', + 'role_access_api' => 'Akses Sistem API', + 'role_manage_settings' => 'Kelola setelan aplikasi', + 'role_asset' => 'Izin Aset', + 'roles_system_warning' => 'Ketahuilah bahwa akses ke salah satu dari tiga izin di atas dapat memungkinkan pengguna untuk mengubah hak mereka sendiri atau orang lain dalam sistem. Hanya tetapkan peran dengan izin ini untuk pengguna tepercaya.', + 'role_asset_desc' => 'Izin ini mengontrol akses default ke aset dalam sistem. Izin pada Buku, Bab, dan Halaman akan menggantikan izin ini.', + 'role_asset_admins' => 'Admin secara otomatis diberi akses ke semua konten tetapi opsi ini dapat menampilkan atau menyembunyikan opsi UI.', + 'role_all' => 'Semua', + 'role_own' => 'Sendiri', + 'role_controlled_by_asset' => 'Dikendalikan oleh aset tempat mereka diunggah', + 'role_save' => 'Simpan Peran', + 'role_update_success' => 'Peran berhasil diperbarui', + 'role_users' => 'Peran berhasil diperbarui', + 'role_users_none' => 'Saat ini tidak ada pengguna yang ditugaskan untuk peran ini', + + // Users + 'users' => 'Pengguna', + 'user_profile' => 'Profil Pengguna', + 'users_add_new' => 'Tambahkan pengguna baru', + 'users_search' => 'Cari Pengguna', + 'users_latest_activity' => 'Aktivitas Terbaru', + 'users_details' => 'Detail Pengguna', + 'users_details_desc' => 'Tetapkan nama tampilan dan alamat email untuk pengguna ini. Alamat email akan digunakan untuk masuk ke aplikasi.', + 'users_details_desc_no_email' => 'Tetapkan nama tampilan untuk pengguna ini agar orang lain dapat mengenalinya.', + 'users_role' => 'Peran Pengguna', + 'users_role_desc' => 'Pilih peran mana yang akan ditetapkan untuk pengguna ini. Jika pengguna ditetapkan ke beberapa peran, izin dari peran tersebut akan bertumpuk dan mereka akan menerima semua kemampuan dari peran yang ditetapkan.', + 'users_password' => 'Kata Sandi Pengguna', + 'users_password_desc' => 'Atur kata sandi yang digunakan untuk masuk ke aplikasi. Panjangnya minimal harus 6 karakter.', + 'users_send_invite_text' => 'Anda dapat memilih untuk mengirimi pengguna ini email undangan yang memungkinkan mereka menyetel sandi mereka sendiri, atau Anda dapat menyetel sandi mereka sendiri.', + 'users_send_invite_option' => 'Kirim email undangan pengguna', + 'users_external_auth_id' => 'Otentikasi Eksternal ID', + 'users_external_auth_id_desc' => 'Ini adalah ID yang digunakan untuk mencocokkan pengguna ini saat berkomunikasi dengan sistem otentikasi eksternal Anda.', + 'users_password_warning' => 'Hanya isi di bawah ini jika Anda ingin mengubah kata sandi Anda.', + 'users_system_public' => 'Pengguna ini mewakili semua pengguna tamu yang mengunjungi instance Anda. Ini tidak dapat digunakan untuk masuk tetapi ditetapkan secara otomatis.', + 'users_delete' => 'Hapus pengguna', + 'users_delete_named' => 'Hapus Pengguna :userName', + 'users_delete_warning' => 'Ini sepenuhnya akan menghapus pengguna ini dengan nama \':userName\' dari sistem.', + 'users_delete_confirm' => 'Apakah Anda yakin ingin menghapus pengguna ini?', + 'users_migrate_ownership' => 'Migrasikan Kepemilikan', + 'users_migrate_ownership_desc' => 'Pilih pengguna di sini jika Anda ingin pengguna lain menjadi pemilik semua item yang saat ini dimiliki oleh pengguna ini.', + 'users_none_selected' => 'Tidak ada pengguna yang dipilih', + 'users_delete_success' => 'Pengguna berhasil dihapus', + 'users_edit' => 'Edit Pengguna', + 'users_edit_profile' => 'Edit Profil', + 'users_edit_success' => 'Pengguna berhasil diperbarui', + 'users_avatar' => 'Abatar Pengguna', + 'users_avatar_desc' => 'Pilih gambar untuk mewakili pengguna ini. berukuran 256px.', + 'users_preferred_language' => 'Bahasa Pilihan', + 'users_preferred_language_desc' => 'Opsi ini akan mengubah bahasa yang digunakan untuk antarmuka pengguna aplikasi. Ini tidak akan memengaruhi konten yang dibuat pengguna.', + 'users_social_accounts' => 'Akun Sosial', + 'users_social_accounts_info' => 'Di sini Anda dapat menghubungkan akun Anda yang lain untuk login yang lebih cepat dan mudah. Memutuskan akun di sini tidak mencabut akses resmi sebelumnya. Cabut akses dari pengaturan profil Anda pada akun sosial yang terhubung.', + 'users_social_connect' => 'Hubungkan Akun', + 'users_social_disconnect' => 'Putuskan Sambungan Akun', + 'users_social_connected' => ':socialAccount akun berhasil dilampirkan ke profil Anda.', + 'users_social_disconnected' => ':socialAccount akun berhasil diputuskan dari profil Anda.', + 'users_api_tokens' => 'Token API', + 'users_api_tokens_none' => 'Tidak ada token API yang telah dibuat untuk pengguna ini', + 'users_api_tokens_create' => 'Buat Token', + 'users_api_tokens_expires' => 'Kedaluwarsa', + 'users_api_tokens_docs' => 'Dokumentasi API', + + // API Tokens + 'user_api_token_create' => 'Buat Token API', + 'user_api_token_name' => 'Nama', + 'user_api_token_name_desc' => 'Berikan token Anda nama yang dapat dibaca sebagai pengingat masa depan akan tujuan yang dimaksudkan.', + 'user_api_token_expiry' => 'Tanggal kadaluarsa', + 'user_api_token_expiry_desc' => 'Setel tanggal token ini kedaluwarsa. Setelah tanggal ini, permintaan yang dibuat menggunakan token ini tidak akan berfungsi lagi. Mengosongkan bidang ini akan menetapkan masa berlaku 100 tahun ke depan.', + 'user_api_token_create_secret_message' => 'Segera setelah membuat token ini, "Token ID" & "Token Secret" akan dibuat dan ditampilkan. Rahasianya hanya akan ditampilkan satu kali jadi pastikan untuk menyalin nilainya ke tempat yang aman dan terlindungi sebelum melanjutkan.', + 'user_api_token_create_success' => 'Token API berhasil dibuat', + 'user_api_token_update_success' => 'Token API berhasil diperbarui', + 'user_api_token' => 'Token API', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'Ini adalah pengenal yang dibuat oleh sistem yang tidak dapat diedit untuk token ini yang perlu disediakan dalam permintaan API.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'Ini adalah rahasia yang dihasilkan sistem untuk token ini yang perlu disediakan dalam permintaan API. Ini hanya akan ditampilkan kali ini jadi salin nilai ini ke tempat yang aman dan terlindungi.', + 'user_api_token_created' => 'Token dibuat :timeAgo', + 'user_api_token_updated' => 'Token diperbarui :timeAgo', + 'user_api_token_delete' => 'Hapus Token', + 'user_api_token_delete_warning' => 'Ini akan sepenuhnya menghapus token API ini dengan nama \': tokenName\' dari sistem.', + 'user_api_token_delete_confirm' => 'Anda yakin ingin menghapus token API ini?', + 'user_api_token_delete_success' => 'Token API berhasil dihapus', + + //! 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', + 'fr' => 'Français', + 'he' => 'עברית', + 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', + 'it' => 'Italian', + 'ja' => '日本語', + 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', + 'nl' => 'Nederlands', + 'nb' => 'Norsk (Bokmål)', + 'pl' => 'Polski', + 'pt' => 'Português', + 'pt_BR' => 'Português do Brasil', + '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/id/validation.php b/resources/lang/id/validation.php new file mode 100644 index 000000000..39b1ddfb0 --- /dev/null +++ b/resources/lang/id/validation.php @@ -0,0 +1,115 @@ + ':attribute harus diterima.', + 'active_url' => ':attribute bukan URL yang valid.', + 'after' => ':attribute harus setelah tanggal :date.', + 'alpha' => ':attribute hanya boleh berisi huruf.', + 'alpha_dash' => ':attribute hanya boleh berisi huruf, angka, tanda hubung, dan garis bawah.', + 'alpha_num' => ':attribute hanya boleh berisi huruf dan angka.', + 'array' => ':attribute harus berupa larik.', + 'before' => ':attribute harus tanggal sebelum :date.', + 'between' => [ + 'numeric' => ':attribute harus di antara :min dan :max.', + 'file' => ':attribute harus diantara :min dan :max kilobyte.', + 'string' => ':attribute harus memiliki karakter antara :min dan :max.', + 'array' => ':attribute harus memiliki item antara :min dan :max.', + ], + 'boolean' => ':attribute bidang harus berisi benar atau salah.', + 'confirmed' => ':attribute konfirmasi tidak sama.', + 'date' => ':attribute bukan tanggal yang valid.', + 'date_format' => ':attribute tidak sesuai dengan format :format.', + 'different' => ':attribute dan :other harus berbeda.', + 'digits' => ':attribute harus :digits digit.', + 'digits_between' => ':attribute harus diantara :min dan :max digit.', + 'email' => ':attrtibute Harus alamat e-mail yang valid.', + 'ends_with' => ':attribute harus diakhiri dengan salah satu dari berikut ini: :values', + 'filled' => ':attribute bidang diperlukan.', + 'gt' => [ + 'numeric' => ':attribute harus lebih besar dari :value.', + 'file' => ':attribute harus lebih besar dari :value kilobyte.', + 'string' => ':attribute harus lebih besar dari :value karakter.', + 'array' => ':attribute harus memiliki lebih dari item :value.', + ], + 'gte' => [ + 'numeric' => ':attribute harus lebih besar dari atau sama dengan :value.', + 'file' => ':attribute harus lebih besar dari atau sama dengan :value kilobyte.', + 'string' => ':attribute harus lebih besar dari atau sama dengan karakter :value.', + 'array' => ':attribute harus memiliki :value item atau lebih.', + ], + 'exists' => ':attribute yang dipilih tidak valid.', + 'image' => ':attribute harus berupa gambar.', + 'image_extension' => ':attribute harus memiliki ekstensi gambar yang valid & didukung.', + 'in' => ':attribute yang dipilih tidak valid.', + 'integer' => ':attribute harus berupa bilangan bulat.', + 'ip' => ':attribute harus berupa alamat IP yang valid.', + 'ipv4' => ':attribute harus berupa alamat IPv4 yang valid.', + 'ipv6' => ':attribute harus berupa alamat IPv6 yang valid.', + 'json' => ':attribute harus berupa string JSON yang valid.', + 'lt' => [ + 'numeric' => ':attribute harus kurang dari :value.', + 'file' => ':attribute harus kurang dari :value kilobyte.', + 'string' => ':attribute harus kurang dari :value karakter.', + 'array' => ':attribute harus memiliki kurang dari :value item.', + ], + 'lte' => [ + 'numeric' => ':attribute harus kurang dari atau sama dengan :value.', + 'file' => ':attribute harus kurang dari atau sama dengan :value kilobyte.', + 'string' => ':attribute harus kurang dari atau sama dengan :value karakter.', + 'array' => ':attribute tidak boleh memiliki lebih dari :value item.', + ], + 'max' => [ + 'numeric' => ':attribute tidak boleh lebih dari :max.', + 'file' => ':attribute tidak boleh lebih dari :max kilobyte.', + 'string' => ':attribute tidak boleh lebih dari :max karakter.', + 'array' => ':attribute tidak boleh memiliki lebih dari :max item.', + ], + 'mimes' => ':attribute harus berupa file dengan tipe: :value.', + 'min' => [ + 'numeric' => ':attribute minimal harus :min.', + 'file' => ':attribute minimal harus :min kilobyte.', + 'string' => ':attribute setidaknya harus :min karakter.', + 'array' => ':attribute minimal harus memiliki :min item.', + ], + 'no_double_extension' => ':attribute hanya boleh memiliki satu ekstensi file.', + 'not_in' => ':attribute yang dipilih tidak valid.', + 'not_regex' => ':attribute format tidak valid.', + 'numeric' => ':attribute harus berupa nomot.', + 'regex' => 'Format :attribute tidak valid.', + 'required' => ':attribute bidang harus diisi.', + 'required_if' => ':attribute Bidang harus diisi saat :other atau :value.', + 'required_with' => 'Bidang :attribute harus diisi jika ada :nilai.', + 'required_with_all' => 'Bidang :attribute harus diisi jika ada :values.', + 'required_without' => 'Bidang :attribute harus diisi jika :values tidak ada.', + 'required_without_all' => 'Bidang :attribute harus diisi jika tidak ada :value yang ada.', + 'same' => ':attribute dan :other harus sama.', + 'safe_url' => 'Tautan yang diberikan mungkin tidak aman.', + 'size' => [ + 'numeric' => ':attribute harus berukuran :size.', + 'file' => ':attribute harus berukuran :size kilobyte.', + 'string' => ':attribute harus memiliki karakter berukuran :size.', + 'array' => ':attribute harus mengandung :size item.', + ], + 'string' => ':attribute harus berupa string.', + 'timezone' => ':attribute harus menjadi zona yang valid.', + 'unique' => ':attribute sudah diambil.', + 'url' => ':attribute format tidak valid.', + 'uploaded' => 'File tidak dapat diunggah. Server mungkin tidak menerima file dengan ukuran ini.', + + // Custom validation lines + 'custom' => [ + 'password-confirm' => [ + 'required_with' => 'Konfirmasi kata sandi diperlukan', + ], + ], + + // Custom validation attributes + 'attributes' => [], +]; diff --git a/resources/lang/it/common.php b/resources/lang/it/common.php index 9676962bd..7ba9b33d5 100755 --- a/resources/lang/it/common.php +++ b/resources/lang/it/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'Se hai problemi nel cliccare il pulsante ":actionText", copia e incolla lo URL sotto nel tuo browser:', 'email_rights' => 'Tutti i diritti riservati', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privacy Policy', + 'terms_of_service' => 'Terms of Service', ]; diff --git a/resources/lang/it/settings.php b/resources/lang/it/settings.php index f925de962..4f0414baf 100755 --- a/resources/lang/it/settings.php +++ b/resources/lang/it/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'Homepage Applicazione', 'app_homepage_desc' => 'Seleziona una pagina da mostrare nella home anzichè quella di default. I permessi della pagina sono ignorati per quella selezionata.', 'app_homepage_select' => 'Seleziona una pagina', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', 'app_disable_comments' => 'Disattiva commenti', 'app_disable_comments_toggle' => 'Disabilita commenti', 'app_disable_comments_desc' => 'Disabilita i commenti su tutte le pagine nell\'applicazione. I commenti esistenti non sono mostrati. ', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Danese', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/it/validation.php b/resources/lang/it/validation.php index 2e460cdc3..bb602619c 100755 --- a/resources/lang/it/validation.php +++ b/resources/lang/it/validation.php @@ -78,7 +78,6 @@ return [ 'string' => 'Il campo :attribute deve essere almeno :min caratteri.', 'array' => 'Il campo :attribute deve contenere almeno :min elementi.', ], - 'no_double_extension' => ':attribute deve avere solo un\'estensione.', 'not_in' => 'Il :attribute selezionato non è valido.', 'not_regex' => 'Il formato di :attribute non è valido.', 'numeric' => ':attribute deve essere un numero.', diff --git a/resources/lang/ja/common.php b/resources/lang/ja/common.php index 7932dc713..83f4844ba 100644 --- a/resources/lang/ja/common.php +++ b/resources/lang/ja/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => '":actionText" をクリックできない場合、以下のURLをコピーしブラウザで開いてください:', 'email_rights' => 'All rights reserved', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privacy Policy', + 'terms_of_service' => 'Terms of Service', ]; diff --git a/resources/lang/ja/settings.php b/resources/lang/ja/settings.php index 31ab22804..a0f662fdf 100644 --- a/resources/lang/ja/settings.php +++ b/resources/lang/ja/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'Application Homepage', 'app_homepage_desc' => 'Select a view to show on the homepage instead of the default view. Page permissions are ignored for selected pages.', 'app_homepage_select' => 'ページを選択', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', 'app_disable_comments' => 'コメントを無効にする', 'app_disable_comments_toggle' => 'コメントを無効にする', 'app_disable_comments_desc' => 'アプリケーション内のすべてのページのコメントを無効にします。既存のコメントは表示されません。', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/ja/validation.php b/resources/lang/ja/validation.php index 61057f17e..7d9987ce0 100644 --- a/resources/lang/ja/validation.php +++ b/resources/lang/ja/validation.php @@ -78,7 +78,6 @@ return [ 'string' => ':attributeは:min文字以上である必要があります。', 'array' => ':attributeは:min個以上である必要があります。', ], - 'no_double_extension' => 'The :attribute must only have a single file extension.', 'not_in' => '選択された:attributeは不正です。', 'not_regex' => 'The :attribute format is invalid.', 'numeric' => ':attributeは数値である必要があります。', diff --git a/resources/lang/ko/common.php b/resources/lang/ko/common.php index 431562602..55134df8d 100644 --- a/resources/lang/ko/common.php +++ b/resources/lang/ko/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => ':actionText를 클릭할 수 없을 때는 웹 브라우저에서 다음 링크로 접속할 수 있습니다.', 'email_rights' => '모든 권리 소유', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privacy Policy', + 'terms_of_service' => 'Terms of Service', ]; diff --git a/resources/lang/ko/settings.php b/resources/lang/ko/settings.php index 9fec26956..920ce0450 100755 --- a/resources/lang/ko/settings.php +++ b/resources/lang/ko/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => '처음 페이지', 'app_homepage_desc' => '고른 페이지에 설정한 권한은 무시합니다.', 'app_homepage_select' => '문서 고르기', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', 'app_disable_comments' => '댓글 사용 안 함', 'app_disable_comments_toggle' => '댓글 사용 안 함', 'app_disable_comments_desc' => '모든 페이지에서 댓글을 숨깁니다.', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => '히브리어', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/ko/validation.php b/resources/lang/ko/validation.php index 64c4a4345..6754d9620 100644 --- a/resources/lang/ko/validation.php +++ b/resources/lang/ko/validation.php @@ -78,7 +78,6 @@ return [ 'string' => ':attribute(을)를 적어도 :value바이트로 구성하세요.', 'array' => ':attribute(을)를 적어도 :value개로 구성하세요..', ], - 'no_double_extension' => ':attribute(이)가 단일한 확장자를 가져야 합니다.', 'not_in' => '고른 :attribute(이)가 유효하지 않습니다.', 'not_regex' => ':attribute(은)는 유효하지 않은 형식입니다.', 'numeric' => ':attribute(을)를 숫자로만 구성하세요.', diff --git a/resources/lang/lv/activities.php b/resources/lang/lv/activities.php new file mode 100644 index 000000000..8f99e0ff6 --- /dev/null +++ b/resources/lang/lv/activities.php @@ -0,0 +1,49 @@ + 'izveidoja lapu', + 'page_create_notification' => 'Lapa Veiksmīgi Izveidota', + 'page_update' => 'atjaunoja lapu', + 'page_update_notification' => 'Lapa Veiksmīgi Atjaunota', + 'page_delete' => 'izdzēsa lapu', + 'page_delete_notification' => 'Lapa Veiksmīgi Dzēsta', + 'page_restore' => 'atjaunoja lapu', + 'page_restore_notification' => 'Lapa Veiksmīgi Atjaunota', + 'page_move' => 'pārvietoja lapu', + + // Chapters + 'chapter_create' => 'izveidoja nodaļu', + 'chapter_create_notification' => 'Nodaļa Veiksmīgi Izveidota', + 'chapter_update' => 'atjaunoja nodaļu', + 'chapter_update_notification' => 'Nodaļa Veiksmīgi Atjaunota', + 'chapter_delete' => 'izdzēsa nodaļu', + 'chapter_delete_notification' => 'Nodaļa Veiksmīgi Dzēsta', + 'chapter_move' => 'pārvietoja nodaļu', + + // Books + 'book_create' => 'izveidoja grāmatu', + 'book_create_notification' => 'Grāmata Veiksmīgi Izveidota', + 'book_update' => 'atjaunoja grāmatu', + 'book_update_notification' => 'Grāmata Veiksmīgi Atjaunota', + 'book_delete' => 'izdzēsa grāmatu', + 'book_delete_notification' => 'Grāmata Veiksmīgi Dzēsta', + 'book_sort' => 'kārtoja grāmatu', + 'book_sort_notification' => 'Grāmata Veiksmīgi Pārkārtota', + + // Bookshelves + 'bookshelf_create' => 'izveidoja Plauktu', + 'bookshelf_create_notification' => 'Plaukts Veiksmīgi Izveidots', + 'bookshelf_update' => 'atjaunoja plauktu', + 'bookshelf_update_notification' => 'Plaukts Veiksmīgi Atjaunots', + 'bookshelf_delete' => 'izdzēsa plauktu', + 'bookshelf_delete_notification' => 'Plaukts Veiksmīgi Dzēsts', + + // Other + 'commented_on' => 'komentēts', + 'permissions_update' => 'atjaunoja atļaujas', +]; diff --git a/resources/lang/lv/auth.php b/resources/lang/lv/auth.php new file mode 100644 index 000000000..dc84a2d97 --- /dev/null +++ b/resources/lang/lv/auth.php @@ -0,0 +1,77 @@ + 'Šie reģistrācijas dati neatbilst mūsu ierakstiem.', + 'throttle' => 'Pārāk daudz pieteikšanās mēģinājumu. Lūdzu, mēģiniet vēlreiz pēc :seconds seconds.', + + // Login & Register + 'sign_up' => 'Reģistrēties', + 'log_in' => 'Ielogoties', + 'log_in_with' => 'Ielogoties ar :socialDriver', + 'sign_up_with' => 'Pieteikties ar :socialDriver', + 'logout' => 'Iziet', + + 'name' => 'Vārds', + 'username' => 'Lietotājvārds', + 'email' => 'E-pasts', + 'password' => 'Parole', + 'password_confirm' => 'Apstiprināt paroli', + 'password_hint' => 'Jābūt vismaz 8 rakstzīmēm', + 'forgot_password' => 'Aizmirsta parole?', + 'remember_me' => 'Atcerēties mani', + 'ldap_email_hint' => 'Lūdzu ievadiet e-pastu, kuru izmantosiet šim profilam.', + 'create_account' => 'Izveidot profilu', + 'already_have_account' => 'Jau ir profils?', + 'dont_have_account' => 'Nav profila?', + 'social_login' => 'Pieteikšanās ar sociālo tīklu profilu', + 'social_registration' => 'Reģistrēšanās ar sociālo profilu', + 'social_registration_text' => 'Reģistrēties vai pieteikties izmantojot citu servisu.', + + 'register_thanks' => 'Paldies par reģistrāciju!', + 'register_confirm' => 'Lūdzu, pārbaudiet savu e-pastu un nospiediet apstiprināšanas pogu, lai piekļūtu :appName.', + 'registrations_disabled' => 'Reģistrācija ir izslēgta', + 'registration_email_domain_invalid' => 'E-pasta domēnam nav piekļuves pie šīs aplikācijas', + 'register_success' => 'Paldies par reģistrēšanos! Tagad varat pieslēgties.', + + + // Password Reset + 'reset_password' => 'Atiestatīt paroli', + 'reset_password_send_instructions' => 'Ievadiet savu e-pastu zemāk un nosūtīsim e-pastu ar paroles atiestatīšanas saiti.', + 'reset_password_send_button' => 'Nosūtīt atiestatīšanas saiti', + 'reset_password_sent' => 'Paroles atiestatīšanas saite tiks nosūtīta uz :email, ja šāds e-pasts būs derīgs.', + 'reset_password_success' => 'Jūsu parole ir veiksmīgi atiestatīta.', + 'email_reset_subject' => 'Atiestatīt :appName paroli', + 'email_reset_text' => 'Jūs saņemat šo e-pastu, jo mēs saņēmām Jūsu profila paroles atiestatīšanas pieprasījumu.', + 'email_reset_not_requested' => 'Ja Jūs nepieprasījāt paroles atiestatīšanu, tad tālākas darbības nav nepieciešamas.', + + + // Email Confirmation + 'email_confirm_subject' => 'Apstiprinat savu :appName e-pastu', + 'email_confirm_greeting' => 'Paldies, ka pievienojāties :appName!', + 'email_confirm_text' => 'Lūdzu apstipriniet savu e-pastu nospiežot zemāk redzamo pogu:', + 'email_confirm_action' => 'Apstiprināt e-pastu', + 'email_confirm_send_error' => 'E-pasta apriprināšana ir nepieciešama, bet sistēma nevarēja e-pastu nosūtīt. Lūdzu sazinaties ar administratoru, lai pārliecinātos, ka e-pasts ir iestatīts pareizi.', + 'email_confirm_success' => 'Jūsu e-pasts ir apstiprināts!', + 'email_confirm_resent' => 'Apstiprinājuma vēstule tika nosūtīta. Lūdzu, pārbaudiet jūsu e-pastu.', + + 'email_not_confirmed' => 'E-pasts nav apstiprināts', + 'email_not_confirmed_text' => 'Jūsu e-pasta adrese vēl nav apstiprināta.', + 'email_not_confirmed_click_link' => 'Lūdzu, noklikšķiniet uz saiti nosūtītajā e-pastā pēc reģistrēšanās.', + 'email_not_confirmed_resend' => 'Ja neredzi e-pastu, tad vari atkārtoti nosūtīt apstiprinājuma e-pastu iesniedzot zemāk redzamo formu.', + 'email_not_confirmed_resend_button' => 'Atkārtoti nosūtīt apstiprinājuma e-pastu', + + // User Invite + 'user_invite_email_subject' => 'Tu esi uzaicināts pievienoties :appName!', + 'user_invite_email_greeting' => 'Jūsu :appName profils ir izveidots.', + 'user_invite_email_text' => 'Lūdzu, nospiediet zemāk redzamo pogu, lai izveidotu paroli un iegūtu piekļuvi:', + 'user_invite_email_action' => 'Iestatīt profila paroli', + 'user_invite_page_welcome' => 'Sveicināti :appName!', + 'user_invite_page_text' => 'Lai pabeigtu profila izveidi un piekļūtu :appName ir jāizveido parole.', + 'user_invite_page_confirm_button' => 'Apstiprināt paroli', + 'user_invite_success' => 'Parole iestatīta, tagad varat piekļūt :appName!' +]; \ No newline at end of file diff --git a/resources/lang/lv/common.php b/resources/lang/lv/common.php new file mode 100644 index 000000000..2a1643938 --- /dev/null +++ b/resources/lang/lv/common.php @@ -0,0 +1,85 @@ + 'Atcelt', + 'confirm' => 'Apstiprināt', + 'back' => 'Atpakaļ', + 'save' => 'Saglabāt', + 'continue' => 'Turpināt', + 'select' => 'Atlasīt', + 'toggle_all' => 'Iezīmēt visus', + 'more' => 'Vairāk', + + // Form Labels + 'name' => 'Nosaukums', + 'description' => 'Apraksts', + 'role' => 'Loma', + 'cover_image' => 'Vāka attēls', + 'cover_image_description' => 'Šim attēlam būtu jābūt aptuveni 440x250px.', + + // Actions + 'actions' => 'Darbības', + 'view' => 'Skatīt', + 'view_all' => 'Skatīt visus', + 'create' => 'Izveidot', + 'update' => 'Atjaunināt', + 'edit' => 'Rediģēt', + 'sort' => 'Kārtot', + 'move' => 'Pārvietot', + 'copy' => 'Kopēt', + 'reply' => 'Atbildēt', + 'delete' => 'Dzēst', + 'delete_confirm' => 'Apstipriniet dzēšanu', + 'search' => 'Meklēt', + 'search_clear' => 'Notīrīt meklēšanu', + 'reset' => 'Atiestatīt', + 'remove' => 'Noņemt', + 'add' => 'Pievienot', + 'fullscreen' => 'Pilnekrāns', + + // Sort Options + 'sort_options' => 'Kārtošanas Opcijas', + 'sort_direction_toggle' => 'Pārslēgt kārtošanas virzienu', + 'sort_ascending' => 'Kārtot Augoši', + 'sort_descending' => 'Kārtot Dilstoši', + 'sort_name' => 'Vārds', + 'sort_created_at' => 'Izveidošanas Datums', + 'sort_updated_at' => 'Atjaunināšanas datums', + + // Misc + 'deleted_user' => 'Dzēsts lietotājs', + 'no_activity' => 'Nav skatāmu darbību', + 'no_items' => 'Vienumi nav pieejami', + 'back_to_top' => 'Uz augšu', + 'toggle_details' => 'Rādīt aprakstu', + 'toggle_thumbnails' => 'Iezīmēt sīkatēlus', + 'details' => 'Sīkāka informācija', + 'grid_view' => 'Režģa Skats', + 'list_view' => 'Saraksta Skats', + 'default' => 'Noklusējums', + 'breadcrumb' => 'Navigācija', + + // Header + 'profile_menu' => 'Profila izvēlne', + 'view_profile' => 'Apskatīt profilu', + 'edit_profile' => 'Rediģēt profilu', + 'dark_mode' => 'Tumšais režīms', + 'light_mode' => 'Gaišais režīms', + + // Layout tabs + 'tab_info' => 'Informācija', + 'tab_content' => 'Saturs', + + // Email Content + 'email_action_help' => 'Ja ir problēmas noklikšķināt ":actionText" pogu, nokopē un ievieto saiti savā interneta pārlūkā:', + 'email_rights' => 'Visas tiesības aizsargātas', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privātuma politika', + 'terms_of_service' => 'Pakalpojuma noteikumi', +]; diff --git a/resources/lang/lv/components.php b/resources/lang/lv/components.php new file mode 100644 index 000000000..b66461d5a --- /dev/null +++ b/resources/lang/lv/components.php @@ -0,0 +1,34 @@ + 'Attēla izvēle', + 'image_all' => 'Visi', + 'image_all_title' => 'Skatīt visus attēlus', + 'image_book_title' => 'Apskatīt augšupielādētos attēlus šajā grāmatā', + 'image_page_title' => 'Apskatīt augšupielādētos attēlus šajā lapā', + 'image_search_hint' => 'Meklēt pēc attēla vārda', + 'image_uploaded' => 'Augšupielādēts :uploadedDate', + 'image_load_more' => 'Ielādēt vairāk', + 'image_image_name' => 'Attēla nosaukums', + 'image_delete_used' => 'Šis attēls ir ievietots zemāk redzamajās lapās.', + 'image_delete_confirm_text' => 'Vai tiešām vēlaties dzēst šo attēlu?', + 'image_select_image' => 'Atlasīt attēlu', + 'image_dropzone' => 'Ievilkt attēlu vai klikšķinat šeit, lai augšupielādētu', + 'images_deleted' => 'Dzēstie attēli', + 'image_preview' => 'Attēla priekšskatījums', + 'image_upload_success' => 'Attēls ir veiksmīgi augšupielādēts', + 'image_update_success' => 'Attēlā informācija ir veiksmīgi atjunināta', + 'image_delete_success' => 'Attēls veiksmīgi dzēsts', + 'image_upload_remove' => 'Noņemt', + + // Code Editor + 'code_editor' => 'Rediģēt kodu', + 'code_language' => 'Koda valoda', + 'code_content' => 'Koda teksts', + 'code_session_history' => 'Sesijas vēsture', + 'code_save' => 'Saglabāt kodu', +]; diff --git a/resources/lang/lv/entities.php b/resources/lang/lv/entities.php new file mode 100644 index 000000000..3f9d7349b --- /dev/null +++ b/resources/lang/lv/entities.php @@ -0,0 +1,319 @@ + 'Nesen izveidots', + 'recently_created_pages' => 'Nesen izveidotas lapas', + 'recently_updated_pages' => 'Nesen atjaunātas lapas', + 'recently_created_chapters' => 'Nesen izveidotas nodaļas', + 'recently_created_books' => 'Nesen izveidotas grāmatas', + 'recently_created_shelves' => 'Nesen izveidoti plaukti', + 'recently_update' => 'Nesen atjaunināts', + 'recently_viewed' => 'Nesen skatītie', + 'recent_activity' => 'Pēdējās aktivitātes', + 'create_now' => 'Izveidot tagad', + 'revisions' => 'Revīzijas', + 'meta_revision' => 'Revīzija #:revisionCount', + 'meta_created' => 'Izveidots :timeLength', + 'meta_created_name' => ':user izveidojis pirms :timeLength', + 'meta_updated' => 'Atjaunināts :timeLength', + 'meta_updated_name' => ':user atjauninājis pirms :timeLength', + 'meta_owned_name' => 'Īpašnieks :user', + 'entity_select' => 'Izvēlēties vienumu', + 'images' => 'Attēli', + 'my_recent_drafts' => 'Mani melnraksti', + 'my_recently_viewed' => 'Mani nesen skatītie', + 'no_pages_viewed' => 'Neviena lapa vēl nav skatīta', + 'no_pages_recently_created' => 'Nav radīta neviena lapa', + 'no_pages_recently_updated' => 'Nav atjaunināta neviena lapa', + 'export' => 'Eksportēt', + 'export_html' => 'Pilna satura web fails', + 'export_pdf' => 'PDF fails', + 'export_text' => 'Vienkāršs teksta fails', + + // 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_save' => 'Saglabāt atļaujas', + 'permissions_owner' => 'Īpašnieks', + + // Search + 'search_results' => 'Meklēšanas rezultāti', + 'search_total_results_found' => ':count meklēšanas rezultāts|:count meklēšanas rezultāti', + 'search_clear' => 'Notīrīt meklēšanu', + 'search_no_pages' => 'Neviena lapa neatbilst meklēšanai', + 'search_for_term' => 'Meklēt :term', + 'search_more' => 'Vairāk rezultāti', + 'search_advanced' => 'Paplašināta meklēšana', + 'search_terms' => 'Meklēšanas parametri', + 'search_content_type' => 'Satura tips', + 'search_exact_matches' => 'Precīza atbilstība', + 'search_tags' => 'Birku meklēšana', + 'search_options' => 'Iestatījumi', + 'search_viewed_by_me' => 'Manis apskatītie', + 'search_not_viewed_by_me' => 'Neesmu skatījis', + 'search_permissions_set' => 'Iestatītās atļaujas', + 'search_created_by_me' => 'Manis izveidotie', + 'search_updated_by_me' => 'Manis atjauninātie', + 'search_date_options' => 'Datuma iestarījumi', + 'search_updated_before' => 'Atjaunināts pirms', + 'search_updated_after' => 'Atjaunināts pēc', + 'search_created_before' => 'Izveidots pirms', + 'search_created_after' => 'Izveidots pēc', + 'search_set_date' => 'Norādīt datumu', + 'search_update' => 'Atjaunināt meklētāju', + + // Shelves + 'shelf' => 'Plaukts', + 'shelves' => 'Plaukti', + 'x_shelves' => ':count Plaukts|:count Plaukti', + 'shelves_long' => 'Grāmatu plautki', + 'shelves_empty' => 'Neviens plaukts nav izveidots', + 'shelves_create' => 'Izveidot jaunu plauktu', + 'shelves_popular' => 'Populāri plaukti', + 'shelves_new' => 'Jauni plaukti', + 'shelves_new_action' => 'Jauns plaukts', + 'shelves_popular_empty' => 'Populārākie plaukti tiks rādīti šeit.', + 'shelves_new_empty' => 'Pēdējie izveidotie plaukti tiks rādīti šeit.', + 'shelves_save' => 'Saglabāt plauktu', + 'shelves_books' => 'Grāmatas šajā plauktā', + 'shelves_add_books' => 'Pievienot grāmatas šim plauktam', + 'shelves_drag_books' => 'Ievelciet grāmatas šeit, lai novietotu tās šajā plauktā', + 'shelves_empty_contents' => 'Šim gŗamatplauktam nav pievienotu grāmatu', + 'shelves_edit_and_assign' => 'Labot plauktu, lai tam pievienotu grāmatas', + 'shelves_edit_named' => 'Labot grāmatplauktu :name', + 'shelves_edit' => 'Labot grāmatplauktu', + 'shelves_delete' => 'Dzēst grāmatplauktu', + 'shelves_delete_named' => 'Dzēst grāmatplauktu :name', + 'shelves_delete_explain' => "Tiks dzēsts grāmatplaukts ar nosaukumu \":name\". Tajā ievietotās grāmatas netiks dzēstas.", + 'shelves_delete_confirmation' => 'Vai esat pārliecināts, ka vēlaties dzēst šo grāmatplauktu?', + 'shelves_permissions' => 'Grāmatplaukta atļaujas', + 'shelves_permissions_updated' => 'Grāmatplaukta atļaujas atjauninātas', + 'shelves_permissions_active' => 'Grāmatplaukta atļaujas ir aktīvas', + 'shelves_copy_permissions_to_books' => 'Kopēt grāmatplaukta atļaujas uz grāmatām', + 'shelves_copy_permissions' => 'Kopēt atļaujas', + 'shelves_copy_permissions_explain' => 'Šis piemēros pašreizējās grāmatplaukta piekļuves tiesības visām tajā esošajām grāmatām. Pirms ieslēgšanas pārliecinieties, ka ir saglabātas izmaiņas grāmatplaukta piekļuves tiesībām.', + 'shelves_copy_permission_success' => 'Grāmatplaukta atļaujas ir pārkopētas uz :count grāmatām', + + // Books + 'book' => 'Grāmata', + 'books' => 'Grāmatas', + 'x_books' => ':count grāmata|:count grāmatas', + 'books_empty' => 'Neviena grāmata nav izveidota', + 'books_popular' => 'Populārās grāmatas', + 'books_recent' => 'Nesenās grāmatas', + 'books_new' => 'Jaunas grāmatas', + 'books_new_action' => 'Jauna grāmata', + 'books_popular_empty' => 'Populārākās grāmatas tiks rādītas šeit.', + 'books_new_empty' => 'Pēdējās izveidotās grāmatas tiks rādītas šeit.', + 'books_create' => 'Izveidot jaunu grāmatu', + 'books_delete' => 'Dzēst grāmatu', + 'books_delete_named' => 'Dzēst grāmatu :bookName', + 'books_delete_explain' => 'Šī darbība izdzēsīs grāmatu \':bookName\'. Visas lapas un nodaļas tiks izdzēstas.', + 'books_delete_confirmation' => 'Vai esat pārliecināts, ka vēlaties dzēst šo grāmatu?', + 'books_edit' => 'Labot grāmatu', + 'books_edit_named' => 'Labot grāmatu :bookName', + 'books_form_book_name' => 'Grāmatas nosaukums', + 'books_save' => 'Saglabāt grāmatu', + 'books_permissions' => 'Grāmatas atļaujas', + 'books_permissions_updated' => 'Grāmatas atļaujas atjauninātas', + 'books_empty_contents' => 'Lapas vai nodaļas vēl nav izveidotas šai grāmatai.', + 'books_empty_create_page' => 'Izveidot jaunu lapu', + 'books_empty_sort_current_book' => 'Kārtot šo grāmatu', + 'books_empty_add_chapter' => 'Pievienot nodaļu', + 'books_permissions_active' => 'Grāmatas atļaujas ir aktīvas', + 'books_search_this' => 'Meklēt šajā grāmatā', + 'books_navigation' => 'Grāmatas navigācija', + 'books_sort' => 'Kārtot grāmatas saturu', + 'books_sort_named' => 'Kārtot grāmatu :bookName', + 'books_sort_name' => 'Kārtot pēc nosaukuma', + 'books_sort_created' => 'Kārtot pēc izveidošanas datuma', + 'books_sort_updated' => 'Kārtot pēc atjaunināšanas datuma', + 'books_sort_chapters_first' => 'Nodaļas pirmās', + 'books_sort_chapters_last' => 'Nodaļas pēdējās', + 'books_sort_show_other' => 'Rādīt citas grāmatas', + 'books_sort_save' => 'Saglabāt jauno kārtību', + + // Chapters + 'chapter' => 'Nodaļa', + 'chapters' => 'Nodaļas', + 'x_chapters' => ':count nodaļa|:count nodaļas', + 'chapters_popular' => 'Populāras nodaļas', + 'chapters_new' => 'Jauna nodaļa', + 'chapters_create' => 'Izveidot jaunu nodaļu', + 'chapters_delete' => 'Dzēst nodaļu', + 'chapters_delete_named' => 'Dzēst nodaļu :chapterName', + 'chapters_delete_explain' => 'Šī darbība dzēsīs nodaļu \':chapterName\'. Visas tajā esošās lapas arī tiks dzēstas.', + 'chapters_delete_confirm' => 'Vai esat pārliecināts, ka vēlaties dzēst šo nodaļu?', + 'chapters_edit' => 'Labot nodaļu', + 'chapters_edit_named' => 'Labot nodaļu :chapterName', + 'chapters_save' => 'Saglabāt nodaļu', + 'chapters_move' => 'Pārvietot nodaļu', + 'chapters_move_named' => 'Pārvietot nodaļu :chapterName', + 'chapter_move_success' => 'Nodaļa pārviedota uz :bookName', + 'chapters_permissions' => 'Nodaļas atļaujas', + 'chapters_empty' => 'Šajā nodaļā nav pievienotu lapu.', + 'chapters_permissions_active' => 'Nodaļas atļaujas ir aktīvas', + 'chapters_permissions_success' => 'Nodaļas atļaujas ir atjauninātas', + 'chapters_search_this' => 'Meklēt šajā nodaļā', + + // Pages + 'page' => 'Lapa', + 'pages' => 'Lapas', + 'x_pages' => ':count lapa|:count lapas', + 'pages_popular' => 'Populātas lapas', + 'pages_new' => 'Jauna lapa', + 'pages_attachments' => 'Pielikumi', + 'pages_navigation' => 'Lapas navigācija', + 'pages_delete' => 'Dzēst lapu', + 'pages_delete_named' => 'Dzēst lapu :pageName', + 'pages_delete_draft_named' => 'Dzēst :pageName melnrakstu', + 'pages_delete_draft' => 'Dzēst melnrakstu', + 'pages_delete_success' => 'Lapa ir dzēsta', + 'pages_delete_draft_success' => 'Melnraksts ir dzēsts', + 'pages_delete_confirm' => 'Vai esat pārliecināts, ka vēlaties dzēst šo lapu?', + 'pages_delete_draft_confirm' => 'Vai esat pārliecināts, ka vēlaties dzēst šo melnrakstu?', + 'pages_editing_named' => 'Rediģē lapu :pageName', + 'pages_edit_draft_options' => 'Melnraksta iestatījumi', + 'pages_edit_save_draft' => 'Saglabāt melnrakstu', + 'pages_edit_draft' => 'Labot melnrakstu', + 'pages_editing_draft' => 'Labo melnrakstu', + 'pages_editing_page' => 'Labo lapu', + 'pages_edit_draft_save_at' => 'Melnraksts saglabāts ', + 'pages_edit_delete_draft' => 'Dzēst melnrakstu', + 'pages_edit_discard_draft' => 'Atmest malnrakstu', + 'pages_edit_set_changelog' => 'Pievienot izmaiņu aprakstu', + 'pages_edit_enter_changelog_desc' => 'Ievadi nelielu aprakstu par vaiktajām izmaiņām', + 'pages_edit_enter_changelog' => 'Izmaiņu apraksts', + 'pages_save' => 'Saglabāt lapu', + 'pages_title' => 'Lapas virsraksts', + 'pages_name' => 'Lapas nosaukums', + 'pages_md_editor' => 'Redaktors', + 'pages_md_preview' => 'Priekšskatījums', + 'pages_md_insert_image' => 'Ievietot attēlu', + 'pages_md_insert_link' => 'Ievietot vienuma saiti', + 'pages_md_insert_drawing' => 'Ievietot zīmējumu', + 'pages_not_in_chapter' => 'Lapa nav nodaļā', + 'pages_move' => 'Pārvietot lapu', + 'pages_move_success' => 'Lapa pārvietota uz ":parentName"', + 'pages_copy' => 'Kopēt lapu', + 'pages_copy_desination' => 'Kopijas mērķa vieta', + 'pages_copy_success' => 'Lapa veiksmīgi nokopēta', + 'pages_permissions' => 'Lapas atļaujas', + 'pages_permissions_success' => 'Lapas atļaujas atjauninātas', + 'pages_revision' => 'Revīzijas', + 'pages_revisions' => 'Lapas revīzijas', + 'pages_revisions_named' => ':pageName lapas revīzijas', + 'pages_revision_named' => ':pageName lapas revīzija', + 'pages_revision_restored_from' => 'Atjaunots no #:id; :summary', + 'pages_revisions_created_by' => 'Izveidoja', + 'pages_revisions_date' => 'Revīzijas datums', + 'pages_revisions_number' => '#', + 'pages_revisions_numbered' => 'Revīzija #:id', + 'pages_revisions_numbered_changes' => 'Revīzijas #:id izmaiņas', + 'pages_revisions_changelog' => 'Izmaiņu žurnāls', + 'pages_revisions_changes' => 'Izmaiņas', + 'pages_revisions_current' => 'Tekošā versija', + 'pages_revisions_preview' => 'Priekšskatījums', + 'pages_revisions_restore' => 'Atjaunot', + 'pages_revisions_none' => 'Šai lapai nav revīziju', + 'pages_copy_link' => 'Kopēt saiti', + 'pages_edit_content_link' => 'Labot saturu', + 'pages_permissions_active' => 'Lapas atļaujas ir aktīvas', + 'pages_initial_revision' => 'Sākotnējā publikācija', + 'pages_initial_name' => 'Jauna lapa', + 'pages_editing_draft_notification' => 'Jūs pašlaik veicat izmaiņas melnrakstā, kurš pēdējo reizi ir saglabāts :timeDiff.', + 'pages_draft_edited_notification' => 'Šī lapa ir tikusi atjaunināta. Šo melnrakstu ieteicams atmest.', + 'pages_draft_edit_active' => [ + 'start_a' => ':count lietotāji pašlaik veic izmaiņas šajā lapā', + 'start_b' => ':userName veic izmaiņas šajā lapā', + 'time_a' => 'kopš šī lapa pēdējo reizi ir atjaunināta', + 'time_b' => 'pēdējās :minCount minūtēs', + 'message' => ':start :time. Esat uzmanīgi, lai neaizstātu viens otra izmaiņas!', + ], + 'pages_draft_discarded' => 'Melnraksts ir atcelts, redaktors ir atjaunināts ar pašreizējo lapas saturu', + 'pages_specific' => 'Konkrēta lapa', + 'pages_is_template' => 'Lapas šablons', + + // Editor Sidebar + 'page_tags' => 'Lapas birkas', + 'chapter_tags' => 'Nodaļas birkas', + 'book_tags' => 'Grāmatas birkas', + 'shelf_tags' => 'Plauktu birkas', + 'tag' => 'Birka', + 'tags' => 'Birkas', + 'tag_name' => 'Birkas nosaukums', + 'tag_value' => 'Birkas papildvērtība (neobligāta)', + 'tags_explain' => "Pievieno birkas, lai precīzāk grupētu saturu.\n Tu vari pievienot papildus vērtību birkai vēl precīzākai grupēšanai.", + 'tags_add' => 'Pievienot vēlvienu birku', + 'tags_remove' => 'Noņemt šo birku', + 'attachments' => 'Pielikumi', + 'attachments_explain' => 'Augšupielādējiet dažus failus vai pievieno saites, kas tiks parādītas jūsu lapā. Tie būs redzami lapas sānjoslā.', + 'attachments_explain_instant_save' => 'Izmaiņas šeit tiek saglabātas nekavējoties.', + 'attachments_items' => 'Pievienotie vienumi', + 'attachments_upload' => 'Augšupielādēt failu', + 'attachments_link' => 'Pievienot saiti', + 'attachments_set_link' => 'Uzstādīt saiti', + 'attachments_delete' => 'Vai tiešām vēlaties dzēst šo pielikumu?', + 'attachments_dropzone' => 'Ievilkt failus vai klikšķināt šeit, lai pievieotu failus', + 'attachments_no_files' => 'Neviens fails nav augšupielādēts', + 'attachments_explain_link' => 'Ja nevēlaties augšupielādēt failu, varat pievienot saiti. Tā var būt saite uz citu lapu vai saite uz failu mākonī.', + 'attachments_link_name' => 'Saites nosaukums', + 'attachment_link' => 'Pielikuma saite', + 'attachments_link_url' => 'Saite uz failu', + 'attachments_link_url_hint' => 'Web lapas vai faila URL', + 'attach' => 'Pievienot', + 'attachments_insert_link' => 'Pievienot pielikuma saiti lapai', + 'attachments_edit_file' => 'Rediģēt failu', + 'attachments_edit_file_name' => 'Faila nosaukums', + 'attachments_edit_drop_upload' => 'Ievelc failus vai spied šeit, lai augšupielādētu vai aizstātu failus', + 'attachments_order_updated' => 'Pielikuma secība ir atjaunināta', + 'attachments_updated_success' => 'Pielikuma informācja ir atjaunināta', + 'attachments_deleted' => 'Pielikums dzēsts', + 'attachments_file_uploaded' => 'Fails veiksmīgi augšupielādēts', + 'attachments_file_updated' => 'Fails veiksmīgi atjaunināts', + 'attachments_link_attached' => 'Hipersaite veismīgi pievienota lapai', + 'templates' => 'Šabloni', + 'templates_set_as_template' => 'Šī lapa ir šablons', + 'templates_explain_set_as_template' => 'Jūs varat iestatīt šo lapu kā veidni, lai tās saturs tiktu izmantots, veidojot citas lapas. Citi lietotāji varēs izmantot šo veidni, ja viņiem būs atļauja piekļūt šai lapai.', + 'templates_replace_content' => 'Aizstāt lapas saturu', + 'templates_append_content' => 'Pievienot lapas saturam (beigās)', + 'templates_prepend_content' => 'Pievienot lapas saturam (sākumā)', + + // Profile View + 'profile_user_for_x' => 'Lietotājs jau :time', + 'profile_created_content' => 'Izveidotais saturs', + 'profile_not_created_pages' => ':userName nav izveidojis lapas', + 'profile_not_created_chapters' => ':userName nav izveidojis nodalas', + 'profile_not_created_books' => ':userName nav izveidojis grāmatas', + 'profile_not_created_shelves' => ':userName nav izveidojis grāmatplauktus', + + // Comments + 'comment' => 'Komentārs', + 'comments' => 'Komentāri', + 'comment_add' => 'Pievienot komentāru', + 'comment_placeholder' => 'Pievieno komentāru', + 'comment_count' => '{0} Nav komentāru |{1} 1 Komentārs|[2,*] :count Komentāri', + 'comment_save' => 'Saglabāt komentāru', + 'comment_saving' => 'Saglabā komentāru...', + 'comment_deleting' => 'Dzēš komentāru...', + 'comment_new' => 'Jauns komentārs', + 'comment_created' => 'komentējis :createDiff', + 'comment_updated' => ':username atjauninājis pirms :updateDiff', + 'comment_deleted_success' => 'Komentārs ir dzēsts', + 'comment_created_success' => 'Komentārs ir pievienots', + 'comment_updated_success' => 'Komentārs ir atjaunināts', + 'comment_delete_confirm' => 'Vai esat pārliecināts, ka vēlaties dzēst šo komentāru?', + 'comment_in_reply_to' => 'Atbildēt uz :commentId', + + // Revision + 'revision_delete_confirm' => 'Vai esat pārliecināts, ka vēlaties dzēst šo revīziju?', + 'revision_restore_confirm' => 'Vai esat pārliecināts, ka vēlaties atjaunot šo revīziju? Tekošais lapas saturs tiks aizstāts.', + 'revision_delete_success' => 'Revīzija dzēsta', + 'revision_cannot_delete_latest' => 'Nevar dzēst tekošo revīziju.' +]; \ No newline at end of file diff --git a/resources/lang/lv/errors.php b/resources/lang/lv/errors.php new file mode 100644 index 000000000..f5e55a603 --- /dev/null +++ b/resources/lang/lv/errors.php @@ -0,0 +1,102 @@ + 'Jums nav atļauts piekļūt šai lapai.', + 'permissionJson' => 'Jums nav atļauts veikt konkrēto darbību.', + + // Auth + 'error_user_exists_different_creds' => 'Lietotājs ar epastu :email bet ar citiem piekļuves datiem jau eksistē.', + 'email_already_confirmed' => 'Epasts jau ir apstiprināts, mēģini ielogoties.', + 'email_confirmation_invalid' => 'Šis apstiprinājuma žetons nav derīgs vai jau ir izmantots. Lūdzu, mēģiniet reģistrēties vēlreiz.', + 'email_confirmation_expired' => 'Apstiprinājuma žetona derīguma termiņš ir beidzies. Ir nosūtīts jauns apstiprinājuma e-pasts.', + 'email_confirmation_awaiting' => 'Šī konta e-pasta adresei ir nepieciešms apstiprinājums', + 'ldap_fail_anonymous' => 'LDAP piekļuve neveiksmīga izmantojot anonymous bind', + 'ldap_fail_authed' => 'LDAP piekļuve neveiksmīga izmantojot norādīto dn un paroli', + 'ldap_extension_not_installed' => 'LDAP PHP paplašinājums nav instalēts', + 'ldap_cannot_connect' => 'Nav iespējams pieslēgties LDAP serverim, sākotnējais pieslēgums neveiksmīgs', + 'saml_already_logged_in' => 'Jau ielogojies', + 'saml_user_not_registered' => 'Lietotājs :name nav reģistrēts un automātiska reģistrācija ir izslēgta', + 'saml_no_email_address' => 'Ārējās autentifikācijas sistēmas sniegtajos datos nevarēja atrast šī lietotāja e-pasta adresi', + 'saml_invalid_response_id' => 'Ārējās autentifikācijas sistēmas pieprasījums neatpazīst procesu, kuru sākusi šī lietojumprogramma. Pārvietojoties atpakaļ pēc pieteikšanās var rasties šāda problēma.', + 'saml_fail_authed' => 'Piekļuve ar :system neizdevās, sistēma nepieļāva veiksmīgu autorizāciju', + 'social_no_action_defined' => 'Darbības nav definētas', + 'social_login_bad_response' => "Saņemta kļūda izmantojot :socialAccount piekļuvi:\n:error", + 'social_account_in_use' => 'Šis :socialAccount konts jau tiek izmantots, mēģiniet ieiet ar :socialAccount piekļuves iespēju.', + 'social_account_email_in_use' => 'Šis epasts :email jau tiek izmantots. Ja jums jau ir konts, jūs varat pieslēgt savu :socialAccount kontu savos profila uzstādījumos.', + 'social_account_existing' => 'Šis :socialAccount konts jau ir piesaistīts jūsu profilam.', + 'social_account_already_used_existing' => 'Šo :socialAccount konts jau ir piesaistīts citam lietotājam.', + 'social_account_not_used' => 'Šis :socialAccount konts nav piesaistīts nevienam lietotājām. Lūdzu pievienojiet to savos profila uzstādījumos. ', + 'social_account_register_instructions' => 'Ja jums vēl nav savs konts, jūs varat reģistrēt kontu izmantojot :socialAccount piekļuvi.', + 'social_driver_not_found' => 'Sociālā tīkla savienojums nav atrasts', + 'social_driver_not_configured' => 'Jūsu :socialAccount sociālie iestatījumi nav uzstādīti pareizi.', + 'invite_token_expired' => 'Šī uzaicinājuma saite ir novecojusi. Tā vietā jūs varat mēģināt atiestatīt sava konta paroli.', + + // System + 'path_not_writable' => 'Faila ceļā :filePath nav iespējams ielādēt failus. Lūdzu pārliecinieties, ka serverim tur ir rakstīšanas tiesības.', + 'cannot_get_image_from_url' => 'Nevar iegūt bildi no :url', + 'cannot_create_thumbs' => 'Serveris nevar izveidot samazinātus attēlus. Lūdzu pārbaudiet, vai ir uzstādīts PHP GD paplašinājums.', + 'server_upload_limit' => 'Serveris neatļauj šāda izmēra failu ielādi. Lūdzu mēģiniet mazāka izmēra failu.', + 'uploaded' => 'Serveris neatļauj šāda izmēra failu ielādi. Lūdzu mēģiniet mazāka izmēra failu.', + 'image_upload_error' => 'Radās kļūda augšupielādējot attēlu', + 'image_upload_type_error' => 'Ielādējamā attēla tips nav derīgs', + 'file_upload_timeout' => 'Faila augšupielādē ir iestājies noilgums.', + + // Attachments + 'attachment_not_found' => 'Pielikums nav atrasts', + + // Pages + 'page_draft_autosave_fail' => 'Neizdevās saglabāt uzmetumu. Pārliecinieties, ka jūsu interneta pieslēgums ir aktīvs pirms saglabājiet šo lapu', + 'page_custom_home_deletion' => 'Nav iespējams izdzēst lapu kamēr tā ir uzstādīta kā sākumlapa', + + // Entities + 'entity_not_found' => 'Vienība nav atrasta', + 'bookshelf_not_found' => 'Grāmatplaukts nav atrasts', + 'book_not_found' => 'Grāmata nav atrasta', + 'page_not_found' => 'Lapa nav atrasta', + 'chapter_not_found' => 'Nodaļa nav atrasta', + 'selected_book_not_found' => 'Iezīmētā grāmata nav atrasta', + 'selected_book_chapter_not_found' => 'Izvēlētā grāmata vai nodaļa nav atrasta', + 'guests_cannot_save_drafts' => 'Viesi nevar saglabāt melnrakstus', + + // Users + 'users_cannot_delete_only_admin' => 'Jūs nevarat dzēst vienīgo administratoru', + 'users_cannot_delete_guest' => 'Jūs nevarat dzēst lietotāju "viesis"', + + // Roles + 'role_cannot_be_edited' => 'Šo lomu nevar rediģēt', + 'role_system_cannot_be_deleted' => 'Šī ir sistēmas loma un nevar tikt izdzēsta', + 'role_registration_default_cannot_delete' => 'Šī loma nevar tikt izdzēsta, kamēr tā uzstādīta kā noklusētā reģistrācijas loma', + 'role_cannot_remove_only_admin' => 'Šis ir vienīgais lietotājs, kam norādīta administratora loma. Pievienojiet administratora lomu citam lietotājam pirms mēģiniet to izslēgt šeit.', + + // Comments + 'comment_list' => 'Radās kļūda ielasot komentārus.', + 'cannot_add_comment_to_draft' => 'Melnrakstam nevar pievienot komentārus.', + 'comment_add' => 'Radās kļūda pievienojot/atjaunojot komentāru.', + 'comment_delete' => 'Radās kļūda dzēšot komentāru.', + 'empty_comment' => 'Nevar pievienot tukšu komentāru.', + + // Error pages + '404_page_not_found' => 'Lapa nav atrasta', + 'sorry_page_not_found' => 'Atvainojiet, meklētā lapa nav atrasta.', + 'sorry_page_not_found_permission_warning' => 'Ja šai lapai būtu bijis te jābūt, jums var nebūt pietiekamas piekļuves tiesības, lai to apskatītu.', + 'return_home' => 'Atgriezties uz sākumu', + 'error_occurred' => 'Radusies kļūda', + 'app_down' => ':appName pagaidām nav pieejams', + 'back_soon' => 'Drīz būs atkal pieejams.', + + // API errors + 'api_no_authorization_found' => 'Pieprasījumā nav atrasts autorizācijas žetons', + 'api_bad_authorization_format' => 'Pieprasījumā atrasts autorizācijas žetons, taču tā formāts nav pareizs', + 'api_user_token_not_found' => 'Nav atrasts norādītajam autorizācijas žetonam atbilstošs API žetons', + 'api_incorrect_token_secret' => 'Norādītā slepenā atslēga izmantotajam API žetonam nav pareiza', + 'api_user_no_api_permission' => 'Izmantotā API žetona īpašniekam nav tiesības veikt API izsaukumus', + 'api_user_token_expired' => 'Autorizācijas žetona derīguma termiņš ir izbeidzies', + + // Settings & Maintenance + 'maintenance_test_email_failure' => 'Radusies kļūda sūtot testa epastu:', + +]; diff --git a/resources/lang/lv/pagination.php b/resources/lang/lv/pagination.php new file mode 100644 index 000000000..c46d6dc04 --- /dev/null +++ b/resources/lang/lv/pagination.php @@ -0,0 +1,12 @@ + '« Iepriekšējais', + 'next' => 'Nākamais »', + +]; diff --git a/resources/lang/lv/passwords.php b/resources/lang/lv/passwords.php new file mode 100644 index 000000000..7d939574f --- /dev/null +++ b/resources/lang/lv/passwords.php @@ -0,0 +1,15 @@ + 'Parolēm jābūt vismaz astoņu simbolu garām un jāatbilst apstiprinājumam.', + 'user' => "Mēs nevaram atrast lietotāju ar šādu e-pasta adresi.", + 'token' => 'Paroles atiestatīšanas atslēga neatbilst šai e-pasta adresei.', + 'sent' => 'Esam nosūtījuši paroles atiestatīšanas saiti!', + 'reset' => 'Parole ir atiestatīta!', + +]; diff --git a/resources/lang/lv/settings.php b/resources/lang/lv/settings.php new file mode 100644 index 000000000..de6b2754a --- /dev/null +++ b/resources/lang/lv/settings.php @@ -0,0 +1,266 @@ + 'Iestatījumi', + 'settings_save' => 'Saglabāt iestatījumus', + 'settings_save_success' => 'Iestatījumi saglabāti', + + // App Settings + 'app_customization' => 'Pielāgojumi', + 'app_features_security' => 'Funkcijas un drošība', + 'app_name' => 'Lietotnes nosaukums', + 'app_name_desc' => 'Šis vārds tiks rādīts navigācijas joslā un sistēmas sūtītajis e-pastos.', + 'app_name_header' => 'Rādīt vārdu navigācijas joslā', + 'app_public_access' => 'Publiska piekļuve', + 'app_public_access_desc' => 'Šīs opcijas ieslēgšana ļaus neautorizētiem apmeklētājiem piekļūt jūsu BookStack saturam.', + 'app_public_access_desc_guest' => 'Publisku apmeklētāju piekļuvi var kontrolēt "Guest" (Viesa) lietotāja uzstādījumos.', + 'app_public_access_toggle' => 'Atļaut publisku piekļuvi', + 'app_public_viewing' => 'Atļaut publisku piekļuvi?', + 'app_secure_images' => 'Paaugstinātas drošības attēlu ielāde', + 'app_secure_images_toggle' => 'Ieslēgt paaugstinātas drošības attēlu ielādi', + 'app_secure_images_desc' => 'Ātrdarbības nolūkos attēli ir publiski pieejami. Šī opcija pievieno nejaušu grūti uzminamu teksta virkni attēlu adresēs. Pārliecinieties kā ir izslēgta direktoriju pārlūkošana, lai nepieļautu vieglu piekļuvi šiem failiem.', + 'app_editor' => 'Lapas redaktors', + 'app_editor_desc' => 'Izvēlēties kurš redaktors tiks izmatots lapu rediģēšanai visiem lietotājiem.', + 'app_custom_html' => 'Pielāgot HTML head saturu', + 'app_custom_html_desc' => 'Šis saturs tiks pievienots sadaļas apakšā visām lapām. Tas ir noderīgi papildinot CSS stilus vai pievienojot analītikas kodu.', + 'app_custom_html_disabled_notice' => 'Pielāgots HTML head saturs ir izslēgts šajā uzstādījumu lapā, lai nodrošinātu, ka iespējams atcelt jebkādas kritiskas izmaiņas.', + 'app_logo' => 'Lietotnes logo', + 'app_logo_desc' => 'Attēlam jābūt 43px augstam.
Lielāki attēli tiks samazināti.', + 'app_primary_color' => 'Galvenā aplikācijas krāsa', + 'app_primary_color_desc' => 'Uzstāda primāro krāsu aplikācijai, ieskaitot banneri, pogas un saites.', + 'app_homepage' => 'Aplikācijas sākumlapa', + 'app_homepage_desc' => 'Izvēlēties skatu, ko rādīt sākumlapā noklusētā skata vietā. Lapas piekļuves tiesības izvēlētajai lapai netiks ņemtas vērā.', + 'app_homepage_select' => 'Izvēlēties lapu', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Saites nosaukums', + 'app_footer_links_url' => 'Saites URL', + 'app_footer_links_add' => 'Add Footer Link', + 'app_disable_comments' => 'Izslēgt komentārus', + 'app_disable_comments_toggle' => 'Izslēgt komentārus', + 'app_disable_comments_desc' => 'Atslēdz komentārus visās aplikācijas lapās.
Jau eksistējoši komentāri netiks attēloti.', + + // Color settings + 'content_colors' => 'Satura krāsas', + 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'bookshelf_color' => 'Plaukta krāsa', + 'book_color' => 'Grāmatas krāsa', + 'chapter_color' => 'Nodaļas krāsa', + 'page_color' => 'Lapas krāsa', + 'page_draft_color' => 'Lapas uzmetuma krāsa', + + // Registration Settings + 'reg_settings' => 'Reģistrācija', + 'reg_enable' => 'Iespējot reģistrāciju', + 'reg_enable_toggle' => 'Iespējot reģistrāciju', + 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', + 'reg_default_role' => 'Noklusētā lietotāja loma pēc reģistrācijas', + 'reg_enable_external_warning' => 'Šis uzstādījums tiek ignorēts kamēr tiek izmantota ārēja LDAP vai SAML autentifikācija. Tiks izveidoti lietotāju konti neeksistējošiem leitotājiem, ja autentifikācija pret ārējo sistēmu būs veiksmīga.', + 'reg_email_confirmation' => 'E-pasta apstiprinājums', + 'reg_email_confirmation_toggle' => 'Pieprasīt epasta apstiprināšanu', + 'reg_confirm_email_desc' => 'Ja ieslēgts domēnu ierobežojums, tad būs nepieciešama epasta apstiprināšana un šis uzstādījums tiks ignorēts.', + 'reg_confirm_restrict_domain' => 'Domēnu ierobežojums', + 'reg_confirm_restrict_domain_desc' => 'Enter a comma separated list of email domains you would like to restrict registration to. Users will be sent an email to confirm their address before being allowed to interact with the application.
Note that users will be able to change their email addresses after successful registration.', + 'reg_confirm_restrict_domain_placeholder' => 'Nav ierobežojumu', + + // Maintenance settings + 'maint' => 'Apkope', + 'maint_image_cleanup' => 'Tīrīt neizmantotās bildes', + 'maint_image_cleanup_desc' => "Scans page & revision content to check which images and drawings are currently in use and which images are redundant. Ensure you create a full database and image backup before running this.", + 'maint_delete_images_only_in_revisions' => 'Dzēst arī attēlus, kas izmantoti tikai vecās lapu satura versijās', + 'maint_image_cleanup_run' => 'Veikt tīrīšanu', + 'maint_image_cleanup_warning' => ':count iespējami neizmantoti attēli atrasti. Vai tiešām vēlaties izdzēst šos attēlus?', + 'maint_image_cleanup_success' => ':count iespējami neizmantoti attēli atrasti un izdzēsti!', + 'maint_image_cleanup_nothing_found' => 'Nav atrasti neizmantoti attēli, nekas netika izdzēsts!', + 'maint_send_test_email' => 'Nosūtīt testa epastu', + 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', + 'maint_send_test_email_run' => 'Nosūtīt testa epastu', + 'maint_send_test_email_success' => 'Epasts nosūtīts uz :address', + 'maint_send_test_email_mail_subject' => 'Testa epasts', + 'maint_send_test_email_mail_greeting' => 'Izskatās, ka epasta piegāde strādā!', + 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', + 'maint_recycle_bin_desc' => 'Deleted shelves, books, chapters & pages are sent to the recycle bin so they can be restored or permanently deleted. Older items in the recycle bin may be automatically removed after a while depending on system configuration.', + 'maint_recycle_bin_open' => 'Atvērt miskasti', + + // Recycle Bin + 'recycle_bin' => 'Miskaste', + 'recycle_bin_desc' => 'Here you can restore items that have been deleted or choose to permanently remove them from the system. This list is unfiltered unlike similar activity lists in the system where permission filters are applied.', + 'recycle_bin_deleted_item' => 'Dzēsta vienība', + 'recycle_bin_deleted_by' => 'Izdzēsa', + 'recycle_bin_deleted_at' => 'Dzēšanas laiks', + 'recycle_bin_permanently_delete' => 'Neatgriezeniski izdzēst', + 'recycle_bin_restore' => 'Atjaunot', + 'recycle_bin_contents_empty' => 'Miskaste ir tukša', + 'recycle_bin_empty' => 'Iztīrīt miskasti', + 'recycle_bin_empty_confirm' => 'This will permanently destroy all items in the recycle bin including content contained within each item. Are you sure you want to empty the recycle bin?', + 'recycle_bin_destroy_confirm' => 'Šī darbība pilnībā izdzēsis šo vienību kopā ar tai pakārtotajiem elementiem no sistēmas, un jūs nevarēsiet šo saturu atjaunot. Vai tiešām vēlaties pilnībā izdzēst šo vienību?', + 'recycle_bin_destroy_list' => 'Dzēšamās vienības', + 'recycle_bin_restore_list' => 'Atjaunojamās vienības', + 'recycle_bin_restore_confirm' => 'This action will restore the deleted item, including any child elements, to their original location. If the original location has since been deleted, and is now in the recycle bin, the parent item will also need to be restored.', + 'recycle_bin_restore_deleted_parent' => 'The parent of this item has also been deleted. These will remain deleted until that parent is also restored.', + 'recycle_bin_destroy_notification' => 'Deleted :count total items from the recycle bin.', + 'recycle_bin_restore_notification' => 'Restored :count total items from the recycle bin.', + + // Audit Log + 'audit' => 'Auditācijas pieraksti', + 'audit_desc' => 'Šie auditācijas pieraksti attēlo sarakstu ar sistēmā reģistrētajām aktivitātēm. Šis saraksts nav filtrēts atšķirībā no līdzīgiem aktivitāšu sarakstiem sistēmā, kur ir piemēroti atļauto darbību filtri.', + 'audit_event_filter' => 'Notikumu filtrs', + 'audit_event_filter_no_filter' => 'Bez filtra', + 'audit_deleted_item' => 'Dzēsta vienība', + 'audit_deleted_item_name' => 'Vārds: :name', + 'audit_table_user' => 'Lietotājs', + 'audit_table_event' => 'Notikums', + 'audit_table_related' => 'Saistīta vienība vai detaļa', + 'audit_table_date' => 'Notikuma datums', + 'audit_date_from' => 'Datums no', + 'audit_date_to' => 'Datums līdz', + + // Role Settings + 'roles' => 'Grupas', + 'role_user_roles' => 'Lietotāju grupas', + 'role_create' => 'Izveidot jaunu grupu', + 'role_create_success' => 'Grupa veiksmīgi izveidota', + 'role_delete' => 'Dzēst grupu', + 'role_delete_confirm' => 'Loma \':roleName\' tiks dzēsta.', + 'role_delete_users_assigned' => 'Šajā grupā ir pievienoti :userCount lietotāji. Ja vēlaties pārvietot lietotājus no šīs grupas, tad izvēlaties kādu no zemāk redzamajām grupām.', + 'role_delete_no_migration' => "Nepārvietot lietotājus", + 'role_delete_sure' => 'Vai tiešām vēlaties dzēst grupu?', + 'role_delete_success' => 'Grupa veiksmīgi dzēsta', + 'role_edit' => 'Rediģēt grupu', + 'role_details' => 'Informācija par grupu', + 'role_name' => 'Grupas nosaukums', + 'role_desc' => 'Īss grupas apaksts', + 'role_external_auth_id' => 'Ārējais autentifikācijas ID', + 'role_system' => 'Sistēmas atļaujas', + 'role_manage_users' => 'Pārvaldīt lietotājus', + 'role_manage_roles' => 'Pārvaldīt grupas un grupu atļaujas', + 'role_manage_entity_permissions' => 'Pārvaldīt visu grāmatu, nodaļu un lapu atļaujas', + 'role_manage_own_entity_permissions' => 'Pārvaldīt atļaujas savām grāmatām, nodaļām un lapām', + 'role_manage_page_templates' => 'Pārvaldīt lapas veidnes', + 'role_access_api' => 'Piekļūt sistēmas API', + 'role_manage_settings' => 'Pārvaldīt iestatījumus', + 'role_asset' => 'Asset Permissions', + 'roles_system_warning' => 'Jebkuras no trīs augstāk redzamajām atļaujām dod iespēju lietotājam mainīt savas un citu lietotāju sistēmas atļaujas. Pievieno šīs grupu atļaujas tikai tiem lietotājiem, kuriem uzticies.', + 'role_asset_desc' => 'These permissions control default access to the assets within the system. Permissions on Books, Chapters and Pages will override these permissions.', + 'role_asset_admins' => 'Admins are automatically given access to all content but these options may show or hide UI options.', + 'role_all' => 'Visi', + 'role_own' => 'Savi', + 'role_controlled_by_asset' => 'Controlled by the asset they are uploaded to', + 'role_save' => 'Saglabāt grupu', + 'role_update_success' => 'Grupa veiksmīgi atjaunināta', + 'role_users' => 'Lietotāji šajā grupā', + 'role_users_none' => 'Pagaidām neviens lietotājs nav pievienots šai grupai', + + // Users + 'users' => 'Lietotāji', + 'user_profile' => 'Lietotāja profils', + 'users_add_new' => 'Pievienot jaunu lietotāju', + 'users_search' => 'Meklēt lietotājus', + 'users_latest_activity' => 'Pēdējās aktivitātes', + 'users_details' => 'Lietotāja informācija', + 'users_details_desc' => 'Set a display name and an email address for this user. The email address will be used for logging into the application.', + 'users_details_desc_no_email' => 'Set a display name for this user so others can recognise them.', + 'users_role' => 'Lietotāju grupas', + 'users_role_desc' => 'Izvēlēties kurām grupām pievienot lietotāju. Ja lietotājs ir pievienots vairākām grupām, tad lietotājam būs pieejamas visu grupu atļaujas.', + 'users_password' => 'Lietotāja parole', + 'users_password_desc' => 'Set a password used to log-in to the application. This must be at least 6 characters long.', + 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', + 'users_send_invite_option' => 'Nosūtīt lietotāja uzaicinājuma epastu', + 'users_external_auth_id' => 'Ārējais autentifikācijas ID', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', + 'users_password_warning' => 'Only fill the below if you would like to change your password.', + 'users_system_public' => 'This user represents any guest users that visit your instance. It cannot be used to log in but is assigned automatically.', + 'users_delete' => 'Dzēst lietotāju', + 'users_delete_named' => 'Dzēst lietotāju :userName', + 'users_delete_warning' => 'This will fully delete this user with the name \':userName\' from the system.', + 'users_delete_confirm' => 'Are you sure you want to delete this user?', + 'users_migrate_ownership' => 'Migrate Ownership', + 'users_migrate_ownership_desc' => 'Select a user here if you want another user to become the owner of all items currently owned by this user.', + 'users_none_selected' => 'Nav izvēlēts lietotājs', + 'users_delete_success' => 'Lietotājs veiksmīgi dzēsts', + 'users_edit' => 'Rediģēt lietotāju', + 'users_edit_profile' => 'Rediģēt profilu', + 'users_edit_success' => 'Lietotājs veiksmīgi atjaunināts', + 'users_avatar' => 'User Avatar', + 'users_avatar_desc' => 'Select an image to represent this user. This should be approx 256px square.', + 'users_preferred_language' => 'Vēlamā valoda', + 'users_preferred_language_desc' => 'This option will change the language used for the user-interface of the application. This will not affect any user-created content.', + 'users_social_accounts' => 'Sociālie konti', + 'users_social_accounts_info' => 'Here you can connect your other accounts for quicker and easier login. Disconnecting an account here does not revoke previously authorized access. Revoke access from your profile settings on the connected social account.', + 'users_social_connect' => 'Pievienot kontu', + 'users_social_disconnect' => 'Atvienot kontu', + 'users_social_connected' => ':socialAccount konts veiksmīgi pieslēgts jūsu profilam.', + 'users_social_disconnected' => ':socialAccount konts veiksmīgi atslēgts no jūsu profila.', + 'users_api_tokens' => 'API žetoni', + 'users_api_tokens_none' => 'Šim lietotājam nav izveidotu API žetonu', + 'users_api_tokens_create' => 'Izveidot žetonu', + 'users_api_tokens_expires' => 'Derīguma termiņš', + 'users_api_tokens_docs' => 'API dokumentācija', + + // API Tokens + 'user_api_token_create' => 'Izveidot API žetonu', + 'user_api_token_name' => 'Vārds', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Derīgs līdz', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API žetons veiksmīgi izveidots', + 'user_api_token_update_success' => 'API žetons veiksmīgi atjaunināts', + 'user_api_token' => 'API žetons', + 'user_api_token_id' => 'Žetona ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Žetons izveidots :timeAgo', + 'user_api_token_updated' => 'Žetons atjaunināts :timeAgo', + 'user_api_token_delete' => 'Dzēst žetonu', + 'user_api_token_delete_warning' => 'Šī darbība pilnībā izdzēsīs API žetonu \':tokenName\' no sistēmas.', + 'user_api_token_delete_confirm' => 'Vai tiešām vēlaties dzēst šo API žetonu?', + 'user_api_token_delete_success' => 'API žetons veiksmīgi dzēsts', + + //! 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', + 'fr' => 'Français', + 'he' => 'עברית', + 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', + 'it' => 'Italian', + 'ja' => '日本語', + 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', + 'nl' => 'Nederlands', + 'nb' => 'Norsk (Bokmål)', + 'pl' => 'Polski', + 'pt' => 'Português', + 'pt_BR' => 'Português do Brasil', + '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/lv/validation.php b/resources/lang/lv/validation.php new file mode 100644 index 000000000..5aeccb6e0 --- /dev/null +++ b/resources/lang/lv/validation.php @@ -0,0 +1,115 @@ + ':attribute ir jāapstiprina.', + 'active_url' => ':attribute nav derīgs URL.', + 'after' => ':attribute ir jābūt datumam pēc :date.', + 'alpha' => ':attribute var saturēt tikai burtus.', + 'alpha_dash' => ':attribute var saturēt tikai burtus, ciparus, domuzīmes un apakš svītras.', + 'alpha_num' => ':attribute var saturēt tikai burtus un ciparus.', + 'array' => ':attribute ir jābūt masīvam.', + 'before' => ':attribute jābūt datumam pirms :date.', + 'between' => [ + 'numeric' => ':attribute jābūt starp :min un :max.', + 'file' => ':attribute jābūt starp :min un :max kilobaitiem.', + 'string' => ':attribute jābūt starp :min un :max rakstzīmēm.', + 'array' => 'Atribūtam jābūt starp: min un: max vienumiem.', + ], + 'boolean' => ':attribute jābūt True vai False.', + 'confirmed' => ':attribute apstiprinājums nesakrīt.', + 'date' => ':attribute nav derīgs datums.', + 'date_format' => ':attribute neatbilst formātam :format.', + 'different' => ':attribute un :other jābūt atšķirīgiem.', + 'digits' => ':attribute jābūt :digits cipariem.', + 'digits_between' => ':attribute jābūt starp :min un :max cipariem.', + 'email' => ':attribute jābūt derīgai e-pasta adresei.', + 'ends_with' => ':attribute jābeidzas ar vienu no :values', + 'filled' => ':attribute lauks ir obligāts.', + 'gt' => [ + 'numeric' => ':attribute jābūt lielākam kā :value.', + 'file' => ':attribute jābūt lielākam kā :value kilobaitiem.', + 'string' => ':attribute jābūt lielākam kā :value rakstzīmēm.', + 'array' => ':attribute jāsatur vairāk kā :value vienības.', + ], + 'gte' => [ + 'numeric' => ':attribute jābūt lielākam vai vienādam ar :value.', + 'file' => ':attribute jābūt lielākam vai vienādam ar :value kilobaitiem.', + 'string' => ':attribute jābūt lielākam vai vienādam ar :value rakstzīmēm.', + 'array' => ':attribute jāsatur :value vai vairāk vienumus.', + ], + 'exists' => 'Izvēlētais :attribute ir nederīgs.', + 'image' => ':attribute jābūt attēlam.', + 'image_extension' => ':attribute jābūt derīgam un atbalstītam bildes paplašinājumam.', + 'in' => 'Iezīmētais :attribute ir nederīgs.', + 'integer' => ':attribute ir jābūt veselam skaitlim.', + 'ip' => ':attribute jābūt derīgai IP adresei.', + 'ipv4' => ':attribute jābūt derīgai IPv4 adresei.', + 'ipv6' => ':attribute jābūt derīgai IPv6 adresei.', + 'json' => ':attribute jābūt derīgai JSON virknei.', + 'lt' => [ + 'numeric' => ':attribute jābūt mazākam par :value.', + 'file' => ':attribute jābūt mazāk kā :value kilobaitiem.', + 'string' => ':attribute jābūt mazāk kā :value rakstzīmēm.', + 'array' => ':attribute jāsatur mazāk kā :value vienības.', + ], + 'lte' => [ + 'numeric' => ':attribute jābūt mazākam vai vienādam ar :value.', + 'file' => ':attribute jābūt mazākam vai vienādam ar :value kilobaitiem.', + 'string' => ':attribute jābūt mazākam vai vienādam ar :value rakstzīmēm.', + 'array' => ':attribute nedrīkst pārsniegt :value vienības.', + ], + 'max' => [ + 'numeric' => ':attribute nevar būt lielāks kā :max.', + 'file' => ':attribute nedrīkst būt lielāks kā :max kilobaiti.', + 'string' => ':attribute nedrīkst būt lielāks kā :max rakstzīmēm.', + 'array' => ':attribute nedrīkst būt lielāks kā :max vienumi.', + ], + 'mimes' => ':attribute jābūt faila tipam: :values.', + 'min' => [ + 'numeric' => ':attribute ir jābūt vismaz :min.', + 'file' => ':attribute jābūt vismaz :min kilobaitiem.', + 'string' => ':attribute ir jābūt vismaz :min rakstzīmēm.', + 'array' => ':attribute ir jābūt vismaz :min vienībām.', + ], + 'no_double_extension' => ':attribute drīkst būt tikai viens faila paplašinājums.', + 'not_in' => 'Izvēlētais: atribūts ir nederīgs.', + 'not_regex' => ':attribute formāts nav derīgs.', + 'numeric' => ':attribute ir jābūt skaitlim.', + 'regex' => ':attribute formāts nav derīgs.', + 'required' => ':attribute lauks ir obligāts.', + 'required_if' => ':attribute lauks ir nepieciešams, kad :other ir :value.', + 'required_with' => ':attribute lauks ir obligāts, ja ir :values.', + 'required_with_all' => ':attribute lauks ir obligāts, ja ir :values.', + 'required_without' => ':attribute lauks ir obligāts, ja nav :values.', + 'required_without_all' => ':attribute lauks ir obligāts, ja nav neviena no :values.', + 'same' => ':attribute un :other jāsakrīt.', + 'safe_url' => 'Norādītā saite var būt nedroša.', + 'size' => [ + 'numeric' => ':attribute ir jābūt :size.', + 'file' => ':attribute jābūt :size kilobaiti.', + 'string' => ':attribute jābūt :size rakstzīmēm.', + 'array' => ':attribute jāsatur :size vienības.', + ], + 'string' => ':attribute jābūt teksta virknei.', + 'timezone' => ':attribute jābūt derīgai zonai.', + 'unique' => ':attribute jau ir aizņemts.', + 'url' => ':attribute formāts nav derīgs.', + 'uploaded' => 'Fails netika ielādēts. Serveris nevar pieņemt šāda izmēra failus.', + + // Custom validation lines + 'custom' => [ + 'password-confirm' => [ + 'required_with' => 'Nepieciešams paroles apstiprinājums', + ], + ], + + // Custom validation attributes + 'attributes' => [], +]; diff --git a/resources/lang/nb/activities.php b/resources/lang/nb/activities.php index e2516ab74..bf23393ab 100644 --- a/resources/lang/nb/activities.php +++ b/resources/lang/nb/activities.php @@ -46,5 +46,5 @@ return [ // Other 'commented_on' => 'kommenterte på', - 'permissions_update' => 'updated permissions', + 'permissions_update' => 'oppdaterte tilganger', ]; diff --git a/resources/lang/nb/common.php b/resources/lang/nb/common.php index 5fab43787..806e2c0a1 100644 --- a/resources/lang/nb/common.php +++ b/resources/lang/nb/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'Om du har problemer med å trykke på «:actionText»-knappen, bruk nettadressen under for å gå direkte dit:', 'email_rights' => 'Kopibeskyttet', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privacy Policy', + 'terms_of_service' => 'Terms of Service', ]; diff --git a/resources/lang/nb/entities.php b/resources/lang/nb/entities.php index dfee93e1f..b27683c62 100644 --- a/resources/lang/nb/entities.php +++ b/resources/lang/nb/entities.php @@ -22,7 +22,7 @@ return [ 'meta_created_name' => 'Opprettet :timeLength av :user', 'meta_updated' => 'Oppdatert :timeLength', 'meta_updated_name' => 'Oppdatert :timeLength av :user', - 'meta_owned_name' => 'Owned by :user', + 'meta_owned_name' => 'Eies av :user', 'entity_select' => 'Velg entitet', 'images' => 'Bilder', 'my_recent_drafts' => 'Mine nylige utkast', @@ -40,7 +40,7 @@ return [ 'permissions_intro' => 'Når disse er tillatt, vil disse tillatelsene ha prioritet over alle angitte rolletillatelser.', 'permissions_enable' => 'Aktiver egendefinerte tillatelser', 'permissions_save' => 'Lagre tillatelser', - 'permissions_owner' => 'Owner', + 'permissions_owner' => 'Eier', // Search 'search_results' => 'Søkeresultater', @@ -210,7 +210,7 @@ return [ 'pages_revisions' => 'Sidens revisjoner', 'pages_revisions_named' => 'Revisjoner for :pageName', 'pages_revision_named' => 'Revisjoner for :pageName', - 'pages_revision_restored_from' => 'Restored from #:id; :summary', + 'pages_revision_restored_from' => 'Gjenopprettet fra #:id; :summary', 'pages_revisions_created_by' => 'Skrevet av', 'pages_revisions_date' => 'Revideringsdato', 'pages_revisions_number' => '#', diff --git a/resources/lang/nb/errors.php b/resources/lang/nb/errors.php index 4e5c07f65..35cee29a4 100644 --- a/resources/lang/nb/errors.php +++ b/resources/lang/nb/errors.php @@ -28,7 +28,7 @@ return [ 'social_account_in_use' => 'Denne :socialAccount kontoen er allerede registrert, Prøv å logge inn med :socialAccount alternativet.', 'social_account_email_in_use' => 'E-posten :email er allerede i bruk. Har du allerede en konto hos :socialAccount kan dette angis fra profilsiden din.', 'social_account_existing' => 'Denne :socialAccount er allerede koblet til din konto.', - 'social_account_already_used_existing' => 'This :socialAccount account is already used by another user.', + 'social_account_already_used_existing' => 'Denne :socialAccount kontoen brukes allerede av noen andre.', 'social_account_not_used' => 'Denne :socialAccount konten er ikke koblet til noen konto, angi denne i profilinnstillingene dine. ', 'social_account_register_instructions' => 'Har du ikke en konto her ennå, kan du benytte :socialAccount alternativet for å registrere deg.', 'social_driver_not_found' => 'Autentiseringstjeneste fra sosiale medier er ikke installert', diff --git a/resources/lang/nb/settings.php b/resources/lang/nb/settings.php index e952225dd..4bd35776d 100644 --- a/resources/lang/nb/settings.php +++ b/resources/lang/nb/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'Applikasjonens hjemmeside', 'app_homepage_desc' => 'Velg en visning som skal vises på hjemmesiden i stedet for standardvisningen. Sidetillatelser ignoreres for utvalgte sider.', 'app_homepage_select' => 'Velg en side', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', 'app_disable_comments' => 'Deaktiver kommentarer', 'app_disable_comments_toggle' => 'Deaktiver kommentarer', 'app_disable_comments_desc' => 'Deaktiver kommentarer på tvers av alle sidene i applikasjonen.
Eksisterende kommentarer vises ikke.', @@ -65,10 +70,10 @@ return [ 'reg_confirm_restrict_domain_placeholder' => 'Ingen begrensninger er satt', // Maintenance settings - 'maint' => 'Maintenance', + 'maint' => 'Vedlikehold', 'maint_image_cleanup' => 'Bildeopprydding', 'maint_image_cleanup_desc' => "Skanner side og revisjonsinnhold for å sjekke hvilke bilder og tegninger som for øyeblikket er i bruk, og hvilke bilder som er overflødige. Forsikre deg om at du lager en full database og sikkerhetskopiering av bilder før du kjører denne.", - 'maint_delete_images_only_in_revisions' => 'Also delete images that only exist in old page revisions', + 'maint_delete_images_only_in_revisions' => 'Slett også bilder som bare finnes i game siderevisjoner', 'maint_image_cleanup_run' => 'Kjør opprydding', 'maint_image_cleanup_warning' => ':count potensielt ubrukte bilder ble funnet. Er du sikker på at du vil slette disse bildene?', 'maint_image_cleanup_success' => ':count potensielt ubrukte bilder funnet og slettet!', @@ -80,27 +85,27 @@ return [ 'maint_send_test_email_mail_subject' => 'Test-e-post', 'maint_send_test_email_mail_greeting' => 'E-postsending ser ut til å fungere!', 'maint_send_test_email_mail_text' => 'Gratulerer! Da du mottok dette e-postvarselet, ser det ut til at e-postinnstillingene dine er konfigurert riktig.', - 'maint_recycle_bin_desc' => 'Deleted shelves, books, chapters & pages are sent to the recycle bin so they can be restored or permanently deleted. Older items in the recycle bin may be automatically removed after a while depending on system configuration.', - 'maint_recycle_bin_open' => 'Open Recycle Bin', + 'maint_recycle_bin_desc' => 'Slettede hyller, bøker, kapitler og sider kastes i papirkurven så de kan bli gjenopprettet eller slettet permanent. Eldre utgaver i papirkurven kan slettes automatisk etter en stund, avhengig av systemkonfigurasjonen.', + 'maint_recycle_bin_open' => 'Åpne papirkurven', // Recycle Bin - 'recycle_bin' => 'Recycle Bin', - 'recycle_bin_desc' => 'Here you can restore items that have been deleted or choose to permanently remove them from the system. This list is unfiltered unlike similar activity lists in the system where permission filters are applied.', - 'recycle_bin_deleted_item' => 'Deleted Item', - 'recycle_bin_deleted_by' => 'Deleted By', - 'recycle_bin_deleted_at' => 'Deletion Time', - 'recycle_bin_permanently_delete' => 'Permanently Delete', - 'recycle_bin_restore' => 'Restore', - 'recycle_bin_contents_empty' => 'The recycle bin is currently empty', - 'recycle_bin_empty' => 'Empty Recycle Bin', - 'recycle_bin_empty_confirm' => 'This will permanently destroy all items in the recycle bin including content contained within each item. Are you sure you want to empty the recycle bin?', - 'recycle_bin_destroy_confirm' => 'This action will permanently delete this item, along with any child elements listed below, from the system and you will not be able to restore this content. Are you sure you want to permanently delete this item?', - 'recycle_bin_destroy_list' => 'Items to be Destroyed', - 'recycle_bin_restore_list' => 'Items to be Restored', - 'recycle_bin_restore_confirm' => 'This action will restore the deleted item, including any child elements, to their original location. If the original location has since been deleted, and is now in the recycle bin, the parent item will also need to be restored.', - 'recycle_bin_restore_deleted_parent' => 'The parent of this item has also been deleted. These will remain deleted until that parent is also restored.', - 'recycle_bin_destroy_notification' => 'Deleted :count total items from the recycle bin.', - 'recycle_bin_restore_notification' => 'Restored :count total items from the recycle bin.', + 'recycle_bin' => 'Papirkurven', + 'recycle_bin_desc' => 'Her kan du gjenopprette ting du har kastet i papirkurven eller velge å slette dem permanent fra systemet. Denne listen er ikke filtrert i motsetning til lignende lister i systemet hvor tilgangskontroll overholdes.', + 'recycle_bin_deleted_item' => 'Kastet element', + 'recycle_bin_deleted_by' => 'Kastet av', + 'recycle_bin_deleted_at' => 'Kastet den', + 'recycle_bin_permanently_delete' => 'Slett permanent', + 'recycle_bin_restore' => 'Gjenopprett', + 'recycle_bin_contents_empty' => 'Papirkurven er for øyeblikket tom', + 'recycle_bin_empty' => 'Tøm papirkurven', + 'recycle_bin_empty_confirm' => 'Dette vil slette alle elementene i papirkurven permanent. Dette inkluderer innhold i hvert element. Er du sikker på at du vil tømme papirkurven?', + 'recycle_bin_destroy_confirm' => 'Denne handlingen vil permanent slette dette elementet og alle dets underelementer fra systemet, som beskrevet nedenfor. Du vil ikke kunne gjenopprette dette innholdet med mindre du har en tidligere sikkerhetskopi av databasen. Er du sikker på at du vil fortsette?', + 'recycle_bin_destroy_list' => 'Elementer som skal slettes', + 'recycle_bin_restore_list' => 'Elementer som skal gjenopprettes', + 'recycle_bin_restore_confirm' => 'Denne handlingen vil hente opp elementet fra papirkurven, inkludert underliggende innhold, til sin opprinnelige sted. Om den opprinnelige plassen har blitt slettet i mellomtiden og nå befinner seg i papirkurven, vil også dette bli hentet opp igjen.', + 'recycle_bin_restore_deleted_parent' => 'Det overordnede elementet var også kastet i papirkurven. Disse elementene vil forbli kastet inntil det overordnede også hentes opp igjen.', + 'recycle_bin_destroy_notification' => 'Slettet :count elementer fra papirkurven.', + 'recycle_bin_restore_notification' => 'Gjenopprettet :count elementer fra papirkurven.', // Audit Log 'audit' => 'Revisjonslogg', @@ -111,7 +116,7 @@ return [ 'audit_deleted_item_name' => 'Navn: :name', 'audit_table_user' => 'Kontoholder', 'audit_table_event' => 'Hendelse', - 'audit_table_related' => 'Related Item or Detail', + 'audit_table_related' => 'Relaterte elementer eller detaljer', 'audit_table_date' => 'Aktivitetsdato', 'audit_date_from' => 'Datoperiode fra', 'audit_date_to' => 'Datoperiode til', @@ -153,11 +158,11 @@ return [ 'role_users_none' => 'Ingen kontoholdere er gitt denne rollen', // Users - 'users' => 'Users', + 'users' => 'Brukere', 'user_profile' => 'Profil', 'users_add_new' => 'Register ny konto', 'users_search' => 'Søk i kontoer', - 'users_latest_activity' => 'Latest Activity', + 'users_latest_activity' => 'Siste aktivitet', 'users_details' => 'Kontodetaljer', 'users_details_desc' => 'Angi et visningsnavn og en e-postadresse for denne kontoholderen. E-postadressen vil bli brukt til å logge på applikasjonen.', 'users_details_desc_no_email' => 'Angi et visningsnavn for denne kontoholderen slik at andre kan gjenkjenne dem.', @@ -175,9 +180,9 @@ return [ 'users_delete_named' => 'Slett kontoen :userName', 'users_delete_warning' => 'Dette vil fullstendig slette denne brukeren med navnet «:userName» fra systemet.', 'users_delete_confirm' => 'Er du sikker på at du vil slette denne kontoen?', - 'users_migrate_ownership' => 'Migrate Ownership', - 'users_migrate_ownership_desc' => 'Select a user here if you want another user to become the owner of all items currently owned by this user.', - 'users_none_selected' => 'No user selected', + 'users_migrate_ownership' => 'Overfør eierskap', + 'users_migrate_ownership_desc' => 'Velg en bruker her, som du ønsker skal ta eierskap over alle elementene som er eid av denne brukeren.', + 'users_none_selected' => 'Ingen bruker valgt', 'users_delete_success' => 'Konto slettet', 'users_edit' => 'Rediger konto', 'users_edit_profile' => 'Rediger profil', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/nb/validation.php b/resources/lang/nb/validation.php index 87e6c7529..d06240c7c 100644 --- a/resources/lang/nb/validation.php +++ b/resources/lang/nb/validation.php @@ -78,7 +78,6 @@ return [ 'string' => ':attribute må være på minst :min tegn.', 'array' => ':attribute må minst ha :min ting.', ], - 'no_double_extension' => ':attribute kan bare ha en formattype spesifisert.', 'not_in' => 'Den valgte :attribute er ugyldig.', 'not_regex' => ':attribute format er ugyldig.', 'numeric' => ':attribute må være et nummer.', @@ -90,7 +89,7 @@ return [ 'required_without' => ':attribute feltet er påkrevt når :values ikke er tilgjengelig.', 'required_without_all' => ':attribute feltet er påkrevt når ingen av :values er tilgjengelig.', 'same' => ':attribute og :other må samsvare.', - 'safe_url' => 'The provided link may not be safe.', + 'safe_url' => 'Den angitte lenken kan være farlig.', 'size' => [ 'numeric' => ':attribute må være :size.', 'file' => ':attribute må være :size kilobytes.', diff --git a/resources/lang/nl/common.php b/resources/lang/nl/common.php index 7a2d633c6..b42680005 100644 --- a/resources/lang/nl/common.php +++ b/resources/lang/nl/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'Als je de knop ":actionText" niet werkt, kopieer en plak de onderstaande URL in je web browser:', 'email_rights' => 'Alle rechten voorbehouden', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privacy Policy', + 'terms_of_service' => 'Terms of Service', ]; diff --git a/resources/lang/nl/settings.php b/resources/lang/nl/settings.php index 12f3150a0..e5f7d0b53 100644 --- a/resources/lang/nl/settings.php +++ b/resources/lang/nl/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'Applicatie Homepagina', 'app_homepage_desc' => 'Selecteer een weergave om weer te geven op de homepage in plaats van de standaard weergave. Paginarechten worden genegeerd voor geselecteerde pagina\'s.', 'app_homepage_select' => 'Selecteer een pagina', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', 'app_disable_comments' => 'Reacties uitschakelen', 'app_disable_comments_toggle' => 'Opmerkingen uitschakelen', 'app_disable_comments_desc' => 'Schakel opmerkingen uit op alle pagina\'s in de applicatie. Bestaande opmerkingen worden niet getoond.', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/nl/validation.php b/resources/lang/nl/validation.php index 2f8ffc9f0..fa1691050 100644 --- a/resources/lang/nl/validation.php +++ b/resources/lang/nl/validation.php @@ -78,7 +78,6 @@ return [ 'string' => ':attribute moet minstens :min karakters bevatten.', 'array' => ':attribute moet minstens :min items bevatten.', ], - 'no_double_extension' => ':attribute mag maar een enkele bestandsextensie hebben.', 'not_in' => ':attribute is ongeldig.', 'not_regex' => ':attribute formaat is ongeldig.', 'numeric' => ':attribute moet een getal zijn.', diff --git a/resources/lang/pl/common.php b/resources/lang/pl/common.php index c93d0b9e1..7fe3f2ecd 100644 --- a/resources/lang/pl/common.php +++ b/resources/lang/pl/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'Jeśli masz problem z kliknięciem przycisku ":actionText", skopiuj i wklej poniższy adres URL w nowej karcie swojej przeglądarki:', 'email_rights' => 'Wszelkie prawa zastrzeżone', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privacy Policy', + 'terms_of_service' => 'Terms of Service', ]; diff --git a/resources/lang/pl/settings.php b/resources/lang/pl/settings.php index abba0ce60..3925f457b 100644 --- a/resources/lang/pl/settings.php +++ b/resources/lang/pl/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'Strona główna', 'app_homepage_desc' => 'Wybierz widok, który będzie wyświetlany na stronie głównej zamiast w widoku domyślnego. Uprawnienia dostępowe są ignorowane dla wybranych stron.', 'app_homepage_select' => 'Wybierz stronę', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', 'app_disable_comments' => 'Wyłącz komentarze', 'app_disable_comments_toggle' => 'Wyłącz komentowanie', 'app_disable_comments_desc' => 'Wyłącz komentarze na wszystkich stronach w aplikacji. Istniejące komentarze nie będą pokazywane.', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/pl/validation.php b/resources/lang/pl/validation.php index 26ac348c1..cc33dc878 100644 --- a/resources/lang/pl/validation.php +++ b/resources/lang/pl/validation.php @@ -78,7 +78,6 @@ return [ 'string' => 'Długość :attribute nie może być mniejsza niż :min znaków.', 'array' => 'Rozmiar :attribute musi posiadać co najmniej :min elementy.', ], - 'no_double_extension' => ':attribute może mieć tylko jedno rozszerzenie.', 'not_in' => 'Wartość :attribute jest nieprawidłowa.', 'not_regex' => 'Format :attribute jest nieprawidłowy.', 'numeric' => ':attribute musi być liczbą.', diff --git a/resources/lang/pt/activities.php b/resources/lang/pt/activities.php index 4cac54b2a..8a5d15e8f 100644 --- a/resources/lang/pt/activities.php +++ b/resources/lang/pt/activities.php @@ -6,43 +6,44 @@ return [ // Pages - 'page_create' => 'created page', - 'page_create_notification' => 'Page Successfully Created', - 'page_update' => 'updated page', - 'page_update_notification' => 'Page Successfully Updated', - 'page_delete' => 'deleted page', - 'page_delete_notification' => 'Page Successfully Deleted', - 'page_restore' => 'restored page', - 'page_restore_notification' => 'Page Successfully Restored', - 'page_move' => 'moved page', + 'page_create' => 'página criada', + 'page_create_notification' => 'Página criada com sucesso', + 'page_update' => 'página atualizada', + 'page_update_notification' => 'Página atualizada com sucesso', + 'page_delete' => 'página eliminada', + 'page_delete_notification' => 'Página eliminada com sucesso', + 'page_restore' => 'página restaurada', + 'page_restore_notification' => 'Página restaurada com sucesso', + 'page_move' => 'página movida', // Chapters - 'chapter_create' => 'created chapter', - 'chapter_create_notification' => 'Chapter Successfully Created', - 'chapter_update' => 'updated chapter', - 'chapter_update_notification' => 'Chapter Successfully Updated', - 'chapter_delete' => 'deleted chapter', - 'chapter_delete_notification' => 'Chapter Successfully Deleted', - 'chapter_move' => 'moved chapter', + 'chapter_create' => 'capítulo criado', + 'chapter_create_notification' => 'Capítulo criado com sucesso', + 'chapter_update' => 'capítulo atualizado', + 'chapter_update_notification' => 'Capítulo atualizado com sucesso', + 'chapter_delete' => 'capítulo excluído', + 'chapter_delete_notification' => 'Capítulo excluído com sucesso', + 'chapter_move' => 'capítulo movido', // Books - 'book_create' => 'created book', - 'book_create_notification' => 'Book Successfully Created', - 'book_update' => 'updated book', - 'book_update_notification' => 'Book Successfully Updated', - 'book_delete' => 'deleted book', - 'book_delete_notification' => 'Book Successfully Deleted', - 'book_sort' => 'sorted book', - 'book_sort_notification' => 'Book Successfully Re-sorted', + 'book_create' => 'livro criado', + 'book_create_notification' => 'Livro criado com sucesso', + 'book_update' => 'livro atualizado', + 'book_update_notification' => 'Livro atualizado com sucesso', + 'book_delete' => 'livro eliminado', + 'book_delete_notification' => 'Livro eliminado com sucesso', + 'book_sort' => 'livro ordenado', + 'book_sort_notification' => 'Livro reordenado com sucesso', // Bookshelves - 'bookshelf_create' => 'created Bookshelf', - 'bookshelf_create_notification' => 'Bookshelf Successfully Created', - 'bookshelf_update' => 'updated bookshelf', - 'bookshelf_update_notification' => 'Bookshelf Successfully Updated', - 'bookshelf_delete' => 'deleted bookshelf', - 'bookshelf_delete_notification' => 'Bookshelf Successfully Deleted', + 'bookshelf_create' => 'estante criada', + 'bookshelf_create_notification' => 'Estante criada com sucesso', + 'bookshelf_update' => 'estante atualizada', + 'bookshelf_update_notification' => 'Estante atualizada com sucesso', + 'bookshelf_delete' => 'excluiu a prateleira', + 'bookshelf_delete_notification' => 'Estante eliminada com sucesso', // Other - 'commented_on' => 'commented on', + 'commented_on' => 'comentado a', + 'permissions_update' => 'permissões atualizadas', ]; diff --git a/resources/lang/pt/auth.php b/resources/lang/pt/auth.php index d64fce93a..7d520a5f7 100644 --- a/resources/lang/pt/auth.php +++ b/resources/lang/pt/auth.php @@ -6,72 +6,72 @@ */ return [ - 'failed' => 'These credentials do not match our records.', - 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', + 'failed' => 'As credenciais fornecidas não correspondem aos nossos registos.', + 'throttle' => 'Demasiadas tentativas de início de sessão. Por favor, tente novamente em :seconds segundos.', // Login & Register - 'sign_up' => 'Sign up', - 'log_in' => 'Log in', - 'log_in_with' => 'Login with :socialDriver', - 'sign_up_with' => 'Sign up with :socialDriver', - 'logout' => 'Logout', + 'sign_up' => 'Criar conta', + 'log_in' => 'Iniciar sessão', + 'log_in_with' => 'Iniciar sessão com :socialDriver', + 'sign_up_with' => 'Criar conta com :socialDriver', + 'logout' => 'Terminar sessão', - 'name' => 'Name', - 'username' => 'Username', - 'email' => 'Email', - 'password' => 'Password', - 'password_confirm' => 'Confirm Password', - 'password_hint' => 'Must be over 7 characters', - 'forgot_password' => 'Forgot Password?', - 'remember_me' => 'Remember Me', - 'ldap_email_hint' => 'Please enter an email to use for this account.', - 'create_account' => 'Create Account', - 'already_have_account' => 'Already have an account?', - 'dont_have_account' => 'Don\'t have an account?', - 'social_login' => 'Social Login', - 'social_registration' => 'Social Registration', - 'social_registration_text' => 'Register and sign in using another service.', + 'name' => 'Nome', + 'username' => 'Nome de utilizador', + 'email' => 'E-mail', + 'password' => 'Palavra-passe', + 'password_confirm' => 'Confirmar Palavra-passe', + 'password_hint' => 'Deve ser maior que 7 caracteres', + 'forgot_password' => 'Esqueceu-se da palavra-passe?', + 'remember_me' => 'Lembrar-se de mim', + 'ldap_email_hint' => 'Por favor insira um endereço de e-mail para esta conta.', + 'create_account' => 'Criar Conta', + 'already_have_account' => 'Já possui uma conta?', + 'dont_have_account' => 'Não possui uma conta?', + 'social_login' => 'Inicio de Sessão com Redes Sociais', + 'social_registration' => 'Registo com Redes Sociais', + 'social_registration_text' => 'Registe e inicie sessão com recurso a outro serviço.', - 'register_thanks' => 'Thanks for registering!', - 'register_confirm' => 'Please check your email and click the confirmation button to access :appName.', - 'registrations_disabled' => 'Registrations are currently disabled', - 'registration_email_domain_invalid' => 'That email domain does not have access to this application', - 'register_success' => 'Thanks for signing up! You are now registered and signed in.', + 'register_thanks' => 'Obrigado por se registar!', + 'register_confirm' => 'Por favor, verifique o seu e-mail e carregue no botão de confirmação para aceder :appName.', + 'registrations_disabled' => 'Os registos estão temporariamente desativados', + 'registration_email_domain_invalid' => 'O domínio de e-mail usado não tem acesso permitido a esta aplicação', + 'register_success' => 'Obrigado por se registar! Você está agora registado e com a sessão iniciada.', // Password Reset - 'reset_password' => 'Reset Password', - 'reset_password_send_instructions' => 'Enter your email below and you will be sent an email with a password reset link.', - 'reset_password_send_button' => 'Send Reset Link', - 'reset_password_sent' => 'A password reset link will be sent to :email if that email address is found in the system.', - 'reset_password_success' => 'Your password has been successfully reset.', - 'email_reset_subject' => 'Reset your :appName password', - 'email_reset_text' => 'You are receiving this email because we received a password reset request for your account.', - 'email_reset_not_requested' => 'If you did not request a password reset, no further action is required.', + 'reset_password' => 'Redefinir Senha', + 'reset_password_send_instructions' => 'Insira o seu endereço de e-mail abaixo, e uma mensagem com o link de redefinição de palavra-passe será lhe enviada.', + 'reset_password_send_button' => 'Enviar o Link de Redefinição', + 'reset_password_sent' => 'Um link de redefinição de palavra-passe será enviado para :email, se o endereço de e-mail for encontrado no sistema.', + 'reset_password_success' => 'A sua palavra-passe foi redefinida com sucesso.', + 'email_reset_subject' => 'Redefina a sua palavra-passe de :appName', + 'email_reset_text' => 'Você recebeu este e-mail pois recebemos uma solicitação de redefinição de senha para a sua conta.', + 'email_reset_not_requested' => 'Caso não tenha sido você a solicitar a redefinição de senha, ignore este e-mail.', // Email Confirmation - 'email_confirm_subject' => 'Confirm your email on :appName', - 'email_confirm_greeting' => 'Thanks for joining :appName!', - 'email_confirm_text' => 'Please confirm your email address by clicking the button below:', - 'email_confirm_action' => 'Confirm Email', - 'email_confirm_send_error' => 'Email confirmation required but the system could not send the email. Contact the admin to ensure email is set up correctly.', - 'email_confirm_success' => 'Your email has been confirmed!', - 'email_confirm_resent' => 'Confirmation email resent, Please check your inbox.', + 'email_confirm_subject' => 'Confirme o seu endereço de e-mail para :appName', + 'email_confirm_greeting' => 'Obrigado por se registar em :appName!', + 'email_confirm_text' => 'Por favor, confirme o seu endereço de e-mail ao carregar no botão abaixo:', + 'email_confirm_action' => 'Confirmar E-mail', + 'email_confirm_send_error' => 'A confirmação do endereço de e-mail é requerida, mas o sistema não pôde enviar a mensagem. Por favor, entre em contacto com o administrador para se certificar que o serviço de envio de e-mails está corretamente configurado.', + 'email_confirm_success' => 'O seu endereço de e-mail foi confirmado!', + 'email_confirm_resent' => 'E-mail de confirmação reenviado. Por favor, verifique a sua caixa de entrada.', - 'email_not_confirmed' => 'Email Address Not Confirmed', - 'email_not_confirmed_text' => 'Your email address has not yet been confirmed.', - 'email_not_confirmed_click_link' => 'Please click the link in the email that was sent shortly after you registered.', - 'email_not_confirmed_resend' => 'If you cannot find the email you can re-send the confirmation email by submitting the form below.', - 'email_not_confirmed_resend_button' => 'Resend Confirmation Email', + 'email_not_confirmed' => 'Endereço de E-mail Não Confirmado', + 'email_not_confirmed_text' => 'O seu endereço de e-mail ainda não foi confirmado.', + 'email_not_confirmed_click_link' => 'Por favor, carregue no link que se encontra no e-mail que lhe foi enviado após o seu registo.', + 'email_not_confirmed_resend' => 'Caso não encontre o e-mail poderá reenviar a confirmação utilizando o formulário abaixo.', + 'email_not_confirmed_resend_button' => 'Reenviar o E-mail de Confirmação', // User Invite - 'user_invite_email_subject' => 'You have been invited to join :appName!', - 'user_invite_email_greeting' => 'An account has been created for you on :appName.', - 'user_invite_email_text' => 'Click the button below to set an account password and gain access:', - 'user_invite_email_action' => 'Set Account Password', - 'user_invite_page_welcome' => 'Welcome to :appName!', - 'user_invite_page_text' => 'To finalise your account and gain access you need to set a password which will be used to log-in to :appName on future visits.', - 'user_invite_page_confirm_button' => 'Confirm Password', - 'user_invite_success' => 'Password set, you now have access to :appName!' + 'user_invite_email_subject' => 'Você recebeu um convite para se juntar a :appName!', + 'user_invite_email_greeting' => 'Uma conta foi criada para si em :appName.', + 'user_invite_email_text' => 'Carregue no botão abaixo para definir uma palavra-passe de conta e obter acesso:', + 'user_invite_email_action' => 'Defina a Palavra-passe da Conta', + 'user_invite_page_welcome' => 'Bem-vindo(a) a :appName!', + 'user_invite_page_text' => 'Para finalizar a sua conta e obter acesso, precisa de definir uma senha que será utilizada para efetuar login em :appName em visitas futuras.', + 'user_invite_page_confirm_button' => 'Confirmar Palavra-Passe', + 'user_invite_success' => 'Palavra-passe definida, tem agora acesso a :appName!' ]; \ No newline at end of file diff --git a/resources/lang/pt/common.php b/resources/lang/pt/common.php index e87bd11a5..5e6197bd4 100644 --- a/resources/lang/pt/common.php +++ b/resources/lang/pt/common.php @@ -5,76 +5,81 @@ return [ // Buttons - 'cancel' => 'Cancel', - 'confirm' => 'Confirm', - 'back' => 'Back', - 'save' => 'Save', - 'continue' => 'Continue', - 'select' => 'Select', - 'toggle_all' => 'Toggle All', - 'more' => 'More', + 'cancel' => 'Cancelar', + 'confirm' => 'Confirmar', + 'back' => 'Voltar', + 'save' => 'Guardar', + 'continue' => 'Continuar', + 'select' => 'Selecionar', + 'toggle_all' => 'Alternar Todos', + 'more' => 'Mais', // Form Labels - 'name' => 'Name', - 'description' => 'Description', - 'role' => 'Role', - 'cover_image' => 'Cover image', - 'cover_image_description' => 'This image should be approx 440x250px.', + 'name' => 'Nome', + 'description' => 'Descrição', + 'role' => 'Cargo', + 'cover_image' => 'Imagem de capa', + 'cover_image_description' => 'Esta imagem deve ser aproximadamente 440x250px.', // Actions - 'actions' => 'Actions', - 'view' => 'View', - 'view_all' => 'View All', - 'create' => 'Create', - 'update' => 'Update', - 'edit' => 'Edit', - 'sort' => 'Sort', - 'move' => 'Move', - 'copy' => 'Copy', - 'reply' => 'Reply', - 'delete' => 'Delete', - 'delete_confirm' => 'Confirm Deletion', - 'search' => 'Search', - 'search_clear' => 'Clear Search', - 'reset' => 'Reset', - 'remove' => 'Remove', - 'add' => 'Add', - 'fullscreen' => 'Fullscreen', + 'actions' => 'Ações', + 'view' => 'Visualizar', + 'view_all' => 'Visualizar Todos', + 'create' => 'Criar', + 'update' => 'Atualizar', + 'edit' => 'Editar', + 'sort' => 'Ordenar', + 'move' => 'Mover', + 'copy' => 'Copiar', + 'reply' => 'Responder', + 'delete' => 'Eliminar', + 'delete_confirm' => 'Confirmar eliminação', + 'search' => 'Pesquisar', + 'search_clear' => 'Limpar Pesquisa', + 'reset' => 'Redefinir', + 'remove' => 'Remover', + 'add' => 'Adicionar', + 'fullscreen' => 'Ecrã completo', // Sort Options - 'sort_options' => 'Sort Options', - 'sort_direction_toggle' => 'Sort Direction Toggle', - 'sort_ascending' => 'Sort Ascending', - 'sort_descending' => 'Sort Descending', - 'sort_name' => 'Name', - 'sort_created_at' => 'Created Date', - 'sort_updated_at' => 'Updated Date', + 'sort_options' => 'Opções de Ordenação', + 'sort_direction_toggle' => 'Alternar Direção de Ordenação', + 'sort_ascending' => 'Ordenação Crescente', + 'sort_descending' => 'Ordenação Decrescente', + 'sort_name' => 'Nome', + 'sort_created_at' => 'Data de Criação', + 'sort_updated_at' => 'Data de Atualização', // Misc - 'deleted_user' => 'Deleted User', - 'no_activity' => 'No activity to show', - 'no_items' => 'No items available', - 'back_to_top' => 'Back to top', - 'toggle_details' => 'Toggle Details', - 'toggle_thumbnails' => 'Toggle Thumbnails', - 'details' => 'Details', - 'grid_view' => 'Grid View', - 'list_view' => 'List View', - 'default' => 'Default', - 'breadcrumb' => 'Breadcrumb', + 'deleted_user' => 'Utilizador Eliminado', + 'no_activity' => 'Nenhuma atividade a mostrar', + 'no_items' => 'Nenhum item disponível', + 'back_to_top' => 'Voltar ao topo', + 'toggle_details' => 'Alternar Detalhes', + 'toggle_thumbnails' => 'Alternar Miniaturas', + 'details' => 'Detalhes', + 'grid_view' => 'Visualização em Grade', + 'list_view' => 'Visualização em Lista', + 'default' => 'Padrão', + 'breadcrumb' => 'Caminho', // Header - 'profile_menu' => 'Profile Menu', - 'view_profile' => 'View Profile', - 'edit_profile' => 'Edit Profile', - 'dark_mode' => 'Dark Mode', - 'light_mode' => 'Light Mode', + 'profile_menu' => 'Menu de Perfil', + 'view_profile' => 'Visualizar Perfil', + 'edit_profile' => 'Editar Perfil', + 'dark_mode' => 'Modo Escuro', + 'light_mode' => 'Modo Claro', // Layout tabs - 'tab_info' => 'Info', - 'tab_content' => 'Content', + 'tab_info' => 'Informações', + 'tab_content' => 'Conteúdo', // Email Content - 'email_action_help' => 'If you’re having trouble clicking the ":actionText" button, copy and paste the URL below into your web browser:', - 'email_rights' => 'All rights reserved', + 'email_action_help' => 'Se estiver com problemas ao carregar no botão ":actionText", copie e cole o URL abaixo no seu navegador:', + 'email_rights' => 'Todos os direitos reservados', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Política de Privacidade', + 'terms_of_service' => 'Termos de Utilização', ]; diff --git a/resources/lang/pt/components.php b/resources/lang/pt/components.php index 48a0a32fa..bdec20226 100644 --- a/resources/lang/pt/components.php +++ b/resources/lang/pt/components.php @@ -5,30 +5,30 @@ return [ // Image Manager - 'image_select' => 'Image Select', - 'image_all' => 'All', - 'image_all_title' => 'View all images', - 'image_book_title' => 'View images uploaded to this book', - 'image_page_title' => 'View images uploaded to this page', - 'image_search_hint' => 'Search by image name', - 'image_uploaded' => 'Uploaded :uploadedDate', - 'image_load_more' => 'Load More', - 'image_image_name' => 'Image Name', - 'image_delete_used' => 'This image is used in the pages below.', - 'image_delete_confirm_text' => 'Are you sure you want to delete this image?', - 'image_select_image' => 'Select Image', - 'image_dropzone' => 'Drop images or click here to upload', - 'images_deleted' => 'Images Deleted', - 'image_preview' => 'Image Preview', - 'image_upload_success' => 'Image uploaded successfully', - 'image_update_success' => 'Image details successfully updated', - 'image_delete_success' => 'Image successfully deleted', - 'image_upload_remove' => 'Remove', + 'image_select' => 'Selecionar Imagem', + 'image_all' => 'Todas', + 'image_all_title' => 'Visualizar todas as imagens', + 'image_book_title' => 'Visualizar imagens relacionadas a este livro', + 'image_page_title' => 'Visualizar imagens relacionadas a esta página', + 'image_search_hint' => 'Pesquisar imagem por nome', + 'image_uploaded' => 'Adicionada em :uploadedDate', + 'image_load_more' => 'Carregar Mais', + 'image_image_name' => 'Nome da Imagem', + 'image_delete_used' => 'Esta imagem é utilizada nas páginas abaixo.', + 'image_delete_confirm_text' => 'Tem certeza de que deseja eliminar esta imagem?', + 'image_select_image' => 'Selecionar Imagem', + 'image_dropzone' => 'Arraste imagens ou carregue aqui para fazer upload', + 'images_deleted' => 'Imagens Eliminadas', + 'image_preview' => 'Pré-visualização de Imagem', + 'image_upload_success' => 'Carregamento da imagem efetuado com sucesso', + 'image_update_success' => 'Detalhes da imagem atualizados com sucesso', + 'image_delete_success' => 'Imagem eliminada com sucesso', + 'image_upload_remove' => 'Remover', // Code Editor - 'code_editor' => 'Edit Code', - 'code_language' => 'Code Language', - 'code_content' => 'Code Content', - 'code_session_history' => 'Session History', - 'code_save' => 'Save Code', + 'code_editor' => 'Editar Código', + 'code_language' => 'Linguagem do Código', + 'code_content' => 'Código', + 'code_session_history' => 'Histórico de Sessão', + 'code_save' => 'Guardar Código', ]; diff --git a/resources/lang/pt/entities.php b/resources/lang/pt/entities.php index f64867a56..e141a3603 100644 --- a/resources/lang/pt/entities.php +++ b/resources/lang/pt/entities.php @@ -6,311 +6,314 @@ return [ // Shared - 'recently_created' => 'Recently Created', - 'recently_created_pages' => 'Recently Created Pages', - 'recently_updated_pages' => 'Recently Updated Pages', - 'recently_created_chapters' => 'Recently Created Chapters', - 'recently_created_books' => 'Recently Created Books', - 'recently_created_shelves' => 'Recently Created Shelves', - 'recently_update' => 'Recently Updated', - 'recently_viewed' => 'Recently Viewed', - 'recent_activity' => 'Recent Activity', - 'create_now' => 'Create one now', - 'revisions' => 'Revisions', - 'meta_revision' => 'Revision #:revisionCount', - 'meta_created' => 'Created :timeLength', - 'meta_created_name' => 'Created :timeLength by :user', - 'meta_updated' => 'Updated :timeLength', - 'meta_updated_name' => 'Updated :timeLength by :user', - 'entity_select' => 'Entity Select', - 'images' => 'Images', - 'my_recent_drafts' => 'My Recent Drafts', - 'my_recently_viewed' => 'My Recently Viewed', - 'no_pages_viewed' => 'You have not viewed any pages', - 'no_pages_recently_created' => 'No pages have been recently created', - 'no_pages_recently_updated' => 'No pages have been recently updated', - 'export' => 'Export', - 'export_html' => 'Contained Web File', - 'export_pdf' => 'PDF File', - 'export_text' => 'Plain Text File', + 'recently_created' => 'Criado recentemente', + 'recently_created_pages' => 'Páginas Criadas Recentemente', + 'recently_updated_pages' => 'Páginas Atualizadas Recentemente', + 'recently_created_chapters' => 'Capítulos Criados Recentemente', + 'recently_created_books' => 'Livros Criados Recentemente', + 'recently_created_shelves' => 'Estantes Criadas Recentemente', + 'recently_update' => 'Atualizados Recentemente', + 'recently_viewed' => 'Visualizados Recentemente', + 'recent_activity' => 'Atividade Recente', + 'create_now' => 'Criar um agora', + 'revisions' => 'Revisões', + 'meta_revision' => 'Revisão #:revisionCount', + 'meta_created' => 'Criado :timeLength', + 'meta_created_name' => 'Criado :timeLength por :user', + 'meta_updated' => 'Atualizado :timeLength', + 'meta_updated_name' => 'Atualizado :timeLength por :user', + 'meta_owned_name' => 'Propriedade de :user', + 'entity_select' => 'Seleção de Entidade', + 'images' => 'Imagens', + 'my_recent_drafts' => 'Os Meus Rascunhos Recentes', + 'my_recently_viewed' => 'Visualizados Recentemente Por Mim', + 'no_pages_viewed' => 'Você não viu nenhuma página', + 'no_pages_recently_created' => 'Nenhuma página foi recentemente criada', + 'no_pages_recently_updated' => 'Nenhuma página foi recentemente atualizada', + 'export' => 'Exportar', + 'export_html' => 'Arquivo Web contido', + 'export_pdf' => 'Arquivo PDF', + 'export_text' => 'Arquivo Texto', // 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_save' => 'Save Permissions', + '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_save' => 'Guardar Permissões', + 'permissions_owner' => 'Proprietário', // Search - 'search_results' => 'Search Results', - 'search_total_results_found' => ':count result found|:count total results found', - 'search_clear' => 'Clear Search', - 'search_no_pages' => 'No pages matched this search', - 'search_for_term' => 'Search for :term', - 'search_more' => 'More Results', - 'search_advanced' => 'Advanced Search', - 'search_terms' => 'Search Terms', - 'search_content_type' => 'Content Type', - 'search_exact_matches' => 'Exact Matches', - 'search_tags' => 'Tag Searches', - 'search_options' => 'Options', - 'search_viewed_by_me' => 'Viewed by me', - 'search_not_viewed_by_me' => 'Not viewed by me', - 'search_permissions_set' => 'Permissions set', - 'search_created_by_me' => 'Created by me', - 'search_updated_by_me' => 'Updated by me', - 'search_date_options' => 'Date Options', - 'search_updated_before' => 'Updated before', - 'search_updated_after' => 'Updated after', - 'search_created_before' => 'Created before', - 'search_created_after' => 'Created after', - 'search_set_date' => 'Set Date', - 'search_update' => 'Update Search', + 'search_results' => 'Resultado(s) da Pesquisa', + 'search_total_results_found' => ':count resultado encontrado|:count resultados encontrados', + 'search_clear' => 'Limpar Pesquisa', + 'search_no_pages' => 'Nenhuma página corresponde à pesquisa', + 'search_for_term' => 'Pesquisar por :term', + 'search_more' => 'Mais Resultados', + 'search_advanced' => 'Pesquisa Avançada', + 'search_terms' => 'Termos da Pesquisa', + 'search_content_type' => 'Tipo de Conteúdo', + 'search_exact_matches' => 'Correspondências Exatas', + 'search_tags' => 'Persquisar Tags', + 'search_options' => 'Opções', + 'search_viewed_by_me' => 'Visualizado por mim', + 'search_not_viewed_by_me' => 'Não visualizado por mim', + 'search_permissions_set' => 'Permissão definida', + 'search_created_by_me' => 'Criado por mim', + 'search_updated_by_me' => 'Atualizado por mim', + 'search_date_options' => 'Opções de Data', + 'search_updated_before' => 'Atualizado antes de', + 'search_updated_after' => 'Atualizado depois de', + 'search_created_before' => 'Criado antes de', + 'search_created_after' => 'Criado depois de', + 'search_set_date' => 'Definir Data', + 'search_update' => 'Atualizar pesquisa', // Shelves - 'shelf' => 'Shelf', - 'shelves' => 'Shelves', - 'x_shelves' => ':count Shelf|:count Shelves', - 'shelves_long' => 'Bookshelves', - 'shelves_empty' => 'No shelves have been created', - 'shelves_create' => 'Create New Shelf', - 'shelves_popular' => 'Popular Shelves', - 'shelves_new' => 'New Shelves', - 'shelves_new_action' => 'New Shelf', - 'shelves_popular_empty' => 'The most popular shelves will appear here.', - 'shelves_new_empty' => 'The most recently created shelves will appear here.', - 'shelves_save' => 'Save Shelf', - 'shelves_books' => 'Books on this shelf', - 'shelves_add_books' => 'Add books to this shelf', - 'shelves_drag_books' => 'Drag books here to add them to this shelf', - 'shelves_empty_contents' => 'This shelf has no books assigned to it', - 'shelves_edit_and_assign' => 'Edit shelf to assign books', - 'shelves_edit_named' => 'Edit Bookshelf :name', - 'shelves_edit' => 'Edit Bookshelf', - 'shelves_delete' => 'Delete Bookshelf', - '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_copy_permissions_to_books' => 'Copy Permissions to Books', - 'shelves_copy_permissions' => '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', + 'shelf' => 'Estante', + 'shelves' => 'Estantes', + 'x_shelves' => ':count Estante|:count Estantes', + 'shelves_long' => 'Estantes de Livros', + 'shelves_empty' => 'Nenhuma estante foi criada', + 'shelves_create' => 'Criar Nova Estante', + 'shelves_popular' => 'Estantes Populares', + 'shelves_new' => 'Estantes Novas', + 'shelves_new_action' => 'Nova Estante', + 'shelves_popular_empty' => 'As estantes mais populares serão mostradas aqui.', + 'shelves_new_empty' => 'As mais recentes estantes criadas serão mostradas aqui.', + 'shelves_save' => 'Guardar Estante', + 'shelves_books' => 'Livros nesta estante', + 'shelves_add_books' => 'Adicionar livros a esta estante', + 'shelves_drag_books' => 'Arraste livros aqui para adicioná-los a esta estante', + 'shelves_empty_contents' => 'Esta estante não tem livros atribuídos', + 'shelves_edit_and_assign' => 'Editar estante para atribuir livros', + 'shelves_edit_named' => 'Editar Estante de Livros :name', + 'shelves_edit' => 'Editar Estante de Livros', + 'shelves_delete' => 'Eliminar Estante de Livros', + 'shelves_delete_named' => 'Excluir Prateleira de Livros :name', + 'shelves_delete_explain' => "A ação vai eliminar a estante de nome ':name'. Os livros nela presentes não serão eliminados.", + 'shelves_delete_confirmation' => 'Tem a certeza que quer eliminar esta estante de livros?', + 'shelves_permissions' => 'Permissões da Estante', + 'shelves_permissions_updated' => 'Permissões da Estante de Livros Atualizada', + 'shelves_permissions_active' => 'Permissões da Estante de Livros Ativas', + 'shelves_copy_permissions_to_books' => 'Copiar Permissões para Livros', + 'shelves_copy_permissions' => 'Copiar Permissões', + 'shelves_copy_permissions_explain' => 'Isto aplicará as configurações de permissões atuais desta estante a todos os livros nela contidos. Antes de ativar, assegure-se de que quaisquer alterações nas permissões desta estante foram guardadas.', + 'shelves_copy_permission_success' => 'Permissões de estante copiadas para :count livros', // Books - 'book' => 'Book', - 'books' => 'Books', - 'x_books' => ':count Book|:count Books', - 'books_empty' => 'No books have been created', - 'books_popular' => 'Popular Books', - 'books_recent' => 'Recent Books', - 'books_new' => 'New Books', - 'books_new_action' => 'New Book', - 'books_popular_empty' => 'The most popular books will appear here.', - 'books_new_empty' => 'The most recently created books will appear here.', - 'books_create' => 'Create New Book', - 'books_delete' => 'Delete Book', - 'books_delete_named' => 'Delete Book :bookName', - 'books_delete_explain' => 'This will delete the book with the name \':bookName\'. All pages and chapters will be removed.', - 'books_delete_confirmation' => 'Are you sure you want to delete this book?', - 'books_edit' => 'Edit Book', - 'books_edit_named' => 'Edit Book :bookName', - 'books_form_book_name' => 'Book Name', - 'books_save' => 'Save Book', - 'books_permissions' => 'Book Permissions', - 'books_permissions_updated' => 'Book Permissions Updated', - 'books_empty_contents' => 'No pages or chapters have been created for this book.', - 'books_empty_create_page' => 'Create a new page', - 'books_empty_sort_current_book' => 'Sort the current book', - 'books_empty_add_chapter' => 'Add a chapter', - 'books_permissions_active' => 'Book Permissions Active', - 'books_search_this' => 'Search this book', - 'books_navigation' => 'Book Navigation', - 'books_sort' => 'Sort Book Contents', - 'books_sort_named' => 'Sort Book :bookName', - 'books_sort_name' => 'Sort by Name', - 'books_sort_created' => 'Sort by Created Date', - 'books_sort_updated' => 'Sort by Updated Date', - 'books_sort_chapters_first' => 'Chapters First', - 'books_sort_chapters_last' => 'Chapters Last', - 'books_sort_show_other' => 'Show Other Books', - 'books_sort_save' => 'Save New Order', + 'book' => 'Livro', + 'books' => 'Livros', + 'x_books' => ':count Livro|:count Livros', + 'books_empty' => 'Nenhum livro foi criado', + 'books_popular' => 'Livros Populares', + 'books_recent' => 'Livros Recentes', + 'books_new' => 'Livros Novos', + 'books_new_action' => 'Novo Livro', + 'books_popular_empty' => 'Os livros mais populares serão mostrados aqui.', + 'books_new_empty' => 'Os livros mais recentemente criados serão mostrados aqui.', + 'books_create' => 'Criar Livro Novo', + 'books_delete' => 'Eliminar Livro', + 'books_delete_named' => 'Eliminar Livro :bookName', + 'books_delete_explain' => 'A ação vai eliminar o livro com de nome \':bookName\'. Todas as páginas e capítulos serão também removidos.', + 'books_delete_confirmation' => 'Tem a certeza que quer eliminar este livro?', + 'books_edit' => 'Editar Livro', + 'books_edit_named' => 'Editar Livro :bookName', + 'books_form_book_name' => 'Nome do Livro', + 'books_save' => 'Guardar Livro', + 'books_permissions' => 'Permissões do Livro', + 'books_permissions_updated' => 'Permissões do Livro Atualizadas', + 'books_empty_contents' => 'Nenhuma página ou capítulo foram criados para este livro.', + 'books_empty_create_page' => 'Criar uma nova página', + 'books_empty_sort_current_book' => 'Ordenar o livro atual', + 'books_empty_add_chapter' => 'Adicionar um capítulo', + 'books_permissions_active' => 'Permissões do Livro Ativas', + 'books_search_this' => 'Pesquisar neste livro', + 'books_navigation' => 'Navegação do Livro', + 'books_sort' => 'Ordenar Conteúdos do Livro', + 'books_sort_named' => 'Ordenar Livro :bookName', + 'books_sort_name' => 'Ordenar por Nome', + 'books_sort_created' => 'Ordenar por Data de Criação', + 'books_sort_updated' => 'Ordenar por Data de Atualização', + 'books_sort_chapters_first' => 'Capítulos Primeiro', + 'books_sort_chapters_last' => 'Capítulos por Último', + 'books_sort_show_other' => 'Mostrar Outros Livros', + 'books_sort_save' => 'Guardar Nova Ordenação', // Chapters - 'chapter' => 'Chapter', - 'chapters' => 'Chapters', - 'x_chapters' => ':count Chapter|:count Chapters', - 'chapters_popular' => 'Popular Chapters', - 'chapters_new' => 'New Chapter', - 'chapters_create' => 'Create New Chapter', - 'chapters_delete' => 'Delete Chapter', - 'chapters_delete_named' => 'Delete Chapter :chapterName', - 'chapters_delete_explain' => 'This will delete the chapter with the name \':chapterName\'. All pages will be removed and added directly to the parent book.', - 'chapters_delete_confirm' => 'Are you sure you want to delete this chapter?', - 'chapters_edit' => 'Edit Chapter', - 'chapters_edit_named' => 'Edit Chapter :chapterName', - 'chapters_save' => 'Save Chapter', - 'chapters_move' => 'Move Chapter', - 'chapters_move_named' => 'Move Chapter :chapterName', - 'chapter_move_success' => 'Chapter moved to :bookName', - 'chapters_permissions' => 'Chapter Permissions', - 'chapters_empty' => 'No pages are currently in this chapter.', - 'chapters_permissions_active' => 'Chapter Permissions Active', - 'chapters_permissions_success' => 'Chapter Permissions Updated', - 'chapters_search_this' => 'Search this chapter', + 'chapter' => 'Capítulo', + 'chapters' => 'Capítulos', + 'x_chapters' => ':count Capítulo|:count Capítulos', + 'chapters_popular' => 'Capítulos Populares', + 'chapters_new' => 'Novo Capítulo', + 'chapters_create' => 'Criar Novo Capítulo', + 'chapters_delete' => 'Eliminar Capítulo', + 'chapters_delete_named' => 'Eliminar Capítulo :chapterName', + 'chapters_delete_explain' => 'Isto irá eliminar o capítulo com o nome \':chapterName\'. Todas as páginas existentes dentro do mesmo serão também eliminadas.', + 'chapters_delete_confirm' => 'Tem certeza que deseja eliminar o capítulo?', + 'chapters_edit' => 'Editar Capítulo', + 'chapters_edit_named' => 'Editar Capítulo :chapterName', + 'chapters_save' => 'Guardar Capítulo', + 'chapters_move' => 'Mover Capítulo', + 'chapters_move_named' => 'Mover Capítulo :chapterName', + 'chapter_move_success' => 'Capítulo movido para :bookName', + 'chapters_permissions' => 'Permissões do Capítulo', + 'chapters_empty' => 'Nenhuma página existente neste capítulo.', + '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', // Pages - 'page' => 'Page', - 'pages' => 'Pages', - 'x_pages' => ':count Page|:count Pages', - 'pages_popular' => 'Popular Pages', - 'pages_new' => 'New Page', - 'pages_attachments' => 'Attachments', - 'pages_navigation' => 'Page Navigation', - 'pages_delete' => 'Delete Page', - 'pages_delete_named' => 'Delete Page :pageName', - 'pages_delete_draft_named' => 'Delete Draft Page :pageName', - 'pages_delete_draft' => 'Delete Draft Page', - 'pages_delete_success' => 'Page deleted', - 'pages_delete_draft_success' => 'Draft page deleted', - 'pages_delete_confirm' => 'Are you sure you want to delete this page?', - 'pages_delete_draft_confirm' => 'Are you sure you want to delete this draft page?', - 'pages_editing_named' => 'Editing Page :pageName', - 'pages_edit_draft_options' => 'Draft Options', - 'pages_edit_save_draft' => 'Save Draft', - 'pages_edit_draft' => 'Edit Page Draft', - 'pages_editing_draft' => 'Editing Draft', - 'pages_editing_page' => 'Editing Page', - 'pages_edit_draft_save_at' => 'Draft saved at ', - 'pages_edit_delete_draft' => 'Delete Draft', - 'pages_edit_discard_draft' => 'Discard Draft', - 'pages_edit_set_changelog' => 'Set Changelog', - 'pages_edit_enter_changelog_desc' => 'Enter a brief description of the changes you\'ve made', - 'pages_edit_enter_changelog' => 'Enter Changelog', - 'pages_save' => 'Save Page', - 'pages_title' => 'Page Title', - 'pages_name' => 'Page Name', + 'page' => 'Página', + 'pages' => 'Páginas', + 'x_pages' => ':count Página|:count Páginas', + 'pages_popular' => 'Páginas Populares', + 'pages_new' => 'Nova Página', + 'pages_attachments' => 'Anexos', + 'pages_navigation' => 'Navegação da Página', + 'pages_delete' => 'Eliminar Página', + 'pages_delete_named' => 'Eliminar Página :pageName', + 'pages_delete_draft_named' => 'Eliminar Rascunho de Página de nome :pageName', + 'pages_delete_draft' => 'Eliminar Rascunho de Página', + 'pages_delete_success' => 'Página eliminada', + 'pages_delete_draft_success' => 'Rascunho de página eliminado', + 'pages_delete_confirm' => 'Tem certeza que deseja eliminar a página?', + 'pages_delete_draft_confirm' => 'Tem certeza que deseja eliminar o rascunho de página?', + 'pages_editing_named' => 'A Editar a Página :pageName', + 'pages_edit_draft_options' => 'Opções de Rascunho', + 'pages_edit_save_draft' => 'Guardar Rascunho', + 'pages_edit_draft' => 'Editar Rascunho de Página', + 'pages_editing_draft' => 'A Editar Rascunho', + 'pages_editing_page' => 'A Editar Página', + 'pages_edit_draft_save_at' => 'Rascunho guardado em ', + 'pages_edit_delete_draft' => 'Eliminar Rascunho', + 'pages_edit_discard_draft' => 'Descartar Rascunho', + 'pages_edit_set_changelog' => 'Relatar Alterações', + 'pages_edit_enter_changelog_desc' => 'Digite uma breve descrição das alterações efetuadas por si', + 'pages_edit_enter_changelog' => 'Inserir Alterações', + 'pages_save' => 'Guardar Página', + 'pages_title' => 'Título da Página', + 'pages_name' => 'Nome da Página', 'pages_md_editor' => 'Editor', - 'pages_md_preview' => 'Preview', - 'pages_md_insert_image' => 'Insert Image', - 'pages_md_insert_link' => 'Insert Entity Link', - 'pages_md_insert_drawing' => 'Insert Drawing', - 'pages_not_in_chapter' => 'Page is not in a chapter', - 'pages_move' => 'Move Page', - 'pages_move_success' => 'Page moved to ":parentName"', - 'pages_copy' => 'Copy Page', - 'pages_copy_desination' => 'Copy Destination', - 'pages_copy_success' => 'Page successfully copied', - 'pages_permissions' => 'Page Permissions', - 'pages_permissions_success' => 'Page permissions updated', - 'pages_revision' => 'Revision', - 'pages_revisions' => 'Page Revisions', - 'pages_revisions_named' => 'Page Revisions for :pageName', - 'pages_revision_named' => 'Page Revision for :pageName', - 'pages_revisions_created_by' => 'Created By', - 'pages_revisions_date' => 'Revision Date', + 'pages_md_preview' => 'Pré-Visualização', + 'pages_md_insert_image' => 'Inserir Imagem', + 'pages_md_insert_link' => 'Inserir Link para Entidade', + 'pages_md_insert_drawing' => 'Inserir Desenho', + 'pages_not_in_chapter' => 'A página não está dentro de um capítulo', + 'pages_move' => 'Mover Página', + 'pages_move_success' => 'Pagina movida para ":parentName"', + 'pages_copy' => 'Copiar Página', + 'pages_copy_desination' => 'Destino da Cópia', + 'pages_copy_success' => 'Página copiada com sucesso', + 'pages_permissions' => 'Permissões da Página', + 'pages_permissions_success' => 'Permissões da Página atualizadas', + 'pages_revision' => 'Revisão', + 'pages_revisions' => 'Revisões da Página', + 'pages_revisions_named' => 'Revisões de Página para :pageName', + 'pages_revision_named' => 'Revisão de Página para :pageName', + 'pages_revision_restored_from' => 'Recuperado de #:id; :summary', + 'pages_revisions_created_by' => 'Criado por', + 'pages_revisions_date' => 'Data da Revisão', 'pages_revisions_number' => '#', - 'pages_revisions_numbered' => 'Revision #:id', - 'pages_revisions_numbered_changes' => 'Revision #:id Changes', - 'pages_revisions_changelog' => 'Changelog', - 'pages_revisions_changes' => 'Changes', - 'pages_revisions_current' => 'Current Version', - 'pages_revisions_preview' => 'Preview', - 'pages_revisions_restore' => 'Restore', - 'pages_revisions_none' => 'This page has no revisions', - 'pages_copy_link' => 'Copy Link', - 'pages_edit_content_link' => 'Edit Content', - 'pages_permissions_active' => 'Page Permissions Active', - 'pages_initial_revision' => 'Initial publish', - 'pages_initial_name' => 'New Page', - 'pages_editing_draft_notification' => 'You are currently editing a draft that was last saved :timeDiff.', - 'pages_draft_edited_notification' => 'This page has been updated by since that time. It is recommended that you discard this draft.', + 'pages_revisions_numbered' => 'Revisão #:id', + 'pages_revisions_numbered_changes' => 'Alterações da Revisão #:id', + 'pages_revisions_changelog' => 'Relatório de Alterações', + 'pages_revisions_changes' => 'Alterações', + 'pages_revisions_current' => 'Versão Atual', + 'pages_revisions_preview' => 'Pré-Visualização', + 'pages_revisions_restore' => 'Restaurar', + 'pages_revisions_none' => 'Essa página não tem revisões', + 'pages_copy_link' => 'Copiar Link', + 'pages_edit_content_link' => 'Editar Conteúdo', + 'pages_permissions_active' => 'Permissões de Página Ativas', + 'pages_initial_revision' => 'Publicação Inicial', + 'pages_initial_name' => 'Nova Página', + 'pages_editing_draft_notification' => 'Você está atualmente a editar um rascunho que foi guardado pela última vez a :timeDiff.', + 'pages_draft_edited_notification' => 'Esta página entretanto já foi atualizada. É recomendado que você descarte este rascunho.', 'pages_draft_edit_active' => [ - 'start_a' => ':count users have started editing this page', - 'start_b' => ':userName has started editing this page', - 'time_a' => 'since the page was last updated', - 'time_b' => 'in the last :minCount minutes', - 'message' => ':start :time. Take care not to overwrite each other\'s updates!', + 'start_a' => ':count usuários iniciaram a edição dessa página', + 'start_b' => ':userName iniciou a edição desta página', + 'time_a' => 'desde que a página foi atualizada pela última vez', + 'time_b' => 'nos últimos :minCount minutos', + 'message' => ':start :time. Tenha cuidado para não sobrescrever atualizações de outras pessoas!', ], - 'pages_draft_discarded' => 'Draft discarded, The editor has been updated with the current page content', - 'pages_specific' => 'Specific Page', - 'pages_is_template' => 'Page Template', + 'pages_draft_discarded' => 'Rascunho descartado. O editor foi atualizado com o conteúdo atual da página', + 'pages_specific' => 'Página Específica', + 'pages_is_template' => 'Modelo de Página', // Editor Sidebar - 'page_tags' => 'Page Tags', - 'chapter_tags' => 'Chapter Tags', - 'book_tags' => 'Book Tags', - 'shelf_tags' => 'Shelf Tags', - 'tag' => 'Tag', - 'tags' => 'Tags', - 'tag_name' => 'Tag Name', - 'tag_value' => 'Tag Value (Optional)', - 'tags_explain' => "Add some tags to better categorise your content. \n You can assign a value to a tag for more in-depth organisation.", - 'tags_add' => 'Add another tag', - 'tags_remove' => 'Remove this tag', - 'attachments' => 'Attachments', - 'attachments_explain' => 'Upload some files or attach some links to display on your page. These are visible in the page sidebar.', - 'attachments_explain_instant_save' => 'Changes here are saved instantly.', - 'attachments_items' => 'Attached Items', - 'attachments_upload' => 'Upload File', - 'attachments_link' => 'Attach Link', - 'attachments_set_link' => 'Set Link', - 'attachments_delete' => 'Are you sure you want to delete this attachment?', - 'attachments_dropzone' => 'Drop files or click here to attach a file', - 'attachments_no_files' => 'No files have been uploaded', - 'attachments_explain_link' => 'You can attach a link if you\'d prefer not to upload a file. This can be a link to another page or a link to a file in the cloud.', - 'attachments_link_name' => 'Link Name', - 'attachment_link' => 'Attachment link', - 'attachments_link_url' => 'Link to file', - 'attachments_link_url_hint' => 'Url of site or file', - 'attach' => 'Attach', - 'attachments_insert_link' => 'Add Attachment Link to Page', - 'attachments_edit_file' => 'Edit File', - 'attachments_edit_file_name' => 'File Name', - 'attachments_edit_drop_upload' => 'Drop files or click here to upload and overwrite', - 'attachments_order_updated' => 'Attachment order updated', - 'attachments_updated_success' => 'Attachment details updated', - 'attachments_deleted' => 'Attachment deleted', - 'attachments_file_uploaded' => 'File successfully uploaded', - 'attachments_file_updated' => 'File successfully updated', - 'attachments_link_attached' => 'Link successfully attached to page', - 'templates' => 'Templates', - 'templates_set_as_template' => 'Page is a template', - 'templates_explain_set_as_template' => 'You can set this page as a template so its contents be utilized when creating other pages. Other users will be able to use this template if they have view permissions for this page.', - 'templates_replace_content' => 'Replace page content', - 'templates_append_content' => 'Append to page content', - 'templates_prepend_content' => 'Prepend to page content', + 'page_tags' => 'Etiquetas de Página', + 'chapter_tags' => 'Etiquetas do Capítulo', + 'book_tags' => 'Etiquetas do Livro', + 'shelf_tags' => 'Etiquetas da Prateleira', + 'tag' => 'Etiqueta', + 'tags' => 'Etiquetas', + 'tag_name' => 'Nome da Etiqueta', + 'tag_value' => 'Valor da Etiqueta (Opcional)', + 'tags_explain' => "Adicione algumas etiquetas para melhor categorizar o seu conteúdo. \n Você poderá atribuir valores às etiquetas para uma organização mais complexa.", + 'tags_add' => 'Adicionar outra etiqueta', + 'tags_remove' => 'Remover esta etiqueta', + 'attachments' => 'Anexos', + 'attachments_explain' => 'Carregue alguns arquivos ou anexe links para serem exibidos na sua página. Eles estarão visíveis na barra lateral à direita.', + 'attachments_explain_instant_save' => 'As mudanças são guardadas instantaneamente.', + 'attachments_items' => 'Itens Anexados', + 'attachments_upload' => 'Carregamento de Arquivos', + 'attachments_link' => 'Anexar Link', + 'attachments_set_link' => 'Definir Link', + 'attachments_delete' => 'Tem certeza de que deseja eliminar este anexo?', + 'attachments_dropzone' => 'Arraste arquivos para aqui ou clique para os anexar', + 'attachments_no_files' => 'Nenhum arquivo foi enviado', + 'attachments_explain_link' => 'Pode anexar um link se preferir não fazer o carregamento do arquivo. O link poderá ser para uma outra página ou para um arquivo na nuvem.', + 'attachments_link_name' => 'Nome do Link', + 'attachment_link' => 'Link do Anexo', + 'attachments_link_url' => 'Link para o Arquivo', + 'attachments_link_url_hint' => 'Url do sítio ou arquivo', + 'attach' => 'Anexar', + 'attachments_insert_link' => 'Adicionar Link de Anexo à Página', + 'attachments_edit_file' => 'Editar Arquivo', + 'attachments_edit_file_name' => 'Nome do Arquivo', + 'attachments_edit_drop_upload' => 'Arraste arquivos para aqui ou carregue para anexar arquivos e sobrescreve-los', + 'attachments_order_updated' => 'Ordem dos anexos atualizada', + 'attachments_updated_success' => 'Detalhes dos anexos atualizados', + 'attachments_deleted' => 'Anexo eliminado', + 'attachments_file_uploaded' => 'Carregamento de arquivo efetuado com sucesso', + 'attachments_file_updated' => 'Arquivo atualizado com sucesso', + 'attachments_link_attached' => 'Link anexado com sucesso à página', + 'templates' => 'Modelos', + 'templates_set_as_template' => 'A página é um modelo', + 'templates_explain_set_as_template' => 'Pode definir esta página como um modelo para que o seu conteúdo possa ser utilizado para criar outras páginas. Outros usuários poderão utilizar esta página como modelo se tiverem permissão para visualiza-la.', + 'templates_replace_content' => 'Substituir conteúdo da página', + 'templates_append_content' => 'Adicionar ao fim do conteúdo da página', + 'templates_prepend_content' => 'Adicionar ao início do conteúdo da página', // Profile View - 'profile_user_for_x' => 'User for :time', - 'profile_created_content' => 'Created Content', - 'profile_not_created_pages' => ':userName has not created any pages', - 'profile_not_created_chapters' => ':userName has not created any chapters', - 'profile_not_created_books' => ':userName has not created any books', - 'profile_not_created_shelves' => ':userName has not created any shelves', + 'profile_user_for_x' => 'Utilizador por :time', + 'profile_created_content' => 'Conteúdo Criado', + 'profile_not_created_pages' => ':userName não criou páginas', + 'profile_not_created_chapters' => ':userName não criou capítulos', + 'profile_not_created_books' => ':userName não criou livros', + 'profile_not_created_shelves' => ':userName não criou estantes', // Comments - 'comment' => 'Comment', - 'comments' => 'Comments', - 'comment_add' => 'Add Comment', - 'comment_placeholder' => 'Leave a comment here', - 'comment_count' => '{0} No Comments|{1} 1 Comment|[2,*] :count Comments', - 'comment_save' => 'Save Comment', - 'comment_saving' => 'Saving comment...', - 'comment_deleting' => 'Deleting comment...', - 'comment_new' => 'New Comment', - 'comment_created' => 'commented :createDiff', - 'comment_updated' => 'Updated :updateDiff by :username', - 'comment_deleted_success' => 'Comment deleted', - 'comment_created_success' => 'Comment added', - 'comment_updated_success' => 'Comment updated', - 'comment_delete_confirm' => 'Are you sure you want to delete this comment?', - 'comment_in_reply_to' => 'In reply to :commentId', + 'comment' => 'Comentário', + 'comments' => 'Comentários', + 'comment_add' => 'Adicionar Comentário', + 'comment_placeholder' => 'Digite aqui os seus comentários', + 'comment_count' => '{0} Nenhum comentário|{1} 1 Comentário|[2,*] :count Comentários', + 'comment_save' => 'Guardar comentário', + 'comment_saving' => 'Guardar comentário...', + 'comment_deleting' => 'Remover comentário...', + 'comment_new' => 'Comentário Novo', + 'comment_created' => 'comentado :createDiff', + 'comment_updated' => 'A editar :updateDiff por :username', + 'comment_deleted_success' => 'Comentário removido', + 'comment_created_success' => 'Comentário adicionado', + 'comment_updated_success' => 'Comentário editado', + 'comment_delete_confirm' => 'Tem a certeza de que deseja eliminar este comentário?', + 'comment_in_reply_to' => 'Em resposta à :commentId', // Revision - 'revision_delete_confirm' => 'Are you sure you want to delete this revision?', - 'revision_restore_confirm' => 'Are you sure you want to restore this revision? The current page contents will be replaced.', - 'revision_delete_success' => 'Revision deleted', - 'revision_cannot_delete_latest' => 'Cannot delete the latest revision.' + 'revision_delete_confirm' => 'Tem a certeza de que deseja eliminar esta revisão?', + 'revision_restore_confirm' => 'Tem a certeza que deseja restaurar esta revisão? O conteúdo atual da página será substituído.', + 'revision_delete_success' => 'Revisão excluída', + 'revision_cannot_delete_latest' => 'Não é possível eliminar a revisão mais recente.' ]; \ No newline at end of file diff --git a/resources/lang/pt/errors.php b/resources/lang/pt/errors.php index 79024e482..d1f3d8a5f 100644 --- a/resources/lang/pt/errors.php +++ b/resources/lang/pt/errors.php @@ -5,98 +5,98 @@ return [ // Permissions - 'permission' => 'You do not have permission to access the requested page.', - 'permissionJson' => 'You do not have permission to perform the requested action.', + 'permission' => 'Você não tem permissão para aceder à página requisitada.', + 'permissionJson' => 'Você não tem permissão para realizar a ação requerida.', // Auth - 'error_user_exists_different_creds' => 'A user with the email :email already exists but with different credentials.', - 'email_already_confirmed' => 'Email has already been confirmed, Try logging in.', - 'email_confirmation_invalid' => 'This confirmation token is not valid or has already been used, Please try registering again.', - 'email_confirmation_expired' => 'The confirmation token has expired, A new confirmation email has been sent.', - 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', - 'ldap_fail_anonymous' => 'LDAP access failed using anonymous bind', - 'ldap_fail_authed' => 'LDAP access failed using given dn & password details', - 'ldap_extension_not_installed' => 'LDAP PHP extension not installed', - 'ldap_cannot_connect' => 'Cannot connect to ldap server, Initial connection failed', - 'saml_already_logged_in' => 'Already logged in', - 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', - 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', - 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', - 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', - 'social_no_action_defined' => 'No action defined', - 'social_login_bad_response' => "Error received during :socialAccount login: \n:error", - 'social_account_in_use' => 'This :socialAccount account is already in use, Try logging in via the :socialAccount option.', - 'social_account_email_in_use' => 'The email :email is already in use. If you already have an account you can connect your :socialAccount account from your profile settings.', - 'social_account_existing' => 'This :socialAccount is already attached to your profile.', - 'social_account_already_used_existing' => 'This :socialAccount account is already used by another user.', - 'social_account_not_used' => 'This :socialAccount account is not linked to any users. Please attach it in your profile settings. ', - 'social_account_register_instructions' => 'If you do not yet have an account, You can register an account using the :socialAccount option.', - 'social_driver_not_found' => 'Social driver not found', - 'social_driver_not_configured' => 'Your :socialAccount social settings are not configured correctly.', - 'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.', + 'error_user_exists_different_creds' => 'Um utilizador com o endereço de e-mail :email já existe mas com credenciais diferentes.', + 'email_already_confirmed' => 'E-mail já foi confirmado. Tente iniciar sessão.', + 'email_confirmation_invalid' => 'Este token de confirmação não é válido ou já foi utilizado. Por favor, tente registar-se novamente.', + 'email_confirmation_expired' => 'O token de confirmação já expirou. Um novo e-mail foi enviado.', + 'email_confirmation_awaiting' => 'O endereço de e-mail da conta em uso precisa ser confirmado', + 'ldap_fail_anonymous' => 'O acesso LDAP falhou ao tentar usar o anonymous bind', + 'ldap_fail_authed' => 'O acesso LDAP falhou ao tentar os detalhes do dn e senha fornecidos', + 'ldap_extension_not_installed' => 'A extensão LDAP PHP não está instalada', + 'ldap_cannot_connect' => 'Não foi possível conectar ao servidor LDAP. Conexão inicial falhou', + 'saml_already_logged_in' => 'Sessão já iniciada', + 'saml_user_not_registered' => 'O utilizador :name não está registado e o registo automático está desativado', + 'saml_no_email_address' => 'Não foi possível encontrar um endereço de e-mail para este utilizador nos dados providenciados pelo sistema de autenticação externa', + 'saml_invalid_response_id' => 'A requisição do sistema de autenticação externa não foi reconhecia por um processo iniciado por esta aplicação. Navegar para o caminho anterior após o inicio de sessão pode provocar este problema.', + 'saml_fail_authed' => 'Inicio de sessão com :system falhou. O sistema não forneceu uma autorização bem sucedida', + 'social_no_action_defined' => 'Nenhuma ação definida', + 'social_login_bad_response' => "Erro recebido durante o inicio de sessão :socialAccount: \n:error", + 'social_account_in_use' => 'Esta conta :socialAccount já está em uso. Por favor, tente entrar utilizando a opção :socialAccount.', + 'social_account_email_in_use' => 'O e-mail :email já está em uso. Se já possui uma conta poderá ligar a sua conta :socialAccount a partir das configurações do seu perfil.', + 'social_account_existing' => 'Esta conta :socialAccount já está vinculada a este perfil.', + 'social_account_already_used_existing' => 'Esta conta :socialAccount já está a ser utilizada por outro utilizador.', + 'social_account_not_used' => 'Esta conta :socialAccount não está vinculada a nenhum utilizador. Por favor vincule a conta nas suas configurações de perfil. ', + 'social_account_register_instructions' => 'Se não possui uma conta, poderá registar-se utilizando a opção :socialAccount.', + 'social_driver_not_found' => 'Social driver não encontrado', + 'social_driver_not_configured' => 'Os seus parâmetros sociais de :socialAccount não estão corretamente configurados.', + 'invite_token_expired' => 'Este link de convite expirou. Alternativamente, pode tentar redefinir a senha da sua conta.', // System - 'path_not_writable' => 'File path :filePath could not be uploaded to. Ensure it is writable to the server.', - 'cannot_get_image_from_url' => 'Cannot get image from :url', - 'cannot_create_thumbs' => 'The server cannot create thumbnails. Please check you have the GD PHP extension installed.', - 'server_upload_limit' => 'The server does not allow uploads of this size. Please try a smaller file size.', - 'uploaded' => 'The server does not allow uploads of this size. Please try a smaller file size.', - 'image_upload_error' => 'An error occurred uploading the image', - 'image_upload_type_error' => 'The image type being uploaded is invalid', - 'file_upload_timeout' => 'The file upload has timed out.', + 'path_not_writable' => 'O caminho do arquivo :filePath não pôde ser carregado. Certifique-se de que tem permissões de escrita no servidor.', + 'cannot_get_image_from_url' => 'Não foi possível obter a imagem a partir de :url', + 'cannot_create_thumbs' => 'O servidor não pôde criar as miniaturas de imagem. Por favor, verifique se a extensão GD PHP está instalada.', + 'server_upload_limit' => 'O servidor não permite o carregamento de arquivos com esse tamanho. Por favor, tente fazer o carregamento de arquivos mais pequenos.', + 'uploaded' => 'O servidor não permite o carregamento de arquivos com esse tamanho. Por favor, tente fazer o carregamento de arquivos mais pequenos.', + 'image_upload_error' => 'Ocorreu um erro no carregamento da imagem', + 'image_upload_type_error' => 'O tipo de imagem enviada é inválida', + 'file_upload_timeout' => 'O carregamento do arquivo expirou.', // Attachments - 'attachment_not_found' => 'Attachment not found', + 'attachment_not_found' => 'Anexo não encontrado', // Pages - 'page_draft_autosave_fail' => 'Failed to save draft. Ensure you have internet connection before saving this page', - 'page_custom_home_deletion' => 'Cannot delete a page while it is set as a homepage', + 'page_draft_autosave_fail' => 'Falha ao tentar guardar o rascunho. Certifique-se que a conexão de Internet está funcional antes de tentar guardar esta página', + 'page_custom_home_deletion' => 'Não é possível eliminar uma página que está definida como página inicial', // Entities - 'entity_not_found' => 'Entity not found', - 'bookshelf_not_found' => 'Bookshelf not found', - 'book_not_found' => 'Book not found', - 'page_not_found' => 'Page not found', - 'chapter_not_found' => 'Chapter not found', - 'selected_book_not_found' => 'The selected book was not found', - 'selected_book_chapter_not_found' => 'The selected Book or Chapter was not found', - 'guests_cannot_save_drafts' => 'Guests cannot save drafts', + 'entity_not_found' => 'Entidade não encontrada', + 'bookshelf_not_found' => 'Estante de Livros 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', + 'selected_book_not_found' => 'O livro selecionado não foi encontrado', + 'selected_book_chapter_not_found' => 'O Livro ou Capítulo selecionado não foi encontrado', + 'guests_cannot_save_drafts' => 'Convidados não podem guardar rascunhos', // Users - 'users_cannot_delete_only_admin' => 'You cannot delete the only admin', - 'users_cannot_delete_guest' => 'You cannot delete the guest user', + 'users_cannot_delete_only_admin' => 'Não pode excluir o único administrador', + 'users_cannot_delete_guest' => 'Não pode excluir o usuário convidado', // Roles - 'role_cannot_be_edited' => 'This role cannot be edited', - 'role_system_cannot_be_deleted' => 'This role is a system role and cannot be deleted', - 'role_registration_default_cannot_delete' => 'This role cannot be deleted while set as the default registration role', - 'role_cannot_remove_only_admin' => 'This user is the only user assigned to the administrator role. Assign the administrator role to another user before attempting to remove it here.', + 'role_cannot_be_edited' => 'Este cargo não pode ser editado', + 'role_system_cannot_be_deleted' => 'Este cargo é um cargo do sistema e não pode ser excluído', + 'role_registration_default_cannot_delete' => 'Este cargo não poderá se excluído enquanto estiver definido como o cargo padrão', + 'role_cannot_remove_only_admin' => 'Este utilizador é o único vinculado ao cargo de administrador. Atribua o cargo de administrador a outro antes de tentar removê-lo aqui.', // Comments - 'comment_list' => 'An error occurred while fetching the comments.', - 'cannot_add_comment_to_draft' => 'You cannot add comments to a draft.', - 'comment_add' => 'An error occurred while adding / updating the comment.', - 'comment_delete' => 'An error occurred while deleting the comment.', - 'empty_comment' => 'Cannot add an empty comment.', + 'comment_list' => 'Ocorreu um erro ao recolher os comentários.', + 'cannot_add_comment_to_draft' => 'Não pode adicionar comentários a um rascunho.', + 'comment_add' => 'Ocorreu um erro ao adicionar/atualizar o comentário.', + 'comment_delete' => 'Ocorreu um erro ao eliminar o comentário.', + 'empty_comment' => 'Não é possível adicionar um comentário vazio.', // Error pages - '404_page_not_found' => 'Page Not Found', - 'sorry_page_not_found' => 'Sorry, The page you were looking for could not be found.', - 'sorry_page_not_found_permission_warning' => 'If you expected this page to exist, you might not have permission to view it.', - 'return_home' => 'Return to home', - 'error_occurred' => 'An Error Occurred', - 'app_down' => ':appName is down right now', - 'back_soon' => 'It will be back up soon.', + '404_page_not_found' => 'Página Não Encontrada', + 'sorry_page_not_found' => 'Desculpe, a página que procura não foi encontrada.', + 'sorry_page_not_found_permission_warning' => 'Se esperava que esta página existisse, talvez não tenha permissão para visualizá-la.', + 'return_home' => 'Regressar à página inicial', + 'error_occurred' => 'Ocorreu um Erro', + 'app_down' => ':appName está fora do ar de momento', + 'back_soon' => 'Voltaremos em breve.', // API errors - 'api_no_authorization_found' => 'No authorization token found on the request', - 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', - 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', - 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', - 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', - 'api_user_token_expired' => 'The authorization token used has expired', + 'api_no_authorization_found' => 'Nenhum token de autorização encontrado na requisição', + 'api_bad_authorization_format' => 'Um token de autorização foi encontrado na requisição, mas o formato parece incorreto', + 'api_user_token_not_found' => 'Nenhum token de API correspondente foi encontrado para o token de autorização fornecido', + 'api_incorrect_token_secret' => 'O segredo fornecido para o token de API usado está incorreto', + 'api_user_no_api_permission' => 'O proprietário do token de API utilizado não tem permissão para fazer requisições de API', + 'api_user_token_expired' => 'O token de autenticação expirou', // Settings & Maintenance - 'maintenance_test_email_failure' => 'Error thrown when sending a test email:', + 'maintenance_test_email_failure' => 'Erro lançado ao enviar um e-mail de teste:', ]; diff --git a/resources/lang/pt/pagination.php b/resources/lang/pt/pagination.php index 85bd12fc3..1870e3418 100644 --- a/resources/lang/pt/pagination.php +++ b/resources/lang/pt/pagination.php @@ -6,7 +6,7 @@ */ return [ - 'previous' => '« Previous', - 'next' => 'Next »', + 'previous' => '« Anterior', + 'next' => 'Seguinte »', ]; diff --git a/resources/lang/pt/passwords.php b/resources/lang/pt/passwords.php index b408f3c2f..e468b9f68 100644 --- a/resources/lang/pt/passwords.php +++ b/resources/lang/pt/passwords.php @@ -6,10 +6,10 @@ */ return [ - 'password' => 'Passwords must be at least eight characters and match the confirmation.', - 'user' => "We can't find a user with that e-mail address.", - 'token' => 'The password reset token is invalid for this email address.', - 'sent' => 'We have e-mailed your password reset link!', - 'reset' => 'Your password has been reset!', + 'password' => 'As palavras-passe devem ter no mínimo oito caracteres e serem iguais à confirmação.', + 'user' => "Não pudemos encontrar um utilizador com o endereço de e-mail fornecido.", + 'token' => 'O token de redefinição de senha é inválido para este endereço de e-mail.', + 'sent' => 'Enviamos o link de redefinição de palavra-passe para o seu e-mail!', + 'reset' => 'A sua palavra-passe foi redefinida com sucesso!', ]; diff --git a/resources/lang/pt/settings.php b/resources/lang/pt/settings.php index 2bd314cf0..2ff60c033 100644 --- a/resources/lang/pt/settings.php +++ b/resources/lang/pt/settings.php @@ -7,192 +7,222 @@ return [ // Common Messages - 'settings' => 'Settings', - 'settings_save' => 'Save Settings', - 'settings_save_success' => 'Settings saved', + 'settings' => 'Configurações', + 'settings_save' => 'Guardar Configurações', + 'settings_save_success' => 'Configurações guardadas', // App Settings - 'app_customization' => 'Customization', - 'app_features_security' => 'Features & Security', - 'app_name' => 'Application Name', - 'app_name_desc' => 'This name is shown in the header and in any system-sent emails.', - 'app_name_header' => 'Show name in header', - 'app_public_access' => 'Public Access', - 'app_public_access_desc' => 'Enabling this option will allow visitors, that are not logged-in, to access content in your BookStack instance.', - 'app_public_access_desc_guest' => 'Access for public visitors can be controlled through the "Guest" user.', - 'app_public_access_toggle' => 'Allow public access', - 'app_public_viewing' => 'Allow public viewing?', - 'app_secure_images' => 'Higher Security Image Uploads', - 'app_secure_images_toggle' => 'Enable higher security image uploads', - 'app_secure_images_desc' => 'For performance reasons, all images are public. This option adds a random, hard-to-guess string in front of image urls. Ensure directory indexes are not enabled to prevent easy access.', - 'app_editor' => 'Page Editor', - 'app_editor_desc' => 'Select which editor will be used by all users to edit pages.', - 'app_custom_html' => 'Custom HTML Head Content', - 'app_custom_html_desc' => 'Any content added here will be inserted into the bottom of the section of every page. This is handy for overriding styles or adding analytics code.', - 'app_custom_html_disabled_notice' => 'Custom HTML head content is disabled on this settings page to ensure any breaking changes can be reverted.', - 'app_logo' => 'Application Logo', - 'app_logo_desc' => 'This image should be 43px in height.
Large images will be scaled down.', - 'app_primary_color' => 'Application Primary Color', - 'app_primary_color_desc' => 'Sets the primary color for the application including the banner, buttons, and links.', - 'app_homepage' => 'Application Homepage', - 'app_homepage_desc' => 'Select a view to show on the homepage instead of the default view. Page permissions are ignored for selected pages.', - 'app_homepage_select' => 'Select a page', - 'app_disable_comments' => 'Disable Comments', - 'app_disable_comments_toggle' => 'Disable comments', - 'app_disable_comments_desc' => 'Disables comments across all pages in the application.
Existing comments are not shown.', + 'app_customization' => 'Personalização', + 'app_features_security' => 'Recursos & Segurança', + 'app_name' => 'Nome da Aplicação', + 'app_name_desc' => 'Este nome será mostrado no cabeçalho e em e-mails.', + 'app_name_header' => 'Mostrar o nome no cabeçalho', + 'app_public_access' => 'Acesso Público', + 'app_public_access_desc' => 'Ativar esta opção irá permitir que os visitantes que não estão autenticados, acedam ao conteúdo da sua instância do BookStack.', + 'app_public_access_desc_guest' => 'O acesso de visitantes públicos pode ser controlado através do utilizador "Convidado".', + 'app_public_access_toggle' => 'Permitir acesso público', + 'app_public_viewing' => 'Permitir visualização pública?', + 'app_secure_images' => 'Carregamento de Imagens mais Seguro', + 'app_secure_images_toggle' => 'Ativar o carregamento de imagem mais seguro', + 'app_secure_images_desc' => 'Por razões de performance, todas as imagens são públicas. Esta opção adiciona uma string aleatória na frente das Urls de imagens. Certifique-se de que os diretórios não possam ser indexados para prevenir acesso indesejado.', + 'app_editor' => 'Editor de Página', + 'app_editor_desc' => 'Selecione qual editor será utilizado pelos utilizadores ao editar páginas.', + 'app_custom_html' => 'Conteúdo personalizado para para o Head do HTML', + 'app_custom_html_desc' => 'Quaisquer conteúdos aqui adicionados serão inseridos no final da secção de cada página. Esta é uma maneira útil de sobrescrever estilos e adicionar códigos de análise de site.', + 'app_custom_html_disabled_notice' => 'O conteúdo personalizado do HTML está desativado nesta página de configurações, para garantir que quaisquer alterações que acabem maliciosas possam ser revertidas.', + 'app_logo' => 'Logo da Aplicação', + 'app_logo_desc' => 'A imagem deve ter 43px de altura.
Imagens maiores serão reduzidas.', + 'app_primary_color' => 'Cor Primária da Aplicação', + 'app_primary_color_desc' => 'Define a cor primária para a aplicação, incluindo o banner, botões e links.', + 'app_homepage' => 'Página Inicial', + 'app_homepage_desc' => 'Selecione uma opção para ser exibida como página inicial em vez da padrão. Permissões de página serão ignoradas para as páginas selecionadas.', + 'app_homepage_select' => 'Selecione uma página', + 'app_footer_links' => 'Links do Rodapé', + 'app_footer_links_desc' => 'Adicionar links para mostrar dentro do rodapé do site. Estes serão exibidos no rodapé da maioria das páginas, incluindo as que não requerem autenticação. Pode utilizar uma etiqueta de "trans::" para utilizar traduções definidas pelo sistema. Por exemplo: Utilizando "trans::common.privacy_policy" fornecerá o texto traduzido "Política de Privacidade" e "trans::common.terms_of_service" fornecerá o texto traduzido "Termos de Serviço".', + 'app_footer_links_label' => 'Etiqueta do Link', + 'app_footer_links_url' => 'URL do link', + 'app_footer_links_add' => 'Adicionar Link de Rodapé', + 'app_disable_comments' => 'Desativar Comentários', + 'app_disable_comments_toggle' => 'Desativar comentários', + 'app_disable_comments_desc' => 'Desativar comentários em todas as páginas no aplicativo.
Comentários existentes não serão exibidos.', // Color settings - 'content_colors' => 'Content Colors', - 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', - 'bookshelf_color' => 'Shelf Color', - 'book_color' => 'Book Color', - 'chapter_color' => 'Chapter Color', - 'page_color' => 'Page Color', - 'page_draft_color' => 'Page Draft Color', + 'content_colors' => 'Cores do Conteúdo', + 'content_colors_desc' => 'Define as cores para todos os elementos da hierarquia de organização de páginas. Escolher cores com brilho similar ao das cores padrão é aconselhável para a legibilidade.', + 'bookshelf_color' => 'Cor da Prateleira', + 'book_color' => 'Cor do Livro', + 'chapter_color' => 'Cor do Capítulo', + 'page_color' => 'Cor da Página', + 'page_draft_color' => 'Cor do Rascunho', // Registration Settings - 'reg_settings' => 'Registration', - 'reg_enable' => 'Enable Registration', - 'reg_enable_toggle' => 'Enable registration', - 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', - 'reg_default_role' => 'Default user role after registration', - 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', - 'reg_email_confirmation' => 'Email Confirmation', - 'reg_email_confirmation_toggle' => 'Require email confirmation', - 'reg_confirm_email_desc' => 'If domain restriction is used then email confirmation will be required and this option will be ignored.', - 'reg_confirm_restrict_domain' => 'Domain Restriction', - 'reg_confirm_restrict_domain_desc' => 'Enter a comma separated list of email domains you would like to restrict registration to. Users will be sent an email to confirm their address before being allowed to interact with the application.
Note that users will be able to change their email addresses after successful registration.', - 'reg_confirm_restrict_domain_placeholder' => 'No restriction set', + 'reg_settings' => 'Cadastro', + 'reg_enable' => 'Habilitar Cadastro', + 'reg_enable_toggle' => 'Habilitar cadastro', + 'reg_enable_desc' => 'Quando o cadastro é habilitado, visitantes poderão cadastrar-se como usuários do aplicativo. Realizado o cadastro, recebem um único cargo padrão.', + 'reg_default_role' => 'Cargo padrão para usuários após o cadastro', + 'reg_enable_external_warning' => 'A opção acima é ignorada enquanto a autenticação externa LDAP ou SAML estiver ativa. Contas de usuários para membros não existentes serão criadas automaticamente se a autenticação pelo sistema externo em uso for bem sucedida.', + 'reg_email_confirmation' => 'Confirmação de E-mail', + 'reg_email_confirmation_toggle' => 'Requerer confirmação de e-mail', + 'reg_confirm_email_desc' => 'Em caso da restrição de domínios estar em uso, a confirmação de e-mail será requerida e esta opção será ignorada.', + 'reg_confirm_restrict_domain' => 'Restrição de Domínios', + 'reg_confirm_restrict_domain_desc' => 'Entre com uma lista separada por vírgulas de domínios de e-mails aos quais você deseja restringir o registo. Um e-mail de confirmação será enviado para o utilizador validar o seu respetivo endereço de e-mail antes de ser permitida a interação com a aplicação.
Note que os utilizadores serão capazes de alterar os seus endereços de e-mail após o sucesso na confirmação do registo.', + 'reg_confirm_restrict_domain_placeholder' => 'Nenhuma restrição definida', // Maintenance settings - 'maint' => 'Maintenance', - 'maint_image_cleanup' => 'Cleanup Images', - 'maint_image_cleanup_desc' => "Scans page & revision content to check which images and drawings are currently in use and which images are redundant. Ensure you create a full database and image backup before running this.", - 'maint_image_cleanup_ignore_revisions' => 'Ignore images in revisions', - 'maint_image_cleanup_run' => 'Run Cleanup', - 'maint_image_cleanup_warning' => ':count potentially unused images were found. Are you sure you want to delete these images?', - 'maint_image_cleanup_success' => ':count potentially unused images found and deleted!', - 'maint_image_cleanup_nothing_found' => 'No unused images found, Nothing deleted!', - 'maint_send_test_email' => 'Send a Test Email', - 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', - 'maint_send_test_email_run' => 'Send test email', - 'maint_send_test_email_success' => 'Email sent to :address', - 'maint_send_test_email_mail_subject' => 'Test Email', - 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', - 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', + 'maint' => 'Manutenção', + 'maint_image_cleanup' => 'Limpeza de Imagens', + 'maint_image_cleanup_desc' => "Examina páginas e reviste os seus conteúdos para verificar quais imagens e desenhos estão atualmente em uso e quais são redundantes. Certifique-se de criar uma cópia de segurança completa da base de dados e imagens antes de executar esta ação.", + 'maint_delete_images_only_in_revisions' => 'Eliminar também imagens que existam apenas em revisões de página antigas', + 'maint_image_cleanup_run' => 'Executar Limpeza', + 'maint_image_cleanup_warning' => ':count imagens potencialmente não utilizadas foram encontradas. Tem certeza de que deseja eliminar estas imagens?', + 'maint_image_cleanup_success' => ':count imagens potencialmente não utilizadas foram encontradas e eliminadas!', + 'maint_image_cleanup_nothing_found' => 'Nenhuma imagem por utilizar foi encontrada, nada foi eliminado!', + 'maint_send_test_email' => 'Enviar um E-mail de Teste', + 'maint_send_test_email_desc' => 'Esta opção envia um e-mail de teste para o endereço especificado no seu perfil.', + 'maint_send_test_email_run' => 'Enviar e-mail de teste', + 'maint_send_test_email_success' => 'E-mail enviado para :address', + 'maint_send_test_email_mail_subject' => 'E-mail de Teste', + 'maint_send_test_email_mail_greeting' => 'O envio de e-mails parece funcionar!', + 'maint_send_test_email_mail_text' => 'Parabéns! Já que recebeu esta notificação, as suas opções de e-mail parecem estar configuradas corretamente.', + 'maint_recycle_bin_desc' => 'Estantes, livros, capítulos e páginas eliminados são mandados para a reciclagem podendo assim ser restaurados ou excluídos permanentemente. Itens mais antigos da podem vir a ser automaticamente removidos da reciclagem após um tempo, dependendo da configuração do sistema.', + 'maint_recycle_bin_open' => 'Abrir Reciclagem', + + // Recycle Bin + 'recycle_bin' => 'Reciclagem', + 'recycle_bin_desc' => 'Aqui pode restaurar itens que foram eliminados ou eliminá-los permanentemente do sistema. Esta lista não é filtrada diferentemente de listas de atividades parecidas no sistema onde filtros de permissão são aplicados.', + 'recycle_bin_deleted_item' => 'Item eliminado', + 'recycle_bin_deleted_by' => 'Eliminado por', + 'recycle_bin_deleted_at' => 'Data de Eliminação', + 'recycle_bin_permanently_delete' => 'Eliminar permanentemente', + 'recycle_bin_restore' => 'Restaurar', + 'recycle_bin_contents_empty' => 'A reciclagem está atualmente vazia', + 'recycle_bin_empty' => 'Esvaziar Reciclagem', + 'recycle_bin_empty_confirm' => 'Isto irá destruir permanentemente todos os itens na reciclagem inclusive o conteúdo de cada item. Tem certeza de que a deseja esvaziar?', + 'recycle_bin_destroy_confirm' => 'Esta ação irá excluir permanentemente do sistema este item junto com todos os elementos filhos listados abaixo. Não poderá restaurar este conteúdo. Tem certeza de que deseja excluir permanentemente este item?', + 'recycle_bin_destroy_list' => 'Itens a serem Destruídos', + 'recycle_bin_restore_list' => 'Itens a serem Restaurados', + 'recycle_bin_restore_confirm' => 'Esta ação irá restaurar o item excluído, inclusive quaisquer elementos filhos, para o seu local original. Se a localização original tiver, entretanto, sido eliminada e estiver agora na reciclagem, o item pai também precisará de ser restaurado.', + 'recycle_bin_restore_deleted_parent' => 'O parente deste item foi também eliminado. Estes permanecerão eliminados até que o parente seja também restaurado.', + 'recycle_bin_destroy_notification' => 'Eliminados no total :count itens da lixeira.', + 'recycle_bin_restore_notification' => 'Restaurados no total :count itens da reciclagem.', // Audit Log - 'audit' => 'Audit Log', - 'audit_desc' => 'This audit log displays a list of activities tracked in the system. This list is unfiltered unlike similar activity lists in the system where permission filters are applied.', - 'audit_event_filter' => 'Event Filter', - 'audit_event_filter_no_filter' => 'No Filter', - 'audit_deleted_item' => 'Deleted Item', - 'audit_deleted_item_name' => 'Name: :name', - 'audit_table_user' => 'User', - 'audit_table_event' => 'Event', - 'audit_table_item' => 'Related Item', - 'audit_table_date' => 'Activity Date', - 'audit_date_from' => 'Date Range From', - 'audit_date_to' => 'Date Range To', + 'audit' => 'Registo de auditoria', + 'audit_desc' => 'Este registo de auditoria exibe uma lista de atividades rastreadas no sistema. Esta lista não é filtrada ao contrário de listas de atividades semelhantes no sistema onde os filtros de permissão são aplicados.', + 'audit_event_filter' => 'Filtro de Evento', + 'audit_event_filter_no_filter' => 'Sem filtro', + 'audit_deleted_item' => 'Item excluído', + 'audit_deleted_item_name' => 'Nome: :name', + 'audit_table_user' => 'Utilizador', + 'audit_table_event' => 'Evento', + 'audit_table_related' => 'Item ou Detalhe Relacionado', + 'audit_table_date' => 'Data da Atividade', + 'audit_date_from' => 'Intervalo De', + 'audit_date_to' => 'Intervalo Até', // Role Settings - 'roles' => 'Roles', - 'role_user_roles' => 'User Roles', - 'role_create' => 'Create New Role', - 'role_create_success' => 'Role successfully created', - 'role_delete' => 'Delete Role', - 'role_delete_confirm' => 'This will delete the role with the name \':roleName\'.', - 'role_delete_users_assigned' => 'This role has :userCount users assigned to it. If you would like to migrate the users from this role select a new role below.', - 'role_delete_no_migration' => "Don't migrate users", - 'role_delete_sure' => 'Are you sure you want to delete this role?', - 'role_delete_success' => 'Role successfully deleted', - 'role_edit' => 'Edit Role', - 'role_details' => 'Role Details', - 'role_name' => 'Role Name', - 'role_desc' => 'Short Description of Role', - 'role_external_auth_id' => 'External Authentication IDs', - 'role_system' => 'System Permissions', - 'role_manage_users' => 'Manage users', - 'role_manage_roles' => 'Manage roles & role permissions', - 'role_manage_entity_permissions' => 'Manage all book, chapter & page permissions', - 'role_manage_own_entity_permissions' => 'Manage permissions on own book, chapter & pages', - 'role_manage_page_templates' => 'Manage page templates', - 'role_access_api' => 'Access system API', - 'role_manage_settings' => 'Manage app settings', - 'role_asset' => 'Asset Permissions', - 'roles_system_warning' => 'Be aware that access to any of the above three permissions can allow a user to alter their own privileges or the privileges of others in the system. Only assign roles with these permissions to trusted users.', - 'role_asset_desc' => 'These permissions control default access to the assets within the system. Permissions on Books, Chapters and Pages will override these permissions.', - 'role_asset_admins' => 'Admins are automatically given access to all content but these options may show or hide UI options.', - 'role_all' => 'All', - 'role_own' => 'Own', - 'role_controlled_by_asset' => 'Controlled by the asset they are uploaded to', - 'role_save' => 'Save Role', - 'role_update_success' => 'Role successfully updated', - 'role_users' => 'Users in this role', - 'role_users_none' => 'No users are currently assigned to this role', + 'roles' => 'Cargos', + 'role_user_roles' => 'Cargos de Utilizador', + 'role_create' => 'Criar novo Cargo', + 'role_create_success' => 'Cargo criado com sucesso', + 'role_delete' => 'Excluir Cargo', + 'role_delete_confirm' => 'A ação vai eliminar o cargo de nome \':roleName\'.', + 'role_delete_users_assigned' => 'Esse cargo tem :userCount utilizadores vinculados nele. Se quiser migrar utilizadores deste cargo para outro, selecione um novo cargo.', + 'role_delete_no_migration' => "Não migrar utilizadores", + 'role_delete_sure' => 'Tem certeza que deseja excluir este cargo?', + 'role_delete_success' => 'Cargo excluído com sucesso', + 'role_edit' => 'Editar Cargo', + 'role_details' => 'Detalhes do Cargo', + 'role_name' => 'Nome do Cargo', + 'role_desc' => 'Breve Descrição do Cargo', + 'role_external_auth_id' => 'IDs de Autenticação Externa', + 'role_system' => 'Permissões do Sistema', + 'role_manage_users' => 'Gerir utilizadores', + 'role_manage_roles' => 'Gerir cargos e permissões de cargos', + 'role_manage_entity_permissions' => 'Gerir todos os livros, capítulos e permissões de páginas', + 'role_manage_own_entity_permissions' => 'Gerir permissões de seu próprio livro, capítulo e paginas', + 'role_manage_page_templates' => 'Gerir modelos de página', + 'role_access_api' => 'Aceder à API do sistema', + 'role_manage_settings' => 'Gerir as configurações da aplicação', + 'role_asset' => 'Permissões de Ativos', + 'roles_system_warning' => 'Esteja ciente de que o acesso a qualquer uma das três permissões acima pode permitir que um utilizador altere os seus próprios privilégios ou privilégios de outros no sistema. Apenas atribua cargos com essas permissões a utilizadores de confiança.', + 'role_asset_desc' => 'Estas 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 estas permissões.', + 'role_asset_admins' => 'Os administradores recebem automaticamente acesso a todo o conteúdo, mas estas opções podem mostrar ou ocultar as opções da Interface de Usuário.', + 'role_all' => 'Todos', + 'role_own' => 'Próprio', + 'role_controlled_by_asset' => 'Controlado pelo ativo para o qual eles são enviados', + 'role_save' => 'Guardar Cargo', + 'role_update_success' => 'Cargo atualizado com sucesso', + 'role_users' => 'Utilizadores com este cargo', + 'role_users_none' => 'Nenhum utilizador está atualmente vinculado a este cargo', // Users - 'users' => 'Users', - 'user_profile' => 'User Profile', - 'users_add_new' => 'Add New User', - 'users_search' => 'Search Users', - 'users_details' => 'User Details', - 'users_details_desc' => 'Set a display name and an email address for this user. The email address will be used for logging into the application.', - 'users_details_desc_no_email' => 'Set a display name for this user so others can recognise them.', - 'users_role' => 'User Roles', - 'users_role_desc' => 'Select which roles this user will be assigned to. If a user is assigned to multiple roles the permissions from those roles will stack and they will receive all abilities of the assigned roles.', - 'users_password' => 'User Password', - 'users_password_desc' => 'Set a password used to log-in to the application. This must be at least 6 characters long.', - 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', - 'users_send_invite_option' => 'Send user invite email', - 'users_external_auth_id' => 'External Authentication ID', - 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', - 'users_password_warning' => 'Only fill the below if you would like to change your password.', - 'users_system_public' => 'This user represents any guest users that visit your instance. It cannot be used to log in but is assigned automatically.', - 'users_delete' => 'Delete User', - 'users_delete_named' => 'Delete user :userName', - 'users_delete_warning' => 'This will fully delete this user with the name \':userName\' from the system.', - 'users_delete_confirm' => 'Are you sure you want to delete this user?', - 'users_delete_success' => 'Users successfully removed', - 'users_edit' => 'Edit User', - 'users_edit_profile' => 'Edit Profile', - 'users_edit_success' => 'User successfully updated', - 'users_avatar' => 'User Avatar', - 'users_avatar_desc' => 'Select an image to represent this user. This should be approx 256px square.', - 'users_preferred_language' => 'Preferred Language', - 'users_preferred_language_desc' => 'This option will change the language used for the user-interface of the application. This will not affect any user-created content.', - 'users_social_accounts' => 'Social Accounts', - 'users_social_accounts_info' => 'Here you can connect your other accounts for quicker and easier login. Disconnecting an account here does not revoke previously authorized access. Revoke access from your profile settings on the connected social account.', - 'users_social_connect' => 'Connect Account', - 'users_social_disconnect' => 'Disconnect Account', - 'users_social_connected' => ':socialAccount account was successfully attached to your profile.', - 'users_social_disconnected' => ':socialAccount account was successfully disconnected from your profile.', - 'users_api_tokens' => 'API Tokens', - 'users_api_tokens_none' => 'No API tokens have been created for this user', - 'users_api_tokens_create' => 'Create Token', - 'users_api_tokens_expires' => 'Expires', - 'users_api_tokens_docs' => 'API Documentation', + 'users' => 'Utilizadores', + 'user_profile' => 'Perfil do Utilizador', + 'users_add_new' => 'Adicionar Novo Utilizador', + 'users_search' => 'Pesquisar Utilizadores', + 'users_latest_activity' => 'Última atividade', + 'users_details' => 'Detalhes do Utilizador', + 'users_details_desc' => 'Defina um nome de exibição e um endereço de e-mail para este utilizador. O endereço de e-mail será utilizado na autenticação da aplicação.', + 'users_details_desc_no_email' => 'Defina um nome de exibição para este utilizador para que outros possam reconhecê-lo.', + 'users_role' => 'Cargos do Utilizador', + 'users_role_desc' => 'Selecione os cargos aos quais este utilizador será vinculado. Se um utilizador for vinculado a múltiplos cargos, as suas permissões serão empilhadas e ele receberá todas as habilidades dos cargos atribuídos.', + 'users_password' => 'Palavra-passe do Utilizador', + 'users_password_desc' => 'Defina uma palavra-passe utilizada para efetuar a autenticação na aplicação. Esta deve ter pelo menos 6 caracteres.', + 'users_send_invite_text' => 'Pode escolher enviar a este utilizador um convite por e-mail que o possibilitará definir a sua própria palavra-passe, ou defina você mesmo uma.', + 'users_send_invite_option' => 'Enviar convite por e-mail', + 'users_external_auth_id' => 'ID de Autenticação Externa', + 'users_external_auth_id_desc' => 'Este ID é utilizado para relacionar um utilizador ao comunicar com um sistema de autenticação externo.', + 'users_password_warning' => 'Apenas preencha os dados abaixo caso queira modificar a sua palavra-passe.', + 'users_system_public' => 'Este utilizador representa quaisquer convidados que visitam a aplicação. Não pode ser utilizado para efetuar autenticação mas é automaticamente atribuído.', + 'users_delete' => 'Eliminar Utilizador', + 'users_delete_named' => 'Eliminar :userName', + 'users_delete_warning' => 'A ação vai eliminar completamente o utilizador de nome \':userName\' do sistema.', + 'users_delete_confirm' => 'Tem certeza que eliminar este utilizador?', + 'users_migrate_ownership' => 'Migrar Posse', + 'users_migrate_ownership_desc' => 'Selecione um utilizador aqui se desejar que outro se torne o proprietário de todos os itens atualmente pertencentes a este.', + 'users_none_selected' => 'Nenhum utilizador selecionado', + 'users_delete_success' => 'Utilizador removido com sucesso', + 'users_edit' => 'Editar Utilizador', + 'users_edit_profile' => 'Editar Perfil', + 'users_edit_success' => 'Utilizador atualizado com sucesso', + 'users_avatar' => 'Avatar do Utilizador', + 'users_avatar_desc' => 'Defina uma imagem para representar este utilizador. Deve ser um quadrado com aproximadamente 256px de altura e largura.', + 'users_preferred_language' => 'Linguagem de Preferência', + 'users_preferred_language_desc' => 'Esta opção irá alterar o idioma utilizado para a interface de utilizador da aplicação. Isto não afetará nenhum conteúdo criado por utilizadores.', + 'users_social_accounts' => 'Contas Sociais', + 'users_social_accounts_info' => 'Aqui pode ligar outras contas para acesso mais rápido. Desligar uma conta não retira a possibilidade de acesso usando-a. Para revogar o acesso ao perfil através da conta social, você deverá fazê-lo na sua conta social.', + 'users_social_connect' => 'Contas Associadas', + 'users_social_disconnect' => 'Dissociar Conta', + 'users_social_connected' => 'A conta:socialAccount foi associada com sucesso ao seu perfil.', + 'users_social_disconnected' => 'A conta:socialAccount foi dissociada com sucesso de seu perfil.', + 'users_api_tokens' => 'Tokens de API', + 'users_api_tokens_none' => 'Nenhum token de API foi criado para este utilizador', + 'users_api_tokens_create' => 'Criar Token', + 'users_api_tokens_expires' => 'Expira', + 'users_api_tokens_docs' => 'Documentação da API', // API Tokens - 'user_api_token_create' => 'Create API Token', - 'user_api_token_name' => 'Name', - 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', - 'user_api_token_expiry' => 'Expiry Date', - 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', - 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', - 'user_api_token_create_success' => 'API token successfully created', - 'user_api_token_update_success' => 'API token successfully updated', - 'user_api_token' => 'API Token', - 'user_api_token_id' => 'Token ID', - 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', - 'user_api_token_secret' => 'Token Secret', - 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', - 'user_api_token_created' => 'Token Created :timeAgo', - 'user_api_token_updated' => 'Token Updated :timeAgo', - 'user_api_token_delete' => 'Delete Token', - 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', - 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', - 'user_api_token_delete_success' => 'API token successfully deleted', + 'user_api_token_create' => 'Criar Token de API', + 'user_api_token_name' => 'Nome', + 'user_api_token_name_desc' => 'Dê ao seu token um nome legível como um futuro lembrete de seu propósito.', + 'user_api_token_expiry' => 'Data de Expiração', + 'user_api_token_expiry_desc' => 'Defina uma data em que este token expira. Depois desta data, as requisições feitas usando este token deixarão de funcionar. Deixar este campo em branco definirá um prazo de 100 anos futuros.', + 'user_api_token_create_secret_message' => 'Imediatamente após a criação deste token, um "ID de token" e "Segredo de token" serão gerados e exibidos. O segredo só será mostrado uma única vez, portanto, certifique-se de copiar o valor para algum lugar seguro antes de prosseguir.', + 'user_api_token_create_success' => 'Token de API criado com sucesso', + 'user_api_token_update_success' => 'Token de API atualizado com sucesso', + 'user_api_token' => 'Token de API', + 'user_api_token_id' => 'ID do Token', + 'user_api_token_id_desc' => 'Este é um identificador de sistema não editável, gerado para este token, que precisará ser fornecido em solicitações de API.', + 'user_api_token_secret' => 'Segredo do Token', + 'user_api_token_secret_desc' => 'Este é um segredo de sistema gerado para este token que precisará ser fornecido em requisições de API. Isto só será mostrado nesta única vez, portanto, copie este valor para um lugar seguro.', + 'user_api_token_created' => 'Token criado a :timeAgo', + 'user_api_token_updated' => 'Token atualizado a :timeAgo', + 'user_api_token_delete' => 'Eliminar Token', + 'user_api_token_delete_warning' => 'Isto irá excluir completamente este token de API com o nome \':tokenName\' do sistema.', + 'user_api_token_delete_confirm' => 'Tem certeza que deseja eliminar este token de API?', + 'user_api_token_delete_success' => 'Token de API excluído com sucesso', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. @@ -200,6 +230,9 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', @@ -209,11 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', + 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/pt/validation.php b/resources/lang/pt/validation.php index 76b57a2a3..b36ed0dab 100644 --- a/resources/lang/pt/validation.php +++ b/resources/lang/pt/validation.php @@ -8,104 +8,104 @@ return [ // Standard laravel validation lines - 'accepted' => 'The :attribute must be accepted.', - 'active_url' => 'The :attribute is not a valid URL.', - 'after' => 'The :attribute must be a date after :date.', - 'alpha' => 'The :attribute may only contain letters.', - 'alpha_dash' => 'The :attribute may only contain letters, numbers, dashes and underscores.', - 'alpha_num' => 'The :attribute may only contain letters and numbers.', - 'array' => 'The :attribute must be an array.', - 'before' => 'The :attribute must be a date before :date.', + 'accepted' => 'O campo :attribute deve ser aceite.', + 'active_url' => 'O campo :attribute não é um URL válido.', + 'after' => 'O campo :attribute deve ser uma data posterior à data :date.', + 'alpha' => 'O campo :attribute deve conter apenas letras.', + 'alpha_dash' => 'O campo :attribute deve conter apenas letras, números, traços e sublinhado.', + 'alpha_num' => 'O campo :attribute deve conter apenas letras e números.', + 'array' => 'O campo :attribute deve ser uma lista(array).', + 'before' => 'O campo :attribute deve ser uma data anterior à data :date.', 'between' => [ - 'numeric' => 'The :attribute must be between :min and :max.', - 'file' => 'The :attribute must be between :min and :max kilobytes.', - 'string' => 'The :attribute must be between :min and :max characters.', - 'array' => 'The :attribute must have between :min and :max items.', + 'numeric' => 'O campo :attribute deve estar entre :min e :max.', + 'file' => 'O campo :attribute deve ter entre :min e :max kilobytes.', + 'string' => 'O campo :attribute deve ter entre :min e :max caracteres.', + 'array' => 'O campo :attribute deve ter entre :min e :max itens.', ], - 'boolean' => 'The :attribute field must be true or false.', - 'confirmed' => 'The :attribute confirmation does not match.', - 'date' => 'The :attribute is not a valid date.', - 'date_format' => 'The :attribute does not match the format :format.', - 'different' => 'The :attribute and :other must be different.', - 'digits' => 'The :attribute must be :digits digits.', - 'digits_between' => 'The :attribute must be between :min and :max digits.', - 'email' => 'The :attribute must be a valid email address.', - 'ends_with' => 'The :attribute must end with one of the following: :values', - 'filled' => 'The :attribute field is required.', + 'boolean' => 'O campo :attribute deve ser verdadeiro ou falso.', + 'confirmed' => 'O campo :attribute não é igual à sua confirmação.', + 'date' => 'O campo :attribute não está num formato de data válido.', + 'date_format' => 'O campo :attribute não tem a formatação :format.', + 'different' => 'O campo :attribute e o campo :other devem ser diferentes.', + 'digits' => 'O campo :attribute deve ter :digits dígitos.', + 'digits_between' => 'O campo :attribute deve ter entre :min e :max dígitos.', + 'email' => 'O campo :attribute deve ser um endereço de e-mail válido.', + 'ends_with' => 'O campo :attribute deve terminar com um dos seguintes: :values', + 'filled' => 'O campo :attribute é requerido.', 'gt' => [ - 'numeric' => 'The :attribute must be greater than :value.', - 'file' => 'The :attribute must be greater than :value kilobytes.', - 'string' => 'The :attribute must be greater than :value characters.', - 'array' => 'The :attribute must have more than :value items.', + 'numeric' => 'O campo :attribute deve ser maior que :value.', + 'file' => 'O campo :attribute deve ser maior que :value kilobytes.', + 'string' => 'O campo :attribute deve ser maior que :value caracteres.', + 'array' => 'O campo :attribute deve ter mais que :value itens.', ], 'gte' => [ - 'numeric' => 'The :attribute must be greater than or equal :value.', - 'file' => 'The :attribute must be greater than or equal :value kilobytes.', - 'string' => 'The :attribute must be greater than or equal :value characters.', - 'array' => 'The :attribute must have :value items or more.', + 'numeric' => 'O campo :attribute deve ser maior ou igual a :value.', + 'file' => 'O campo :attribute deve ser maior ou igual a :value kilobytes.', + 'string' => 'O campo :attribute deve ser maior ou igual a :value caracteres.', + 'array' => 'O campo :attribute deve ter :value itens ou mais.', ], - 'exists' => 'The selected :attribute is invalid.', - 'image' => 'The :attribute must be an image.', - 'image_extension' => 'The :attribute must have a valid & supported image extension.', - 'in' => 'The selected :attribute is invalid.', - 'integer' => 'The :attribute must be an integer.', - 'ip' => 'The :attribute must be a valid IP address.', - 'ipv4' => 'The :attribute must be a valid IPv4 address.', - 'ipv6' => 'The :attribute must be a valid IPv6 address.', - 'json' => 'The :attribute must be a valid JSON string.', + 'exists' => 'O campo :attribute selecionado não é válido.', + 'image' => 'O campo :attribute deve ser uma imagem.', + 'image_extension' => 'O campo :attribute deve ter uma extensão de imagem válida e suportada.', + 'in' => 'O campo :attribute selecionado não é válido.', + 'integer' => 'O campo :attribute deve ser um número inteiro.', + 'ip' => 'O campo :attribute deve ser um endereço IP válido.', + 'ipv4' => 'O campo :attribute deve ser um endereço IPv4 válido.', + 'ipv6' => 'O campo :attribute deve ser um endereço IPv6 válido.', + 'json' => 'O campo :attribute deve ser uma string JSON válida.', 'lt' => [ - 'numeric' => 'The :attribute must be less than :value.', - 'file' => 'The :attribute must be less than :value kilobytes.', - 'string' => 'The :attribute must be less than :value characters.', - 'array' => 'The :attribute must have less than :value items.', + 'numeric' => 'O campo :attribute deve ser menor que :value.', + 'file' => 'O campo :attribute deve ser menor que :value kilobytes.', + 'string' => 'O campo :attribute deve ser menor que :value caracteres.', + 'array' => 'O campo :attribute deve conter menos que :value itens.', ], 'lte' => [ - 'numeric' => 'The :attribute must be less than or equal :value.', - 'file' => 'The :attribute must be less than or equal :value kilobytes.', - 'string' => 'The :attribute must be less than or equal :value characters.', - 'array' => 'The :attribute must not have more than :value items.', + 'numeric' => 'O campo :attribute deve ser menor ou igual a :value.', + 'file' => 'O campo :attribute deve ser menor ou igual a :value kilobytes.', + 'string' => 'O campo :attribute deve ser menor ou igual a :value caracteres.', + 'array' => 'O campo :attribute não deve conter mais que :value itens.', ], 'max' => [ - 'numeric' => 'The :attribute may not be greater than :max.', - 'file' => 'The :attribute may not be greater than :max kilobytes.', - 'string' => 'The :attribute may not be greater than :max characters.', - 'array' => 'The :attribute may not have more than :max items.', + 'numeric' => 'O valor para o campo :attribute não deve ser maior que :max.', + 'file' => 'O valor para o campo :attribute não deve ter tamanho maior que :max kilobytes.', + 'string' => 'O valor para o campo :attribute não deve ter mais que :max caracteres.', + 'array' => 'O valor para o campo :attribute não deve ter mais que :max itens.', ], - 'mimes' => 'The :attribute must be a file of type: :values.', + 'mimes' => 'O campo :attribute deve ser do tipo type: :values.', 'min' => [ - 'numeric' => 'The :attribute must be at least :min.', - 'file' => 'The :attribute must be at least :min kilobytes.', - 'string' => 'The :attribute must be at least :min characters.', - 'array' => 'The :attribute must have at least :min items.', + 'numeric' => 'O campo :attribute não deve ser menor que :min.', + 'file' => 'O campo :attribute não deve ter tamanho menor que :min kilobytes.', + 'string' => 'O campo :attribute não deve ter menos que :min caracteres.', + 'array' => 'O campo :attribute não deve ter menos que :min itens.', ], - 'no_double_extension' => 'The :attribute must only have a single file extension.', - 'not_in' => 'The selected :attribute is invalid.', - 'not_regex' => 'The :attribute format is invalid.', - 'numeric' => 'The :attribute must be a number.', - 'regex' => 'The :attribute format is invalid.', - 'required' => 'The :attribute field is required.', - 'required_if' => 'The :attribute field is required when :other is :value.', - 'required_with' => 'The :attribute field is required when :values is present.', - 'required_with_all' => 'The :attribute field is required when :values is present.', - 'required_without' => 'The :attribute field is required when :values is not present.', - 'required_without_all' => 'The :attribute field is required when none of :values are present.', - 'same' => 'The :attribute and :other must match.', + 'not_in' => 'O campo selecionado :attribute é inválido.', + 'not_regex' => 'O formato do campo :attribute é inválido.', + 'numeric' => 'O campo :attribute deve ser um número.', + 'regex' => 'O formato do campo :attribute é inválido.', + 'required' => 'O campo :attribute é requerido.', + 'required_if' => 'O campo :attribute é requerido quando o campo :other tem valor :value.', + 'required_with' => 'O campo :attribute é requerido quando os valores :values estiverem presentes.', + 'required_with_all' => 'O campo :attribute é requerido quando os valores :values estiverem presentes.', + 'required_without' => 'O campo :attribute é requerido quando os valores :values não estiverem presentes.', + 'required_without_all' => 'O campo :attribute é requerido quando nenhum dos valores :values estiverem presentes.', + 'same' => 'O campo :attribute e o campo :other devem ser iguais.', + 'safe_url' => 'O link fornecido poderá não ser seguro.', 'size' => [ - 'numeric' => 'The :attribute must be :size.', - 'file' => 'The :attribute must be :size kilobytes.', - 'string' => 'The :attribute must be :size characters.', - 'array' => 'The :attribute must contain :size items.', + 'numeric' => 'O tamanho do campo :attribute deve ser :size.', + 'file' => 'O tamanho do arquivo :attribute deve ser de :size kilobytes.', + 'string' => 'O tamanho do campo :attribute deve ser de :size caracteres.', + 'array' => 'O campo :attribute deve conter :size itens.', ], - 'string' => 'The :attribute must be a string.', - 'timezone' => 'The :attribute must be a valid zone.', - 'unique' => 'The :attribute has already been taken.', - 'url' => 'The :attribute format is invalid.', - 'uploaded' => 'The file could not be uploaded. The server may not accept files of this size.', + 'string' => 'O campo :attribute deve ser uma string.', + 'timezone' => 'O campo :attribute deve conter uma timezone válida.', + 'unique' => 'Já existe um campo/dado de nome :attribute.', + 'url' => 'O formato da URL :attribute é inválido.', + 'uploaded' => 'O arquivo não pôde ser carregado. O servidor pode não aceitar arquivos deste tamanho.', // Custom validation lines 'custom' => [ 'password-confirm' => [ - 'required_with' => 'Password confirmation required', + 'required_with' => 'Confirmação de senha requerida', ], ], diff --git a/resources/lang/pt_BR/activities.php b/resources/lang/pt_BR/activities.php index 2fa3d6571..33781417f 100644 --- a/resources/lang/pt_BR/activities.php +++ b/resources/lang/pt_BR/activities.php @@ -45,5 +45,5 @@ return [ // Other 'commented_on' => 'comentou em', - 'permissions_update' => 'updated permissions', + 'permissions_update' => 'atualizou permissões', ]; diff --git a/resources/lang/pt_BR/common.php b/resources/lang/pt_BR/common.php index 8b0dffe6e..4caf7070b 100644 --- a/resources/lang/pt_BR/common.php +++ b/resources/lang/pt_BR/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'Se você estiver tendo problemas ao clicar o botão ":actionText", copie e cole a URL abaixo no seu navegador:', 'email_rights' => 'Todos os direitos reservados', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Políticas de Privacidade', + 'terms_of_service' => 'Termos de Serviço', ]; diff --git a/resources/lang/pt_BR/entities.php b/resources/lang/pt_BR/entities.php index 129e1f260..b90cee374 100644 --- a/resources/lang/pt_BR/entities.php +++ b/resources/lang/pt_BR/entities.php @@ -22,7 +22,7 @@ return [ 'meta_created_name' => 'Criado :timeLength por :user', 'meta_updated' => 'Atualizado :timeLength', 'meta_updated_name' => 'Atualizado :timeLength por :user', - 'meta_owned_name' => 'Owned by :user', + 'meta_owned_name' => 'De :user', 'entity_select' => 'Seleção de Entidade', 'images' => 'Imagens', 'my_recent_drafts' => 'Meus Rascunhos Recentes', @@ -40,7 +40,7 @@ return [ 'permissions_intro' => 'Uma vez habilitadas, estas permissões terão prioridade sobre outro conjunto de permissões.', 'permissions_enable' => 'Habilitar Permissões Customizadas', 'permissions_save' => 'Salvar Permissões', - 'permissions_owner' => 'Owner', + 'permissions_owner' => 'Proprietário', // Search 'search_results' => 'Resultado(s) da Pesquisa', @@ -148,7 +148,7 @@ return [ 'chapters_create' => 'Criar Novo Capítulo', 'chapters_delete' => 'Excluir Capítulo', 'chapters_delete_named' => 'Excluir Capítulo :chapterName', - 'chapters_delete_explain' => 'This will delete the chapter with the name \':chapterName\'. All pages that exist within this chapter will also be deleted.', + 'chapters_delete_explain' => 'Isto irá excluir o capítulo com o nome \':chapterName\'. Todas as páginas que existem neste capítulo também serão excluídas.', 'chapters_delete_confirm' => 'Tem certeza que deseja excluir o capítulo?', 'chapters_edit' => 'Editar Capítulo', 'chapters_edit_named' => 'Editar Capítulo :chapterName', @@ -210,7 +210,7 @@ return [ 'pages_revisions' => 'Revisões da Página', 'pages_revisions_named' => 'Revisões de Página para :pageName', 'pages_revision_named' => 'Revisão de Página para :pageName', - 'pages_revision_restored_from' => 'Restored from #:id; :summary', + 'pages_revision_restored_from' => 'Restaurado de #:id; :summary', 'pages_revisions_created_by' => 'Criada por', 'pages_revisions_date' => 'Data da Revisão', 'pages_revisions_number' => '#', @@ -268,7 +268,7 @@ return [ 'attachments_link_url' => 'Link para o Arquivo', 'attachments_link_url_hint' => 'URL do site ou arquivo', 'attach' => 'Anexar', - 'attachments_insert_link' => 'Add Attachment Link to Page', + 'attachments_insert_link' => 'Adicionar Link de Anexo à Página', 'attachments_edit_file' => 'Editar Arquivo', 'attachments_edit_file_name' => 'Nome do Arquivo', 'attachments_edit_drop_upload' => 'Arraste arquivos para cá ou clique para anexar arquivos e sobrescreve-los', diff --git a/resources/lang/pt_BR/settings.php b/resources/lang/pt_BR/settings.php index a970e0231..1eab14803 100644 --- a/resources/lang/pt_BR/settings.php +++ b/resources/lang/pt_BR/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'Página Inicial', 'app_homepage_desc' => 'Selecione uma opção para ser exibida como página inicial em vez da padrão. Permissões de página serão ignoradas para as páginas selecionadas.', 'app_homepage_select' => 'Selecione uma página', + 'app_footer_links' => 'Links do Rodapé', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', 'app_disable_comments' => 'Desativar Comentários', 'app_disable_comments_toggle' => 'Desativar comentários', 'app_disable_comments_desc' => 'Desativar comentários em todas as páginas no aplicativo.
Comentários existentes não serão exibidos.', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/pt_BR/validation.php b/resources/lang/pt_BR/validation.php index 9777eacac..ea3779c78 100644 --- a/resources/lang/pt_BR/validation.php +++ b/resources/lang/pt_BR/validation.php @@ -78,7 +78,6 @@ return [ 'string' => 'O campo :attribute não deve ter menos que :min caracteres.', 'array' => 'O campo :attribute não deve ter menos que :min itens.', ], - 'no_double_extension' => 'O campo :attribute deve ter apenas uma extensão de arquivo.', 'not_in' => 'O campo selecionado :attribute é inválido.', 'not_regex' => 'O formato do campo :attribute é inválido.', 'numeric' => 'O campo :attribute deve ser um número.', @@ -90,7 +89,7 @@ return [ 'required_without' => 'O campo :attribute é requerido quando os valores :values não estiverem presentes.', 'required_without_all' => 'O campo :attribute é requerido quando nenhum dos valores :values estiverem presentes.', 'same' => 'O campo :attribute e o campo :other devem ser iguais.', - 'safe_url' => 'The provided link may not be safe.', + 'safe_url' => 'O link fornecido pode não ser seguro.', 'size' => [ 'numeric' => 'O tamanho do campo :attribute deve ser :size.', 'file' => 'O tamanho do arquivo :attribute deve ser de :size kilobytes.', diff --git a/resources/lang/ru/common.php b/resources/lang/ru/common.php index 12eac6912..da9f298e2 100644 --- a/resources/lang/ru/common.php +++ b/resources/lang/ru/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'Если у вас возникли проблемы с нажатием кнопки \':actionText\', то скопируйте и вставьте указанный URL-адрес в свой браузер:', 'email_rights' => 'Все права защищены', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privacy Policy', + 'terms_of_service' => 'Terms of Service', ]; diff --git a/resources/lang/ru/settings.php b/resources/lang/ru/settings.php index 472973ca2..7e359c36f 100755 --- a/resources/lang/ru/settings.php +++ b/resources/lang/ru/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'Стартовая страница приложения', 'app_homepage_desc' => 'Выберите страницу, которая будет отображаться на главной странице вместо стандартной. Права на страницы игнорируются для выбранных страниц.', 'app_homepage_select' => 'Выберите страницу', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', 'app_disable_comments' => 'Отключение комментариев', 'app_disable_comments_toggle' => 'Отключить комментарии', 'app_disable_comments_desc' => 'Отключение комментариев на всех страницах. Существующие комментарии будут скрыты.', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/ru/validation.php b/resources/lang/ru/validation.php index d16ead5d8..8c583f7e7 100644 --- a/resources/lang/ru/validation.php +++ b/resources/lang/ru/validation.php @@ -78,7 +78,6 @@ return [ 'string' => ':attribute должен быть минимум :min символов.', 'array' => ':attribute должен содержать хотя бы :min элементов.', ], - 'no_double_extension' => ':attribute должен иметь только одно расширение файла.', 'not_in' => 'Выбранный :attribute некорректен.', 'not_regex' => 'Формат :attribute некорректен.', 'numeric' => ':attribute должен быть числом.', diff --git a/resources/lang/sk/common.php b/resources/lang/sk/common.php index 555c2c6f2..aefe487e5 100644 --- a/resources/lang/sk/common.php +++ b/resources/lang/sk/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'Ak máte problém klinkúť na tlačidlo ":actionText", skopírujte a vložte URL uvedenú nižšie do Vášho prehliadača:', 'email_rights' => 'Všetky práva vyhradené', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privacy Policy', + 'terms_of_service' => 'Terms of Service', ]; diff --git a/resources/lang/sk/settings.php b/resources/lang/sk/settings.php index 17e658a3f..60a1a5add 100644 --- a/resources/lang/sk/settings.php +++ b/resources/lang/sk/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'Application Homepage', 'app_homepage_desc' => 'Select a view to show on the homepage instead of the default view. Page permissions are ignored for selected pages.', 'app_homepage_select' => 'Select a page', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', 'app_disable_comments' => 'Zakázať komentáre', 'app_disable_comments_toggle' => 'Disable comments', 'app_disable_comments_desc' => 'Zakázať komentáre na všetkých stránkach aplikácie. Existujúce komentáre sa nezobrazujú.', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/sk/validation.php b/resources/lang/sk/validation.php index c127b0623..545313415 100644 --- a/resources/lang/sk/validation.php +++ b/resources/lang/sk/validation.php @@ -78,7 +78,6 @@ return [ 'string' => ':attribute musí mať aspoň :min znakov.', 'array' => ':attribute musí mať aspoň :min položiek.', ], - 'no_double_extension' => 'The :attribute must only have a single file extension.', 'not_in' => 'Vybraný :attribute je neplatný.', 'not_regex' => 'The :attribute format is invalid.', 'numeric' => ':attribute musí byť číslo.', diff --git a/resources/lang/sl/common.php b/resources/lang/sl/common.php index 65a42288c..bed877a66 100644 --- a/resources/lang/sl/common.php +++ b/resources/lang/sl/common.php @@ -9,7 +9,7 @@ return [ 'confirm' => 'Potrdi', 'back' => 'Nazaj', 'save' => 'Shrani', - 'continue' => 'Nadaljuj', + 'continue' => 'Naprej', 'select' => 'Izberi', 'toggle_all' => 'Vklopi vse', 'more' => 'Več', @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'V kolikor imate težave s klikom na gumb ":actionText", kopirajte in prilepite spodnjo povezavo v vaš brskalnik:', 'email_rights' => 'Vse pravice pridržane', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Pravilnik o zasebnosti', + 'terms_of_service' => 'Pogoji uporabe', ]; diff --git a/resources/lang/sl/entities.php b/resources/lang/sl/entities.php index 9e400bbec..c0a03b44c 100644 --- a/resources/lang/sl/entities.php +++ b/resources/lang/sl/entities.php @@ -22,7 +22,7 @@ return [ 'meta_created_name' => 'Ustvaril :timeLength uporabnik :user', 'meta_updated' => 'Posodobljeno :timeLength', 'meta_updated_name' => 'Posodobil :timeLength uporabnik :user', - 'meta_owned_name' => 'Owned by :user', + 'meta_owned_name' => 'V lasti :user', 'entity_select' => 'Izbira entitete', 'images' => 'Slike', 'my_recent_drafts' => 'Moji nedavni osnutki', @@ -40,7 +40,7 @@ return [ '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_save' => 'Shrani dovoljenja', - 'permissions_owner' => 'Owner', + 'permissions_owner' => 'Lastnik', // Search 'search_results' => 'Rezultati iskanja', @@ -148,7 +148,7 @@ return [ 'chapters_create' => 'Ustvari novo poglavje', 'chapters_delete' => 'Izbriši poglavje', 'chapters_delete_named' => 'Izbriši poglavje :chapterName', - 'chapters_delete_explain' => 'This will delete the chapter with the name \':chapterName\'. All pages that exist within this chapter will also be deleted.', + 'chapters_delete_explain' => 'Poglavje z imenom ":chapterName" bo izbrisano. Vse strani znotraj poglavja bodo prav tako izbrisane.', 'chapters_delete_confirm' => 'Ste prepričani, da želite izbrisati to poglavje?', 'chapters_edit' => 'Uredi poglavje', 'chapters_edit_named' => 'Uredi poglavje :chapterName', @@ -210,7 +210,7 @@ return [ 'pages_revisions' => 'Pregled strani', 'pages_revisions_named' => 'Pregledi strani za :pageName', 'pages_revision_named' => 'Pregled strani za :pageName', - 'pages_revision_restored_from' => 'Restored from #:id; :summary', + 'pages_revision_restored_from' => 'Obnovljeno iz #:id; :summary', 'pages_revisions_created_by' => 'Ustvaril', 'pages_revisions_date' => 'Datum revizije', 'pages_revisions_number' => '#', diff --git a/resources/lang/sl/settings.php b/resources/lang/sl/settings.php index feae93bd5..8373c8ceb 100644 --- a/resources/lang/sl/settings.php +++ b/resources/lang/sl/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'Domača stran aplikacije', 'app_homepage_desc' => 'Izberi pogled, da se pokaže na domači strani, namesto osnovnega pogleda. Dovoljenja strani so prezrta za izbrane strani.', 'app_homepage_select' => 'Izberi stran', + 'app_footer_links' => 'Povezave v nogi', + 'app_footer_links_desc' => 'Dodaj URL povezave, ki bodo na voljo v nogi spletne strani. Povezave bodo vidne na dnu večine strani, vključno s tistimi, ki ne zahtevajo prijave. Na voljo imate oznako "trans::" za uporabo sistemskih prevodov. Na primer: uporaba oznake "trans::common.privacy_policy" bo poskrbela za prevod besedila "Privacy Policy" in oznaka "trans::common.terms_of_service" bo poskrbela za prevod besedila "Terms of Service".', + 'app_footer_links_label' => 'Oznaka povezave', + 'app_footer_links_url' => 'Naslov URL povezave', + 'app_footer_links_add' => 'Dodaj povezavo v nogo', 'app_disable_comments' => 'Onemogoči komentarje', 'app_disable_comments_toggle' => 'Onemogoči komentarje', 'app_disable_comments_desc' => 'Onemogoči komentarje na vseh straneh v aplikaciji.
Obstoječi komentarji se ne prikazujejo.', @@ -68,7 +73,7 @@ return [ 'maint' => 'Vzdrževanje', 'maint_image_cleanup' => 'Odstrani /počisti slike', 'maint_image_cleanup_desc' => "Pregleda vsebino strani in revizij ter ugotovi, katere slike in risbe so v uporabi in katere so odvečne. Preden to poženeš, naredi popolno varnostno kopijo podatkovne zbirke in slik.", - 'maint_delete_images_only_in_revisions' => 'Also delete images that only exist in old page revisions', + 'maint_delete_images_only_in_revisions' => 'Izbriši tudi slike, ki obstajajo le v starih različicah strani', 'maint_image_cleanup_run' => 'Zaženi čiščenje', 'maint_image_cleanup_warning' => 'Najdenih je bilo :count verjetno neuporabljenih slik. Ali si prepričan, da želiš odstraniti izbrane slike?', 'maint_image_cleanup_success' => ':count verjetno neuporavljenih slik je bilo najdenih in izbrisanih!', @@ -175,10 +180,10 @@ return [ 'users_delete_named' => 'Brisanje uporabnika :userName', 'users_delete_warning' => 'Iz sistema se bo popolnoma izbrisal uporabnik z imenom \':userName\'', 'users_delete_confirm' => 'Ste prepričani, da želite izbrisati tega uporabnika?', - 'users_migrate_ownership' => 'Migrate Ownership', - 'users_migrate_ownership_desc' => 'Select a user here if you want another user to become the owner of all items currently owned by this user.', - 'users_none_selected' => 'No user selected', - 'users_delete_success' => 'User successfully removed', + 'users_migrate_ownership' => 'Prenesi lastništvo', + 'users_migrate_ownership_desc' => 'Izberite uporabnika, če želite nanj prenesti lastništvo vseh vnosov.', + 'users_none_selected' => 'Ni izbranega uporabnika', + 'users_delete_success' => 'Uporabnik uspešno odstranjen', 'users_edit' => 'Uredi uporabnika', 'users_edit_profile' => 'Uredi profil', 'users_edit_success' => 'Uporabnik uspešno posodobljen', @@ -227,6 +232,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'danščina', 'de' => 'Deutsch (Sie)', @@ -236,12 +243,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/sl/validation.php b/resources/lang/sl/validation.php index bc7242bac..9b1a5ff46 100644 --- a/resources/lang/sl/validation.php +++ b/resources/lang/sl/validation.php @@ -78,7 +78,6 @@ return [ 'string' => ':attribute mora biti najmanj :min znakov.', 'array' => ':attribute mora imeti vsaj :min elementov.', ], - 'no_double_extension' => ':attribute mora imeti samo eno razširitveno datoteko', 'not_in' => 'Izbrani atribut je neveljaven.', 'not_regex' => ':attribute oblika ni veljavna.', 'numeric' => 'Atribut mora biti število.', diff --git a/resources/lang/sv/common.php b/resources/lang/sv/common.php index 7ad2712cc..af2ace329 100644 --- a/resources/lang/sv/common.php +++ b/resources/lang/sv/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'Om du har problem, klicka på knappen ":actionText", och kopiera och klistra in den här adressen i din webbläsare:', 'email_rights' => 'Alla rättigheter är reserverade', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privacy Policy', + 'terms_of_service' => 'Terms of Service', ]; diff --git a/resources/lang/sv/settings.php b/resources/lang/sv/settings.php index 8c6caaf4a..07b1b5d4a 100644 --- a/resources/lang/sv/settings.php +++ b/resources/lang/sv/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'Startsida', 'app_homepage_desc' => 'Välj en sida att använda som startsida istället för standardvyn. Den valda sidans rättigheter kommer att ignoreras.', 'app_homepage_select' => 'Välj en sida', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', 'app_disable_comments' => 'Inaktivera kommentarer', 'app_disable_comments_toggle' => 'Inaktivera kommentarer', 'app_disable_comments_desc' => 'Inaktivera kommentarer på alla sidor i applikationen. Befintliga kommentarer visas inte.', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Danska', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/sv/validation.php b/resources/lang/sv/validation.php index 319031855..da39796bc 100644 --- a/resources/lang/sv/validation.php +++ b/resources/lang/sv/validation.php @@ -78,7 +78,6 @@ return [ 'string' => ':attribute måste vara minst :min tecken.', 'array' => ':attribute måste ha minst :min poster.', ], - 'no_double_extension' => ':attribute får bara ha ett filtillägg.', 'not_in' => 'Vald :attribute är inte giltig', 'not_regex' => 'Formatet på :attribute är ogiltigt.', 'numeric' => ':attribute måste vara ett nummer.', diff --git a/resources/lang/th/validation.php b/resources/lang/th/validation.php index 76b57a2a3..f4af9bc6f 100644 --- a/resources/lang/th/validation.php +++ b/resources/lang/th/validation.php @@ -78,7 +78,6 @@ return [ 'string' => 'The :attribute must be at least :min characters.', 'array' => 'The :attribute must have at least :min items.', ], - 'no_double_extension' => 'The :attribute must only have a single file extension.', 'not_in' => 'The selected :attribute is invalid.', 'not_regex' => 'The :attribute format is invalid.', 'numeric' => 'The :attribute must be a number.', diff --git a/resources/lang/tr/common.php b/resources/lang/tr/common.php index a252ac770..257408e58 100644 --- a/resources/lang/tr/common.php +++ b/resources/lang/tr/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => '":actionText" butonuna tıklamada sorun yaşıyorsanız, aşağıda bulunan bağlantıyı kopyalayıp tarayıcınıza yapıştırın:', 'email_rights' => 'Tüm hakları saklıdır', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privacy Policy', + 'terms_of_service' => 'Terms of Service', ]; diff --git a/resources/lang/tr/settings.php b/resources/lang/tr/settings.php index fd861c170..8ba1192c7 100755 --- a/resources/lang/tr/settings.php +++ b/resources/lang/tr/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'Ana Sayfa', 'app_homepage_desc' => 'Varsayılan görünüm yerine ana sayfada görünmesi için bir görünüm seçin. Sayfa izinleri, burada seçeceğiniz sayfalar için yok sayılacaktır.', 'app_homepage_select' => 'Bir sayfa seçin', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', 'app_disable_comments' => 'Yorumları Devre Dışı Bırak', 'app_disable_comments_toggle' => 'Yorumları devre dışı bırak', 'app_disable_comments_desc' => 'Bütün sayfalar için yorumları devre dışı bırakır.
Mevcut yorumlar gösterilmeyecektir.', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Danca', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'İbranice', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/tr/validation.php b/resources/lang/tr/validation.php index 45b7189d7..48bbef92b 100644 --- a/resources/lang/tr/validation.php +++ b/resources/lang/tr/validation.php @@ -78,7 +78,6 @@ return [ 'string' => ':attribute, en az :min karakter içermelidir.', 'array' => ':attribute, en az :min öge içermelidir.', ], - 'no_double_extension' => ':attribute, sadece tek bir dosya tipinde olmalıdır.', 'not_in' => 'Seçili :attribute geçersiz.', 'not_regex' => ':attribute formatı geçersiz.', 'numeric' => ':attribute, bir sayı olmalıdır.', diff --git a/resources/lang/uk/activities.php b/resources/lang/uk/activities.php index 51cf9db19..f16f6fe3e 100644 --- a/resources/lang/uk/activities.php +++ b/resources/lang/uk/activities.php @@ -45,5 +45,5 @@ return [ // Other 'commented_on' => 'прокоментував', - 'permissions_update' => 'updated permissions', + 'permissions_update' => 'оновив дозволи', ]; diff --git a/resources/lang/uk/common.php b/resources/lang/uk/common.php index 79fe3c24b..272b34c9a 100644 --- a/resources/lang/uk/common.php +++ b/resources/lang/uk/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'Якщо у вас виникають проблеми при натисканні кнопки ":actionText", скопіюйте та вставте URL у свій веб-браузер:', 'email_rights' => 'Всі права захищені', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privacy Policy', + 'terms_of_service' => 'Terms of Service', ]; diff --git a/resources/lang/uk/entities.php b/resources/lang/uk/entities.php index 3ca3915f4..7cfb51ed2 100644 --- a/resources/lang/uk/entities.php +++ b/resources/lang/uk/entities.php @@ -22,7 +22,7 @@ return [ 'meta_created_name' => ':user створив :timeLength', 'meta_updated' => 'Оновлено :timeLength', 'meta_updated_name' => ':user оновив :timeLength', - 'meta_owned_name' => 'Owned by :user', + 'meta_owned_name' => 'Власник :user', 'entity_select' => 'Вибір об\'єкта', 'images' => 'Зображення', 'my_recent_drafts' => 'Мої останні чернетки', @@ -40,7 +40,7 @@ return [ 'permissions_intro' => 'Після ввімкнення ці дозволи будуть мати вищий пріоритет ніж інші дозволи ролей.', 'permissions_enable' => 'Увімкнути спеціальні дозволи', 'permissions_save' => 'Зберегти дозволи', - 'permissions_owner' => 'Owner', + 'permissions_owner' => 'Власник', // Search 'search_results' => 'Результати пошуку', @@ -148,7 +148,7 @@ return [ 'chapters_create' => 'Створити новий розділ', 'chapters_delete' => 'Видалити розділ', 'chapters_delete_named' => 'Видалити розділ :chapterName', - 'chapters_delete_explain' => 'This will delete the chapter with the name \':chapterName\'. All pages that exist within this chapter will also be deleted.', + 'chapters_delete_explain' => 'Це видалить розділ під назвою \':chapterName\'. Усі сторінки, що існують у цьому розділі, також будуть видалені.', 'chapters_delete_confirm' => 'Ви впевнені, що хочете видалити цей розділ?', 'chapters_edit' => 'Редагувати розділ', 'chapters_edit_named' => 'Редагувати розділ :chapterName', @@ -210,7 +210,7 @@ return [ 'pages_revisions' => 'Версія сторінки', 'pages_revisions_named' => 'Версії сторінки для :pageName', 'pages_revision_named' => 'Версія сторінки для :pageName', - 'pages_revision_restored_from' => 'Restored from #:id; :summary', + 'pages_revision_restored_from' => 'Відновлено з #:id; :summary', 'pages_revisions_created_by' => 'Створена', 'pages_revisions_date' => 'Дата версії', 'pages_revisions_number' => '#', diff --git a/resources/lang/uk/settings.php b/resources/lang/uk/settings.php index b94ae4e8c..d767b7216 100644 --- a/resources/lang/uk/settings.php +++ b/resources/lang/uk/settings.php @@ -15,7 +15,7 @@ return [ 'app_customization' => 'Налаштування', 'app_features_security' => 'Особливості та безпека', 'app_name' => 'Назва програми', - 'app_name_desc' => 'Ця назва відображається у заголовку та у всіх листах.', + 'app_name_desc' => 'Ця назва показується у заголовку та в усіх листах.', 'app_name_header' => 'Показати назву програми в заголовку', 'app_public_access' => 'Публічнй доступ', 'app_public_access_desc' => 'Увімкнення цієї опції дозволить відвідувачам, які не увійшли в систему, отримати доступ до вмісту у вашому екземплярі BookStack.', @@ -35,8 +35,13 @@ return [ 'app_primary_color' => 'Основний колір програми', 'app_primary_color_desc' => 'Колір потрібно вказати у hex-форматі.
Залиште порожнім, щоб використати стандартний колір.', 'app_homepage' => 'Домашня сторінка програми', - 'app_homepage_desc' => 'Виберіть сторінку, яка відображатиметься на домашній сторінці замість перегляду за умовчанням. Права на сторінку не враховуються для вибраних сторінок.', + 'app_homepage_desc' => 'Виберіть сторінку, яка показуватиметься на домашній сторінці замість перегляду за замовчуванням. Права на сторінку не враховуються для вибраних сторінок.', 'app_homepage_select' => 'Вибрати сторінку', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', 'app_disable_comments' => 'Вимкнути коментарі', 'app_disable_comments_toggle' => 'Вимкнути коментарі', 'app_disable_comments_desc' => 'Вимкнути коментарі на всіх сторінках програми. Існуючі коментарі не відображаються.', @@ -52,7 +57,7 @@ return [ // Registration Settings 'reg_settings' => 'Реєстрація', - 'reg_enable' => 'Дозволити реєстрацію', + 'reg_enable' => 'Дозвіл на реєстрацію', 'reg_enable_toggle' => 'Дозволити реєстрацію', 'reg_enable_desc' => 'При включенні реєстрації відвідувач зможе зареєструватися як користувач програми. Після реєстрації їм надається єдина роль користувача за замовчуванням.', 'reg_default_role' => 'Роль користувача за умовчанням після реєстрації', @@ -60,7 +65,7 @@ return [ 'reg_email_confirmation' => 'Підтвердження електронною поштою', 'reg_email_confirmation_toggle' => 'Необхідне підтвердження електронною поштою', 'reg_confirm_email_desc' => 'Якщо використовується обмеження домену, то підтвердження електронною поштою буде потрібно, а нижче значення буде проігноровано.', - 'reg_confirm_restrict_domain' => 'Обмежити по домену', + 'reg_confirm_restrict_domain' => 'Обмеження по домену', 'reg_confirm_restrict_domain_desc' => 'Введіть список розділених комами доменів електронної пошти, до яких ви хочете обмежити реєстрацію. Користувачам буде надіслано електронне повідомлення для підтвердження своєї адреси, перш ніж дозволяти взаємодіяти з додатком.
Зауважте, що користувачі зможуть змінювати свої електронні адреси після успішної реєстрації.', 'reg_confirm_restrict_domain_placeholder' => 'Не встановлено обмежень', @@ -68,7 +73,7 @@ return [ 'maint' => 'Обслуговування', 'maint_image_cleanup' => 'Очищення зображень', 'maint_image_cleanup_desc' => "Сканує вміст сторінки та версій, щоб перевірити, які зображення та малюнки в даний час використовуються, а також які зображення зайві. Переконайтеся, що ви створили повну резервну копію бази даних та зображення, перш ніж запускати це.", - 'maint_delete_images_only_in_revisions' => 'Also delete images that only exist in old page revisions', + 'maint_delete_images_only_in_revisions' => 'Також видалити зображення, що існують лише в старих версіях сторінки', 'maint_image_cleanup_run' => 'Запустити очищення', 'maint_image_cleanup_warning' => ':count потенційно невикористаних зображень було знайдено. Ви впевнені, що хочете видалити ці зображення?', 'maint_image_cleanup_success' => ':count потенційно невикористані зображення знайдено і видалено!', @@ -80,27 +85,27 @@ return [ 'maint_send_test_email_mail_subject' => 'Перевірка електронної пошти', 'maint_send_test_email_mail_greeting' => 'Доставляння електронної пошти працює!', 'maint_send_test_email_mail_text' => 'Вітаємо! Оскільки ви отримали цього листа, поштова скринька налаштована правильно.', - 'maint_recycle_bin_desc' => 'Deleted shelves, books, chapters & pages are sent to the recycle bin so they can be restored or permanently deleted. Older items in the recycle bin may be automatically removed after a while depending on system configuration.', - 'maint_recycle_bin_open' => 'Open Recycle Bin', + 'maint_recycle_bin_desc' => 'Видалені полиці, книги, розділи та сторінки попадають кошик, щоб їх можна було відновити або видалити остаточно. Старіші елементи з кошика можна автоматично видаляти через деякий час, залежно від налаштувань системи.', + 'maint_recycle_bin_open' => 'Відкрити кошик', // Recycle Bin - 'recycle_bin' => 'Recycle Bin', - 'recycle_bin_desc' => 'Here you can restore items that have been deleted or choose to permanently remove them from the system. This list is unfiltered unlike similar activity lists in the system where permission filters are applied.', - 'recycle_bin_deleted_item' => 'Deleted Item', - 'recycle_bin_deleted_by' => 'Deleted By', - 'recycle_bin_deleted_at' => 'Deletion Time', - 'recycle_bin_permanently_delete' => 'Permanently Delete', - 'recycle_bin_restore' => 'Restore', - 'recycle_bin_contents_empty' => 'The recycle bin is currently empty', - 'recycle_bin_empty' => 'Empty Recycle Bin', - 'recycle_bin_empty_confirm' => 'This will permanently destroy all items in the recycle bin including content contained within each item. Are you sure you want to empty the recycle bin?', - 'recycle_bin_destroy_confirm' => 'This action will permanently delete this item, along with any child elements listed below, from the system and you will not be able to restore this content. Are you sure you want to permanently delete this item?', - 'recycle_bin_destroy_list' => 'Items to be Destroyed', - 'recycle_bin_restore_list' => 'Items to be Restored', - 'recycle_bin_restore_confirm' => 'This action will restore the deleted item, including any child elements, to their original location. If the original location has since been deleted, and is now in the recycle bin, the parent item will also need to be restored.', - 'recycle_bin_restore_deleted_parent' => 'The parent of this item has also been deleted. These will remain deleted until that parent is also restored.', - 'recycle_bin_destroy_notification' => 'Deleted :count total items from the recycle bin.', - 'recycle_bin_restore_notification' => 'Restored :count total items from the recycle bin.', + 'recycle_bin' => 'Кошик', + 'recycle_bin_desc' => 'Тут ви можете відновити видалені елементи, або назавжди видалити їх із системи. Цей список нефільтрований, на відміну від подібних списків активності в системі, де застосовуються фільтри дозволів.', + 'recycle_bin_deleted_item' => 'Виадлений елемент', + '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_destroy_notification' => 'Видалено :count елементів із кошика.', + 'recycle_bin_restore_notification' => 'Відновлено :count елементів із кошика.', // Audit Log 'audit' => 'Журнал аудиту', @@ -111,7 +116,7 @@ return [ 'audit_deleted_item_name' => 'Назва: :name', 'audit_table_user' => 'Користувач', 'audit_table_event' => 'Подія', - 'audit_table_related' => 'Related Item or Detail', + 'audit_table_related' => 'Пов’язаний елемент', 'audit_table_date' => 'Дата активності', 'audit_date_from' => 'Діапазон дат від', 'audit_date_to' => 'Діапазон дат до', @@ -157,7 +162,7 @@ return [ 'user_profile' => 'Профіль користувача', 'users_add_new' => 'Додати нового користувача', 'users_search' => 'Пошук користувачів', - 'users_latest_activity' => 'Latest Activity', + 'users_latest_activity' => 'Остання активність', 'users_details' => 'Відомості про користувача', 'users_details_desc' => 'Встановіть ім\'я та електронну адресу для цього користувача. Адреса електронної пошти буде використана для входу до програми.', 'users_details_desc_no_email' => 'Встановіть ім\'я для цього користувача, щоб інші могли його розпізнати.', @@ -175,10 +180,10 @@ return [ 'users_delete_named' => 'Видалити користувача :userName', 'users_delete_warning' => 'Це повне видалення цього користувача з ім\'ям \':userName\' з системи.', 'users_delete_confirm' => 'Ви впевнені, що хочете видалити цього користувача?', - 'users_migrate_ownership' => 'Migrate Ownership', - 'users_migrate_ownership_desc' => 'Select a user here if you want another user to become the owner of all items currently owned by this user.', - 'users_none_selected' => 'No user selected', - 'users_delete_success' => 'User successfully removed', + 'users_migrate_ownership' => 'Право власності при міграції', + 'users_migrate_ownership_desc' => 'Виберіть тут користувача, якщо ви хочете, щоб інший користувач став власником усіх елементів, які зараз належать цьому користувачеві.', + 'users_none_selected' => 'Не вибрано жодного користувача', + 'users_delete_success' => 'Користувача успішно видалено', 'users_edit' => 'Редагувати користувача', 'users_edit_profile' => 'Редагувати профіль', 'users_edit_success' => 'Користувача успішно оновлено', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/uk/validation.php b/resources/lang/uk/validation.php index 51b9a0999..77df1ed4e 100644 --- a/resources/lang/uk/validation.php +++ b/resources/lang/uk/validation.php @@ -78,7 +78,6 @@ return [ 'string' => 'Текст в полі :attribute повинен містити не менше :min символів.', 'array' => 'Поле :attribute повинне містити не менше :min елементів.', ], - 'no_double_extension' => 'Поле :attribute повинне містити тільки одне розширення файлу.', 'not_in' => 'Вибране для :attribute значення не коректне.', 'not_regex' => 'Формат поля :attribute не вірний.', 'numeric' => 'Поле :attribute повинно містити число.', @@ -90,7 +89,7 @@ return [ 'required_without' => 'Поле :attribute є обов\'язковим для заповнення, коли :values не вказано.', 'required_without_all' => 'Поле :attribute є обов\'язковим для заповнення, коли :values не вказано.', 'same' => 'Поля :attribute та :other мають збігатися.', - 'safe_url' => 'The provided link may not be safe.', + 'safe_url' => 'Надане посилання може бути небезпечним.', 'size' => [ 'numeric' => 'Поле :attribute має бути довжини :size.', 'file' => 'Файл в полі :attribute має бути розміром :size кілобайт.', diff --git a/resources/lang/vi/activities.php b/resources/lang/vi/activities.php index 42b34f383..85a850e27 100644 --- a/resources/lang/vi/activities.php +++ b/resources/lang/vi/activities.php @@ -45,5 +45,5 @@ return [ // Other 'commented_on' => 'đã bình luận về', - 'permissions_update' => 'updated permissions', + 'permissions_update' => 'các quyền đã được cập nhật', ]; diff --git a/resources/lang/vi/common.php b/resources/lang/vi/common.php index d1dc8a048..dff393ba8 100644 --- a/resources/lang/vi/common.php +++ b/resources/lang/vi/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => 'Nếu bạn đang có vấn đề trong việc bấm nút ":actionText", sao chép và dán địa chỉ URL dưới đây vào trình duyệt web:', 'email_rights' => 'Bản quyền đã được bảo hộ', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privacy Policy', + 'terms_of_service' => 'Terms of Service', ]; diff --git a/resources/lang/vi/settings.php b/resources/lang/vi/settings.php index 67fcb1285..6f282a568 100644 --- a/resources/lang/vi/settings.php +++ b/resources/lang/vi/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'Trang chủ Ứng dụng', 'app_homepage_desc' => 'Chọn hiển thị để hiện tại trang chủ thay cho hiển thị mặc định. Quyền cho trang được bỏ qua cho các trang được chọn.', 'app_homepage_select' => 'Chọn một trang', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', 'app_disable_comments' => 'Tắt bình luận', 'app_disable_comments_toggle' => 'Tắt bình luận', 'app_disable_comments_desc' => 'Tắt các bình luận trên tất cả các trang của ứng dụng.
Các bình luận đã tồn tại sẽ không được hiển thị.', @@ -86,12 +91,12 @@ return [ // Recycle Bin 'recycle_bin' => 'Thùng Rác', 'recycle_bin_desc' => 'Here you can restore items that have been deleted or choose to permanently remove them from the system. This list is unfiltered unlike similar activity lists in the system where permission filters are applied.', - 'recycle_bin_deleted_item' => 'Deleted Item', + 'recycle_bin_deleted_item' => 'Mục Đã Xóa', 'recycle_bin_deleted_by' => 'Xóa Bởi', 'recycle_bin_deleted_at' => 'Thời điểm Xóa', 'recycle_bin_permanently_delete' => 'Xóa Vĩnh viễn', 'recycle_bin_restore' => 'Khôi phục', - 'recycle_bin_contents_empty' => 'The recycle bin is currently empty', + 'recycle_bin_contents_empty' => 'Thùng rác hiện đang trống', 'recycle_bin_empty' => 'Dọn dẹp Thùng Rác', 'recycle_bin_empty_confirm' => 'This will permanently destroy all items in the recycle bin including content contained within each item. Are you sure you want to empty the recycle bin?', 'recycle_bin_destroy_confirm' => 'This action will permanently delete this item, along with any child elements listed below, from the system and you will not be able to restore this content. Are you sure you want to permanently delete this item?', @@ -106,15 +111,15 @@ return [ 'audit' => 'Audit Log', 'audit_desc' => 'This audit log displays a list of activities tracked in the system. This list is unfiltered unlike similar activity lists in the system where permission filters are applied.', 'audit_event_filter' => 'Event Filter', - 'audit_event_filter_no_filter' => 'No Filter', - 'audit_deleted_item' => 'Deleted Item', - 'audit_deleted_item_name' => 'Name: :name', + 'audit_event_filter_no_filter' => 'Không Lọc', + 'audit_deleted_item' => 'Mục Đã Xóa', + 'audit_deleted_item_name' => 'Tên: :name', 'audit_table_user' => 'Người dùng', - 'audit_table_event' => 'Event', + 'audit_table_event' => 'Sự kiện', 'audit_table_related' => 'Related Item or Detail', - 'audit_table_date' => 'Activity Date', - 'audit_date_from' => 'Date Range From', - 'audit_date_to' => 'Date Range To', + 'audit_table_date' => 'Ngày hoạt động', + 'audit_date_from' => 'Ngày từ khoảng', + 'audit_date_to' => 'Ngày đến khoảng', // Role Settings 'roles' => 'Quyền', @@ -157,7 +162,7 @@ return [ 'user_profile' => 'Hồ sơ người dùng', 'users_add_new' => 'Thêm người dùng mới', 'users_search' => 'Tìm kiếm người dùng', - 'users_latest_activity' => 'Latest Activity', + 'users_latest_activity' => 'Hoạt động mới nhất', 'users_details' => 'Chi tiết người dùng', 'users_details_desc' => 'Hiển thị tên và địa chỉ email cho người dùng này. Địa chỉ email sẽ được sử dụng để đăng nhập vào ứng dụng.', 'users_details_desc_no_email' => 'Đặt tên cho người dùng này để giúp người dùng khác nhận ra họ.', @@ -177,8 +182,8 @@ return [ 'users_delete_confirm' => 'Bạn có chắc muốn xóa người dùng này không?', 'users_migrate_ownership' => 'Migrate Ownership', 'users_migrate_ownership_desc' => 'Select a user here if you want another user to become the owner of all items currently owned by this user.', - 'users_none_selected' => 'No user selected', - 'users_delete_success' => 'User successfully removed', + 'users_none_selected' => 'Chưa chọn người dùng', + 'users_delete_success' => 'Người dùng đã được xóa thành công', 'users_edit' => 'Sửa người dùng', 'users_edit_profile' => 'Sửa Hồ sơ', 'users_edit_success' => 'Người dùng được cập nhật thành công', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => 'Đan Mạch', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/vi/validation.php b/resources/lang/vi/validation.php index c00207175..bcfb178fb 100644 --- a/resources/lang/vi/validation.php +++ b/resources/lang/vi/validation.php @@ -78,7 +78,6 @@ return [ 'string' => ':attribute phải có tối thiểu :min ký tự.', 'array' => ':attribute phải có tối thiểu :min mục.', ], - 'no_double_extension' => ':attribute chỉ được có một định dạng mở rộng duy nhất.', 'not_in' => ':attribute đã chọn không hợp lệ.', 'not_regex' => 'Định dạng của :attribute không hợp lệ.', 'numeric' => ':attribute phải là một số.', diff --git a/resources/lang/zh_CN/common.php b/resources/lang/zh_CN/common.php index e96edaf1e..c94a0d30f 100644 --- a/resources/lang/zh_CN/common.php +++ b/resources/lang/zh_CN/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => '如果您无法点击“:actionText”按钮,请将下面的网址复制到您的浏览器中打开:', 'email_rights' => '版权所有', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => '隐私政策', + 'terms_of_service' => '服务条款', ]; diff --git a/resources/lang/zh_CN/settings.php b/resources/lang/zh_CN/settings.php index 5d58ace2c..09359b5cd 100755 --- a/resources/lang/zh_CN/settings.php +++ b/resources/lang/zh_CN/settings.php @@ -37,6 +37,11 @@ return [ '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' => '在站点的所有页面上禁用评论,现有评论也不会显示出来。', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => '保加利亚语', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => '丹麦', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => 'עברית', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => '挪威语 (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/zh_CN/validation.php b/resources/lang/zh_CN/validation.php index 8bb8a207a..72b0d594e 100644 --- a/resources/lang/zh_CN/validation.php +++ b/resources/lang/zh_CN/validation.php @@ -78,7 +78,6 @@ return [ 'string' => ':attribute 至少为:min个字符。', 'array' => ':attribute 至少有:min项。', ], - 'no_double_extension' => ':attribute 必须具有一个扩展名。', 'not_in' => '选中的 :attribute 无效。', 'not_regex' => ':attribute 格式错误。', 'numeric' => ':attribute 必须是一个数。', diff --git a/resources/lang/zh_TW/common.php b/resources/lang/zh_TW/common.php index 1d26ded29..2588e57a1 100644 --- a/resources/lang/zh_TW/common.php +++ b/resources/lang/zh_TW/common.php @@ -77,4 +77,9 @@ return [ // Email Content 'email_action_help' => '如果您無法點選“:actionText”按鈕,請將下面的網址複製到您的瀏覽器中打開:', 'email_rights' => '版權所有', + + // Footer Link Options + // Not directly used but available for convenience to users. + 'privacy_policy' => 'Privacy Policy', + 'terms_of_service' => 'Terms of Service', ]; diff --git a/resources/lang/zh_TW/settings.php b/resources/lang/zh_TW/settings.php index 50ef79cbb..429cba473 100644 --- a/resources/lang/zh_TW/settings.php +++ b/resources/lang/zh_TW/settings.php @@ -37,6 +37,11 @@ return [ 'app_homepage' => 'App首頁', 'app_homepage_desc' => '選擇要做為首頁的頁面,這將會替換預設首頁,而且這個頁面的權限設定將被忽略。', 'app_homepage_select' => '預設首頁選擇', + 'app_footer_links' => 'Footer Links', + 'app_footer_links_desc' => 'Add links to show within the site footer. These will be displayed at the bottom of most pages, including those that do not require login. You can use a label of "trans::" to use system-defined translations. For example: Using "trans::common.privacy_policy" will provide the translated text "Privacy Policy" and "trans::common.terms_of_service" will provide the translated text "Terms of Service".', + 'app_footer_links_label' => 'Link Label', + 'app_footer_links_url' => 'Link URL', + 'app_footer_links_add' => 'Add Footer Link', 'app_disable_comments' => '關閉評論', 'app_disable_comments_toggle' => '禁用評論', 'app_disable_comments_desc' => '在App的所有頁面上關閉評論,已經存在的評論也不會顯示。', @@ -226,6 +231,8 @@ return [ 'en' => 'English', 'ar' => 'العربية', 'bg' => 'Bǎlgarski', + 'bs' => 'Bosanski', + 'ca' => 'Català', 'cs' => 'Česky', 'da' => '丹麥', 'de' => 'Deutsch (Sie)', @@ -235,12 +242,15 @@ return [ 'fr' => 'Français', 'he' => '希伯來語', 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', 'it' => 'Italian', 'ja' => '日本語', 'ko' => '한국어', + 'lv' => 'Latviešu Valoda', 'nl' => 'Nederlands', 'nb' => 'Norsk (Bokmål)', 'pl' => 'Polski', + 'pt' => 'Português', 'pt_BR' => 'Português do Brasil', 'ru' => 'Русский', 'sk' => 'Slovensky', diff --git a/resources/lang/zh_TW/validation.php b/resources/lang/zh_TW/validation.php index 7a46288ad..f8a7dac63 100644 --- a/resources/lang/zh_TW/validation.php +++ b/resources/lang/zh_TW/validation.php @@ -78,7 +78,6 @@ return [ 'string' => ':attribute 至少為:min個字元。', 'array' => ':attribute 至少有:min項。', ], - 'no_double_extension' => 'The :attribute必須僅具有一個文件擴展名。', 'not_in' => '選中的 :attribute 無效。', 'not_regex' => 'The :attribute格式無效。', 'numeric' => ':attribute 必須是一個數。', diff --git a/resources/sass/_components.scss b/resources/sass/_components.scss index ede26c51c..ad6304694 100644 --- a/resources/sass/_components.scss +++ b/resources/sass/_components.scss @@ -783,6 +783,6 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group { .custom-select-input { max-width: 280px; - border: 1px solid #DDD; - border-radius: 4px; + border: 1px solid #D4D4D4; + border-radius: 3px; } \ No newline at end of file diff --git a/resources/sass/_header.scss b/resources/sass/_header.scss index 246ef4b5b..f371e0410 100644 --- a/resources/sass/_header.scss +++ b/resources/sass/_header.scss @@ -3,7 +3,7 @@ */ header .grid { - grid-template-columns: auto min-content auto; + grid-template-columns: minmax(max-content, 2fr) 1fr minmax(max-content, 2fr); } @include smaller-than($l) { @@ -77,9 +77,6 @@ header { } -.header-search { - display: inline-block; -} header .search-box { display: inline-block; margin-top: 10px; @@ -272,7 +269,7 @@ header .search-box { .dropdown-search { position: relative; .dropdown-search-toggle { - padding: 6px; + padding: $-xs; border: 1px solid transparent; border-radius: 4px; &:hover { @@ -284,6 +281,14 @@ header .search-box { } } +.dropdown-search-toggle.compact { + padding: $-xxs $-xs; + .avatar { + height: 22px; + width: 22px; + } +} + .faded { a, button, span, span > div { color: #666; diff --git a/resources/sass/_html.scss b/resources/sass/_html.scss index 026295669..1d5defa97 100644 --- a/resources/sass/_html.scss +++ b/resources/sass/_html.scss @@ -25,7 +25,6 @@ body { line-height: 1.6; @include lightDark(color, #444, #AAA); -webkit-font-smoothing: antialiased; - background-color: #F2F2F2; height: 100%; display: flex; flex-direction: column; diff --git a/resources/sass/_layout.scss b/resources/sass/_layout.scss index c12cae256..60205eaaa 100644 --- a/resources/sass/_layout.scss +++ b/resources/sass/_layout.scss @@ -256,6 +256,7 @@ body.flexbox { .tri-layout-middle { grid-area: b; padding-top: $-m; + min-width: 0; } } @include smaller-than($xxl) { diff --git a/resources/sass/_lists.scss b/resources/sass/_lists.scss index a3a58e6c6..d6ea66350 100644 --- a/resources/sass/_lists.scss +++ b/resources/sass/_lists.scss @@ -430,6 +430,9 @@ ul.pagination { flex: 1; text-align: start; } + > .content { + min-width: 0; + } &:not(.no-hover) { cursor: pointer; } diff --git a/resources/sass/_tinymce.scss b/resources/sass/_tinymce.scss index dfaf6683e..05f48b073 100644 --- a/resources/sass/_tinymce.scss +++ b/resources/sass/_tinymce.scss @@ -63,8 +63,14 @@ } .page-content.mce-content-body { - padding-top: 16px; + padding-block-start: 1rem; + padding-block-end: 1rem; outline: none; + display: block; +} + +.page-content.mce-content-body > :last-child { + margin-bottom: 3rem; } // Fix to prevent 'No color' option from not being clickable. diff --git a/resources/sass/_variables.scss b/resources/sass/_variables.scss index d0d1f27d3..42207528b 100644 --- a/resources/sass/_variables.scss +++ b/resources/sass/_variables.scss @@ -28,7 +28,7 @@ $-xs: 6px; $-xxs: 3px; // List of our spacing sizes -$spacing: (('none', 0), ('xxs', $-xxs), ('xs', $-xs), ('s', $-s), ('m', $-m), ('l', $-l), ('xl', $-xl), ('xxl', $-xxl)); +$spacing: (('none', 0), ('xxs', $-xxs), ('xs', $-xs), ('s', $-s), ('m', $-m), ('l', $-l), ('xl', $-xl), ('xxl', $-xxl), ('auto', auto)); // Fonts $text: -apple-system, BlinkMacSystemFont, diff --git a/resources/sass/export-styles.scss b/resources/sass/export-styles.scss index 6d9a1a718..278e5b6c5 100644 --- a/resources/sass/export-styles.scss +++ b/resources/sass/export-styles.scss @@ -19,6 +19,7 @@ body { font-family: 'DejaVu Sans', -apple-system, BlinkMacSystemFont, "Segoe UI", "Oxygen", "Ubuntu", "Roboto", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; margin: 0; padding: 0; + display: block; } table { diff --git a/resources/sass/styles.scss b/resources/sass/styles.scss index 614b7f295..743db9888 100644 --- a/resources/sass/styles.scss +++ b/resources/sass/styles.scss @@ -193,8 +193,12 @@ $btt-size: 40px; .entity-list-item p { margin-bottom: 0; } + .entity-list-item:focus { + outline: 2px dotted var(--color-primary); + outline-offset: -4px; + } .entity-list-item.selected { - background-color: rgba(0, 0, 0, 0.05) !important; + @include lightDark(background-color, rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.05)); } .loading { height: 400px; diff --git a/resources/views/books/list-item.blade.php b/resources/views/books/list-item.blade.php index 17cf4c71f..a3ff0971f 100644 --- a/resources/views/books/list-item.blade.php +++ b/resources/views/books/list-item.blade.php @@ -5,7 +5,7 @@

{{ $book->name }}

-

{{ $book->getExcerpt() }}

+

{{ $book->description }}

\ No newline at end of file diff --git a/resources/views/common/header.blade.php b/resources/views/common/header.blade.php index 80e79410a..52f6b8cbb 100644 --- a/resources/views/common/header.blade.php +++ b/resources/views/common/header.blade.php @@ -13,7 +13,7 @@
@icon('more')
-
diff --git a/resources/views/users/delete.blade.php b/resources/views/users/delete.blade.php index aba6f5cc1..7b1d38d34 100644 --- a/resources/views/users/delete.blade.php +++ b/resources/views/users/delete.blade.php @@ -20,7 +20,7 @@

{{ trans('settings.users_migrate_ownership_desc') }}

- @include('components.user-select', ['name' => 'new_owner_id', 'user' => null]) + @include('components.user-select', ['name' => 'new_owner_id', 'user' => null, 'compact' => false])
diff --git a/routes/web.php b/routes/web.php index 64d08e165..9d482dc41 100644 --- a/routes/web.php +++ b/routes/web.php @@ -99,7 +99,7 @@ Route::group(['middleware' => 'auth'], function () { }); // User Profile routes - Route::get('/user/{userId}', 'UserController@showProfilePage'); + Route::get('/user/{slug}', 'UserProfileController@show'); // Image routes Route::get('/images/gallery', 'Images\GalleryImageController@list'); @@ -217,12 +217,12 @@ Route::group(['middleware' => 'auth'], function () { }); // Social auth routes -Route::get('/login/service/{socialDriver}', 'Auth\SocialController@getSocialLogin'); -Route::get('/login/service/{socialDriver}/callback', 'Auth\SocialController@socialCallback'); +Route::get('/login/service/{socialDriver}', 'Auth\SocialController@login'); +Route::get('/login/service/{socialDriver}/callback', 'Auth\SocialController@callback'); Route::group(['middleware' => 'auth'], function () { - Route::get('/login/service/{socialDriver}/detach', 'Auth\SocialController@detachSocialAccount'); + Route::get('/login/service/{socialDriver}/detach', 'Auth\SocialController@detach'); }); -Route::get('/register/service/{socialDriver}', 'Auth\SocialController@socialRegister'); +Route::get('/register/service/{socialDriver}', 'Auth\SocialController@register'); // Login/Logout routes Route::get('/login', 'Auth\LoginController@getLogin'); diff --git a/tests/AuditLogTest.php b/tests/AuditLogTest.php index 3dc6fd7c2..55a458786 100644 --- a/tests/AuditLogTest.php +++ b/tests/AuditLogTest.php @@ -4,6 +4,7 @@ use BookStack\Actions\Activity; use BookStack\Actions\ActivityService; use BookStack\Actions\ActivityType; use BookStack\Auth\UserRepo; +use BookStack\Entities\Models\Chapter; use BookStack\Entities\Tools\TrashCan; use BookStack\Entities\Models\Page; use BookStack\Entities\Repos\PageRepo; @@ -117,4 +118,26 @@ class AuditLogTest extends TestCase $resp->assertDontSeeText($page->name); } + public function test_user_filter() + { + $admin = $this->getAdmin(); + $editor = $this->getEditor(); + $this->actingAs($admin); + $page = Page::query()->first(); + $this->activityService->addForEntity($page, ActivityType::PAGE_CREATE); + + $this->actingAs($editor); + $chapter = Chapter::query()->first(); + $this->activityService->addForEntity($chapter, ActivityType::CHAPTER_UPDATE); + + $resp = $this->actingAs($admin)->get('settings/audit?user=' . $admin->id); + $resp->assertSeeText($page->name); + $resp->assertDontSeeText($chapter->name); + + $resp = $this->actingAs($admin)->get('settings/audit?user=' . $editor->id); + $resp->assertSeeText($chapter->name); + $resp->assertDontSeeText($page->name); + + } + } \ No newline at end of file diff --git a/tests/Auth/AuthTest.php b/tests/Auth/AuthTest.php index a0de7f803..f88fc1904 100644 --- a/tests/Auth/AuthTest.php +++ b/tests/Auth/AuthTest.php @@ -9,6 +9,7 @@ use BookStack\Settings\SettingService; use DB; use Hash; use Illuminate\Support\Facades\Notification; +use Illuminate\Support\Str; use Tests\BrowserKitTest; class AuthTest extends BrowserKitTest @@ -221,6 +222,7 @@ class AuthTest extends BrowserKitTest public function test_user_creation() { + /** @var User $user */ $user = factory(User::class)->make(); $adminRole = Role::getRole('admin'); @@ -234,8 +236,11 @@ class AuthTest extends BrowserKitTest ->type($user->password, '#password-confirm') ->press('Save') ->seePageIs('/settings/users') - ->seeInDatabase('users', $user->toArray()) + ->seeInDatabase('users', $user->only(['name', 'email'])) ->see($user->name); + + $user->refresh(); + $this->assertStringStartsWith(Str::slug($user->name), $user->slug); } public function test_user_updating() @@ -252,6 +257,9 @@ class AuthTest extends BrowserKitTest ->seePageIs('/settings/users') ->seeInDatabase('users', ['id' => $user->id, 'name' => 'Barry Scott', 'password' => $password]) ->notSeeInDatabase('users', ['name' => $user->name]); + + $user->refresh(); + $this->assertStringStartsWith(Str::slug($user->name), $user->slug); } public function test_user_password_update() diff --git a/tests/Auth/LdapTest.php b/tests/Auth/LdapTest.php index 3cb39ca2c..840dfd630 100644 --- a/tests/Auth/LdapTest.php +++ b/tests/Auth/LdapTest.php @@ -4,6 +4,7 @@ use BookStack\Auth\Access\LdapService; use BookStack\Auth\Role; use BookStack\Auth\Access\Ldap; use BookStack\Auth\User; +use BookStack\Exceptions\LdapException; use Mockery\MockInterface; use Tests\BrowserKitTest; @@ -40,6 +41,14 @@ class LdapTest extends BrowserKitTest $this->mockUser = factory(User::class)->make(); } + protected function runFailedAuthLogin() + { + $this->commonLdapMocks(1, 1, 1, 1, 1); + $this->mockLdap->shouldReceive('searchAndGetEntries')->times(1) + ->andReturn(['count' => 0]); + $this->post('/login', ['username' => 'timmyjenkins', 'password' => 'cattreedog']); + } + protected function mockEscapes($times = 1) { $this->mockLdap->shouldReceive('escape')->times($times)->andReturnUsing(function($val) { @@ -550,6 +559,22 @@ class LdapTest extends BrowserKitTest ]); } + public function test_start_tls_called_if_option_set() + { + config()->set(['services.ldap.start_tls' => true]); + $this->mockLdap->shouldReceive('startTls')->once()->andReturn(true); + $this->runFailedAuthLogin(); + } + + public function test_connection_fails_if_tls_fails() + { + config()->set(['services.ldap.start_tls' => true]); + $this->mockLdap->shouldReceive('startTls')->once()->andReturn(false); + $this->commonLdapMocks(1, 1, 0, 0, 0); + $this->post('/login', ['username' => 'timmyjenkins', 'password' => 'cattreedog']); + $this->assertResponseStatus(500); + } + public function test_ldap_attributes_can_be_binary_decoded_if_marked() { config()->set(['services.ldap.id_attribute' => 'BIN;uid']); @@ -640,12 +665,7 @@ class LdapTest extends BrowserKitTest { $log = $this->withTestLogger(); config()->set(['logging.failed_login.message' => 'Failed login for %u']); - - $this->commonLdapMocks(1, 1, 1, 1, 1); - $this->mockLdap->shouldReceive('searchAndGetEntries')->times(1) - ->andReturn(['count' => 0]); - - $this->post('/login', ['username' => 'timmyjenkins', 'password' => 'cattreedog']); + $this->runFailedAuthLogin(); $this->assertTrue($log->hasWarningThatContains('Failed login for timmyjenkins')); } } diff --git a/tests/Auth/SocialAuthTest.php b/tests/Auth/SocialAuthTest.php index d448b567e..4369d8b7a 100644 --- a/tests/Auth/SocialAuthTest.php +++ b/tests/Auth/SocialAuthTest.php @@ -17,8 +17,7 @@ class SocialAuthTest extends TestCase $this->setSettings(['registration-enabled' => 'true']); config(['GOOGLE_APP_ID' => 'abc123', 'GOOGLE_APP_SECRET' => '123abc', 'APP_URL' => 'http://localhost']); - $mockSocialite = Mockery::mock(Factory::class); - $this->app[Factory::class] = $mockSocialite; + $mockSocialite = $this->mock(Factory::class); $mockSocialDriver = Mockery::mock(Provider::class); $mockSocialUser = Mockery::mock(\Laravel\Socialite\Contracts\User::class); @@ -46,8 +45,7 @@ class SocialAuthTest extends TestCase 'APP_URL' => 'http://localhost' ]); - $mockSocialite = Mockery::mock(Factory::class); - $this->app[Factory::class] = $mockSocialite; + $mockSocialite = $this->mock(Factory::class); $mockSocialDriver = Mockery::mock(Provider::class); $mockSocialUser = Mockery::mock(\Laravel\Socialite\Contracts\User::class); @@ -93,8 +91,7 @@ class SocialAuthTest extends TestCase ]); $user = factory(User::class)->make(); - $mockSocialite = Mockery::mock(Factory::class); - $this->app[Factory::class] = $mockSocialite; + $mockSocialite = $this->mock(Factory::class); $mockSocialDriver = Mockery::mock(Provider::class); $mockSocialUser = Mockery::mock(\Laravel\Socialite\Contracts\User::class); @@ -132,8 +129,7 @@ class SocialAuthTest extends TestCase ]); $user = factory(User::class)->make(); - $mockSocialite = Mockery::mock(Factory::class); - $this->app[Factory::class] = $mockSocialite; + $mockSocialite = $this->mock(Factory::class); $mockSocialDriver = Mockery::mock(Provider::class); $mockSocialUser = Mockery::mock(\Laravel\Socialite\Contracts\User::class); @@ -169,8 +165,7 @@ class SocialAuthTest extends TestCase $this->setSettings(['registration-enabled' => 'true']); config(['GITHUB_APP_ID' => 'abc123', 'GITHUB_APP_SECRET' => '123abc', 'APP_URL' => 'http://localhost']); - $mockSocialite = Mockery::mock(Factory::class); - $this->app[Factory::class] = $mockSocialite; + $mockSocialite = $this->mock(Factory::class); $mockSocialDriver = Mockery::mock(Provider::class); $mockSocialUser = Mockery::mock(\Laravel\Socialite\Contracts\User::class); diff --git a/tests/Auth/UserInviteTest.php b/tests/Auth/UserInviteTest.php index f2a1d0e78..b6f521eaa 100644 --- a/tests/Auth/UserInviteTest.php +++ b/tests/Auth/UserInviteTest.php @@ -18,13 +18,15 @@ class UserInviteTest extends TestCase Notification::fake(); $admin = $this->getAdmin(); - $this->actingAs($admin)->post('/settings/users/create', [ + $email = Str::random(16) . '@example.com'; + $resp = $this->actingAs($admin)->post('/settings/users/create', [ 'name' => 'Barry', - 'email' => 'tester@example.com', + 'email' => $email, 'send_invite' => 'true', ]); + $resp->assertRedirect('/settings/users'); - $newUser = User::query()->where('email', '=', 'tester@example.com')->orderBy('id', 'desc')->first(); + $newUser = User::query()->where('email', '=', $email)->orderBy('id', 'desc')->first(); Notification::assertSentTo($newUser, UserInvite::class); $this->assertDatabaseHas('user_invites', [ diff --git a/tests/BrowserKitTest.php b/tests/BrowserKitTest.php index 6c332a984..45e20b5e2 100644 --- a/tests/BrowserKitTest.php +++ b/tests/BrowserKitTest.php @@ -4,7 +4,6 @@ use BookStack\Auth\User; use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Chapter; use BookStack\Entities\Models\Entity; -use BookStack\Auth\Role; use BookStack\Auth\Permissions\PermissionService; use BookStack\Entities\Models\Page; use BookStack\Settings\SettingService; @@ -120,7 +119,7 @@ abstract class BrowserKitTest extends TestCase */ protected function seeInNthElement($element, $position, $text, $negate = false) { - $method = $negate ? 'assertNotRegExp' : 'assertRegExp'; + $method = $negate ? 'assertDoesNotMatchRegularExpression' : 'assertMatchesRegularExpression'; $rawPattern = preg_quote($text, '/'); diff --git a/tests/Commands/AddAdminCommandTest.php b/tests/Commands/AddAdminCommandTest.php new file mode 100644 index 000000000..6b03c86f9 --- /dev/null +++ b/tests/Commands/AddAdminCommandTest.php @@ -0,0 +1,25 @@ + 'admintest@example.com', + '--name' => 'Admin Test', + '--password' => 'testing-4', + ]); + $this->assertTrue($exitCode === 0, 'Command executed successfully'); + + $this->assertDatabaseHas('users', [ + 'email' => 'admintest@example.com', + 'name' => 'Admin Test' + ]); + + $this->assertTrue(User::query()->where('email', '=', 'admintest@example.com')->first()->hasSystemRole('admin'), 'User has admin role as expected'); + $this->assertTrue(\Auth::attempt(['email' => 'admintest@example.com', 'password' => 'testing-4']), 'Password stored as expected'); + } +} \ No newline at end of file diff --git a/tests/Commands/ClearActivityCommandTest.php b/tests/Commands/ClearActivityCommandTest.php new file mode 100644 index 000000000..751a165c6 --- /dev/null +++ b/tests/Commands/ClearActivityCommandTest.php @@ -0,0 +1,33 @@ +asEditor(); + $page = Page::first(); + \Activity::addForEntity($page, ActivityType::PAGE_UPDATE); + + $this->assertDatabaseHas('activities', [ + 'type' => 'page_update', + 'entity_id' => $page->id, + 'user_id' => $this->getEditor()->id + ]); + + + DB::rollBack(); + $exitCode = \Artisan::call('bookstack:clear-activity'); + DB::beginTransaction(); + $this->assertTrue($exitCode === 0, 'Command executed successfully'); + + + $this->assertDatabaseMissing('activities', [ + 'type' => 'page_update' + ]); + } +} \ No newline at end of file diff --git a/tests/Commands/ClearRevisionsCommandTest.php b/tests/Commands/ClearRevisionsCommandTest.php new file mode 100644 index 000000000..e0293faf1 --- /dev/null +++ b/tests/Commands/ClearRevisionsCommandTest.php @@ -0,0 +1,47 @@ +asEditor(); + $pageRepo = app(PageRepo::class); + $page = Page::first(); + $pageRepo->update($page, ['name' => 'updated page', 'html' => '

new content

', 'summary' => 'page revision testing']); + $pageRepo->updatePageDraft($page, ['name' => 'updated page', 'html' => '

new content in draft

', 'summary' => 'page revision testing']); + + $this->assertDatabaseHas('page_revisions', [ + 'page_id' => $page->id, + 'type' => 'version' + ]); + $this->assertDatabaseHas('page_revisions', [ + 'page_id' => $page->id, + 'type' => 'update_draft' + ]); + + $exitCode = Artisan::call('bookstack:clear-revisions'); + $this->assertTrue($exitCode === 0, 'Command executed successfully'); + + $this->assertDatabaseMissing('page_revisions', [ + 'page_id' => $page->id, + 'type' => 'version' + ]); + $this->assertDatabaseHas('page_revisions', [ + 'page_id' => $page->id, + 'type' => 'update_draft' + ]); + + $exitCode = Artisan::call('bookstack:clear-revisions', ['--all' => true]); + $this->assertTrue($exitCode === 0, 'Command executed successfully'); + + $this->assertDatabaseMissing('page_revisions', [ + 'page_id' => $page->id, + 'type' => 'update_draft' + ]); + } +} \ No newline at end of file diff --git a/tests/Commands/ClearViewsCommandTest.php b/tests/Commands/ClearViewsCommandTest.php new file mode 100644 index 000000000..04665adcf --- /dev/null +++ b/tests/Commands/ClearViewsCommandTest.php @@ -0,0 +1,32 @@ +asEditor(); + $page = Page::first(); + + $this->get($page->getUrl()); + + $this->assertDatabaseHas('views', [ + 'user_id' => $this->getEditor()->id, + 'viewable_id' => $page->id, + 'views' => 1 + ]); + + DB::rollBack(); + $exitCode = \Artisan::call('bookstack:clear-views'); + DB::beginTransaction(); + $this->assertTrue($exitCode === 0, 'Command executed successfully'); + + $this->assertDatabaseMissing('views', [ + 'user_id' => $this->getEditor()->id + ]); + } +} \ No newline at end of file diff --git a/tests/Commands/CopyShelfPermissionsCommandTest.php b/tests/Commands/CopyShelfPermissionsCommandTest.php new file mode 100644 index 000000000..87199bdc3 --- /dev/null +++ b/tests/Commands/CopyShelfPermissionsCommandTest.php @@ -0,0 +1,54 @@ +artisan('bookstack:copy-shelf-permissions') + ->expectsOutput('Either a --slug or --all option must be provided.') + ->assertExitCode(0); + } + + public function test_copy_shelf_permissions_command_using_slug() + { + $shelf = Bookshelf::first(); + $child = $shelf->books()->first(); + $editorRole = $this->getEditor()->roles()->first(); + $this->assertFalse(boolval($child->restricted), "Child book should not be restricted by default"); + $this->assertTrue($child->permissions()->count() === 0, "Child book should have no permissions by default"); + + $this->setEntityRestrictions($shelf, ['view', 'update'], [$editorRole]); + $this->artisan('bookstack:copy-shelf-permissions', [ + '--slug' => $shelf->slug, + ]); + $child = $shelf->books()->first(); + + $this->assertTrue(boolval($child->restricted), "Child book should now be restricted"); + $this->assertTrue($child->permissions()->count() === 2, "Child book should have copied permissions"); + $this->assertDatabaseHas('entity_permissions', ['restrictable_id' => $child->id, 'action' => 'view', 'role_id' => $editorRole->id]); + $this->assertDatabaseHas('entity_permissions', ['restrictable_id' => $child->id, 'action' => 'update', 'role_id' => $editorRole->id]); + } + + public function test_copy_shelf_permissions_command_using_all() + { + $shelf = Bookshelf::query()->first(); + Bookshelf::query()->where('id', '!=', $shelf->id)->delete(); + $child = $shelf->books()->first(); + $editorRole = $this->getEditor()->roles()->first(); + $this->assertFalse(boolval($child->restricted), "Child book should not be restricted by default"); + $this->assertTrue($child->permissions()->count() === 0, "Child book should have no permissions by default"); + + $this->setEntityRestrictions($shelf, ['view', 'update'], [$editorRole]); + $this->artisan('bookstack:copy-shelf-permissions --all') + ->expectsQuestion('Permission settings for all shelves will be cascaded. Books assigned to multiple shelves will receive only the permissions of it\'s last processed shelf. Are you sure you want to proceed?', 'y'); + $child = $shelf->books()->first(); + + $this->assertTrue(boolval($child->restricted), "Child book should now be restricted"); + $this->assertTrue($child->permissions()->count() === 2, "Child book should have copied permissions"); + $this->assertDatabaseHas('entity_permissions', ['restrictable_id' => $child->id, 'action' => 'view', 'role_id' => $editorRole->id]); + $this->assertDatabaseHas('entity_permissions', ['restrictable_id' => $child->id, 'action' => 'update', 'role_id' => $editorRole->id]); + } +} \ No newline at end of file diff --git a/tests/Commands/RegenerateCommentContentCommandTest.php b/tests/Commands/RegenerateCommentContentCommandTest.php new file mode 100644 index 000000000..1deeaa703 --- /dev/null +++ b/tests/Commands/RegenerateCommentContentCommandTest.php @@ -0,0 +1,29 @@ +forceCreate([ + 'html' => 'some_old_content', + 'text' => 'some_fresh_content', + ]); + + $this->assertDatabaseHas('comments', [ + 'html' => 'some_old_content', + ]); + + $exitCode = \Artisan::call('bookstack:regenerate-comment-content'); + $this->assertTrue($exitCode === 0, 'Command executed successfully'); + + $this->assertDatabaseMissing('comments', [ + 'html' => 'some_old_content', + ]); + $this->assertDatabaseHas('comments', [ + 'html' => "

some_fresh_content

\n", + ]); + } +} \ No newline at end of file diff --git a/tests/Commands/RegeneratePermissionsCommandTest.php b/tests/Commands/RegeneratePermissionsCommandTest.php new file mode 100644 index 000000000..d5b34ba17 --- /dev/null +++ b/tests/Commands/RegeneratePermissionsCommandTest.php @@ -0,0 +1,24 @@ +truncate(); + $page = Page::first(); + + $this->assertDatabaseMissing('joint_permissions', ['entity_id' => $page->id]); + + $exitCode = \Artisan::call('bookstack:regenerate-permissions'); + $this->assertTrue($exitCode === 0, 'Command executed successfully'); + DB::beginTransaction(); + + $this->assertDatabaseHas('joint_permissions', ['entity_id' => $page->id]); + } +} \ No newline at end of file diff --git a/tests/Commands/UpdateUrlCommandTest.php b/tests/Commands/UpdateUrlCommandTest.php new file mode 100644 index 000000000..7043ce047 --- /dev/null +++ b/tests/Commands/UpdateUrlCommandTest.php @@ -0,0 +1,59 @@ +first(); + $page->html = ''; + $page->save(); + + $this->artisan('bookstack:update-url https://example.com https://cats.example.com') + ->expectsQuestion("This will search for \"https://example.com\" in your database and replace it with \"https://cats.example.com\".\nAre you sure you want to proceed?", 'y') + ->expectsQuestion("This operation could cause issues if used incorrectly. Have you made a backup of your existing database?", 'y'); + + $this->assertDatabaseHas('pages', [ + 'id' => $page->id, + 'html' => '' + ]); + } + + public function test_command_requires_valid_url() + { + $badUrlMessage = "The given urls are expected to be full urls starting with http:// or https://"; + $this->artisan('bookstack:update-url //example.com https://cats.example.com')->expectsOutput($badUrlMessage); + $this->artisan('bookstack:update-url https://example.com htts://cats.example.com')->expectsOutput($badUrlMessage); + $this->artisan('bookstack:update-url example.com https://cats.example.com')->expectsOutput($badUrlMessage); + + $this->expectException(RuntimeException::class); + $this->artisan('bookstack:update-url https://cats.example.com'); + } + + public function test_command_updates_settings() + { + setting()->put('my-custom-item', 'https://example.com/donkey/cat'); + $this->runUpdate('https://example.com', 'https://cats.example.com'); + + $settingVal = setting('my-custom-item'); + $this->assertEquals('https://cats.example.com/donkey/cat', $settingVal); + } + + public function test_command_updates_array_settings() + { + setting()->put('my-custom-array-item', [['name' => 'a https://example.com/donkey/cat url']]); + $this->runUpdate('https://example.com', 'https://cats.example.com'); + $settingVal = setting('my-custom-array-item'); + $this->assertEquals('a https://cats.example.com/donkey/cat url', $settingVal[0]['name']); + } + + protected function runUpdate(string $oldUrl, string $newUrl) + { + $this->artisan("bookstack:update-url {$oldUrl} {$newUrl}") + ->expectsQuestion("This will search for \"{$oldUrl}\" in your database and replace it with \"{$newUrl}\".\nAre you sure you want to proceed?", 'y') + ->expectsQuestion("This operation could cause issues if used incorrectly. Have you made a backup of your existing database?", 'y'); + } +} \ No newline at end of file diff --git a/tests/CommandsTest.php b/tests/CommandsTest.php deleted file mode 100644 index 8c6ea84bf..000000000 --- a/tests/CommandsTest.php +++ /dev/null @@ -1,222 +0,0 @@ -asEditor(); - $page = Page::first(); - - $this->get($page->getUrl()); - - $this->assertDatabaseHas('views', [ - 'user_id' => $this->getEditor()->id, - 'viewable_id' => $page->id, - 'views' => 1 - ]); - - $exitCode = \Artisan::call('bookstack:clear-views'); - $this->assertTrue($exitCode === 0, 'Command executed successfully'); - - $this->assertDatabaseMissing('views', [ - 'user_id' => $this->getEditor()->id - ]); - } - - public function test_clear_activity_command() - { - $this->asEditor(); - $page = Page::first(); - \Activity::addForEntity($page, ActivityType::PAGE_UPDATE); - - $this->assertDatabaseHas('activities', [ - 'type' => 'page_update', - 'entity_id' => $page->id, - 'user_id' => $this->getEditor()->id - ]); - - $exitCode = \Artisan::call('bookstack:clear-activity'); - $this->assertTrue($exitCode === 0, 'Command executed successfully'); - - - $this->assertDatabaseMissing('activities', [ - 'type' => 'page_update' - ]); - } - - public function test_clear_revisions_command() - { - $this->asEditor(); - $pageRepo = app(PageRepo::class); - $page = Page::first(); - $pageRepo->update($page, ['name' => 'updated page', 'html' => '

new content

', 'summary' => 'page revision testing']); - $pageRepo->updatePageDraft($page, ['name' => 'updated page', 'html' => '

new content in draft

', 'summary' => 'page revision testing']); - - $this->assertDatabaseHas('page_revisions', [ - 'page_id' => $page->id, - 'type' => 'version' - ]); - $this->assertDatabaseHas('page_revisions', [ - 'page_id' => $page->id, - 'type' => 'update_draft' - ]); - - $exitCode = \Artisan::call('bookstack:clear-revisions'); - $this->assertTrue($exitCode === 0, 'Command executed successfully'); - - $this->assertDatabaseMissing('page_revisions', [ - 'page_id' => $page->id, - 'type' => 'version' - ]); - $this->assertDatabaseHas('page_revisions', [ - 'page_id' => $page->id, - 'type' => 'update_draft' - ]); - - $exitCode = \Artisan::call('bookstack:clear-revisions', ['--all' => true]); - $this->assertTrue($exitCode === 0, 'Command executed successfully'); - - $this->assertDatabaseMissing('page_revisions', [ - 'page_id' => $page->id, - 'type' => 'update_draft' - ]); - } - - public function test_regen_permissions_command() - { - JointPermission::query()->truncate(); - $page = Page::first(); - - $this->assertDatabaseMissing('joint_permissions', ['entity_id' => $page->id]); - - $exitCode = \Artisan::call('bookstack:regenerate-permissions'); - $this->assertTrue($exitCode === 0, 'Command executed successfully'); - - $this->assertDatabaseHas('joint_permissions', ['entity_id' => $page->id]); - } - - public function test_add_admin_command() - { - $exitCode = \Artisan::call('bookstack:create-admin', [ - '--email' => 'admintest@example.com', - '--name' => 'Admin Test', - '--password' => 'testing-4', - ]); - $this->assertTrue($exitCode === 0, 'Command executed successfully'); - - $this->assertDatabaseHas('users', [ - 'email' => 'admintest@example.com', - 'name' => 'Admin Test' - ]); - - $this->assertTrue(User::where('email', '=', 'admintest@example.com')->first()->hasSystemRole('admin'), 'User has admin role as expected'); - $this->assertTrue(\Auth::attempt(['email' => 'admintest@example.com', 'password' => 'testing-4']), 'Password stored as expected'); - } - - public function test_copy_shelf_permissions_command_shows_error_when_no_required_option_given() - { - $this->artisan('bookstack:copy-shelf-permissions') - ->expectsOutput('Either a --slug or --all option must be provided.') - ->assertExitCode(0); - } - - public function test_copy_shelf_permissions_command_using_slug() - { - $shelf = Bookshelf::first(); - $child = $shelf->books()->first(); - $editorRole = $this->getEditor()->roles()->first(); - $this->assertFalse(boolval($child->restricted), "Child book should not be restricted by default"); - $this->assertTrue($child->permissions()->count() === 0, "Child book should have no permissions by default"); - - $this->setEntityRestrictions($shelf, ['view', 'update'], [$editorRole]); - $this->artisan('bookstack:copy-shelf-permissions', [ - '--slug' => $shelf->slug, - ]); - $child = $shelf->books()->first(); - - $this->assertTrue(boolval($child->restricted), "Child book should now be restricted"); - $this->assertTrue($child->permissions()->count() === 2, "Child book should have copied permissions"); - $this->assertDatabaseHas('entity_permissions', ['restrictable_id' => $child->id, 'action' => 'view', 'role_id' => $editorRole->id]); - $this->assertDatabaseHas('entity_permissions', ['restrictable_id' => $child->id, 'action' => 'update', 'role_id' => $editorRole->id]); - } - - public function test_copy_shelf_permissions_command_using_all() - { - $shelf = Bookshelf::query()->first(); - Bookshelf::query()->where('id', '!=', $shelf->id)->delete(); - $child = $shelf->books()->first(); - $editorRole = $this->getEditor()->roles()->first(); - $this->assertFalse(boolval($child->restricted), "Child book should not be restricted by default"); - $this->assertTrue($child->permissions()->count() === 0, "Child book should have no permissions by default"); - - $this->setEntityRestrictions($shelf, ['view', 'update'], [$editorRole]); - $this->artisan('bookstack:copy-shelf-permissions --all') - ->expectsQuestion('Permission settings for all shelves will be cascaded. Books assigned to multiple shelves will receive only the permissions of it\'s last processed shelf. Are you sure you want to proceed?', 'y'); - $child = $shelf->books()->first(); - - $this->assertTrue(boolval($child->restricted), "Child book should now be restricted"); - $this->assertTrue($child->permissions()->count() === 2, "Child book should have copied permissions"); - $this->assertDatabaseHas('entity_permissions', ['restrictable_id' => $child->id, 'action' => 'view', 'role_id' => $editorRole->id]); - $this->assertDatabaseHas('entity_permissions', ['restrictable_id' => $child->id, 'action' => 'update', 'role_id' => $editorRole->id]); - } - - public function test_update_url_command_updates_page_content() - { - $page = Page::query()->first(); - $page->html = ''; - $page->save(); - - $this->artisan('bookstack:update-url https://example.com https://cats.example.com') - ->expectsQuestion("This will search for \"https://example.com\" in your database and replace it with \"https://cats.example.com\".\nAre you sure you want to proceed?", 'y') - ->expectsQuestion("This operation could cause issues if used incorrectly. Have you made a backup of your existing database?", 'y'); - - $this->assertDatabaseHas('pages', [ - 'id' => $page->id, - 'html' => '' - ]); - } - - public function test_update_url_command_requires_valid_url() - { - $badUrlMessage = "The given urls are expected to be full urls starting with http:// or https://"; - $this->artisan('bookstack:update-url //example.com https://cats.example.com')->expectsOutput($badUrlMessage); - $this->artisan('bookstack:update-url https://example.com htts://cats.example.com')->expectsOutput($badUrlMessage); - $this->artisan('bookstack:update-url example.com https://cats.example.com')->expectsOutput($badUrlMessage); - - $this->expectException(RuntimeException::class); - $this->artisan('bookstack:update-url https://cats.example.com'); - } - - public function test_regenerate_comment_content_command() - { - Comment::query()->forceCreate([ - 'html' => 'some_old_content', - 'text' => 'some_fresh_content', - ]); - - $this->assertDatabaseHas('comments', [ - 'html' => 'some_old_content', - ]); - - $exitCode = \Artisan::call('bookstack:regenerate-comment-content'); - $this->assertTrue($exitCode === 0, 'Command executed successfully'); - - $this->assertDatabaseMissing('comments', [ - 'html' => 'some_old_content', - ]); - $this->assertDatabaseHas('comments', [ - 'html' => "

some_fresh_content

\n", - ]); - } -} diff --git a/tests/Entity/BookShelfTest.php b/tests/Entity/BookShelfTest.php index 9b3290370..29fac5ec5 100644 --- a/tests/Entity/BookShelfTest.php +++ b/tests/Entity/BookShelfTest.php @@ -59,7 +59,7 @@ class BookShelfTest extends TestCase public function test_book_not_visible_in_shelf_list_view_if_user_cant_view_shelf() { config()->set([ - 'app.views.bookshelves' => 'list', + 'setting-defaults.user.bookshelves_view_type' => 'list', ]); $shelf = Bookshelf::query()->first(); $book = $shelf->books()->first(); diff --git a/tests/Entity/EntitySearchTest.php b/tests/Entity/EntitySearchTest.php index 2b5dc6d74..6b53b2cb6 100644 --- a/tests/Entity/EntitySearchTest.php +++ b/tests/Entity/EntitySearchTest.php @@ -122,6 +122,7 @@ class EntitySearchTest extends TestCase $page = $this->newPage(['name' => 'My new test quaffleachits', 'html' => 'this is about an orange donkey danzorbhsing']); $this->asEditor(); $editorId = $this->getEditor()->id; + $editorSlug = $this->getEditor()->slug; // Viewed filter searches $this->get('/search?term=' . urlencode('danzorbhsing {not_viewed_by_me}'))->assertSee($page->name); @@ -133,16 +134,23 @@ class EntitySearchTest extends TestCase // User filters $this->get('/search?term=' . urlencode('danzorbhsing {created_by:me}'))->assertDontSee($page->name); $this->get('/search?term=' . urlencode('danzorbhsing {updated_by:me}'))->assertDontSee($page->name); - $this->get('/search?term=' . urlencode('danzorbhsing {updated_by:'.$editorId.'}'))->assertDontSee($page->name); + $this->get('/search?term=' . urlencode('danzorbhsing {owned_by:me}'))->assertDontSee($page->name); + $this->get('/search?term=' . urlencode('danzorbhsing {updated_by:'.$editorSlug.'}'))->assertDontSee($page->name); $page->created_by = $editorId; $page->save(); $this->get('/search?term=' . urlencode('danzorbhsing {created_by:me}'))->assertSee($page->name); - $this->get('/search?term=' . urlencode('danzorbhsing {created_by:'.$editorId.'}'))->assertSee($page->name); + $this->get('/search?term=' . urlencode('danzorbhsing {created_by: '.$editorSlug.'}'))->assertSee($page->name); $this->get('/search?term=' . urlencode('danzorbhsing {updated_by:me}'))->assertDontSee($page->name); + $this->get('/search?term=' . urlencode('danzorbhsing {owned_by:me}'))->assertDontSee($page->name); $page->updated_by = $editorId; $page->save(); $this->get('/search?term=' . urlencode('danzorbhsing {updated_by:me}'))->assertSee($page->name); - $this->get('/search?term=' . urlencode('danzorbhsing {updated_by:'.$editorId.'}'))->assertSee($page->name); + $this->get('/search?term=' . urlencode('danzorbhsing {updated_by:'.$editorSlug.'}'))->assertSee($page->name); + $this->get('/search?term=' . urlencode('danzorbhsing {owned_by:me}'))->assertDontSee($page->name); + $page->owned_by = $editorId; + $page->save(); + $this->get('/search?term=' . urlencode('danzorbhsing {owned_by:me}'))->assertSee($page->name); + $this->get('/search?term=' . urlencode('danzorbhsing {owned_by:'.$editorSlug.'}'))->assertSee($page->name); // Content filters $this->get('/search?term=' . urlencode('{in_name:danzorbhsing}'))->assertDontSee($page->name); diff --git a/tests/Entity/EntityTest.php b/tests/Entity/EntityTest.php index 3a363e2b8..52f9a3ae2 100644 --- a/tests/Entity/EntityTest.php +++ b/tests/Entity/EntityTest.php @@ -162,7 +162,7 @@ class EntityTest extends BrowserKitTest ->press('Save Book'); $expectedPattern = '/\/books\/my-first-book-[0-9a-zA-Z]{3}/'; - $this->assertRegExp($expectedPattern, $this->currentUri, "Did not land on expected page [$expectedPattern].\n"); + $this->assertMatchesRegularExpression($expectedPattern, $this->currentUri, "Did not land on expected page [$expectedPattern].\n"); $book = Book::where('slug', '=', 'my-first-book')->first(); return $book; diff --git a/tests/Entity/ExportTest.php b/tests/Entity/ExportTest.php index 1e44f015a..05672c6ca 100644 --- a/tests/Entity/ExportTest.php +++ b/tests/Entity/ExportTest.php @@ -1,6 +1,5 @@ assertDontSee($page->updated_at->diffForHumans()); } + public function test_page_export_does_not_include_user_or_revision_links() + { + $page = Page::first(); + + $resp = $this->asEditor()->get($page->getUrl('/export/html')); + $resp->assertDontSee($page->getUrl('/revisions')); + $resp->assertDontSee($page->createdBy->getProfileUrl()); + $resp->assertSee($page->createdBy->name); + } + public function test_page_export_sets_right_data_type_for_svg_embeds() { $page = Page::first(); diff --git a/tests/Entity/PageRevisionTest.php b/tests/Entity/PageRevisionTest.php index 68a8f01a9..62fbfbf31 100644 --- a/tests/Entity/PageRevisionTest.php +++ b/tests/Entity/PageRevisionTest.php @@ -66,6 +66,36 @@ class PageRevisionTest extends TestCase $pageView->assertSee('def456'); } + public function test_page_revision_restore_with_markdown_retains_markdown_content() + { + $this->asEditor(); + + $pageRepo = app(PageRepo::class); + $page = Page::first(); + $pageRepo->update($page, ['name' => 'updated page abc123', 'markdown' => '## New Content def456', 'summary' => 'initial page revision testing']); + $pageRepo->update($page, ['name' => 'updated page again', 'markdown' => '## New Content Updated', 'summary' => 'page revision testing']); + $page = Page::find($page->id); + + $pageView = $this->get($page->getUrl()); + $pageView->assertDontSee('abc123'); + $pageView->assertDontSee('def456'); + + $revToRestore = $page->revisions()->where('name', 'like', '%abc123')->first(); + $restoreReq = $this->put($page->getUrl() . '/revisions/' . $revToRestore->id . '/restore'); + $page = Page::find($page->id); + + $restoreReq->assertStatus(302); + $restoreReq->assertRedirect($page->getUrl()); + + $pageView = $this->get($page->getUrl()); + $this->assertDatabaseHas('pages', [ + 'id' => $page->id, + 'markdown' => '## New Content def456', + ]); + $pageView->assertSee('abc123'); + $pageView->assertSee('def456'); + } + public function test_page_revision_restore_sets_new_revision_with_summary() { $this->asEditor(); diff --git a/tests/Entity/SortTest.php b/tests/Entity/SortTest.php index d75a134ea..c27c41f29 100644 --- a/tests/Entity/SortTest.php +++ b/tests/Entity/SortTest.php @@ -91,19 +91,19 @@ class SortTest extends TestCase public function test_page_move_requires_create_permissions_on_parent() { - $page = Page::first(); + $page = Page::query()->first(); $currentBook = $page->book; - $newBook = Book::where('id', '!=', $currentBook->id)->first(); + $newBook = Book::query()->where('id', '!=', $currentBook->id)->first(); $editor = $this->getEditor(); - $this->setEntityRestrictions($newBook, ['view', 'update', 'delete'], $editor->roles); + $this->setEntityRestrictions($newBook, ['view', 'update', 'delete'], $editor->roles->all()); $movePageResp = $this->actingAs($editor)->put($page->getUrl('/move'), [ 'entity_selection' => 'book:' . $newBook->id ]); $this->assertPermissionError($movePageResp); - $this->setEntityRestrictions($newBook, ['view', 'update', 'delete', 'create'], $editor->roles); + $this->setEntityRestrictions($newBook, ['view', 'update', 'delete', 'create'], $editor->roles->all()); $movePageResp = $this->put($page->getUrl('/move'), [ 'entity_selection' => 'book:' . $newBook->id ]); @@ -121,8 +121,8 @@ class SortTest extends TestCase $newBook = Book::where('id', '!=', $currentBook->id)->first(); $editor = $this->getEditor(); - $this->setEntityRestrictions($newBook, ['view', 'update', 'create', 'delete'], $editor->roles); - $this->setEntityRestrictions($page, ['view', 'update', 'create'], $editor->roles); + $this->setEntityRestrictions($newBook, ['view', 'update', 'create', 'delete'], $editor->roles->all()); + $this->setEntityRestrictions($page, ['view', 'update', 'create'], $editor->roles->all()); $movePageResp = $this->actingAs($editor)->put($page->getUrl('/move'), [ 'entity_selection' => 'book:' . $newBook->id @@ -131,7 +131,7 @@ class SortTest extends TestCase $pageView = $this->get($page->getUrl()); $pageView->assertDontSee($page->getUrl('/move')); - $this->setEntityRestrictions($page, ['view', 'update', 'create', 'delete'], $editor->roles); + $this->setEntityRestrictions($page, ['view', 'update', 'create', 'delete'], $editor->roles->all()); $movePageResp = $this->put($page->getUrl('/move'), [ 'entity_selection' => 'book:' . $newBook->id ]); @@ -176,8 +176,8 @@ class SortTest extends TestCase $newBook = Book::where('id', '!=', $currentBook->id)->first(); $editor = $this->getEditor(); - $this->setEntityRestrictions($newBook, ['view', 'update', 'create', 'delete'], $editor->roles); - $this->setEntityRestrictions($chapter, ['view', 'update', 'create'], $editor->roles); + $this->setEntityRestrictions($newBook, ['view', 'update', 'create', 'delete'], $editor->roles->all()); + $this->setEntityRestrictions($chapter, ['view', 'update', 'create'], $editor->roles->all()); $moveChapterResp = $this->actingAs($editor)->put($chapter->getUrl('/move'), [ 'entity_selection' => 'book:' . $newBook->id @@ -186,7 +186,7 @@ class SortTest extends TestCase $pageView = $this->get($chapter->getUrl()); $pageView->assertDontSee($chapter->getUrl('/move')); - $this->setEntityRestrictions($chapter, ['view', 'update', 'create', 'delete'], $editor->roles); + $this->setEntityRestrictions($chapter, ['view', 'update', 'create', 'delete'], $editor->roles->all()); $moveChapterResp = $this->put($chapter->getUrl('/move'), [ 'entity_selection' => 'book:' . $newBook->id ]); @@ -196,6 +196,24 @@ class SortTest extends TestCase $this->assertTrue($chapter->book->id == $newBook->id, 'Page book is now the new book'); } + public function test_chapter_move_changes_book_for_deleted_pages_within() + { + /** @var Chapter $chapter */ + $chapter = Chapter::query()->whereHas('pages')->first(); + $currentBook = $chapter->book; + $pageToCheck = $chapter->pages->first(); + $newBook = Book::query()->where('id', '!=', $currentBook->id)->first(); + + $pageToCheck->delete(); + + $this->asEditor()->put($chapter->getUrl('/move'), [ + 'entity_selection' => 'book:' . $newBook->id + ]); + + $pageToCheck->refresh(); + $this->assertEquals($newBook->id, $pageToCheck->book_id); + } + public function test_book_sort() { $oldBook = Book::query()->first(); diff --git a/tests/Permissions/EntityPermissionsTest.php b/tests/Permissions/EntityPermissionsTest.php index 1e6d1cc32..8dc112e57 100644 --- a/tests/Permissions/EntityPermissionsTest.php +++ b/tests/Permissions/EntityPermissionsTest.php @@ -29,13 +29,13 @@ class EntityPermissionsTest extends BrowserKitTest $this->viewer = $this->getViewer(); } - protected function setEntityRestrictions(Entity $entity, $actions = [], $roles = []) + protected function setRestrictionsForTestRoles(Entity $entity, array $actions = []) { $roles = [ $this->user->roles->first(), $this->viewer->roles->first(), ]; - parent::setEntityRestrictions($entity, $actions, $roles); + $this->setEntityRestrictions($entity, $actions, $roles); } public function test_bookshelf_view_restriction() @@ -46,12 +46,12 @@ class EntityPermissionsTest extends BrowserKitTest ->visit($shelf->getUrl()) ->seePageIs($shelf->getUrl()); - $this->setEntityRestrictions($shelf, []); + $this->setRestrictionsForTestRoles($shelf, []); $this->forceVisit($shelf->getUrl()) ->see('Bookshelf not found'); - $this->setEntityRestrictions($shelf, ['view']); + $this->setRestrictionsForTestRoles($shelf, ['view']); $this->visit($shelf->getUrl()) ->see($shelf->name); @@ -65,12 +65,12 @@ class EntityPermissionsTest extends BrowserKitTest ->visit($shelf->getUrl('/edit')) ->see('Edit Book'); - $this->setEntityRestrictions($shelf, ['view', 'delete']); + $this->setRestrictionsForTestRoles($shelf, ['view', 'delete']); $this->forceVisit($shelf->getUrl('/edit')) ->see('You do not have permission')->seePageIs('/'); - $this->setEntityRestrictions($shelf, ['view', 'update']); + $this->setRestrictionsForTestRoles($shelf, ['view', 'update']); $this->visit($shelf->getUrl('/edit')) ->seePageIs($shelf->getUrl('/edit')); @@ -84,12 +84,12 @@ class EntityPermissionsTest extends BrowserKitTest ->visit($shelf->getUrl('/delete')) ->see('Delete Book'); - $this->setEntityRestrictions($shelf, ['view', 'update']); + $this->setRestrictionsForTestRoles($shelf, ['view', 'update']); $this->forceVisit($shelf->getUrl('/delete')) ->see('You do not have permission')->seePageIs('/'); - $this->setEntityRestrictions($shelf, ['view', 'delete']); + $this->setRestrictionsForTestRoles($shelf, ['view', 'delete']); $this->visit($shelf->getUrl('/delete')) ->seePageIs($shelf->getUrl('/delete'))->see('Delete Book'); @@ -106,7 +106,7 @@ class EntityPermissionsTest extends BrowserKitTest ->visit($bookUrl) ->seePageIs($bookUrl); - $this->setEntityRestrictions($book, []); + $this->setRestrictionsForTestRoles($book, []); $this->forceVisit($bookUrl) ->see('Book not found'); @@ -115,7 +115,7 @@ class EntityPermissionsTest extends BrowserKitTest $this->forceVisit($bookChapter->getUrl()) ->see('Chapter not found'); - $this->setEntityRestrictions($book, ['view']); + $this->setRestrictionsForTestRoles($book, ['view']); $this->visit($bookUrl) ->see($book->name); @@ -139,7 +139,7 @@ class EntityPermissionsTest extends BrowserKitTest ->seeInElement('.actions', 'New Page') ->seeInElement('.actions', 'New Chapter'); - $this->setEntityRestrictions($book, ['view', 'delete', 'update']); + $this->setRestrictionsForTestRoles($book, ['view', 'delete', 'update']); $this->forceVisit($bookUrl . '/create-chapter') ->see('You do not have permission')->seePageIs('/'); @@ -148,7 +148,7 @@ class EntityPermissionsTest extends BrowserKitTest $this->visit($bookUrl)->dontSeeInElement('.actions', 'New Page') ->dontSeeInElement('.actions', 'New Chapter'); - $this->setEntityRestrictions($book, ['view', 'create']); + $this->setRestrictionsForTestRoles($book, ['view', 'create']); $this->visit($bookUrl . '/create-chapter') ->type('test chapter', 'name') @@ -175,7 +175,7 @@ class EntityPermissionsTest extends BrowserKitTest ->visit($bookUrl . '/edit') ->see('Edit Book'); - $this->setEntityRestrictions($book, ['view', 'delete']); + $this->setRestrictionsForTestRoles($book, ['view', 'delete']); $this->forceVisit($bookUrl . '/edit') ->see('You do not have permission')->seePageIs('/'); @@ -184,7 +184,7 @@ class EntityPermissionsTest extends BrowserKitTest $this->forceVisit($bookChapter->getUrl() . '/edit') ->see('You do not have permission')->seePageIs('/'); - $this->setEntityRestrictions($book, ['view', 'update']); + $this->setRestrictionsForTestRoles($book, ['view', 'update']); $this->visit($bookUrl . '/edit') ->seePageIs($bookUrl . '/edit'); @@ -205,7 +205,7 @@ class EntityPermissionsTest extends BrowserKitTest ->visit($bookUrl . '/delete') ->see('Delete Book'); - $this->setEntityRestrictions($book, ['view', 'update']); + $this->setRestrictionsForTestRoles($book, ['view', 'update']); $this->forceVisit($bookUrl . '/delete') ->see('You do not have permission')->seePageIs('/'); @@ -214,7 +214,7 @@ class EntityPermissionsTest extends BrowserKitTest $this->forceVisit($bookChapter->getUrl() . '/delete') ->see('You do not have permission')->seePageIs('/'); - $this->setEntityRestrictions($book, ['view', 'delete']); + $this->setRestrictionsForTestRoles($book, ['view', 'delete']); $this->visit($bookUrl . '/delete') ->seePageIs($bookUrl . '/delete')->see('Delete Book'); @@ -234,14 +234,14 @@ class EntityPermissionsTest extends BrowserKitTest ->visit($chapterUrl) ->seePageIs($chapterUrl); - $this->setEntityRestrictions($chapter, []); + $this->setRestrictionsForTestRoles($chapter, []); $this->forceVisit($chapterUrl) ->see('Chapter not found'); $this->forceVisit($chapterPage->getUrl()) ->see('Page not found'); - $this->setEntityRestrictions($chapter, ['view']); + $this->setRestrictionsForTestRoles($chapter, ['view']); $this->visit($chapterUrl) ->see($chapter->name); @@ -258,13 +258,13 @@ class EntityPermissionsTest extends BrowserKitTest ->visit($chapterUrl) ->seeInElement('.actions', 'New Page'); - $this->setEntityRestrictions($chapter, ['view', 'delete', 'update']); + $this->setRestrictionsForTestRoles($chapter, ['view', 'delete', 'update']); $this->forceVisit($chapterUrl . '/create-page') ->see('You do not have permission')->seePageIs('/'); $this->visit($chapterUrl)->dontSeeInElement('.actions', 'New Page'); - $this->setEntityRestrictions($chapter, ['view', 'create']); + $this->setRestrictionsForTestRoles($chapter, ['view', 'create']); $this->visit($chapterUrl . '/create-page') @@ -286,14 +286,14 @@ class EntityPermissionsTest extends BrowserKitTest ->visit($chapterUrl . '/edit') ->see('Edit Chapter'); - $this->setEntityRestrictions($chapter, ['view', 'delete']); + $this->setRestrictionsForTestRoles($chapter, ['view', 'delete']); $this->forceVisit($chapterUrl . '/edit') ->see('You do not have permission')->seePageIs('/'); $this->forceVisit($chapterPage->getUrl() . '/edit') ->see('You do not have permission')->seePageIs('/'); - $this->setEntityRestrictions($chapter, ['view', 'update']); + $this->setRestrictionsForTestRoles($chapter, ['view', 'update']); $this->visit($chapterUrl . '/edit') ->seePageIs($chapterUrl . '/edit')->see('Edit Chapter'); @@ -311,14 +311,14 @@ class EntityPermissionsTest extends BrowserKitTest ->visit($chapterUrl . '/delete') ->see('Delete Chapter'); - $this->setEntityRestrictions($chapter, ['view', 'update']); + $this->setRestrictionsForTestRoles($chapter, ['view', 'update']); $this->forceVisit($chapterUrl . '/delete') ->see('You do not have permission')->seePageIs('/'); $this->forceVisit($chapterPage->getUrl() . '/delete') ->see('You do not have permission')->seePageIs('/'); - $this->setEntityRestrictions($chapter, ['view', 'delete']); + $this->setRestrictionsForTestRoles($chapter, ['view', 'delete']); $this->visit($chapterUrl . '/delete') ->seePageIs($chapterUrl . '/delete')->see('Delete Chapter'); @@ -335,12 +335,12 @@ class EntityPermissionsTest extends BrowserKitTest ->visit($pageUrl) ->seePageIs($pageUrl); - $this->setEntityRestrictions($page, ['update', 'delete']); + $this->setRestrictionsForTestRoles($page, ['update', 'delete']); $this->forceVisit($pageUrl) ->see('Page not found'); - $this->setEntityRestrictions($page, ['view']); + $this->setRestrictionsForTestRoles($page, ['view']); $this->visit($pageUrl) ->see($page->name); @@ -355,12 +355,12 @@ class EntityPermissionsTest extends BrowserKitTest ->visit($pageUrl . '/edit') ->seeInField('name', $page->name); - $this->setEntityRestrictions($page, ['view', 'delete']); + $this->setRestrictionsForTestRoles($page, ['view', 'delete']); $this->forceVisit($pageUrl . '/edit') ->see('You do not have permission')->seePageIs('/'); - $this->setEntityRestrictions($page, ['view', 'update']); + $this->setRestrictionsForTestRoles($page, ['view', 'update']); $this->visit($pageUrl . '/edit') ->seePageIs($pageUrl . '/edit')->seeInField('name', $page->name); @@ -375,12 +375,12 @@ class EntityPermissionsTest extends BrowserKitTest ->visit($pageUrl . '/delete') ->see('Delete Page'); - $this->setEntityRestrictions($page, ['view', 'update']); + $this->setRestrictionsForTestRoles($page, ['view', 'update']); $this->forceVisit($pageUrl . '/delete') ->see('You do not have permission')->seePageIs('/'); - $this->setEntityRestrictions($page, ['view', 'delete']); + $this->setRestrictionsForTestRoles($page, ['view', 'delete']); $this->visit($pageUrl . '/delete') ->seePageIs($pageUrl . '/delete')->see('Delete Page'); @@ -460,7 +460,7 @@ class EntityPermissionsTest extends BrowserKitTest $page = $chapter->pages->first(); $page2 = $chapter->pages[2]; - $this->setEntityRestrictions($page, []); + $this->setRestrictionsForTestRoles($page, []); $this->actingAs($this->user) ->visit($page2->getUrl()) @@ -472,7 +472,7 @@ class EntityPermissionsTest extends BrowserKitTest $chapter = Chapter::first(); $page = $chapter->pages->first(); - $this->setEntityRestrictions($page, []); + $this->setRestrictionsForTestRoles($page, []); $this->actingAs($this->user) ->visit($chapter->getUrl()) @@ -484,7 +484,7 @@ class EntityPermissionsTest extends BrowserKitTest $chapter = Chapter::first(); $page = $chapter->pages->first(); - $this->setEntityRestrictions($page, []); + $this->setRestrictionsForTestRoles($page, []); $this->actingAs($this->user) ->visit($chapter->getUrl()) @@ -499,7 +499,7 @@ class EntityPermissionsTest extends BrowserKitTest ->see($chapter->pages->first()->name); foreach ($chapter->pages as $page) { - $this->setEntityRestrictions($page, []); + $this->setRestrictionsForTestRoles($page, []); } $this->actingAs($this->user) @@ -515,12 +515,12 @@ class EntityPermissionsTest extends BrowserKitTest ->visit($shelf->getUrl('/edit')) ->dontSee('Edit Book'); - $this->setEntityRestrictions($shelf, ['view', 'delete']); + $this->setRestrictionsForTestRoles($shelf, ['view', 'delete']); $this->forceVisit($shelf->getUrl('/edit')) ->see('You do not have permission')->seePageIs('/'); - $this->setEntityRestrictions($shelf, ['view', 'update']); + $this->setRestrictionsForTestRoles($shelf, ['view', 'update']); $this->visit($shelf->getUrl('/edit')) ->seePageIs($shelf->getUrl('/edit')); @@ -534,12 +534,12 @@ class EntityPermissionsTest extends BrowserKitTest ->visit($shelf->getUrl('/delete')) ->dontSee('Delete Book'); - $this->setEntityRestrictions($shelf, ['view', 'update']); + $this->setRestrictionsForTestRoles($shelf, ['view', 'update']); $this->forceVisit($shelf->getUrl('/delete')) ->see('You do not have permission')->seePageIs('/'); - $this->setEntityRestrictions($shelf, ['view', 'delete']); + $this->setRestrictionsForTestRoles($shelf, ['view', 'delete']); $this->visit($shelf->getUrl('/delete')) ->seePageIs($shelf->getUrl('/delete'))->see('Delete Book'); @@ -555,7 +555,7 @@ class EntityPermissionsTest extends BrowserKitTest ->dontSeeInElement('.actions', 'New Page') ->dontSeeInElement('.actions', 'New Chapter'); - $this->setEntityRestrictions($book, ['view', 'delete', 'update']); + $this->setRestrictionsForTestRoles($book, ['view', 'delete', 'update']); $this->forceVisit($bookUrl . '/create-chapter') ->see('You do not have permission')->seePageIs('/'); @@ -564,7 +564,7 @@ class EntityPermissionsTest extends BrowserKitTest $this->visit($bookUrl)->dontSeeInElement('.actions', 'New Page') ->dontSeeInElement('.actions', 'New Chapter'); - $this->setEntityRestrictions($book, ['view', 'create']); + $this->setRestrictionsForTestRoles($book, ['view', 'create']); $this->visit($bookUrl . '/create-chapter') ->type('test chapter', 'name') @@ -591,7 +591,7 @@ class EntityPermissionsTest extends BrowserKitTest ->visit($bookUrl . '/edit') ->dontSee('Edit Book'); - $this->setEntityRestrictions($book, ['view', 'delete']); + $this->setRestrictionsForTestRoles($book, ['view', 'delete']); $this->forceVisit($bookUrl . '/edit') ->see('You do not have permission')->seePageIs('/'); @@ -600,7 +600,7 @@ class EntityPermissionsTest extends BrowserKitTest $this->forceVisit($bookChapter->getUrl() . '/edit') ->see('You do not have permission')->seePageIs('/'); - $this->setEntityRestrictions($book, ['view', 'update']); + $this->setRestrictionsForTestRoles($book, ['view', 'update']); $this->visit($bookUrl . '/edit') ->seePageIs($bookUrl . '/edit'); @@ -621,7 +621,7 @@ class EntityPermissionsTest extends BrowserKitTest ->visit($bookUrl . '/delete') ->dontSee('Delete Book'); - $this->setEntityRestrictions($book, ['view', 'update']); + $this->setRestrictionsForTestRoles($book, ['view', 'update']); $this->forceVisit($bookUrl . '/delete') ->see('You do not have permission')->seePageIs('/'); @@ -630,7 +630,7 @@ class EntityPermissionsTest extends BrowserKitTest $this->forceVisit($bookChapter->getUrl() . '/delete') ->see('You do not have permission')->seePageIs('/'); - $this->setEntityRestrictions($book, ['view', 'delete']); + $this->setRestrictionsForTestRoles($book, ['view', 'delete']); $this->visit($bookUrl . '/delete') ->seePageIs($bookUrl . '/delete')->see('Delete Book'); @@ -651,8 +651,8 @@ class EntityPermissionsTest extends BrowserKitTest $entity->save(); } - $this->setEntityRestrictions($book, []); - $this->setEntityRestrictions($bookPage, ['view']); + $this->setRestrictionsForTestRoles($book, []); + $this->setRestrictionsForTestRoles($bookPage, ['view']); $this->actingAs($this->viewer); $this->get($bookPage->getUrl()); @@ -667,8 +667,8 @@ class EntityPermissionsTest extends BrowserKitTest $firstBook = Book::first(); $secondBook = Book::find(2); - $this->setEntityRestrictions($firstBook, ['view', 'update']); - $this->setEntityRestrictions($secondBook, ['view']); + $this->setRestrictionsForTestRoles($firstBook, ['view', 'update']); + $this->setRestrictionsForTestRoles($secondBook, ['view']); // Test sort page visibility $this->actingAs($this->user)->visit($secondBook->getUrl() . '/sort') @@ -683,8 +683,8 @@ class EntityPermissionsTest extends BrowserKitTest $firstBook = Book::first(); $secondBook = Book::find(2); - $this->setEntityRestrictions($firstBook, ['view', 'update']); - $this->setEntityRestrictions($secondBook, ['view']); + $this->setRestrictionsForTestRoles($firstBook, ['view', 'update']); + $this->setRestrictionsForTestRoles($secondBook, ['view']); $firstBookChapter = $this->newChapter(['name' => 'first book chapter'], $firstBook); $secondBookChapter = $this->newChapter(['name' => 'second book chapter'], $secondBook); @@ -726,14 +726,14 @@ class EntityPermissionsTest extends BrowserKitTest public function test_can_create_page_if_chapter_has_permissions_when_book_not_visible() { $book = Book::first(); - $this->setEntityRestrictions($book, []); + $this->setRestrictionsForTestRoles($book, []); $bookChapter = $book->chapters->first(); - $this->setEntityRestrictions($bookChapter, ['view']); + $this->setRestrictionsForTestRoles($bookChapter, ['view']); $this->actingAs($this->user)->visit($bookChapter->getUrl()) ->dontSee('New Page'); - $this->setEntityRestrictions($bookChapter, ['view', 'create']); + $this->setRestrictionsForTestRoles($bookChapter, ['view', 'create']); $this->actingAs($this->user)->visit($bookChapter->getUrl()) ->click('New Page') diff --git a/tests/PublicActionTest.php b/tests/PublicActionTest.php index 194190124..7caefd0ac 100644 --- a/tests/PublicActionTest.php +++ b/tests/PublicActionTest.php @@ -9,71 +9,73 @@ use BookStack\Entities\Models\Book; use BookStack\Entities\Models\Chapter; use BookStack\Entities\Models\Page; -class PublicActionTest extends BrowserKitTest +class PublicActionTest extends TestCase { public function test_app_not_public() { $this->setSettings(['app-public' => 'false']); - $book = Book::orderBy('name', 'asc')->first(); - $this->visit('/books')->seePageIs('/login'); - $this->visit($book->getUrl())->seePageIs('/login'); + $book = Book::query()->first(); + $this->get('/books')->assertRedirect('/login'); + $this->get($book->getUrl())->assertRedirect('/login'); - $page = Page::first(); - $this->visit($page->getUrl())->seePageIs('/login'); + $page = Page::query()->first(); + $this->get($page->getUrl())->assertRedirect('/login'); } public function test_login_link_visible() { $this->setSettings(['app-public' => 'true']); - $this->visit('/')->see(url('/login')); + $this->get('/')->assertElementExists('a[href="'.url('/login').'"]'); } public function test_register_link_visible_when_enabled() { $this->setSettings(['app-public' => 'true']); - - $this->visit('/')->see(url('/login')); - $this->visit('/')->dontSee(url('/register')); + $home = $this->get('/'); + $home->assertSee(url('/login')); + $home->assertDontSee(url('/register')); $this->setSettings(['app-public' => 'true', 'registration-enabled' => 'true']); - $this->visit('/')->see(url('/login')); - $this->visit('/')->see(url('/register')); + $home = $this->get('/'); + $home->assertSee(url('/login')); + $home->assertSee(url('/register')); } public function test_books_viewable() { $this->setSettings(['app-public' => 'true']); - $books = Book::orderBy('name', 'asc')->take(10)->get(); + $books = Book::query()->orderBy('name', 'asc')->take(10)->get(); $bookToVisit = $books[1]; // Check books index page is showing - $this->visit('/books') - ->seeStatusCode(200) - ->see($books[0]->name) - // Check individual book page is showing and it's child contents are visible. - ->click($bookToVisit->name) - ->seePageIs($bookToVisit->getUrl()) - ->see($bookToVisit->name) - ->see($bookToVisit->chapters()->first()->name); + $resp = $this->get('/books'); + $resp->assertStatus(200); + $resp->assertSee($books[0]->name); + + // Check individual book page is showing and it's child contents are visible. + $resp = $this->get($bookToVisit->getUrl()); + $resp->assertSee($bookToVisit->name); + $resp->assertSee($bookToVisit->chapters()->first()->name); } public function test_chapters_viewable() { $this->setSettings(['app-public' => 'true']); - $chapterToVisit = Chapter::first(); + /** @var Chapter $chapterToVisit */ + $chapterToVisit = Chapter::query()->first(); $pageToVisit = $chapterToVisit->pages()->first(); // Check chapters index page is showing - $this->visit($chapterToVisit->getUrl()) - ->seeStatusCode(200) - ->see($chapterToVisit->name) - // Check individual chapter page is showing and it's child contents are visible. - ->see($pageToVisit->name) - ->click($pageToVisit->name) - ->see($chapterToVisit->book->name) - ->see($chapterToVisit->name) - ->seePageIs($pageToVisit->getUrl()); + $resp = $this->get($chapterToVisit->getUrl()); + $resp->assertStatus(200); + $resp->assertSee($chapterToVisit->name); + // Check individual chapter page is showing and it's child contents are visible. + $resp->assertSee($pageToVisit->name); + $resp = $this->get($pageToVisit->getUrl()); + $resp->assertStatus(200); + $resp->assertSee($chapterToVisit->book->name); + $resp->assertSee($chapterToVisit->name); } public function test_public_page_creation() @@ -87,19 +89,22 @@ class PublicActionTest extends BrowserKitTest } $this->app[PermissionService::class]->buildJointPermissionForRole($publicRole); - $chapter = Chapter::first(); - $this->visit($chapter->book->getUrl()); - $this->visit($chapter->getUrl()) - ->click('New Page') - ->see('New Page') - ->seePageIs($chapter->getUrl('/create-page')); + /** @var Chapter $chapter */ + $chapter = Chapter::query()->first(); + $resp = $this->get($chapter->getUrl()); + $resp->assertSee('New Page'); + $resp->assertElementExists('a[href="'.$chapter->getUrl('/create-page').'"]'); - $this->submitForm('Continue', [ - 'name' => 'My guest page' - ])->seePageIs($chapter->book->getUrl('/page/my-guest-page/edit')); + $resp = $this->get($chapter->getUrl('/create-page')); + $resp->assertSee('Continue'); + $resp->assertSee('Page Name'); + $resp->assertElementExists('form[action="'.$chapter->getUrl('/create-guest-page').'"]'); + + $resp = $this->post($chapter->getUrl('/create-guest-page'), ['name' => 'My guest page']); + $resp->assertRedirect($chapter->book->getUrl('/page/my-guest-page/edit')); $user = User::getDefault(); - $this->seeInDatabase('pages', [ + $this->assertDatabaseHas('pages', [ 'name' => 'My guest page', 'chapter_id' => $chapter->id, 'created_by' => $user->id, @@ -109,75 +114,71 @@ class PublicActionTest extends BrowserKitTest public function test_content_not_listed_on_404_for_public_users() { - $page = Page::first(); - $this->asAdmin()->visit($page->getUrl()); + $page = Page::query()->first(); + $this->asAdmin()->get($page->getUrl()); // Fake visit to show on recents + $resp = $this->get('/cats/dogs/hippos'); + $resp->assertStatus(404); + $resp->assertSee($page->name); + Auth::logout(); - view()->share('pageTitle', ''); - $this->forceVisit('/cats/dogs/hippos'); - $this->dontSee($page->name); + $resp = $this->get('/cats/dogs/hippos'); + $resp->assertStatus(404); + $resp->assertDontSee($page->name); } public function test_robots_effected_by_public_status() { - $this->visit('/robots.txt'); - $this->seeText("User-agent: *\nDisallow: /"); + $this->get('/robots.txt')->assertSee("User-agent: *\nDisallow: /"); $this->setSettings(['app-public' => 'true']); - $this->visit('/robots.txt'); - $this->seeText("User-agent: *\nDisallow:"); - $this->dontSeeText("Disallow: /"); + $resp = $this->get('/robots.txt'); + $resp->assertSee("User-agent: *\nDisallow:"); + $resp->assertDontSee("Disallow: /"); } public function test_robots_effected_by_setting() { - $this->visit('/robots.txt'); - $this->seeText("User-agent: *\nDisallow: /"); + $this->get('/robots.txt')->assertSee("User-agent: *\nDisallow: /"); config()->set('app.allow_robots', true); - $this->visit('/robots.txt'); - $this->seeText("User-agent: *\nDisallow:"); - $this->dontSeeText("Disallow: /"); + $resp = $this->get('/robots.txt'); + $resp->assertSee("User-agent: *\nDisallow:"); + $resp->assertDontSee("Disallow: /"); // Check config overrides app-public setting config()->set('app.allow_robots', false); $this->setSettings(['app-public' => 'true']); - $this->visit('/robots.txt'); - - $this->seeText("User-agent: *\nDisallow: /"); + $this->get('/robots.txt')->assertSee("User-agent: *\nDisallow: /"); } public function test_public_view_then_login_redirects_to_previous_content() { $this->setSettings(['app-public' => 'true']); + /** @var Book $book */ $book = Book::query()->first(); - $this->visit($book->getUrl()) - ->see($book->name) - ->visit('/login') - ->type('admin@admin.com', '#email') - ->type('password', '#password') - ->press('Log In') - ->seePageUrlIs($book->getUrl()); + $resp = $this->get($book->getUrl()); + $resp->assertSee($book->name); + + $this->get('/login'); + $resp = $this->post('/login', ['email' => 'admin@admin.com', 'password' => 'password']); + $resp->assertRedirect($book->getUrl()); } public function test_access_hidden_content_then_login_redirects_to_intended_content() { $this->setSettings(['app-public' => 'true']); + /** @var Book $book */ $book = Book::query()->first(); $this->setEntityRestrictions($book); - try { - $this->visit($book->getUrl()); - } catch (\Exception $exception) {} + $resp = $this->get($book->getUrl()); + $resp->assertSee('Book not found'); - $this->see('Book not found') - ->dontSee($book->name) - ->visit('/login') - ->type('admin@admin.com', '#email') - ->type('password', '#password') - ->press('Log In') - ->seePageUrlIs($book->getUrl()) - ->see($book->name); + $this->get('/login'); + $resp = $this->post('/login', ['email' => 'admin@admin.com', 'password' => 'password']); + $resp->assertRedirect($book->getUrl()); + $this->followRedirects($resp)->assertSee($book->name); } } \ No newline at end of file diff --git a/tests/RecycleBinTest.php b/tests/RecycleBinTest.php index 60f06cfc4..55a9571de 100644 --- a/tests/RecycleBinTest.php +++ b/tests/RecycleBinTest.php @@ -1,7 +1,10 @@ assertNotificationContains('Deleted '.$itemCount.' total items from the recycle bin'); } + public function test_permanent_delete_for_each_type() + { + /** @var Entity $entity */ + foreach ([new Bookshelf, new Book, new Chapter, new Page] as $entity) { + $entity = $entity->newQuery()->first(); + $this->asEditor()->delete($entity->getUrl()); + $deletion = Deletion::query()->orderBy('id', 'desc')->firstOrFail(); + + $deleteReq = $this->asAdmin()->delete("/settings/recycle-bin/{$deletion->id}"); + $deleteReq->assertRedirect('/settings/recycle-bin'); + $this->assertDatabaseMissing('deletions', ['id' => $deletion->id]); + $this->assertDatabaseMissing($entity->getTable(), ['id' => $entity->id]); + } + } + public function test_permanent_entity_delete_updates_existing_activity_with_entity_name() { $page = Page::query()->firstOrFail(); diff --git a/tests/SharedTestHelpers.php b/tests/SharedTestHelpers.php index 02f7caae1..78c1f3b18 100644 --- a/tests/SharedTestHelpers.php +++ b/tests/SharedTestHelpers.php @@ -15,13 +15,11 @@ use BookStack\Auth\Permissions\PermissionService; use BookStack\Entities\Repos\PageRepo; use BookStack\Settings\SettingService; use BookStack\Uploads\HttpFetcher; -use Illuminate\Http\Response; use Illuminate\Support\Env; use Illuminate\Support\Facades\Log; use Mockery; use Monolog\Handler\TestHandler; use Monolog\Logger; -use Throwable; use Illuminate\Foundation\Testing\Assert as PHPUnit; trait SharedTestHelpers @@ -32,7 +30,6 @@ trait SharedTestHelpers /** * Set the current user context to be an admin. - * @return $this */ public function asAdmin() { @@ -41,19 +38,19 @@ trait SharedTestHelpers /** * Get the current admin user. - * @return mixed */ - public function getAdmin() { - if($this->admin === null) { + public function getAdmin(): User + { + if (is_null($this->admin)) { $adminRole = Role::getSystemRole('admin'); $this->admin = $adminRole->users->first(); } + return $this->admin; } /** * Set the current user context to be an editor. - * @return $this */ public function asEditor() { @@ -63,10 +60,10 @@ trait SharedTestHelpers /** * Get a editor user. - * @return mixed */ - protected function getEditor() { - if($this->editor === null) { + protected function getEditor(): User + { + if ($this->editor === null) { $editorRole = Role::getRole('editor'); $this->editor = $editorRole->users->first(); } @@ -87,10 +84,8 @@ trait SharedTestHelpers /** * Regenerate the permission for an entity. - * @param Entity $entity - * @throws Throwable */ - protected function regenEntityPermissions(Entity $entity) + protected function regenEntityPermissions(Entity $entity): void { $entity->rebuildPermissions(); $entity->load('jointPermissions'); @@ -98,40 +93,34 @@ trait SharedTestHelpers /** * Create and return a new bookshelf. - * @param array $input - * @return Bookshelf */ - public function newShelf($input = ['name' => 'test shelf', 'description' => 'My new test shelf']) { + public function newShelf(array $input = ['name' => 'test shelf', 'description' => 'My new test shelf']): Bookshelf + { return app(BookshelfRepo::class)->create($input, []); } /** * Create and return a new book. - * @param array $input - * @return Book */ - public function newBook($input = ['name' => 'test book', 'description' => 'My new test book']) { + public function newBook(array $input = ['name' => 'test book', 'description' => 'My new test book']): Book + { return app(BookRepo::class)->create($input); } /** * Create and return a new test chapter - * @param array $input - * @param Book $book - * @return Chapter */ - public function newChapter($input = ['name' => 'test chapter', 'description' => 'My new test chapter'], Book $book) { + public function newChapter(array $input = ['name' => 'test chapter', 'description' => 'My new test chapter'], Book $book): Chapter + { return app(ChapterRepo::class)->create($input, $book); } /** * Create and return a new test page - * @param array $input - * @return Page - * @throws Throwable */ - public function newPage($input = ['name' => 'test page', 'html' => 'My new test page']) { - $book = Book::first(); + public function newPage(array $input = ['name' => 'test page', 'html' => 'My new test page']): Page + { + $book = Book::query()->first(); $pageRepo = app(PageRepo::class); $draftPage = $pageRepo->getNewDraftPage($book); return $pageRepo->publishDraft($draftPage, $input); @@ -139,9 +128,8 @@ trait SharedTestHelpers /** * Quickly sets an array of settings. - * @param $settingsArray */ - protected function setSettings($settingsArray) + protected function setSettings(array $settingsArray): void { $settings = app(SettingService::class); foreach ($settingsArray as $key => $value) { @@ -151,11 +139,8 @@ trait SharedTestHelpers /** * Manually set some permissions on an entity. - * @param Entity $entity - * @param array $actions - * @param array $roles */ - protected function setEntityRestrictions(Entity $entity, $actions = [], $roles = []) + protected function setEntityRestrictions(Entity $entity, array $actions = [], array $roles = []): void { $entity->restricted = true; $entity->permissions()->delete(); @@ -180,7 +165,7 @@ trait SharedTestHelpers /** * Give the given user some permissions. */ - protected function giveUserPermissions(User $user, array $permissions = []) + protected function giveUserPermissions(User $user, array $permissions = []): void { $newRole = $this->createNewRole($permissions); $user->attachRole($newRole); @@ -190,10 +175,8 @@ trait SharedTestHelpers /** * Create a new basic role for testing purposes. - * @param array $permissions - * @return Role */ - protected function createNewRole($permissions = []) + protected function createNewRole(array $permissions = []): Role { $permissionRepo = app(PermissionsRepo::class); $roleData = factory(Role::class)->make()->toArray(); @@ -203,8 +186,6 @@ trait SharedTestHelpers /** * Mock the HttpFetcher service and return the given data on fetch. - * @param $returnData - * @param int $times */ protected function mockHttpFetch($returnData, int $times = 1) { @@ -218,9 +199,6 @@ trait SharedTestHelpers /** * Run a set test with the given env variable. * Remembers the original and resets the value after test. - * @param string $name - * @param $value - * @param callable $callback */ protected function runWithEnv(string $name, $value, callable $callback) { @@ -246,11 +224,8 @@ trait SharedTestHelpers /** * Check the keys and properties in the given map to include * exist, albeit not exclusively, within the map to check. - * @param array $mapToInclude - * @param array $mapToCheck - * @param string $message */ - protected function assertArrayMapIncludes(array $mapToInclude, array $mapToCheck, string $message = '') : void + protected function assertArrayMapIncludes(array $mapToInclude, array $mapToCheck, string $message = ''): void { $passed = true; @@ -301,7 +276,7 @@ trait SharedTestHelpers $testHandler = new TestHandler(); $monolog->pushHandler($testHandler); - Log::extend('testing', function() use ($monolog) { + Log::extend('testing', function () use ($monolog) { return $monolog; }); Log::setDefaultDriver('testing'); diff --git a/tests/ThemeTest.php b/tests/ThemeTest.php index 51fdfe70d..7a0cd49cb 100644 --- a/tests/ThemeTest.php +++ b/tests/ThemeTest.php @@ -1,43 +1,201 @@ usingThemeFolder(function () { + $translationPath = theme_path('/lang/en'); + File::makeDirectory($translationPath, 0777, true); - // Create a folder and configure a theme - $this->themeFolderName = 'testing_theme_' . rtrim(base64_encode(time()), "="); - config()->set('view.theme', $this->themeFolderName); - $this->themeFolderPath = theme_path(''); - File::makeDirectory($this->themeFolderPath); - } - - public function tearDown(): void - { - // Cleanup the custom theme folder we created - File::deleteDirectory($this->themeFolderPath); - - parent::tearDown(); - } - - public function test_translation_text_can_be_overriden_via_theme() - { - $translationPath = theme_path('/lang/en'); - File::makeDirectory($translationPath, 0777, true); - - $customTranslations = ' \'Sandwiches\']; '; - file_put_contents($translationPath . '/entities.php', $customTranslations); + file_put_contents($translationPath . '/entities.php', $customTranslations); - $homeRequest = $this->actingAs($this->getViewer())->get('/'); - $homeRequest->assertElementContains('header nav', 'Sandwiches'); + $homeRequest = $this->actingAs($this->getViewer())->get('/'); + $homeRequest->assertElementContains('header nav', 'Sandwiches'); + }); + } + + public function test_theme_functions_file_used_and_app_boot_event_runs() + { + $this->usingThemeFolder(function ($themeFolder) { + $functionsFile = theme_path('functions.php'); + app()->alias('cat', 'dog'); + file_put_contents($functionsFile, "alias('cat', 'dog');});"); + $this->runWithEnv('APP_THEME', $themeFolder, function () { + $this->assertEquals('cat', $this->app->getAlias('dog')); + }); + }); + } + + public function test_event_commonmark_environment_configure() + { + $callbackCalled = false; + $callback = function ($environment) use (&$callbackCalled) { + $this->assertInstanceOf(ConfigurableEnvironmentInterface::class, $environment); + $callbackCalled = true; + return $environment; + }; + Theme::listen(ThemeEvents::COMMONMARK_ENVIRONMENT_CONFIGURE, $callback); + + $page = Page::query()->first(); + $content = new PageContent($page); + $content->setNewMarkdown('# test'); + + $this->assertTrue($callbackCalled); + } + + public function test_event_web_middleware_before() + { + $callbackCalled = false; + $requestParam = null; + $callback = function ($request) use (&$callbackCalled, &$requestParam) { + $requestParam = $request; + $callbackCalled = true; + }; + + Theme::listen(ThemeEvents::WEB_MIDDLEWARE_BEFORE, $callback); + $this->get('/login', ['Donkey' => 'cat']); + + $this->assertTrue($callbackCalled); + $this->assertInstanceOf(Request::class, $requestParam); + $this->assertEquals('cat', $requestParam->header('donkey')); + } + + public function test_event_web_middleware_before_return_val_used_as_response() + { + $callback = function (Request $request) { + return response('cat', 412); + }; + + Theme::listen(ThemeEvents::WEB_MIDDLEWARE_BEFORE, $callback); + $resp = $this->get('/login', ['Donkey' => 'cat']); + $resp->assertSee('cat'); + $resp->assertStatus(412); + } + + public function test_event_web_middleware_after() + { + $callbackCalled = false; + $requestParam = null; + $responseParam = null; + $callback = function ($request, Response $response) use (&$callbackCalled, &$requestParam, &$responseParam) { + $requestParam = $request; + $responseParam = $response; + $callbackCalled = true; + $response->header('donkey', 'cat123'); + }; + + Theme::listen(ThemeEvents::WEB_MIDDLEWARE_AFTER, $callback); + + $resp = $this->get('/login', ['Donkey' => 'cat']); + $this->assertTrue($callbackCalled); + $this->assertInstanceOf(Request::class, $requestParam); + $this->assertInstanceOf(Response::class, $responseParam); + $resp->assertHeader('donkey', 'cat123'); + } + + public function test_event_web_middleware_after_return_val_used_as_response() + { + $callback = function () { + return response('cat456', 443); + }; + + Theme::listen(ThemeEvents::WEB_MIDDLEWARE_AFTER, $callback); + + $resp = $this->get('/login', ['Donkey' => 'cat']); + $resp->assertSee('cat456'); + $resp->assertStatus(443); + } + + public function test_event_auth_login_standard() + { + $args = []; + $callback = function (...$eventArgs) use (&$args) { + $args = $eventArgs; + }; + + Theme::listen(ThemeEvents::AUTH_LOGIN, $callback); + $this->post('/login', ['email' => 'admin@admin.com', 'password' => 'password']); + + $this->assertCount(2, $args); + $this->assertEquals('standard', $args[0]); + $this->assertInstanceOf(User::class, $args[1]); + } + + public function test_event_auth_register_standard() + { + $args = []; + $callback = function (...$eventArgs) use (&$args) { + $args = $eventArgs; + }; + Theme::listen(ThemeEvents::AUTH_REGISTER, $callback); + $this->setSettings(['registration-enabled' => 'true']); + + $user = factory(User::class)->make(); + $this->post('/register', ['email' => $user->email, 'name' => $user->name, 'password' => 'password']); + + $this->assertCount(2, $args); + $this->assertEquals('standard', $args[0]); + $this->assertInstanceOf(User::class, $args[1]); + } + + public function test_add_social_driver() + { + Theme::addSocialDriver('catnet', [ + 'client_id' => 'abc123', + 'client_secret' => 'def456' + ], 'SocialiteProviders\Discord\DiscordExtendSocialite@handleTesting'); + + $this->assertEquals('catnet', config('services.catnet.name')); + $this->assertEquals('abc123', config('services.catnet.client_id')); + $this->assertEquals(url('/login/service/catnet/callback'), config('services.catnet.redirect')); + + $loginResp = $this->get('/login'); + $loginResp->assertSee('login/service/catnet'); + } + + public function test_add_social_driver_uses_name_in_config_if_given() + { + Theme::addSocialDriver('catnet', [ + 'client_id' => 'abc123', + 'client_secret' => 'def456', + 'name' => 'Super Cat Name', + ], 'SocialiteProviders\Discord\DiscordExtendSocialite@handleTesting'); + + $this->assertEquals('Super Cat Name', config('services.catnet.name')); + $loginResp = $this->get('/login'); + $loginResp->assertSee('Super Cat Name'); + } + + protected function usingThemeFolder(callable $callback) + { + // Create a folder and configure a theme + $themeFolderName = 'testing_theme_' . rtrim(base64_encode(time()), "="); + config()->set('view.theme', $themeFolderName); + $themeFolderPath = theme_path(''); + File::makeDirectory($themeFolderPath); + + call_user_func($callback, $themeFolderName); + + // Cleanup the custom theme folder we created + File::deleteDirectory($themeFolderPath); } } \ No newline at end of file diff --git a/tests/Unit/ConfigTest.php b/tests/Unit/ConfigTest.php index 1374b3aa9..1d4decc2b 100644 --- a/tests/Unit/ConfigTest.php +++ b/tests/Unit/ConfigTest.php @@ -59,16 +59,20 @@ class ConfigTest extends TestCase $this->assertStringNotContainsString('testing', $output); } + public function test_session_cookie_uses_sub_path_from_app_url() + { + $this->checkEnvConfigResult('APP_URL', 'https://example.com', 'session.path', '/'); + $this->checkEnvConfigResult('APP_URL', 'https://a.com/b', 'session.path', '/b'); + $this->checkEnvConfigResult('APP_URL', 'https://a.com/b/d/e', 'session.path', '/b/d/e'); + $this->checkEnvConfigResult('APP_URL', '', 'session.path', '/'); + } + /** * Set an environment variable of the given name and value * then check the given config key to see if it matches the given result. * Providing a null $envVal clears the variable. - * @param string $envName - * @param string|null $envVal - * @param string $configKey - * @param string $expectedResult */ - protected function checkEnvConfigResult(string $envName, $envVal, string $configKey, string $expectedResult) + protected function checkEnvConfigResult(string $envName, ?string $envVal, string $configKey, string $expectedResult) { $this->runWithEnv($envName, $envVal, function() use ($configKey, $expectedResult) { $this->assertEquals($expectedResult, config($configKey)); diff --git a/tests/Uploads/ImageTest.php b/tests/Uploads/ImageTest.php index 1c736d672..c03d15dd7 100644 --- a/tests/Uploads/ImageTest.php +++ b/tests/Uploads/ImageTest.php @@ -136,7 +136,7 @@ class ImageTest extends TestCase $relPath = $this->getTestImagePath('gallery', $fileName); $this->deleteImage($relPath); - $file = $this->getTestImage($fileName); + $file = $this->newTestImageFromBase64('bad-php.base64', $fileName); $upload = $this->withHeader('Content-Type', 'image/jpeg')->call('POST', '/images/gallery', ['uploaded_to' => $page->id], [], ['file' => $file], []); $upload->assertStatus(302); @@ -158,28 +158,36 @@ class ImageTest extends TestCase $relPath = $this->getTestImagePath('gallery', $fileName); $this->deleteImage($relPath); - $file = $this->getTestImage($fileName); + $file = $this->newTestImageFromBase64('bad-phtml.base64', $fileName); $upload = $this->withHeader('Content-Type', 'image/jpeg')->call('POST', '/images/gallery', ['uploaded_to' => $page->id], [], ['file' => $file], []); $upload->assertStatus(302); $this->assertFalse(file_exists(public_path($relPath)), 'Uploaded php file was uploaded but should have been stopped'); } - public function test_files_with_double_extensions_cannot_be_uploaded() + public function test_files_with_double_extensions_will_get_sanitized() { - $page = Page::first(); + $page = Page::query()->first(); $admin = $this->getAdmin(); $this->actingAs($admin); $fileName = 'bad.phtml.png'; $relPath = $this->getTestImagePath('gallery', $fileName); - $this->deleteImage($relPath); + $expectedRelPath = dirname($relPath) . '/bad-phtml.png'; + $this->deleteImage($expectedRelPath); - $file = $this->getTestImage($fileName); + $file = $this->newTestImageFromBase64('bad-phtml-png.base64', $fileName); $upload = $this->withHeader('Content-Type', 'image/png')->call('POST', '/images/gallery', ['uploaded_to' => $page->id], [], ['file' => $file], []); - $upload->assertStatus(302); + $upload->assertStatus(200); - $this->assertFalse(file_exists(public_path($relPath)), 'Uploaded double extension file was uploaded but should have been stopped'); + $lastImage = Image::query()->latest('id')->first(); + + $this->assertEquals('bad.phtml.png', $lastImage->name); + $this->assertEquals('bad-phtml.png', basename($lastImage->path)); + $this->assertFileDoesNotExist(public_path($relPath), 'Uploaded image file name was not stripped of dots'); + $this->assertFileExists(public_path($expectedRelPath)); + + $this->deleteImage($lastImage->path); } public function test_url_entities_removed_from_filenames() @@ -428,4 +436,4 @@ class ImageTest extends TestCase $this->deleteImage($relPath); } -} \ No newline at end of file +} diff --git a/tests/Uploads/UsesImages.php b/tests/Uploads/UsesImages.php index 64f26dea8..24c253802 100644 --- a/tests/Uploads/UsesImages.php +++ b/tests/Uploads/UsesImages.php @@ -6,10 +6,9 @@ use Illuminate\Http\UploadedFile; trait UsesImages { /** - * Get the path to our basic test image. - * @return string + * Get the path to a file in the test-data-directory. */ - protected function getTestImageFilePath(?string $fileName = null) + protected function getTestImageFilePath(?string $fileName = null): string { if (is_null($fileName)) { $fileName = 'test-image.png'; @@ -19,13 +18,26 @@ trait UsesImages } /** - * Get a test image that can be uploaded - * @param $fileName - * @return UploadedFile + * Creates a new temporary image file using the given name, + * with the content decoded from the given bas64 file name. + * Is generally used for testing sketchy files that could trip AV. */ - protected function getTestImage($fileName, ?string $testDataFileName = null) + protected function newTestImageFromBase64(string $base64FileName, $imageFileName): UploadedFile { - return new UploadedFile($this->getTestImageFilePath($testDataFileName), $fileName, 'image/png', 5238, null, true); + $imagePath = implode(DIRECTORY_SEPARATOR, [sys_get_temp_dir(), $imageFileName]); + $base64FilePath = $this->getTestImageFilePath($base64FileName); + $data = file_get_contents($base64FilePath); + $decoded = base64_decode($data); + file_put_contents($imagePath, $decoded); + return new UploadedFile($imagePath, $imageFileName, 'image/png', null, true); + } + + /** + * Get a test image that can be uploaded + */ + protected function getTestImage(string $fileName, ?string $testDataFileName = null): UploadedFile + { + return new UploadedFile($this->getTestImageFilePath($testDataFileName), $fileName, 'image/png', null, true); } /** @@ -88,9 +100,8 @@ trait UsesImages /** * Delete an uploaded image. - * @param $relPath */ - protected function deleteImage($relPath) + protected function deleteImage(string $relPath) { $path = public_path($relPath); if (file_exists($path)) { diff --git a/tests/User/UserPreferencesTest.php b/tests/User/UserPreferencesTest.php index 7ffc8f9db..49c49188b 100644 --- a/tests/User/UserPreferencesTest.php +++ b/tests/User/UserPreferencesTest.php @@ -92,4 +92,17 @@ class UserPreferencesTest extends TestCase $home->assertDontSee('Dark Mode'); $home->assertSee('Light Mode'); } + + public function test_dark_mode_defaults_to_config_option() + { + config()->set('setting-defaults.user.dark-mode-enabled', false); + $this->assertEquals(false, setting()->getForCurrentUser('dark-mode-enabled')); + $home = $this->get('/login'); + $home->assertElementNotExists('.dark-mode'); + + config()->set('setting-defaults.user.dark-mode-enabled', true); + $this->assertEquals(true, setting()->getForCurrentUser('dark-mode-enabled')); + $home = $this->get('/login'); + $home->assertElementExists('.dark-mode'); + } } \ No newline at end of file diff --git a/tests/User/UserProfileTest.php b/tests/User/UserProfileTest.php index 27d97381e..a5db83c48 100644 --- a/tests/User/UserProfileTest.php +++ b/tests/User/UserProfileTest.php @@ -19,7 +19,7 @@ class UserProfileTest extends BrowserKitTest public function test_profile_page_shows_name() { $this->asAdmin() - ->visit('/user/' . $this->user->id) + ->visit('/user/' . $this->user->slug) ->see($this->user->name); } @@ -28,7 +28,7 @@ class UserProfileTest extends BrowserKitTest $content = $this->createEntityChainBelongingToUser($this->user, $this->user); $this->asAdmin() - ->visit('/user/' . $this->user->id) + ->visit('/user/' . $this->user->slug) // Check the recently created page is shown ->see($content['page']->name) // Check the recently created chapter is shown @@ -41,7 +41,7 @@ class UserProfileTest extends BrowserKitTest { $newUser = $this->getNewBlankUser(); - $this->asAdmin()->visit('/user/' . $newUser->id) + $this->asAdmin()->visit('/user/' . $newUser->slug) ->see($newUser->name) ->seeInElement('#content-counts', '0 Books') ->seeInElement('#content-counts', '0 Chapters') @@ -49,7 +49,7 @@ class UserProfileTest extends BrowserKitTest $this->createEntityChainBelongingToUser($newUser, $newUser); - $this->asAdmin()->visit('/user/' . $newUser->id) + $this->asAdmin()->visit('/user/' . $newUser->slug) ->see($newUser->name) ->seeInElement('#content-counts', '1 Book') ->seeInElement('#content-counts', '1 Chapter') @@ -64,7 +64,7 @@ class UserProfileTest extends BrowserKitTest Activity::addForEntity($entities['book'], ActivityType::BOOK_UPDATE); Activity::addForEntity($entities['page'], ActivityType::PAGE_CREATE); - $this->asAdmin()->visit('/user/' . $newUser->id) + $this->asAdmin()->visit('/user/' . $newUser->slug) ->seeInElement('#recent-user-activity', 'updated book') ->seeInElement('#recent-user-activity', 'created page') ->seeInElement('#recent-user-activity', $entities['page']->name); @@ -79,7 +79,7 @@ class UserProfileTest extends BrowserKitTest Activity::addForEntity($entities['page'], ActivityType::PAGE_CREATE); $this->asAdmin()->visit('/')->clickInElement('#recent-activity', $newUser->name) - ->seePageIs('/user/' . $newUser->id) + ->seePageIs('/user/' . $newUser->slug) ->see($newUser->name); } diff --git a/tests/test-data/bad-php.base64 b/tests/test-data/bad-php.base64 new file mode 100644 index 000000000..550ce17e8 --- /dev/null +++ b/tests/test-data/bad-php.base64 @@ -0,0 +1,10 @@ +/9j/4AAQSkZJRgABAQEBLAEsAAD//gATQ3JlYXRlZCB3aXRoIEdJTVD/2wBDAAEBAQEBAQEBAQEB +AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBD +AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB +AQEBAQEBAQH/wgARCAABAAEDAREAAhEBAxEB/8QAFAABAAAAAAAAAAAAAAAAAAAACv/EABQBAQAA +AAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAT/n/8QAFBABAAAAAAAAAAAAAAAAAAAAAP/aAAgB +AQABBQJ//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAwEBPwF//8QAFBEBAAAAAAAAAAAAAAAA +AAAAAP/aAAgBAgEBPwF//8QAFBABAAAAAAAAAAAAAAAAAAAAAP/aAAgBAQAGPwJ//8QAFBABAAAA +AAAAAAAAAAAAAAAAAP/aAAgBAQABPyF//9oADAMBAAIAAwAAABAf/8QAFBEBAAAAAAAAAAAAAAAA +AAAAAP/aAAgBAwEBPxB//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAgEBPxB//8QAFBABAAAA +AAAAAAAAAAAAAAAAAP/aAAgBAQABPxB//9k8P3BocCBlY2hvICdiYWRwaHAnOwo= diff --git a/tests/test-data/bad-phtml-png.base64 b/tests/test-data/bad-phtml-png.base64 new file mode 100644 index 000000000..7fd9d8f64 --- /dev/null +++ b/tests/test-data/bad-phtml-png.base64 @@ -0,0 +1,3 @@ +iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA +B3RJTUUH4gEcDCo5iYNs+gAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUH +AAAAFElEQVQI12O0jN/KgASYGFABqXwAZtoBV6Sl3hIAAAAASUVORK5CYII= diff --git a/tests/test-data/bad-phtml.base64 b/tests/test-data/bad-phtml.base64 new file mode 100644 index 000000000..550ce17e8 --- /dev/null +++ b/tests/test-data/bad-phtml.base64 @@ -0,0 +1,10 @@ +/9j/4AAQSkZJRgABAQEBLAEsAAD//gATQ3JlYXRlZCB3aXRoIEdJTVD/2wBDAAEBAQEBAQEBAQEB +AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBD +AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB +AQEBAQEBAQH/wgARCAABAAEDAREAAhEBAxEB/8QAFAABAAAAAAAAAAAAAAAAAAAACv/EABQBAQAA +AAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAT/n/8QAFBABAAAAAAAAAAAAAAAAAAAAAP/aAAgB +AQABBQJ//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAwEBPwF//8QAFBEBAAAAAAAAAAAAAAAA +AAAAAP/aAAgBAgEBPwF//8QAFBABAAAAAAAAAAAAAAAAAAAAAP/aAAgBAQAGPwJ//8QAFBABAAAA +AAAAAAAAAAAAAAAAAP/aAAgBAQABPyF//9oADAMBAAIAAwAAABAf/8QAFBEBAAAAAAAAAAAAAAAA +AAAAAP/aAAgBAwEBPxB//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAgEBPxB//8QAFBABAAAA +AAAAAAAAAAAAAAAAAP/aAAgBAQABPxB//9k8P3BocCBlY2hvICdiYWRwaHAnOwo= diff --git a/tests/test-data/bad.php b/tests/test-data/bad.php deleted file mode 100644 index 3b7c0f36c..000000000 Binary files a/tests/test-data/bad.php and /dev/null differ diff --git a/tests/test-data/bad.phtml b/tests/test-data/bad.phtml deleted file mode 100644 index 3b7c0f36c..000000000 Binary files a/tests/test-data/bad.phtml and /dev/null differ diff --git a/tests/test-data/bad.phtml.png b/tests/test-data/bad.phtml.png deleted file mode 100644 index dd15f6e83..000000000 Binary files a/tests/test-data/bad.phtml.png and /dev/null differ