diff --git a/.env.example.complete b/.env.example.complete index 829a7509b..04cd73b90 100644 --- a/.env.example.complete +++ b/.env.example.complete @@ -37,6 +37,11 @@ APP_AUTO_LANG_PUBLIC=true # Valid timezone values can be found here: https://www.php.net/manual/en/timezones.php APP_TIMEZONE=UTC +# Application theme +# Used to specific a themes/ folder where BookStack UI +# overrides can be made. Defaults to disabled. +APP_THEME=false + # Database details # Host can contain a port (localhost:3306) or a separate DB_PORT option can be used. DB_HOST=localhost @@ -89,7 +94,7 @@ REDIS_SERVERS=127.0.0.1:6379:0 # Queue driver to use # Queue not really currently used but may be configurable in the future. # Would advise not to change this for now. -QUEUE_DRIVER=sync +QUEUE_CONNECTION=sync # Storage system to use # Can be 'local', 'local_secure' or 's3' @@ -121,7 +126,7 @@ STORAGE_S3_ENDPOINT=https://my-custom-s3-compatible.service.com:8001 STORAGE_URL=false # Authentication method to use -# Can be 'standard' or 'ldap' +# Can be 'standard', 'ldap' or 'saml2' AUTH_METHOD=standard # Social authentication configuration @@ -191,6 +196,7 @@ LDAP_PASS=false LDAP_USER_FILTER=false LDAP_VERSION=false LDAP_TLS_INSECURE=false +LDAP_ID_ATTRIBUTE=uid LDAP_EMAIL_ATTRIBUTE=mail LDAP_DISPLAY_NAME_ATTRIBUTE=cn LDAP_FOLLOW_REFERRALS=true @@ -201,6 +207,26 @@ LDAP_USER_TO_GROUPS=false LDAP_GROUP_ATTRIBUTE="memberOf" LDAP_REMOVE_FROM_GROUPS=false +# SAML authentication configuration +# Refer to https://www.bookstackapp.com/docs/admin/saml2-auth/ +SAML2_NAME=SSO +SAML2_EMAIL_ATTRIBUTE=email +SAML2_DISPLAY_NAME_ATTRIBUTES=username +SAML2_EXTERNAL_ID_ATTRIBUTE=null +SAML2_IDP_ENTITYID=null +SAML2_IDP_SSO=null +SAML2_IDP_SLO=null +SAML2_IDP_x509=null +SAML2_ONELOGIN_OVERRIDES=null +SAML2_DUMP_USER_DETAILS=false +SAML2_AUTOLOAD_METADATA=false + +# SAML group sync configuration +# Refer to https://www.bookstackapp.com/docs/admin/saml2-auth/ +SAML2_USER_TO_GROUPS=false +SAML2_GROUP_ATTRIBUTE=group +SAML2_REMOVE_FROM_GROUPS=false + # Disable default third-party services such as Gravatar and Draw.IO # Service-specific options will override this option DISABLE_EXTERNAL_SERVICES=false @@ -235,3 +261,9 @@ ALLOW_CONTENT_SCRIPTS=false # Contents of the robots.txt file can be overridden, making this option obsolete. ALLOW_ROBOTS=null +# The default and maximum item-counts for listing API requests. +API_DEFAULT_ITEM_COUNT=100 +API_MAX_ITEM_COUNT=500 + +# The number of API requests that can be made per minute by a single user. +API_REQUESTS_PER_MIN=180 \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 8b3d29c2d..c4444f242 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,5 +1,5 @@ --- -name: Bug report +name: Bug Report about: Create a report to help us improve --- diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 7f38b9cdc..781cca5b8 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,5 +1,5 @@ --- -name: Feature request +name: Feature Request about: Suggest an idea for this project --- diff --git a/.github/ISSUE_TEMPLATE/language_request.md b/.github/ISSUE_TEMPLATE/language_request.md new file mode 100644 index 000000000..249ef7871 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/language_request.md @@ -0,0 +1,13 @@ +--- +name: Language Request +about: Request a new language to be added to Crowdin for you to translate + +--- + +### Language To Add + +_Specify here the language you want to add._ + +---- + +_This issue template is to request a new language be added to our [Crowdin translation management project](https://crowdin.com/project/bookstack). Please don't use this template to request a new language that you are not prepared to provide translations for._ \ No newline at end of file diff --git a/.github/translators.txt b/.github/translators.txt new file mode 100644 index 000000000..c8d505e82 --- /dev/null +++ b/.github/translators.txt @@ -0,0 +1,73 @@ +Name :: Languages +@robertlandes :: German +@SergioMendolia :: French +@NakaharaL :: Portuguese, Brazilian +@ReeseSebastian :: German +@arietimmerman :: Dutch +@diegoseso :: Spanish +@S64 :: Japanese +@JachuPL :: Polish +@Joorem :: French +@timoschwarzer :: German +@sanderdw :: Dutch +@lbguilherme :: Portuguese, Brazilian +@marcusforsberg :: Swedish +@artur-trzesiok :: Polish +@Alwaysin :: French +@msaus :: Japanese +@moucho :: Spanish +@vriic :: German +@DeehSlash :: Portuguese, Brazilian +@alex2702 :: German +@nicobubulle :: French +@kmoj86 :: Arabic +@houbaron :: Chinese Traditional; Chinese Simplified +@mullinsmikey :: Russian +@limkukhyun :: Korean +@CliffyPrime :: German +@kejjang :: Chinese Traditional +@TheLastOperator :: French +@qianmengnet :: Simplified Chinese +@ezzra :: German; German Informal +@vasiliev123 :: Polish +@Mant1kor :: Ukrainian +@Xiphoseer :: German; German Informal +@maantje :: Dutch +@cima :: Czech +@agvol :: Russian +@Hambern :: Swedish +@NootoNooto :: Dutch +@kostefun :: Russian +@lucaguindani :: French +@miles75 :: Hungarian +@danielroehrig-mm :: German +@oykenfurkan :: Turkish +@qligier :: French +@johnroyer :: Traditional Chinese +@artskoczylas :: Polish +@dellamina :: Italian +@jzoy :: Simplified Chinese +@ististudio :: Korean +@leomartinez :: Spanish Argentina +cipi1965 :: Italian +Mykola Ronik (Mantikor) :: Ukrainian +furkanoyk :: Turkish +m0uch0 :: Spanish +Maxim Zalata (zlatin) :: Russian; Ukrainian +nutsflag :: French +Leonardo Mario Martinez (leonardo.m.martinez) :: Spanish, Argentina +Rodrigo Saczuk Niz (rodrigoniz) :: Portuguese, Brazilian +叫钦叔就好 (254351722) :: Chinese Traditional; Chinese Simplified +aekramer :: Dutch +JachuPL :: Polish +milesteg :: Hungarian +Beenbag :: German +Lett3rs :: Danish +Julian (julian.henneberg) :: German; German Informal +3GNWn :: Danish +dbguichu :: Chinese Simplified +Randy Kim (hyunjun) :: Korean +Francesco M. Taurino (ftaurino) :: Italian +DanielFrederiksen :: Danish +Finn Wessel (19finnwessel6) :: German +Gustav Kånåhols (Kurbitz) :: Swedish diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml new file mode 100644 index 000000000..f6c002c05 --- /dev/null +++ b/.github/workflows/phpunit.yml @@ -0,0 +1,50 @@ +name: phpunit + +on: + push: + branches: + - master + - release + pull_request: + branches: + - '*' + - '*/*' + - '!l10n_master' + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + php: [7.2, 7.3] + steps: + - uses: actions/checkout@v1 + + - name: Get Composer Cache Directory + id: composer-cache + run: | + echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache composer packages + uses: actions/cache@v1 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ matrix.php }} + + - 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 "GRANT ALL ON \`bookstack-test\`.* TO 'bookstack-test'@'localhost';" + mysql -uroot -proot -e 'FLUSH PRIVILEGES;' + + - name: Install composer dependencies & Test + run: composer install --prefer-dist --no-interaction --ansi + + - name: Migrate and seed the database + run: | + php${{ matrix.php }} artisan migrate --force -n --database=mysql_testing + php${{ matrix.php }} artisan db:seed --force -n --class=DummyContentSeeder --database=mysql_testing + + - name: phpunit + run: php${{ matrix.php }} ./vendor/bin/phpunit diff --git a/.gitignore b/.gitignore index 4b8d88ca4..057192034 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,6 @@ nbproject .buildpath .project .settings/ -webpack-stats.json \ No newline at end of file +webpack-stats.json +.phpunit.result.cache +.DS_Store \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 29727f488..000000000 --- a/.travis.yml +++ /dev/null @@ -1,28 +0,0 @@ -dist: trusty -sudo: false -language: php -php: - - 7.0.20 - - 7.1.9 - -cache: - directories: - - $HOME/.composer/cache - -before_script: - - mysql -u root -e 'create database `bookstack-test`;' - - mysql -u root -e "CREATE USER 'bookstack-test'@'localhost' IDENTIFIED BY 'bookstack-test';" - - mysql -u root -e "GRANT ALL ON \`bookstack-test\`.* TO 'bookstack-test'@'localhost';" - - mysql -u root -e "FLUSH PRIVILEGES;" - - phpenv config-rm xdebug.ini - - composer install --prefer-dist --no-interaction - - php artisan clear-compiled -n - - php artisan optimize -n - - php artisan migrate --force -n --database=mysql_testing - - php artisan db:seed --force -n --class=DummyContentSeeder --database=mysql_testing - -after_failure: - - cat storage/logs/laravel.log - -script: - - phpunit diff --git a/app/Actions/Activity.php b/app/Actions/Activity.php index 1ae1811e1..05f0129dd 100644 --- a/app/Actions/Activity.php +++ b/app/Actions/Activity.php @@ -3,13 +3,18 @@ namespace BookStack\Actions; use BookStack\Auth\User; +use BookStack\Entities\Entity; use BookStack\Model; /** - * @property string key - * @property \User user - * @property \Entity entity - * @property string extra + * @property string $key + * @property User $user + * @property Entity $entity + * @property string $extra + * @property string $entity_type + * @property int $entity_id + * @property int $user_id + * @property int $book_id */ class Activity extends Model { diff --git a/app/Actions/ActivityService.php b/app/Actions/ActivityService.php index f4f82a6f4..f56f1ca57 100644 --- a/app/Actions/ActivityService.php +++ b/app/Actions/ActivityService.php @@ -1,8 +1,8 @@ activity->newInstance(); - $activity->user_id = $this->user->id; - $activity->book_id = $bookId; - $activity->key = strtolower($activityKey); - if ($extra !== false) { - $activity->extra = $extra; - } + $activity = $this->newActivityForUser($activityKey, $bookId); $entity->activity()->save($activity); $this->setNotification($activityKey); } /** - * Adds a activity history with a message & without binding to a entity. - * @param $activityKey + * Adds a activity history with a message, without binding to a entity. + * @param string $activityKey + * @param string $message * @param int $bookId - * @param bool|false $extra */ - public function addMessage($activityKey, $bookId = 0, $extra = false) + public function addMessage(string $activityKey, string $message, int $bookId = null) { - $this->activity->user_id = $this->user->id; - $this->activity->book_id = $bookId; - $this->activity->key = strtolower($activityKey); - if ($extra !== false) { - $this->activity->extra = $extra; - } - $this->activity->save(); + $this->newActivityForUser($activityKey, $bookId)->forceFill([ + 'extra' => $message + ])->save(); + $this->setNotification($activityKey); } + /** + * Get a new activity instance for the current user. + * @param string $key + * @param int|null $bookId + * @return Activity + */ + protected function newActivityForUser(string $key, int $bookId = null) + { + return $this->activity->newInstance()->forceFill([ + 'key' => strtolower($key), + 'user_id' => $this->user->id, + 'book_id' => $bookId ?? 0, + ]); + } /** * Removes the entity attachment from each of its activities * and instead uses the 'extra' field with the entities name. * Used when an entity is deleted. - * @param Entity $entity + * @param \BookStack\Entities\Entity $entity * @return mixed */ public function removeEntity(Entity $entity) { + // TODO - Rewrite to db query. $activities = $entity->activity; foreach ($activities as $activity) { $activity->extra = $entity->name; @@ -90,7 +95,11 @@ class ActivityService { $activityList = $this->permissionService ->filterRestrictedEntityRelations($this->activity, 'activities', 'entity_id', 'entity_type') - ->orderBy('created_at', 'desc')->with('user', 'entity')->skip($count * $page)->take($count)->get(); + ->orderBy('created_at', 'desc') + ->with('user', 'entity') + ->skip($count * $page) + ->take($count) + ->get(); return $this->filterSimilar($activityList); } @@ -98,7 +107,7 @@ class ActivityService /** * Gets the latest activity for an entity, Filtering out similar * items to prevent a message activity list. - * @param Entity $entity + * @param \BookStack\Entities\Entity $entity * @param int $count * @param int $page * @return array @@ -171,7 +180,7 @@ class ActivityService $notificationTextKey = 'activities.' . $activityKey . '_notification'; if (trans()->has($notificationTextKey)) { $message = trans($notificationTextKey); - Session::flash('success', $message); + session()->flash('success', $message); } } } diff --git a/app/Actions/ViewService.php b/app/Actions/ViewService.php index 532f31c42..324bfaa4e 100644 --- a/app/Actions/ViewService.php +++ b/app/Actions/ViewService.php @@ -1,8 +1,10 @@ views()->save($this->view->create([ + $entity->views()->save($this->view->newInstance([ 'user_id' => $user->id, 'views' => 1 ])); @@ -59,12 +61,12 @@ class ViewService * @param string $action - used for permission checking * @return Collection */ - public function getPopular(int $count = 10, int $page = 0, $filterModels = null, string $action = 'view') + public function getPopular(int $count = 10, int $page = 0, array $filterModels = null, string $action = 'view') { $skipCount = $count * $page; $query = $this->permissionService ->filterRestrictedEntityRelations($this->view, 'views', 'viewable_id', 'viewable_type', $action) - ->select('*', 'viewable_id', 'viewable_type', \DB::raw('SUM(views) as view_count')) + ->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 new file mode 100644 index 000000000..a0c45608a --- /dev/null +++ b/app/Api/ApiDocsGenerator.php @@ -0,0 +1,125 @@ +getFlatApiRoutes(); + $apiRoutes = $this->loadDetailsFromControllers($apiRoutes); + $apiRoutes = $this->loadDetailsFromFiles($apiRoutes); + $apiRoutes = $apiRoutes->groupBy('base_model'); + return $apiRoutes; + } + + /** + * Load any API details stored in static files. + */ + protected function loadDetailsFromFiles(Collection $routes): Collection + { + return $routes->map(function (array $route) { + $exampleTypes = ['request', 'response']; + foreach ($exampleTypes as $exampleType) { + $exampleFile = base_path("dev/api/{$exampleType}s/{$route['name']}.json"); + $exampleContent = file_exists($exampleFile) ? file_get_contents($exampleFile) : null; + $route["example_{$exampleType}"] = $exampleContent; + } + return $route; + }); + } + + /** + * Load any details we can fetch from the controller and its methods. + */ + protected function loadDetailsFromControllers(Collection $routes): Collection + { + return $routes->map(function (array $route) { + $method = $this->getReflectionMethod($route['controller'], $route['controller_method']); + $comment = $method->getDocComment(); + $route['description'] = $comment ? $this->parseDescriptionFromMethodComment($comment) : null; + $route['body_params'] = $this->getBodyParamsFromClass($route['controller'], $route['controller_method']); + return $route; + }); + } + + /** + * Load body params and their rules by inspecting the given class and method name. + * @throws \Illuminate\Contracts\Container\BindingResolutionException + */ + protected function getBodyParamsFromClass(string $className, string $methodName): ?array + { + /** @var ApiController $class */ + $class = $this->controllerClasses[$className] ?? null; + if ($class === null) { + $class = app()->make($className); + $this->controllerClasses[$className] = $class; + } + + $rules = $class->getValdationRules()[$methodName] ?? []; + foreach ($rules as $param => $ruleString) { + $rules[$param] = explode('|', $ruleString); + } + return count($rules) > 0 ? $rules : null; + } + + /** + * Parse out the description text from a class method comment. + */ + protected function parseDescriptionFromMethodComment(string $comment) + { + $matches = []; + preg_match_all('/^\s*?\*\s((?![@\s]).*?)$/m', $comment, $matches); + return implode(' ', $matches[1] ?? []); + } + + /** + * Get a reflection method from the given class name and method name. + * @throws ReflectionException + */ + protected function getReflectionMethod(string $className, string $methodName): ReflectionMethod + { + $class = $this->reflectionClasses[$className] ?? null; + if ($class === null) { + $class = new ReflectionClass($className); + $this->reflectionClasses[$className] = $class; + } + + return $class->getMethod($methodName); + } + + /** + * Get the system API routes, formatted into a flat collection. + */ + protected function getFlatApiRoutes(): Collection + { + return collect(Route::getRoutes()->getRoutes())->filter(function ($route) { + return strpos($route->uri, 'api/') === 0; + })->map(function ($route) { + [$controller, $controllerMethod] = explode('@', $route->action['uses']); + $baseModelName = explode('.', explode('/', $route->uri)[1])[0]; + $shortName = $baseModelName . '-' . $controllerMethod; + return [ + 'name' => $shortName, + 'uri' => $route->uri, + 'method' => $route->methods[0], + 'controller' => $controller, + 'controller_method' => $controllerMethod, + 'base_model' => $baseModelName, + ]; + }); + } + +} \ No newline at end of file diff --git a/app/Api/ApiToken.php b/app/Api/ApiToken.php new file mode 100644 index 000000000..523c3b8b8 --- /dev/null +++ b/app/Api/ApiToken.php @@ -0,0 +1,31 @@ + 'date:Y-m-d' + ]; + + /** + * Get the user that this token belongs to. + */ + public function user(): BelongsTo + { + return $this->belongsTo(User::class); + } + + /** + * Get the default expiry value for an API token. + * Set to 100 years from now. + */ + public static function defaultExpiry(): string + { + return Carbon::now()->addYears(100)->format('Y-m-d'); + } +} diff --git a/app/Api/ApiTokenGuard.php b/app/Api/ApiTokenGuard.php new file mode 100644 index 000000000..e0a50ebe3 --- /dev/null +++ b/app/Api/ApiTokenGuard.php @@ -0,0 +1,166 @@ +request = $request; + } + + /** + * @inheritDoc + */ + public function user() + { + // Return the user if we've already retrieved them. + // Effectively a request-instance cache for this method. + if (!is_null($this->user)) { + return $this->user; + } + + $user = null; + try { + $user = $this->getAuthorisedUserFromRequest(); + } catch (ApiAuthException $exception) { + $this->lastAuthException = $exception; + } + + $this->user = $user; + return $user; + } + + /** + * Determine if current user is authenticated. If not, throw an exception. + * + * @return \Illuminate\Contracts\Auth\Authenticatable + * + * @throws ApiAuthException + */ + public function authenticate() + { + if (! is_null($user = $this->user())) { + return $user; + } + + if ($this->lastAuthException) { + throw $this->lastAuthException; + } + + throw new ApiAuthException('Unauthorized'); + } + + /** + * Check the API token in the request and fetch a valid authorised user. + * @throws ApiAuthException + */ + protected function getAuthorisedUserFromRequest(): Authenticatable + { + $authToken = trim($this->request->headers->get('Authorization', '')); + $this->validateTokenHeaderValue($authToken); + + [$id, $secret] = explode(':', str_replace('Token ', '', $authToken)); + $token = ApiToken::query() + ->where('token_id', '=', $id) + ->with(['user'])->first(); + + $this->validateToken($token, $secret); + + return $token->user; + } + + /** + * Validate the format of the token header value string. + * @throws ApiAuthException + */ + protected function validateTokenHeaderValue(string $authToken): void + { + if (empty($authToken)) { + throw new ApiAuthException(trans('errors.api_no_authorization_found')); + } + + if (strpos($authToken, ':') === false || strpos($authToken, 'Token ') !== 0) { + throw new ApiAuthException(trans('errors.api_bad_authorization_format')); + } + } + + /** + * Validate the given secret against the given token and ensure the token + * currently has access to the instance API. + * @throws ApiAuthException + */ + protected function validateToken(?ApiToken $token, string $secret): void + { + if ($token === null) { + throw new ApiAuthException(trans('errors.api_user_token_not_found')); + } + + if (!Hash::check($secret, $token->secret)) { + throw new ApiAuthException(trans('errors.api_incorrect_token_secret')); + } + + $now = Carbon::now(); + if ($token->expires_at <= $now) { + throw new ApiAuthException(trans('errors.api_user_token_expired'), 403); + } + + if (!$token->user->can('access-api')) { + throw new ApiAuthException(trans('errors.api_user_no_api_permission'), 403); + } + } + + /** + * @inheritDoc + */ + public function validate(array $credentials = []) + { + if (empty($credentials['id']) || empty($credentials['secret'])) { + return false; + } + + $token = ApiToken::query() + ->where('token_id', '=', $credentials['id']) + ->with(['user'])->first(); + + if ($token === null) { + return false; + } + + return Hash::check($credentials['secret'], $token->secret); + } + + /** + * "Log out" the currently authenticated user. + */ + public function logout() + { + $this->user = null; + } +} \ No newline at end of file diff --git a/app/Api/ListingResponseBuilder.php b/app/Api/ListingResponseBuilder.php new file mode 100644 index 000000000..2fa5644c3 --- /dev/null +++ b/app/Api/ListingResponseBuilder.php @@ -0,0 +1,135 @@ + '=', + 'ne' => '!=', + 'gt' => '>', + 'lt' => '<', + 'gte' => '>=', + 'lte' => '<=', + 'like' => 'like' + ]; + + /** + * ListingResponseBuilder constructor. + */ + public function __construct(Builder $query, Request $request, array $fields) + { + $this->query = $query; + $this->request = $request; + $this->fields = $fields; + } + + /** + * Get the response from this builder. + */ + public function toResponse() + { + $data = $this->fetchData(); + $total = $this->query->count(); + + return response()->json([ + 'data' => $data, + 'total' => $total, + ]); + } + + /** + * Fetch the data to return in the response. + */ + protected function fetchData(): Collection + { + $this->applyCountAndOffset($this->query); + $this->applySorting($this->query); + $this->applyFiltering($this->query); + + return $this->query->get($this->fields); + } + + /** + * Apply any filtering operations found in the request. + */ + protected function applyFiltering(Builder $query) + { + $requestFilters = $this->request->get('filter', []); + if (!is_array($requestFilters)) { + return; + } + + $queryFilters = collect($requestFilters)->map(function ($value, $key) { + return $this->requestFilterToQueryFilter($key, $value); + })->filter(function ($value) { + return !is_null($value); + })->values()->toArray(); + + $query->where($queryFilters); + } + + /** + * Convert a request filter query key/value pair into a [field, op, value] where condition. + */ + protected function requestFilterToQueryFilter($fieldKey, $value): ?array + { + $splitKey = explode(':', $fieldKey); + $field = $splitKey[0]; + $filterOperator = $splitKey[1] ?? 'eq'; + + if (!in_array($field, $this->fields)) { + return null; + } + + if (!in_array($filterOperator, array_keys($this->filterOperators))) { + $filterOperator = 'eq'; + } + + $queryOperator = $this->filterOperators[$filterOperator]; + return [$field, $queryOperator, $value]; + } + + /** + * Apply sorting operations to the query from given parameters + * otherwise falling back to the first given field, ascending. + */ + protected function applySorting(Builder $query) + { + $defaultSortName = $this->fields[0]; + $direction = 'asc'; + + $sort = $this->request->get('sort', ''); + if (strpos($sort, '-') === 0) { + $direction = 'desc'; + } + + $sortName = ltrim($sort, '+- '); + if (!in_array($sortName, $this->fields)) { + $sortName = $defaultSortName; + } + + $query->orderBy($sortName, $direction); + } + + /** + * Apply count and offset for paging, based on params from the request while falling + * back to system defined default, taking the max limit into account. + */ + protected function applyCountAndOffset(Builder $query) + { + $offset = max(0, $this->request->get('offset', 0)); + $maxCount = config('api.max_item_count'); + $count = $this->request->get('count', config('api.default_item_count')); + $count = max(min($maxCount, $count), 1); + + $query->skip($offset)->take($count); + } +} diff --git a/app/Application.php b/app/Application.php index 8c56e9dac..499fdeaa6 100644 --- a/app/Application.php +++ b/app/Application.php @@ -13,7 +13,11 @@ class Application extends \Illuminate\Foundation\Application */ public function configPath($path = '') { - return $this->basePath.DIRECTORY_SEPARATOR.'app'.DIRECTORY_SEPARATOR.'Config'.($path ? DIRECTORY_SEPARATOR.$path : $path); + return $this->basePath + . DIRECTORY_SEPARATOR + . 'app' + . DIRECTORY_SEPARATOR + . 'Config' + . ($path ? DIRECTORY_SEPARATOR.$path : $path); } - -} \ No newline at end of file +} diff --git a/app/Auth/Access/EmailConfirmationService.php b/app/Auth/Access/EmailConfirmationService.php index a94c54d19..9aa3b9b98 100644 --- a/app/Auth/Access/EmailConfirmationService.php +++ b/app/Auth/Access/EmailConfirmationService.php @@ -36,5 +36,4 @@ class EmailConfirmationService extends UserTokenService return setting('registration-confirmation') || setting('registration-restrict'); } - } diff --git a/app/Auth/Access/ExternalAuthService.php b/app/Auth/Access/ExternalAuthService.php new file mode 100644 index 000000000..db8bd2dfb --- /dev/null +++ b/app/Auth/Access/ExternalAuthService.php @@ -0,0 +1,81 @@ +external_auth_id) { + return $this->externalIdMatchesGroupNames($role->external_auth_id, $groupNames); + } + + $roleName = str_replace(' ', '-', trim(strtolower($role->display_name))); + return in_array($roleName, $groupNames); + } + + /** + * Check if the given external auth ID string matches one of the given group names. + */ + protected function externalIdMatchesGroupNames(string $externalId, array $groupNames): bool + { + $externalAuthIds = explode(',', strtolower($externalId)); + + foreach ($externalAuthIds as $externalAuthId) { + if (in_array(trim($externalAuthId), $groupNames)) { + return true; + } + } + + return false; + } + + /** + * Match an array of group names to BookStack system roles. + * Formats group names to be lower-case and hyphenated. + * @param array $groupNames + * @return \Illuminate\Support\Collection + */ + protected function matchGroupsToSystemsRoles(array $groupNames) + { + foreach ($groupNames as $i => $groupName) { + $groupNames[$i] = str_replace(' ', '-', trim(strtolower($groupName))); + } + + $roles = Role::query()->where(function (Builder $query) use ($groupNames) { + $query->whereIn('name', $groupNames); + foreach ($groupNames as $groupName) { + $query->orWhere('external_auth_id', 'LIKE', '%' . $groupName . '%'); + } + })->get(); + + $matchedRoles = $roles->filter(function (Role $role) use ($groupNames) { + return $this->roleMatchesGroupNames($role, $groupNames); + }); + + return $matchedRoles->pluck('id'); + } + + /** + * Sync the groups to the user roles for the current user + */ + public function syncWithGroups(User $user, array $userGroups): void + { + // Get the ids for the roles from the names + $groupsAsRoles = $this->matchGroupsToSystemsRoles($userGroups); + + // Sync groups + if ($this->config['remove_from_groups']) { + $user->roles()->sync($groupsAsRoles); + $user->attachDefaultRole(); + } else { + $user->roles()->syncWithoutDetaching($groupsAsRoles); + } + } +} diff --git a/app/Providers/LdapUserProvider.php b/app/Auth/Access/ExternalBaseUserProvider.php similarity index 61% rename from app/Providers/LdapUserProvider.php rename to app/Auth/Access/ExternalBaseUserProvider.php index 9c91def2f..69295ee4e 100644 --- a/app/Providers/LdapUserProvider.php +++ b/app/Auth/Access/ExternalBaseUserProvider.php @@ -1,12 +1,11 @@ model = $model; - $this->ldapService = $ldapService; } /** @@ -44,7 +35,6 @@ class LdapUserProvider implements UserProvider return new $class; } - /** * Retrieve a user by their unique identifier. * @@ -65,12 +55,7 @@ class LdapUserProvider implements UserProvider */ public function retrieveByToken($identifier, $token) { - $model = $this->createModel(); - - return $model->newQuery() - ->where($model->getAuthIdentifierName(), $identifier) - ->where($model->getRememberTokenName(), $token) - ->first(); + return null; } @@ -83,10 +68,7 @@ class LdapUserProvider implements UserProvider */ public function updateRememberToken(Authenticatable $user, $token) { - if ($user->exists) { - $user->setRememberToken($token); - $user->save(); - } + // } /** @@ -97,27 +79,11 @@ class LdapUserProvider implements UserProvider */ public function retrieveByCredentials(array $credentials) { - // Get user via LDAP - $userDetails = $this->ldapService->getUserDetails($credentials['username']); - if ($userDetails === null) { - return null; - } - // Search current user base by looking up a uid $model = $this->createModel(); - $currentUser = $model->newQuery() - ->where('external_auth_id', $userDetails['uid']) + return $model->newQuery() + ->where('external_auth_id', $credentials['external_auth_id']) ->first(); - - if ($currentUser !== null) { - return $currentUser; - } - - $model->name = $userDetails['name']; - $model->external_auth_id = $userDetails['uid']; - $model->email = $userDetails['email']; - $model->email_confirmed = false; - return $model; } /** @@ -129,6 +95,7 @@ class LdapUserProvider implements UserProvider */ public function validateCredentials(Authenticatable $user, array $credentials) { - return $this->ldapService->validateUserCredentials($user, $credentials['username'], $credentials['password']); + // Should be done in the guard. + return false; } } diff --git a/app/Auth/Access/Guards/ExternalBaseSessionGuard.php b/app/Auth/Access/Guards/ExternalBaseSessionGuard.php new file mode 100644 index 000000000..f3d05366d --- /dev/null +++ b/app/Auth/Access/Guards/ExternalBaseSessionGuard.php @@ -0,0 +1,305 @@ +name = $name; + $this->session = $session; + $this->provider = $provider; + $this->registrationService = $registrationService; + } + + /** + * Get the currently authenticated user. + * + * @return \Illuminate\Contracts\Auth\Authenticatable|null + */ + public function user() + { + if ($this->loggedOut) { + return; + } + + // If we've already retrieved the user for the current request we can just + // return it back immediately. We do not want to fetch the user data on + // every call to this method because that would be tremendously slow. + if (! is_null($this->user)) { + return $this->user; + } + + $id = $this->session->get($this->getName()); + + // First we will try to load the user using the + // identifier in the session if one exists. + if (! is_null($id)) { + $this->user = $this->provider->retrieveById($id); + } + + return $this->user; + } + + /** + * Get the ID for the currently authenticated user. + * + * @return int|null + */ + public function id() + { + if ($this->loggedOut) { + return; + } + + return $this->user() + ? $this->user()->getAuthIdentifier() + : $this->session->get($this->getName()); + } + + /** + * Log a user into the application without sessions or cookies. + * + * @param array $credentials + * @return bool + */ + public function once(array $credentials = []) + { + if ($this->validate($credentials)) { + $this->setUser($this->lastAttempted); + + return true; + } + + return false; + } + + /** + * Log the given user ID into the application without sessions or cookies. + * + * @param mixed $id + * @return \Illuminate\Contracts\Auth\Authenticatable|false + */ + public function onceUsingId($id) + { + if (! is_null($user = $this->provider->retrieveById($id))) { + $this->setUser($user); + + return $user; + } + + return false; + } + + /** + * Validate a user's credentials. + * + * @param array $credentials + * @return bool + */ + public function validate(array $credentials = []) + { + return false; + } + + + /** + * Attempt to authenticate a user using the given credentials. + * + * @param array $credentials + * @param bool $remember + * @return bool + */ + public function attempt(array $credentials = [], $remember = false) + { + return false; + } + + /** + * Log the given user ID into the application. + * + * @param mixed $id + * @param bool $remember + * @return \Illuminate\Contracts\Auth\Authenticatable|false + */ + public function loginUsingId($id, $remember = false) + { + if (! is_null($user = $this->provider->retrieveById($id))) { + $this->login($user, $remember); + + return $user; + } + + return false; + } + + /** + * Log a user into the application. + * + * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param bool $remember + * @return void + */ + public function login(AuthenticatableContract $user, $remember = false) + { + $this->updateSession($user->getAuthIdentifier()); + + $this->setUser($user); + } + + /** + * Update the session with the given ID. + * + * @param string $id + * @return void + */ + protected function updateSession($id) + { + $this->session->put($this->getName(), $id); + + $this->session->migrate(true); + } + + /** + * Log the user out of the application. + * + * @return void + */ + public function logout() + { + $this->clearUserDataFromStorage(); + + // Now we will clear the users out of memory so they are no longer available + // as the user is no longer considered as being signed into this + // application and should not be available here. + $this->user = null; + + $this->loggedOut = true; + } + + /** + * Remove the user data from the session and cookies. + * + * @return void + */ + protected function clearUserDataFromStorage() + { + $this->session->remove($this->getName()); + } + + /** + * Get the last user we attempted to authenticate. + * + * @return \Illuminate\Contracts\Auth\Authenticatable + */ + public function getLastAttempted() + { + return $this->lastAttempted; + } + + /** + * Get a unique identifier for the auth session value. + * + * @return string + */ + public function getName() + { + return 'login_'.$this->name.'_'.sha1(static::class); + } + + /** + * Determine if the user was authenticated via "remember me" cookie. + * + * @return bool + */ + public function viaRemember() + { + return false; + } + + /** + * Return the currently cached user. + * + * @return \Illuminate\Contracts\Auth\Authenticatable|null + */ + public function getUser() + { + return $this->user; + } + + /** + * Set the current user. + * + * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @return $this + */ + public function setUser(AuthenticatableContract $user) + { + $this->user = $user; + + $this->loggedOut = false; + + return $this; + } + +} diff --git a/app/Auth/Access/Guards/LdapSessionGuard.php b/app/Auth/Access/Guards/LdapSessionGuard.php new file mode 100644 index 000000000..3c98140f6 --- /dev/null +++ b/app/Auth/Access/Guards/LdapSessionGuard.php @@ -0,0 +1,114 @@ +ldapService = $ldapService; + parent::__construct($name, $provider, $session, $registrationService); + } + + /** + * Validate a user's credentials. + * + * @param array $credentials + * @return bool + * @throws LdapException + */ + public function validate(array $credentials = []) + { + $userDetails = $this->ldapService->getUserDetails($credentials['username']); + $this->lastAttempted = $this->provider->retrieveByCredentials([ + 'external_auth_id' => $userDetails['uid'] + ]); + + return $this->ldapService->validateUserCredentials($userDetails, $credentials['username'], $credentials['password']); + } + + /** + * Attempt to authenticate a user using the given credentials. + * + * @param array $credentials + * @param bool $remember + * @return bool + * @throws LoginAttemptEmailNeededException + * @throws LoginAttemptException + * @throws LdapException + * @throws UserRegistrationException + */ + public function attempt(array $credentials = [], $remember = false) + { + $username = $credentials['username']; + $userDetails = $this->ldapService->getUserDetails($username); + $this->lastAttempted = $user = $this->provider->retrieveByCredentials([ + 'external_auth_id' => $userDetails['uid'] + ]); + + if (!$this->ldapService->validateUserCredentials($userDetails, $username, $credentials['password'])) { + return false; + } + + if (is_null($user)) { + $user = $this->createNewFromLdapAndCreds($userDetails, $credentials); + } + + // Sync LDAP groups if required + if ($this->ldapService->shouldSyncGroups()) { + $this->ldapService->syncGroups($user, $username); + } + + $this->login($user, $remember); + return true; + } + + /** + * Create a new user from the given ldap credentials and login credentials + * @throws LoginAttemptEmailNeededException + * @throws LoginAttemptException + * @throws UserRegistrationException + */ + protected function createNewFromLdapAndCreds(array $ldapUserDetails, array $credentials): User + { + $email = trim($ldapUserDetails['email'] ?: ($credentials['email'] ?? '')); + + if (empty($email)) { + throw new LoginAttemptEmailNeededException(); + } + + $details = [ + 'name' => $ldapUserDetails['name'], + 'email' => $ldapUserDetails['email'] ?: $credentials['email'], + 'external_auth_id' => $ldapUserDetails['uid'], + 'password' => Str::random(32), + ]; + + return $this->registrationService->registerUser($details, null, false); + } + +} diff --git a/app/Auth/Access/Guards/Saml2SessionGuard.php b/app/Auth/Access/Guards/Saml2SessionGuard.php new file mode 100644 index 000000000..4023913ed --- /dev/null +++ b/app/Auth/Access/Guards/Saml2SessionGuard.php @@ -0,0 +1,40 @@ +ldap = $ldap; $this->config = config('services.ldap'); - $this->userRepo = $userRepo; $this->enabled = config('auth.method') === 'ldap'; } @@ -45,13 +36,10 @@ class LdapService } /** - * Search for attributes for a specific user on the ldap - * @param string $userName - * @param array $attributes - * @return null|array + * Search for attributes for a specific user on the ldap. * @throws LdapException */ - private function getUserWithAttributes($userName, $attributes) + private function getUserWithAttributes(string $userName, array $attributes): ?array { $ldapConnection = $this->getConnection(); $this->bindSystemUser($ldapConnection); @@ -73,16 +61,15 @@ class LdapService /** * Get the details of a user from LDAP using the given username. * User found via configurable user filter. - * @param $userName - * @return array|null * @throws LdapException */ - public function getUserDetails($userName) + public function getUserDetails(string $userName): ?array { + $idAttr = $this->config['id_attribute']; $emailAttr = $this->config['email_attribute']; $displayNameAttr = $this->config['display_name_attribute']; - $user = $this->getUserWithAttributes($userName, ['cn', 'uid', 'dn', $emailAttr, $displayNameAttr]); + $user = $this->getUserWithAttributes($userName, ['cn', 'dn', $idAttr, $emailAttr, $displayNameAttr]); if ($user === null) { return null; @@ -90,7 +77,7 @@ class LdapService $userCn = $this->getUserResponseProperty($user, 'cn', null); return [ - 'uid' => $this->getUserResponseProperty($user, 'uid', $user['dn']), + 'uid' => $this->getUserResponseProperty($user, $idAttr, $user['dn']), 'name' => $this->getUserResponseProperty($user, $displayNameAttr, $userCn), 'dn' => $user['dn'], 'email' => $this->getUserResponseProperty($user, $emailAttr, null), @@ -100,13 +87,10 @@ class LdapService /** * Get a property from an LDAP user response fetch. * Handles properties potentially being part of an array. - * @param array $userDetails - * @param string $propertyKey - * @param $defaultValue - * @return mixed */ protected function getUserResponseProperty(array $userDetails, string $propertyKey, $defaultValue) { + $propertyKey = strtolower($propertyKey); if (isset($userDetails[$propertyKey])) { return (is_array($userDetails[$propertyKey]) ? $userDetails[$propertyKey][0] : $userDetails[$propertyKey]); } @@ -115,27 +99,19 @@ class LdapService } /** - * @param Authenticatable $user - * @param string $username - * @param string $password - * @return bool + * Check if the given credentials are valid for the given user. * @throws LdapException */ - public function validateUserCredentials(Authenticatable $user, $username, $password) + public function validateUserCredentials(array $ldapUserDetails, string $username, string $password): bool { - $ldapUser = $this->getUserDetails($username); - if ($ldapUser === null) { - return false; - } - - if ($ldapUser['uid'] !== $user->external_auth_id) { + if ($ldapUserDetails === null) { return false; } $ldapConnection = $this->getConnection(); try { - $ldapBind = $this->ldap->bind($ldapConnection, $ldapUser['dn'], $password); - } catch (\ErrorException $e) { + $ldapBind = $this->ldap->bind($ldapConnection, $ldapUserDetails['dn'], $password); + } catch (ErrorException $e) { $ldapBind = false; } @@ -205,12 +181,10 @@ class LdapService } /** - * Parse a LDAP server string and return the host and port for - * a connection. Is flexible to formats such as 'ldap.example.com:8069' or 'ldaps://ldap.example.com' - * @param $serverString - * @return array + * Parse a LDAP server string and return the host and port for a connection. + * Is flexible to formats such as 'ldap.example.com:8069' or 'ldaps://ldap.example.com'. */ - protected function parseServerString($serverString) + protected function parseServerString(string $serverString): array { $serverNameParts = explode(':', $serverString); @@ -227,11 +201,8 @@ class LdapService /** * Build a filter string by injecting common variables. - * @param string $filterString - * @param array $attrs - * @return string */ - protected function buildFilter($filterString, array $attrs) + protected function buildFilter(string $filterString, array $attrs): string { $newAttrs = []; foreach ($attrs as $key => $attrText) { @@ -242,12 +213,10 @@ class LdapService } /** - * Get the groups a user is a part of on ldap - * @param string $userName - * @return array + * Get the groups a user is a part of on ldap. * @throws LdapException */ - public function getUserGroups($userName) + public function getUserGroups(string $userName): array { $groupsAttr = $this->config['group_attribute']; $user = $this->getUserWithAttributes($userName, [$groupsAttr]); @@ -262,40 +231,36 @@ class LdapService } /** - * Get the parent groups of an array of groups - * @param array $groupsArray - * @param array $checked - * @return array + * Get the parent groups of an array of groups. * @throws LdapException */ - private function getGroupsRecursive($groupsArray, $checked) + private function getGroupsRecursive(array $groupsArray, array $checked): array { - $groups_to_add = []; + $groupsToAdd = []; foreach ($groupsArray as $groupName) { if (in_array($groupName, $checked)) { continue; } - $groupsToAdd = $this->getGroupGroups($groupName); - $groups_to_add = array_merge($groups_to_add, $groupsToAdd); + $parentGroups = $this->getGroupGroups($groupName); + $groupsToAdd = array_merge($groupsToAdd, $parentGroups); $checked[] = $groupName; } - $groupsArray = array_unique(array_merge($groupsArray, $groups_to_add), SORT_REGULAR); - if (!empty($groups_to_add)) { - return $this->getGroupsRecursive($groupsArray, $checked); - } else { + $groupsArray = array_unique(array_merge($groupsArray, $groupsToAdd), SORT_REGULAR); + + if (empty($groupsToAdd)) { return $groupsArray; } + + return $this->getGroupsRecursive($groupsArray, $checked); } /** - * Get the parent groups of a single group - * @param string $groupName - * @return array + * Get the parent groups of a single group. * @throws LdapException */ - private function getGroupGroups($groupName) + private function getGroupGroups(string $groupName): array { $ldapConnection = $this->getConnection(); $this->bindSystemUser($ldapConnection); @@ -312,17 +277,14 @@ class LdapService return []; } - $groupGroups = $this->groupFilter($groups[0]); - return $groupGroups; + return $this->groupFilter($groups[0]); } /** - * Filter out LDAP CN and DN language in a ldap search return - * Gets the base CN (common name) of the string - * @param array $userGroupSearchResponse - * @return array + * Filter out LDAP CN and DN language in a ldap search return. + * Gets the base CN (common name) of the string. */ - protected function groupFilter(array $userGroupSearchResponse) + protected function groupFilter(array $userGroupSearchResponse): array { $groupsAttr = strtolower($this->config['group_attribute']); $ldapGroups = []; @@ -343,73 +305,12 @@ class LdapService } /** - * Sync the LDAP groups to the user roles for the current user - * @param \BookStack\Auth\User $user - * @param string $username + * Sync the LDAP groups to the user roles for the current user. * @throws LdapException */ public function syncGroups(User $user, string $username) { $userLdapGroups = $this->getUserGroups($username); - - // Get the ids for the roles from the names - $ldapGroupsAsRoles = $this->matchLdapGroupsToSystemsRoles($userLdapGroups); - - // Sync groups - if ($this->config['remove_from_groups']) { - $user->roles()->sync($ldapGroupsAsRoles); - $this->userRepo->attachDefaultRole($user); - } else { - $user->roles()->syncWithoutDetaching($ldapGroupsAsRoles); - } - } - - /** - * Match an array of group names from LDAP to BookStack system roles. - * Formats LDAP group names to be lower-case and hyphenated. - * @param array $groupNames - * @return \Illuminate\Support\Collection - */ - protected function matchLdapGroupsToSystemsRoles(array $groupNames) - { - foreach ($groupNames as $i => $groupName) { - $groupNames[$i] = str_replace(' ', '-', trim(strtolower($groupName))); - } - - $roles = Role::query()->where(function (Builder $query) use ($groupNames) { - $query->whereIn('name', $groupNames); - foreach ($groupNames as $groupName) { - $query->orWhere('external_auth_id', 'LIKE', '%' . $groupName . '%'); - } - })->get(); - - $matchedRoles = $roles->filter(function (Role $role) use ($groupNames) { - return $this->roleMatchesGroupNames($role, $groupNames); - }); - - return $matchedRoles->pluck('id'); - } - - /** - * Check a role against an array of group names to see if it matches. - * Checked against role 'external_auth_id' if set otherwise the name of the role. - * @param \BookStack\Auth\Role $role - * @param array $groupNames - * @return bool - */ - protected function roleMatchesGroupNames(Role $role, array $groupNames) - { - if ($role->external_auth_id) { - $externalAuthIds = explode(',', strtolower($role->external_auth_id)); - foreach ($externalAuthIds as $externalAuthId) { - if (in_array(trim($externalAuthId), $groupNames)) { - return true; - } - } - return false; - } - - $roleName = str_replace(' ', '-', trim(strtolower($role->display_name))); - return in_array($roleName, $groupNames); + $this->syncWithGroups($user, $userLdapGroups); } } diff --git a/app/Auth/Access/RegistrationService.php b/app/Auth/Access/RegistrationService.php new file mode 100644 index 000000000..8cf76013a --- /dev/null +++ b/app/Auth/Access/RegistrationService.php @@ -0,0 +1,118 @@ +userRepo = $userRepo; + $this->emailConfirmationService = $emailConfirmationService; + } + + /** + * Check whether or not registrations are allowed in the app settings. + * @throws UserRegistrationException + */ + public function ensureRegistrationAllowed() + { + if (!$this->registrationAllowed()) { + throw new UserRegistrationException(trans('auth.registrations_disabled'), '/login'); + } + } + + /** + * Check if standard BookStack User registrations are currently allowed. + * Does not prevent external-auth based registration. + */ + protected function registrationAllowed(): bool + { + $authMethod = config('auth.method'); + $authMethodsWithRegistration = ['standard']; + return in_array($authMethod, $authMethodsWithRegistration) && setting('registration-enabled'); + } + + /** + * The registrations flow for all users. + * @throws UserRegistrationException + */ + public function registerUser(array $userData, ?SocialAccount $socialAccount = null, bool $emailConfirmed = false): User + { + $userEmail = $userData['email']; + + // Email restriction + $this->ensureEmailDomainAllowed($userEmail); + + // Ensure user does not already exist + $alreadyUser = !is_null($this->userRepo->getByEmail($userEmail)); + if ($alreadyUser) { + throw new UserRegistrationException(trans('errors.error_user_exists_different_creds', ['email' => $userEmail])); + } + + // Create the user + $newUser = $this->userRepo->registerNew($userData, $emailConfirmed); + + // Assign social account if given + if ($socialAccount) { + $newUser->socialAccounts()->save($socialAccount); + } + + // Start email confirmation flow if required + if ($this->emailConfirmationService->confirmationRequired() && !$emailConfirmed) { + $newUser->save(); + $message = ''; + + try { + $this->emailConfirmationService->sendConfirmation($newUser); + } catch (Exception $e) { + $message = trans('auth.email_confirm_send_error'); + } + + throw new UserRegistrationException($message, '/register/confirm'); + } + + return $newUser; + } + + /** + * Ensure that the given email meets any active email domain registration restrictions. + * Throws if restrictions are active and the email does not match an allowed domain. + * @throws UserRegistrationException + */ + protected function ensureEmailDomainAllowed(string $userEmail): void + { + $registrationRestrict = setting('registration-restrict'); + + if (!$registrationRestrict) { + return; + } + + $restrictedEmailDomains = explode(',', str_replace(' ', '', $registrationRestrict)); + $userEmailDomain = $domain = mb_substr(mb_strrchr($userEmail, "@"), 1); + if (!in_array($userEmailDomain, $restrictedEmailDomains)) { + $redirect = $this->registrationAllowed() ? '/register' : '/login'; + throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), $redirect); + } + } + + /** + * Alias to the UserRepo method of the same name. + * Attaches the default system role, if configured, to the given user. + */ + public function attachDefaultRole(User $user): void + { + $this->userRepo->attachDefaultRole($user); + } + +} \ No newline at end of file diff --git a/app/Auth/Access/Saml2Service.php b/app/Auth/Access/Saml2Service.php new file mode 100644 index 000000000..8f9a24cde --- /dev/null +++ b/app/Auth/Access/Saml2Service.php @@ -0,0 +1,378 @@ +config = config('saml2'); + $this->registrationService = $registrationService; + $this->user = $user; + } + + /** + * Initiate a login flow. + * @throws Error + */ + public function login(): array + { + $toolKit = $this->getToolkit(); + $returnRoute = url('/saml2/acs'); + return [ + 'url' => $toolKit->login($returnRoute, [], false, false, true), + 'id' => $toolKit->getLastRequestID(), + ]; + } + + /** + * Initiate a logout flow. + * @throws Error + */ + public function logout(): array + { + $toolKit = $this->getToolkit(); + $returnRoute = url('/'); + + try { + $url = $toolKit->logout($returnRoute, [], null, null, true); + $id = $toolKit->getLastRequestID(); + } catch (Error $error) { + if ($error->getCode() !== Error::SAML_SINGLE_LOGOUT_NOT_SUPPORTED) { + throw $error; + } + + $this->actionLogout(); + $url = '/'; + $id = null; + } + + return ['url' => $url, 'id' => $id]; + } + + /** + * Process the ACS response from the idp and return the + * matching, or new if registration active, user matched to the idp. + * Returns null if not authenticated. + * @throws Error + * @throws SamlException + * @throws ValidationError + * @throws JsonDebugException + * @throws UserRegistrationException + */ + public function processAcsResponse(?string $requestId): ?User + { + $toolkit = $this->getToolkit(); + $toolkit->processResponse($requestId); + $errors = $toolkit->getErrors(); + + if (!empty($errors)) { + throw new Error( + 'Invalid ACS Response: '.implode(', ', $errors) + ); + } + + if (!$toolkit->isAuthenticated()) { + return null; + } + + $attrs = $toolkit->getAttributes(); + $id = $toolkit->getNameId(); + + return $this->processLoginCallback($id, $attrs); + } + + /** + * Process a response for the single logout service. + * @throws Error + */ + public function processSlsResponse(?string $requestId): ?string + { + $toolkit = $this->getToolkit(); + $redirect = $toolkit->processSLO(true, $requestId, false, null, true); + + $errors = $toolkit->getErrors(); + + if (!empty($errors)) { + throw new Error( + 'Invalid SLS Response: '.implode(', ', $errors) + ); + } + + $this->actionLogout(); + return $redirect; + } + + /** + * Do the required actions to log a user out. + */ + protected function actionLogout() + { + auth()->logout(); + session()->invalidate(); + } + + /** + * Get the metadata for this service provider. + * @throws Error + */ + public function metadata(): string + { + $toolKit = $this->getToolkit(); + $settings = $toolKit->getSettings(); + $metadata = $settings->getSPMetadata(); + $errors = $settings->validateMetadata($metadata); + + if (!empty($errors)) { + throw new Error( + 'Invalid SP metadata: '.implode(', ', $errors), + Error::METADATA_SP_INVALID + ); + } + + return $metadata; + } + + /** + * Load the underlying Onelogin SAML2 toolkit. + * @throws Error + * @throws Exception + */ + protected function getToolkit(): Auth + { + $settings = $this->config['onelogin']; + $overrides = $this->config['onelogin_overrides'] ?? []; + + if ($overrides && is_string($overrides)) { + $overrides = json_decode($overrides, true); + } + + $metaDataSettings = []; + if ($this->config['autoload_from_metadata']) { + $metaDataSettings = IdPMetadataParser::parseRemoteXML($settings['idp']['entityId']); + } + + $spSettings = $this->loadOneloginServiceProviderDetails(); + $settings = array_replace_recursive($settings, $spSettings, $metaDataSettings, $overrides); + return new Auth($settings); + } + + /** + * Load dynamic service provider options required by the onelogin toolkit. + */ + protected function loadOneloginServiceProviderDetails(): array + { + $spDetails = [ + 'entityId' => url('/saml2/metadata'), + 'assertionConsumerService' => [ + 'url' => url('/saml2/acs'), + ], + 'singleLogoutService' => [ + 'url' => url('/saml2/sls') + ], + ]; + + return [ + 'baseurl' => url('/saml2'), + 'sp' => $spDetails + ]; + } + + /** + * Check if groups should be synced. + */ + protected function shouldSyncGroups(): bool + { + return $this->config['user_to_groups'] !== false; + } + + /** + * Calculate the display name + */ + protected function getUserDisplayName(array $samlAttributes, string $defaultValue): string + { + $displayNameAttr = $this->config['display_name_attributes']; + + $displayName = []; + foreach ($displayNameAttr as $dnAttr) { + $dnComponent = $this->getSamlResponseAttribute($samlAttributes, $dnAttr, null); + if ($dnComponent !== null) { + $displayName[] = $dnComponent; + } + } + + if (count($displayName) == 0) { + $displayName = $defaultValue; + } else { + $displayName = implode(' ', $displayName); + } + + return $displayName; + } + + /** + * Get the value to use as the external id saved in BookStack + * used to link the user to an existing BookStack DB user. + */ + protected function getExternalId(array $samlAttributes, string $defaultValue) + { + $userNameAttr = $this->config['external_id_attribute']; + if ($userNameAttr === null) { + return $defaultValue; + } + + return $this->getSamlResponseAttribute($samlAttributes, $userNameAttr, $defaultValue); + } + + /** + * Extract the details of a user from a SAML response. + */ + protected function getUserDetails(string $samlID, $samlAttributes): array + { + $emailAttr = $this->config['email_attribute']; + $externalId = $this->getExternalId($samlAttributes, $samlID); + + $defaultEmail = filter_var($samlID, FILTER_VALIDATE_EMAIL) ? $samlID : null; + $email = $this->getSamlResponseAttribute($samlAttributes, $emailAttr, $defaultEmail); + + return [ + 'external_id' => $externalId, + 'name' => $this->getUserDisplayName($samlAttributes, $externalId), + 'email' => $email, + 'saml_id' => $samlID, + ]; + } + + /** + * Get the groups a user is a part of from the SAML response. + */ + public function getUserGroups(array $samlAttributes): array + { + $groupsAttr = $this->config['group_attribute']; + $userGroups = $samlAttributes[$groupsAttr] ?? null; + + if (!is_array($userGroups)) { + $userGroups = []; + } + + return $userGroups; + } + + /** + * For an array of strings, return a default for an empty array, + * a string for an array with one element and the full array for + * more than one element. + */ + protected function simplifyValue(array $data, $defaultValue) + { + switch (count($data)) { + case 0: + $data = $defaultValue; + break; + case 1: + $data = $data[0]; + break; + } + return $data; + } + + /** + * Get a property from an SAML response. + * Handles properties potentially being an array. + */ + protected function getSamlResponseAttribute(array $samlAttributes, string $propertyKey, $defaultValue) + { + if (isset($samlAttributes[$propertyKey])) { + return $this->simplifyValue($samlAttributes[$propertyKey], $defaultValue); + } + + return $defaultValue; + } + + /** + * Get the user from the database for the specified details. + * @throws SamlException + * @throws UserRegistrationException + */ + protected function getOrRegisterUser(array $userDetails): ?User + { + $user = $this->user->newQuery() + ->where('external_auth_id', '=', $userDetails['external_id']) + ->first(); + + if (is_null($user)) { + $userData = [ + 'name' => $userDetails['name'], + 'email' => $userDetails['email'], + 'password' => Str::random(32), + 'external_auth_id' => $userDetails['external_id'], + ]; + + $user = $this->registrationService->registerUser($userData, null, false); + } + + return $user; + } + + /** + * Process the SAML response for a user. Login the user when + * they exist, optionally registering them automatically. + * @throws SamlException + * @throws JsonDebugException + * @throws UserRegistrationException + */ + public function processLoginCallback(string $samlID, array $samlAttributes): User + { + $userDetails = $this->getUserDetails($samlID, $samlAttributes); + $isLoggedIn = auth()->check(); + + if ($this->config['dump_user_details']) { + throw new JsonDebugException([ + 'id_from_idp' => $samlID, + 'attrs_from_idp' => $samlAttributes, + 'attrs_after_parsing' => $userDetails, + ]); + } + + if ($userDetails['email'] === null) { + throw new SamlException(trans('errors.saml_no_email_address')); + } + + if ($isLoggedIn) { + throw new SamlException(trans('errors.saml_already_logged_in'), '/login'); + } + + $user = $this->getOrRegisterUser($userDetails); + if ($user === null) { + throw new SamlException(trans('errors.saml_user_not_registered', ['name' => $userDetails['external_id']]), '/login'); + } + + if ($this->shouldSyncGroups()) { + $groups = $this->getUserGroups($samlAttributes); + $this->syncWithGroups($user, $groups); + } + + auth()->login($user); + return $user; + } +} diff --git a/app/Auth/Access/SocialAuthService.php b/app/Auth/Access/SocialAuthService.php index 0d46b9f88..16815a8e1 100644 --- a/app/Auth/Access/SocialAuthService.php +++ b/app/Auth/Access/SocialAuthService.php @@ -5,8 +5,11 @@ use BookStack\Auth\UserRepo; use BookStack\Exceptions\SocialDriverNotConfigured; use BookStack\Exceptions\SocialSignInAccountNotUsed; use BookStack\Exceptions\UserRegistrationException; +use Illuminate\Support\Str; use Laravel\Socialite\Contracts\Factory as Socialite; +use Laravel\Socialite\Contracts\Provider; use Laravel\Socialite\Contracts\User as SocialUser; +use Symfony\Component\HttpFoundation\RedirectResponse; class SocialAuthService { @@ -19,9 +22,6 @@ class SocialAuthService /** * SocialAuthService constructor. - * @param \BookStack\Auth\UserRepo $userRepo - * @param Socialite $socialite - * @param SocialAccount $socialAccount */ public function __construct(UserRepo $userRepo, Socialite $socialite, SocialAccount $socialAccount) { @@ -33,11 +33,9 @@ class SocialAuthService /** * Start the social login path. - * @param string $socialDriver - * @return \Symfony\Component\HttpFoundation\RedirectResponse * @throws SocialDriverNotConfigured */ - public function startLogIn($socialDriver) + public function startLogIn(string $socialDriver): RedirectResponse { $driver = $this->validateDriver($socialDriver); return $this->getSocialDriver($driver)->redirect(); @@ -45,11 +43,9 @@ class SocialAuthService /** * Start the social registration process - * @param string $socialDriver - * @return \Symfony\Component\HttpFoundation\RedirectResponse * @throws SocialDriverNotConfigured */ - public function startRegister($socialDriver) + public function startRegister(string $socialDriver): RedirectResponse { $driver = $this->validateDriver($socialDriver); return $this->getSocialDriver($driver)->redirect(); @@ -57,12 +53,9 @@ class SocialAuthService /** * Handle the social registration process on callback. - * @param string $socialDriver - * @param SocialUser $socialUser - * @return SocialUser * @throws UserRegistrationException */ - public function handleRegistrationCallback(string $socialDriver, SocialUser $socialUser) + 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()) { @@ -71,7 +64,7 @@ class SocialAuthService if ($this->userRepo->getByEmail($socialUser->getEmail())) { $email = $socialUser->getEmail(); - throw new UserRegistrationException(trans('errors.social_account_in_use', ['socialAccount'=>$socialDriver, 'email' => $email]), '/login'); + throw new UserRegistrationException(trans('errors.error_user_exists_different_creds', ['email' => $email]), '/login'); } return $socialUser; @@ -79,11 +72,9 @@ class SocialAuthService /** * Get the social user details via the social driver. - * @param string $socialDriver - * @return SocialUser * @throws SocialDriverNotConfigured */ - public function getSocialUser(string $socialDriver) + public function getSocialUser(string $socialDriver): SocialUser { $driver = $this->validateDriver($socialDriver); return $this->socialite->driver($driver)->user(); @@ -91,12 +82,9 @@ class SocialAuthService /** * Handle the login process on a oAuth callback. - * @param $socialDriver - * @param SocialUser $socialUser - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector * @throws SocialSignInAccountNotUsed */ - public function handleLoginCallback($socialDriver, SocialUser $socialUser) + public function handleLoginCallback(string $socialDriver, SocialUser $socialUser) { $socialId = $socialUser->getId(); @@ -104,6 +92,7 @@ class SocialAuthService $socialAccount = $this->socialAccount->where('driver_id', '=', $socialId)->first(); $isLoggedIn = auth()->check(); $currentUser = user(); + $titleCaseDriver = Str::title($socialDriver); // When a user is not logged in and a matching SocialAccount exists, // Simply log the user into the application. @@ -117,26 +106,26 @@ class SocialAuthService if ($isLoggedIn && $socialAccount === null) { $this->fillSocialAccount($socialDriver, $socialUser); $currentUser->socialAccounts()->save($this->socialAccount); - session()->flash('success', trans('settings.users_social_connected', ['socialAccount' => title_case($socialDriver)])); + session()->flash('success', trans('settings.users_social_connected', ['socialAccount' => $titleCaseDriver])); return redirect($currentUser->getEditUrl()); } // When a user is logged in and the social account exists and is already linked to the current user. if ($isLoggedIn && $socialAccount !== null && $socialAccount->user->id === $currentUser->id) { - session()->flash('error', trans('errors.social_account_existing', ['socialAccount' => title_case($socialDriver)])); + session()->flash('error', trans('errors.social_account_existing', ['socialAccount' => $titleCaseDriver])); return redirect($currentUser->getEditUrl()); } // When a user is logged in, A social account exists but the users do not match. if ($isLoggedIn && $socialAccount !== null && $socialAccount->user->id != $currentUser->id) { - session()->flash('error', trans('errors.social_account_already_used_existing', ['socialAccount' => title_case($socialDriver)])); + session()->flash('error', trans('errors.social_account_already_used_existing', ['socialAccount' => $titleCaseDriver])); return redirect($currentUser->getEditUrl()); } // Otherwise let the user know this social account is not used by anyone. - $message = trans('errors.social_account_not_used', ['socialAccount' => title_case($socialDriver)]); - if (setting('registration-enabled')) { - $message .= trans('errors.social_account_register_instructions', ['socialAccount' => title_case($socialDriver)]); + $message = trans('errors.social_account_not_used', ['socialAccount' => $titleCaseDriver]); + 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'); @@ -144,20 +133,18 @@ class SocialAuthService /** * Ensure the social driver is correct and supported. - * - * @param $socialDriver - * @return string * @throws SocialDriverNotConfigured */ - private function validateDriver($socialDriver) + protected function validateDriver(string $socialDriver): string { $driver = trim(strtolower($socialDriver)); if (!in_array($driver, $this->validSocialDrivers)) { abort(404, trans('errors.social_driver_not_found')); } + if (!$this->checkDriverConfigured($driver)) { - throw new SocialDriverNotConfigured(trans('errors.social_driver_not_configured', ['socialAccount' => title_case($socialDriver)])); + throw new SocialDriverNotConfigured(trans('errors.social_driver_not_configured', ['socialAccount' => Str::title($socialDriver)])); } return $driver; @@ -165,10 +152,8 @@ class SocialAuthService /** * Check a social driver has been configured correctly. - * @param $driver - * @return bool */ - private function checkDriverConfigured($driver) + protected function checkDriverConfigured(string $driver): bool { $lowerName = strtolower($driver); $configPrefix = 'services.' . $lowerName . '.'; @@ -178,55 +163,48 @@ class SocialAuthService /** * Gets the names of the active social drivers. - * @return array */ - public function getActiveDrivers() + public function getActiveDrivers(): array { $activeDrivers = []; + foreach ($this->validSocialDrivers as $driverKey) { if ($this->checkDriverConfigured($driverKey)) { $activeDrivers[$driverKey] = $this->getDriverName($driverKey); } } + return $activeDrivers; } /** * Get the presentational name for a driver. - * @param $driver - * @return mixed */ - public function getDriverName($driver) + public function getDriverName(string $driver): string { return config('services.' . strtolower($driver) . '.name'); } /** * Check if the current config for the given driver allows auto-registration. - * @param string $driver - * @return bool */ - public function driverAutoRegisterEnabled(string $driver) + public function driverAutoRegisterEnabled(string $driver): bool { return config('services.' . strtolower($driver) . '.auto_register') === true; } /** * Check if the current config for the given driver allow email address auto-confirmation. - * @param string $driver - * @return bool */ - public function driverAutoConfirmEmailEnabled(string $driver) + public function driverAutoConfirmEmailEnabled(string $driver): bool { return config('services.' . strtolower($driver) . '.auto_confirm') === true; } /** - * @param string $socialDriver - * @param SocialUser $socialUser - * @return SocialAccount + * Fill and return a SocialAccount from the given driver name and SocialUser. */ - public function fillSocialAccount($socialDriver, $socialUser) + public function fillSocialAccount(string $socialDriver, SocialUser $socialUser): SocialAccount { $this->socialAccount->fill([ 'driver' => $socialDriver, @@ -238,22 +216,17 @@ class SocialAuthService /** * Detach a social account from a user. - * @param $socialDriver * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ - public function detachSocialAccount($socialDriver) + public function detachSocialAccount(string $socialDriver) { user()->socialAccounts()->where('driver', '=', $socialDriver)->delete(); - session()->flash('success', trans('settings.users_social_disconnected', ['socialAccount' => title_case($socialDriver)])); - return redirect(user()->getEditUrl()); } /** * Provide redirect options per service for the Laravel Socialite driver - * @param $driverName - * @return \Laravel\Socialite\Contracts\Provider */ - public function getSocialDriver(string $driverName) + public function getSocialDriver(string $driverName): Provider { $driver = $this->socialite->driver($driverName); diff --git a/app/Auth/Access/UserInviteService.php b/app/Auth/Access/UserInviteService.php index 8e04d7b22..20519fc7d 100644 --- a/app/Auth/Access/UserInviteService.php +++ b/app/Auth/Access/UserInviteService.php @@ -19,5 +19,4 @@ class UserInviteService extends UserTokenService $token = $this->createTokenForUser($user); $user->notify(new UserInvite($token)); } - } diff --git a/app/Auth/Access/UserTokenService.php b/app/Auth/Access/UserTokenService.php index 34f3b2851..a1defbf62 100644 --- a/app/Auth/Access/UserTokenService.php +++ b/app/Auth/Access/UserTokenService.php @@ -5,6 +5,7 @@ use BookStack\Exceptions\UserTokenExpiredException; use BookStack\Exceptions\UserTokenNotFoundException; use Carbon\Carbon; use Illuminate\Database\Connection as Database; +use Illuminate\Support\Str; use stdClass; class UserTokenService @@ -73,9 +74,9 @@ class UserTokenService */ protected function generateToken() : string { - $token = str_random(24); + $token = Str::random(24); while ($this->tokenExists($token)) { - $token = str_random(25); + $token = Str::random(25); } return $token; } @@ -130,5 +131,4 @@ class UserTokenService return Carbon::now()->subHours($this->expiryTime) ->gt(new Carbon($tokenEntry->created_at)); } - -} \ No newline at end of file +} diff --git a/app/Auth/Permissions/PermissionService.php b/app/Auth/Permissions/PermissionService.php index a5ab4ea9a..97cc1ca24 100644 --- a/app/Auth/Permissions/PermissionService.php +++ b/app/Auth/Permissions/PermissionService.php @@ -215,7 +215,6 @@ class PermissionService * @param Collection $books * @param array $roles * @param bool $deleteOld - * @throws \Throwable */ protected function buildJointPermissionsForBooks($books, $roles, $deleteOld = false) { @@ -634,42 +633,40 @@ class PermissionService } /** - * Get the children of a book in an efficient single query, Filtered by the permission system. - * @param integer $book_id - * @param bool $filterDrafts - * @param bool $fetchPageContent - * @return QueryBuilder + * Limited the given entity query so that the query will only + * return items that the user has permission for the given ability. */ - public function bookChildrenQuery($book_id, $filterDrafts = false, $fetchPageContent = false) + public function restrictEntityQuery(Builder $query, string $ability = 'view'): Builder { - $entities = $this->entityProvider; - $pageSelect = $this->db->table('pages')->selectRaw($entities->page->entityRawQuery($fetchPageContent)) - ->where('book_id', '=', $book_id)->where(function ($query) use ($filterDrafts) { - $query->where('draft', '=', 0); - if (!$filterDrafts) { - $query->orWhere(function ($query) { - $query->where('draft', '=', 1)->where('created_by', '=', $this->currentUser()->id); - }); - } - }); - $chapterSelect = $this->db->table('chapters')->selectRaw($entities->chapter->entityRawQuery())->where('book_id', '=', $book_id); - $query = $this->db->query()->select('*')->from($this->db->raw("({$pageSelect->toSql()} UNION {$chapterSelect->toSql()}) AS U")) - ->mergeBindings($pageSelect)->mergeBindings($chapterSelect); - - // Add joint permission filter - $whereQuery = $this->db->table('joint_permissions as jp')->selectRaw('COUNT(*)') - ->whereRaw('jp.entity_id=U.id')->whereRaw('jp.entity_type=U.entity_type') - ->where('jp.action', '=', 'view')->whereIn('jp.role_id', $this->getRoles()) - ->where(function ($query) { - $query->where('jp.has_permission', '=', 1)->orWhere(function ($query) { - $query->where('jp.has_permission_own', '=', 1)->where('jp.created_by', '=', $this->currentUser()->id); - }); - }); - $query->whereRaw("({$whereQuery->toSql()}) > 0")->mergeBindings($whereQuery); - - $query->orderBy('draft', 'desc')->orderBy('priority', 'asc'); $this->clean(); - return $query; + return $query->where(function (Builder $parentQuery) use ($ability) { + $parentQuery->whereHas('jointPermissions', function (Builder $permissionQuery) use ($ability) { + $permissionQuery->whereIn('role_id', $this->getRoles()) + ->where('action', '=', $ability) + ->where(function (Builder $query) { + $query->where('has_permission', '=', true) + ->orWhere(function (Builder $query) { + $query->where('has_permission_own', '=', true) + ->where('created_by', '=', $this->currentUser()->id); + }); + }); + }); + }); + } + + /** + * Extend the given page query to ensure draft items are not visible + * unless created by the given user. + */ + public function enforceDraftVisiblityOnQuery(Builder $query): Builder + { + return $query->where(function (Builder $query) { + $query->where('draft', '=', false) + ->orWhere(function (Builder $query) { + $query->where('draft', '=', true) + ->where('created_by', '=', $this->currentUser()->id); + }); + }); } /** @@ -684,12 +681,11 @@ class PermissionService if (strtolower($entityType) === 'page') { // Prevent drafts being visible to others. $query = $query->where(function ($query) { - $query->where('draft', '=', false); - if ($this->currentUser()) { - $query->orWhere(function ($query) { - $query->where('draft', '=', true)->where('created_by', '=', $this->currentUser()->id); + $query->where('draft', '=', false) + ->orWhere(function ($query) { + $query->where('draft', '=', true) + ->where('created_by', '=', $this->currentUser()->id); }); - } }); } diff --git a/app/Auth/Permissions/PermissionsRepo.php b/app/Auth/Permissions/PermissionsRepo.php index 18d5089be..56ef19301 100644 --- a/app/Auth/Permissions/PermissionsRepo.php +++ b/app/Auth/Permissions/PermissionsRepo.php @@ -3,6 +3,7 @@ use BookStack\Auth\Permissions; use BookStack\Auth\Role; use BookStack\Exceptions\PermissionsException; +use Illuminate\Support\Str; class PermissionsRepo { @@ -66,7 +67,7 @@ class PermissionsRepo $role->name = str_replace(' ', '-', strtolower($roleData['display_name'])); // Prevent duplicate names while ($this->role->where('name', '=', $role->name)->count() > 0) { - $role->name .= strtolower(str_random(2)); + $role->name .= strtolower(Str::random(2)); } $role->save(); @@ -136,7 +137,7 @@ class PermissionsRepo // Prevent deleting admin role or default registration role. if ($role->system_name && in_array($role->system_name, $this->systemRoles)) { throw new PermissionsException(trans('errors.role_system_cannot_be_deleted')); - } else if ($role->id == setting('registration-role')) { + } else if ($role->id === intval(setting('registration-role'))) { throw new PermissionsException(trans('errors.role_registration_default_cannot_delete')); } diff --git a/app/Auth/Role.php b/app/Auth/Role.php index 917d8aa26..df9b1cea9 100644 --- a/app/Auth/Role.php +++ b/app/Auth/Role.php @@ -4,6 +4,13 @@ use BookStack\Auth\Permissions\JointPermission; use BookStack\Auth\Permissions\RolePermission; use BookStack\Model; +/** + * Class Role + * @property string $display_name + * @property string $description + * @property string $external_auth_id + * @package BookStack\Auth + */ class Role extends Model { @@ -65,7 +72,7 @@ class Role extends Model */ public function detachPermission(RolePermission $permission) { - $this->permissions()->detach($permission->id); + $this->permissions()->detach([$permission->id]); } /** @@ -75,7 +82,7 @@ class Role extends Model */ public static function getRole($roleName) { - return static::where('name', '=', $roleName)->first(); + return static::query()->where('name', '=', $roleName)->first(); } /** @@ -85,7 +92,7 @@ class Role extends Model */ public static function getSystemRole($roleName) { - return static::where('system_name', '=', $roleName)->first(); + return static::query()->where('system_name', '=', $roleName)->first(); } /** @@ -94,6 +101,15 @@ class Role extends Model */ public static function visible() { - return static::where('hidden', '=', false)->orderBy('name')->get(); + return static::query()->where('hidden', '=', false)->orderBy('name')->get(); + } + + /** + * Get the roles that can be restricted. + * @return \Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection + */ + public static function restrictable() + { + return static::query()->where('system_name', '!=', 'admin')->get(); } } diff --git a/app/Auth/User.php b/app/Auth/User.php index 7ad14d9f0..28fb9c7fc 100644 --- a/app/Auth/User.php +++ b/app/Auth/User.php @@ -1,5 +1,6 @@ first(); + if (!is_null(static::$defaultUser)) { + return static::$defaultUser; + } + + static::$defaultUser = static::where('system_name', '=', 'public')->first(); + return static::$defaultUser; } /** @@ -103,6 +116,17 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon return $this->roles->pluck('system_name')->contains($role); } + /** + * Attach the default system role to this user. + */ + public function attachDefaultRole(): void + { + $roleId = setting('registration-role'); + if ($roleId && $this->roles()->where('id', '=', $roleId)->count() === 0) { + $this->roles()->attach($roleId); + } + } + /** * Get all permissions belonging to a the current user. * @param bool $cache @@ -140,16 +164,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon */ public function attachRole(Role $role) { - $this->attachRoleId($role->id); - } - - /** - * Attach a role id to this user. - * @param $id - */ - public function attachRoleId($id) - { - $this->roles()->attach($id); + $this->roles()->attach($role->id); } /** @@ -207,19 +222,26 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon } /** - * Get the url for editing this user. - * @return string + * Get the API tokens assigned to this user. */ - public function getEditUrl() + public function apiTokens(): HasMany { - return url('/settings/users/' . $this->id); + return $this->hasMany(ApiToken::class); + } + + /** + * Get the url for editing this user. + */ + public function getEditUrl(string $path = ''): string + { + $uri = '/settings/users/' . $this->id . '/' . trim($path, '/'); + return url(rtrim($uri, '/')); } /** * Get the url that links to this user's profile. - * @return mixed */ - public function getProfileUrl() + public function getProfileUrl(): string { return url('/user/' . $this->id); } diff --git a/app/Auth/UserRepo.php b/app/Auth/UserRepo.php index dec973f6c..cfa7bfce1 100644 --- a/app/Auth/UserRepo.php +++ b/app/Auth/UserRepo.php @@ -1,39 +1,37 @@ user = $user; $this->role = $role; - $this->entityRepo = $entityRepo; } /** - * @param string $email - * @return User|null + * Get a user by their email address. */ - public function getByEmail($email) + public function getByEmail(string $email): ?User { return $this->user->where('email', '=', $email)->first(); } @@ -79,31 +77,16 @@ class UserRepo /** * Creates a new user and attaches a role to them. - * @param array $data - * @param boolean $verifyEmail - * @return \BookStack\Auth\User */ - public function registerNew(array $data, $verifyEmail = false) + public function registerNew(array $data, bool $emailConfirmed = false): User { - $user = $this->create($data, $verifyEmail); - $this->attachDefaultRole($user); + $user = $this->create($data, $emailConfirmed); + $user->attachDefaultRole(); $this->downloadAndAssignUserAvatar($user); return $user; } - /** - * Give a user the default role. Used when creating a new user. - * @param User $user - */ - public function attachDefaultRole(User $user) - { - $roleId = setting('registration-role'); - if ($roleId !== false && $user->roles()->where('id', '=', $roleId)->count() === 0) { - $user->attachRoleId($roleId); - } - } - /** * Assign a user to a system-level role. * @param User $user @@ -121,7 +104,7 @@ class UserRepo /** * Checks if the give user is the only admin. - * @param \BookStack\Auth\User $user + * @param User $user * @return bool */ public function isOnlyAdmin(User $user) @@ -173,28 +156,27 @@ class UserRepo /** * Create a new basic instance of user. - * @param array $data - * @param boolean $verifyEmail - * @return \BookStack\Auth\User */ - public function create(array $data, $verifyEmail = false) + public function create(array $data, bool $emailConfirmed = false): User { return $this->user->forceCreate([ 'name' => $data['name'], 'email' => $data['email'], 'password' => bcrypt($data['password']), - 'email_confirmed' => $verifyEmail + 'email_confirmed' => $emailConfirmed, + 'external_auth_id' => $data['external_auth_id'] ?? '', ]); } /** * Remove the given user from storage, Delete all related content. - * @param \BookStack\Auth\User $user + * @param User $user * @throws Exception */ public function destroy(User $user) { $user->socialAccounts()->delete(); + $user->apiTokens()->delete(); $user->delete(); // Delete user profile images @@ -206,7 +188,7 @@ class UserRepo /** * Get the latest activity for a user. - * @param \BookStack\Auth\User $user + * @param User $user * @param int $count * @param int $page * @return array @@ -218,36 +200,35 @@ class UserRepo /** * Get the recently created content for this given user. - * @param \BookStack\Auth\User $user - * @param int $count - * @return mixed */ - public function getRecentlyCreated(User $user, $count = 20) + public function getRecentlyCreated(User $user, int $count = 20): array { - $createdByUserQuery = function (Builder $query) use ($user) { - $query->where('created_by', '=', $user->id); + $query = function (Builder $query) use ($user, $count) { + return $query->orderBy('created_at', 'desc') + ->where('created_by', '=', $user->id) + ->take($count) + ->get(); }; return [ - 'pages' => $this->entityRepo->getRecentlyCreated('page', $count, 0, $createdByUserQuery), - 'chapters' => $this->entityRepo->getRecentlyCreated('chapter', $count, 0, $createdByUserQuery), - 'books' => $this->entityRepo->getRecentlyCreated('book', $count, 0, $createdByUserQuery), - 'shelves' => $this->entityRepo->getRecentlyCreated('bookshelf', $count, 0, $createdByUserQuery) + 'pages' => $query(Page::visible()->where('draft', '=', false)), + 'chapters' => $query(Chapter::visible()), + 'books' => $query(Book::visible()), + 'shelves' => $query(Bookshelf::visible()), ]; } /** * Get asset created counts for the give user. - * @param \BookStack\Auth\User $user - * @return array */ - public function getAssetCounts(User $user) + public function getAssetCounts(User $user): array { + $createdBy = ['created_by' => $user->id]; return [ - 'pages' => $this->entityRepo->getUserTotalCreated('page', $user), - 'chapters' => $this->entityRepo->getUserTotalCreated('chapter', $user), - 'books' => $this->entityRepo->getUserTotalCreated('book', $user), - 'shelves' => $this->entityRepo->getUserTotalCreated('bookshelf', $user), + 'pages' => Page::visible()->where($createdBy)->count(), + 'chapters' => Chapter::visible()->where($createdBy)->count(), + 'books' => Book::visible()->where($createdBy)->count(), + 'shelves' => Bookshelf::visible()->where($createdBy)->count(), ]; } @@ -260,16 +241,6 @@ class UserRepo return $this->role->newQuery()->orderBy('name', 'asc')->get(); } - /** - * Get all the roles which can be given restricted access to - * other entities in the system. - * @return mixed - */ - public function getRestrictableRoles() - { - return $this->role->where('system_name', '!=', 'admin')->get(); - } - /** * Get an avatar image for a user and set it as their avatar. * Returns early if avatars disabled or not set in config. @@ -288,7 +259,7 @@ class UserRepo $user->save(); return true; } catch (Exception $e) { - \Log::error('Failed to save user avatar image'); + Log::error('Failed to save user avatar image'); return false; } } diff --git a/app/Config/api.php b/app/Config/api.php new file mode 100644 index 000000000..6afea2dc8 --- /dev/null +++ b/app/Config/api.php @@ -0,0 +1,23 @@ + env('API_DEFAULT_ITEM_COUNT', 100), + + // The maximum number of items that can be returned in a listing API request. + 'max_item_count' => env('API_MAX_ITEM_COUNT', 500), + + // The number of API requests that can be made per minute by a single user. + 'requests_per_minute' => env('API_REQUESTS_PER_MIN', 180) + +]; diff --git a/app/Config/app.php b/app/Config/app.php index 88052e94c..3b7216b3d 100755 --- a/app/Config/app.php +++ b/app/Config/app.php @@ -52,11 +52,14 @@ return [ 'locale' => env('APP_LANG', 'en'), // Locales available - 'locales' => ['en', 'ar', 'de', 'de_informal', 'es', 'es_AR', 'fr', 'hu', 'nl', 'pt_BR', 'sk', 'cs', 'sv', 'kr', 'ja', 'pl', 'it', 'ru', 'uk', 'zh_CN', 'zh_TW'], + 'locales' => ['en', 'ar', 'da', 'de', 'de_informal', 'es', 'es_AR', 'fr', 'hu', 'nl', 'pt_BR', 'sk', 'cs', 'sv', 'ko', 'ja', 'pl', 'it', 'ru', 'uk', 'zh_CN', 'zh_TW', 'tr'], // Application Fallback Locale 'fallback_locale' => 'en', + // Faker Locale + 'faker_locale' => 'en_GB', + // Enable right-to-left text control. 'rtl' => false, @@ -72,10 +75,6 @@ return [ // Encryption cipher 'cipher' => 'AES-256-CBC', - // Logging configuration - // Options: single, daily, syslog, errorlog - 'log' => env('APP_LOGGING', 'single'), - // Application Services Provides 'providers' => [ @@ -107,7 +106,6 @@ return [ Barryvdh\DomPDF\ServiceProvider::class, Barryvdh\Snappy\ServiceProvider::class, - // BookStack replacement service providers (Extends Laravel) BookStack\Providers\PaginationServiceProvider::class, BookStack\Providers\TranslationServiceProvider::class, @@ -137,6 +135,7 @@ return [ // Laravel 'App' => Illuminate\Support\Facades\App::class, + 'Arr' => Illuminate\Support\Arr::class, 'Artisan' => Illuminate\Support\Facades\Artisan::class, 'Auth' => Illuminate\Support\Facades\Auth::class, 'Blade' => Illuminate\Support\Facades\Blade::class, @@ -166,6 +165,7 @@ return [ 'Schema' => Illuminate\Support\Facades\Schema::class, 'Session' => Illuminate\Support\Facades\Session::class, 'Storage' => Illuminate\Support\Facades\Storage::class, + 'Str' => Illuminate\Support\Str::class, 'URL' => Illuminate\Support\Facades\URL::class, 'Validator' => Illuminate\Support\Facades\Validator::class, 'View' => Illuminate\Support\Facades\View::class, @@ -181,6 +181,7 @@ return [ 'Setting' => BookStack\Facades\Setting::class, 'Views' => BookStack\Facades\Views::class, 'Images' => BookStack\Facades\Images::class, + 'Permissions' => BookStack\Facades\Permissions::class, ], diff --git a/app/Config/auth.php b/app/Config/auth.php index 7bf1ae772..51b152ff1 100644 --- a/app/Config/auth.php +++ b/app/Config/auth.php @@ -11,14 +11,14 @@ return [ // Method of authentication to use - // Options: standard, ldap + // Options: standard, ldap, saml2 'method' => env('AUTH_METHOD', 'standard'), // Authentication Defaults // This option controls the default authentication "guard" and password // reset options for your application. 'defaults' => [ - 'guard' => 'web', + 'guard' => env('AUTH_METHOD', 'standard'), 'passwords' => 'users', ], @@ -26,16 +26,22 @@ return [ // All authentication drivers have a user provider. This defines how the // users are actually retrieved out of your database or other storage // mechanisms used by this application to persist your user's data. - // Supported: "session", "token" + // Supported drivers: "session", "api-token", "ldap-session" 'guards' => [ - 'web' => [ + 'standard' => [ 'driver' => 'session', 'provider' => 'users', ], - + 'ldap' => [ + 'driver' => 'ldap-session', + 'provider' => 'external', + ], + 'saml2' => [ + 'driver' => 'saml2-session', + 'provider' => 'external', + ], 'api' => [ - 'driver' => 'token', - 'provider' => 'users', + 'driver' => 'api-token', ], ], @@ -43,17 +49,15 @@ return [ // All authentication drivers have a user provider. This defines how the // users are actually retrieved out of your database or other storage // mechanisms used by this application to persist your user's data. - // Supported: database, eloquent, ldap 'providers' => [ 'users' => [ - 'driver' => env('AUTH_METHOD', 'standard') === 'standard' ? 'eloquent' : env('AUTH_METHOD'), + 'driver' => 'eloquent', + 'model' => \BookStack\Auth\User::class, + ], + 'external' => [ + 'driver' => 'external-users', 'model' => \BookStack\Auth\User::class, ], - - // 'users' => [ - // 'driver' => 'database', - // 'table' => 'users', - // ], ], // Resetting Passwords @@ -69,4 +73,4 @@ return [ ], ], -]; \ No newline at end of file +]; diff --git a/app/Config/broadcasting.php b/app/Config/broadcasting.php index 3d9eb78f9..7aaaa5693 100644 --- a/app/Config/broadcasting.php +++ b/app/Config/broadcasting.php @@ -24,9 +24,13 @@ return [ 'pusher' => [ 'driver' => 'pusher', - 'key' => env('PUSHER_KEY'), - 'secret' => env('PUSHER_SECRET'), + 'key' => env('PUSHER_APP_KEY'), + 'secret' => env('PUSHER_APP_SECRET'), 'app_id' => env('PUSHER_APP_ID'), + 'options' => [ + 'cluster' => env('PUSHER_APP_CLUSTER'), + 'useTLS' => true, + ], ], 'redis' => [ @@ -38,6 +42,11 @@ return [ 'driver' => 'log', ], + 'null' => [ + 'driver' => 'null', + ], + + ], ]; diff --git a/app/Config/cache.php b/app/Config/cache.php index 43f420457..33d3a1a0b 100644 --- a/app/Config/cache.php +++ b/app/Config/cache.php @@ -14,8 +14,12 @@ if (env('CACHE_DRIVER') === 'memcached') { $memcachedServers = explode(',', trim(env('MEMCACHED_SERVERS', '127.0.0.1:11211:100'), ',')); foreach ($memcachedServers as $index => $memcachedServer) { $memcachedServerDetails = explode(':', $memcachedServer); - if (count($memcachedServerDetails) < 2) $memcachedServerDetails[] = '11211'; - if (count($memcachedServerDetails) < 3) $memcachedServerDetails[] = '100'; + if (count($memcachedServerDetails) < 2) { + $memcachedServerDetails[] = '11211'; + } + if (count($memcachedServerDetails) < 3) { + $memcachedServerDetails[] = '100'; + } $memcachedServers[$index] = array_combine($memcachedServerKeys, $memcachedServerDetails); } } @@ -62,6 +66,6 @@ return [ // Cache key prefix // Used to prevent collisions in shared cache systems. - 'prefix' => env('CACHE_PREFIX', 'bookstack'), + 'prefix' => env('CACHE_PREFIX', 'bookstack_cache'), ]; diff --git a/app/Config/database.php b/app/Config/database.php index 93a44854f..ed654ffb9 100644 --- a/app/Config/database.php +++ b/app/Config/database.php @@ -11,10 +11,9 @@ // REDIS // Split out configuration into an array if (env('REDIS_SERVERS', false)) { - $redisDefaults = ['host' => '127.0.0.1', 'port' => '6379', 'database' => '0', 'password' => null]; $redisServers = explode(',', trim(env('REDIS_SERVERS', '127.0.0.1:6379:0'), ',')); - $redisConfig = []; + $redisConfig = ['client' => 'predis']; $cluster = count($redisServers) > 1; if ($cluster) { @@ -59,14 +58,9 @@ return [ // Many of those shown here are unsupported by BookStack. 'connections' => [ - 'sqlite' => [ - 'driver' => 'sqlite', - 'database' => storage_path('database.sqlite'), - 'prefix' => '', - ], - 'mysql' => [ 'driver' => 'mysql', + 'url' => env('DATABASE_URL'), 'host' => $mysql_host, 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), @@ -76,43 +70,28 @@ return [ 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', + 'prefix_indexes' => true, 'strict' => false, 'engine' => null, + 'options' => extension_loaded('pdo_mysql') ? array_filter([ + PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), + ]) : [], ], 'mysql_testing' => [ 'driver' => 'mysql', + 'url' => env('TEST_DATABASE_URL'), 'host' => '127.0.0.1', 'database' => 'bookstack-test', 'username' => env('MYSQL_USER', 'bookstack-test'), 'password' => env('MYSQL_PASSWORD', 'bookstack-test'), - 'charset' => 'utf8', - 'collation' => 'utf8_unicode_ci', + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', + 'prefix_indexes' => true, 'strict' => false, ], - 'pgsql' => [ - 'driver' => 'pgsql', - 'host' => env('DB_HOST', 'localhost'), - 'database' => env('DB_DATABASE', 'forge'), - 'username' => env('DB_USERNAME', 'forge'), - 'password' => env('DB_PASSWORD', ''), - 'charset' => 'utf8', - 'prefix' => '', - 'schema' => 'public', - ], - - 'sqlsrv' => [ - 'driver' => 'sqlsrv', - 'host' => env('DB_HOST', 'localhost'), - 'database' => env('DB_DATABASE', 'forge'), - 'username' => env('DB_USERNAME', 'forge'), - 'password' => env('DB_PASSWORD', ''), - 'charset' => 'utf8', - 'prefix' => '', - ], - ], // Migration Repository Table diff --git a/app/Config/debugbar.php b/app/Config/debugbar.php index ec942dcd3..fe624eb7d 100644 --- a/app/Config/debugbar.php +++ b/app/Config/debugbar.php @@ -79,6 +79,7 @@ return [ 'files' => false, // Show the included files 'config' => false, // Display config settings 'cache' => false, // Display cache events + 'models' => true, // Display models ], // Configure some DataCollectors diff --git a/app/Config/dompdf.php b/app/Config/dompdf.php index 77f0cff9c..87be53df5 100644 --- a/app/Config/dompdf.php +++ b/app/Config/dompdf.php @@ -69,7 +69,7 @@ return [ * should be an absolute path. * This is only checked on command line call by dompdf.php, but not by * direct class use like: - * $dompdf = new DOMPDF(); $dompdf->load_html($htmldata); $dompdf->render(); $pdfdata = $dompdf->output(); + * $dompdf = new DOMPDF(); $dompdf->load_html($htmldata); $dompdf->render(); $pdfdata = $dompdf->output(); */ "DOMPDF_CHROOT" => realpath(base_path()), diff --git a/app/Config/hashing.php b/app/Config/hashing.php new file mode 100644 index 000000000..756718ce2 --- /dev/null +++ b/app/Config/hashing.php @@ -0,0 +1,37 @@ + 'bcrypt', + + // Bcrypt Options + // Here you may specify the configuration options that should be used when + // passwords are hashed using the Bcrypt algorithm. This will allow you + // to control the amount of time it takes to hash the given password. + 'bcrypt' => [ + 'rounds' => env('BCRYPT_ROUNDS', 10), + ], + + // Argon Options + // Here you may specify the configuration options that should be used when + // passwords are hashed using the Argon algorithm. These will allow you + // to control the amount of time it takes to hash the given password. + 'argon' => [ + 'memory' => 1024, + 'threads' => 2, + 'time' => 2, + ], + +]; diff --git a/app/Config/logging.php b/app/Config/logging.php new file mode 100644 index 000000000..0b55dc24d --- /dev/null +++ b/app/Config/logging.php @@ -0,0 +1,82 @@ + env('LOG_CHANNEL', 'single'), + + // Log Channels + // Here you may configure the log channels for your application. Out of + // the box, Laravel uses the Monolog PHP logging library. This gives + // you a variety of powerful log handlers / formatters to utilize. + // Available Drivers: "single", "daily", "slack", "syslog", + // "errorlog", "monolog", + // "custom", "stack" + 'channels' => [ + 'stack' => [ + 'driver' => 'stack', + 'channels' => ['daily'], + 'ignore_exceptions' => false, + ], + + 'single' => [ + 'driver' => 'single', + 'path' => storage_path('logs/laravel.log'), + 'level' => 'debug', + 'days' => 14, + ], + + 'daily' => [ + 'driver' => 'daily', + 'path' => storage_path('logs/laravel.log'), + 'level' => 'debug', + 'days' => 7, + ], + + 'slack' => [ + 'driver' => 'slack', + 'url' => env('LOG_SLACK_WEBHOOK_URL'), + 'username' => 'Laravel Log', + 'emoji' => ':boom:', + 'level' => 'critical', + ], + + 'stderr' => [ + 'driver' => 'monolog', + 'handler' => StreamHandler::class, + 'with' => [ + 'stream' => 'php://stderr', + ], + ], + + 'syslog' => [ + 'driver' => 'syslog', + 'level' => 'debug', + ], + + 'errorlog' => [ + 'driver' => 'errorlog', + 'level' => 'debug', + ], + + 'null' => [ + 'driver' => 'monolog', + 'handler' => NullHandler::class, + ], + ], + +]; diff --git a/app/Config/mail.php b/app/Config/mail.php index 49407bd8e..a91bdf237 100644 --- a/app/Config/mail.php +++ b/app/Config/mail.php @@ -23,7 +23,7 @@ return [ // Global "From" address & name 'from' => [ 'address' => env('MAIL_FROM', 'mail@bookstackapp.com'), - 'name' => env('MAIL_FROM_NAME','BookStack') + 'name' => env('MAIL_FROM_NAME', 'BookStack') ], // Email encryption protocol @@ -46,4 +46,10 @@ return [ ], ], + // Log Channel + // If you are using the "log" driver, you may specify the logging channel + // if you prefer to keep mail messages separate from other log entries + // for simpler reading. Otherwise, the default channel will be used. + 'log_channel' => env('MAIL_LOG_CHANNEL'), + ]; diff --git a/app/Config/queue.php b/app/Config/queue.php index 721eac136..46f6962c5 100644 --- a/app/Config/queue.php +++ b/app/Config/queue.php @@ -12,11 +12,12 @@ return [ // Default driver to use for the queue // Options: null, sync, redis - 'default' => env('QUEUE_DRIVER', 'sync'), + 'default' => env('QUEUE_CONNECTION', 'sync'), // Queue connection configuration 'connections' => [ + 'sync' => [ 'driver' => 'sync', ], @@ -25,38 +26,15 @@ return [ 'driver' => 'database', 'table' => 'jobs', 'queue' => 'default', - 'expire' => 60, - ], - - 'beanstalkd' => [ - 'driver' => 'beanstalkd', - 'host' => 'localhost', - 'queue' => 'default', - 'ttr' => 60, - ], - - 'sqs' => [ - 'driver' => 'sqs', - 'key' => 'your-public-key', - 'secret' => 'your-secret-key', - 'queue' => 'your-queue-url', - 'region' => 'us-east-1', - ], - - 'iron' => [ - 'driver' => 'iron', - 'host' => 'mq-aws-us-east-1.iron.io', - 'token' => 'your-token', - 'project' => 'your-project-id', - 'queue' => 'your-queue-name', - 'encrypt' => true, + 'retry_after' => 90, ], 'redis' => [ 'driver' => 'redis', 'connection' => 'default', - 'queue' => 'default', - 'expire' => 60, + 'queue' => env('REDIS_QUEUE', 'default'), + 'retry_after' => 90, + 'block_for' => null, ], ], diff --git a/app/Config/saml2.php b/app/Config/saml2.php new file mode 100644 index 000000000..5f2c1395b --- /dev/null +++ b/app/Config/saml2.php @@ -0,0 +1,144 @@ + env('SAML2_NAME', 'SSO'), + + // Dump user details after a login request for debugging purposes + 'dump_user_details' => env('SAML2_DUMP_USER_DETAILS', false), + + // Attribute, within a SAML response, to find the user's email address + 'email_attribute' => env('SAML2_EMAIL_ATTRIBUTE', 'email'), + // Attribute, within a SAML response, to find the user's display name + 'display_name_attributes' => explode('|', env('SAML2_DISPLAY_NAME_ATTRIBUTES', 'username')), + // Attribute, within a SAML response, to use to connect a BookStack user to the SAML user. + 'external_id_attribute' => env('SAML2_EXTERNAL_ID_ATTRIBUTE', null), + + // Group sync options + // Enable syncing, upon login, of SAML2 groups to BookStack groups + 'user_to_groups' => env('SAML2_USER_TO_GROUPS', false), + // Attribute, within a SAML response, to find group names on + 'group_attribute' => env('SAML2_GROUP_ATTRIBUTE', 'group'), + // When syncing groups, remove any groups that no longer match. Otherwise sync only adds new groups. + 'remove_from_groups' => env('SAML2_REMOVE_FROM_GROUPS', false), + + // Autoload IDP details from the metadata endpoint + 'autoload_from_metadata' => env('SAML2_AUTOLOAD_METADATA', false), + + // Overrides, in JSON format, to the configuration passed to underlying onelogin library. + 'onelogin_overrides' => env('SAML2_ONELOGIN_OVERRIDES', null), + + + 'onelogin' => [ + // If 'strict' is True, then the PHP Toolkit will reject unsigned + // or unencrypted messages if it expects them signed or encrypted + // Also will reject the messages if not strictly follow the SAML + // standard: Destination, NameId, Conditions ... are validated too. + 'strict' => true, + + // Enable debug mode (to print errors) + 'debug' => env('APP_DEBUG', false), + + // Set a BaseURL to be used instead of try to guess + // the BaseURL of the view that process the SAML Message. + // Ex. http://sp.example.com/ + // http://example.com/sp/ + 'baseurl' => null, + + // Service Provider Data that we are deploying + 'sp' => [ + // Identifier of the SP entity (must be a URI) + 'entityId' => '', + + // Specifies info about where and how the message MUST be + // returned to the requester, in this case our SP. + 'assertionConsumerService' => [ + // URL Location where the from the IdP will be returned + 'url' => '', + // SAML protocol binding to be used when returning the + // message. Onelogin Toolkit supports for this endpoint the + // HTTP-POST binding only + 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', + ], + + // Specifies info about where and how the message MUST be + // returned to the requester, in this case our SP. + 'singleLogoutService' => [ + // URL Location where the from the IdP will be returned + 'url' => '', + // SAML protocol binding to be used when returning the + // message. Onelogin Toolkit supports for this endpoint the + // HTTP-Redirect binding only + 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect', + ], + + // Specifies constraints on the name identifier to be used to + // represent the requested subject. + // Take a look on lib/Saml2/Constants.php to see the NameIdFormat supported + 'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', + // Usually x509cert and privateKey of the SP are provided by files placed at + // the certs folder. But we can also provide them with the following parameters + 'x509cert' => '', + 'privateKey' => '', + ], + // Identity Provider Data that we want connect with our SP + 'idp' => [ + // Identifier of the IdP entity (must be a URI) + 'entityId' => env('SAML2_IDP_ENTITYID', null), + // SSO endpoint info of the IdP. (Authentication Request protocol) + 'singleSignOnService' => [ + // URL Target of the IdP where the SP will send the Authentication Request Message + 'url' => env('SAML2_IDP_SSO', null), + // SAML protocol binding to be used when returning the + // message. Onelogin Toolkit supports for this endpoint the + // HTTP-Redirect binding only + 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect', + ], + // SLO endpoint info of the IdP. + 'singleLogoutService' => [ + // URL Location of the IdP where the SP will send the SLO Request + 'url' => env('SAML2_IDP_SLO', null), + // URL location of the IdP where the SP will send the SLO Response (ResponseLocation) + // if not set, url for the SLO Request will be used + 'responseUrl' => '', + // SAML protocol binding to be used when returning the + // message. Onelogin Toolkit supports for this endpoint the + // HTTP-Redirect binding only + 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect', + ], + // Public x509 certificate of the IdP + 'x509cert' => env('SAML2_IDP_x509', null), + /* + * Instead of use the whole x509cert you can use a fingerprint in + * order to validate the SAMLResponse, but we don't recommend to use + * that method on production since is exploitable by a collision + * attack. + * (openssl x509 -noout -fingerprint -in "idp.crt" to generate it, + * or add for example the -sha256 , -sha384 or -sha512 parameter) + * + * If a fingerprint is provided, then the certFingerprintAlgorithm is required in order to + * let the toolkit know which Algorithm was used. Possible values: sha1, sha256, sha384 or sha512 + * 'sha1' is the default value. + */ + // 'certFingerprint' => '', + // 'certFingerprintAlgorithm' => 'sha1', + /* In some scenarios the IdP uses different certificates for + * signing/encryption, or is under key rollover phase and more + * than one certificate is published on IdP metadata. + * In order to handle that the toolkit offers that parameter. + * (when used, 'x509cert' and 'certFingerprint' values are + * ignored). + */ + // 'x509certMulti' => array( + // 'signing' => array( + // 0 => '', + // ), + // 'encryption' => array( + // 0 => '', + // ) + // ), + ], + ], + +]; diff --git a/app/Config/services.php b/app/Config/services.php index 97cb71ddc..a0bdd078a 100644 --- a/app/Config/services.php +++ b/app/Config/services.php @@ -22,23 +22,6 @@ return [ // Callback URL for social authentication methods 'callback_url' => env('APP_URL', false), - 'mailgun' => [ - 'domain' => '', - 'secret' => '', - ], - - 'ses' => [ - 'key' => '', - 'secret' => '', - 'region' => 'us-east-1', - ], - - 'stripe' => [ - 'model' => \BookStack\Auth\User::class, - 'key' => '', - 'secret' => '', - ], - 'github' => [ 'client_id' => env('GITHUB_APP_ID', false), 'client_secret' => env('GITHUB_APP_SECRET', false), @@ -98,8 +81,8 @@ return [ 'okta' => [ 'client_id' => env('OKTA_APP_ID'), 'client_secret' => env('OKTA_APP_SECRET'), - 'redirect' => env('APP_URL') . '/login/service/okta/callback', - 'base_url' => env('OKTA_BASE_URL'), + 'redirect' => env('APP_URL') . '/login/service/okta/callback', + 'base_url' => env('OKTA_BASE_URL'), 'name' => 'Okta', 'auto_register' => env('OKTA_AUTO_REGISTER', false), 'auto_confirm' => env('OKTA_AUTO_CONFIRM_EMAIL', false), @@ -140,13 +123,14 @@ return [ 'base_dn' => env('LDAP_BASE_DN', false), 'user_filter' => env('LDAP_USER_FILTER', '(&(uid=${user}))'), 'version' => env('LDAP_VERSION', false), + 'id_attribute' => env('LDAP_ID_ATTRIBUTE', 'uid'), 'email_attribute' => env('LDAP_EMAIL_ATTRIBUTE', 'mail'), 'display_name_attribute' => env('LDAP_DISPLAY_NAME_ATTRIBUTE', 'cn'), 'follow_referrals' => env('LDAP_FOLLOW_REFERRALS', false), - 'user_to_groups' => env('LDAP_USER_TO_GROUPS',false), - 'group_attribute' => env('LDAP_GROUP_ATTRIBUTE', 'memberOf'), - 'remove_from_groups' => env('LDAP_REMOVE_FROM_GROUPS',false), - 'tls_insecure' => env('LDAP_TLS_INSECURE', false), - ] + 'user_to_groups' => env('LDAP_USER_TO_GROUPS', false), + 'group_attribute' => env('LDAP_GROUP_ATTRIBUTE', 'memberOf'), + 'remove_from_groups' => env('LDAP_REMOVE_FROM_GROUPS', false), + 'tls_insecure' => env('LDAP_TLS_INSECURE', false), + ], ]; diff --git a/app/Config/session.php b/app/Config/session.php index bdb5e554b..37f1627bb 100644 --- a/app/Config/session.php +++ b/app/Config/session.php @@ -35,13 +35,18 @@ return [ // Session database table, if database driver is in use 'table' => 'sessions', + // Session Cache Store + // When using the "apc" or "memcached" session drivers, you may specify a + // cache store that should be used for these sessions. This value must + // correspond with one of the application's configured cache stores. + 'store' => null, + // Session Sweeping Lottery // Some session drivers must manually sweep their storage location to get // rid of old sessions from storage. Here are the chances that it will // happen on a given request. By default, the odds are 2 out of 100. 'lottery' => [2, 100], - // Session Cookie Name // Here you may change the name of the cookie used to identify a session // instance by ID. The name specified here will get used every time a diff --git a/app/Config/setting-defaults.php b/app/Config/setting-defaults.php index 4a135573b..d84c0c264 100644 --- a/app/Config/setting-defaults.php +++ b/app/Config/setting-defaults.php @@ -16,7 +16,12 @@ return [ 'app-editor' => 'wysiwyg', 'app-color' => '#206ea7', 'app-color-light' => 'rgba(32,110,167,0.15)', + 'bookshelf-color' => '#a94747', + 'book-color' => '#077b70', + 'chapter-color' => '#af4d0d', + 'page-color' => '#206ea7', + 'page-draft-color' => '#7e50b1', 'app-custom-head' => false, 'registration-enabled' => false, -]; \ No newline at end of file +]; diff --git a/app/Console/Commands/CopyShelfPermissions.php b/app/Console/Commands/CopyShelfPermissions.php new file mode 100644 index 000000000..d9a1c1d72 --- /dev/null +++ b/app/Console/Commands/CopyShelfPermissions.php @@ -0,0 +1,88 @@ +bookshelfRepo = $repo; + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + $shelfSlug = $this->option('slug'); + $cascadeAll = $this->option('all'); + $shelves = null; + + if (!$cascadeAll && !$shelfSlug) { + $this->error('Either a --slug or --all option must be provided.'); + return; + } + + if ($cascadeAll) { + $continue = $this->confirm( + '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?' + ); + + if (!$continue && !$this->hasOption('no-interaction')) { + return; + } + + $shelves = Bookshelf::query()->get(['id', 'restricted']); + } + + if ($shelfSlug) { + $shelves = Bookshelf::query()->where('slug', '=', $shelfSlug)->get(['id', 'restricted']); + if ($shelves->count() === 0) { + $this->info('No shelves found with the given slug.'); + } + } + + foreach ($shelves as $shelf) { + $this->bookshelfRepo->copyDownPermissions($shelf, false); + $this->info('Copied permissions for shelf [' . $shelf->id . ']'); + } + + $this->info('Permissions copied for ' . $shelves->count() . ' shelves.'); + } +} diff --git a/app/Entities/Book.php b/app/Entities/Book.php index 7d3d5e4ae..919f60035 100644 --- a/app/Entities/Book.php +++ b/app/Entities/Book.php @@ -1,21 +1,25 @@ cover ? url($this->cover->getThumb($width, $height, false)) : $default; - } catch (\Exception $err) { + } catch (Exception $err) { $cover = $default; } return $cover; @@ -53,16 +57,23 @@ class Book extends Entity /** * Get the cover image of the book - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ - public function cover() + public function cover(): BelongsTo { return $this->belongsTo(Image::class, 'image_id'); } + /** + * Get the type of the image model that is used when storing a cover image. + */ + public function coverImageTypeKey(): string + { + return 'cover_book'; + } + /** * Get all pages within this book. - * @return \Illuminate\Database\Eloquent\Relations\HasMany + * @return HasMany */ public function pages() { @@ -71,7 +82,7 @@ class Book extends Entity /** * Get the direct child pages of this book. - * @return \Illuminate\Database\Eloquent\Relations\HasMany + * @return HasMany */ public function directPages() { @@ -80,7 +91,7 @@ class Book extends Entity /** * Get all chapters within this book. - * @return \Illuminate\Database\Eloquent\Relations\HasMany + * @return HasMany */ public function chapters() { @@ -89,13 +100,24 @@ class Book extends Entity /** * Get the shelves this book is contained within. - * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany + * @return BelongsToMany */ public function shelves() { return $this->belongsToMany(Bookshelf::class, 'bookshelves_books', 'book_id', 'bookshelf_id'); } + /** + * Get the direct child items within this book. + * @return Collection + */ + public function getDirectChildren(): Collection + { + $pages = $this->directPages()->visible()->get(); + $chapters = $this->chapters()->visible()->get(); + return $pages->contact($chapters)->sortBy('priority')->sortByDesc('draft'); + } + /** * Get an excerpt of this book's description to the specified length or less. * @param int $length @@ -106,13 +128,4 @@ class Book extends Entity $description = $this->description; return mb_strlen($description) > $length ? mb_substr($description, 0, $length-3) . '...' : $description; } - - /** - * Return a generalised, common raw query that can be 'unioned' across entities. - * @return string - */ - public function entityRawQuery() - { - return "'BookStack\\\\Book' as entity_type, id, id as entity_id, slug, name, {$this->textField} as text,'' as html, '0' as book_id, '0' as priority, '0' as chapter_id, '0' as draft, created_by, updated_by, updated_at, created_at"; - } } diff --git a/app/Entities/BookChild.php b/app/Entities/BookChild.php new file mode 100644 index 000000000..6eac4375d --- /dev/null +++ b/app/Entities/BookChild.php @@ -0,0 +1,60 @@ +with('book') + ->whereHas('book', function (Builder $query) use ($bookSlug) { + $query->where('slug', '=', $bookSlug); + }) + ->where('slug', '=', $childSlug); + } + + /** + * Get the book this page sits in. + * @return BelongsTo + */ + public function book(): BelongsTo + { + return $this->belongsTo(Book::class); + } + + /** + * Change the book that this entity belongs to. + */ + public function changeBook(int $newBookId): Entity + { + $this->book_id = $newBookId; + $this->refreshSlug(); + $this->save(); + $this->refresh(); + + // Update related activity + $this->activity()->update(['book_id' => $newBookId]); + + // Update all child pages if a chapter + if ($this instanceof Chapter) { + foreach ($this->pages as $page) { + $page->changeBook($newBookId); + } + } + + return $this; + } +} diff --git a/app/Entities/Bookshelf.php b/app/Entities/Bookshelf.php index db6685688..62c7e2fe4 100644 --- a/app/Entities/Bookshelf.php +++ b/app/Entities/Bookshelf.php @@ -1,8 +1,10 @@ orderBy('order', 'asc'); } + /** + * Related books that are visible to the current user. + */ + public function visibleBooks(): BelongsToMany + { + return $this->books()->visible(); + } + /** * Get the url for this bookshelf. * @param string|bool $path @@ -68,13 +69,20 @@ class Bookshelf extends Entity /** * Get the cover image of the shelf - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ - public function cover() + public function cover(): BelongsTo { return $this->belongsTo(Image::class, 'image_id'); } + /** + * Get the type of the image model that is used when storing a cover image. + */ + public function coverImageTypeKey(): string + { + return 'cover_shelf'; + } + /** * Get an excerpt of this book's description to the specified length or less. * @param int $length @@ -86,22 +94,27 @@ class Bookshelf extends Entity return mb_strlen($description) > $length ? mb_substr($description, 0, $length-3) . '...' : $description; } - /** - * Return a generalised, common raw query that can be 'unioned' across entities. - * @return string - */ - public function entityRawQuery() - { - return "'BookStack\\\\BookShelf' as entity_type, id, id as entity_id, slug, name, {$this->textField} as text,'' as html, '0' as book_id, '0' as priority, '0' as chapter_id, '0' as draft, created_by, updated_by, updated_at, created_at"; - } - /** * Check if this shelf contains the given book. * @param Book $book * @return bool */ - public function contains(Book $book) + public function contains(Book $book): bool { return $this->books()->where('id', '=', $book->id)->count() > 0; } + + /** + * Add a book to the end of this shelf. + * @param Book $book + */ + public function appendBook(Book $book) + { + if ($this->contains($book)) { + return; + } + + $maxOrder = $this->books()->max('order'); + $this->books()->attach($book->id, ['order' => $maxOrder + 1]); + } } diff --git a/app/Entities/BreadcrumbsViewComposer.php b/app/Entities/BreadcrumbsViewComposer.php index 97ddbc2dc..43d63d026 100644 --- a/app/Entities/BreadcrumbsViewComposer.php +++ b/app/Entities/BreadcrumbsViewComposer.php @@ -1,5 +1,6 @@ entityContextManager = $entityContextManager; } @@ -23,8 +24,9 @@ class BreadcrumbsViewComposer public function compose(View $view) { $crumbs = $view->getData()['crumbs']; - if (array_first($crumbs) instanceof Book) { - $shelf = $this->entityContextManager->getContextualShelfForBook(array_first($crumbs)); + $firstCrumb = $crumbs[0] ?? null; + if ($firstCrumb instanceof Book) { + $shelf = $this->entityContextManager->getContextualShelfForBook($firstCrumb); if ($shelf) { array_unshift($crumbs, $shelf); $view->with('crumbs', $crumbs); diff --git a/app/Entities/Chapter.php b/app/Entities/Chapter.php index b204f1903..848bc6448 100644 --- a/app/Entities/Chapter.php +++ b/app/Entities/Chapter.php @@ -1,29 +1,18 @@ $pages + * @package BookStack\Entities + */ +class Chapter extends BookChild { public $searchFactor = 1.3; protected $fillable = ['name', 'description', 'priority', 'book_id']; - /** - * Get the morph class for this model. - * @return string - */ - public function getMorphClass() - { - return 'BookStack\\Chapter'; - } - - /** - * Get the book this chapter is within. - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo - */ - public function book() - { - return $this->belongsTo(Book::class); - } - /** * Get the pages that this chapter contains. * @param string $dir @@ -62,15 +51,6 @@ class Chapter extends Entity return mb_strlen($description) > $length ? mb_substr($description, 0, $length-3) . '...' : $description; } - /** - * Return a generalised, common raw query that can be 'unioned' across entities. - * @return string - */ - public function entityRawQuery() - { - return "'BookStack\\\\Chapter' as entity_type, id, id as entity_id, slug, name, {$this->textField} as text, '' as html, book_id, priority, '0' as chapter_id, '0' as draft, created_by, updated_by, updated_at, created_at"; - } - /** * Check if this chapter has any child pages. * @return bool @@ -79,4 +59,15 @@ class Chapter extends Entity { return count($this->pages) > 0; } + + /** + * Get the visible pages in this chapter. + */ + public function getVisiblePages(): Collection + { + return $this->pages()->visible() + ->orderBy('draft', 'desc') + ->orderBy('priority', 'asc') + ->get(); + } } diff --git a/app/Entities/Entity.php b/app/Entities/Entity.php index 482d21766..5013c39cf 100644 --- a/app/Entities/Entity.php +++ b/app/Entities/Entity.php @@ -6,8 +6,11 @@ use BookStack\Actions\Tag; use BookStack\Actions\View; use BookStack\Auth\Permissions\EntityPermission; use BookStack\Auth\Permissions\JointPermission; +use BookStack\Facades\Permissions; use BookStack\Ownable; use Carbon\Carbon; +use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Relations\MorphMany; /** @@ -15,7 +18,7 @@ use Illuminate\Database\Eloquent\Relations\MorphMany; * The base class for book-like items such as pages, chapters & books. * This is not a database model in itself but extended. * - * @property integer $id + * @property int $id * @property string $name * @property string $slug * @property Carbon $created_at @@ -23,6 +26,11 @@ use Illuminate\Database\Eloquent\Relations\MorphMany; * @property int $created_by * @property int $updated_by * @property boolean $restricted + * @property Collection $tags + * @method static Entity|Builder visible() + * @method static Entity|Builder hasPermission(string $permission) + * @method static Builder withLastView() + * @method static Builder withViewCount() * * @package BookStack\Entities */ @@ -40,14 +48,45 @@ class Entity extends Ownable public $searchFactor = 1.0; /** - * Get the morph class for this model. - * Set here since, due to folder changes, the namespace used - * in the database no longer matches the class namespace. - * @return string + * Get the entities that are visible to the current user. */ - public function getMorphClass() + public function scopeVisible(Builder $query) { - return 'BookStack\\Entity'; + return $this->scopeHasPermission($query, 'view'); + } + + /** + * Scope the query to those entities that the current user has the given permission for. + */ + public function scopeHasPermission(Builder $query, string $permission) + { + return Permissions::restrictEntityQuery($query, $permission); + } + + /** + * Query scope to get the last view from the current user. + */ + public function scopeWithLastView(Builder $query) + { + $viewedAtQuery = View::query()->select('updated_at') + ->whereColumn('viewable_id', '=', $this->getTable() . '.id') + ->where('viewable_type', '=', $this->getMorphClass()) + ->where('user_id', '=', user()->id) + ->take(1); + + return $query->addSelect(['last_viewed_at' => $viewedAtQuery]); + } + + /** + * Query scope to get the total view count of the entities. + */ + public function scopeWithViewCount(Builder $query) + { + $viewCountQuery = View::query()->selectRaw('SUM(views) as view_count') + ->whereColumn('viewable_id', '=', $this->getTable() . '.id') + ->where('viewable_type', '=', $this->getMorphClass())->take(1); + + $query->addSelect(['view_count' => $viewCountQuery]); } /** @@ -87,11 +126,12 @@ class Entity extends Ownable /** * Gets the activity objects for this entity. - * @return \Illuminate\Database\Eloquent\Relations\MorphMany + * @return MorphMany */ public function activity() { - return $this->morphMany(Activity::class, 'entity')->orderBy('created_at', 'desc'); + return $this->morphMany(Activity::class, 'entity') + ->orderBy('created_at', 'desc'); } /** @@ -102,14 +142,9 @@ class Entity extends Ownable return $this->morphMany(View::class, 'viewable'); } - public function viewCountQuery() - { - return $this->views()->selectRaw('viewable_id, sum(views) as view_count')->groupBy('viewable_id'); - } - /** * Get the Tag models that have been user assigned to this entity. - * @return \Illuminate\Database\Eloquent\Relations\MorphMany + * @return MorphMany */ public function tags() { @@ -129,7 +164,7 @@ class Entity extends Ownable /** * Get the related search terms. - * @return \Illuminate\Database\Eloquent\Relations\MorphMany + * @return MorphMany */ public function searchTerms() { @@ -158,7 +193,7 @@ class Entity extends Ownable /** * Get the entity jointPermissions this is connected to. - * @return \Illuminate\Database\Eloquent\Relations\MorphMany + * @return MorphMany */ public function jointPermissions() { @@ -237,15 +272,6 @@ class Entity extends Ownable return trim($text); } - /** - * Return a generalised, common raw query that can be 'unioned' across entities. - * @return string - */ - public function entityRawQuery() - { - return ''; - } - /** * Get the url of this entity * @param $path @@ -255,4 +281,32 @@ class Entity extends Ownable { return $path; } + + /** + * Rebuild the permissions for this entity. + */ + public function rebuildPermissions() + { + /** @noinspection PhpUnhandledExceptionInspection */ + Permissions::buildJointPermissionsForEntity($this); + } + + /** + * Index the current entity for search + */ + public function indexForSearch() + { + $searchService = app()->make(SearchService::class); + $searchService->indexEntity($this); + } + + /** + * Generate and set a new URL slug for this model. + */ + public function refreshSlug(): string + { + $generator = new SlugGenerator($this); + $this->slug = $generator->generate(); + return $this->slug; + } } diff --git a/app/Entities/EntityProvider.php b/app/Entities/EntityProvider.php index d0d4a7ad6..6bf923b31 100644 --- a/app/Entities/EntityProvider.php +++ b/app/Entities/EntityProvider.php @@ -39,11 +39,6 @@ class EntityProvider /** * EntityProvider constructor. - * @param Bookshelf $bookshelf - * @param Book $book - * @param Chapter $chapter - * @param Page $page - * @param PageRevision $pageRevision */ public function __construct( Bookshelf $bookshelf, @@ -62,9 +57,8 @@ class EntityProvider /** * Fetch all core entity types as an associated array * with their basic names as the keys. - * @return Entity[] */ - public function all() + public function all(): array { return [ 'bookshelf' => $this->bookshelf, @@ -76,10 +70,8 @@ class EntityProvider /** * Get an entity instance by it's basic name. - * @param string $type - * @return Entity */ - public function get(string $type) + public function get(string $type): Entity { $type = strtolower($type); return $this->all()[$type]; @@ -87,15 +79,9 @@ class EntityProvider /** * Get the morph classes, as an array, for a single or multiple types. - * @param string|array $types - * @return array */ - public function getMorphClasses($types) + public function getMorphClasses(array $types): array { - if (is_string($types)) { - $types = [$types]; - } - $morphClasses = []; foreach ($types as $type) { $model = $this->get($type); diff --git a/app/Entities/ExportService.php b/app/Entities/ExportService.php index 09635aa21..3ec867959 100644 --- a/app/Entities/ExportService.php +++ b/app/Entities/ExportService.php @@ -1,35 +1,34 @@ entityRepo = $entityRepo; $this->imageService = $imageService; } /** * Convert a page to a self-contained HTML file. * Includes required CSS & image content. Images are base64 encoded into the HTML. - * @param \BookStack\Entities\Page $page - * @return mixed|string - * @throws \Throwable + * @throws Throwable */ public function pageToContainedHtml(Page $page) { - $this->entityRepo->renderPage($page); + $page->html = (new PageContent($page))->render(); $pageHtml = view('pages/export', [ 'page' => $page ])->render(); @@ -38,15 +37,13 @@ class ExportService /** * Convert a chapter to a self-contained HTML file. - * @param \BookStack\Entities\Chapter $chapter - * @return mixed|string - * @throws \Throwable + * @throws Throwable */ public function chapterToContainedHtml(Chapter $chapter) { - $pages = $this->entityRepo->getChapterChildren($chapter); + $pages = $chapter->getVisiblePages(); $pages->each(function ($page) { - $page->html = $this->entityRepo->renderPage($page); + $page->html = (new PageContent($page))->render(); }); $html = view('chapters/export', [ 'chapter' => $chapter, @@ -57,13 +54,11 @@ class ExportService /** * Convert a book to a self-contained HTML file. - * @param Book $book - * @return mixed|string - * @throws \Throwable + * @throws Throwable */ public function bookToContainedHtml(Book $book) { - $bookTree = $this->entityRepo->getBookChildren($book, true, true); + $bookTree = (new BookContents($book))->getTree(false, true); $html = view('books/export', [ 'book' => $book, 'bookChildren' => $bookTree @@ -73,13 +68,11 @@ class ExportService /** * Convert a page to a PDF file. - * @param Page $page - * @return mixed|string - * @throws \Throwable + * @throws Throwable */ public function pageToPdf(Page $page) { - $this->entityRepo->renderPage($page); + $page->html = (new PageContent($page))->render(); $html = view('pages/pdf', [ 'page' => $page ])->render(); @@ -88,32 +81,30 @@ class ExportService /** * Convert a chapter to a PDF file. - * @param \BookStack\Entities\Chapter $chapter - * @return mixed|string - * @throws \Throwable + * @throws Throwable */ public function chapterToPdf(Chapter $chapter) { - $pages = $this->entityRepo->getChapterChildren($chapter); + $pages = $chapter->getVisiblePages(); $pages->each(function ($page) { - $page->html = $this->entityRepo->renderPage($page); + $page->html = (new PageContent($page))->render(); }); + $html = view('chapters/export', [ 'chapter' => $chapter, 'pages' => $pages ])->render(); + return $this->htmlToPdf($html); } /** - * Convert a book to a PDF file - * @param \BookStack\Entities\Book $book - * @return string - * @throws \Throwable + * Convert a book to a PDF file. + * @throws Throwable */ public function bookToPdf(Book $book) { - $bookTree = $this->entityRepo->getBookChildren($book, true, true); + $bookTree = (new BookContents($book))->getTree(false, true); $html = view('books/export', [ 'book' => $book, 'bookChildren' => $bookTree @@ -122,31 +113,27 @@ class ExportService } /** - * Convert normal webpage HTML to a PDF. - * @param $html - * @return string - * @throws \Exception + * Convert normal web-page HTML to a PDF. + * @throws Exception */ - protected function htmlToPdf($html) + protected function htmlToPdf(string $html): string { $containedHtml = $this->containHtml($html); $useWKHTML = config('snappy.pdf.binary') !== false; if ($useWKHTML) { - $pdf = \SnappyPDF::loadHTML($containedHtml); + $pdf = SnappyPDF::loadHTML($containedHtml); $pdf->setOption('print-media-type', true); } else { - $pdf = \DomPDF::loadHTML($containedHtml); + $pdf = DomPDF::loadHTML($containedHtml); } return $pdf->output(); } /** * Bundle of the contents of a html file to be self-contained. - * @param $htmlContent - * @return mixed|string - * @throws \Exception + * @throws Exception */ - protected function containHtml($htmlContent) + protected function containHtml(string $htmlContent): string { $imageTagsOutput = []; preg_match_all("/\/i", $htmlContent, $imageTagsOutput); @@ -188,12 +175,10 @@ class ExportService /** * Converts the page contents into simple plain text. * This method filters any bad looking content to provide a nice final output. - * @param Page $page - * @return mixed */ - public function pageToPlainText(Page $page) + public function pageToPlainText(Page $page): string { - $html = $this->entityRepo->renderPage($page); + $html = (new PageContent($page))->render(); $text = strip_tags($html); // Replace multiple spaces with single spaces $text = preg_replace('/\ {2,}/', ' ', $text); @@ -207,10 +192,8 @@ class ExportService /** * Convert a chapter into a plain text string. - * @param \BookStack\Entities\Chapter $chapter - * @return string */ - public function chapterToPlainText(Chapter $chapter) + public function chapterToPlainText(Chapter $chapter): string { $text = $chapter->name . "\n\n"; $text .= $chapter->description . "\n\n"; @@ -222,12 +205,10 @@ class ExportService /** * Convert a book into a plain text string. - * @param Book $book - * @return string */ - public function bookToPlainText(Book $book) + public function bookToPlainText(Book $book): string { - $bookTree = $this->entityRepo->getBookChildren($book, true, true); + $bookTree = (new BookContents($book))->getTree(false, true); $text = $book->name . "\n\n"; foreach ($bookTree as $bookChild) { if ($bookChild->isA('chapter')) { diff --git a/app/Entities/HasCoverImage.php b/app/Entities/HasCoverImage.php new file mode 100644 index 000000000..31277f4b6 --- /dev/null +++ b/app/Entities/HasCoverImage.php @@ -0,0 +1,20 @@ +book = $book; + } + + /** + * Get the current priority of the last item + * at the top-level of the book. + */ + public function getLastPriority(): int + { + $maxPage = Page::visible()->where('book_id', '=', $this->book->id) + ->where('draft', '=', false) + ->where('chapter_id', '=', 0)->max('priority'); + $maxChapter = Chapter::visible()->where('book_id', '=', $this->book->id) + ->max('priority'); + return max($maxChapter, $maxPage, 1); + } + + /** + * Get the contents as a sorted collection tree. + * TODO - Support $renderPages option + */ + public function getTree(bool $showDrafts = false, bool $renderPages = false): Collection + { + $pages = $this->getPages($showDrafts); + $chapters = Chapter::visible()->where('book_id', '=', $this->book->id)->get(); + $all = collect()->concat($pages)->concat($chapters); + $chapterMap = $chapters->keyBy('id'); + $lonePages = collect(); + + $pages->groupBy('chapter_id')->each(function ($pages, $chapter_id) use ($chapterMap, &$lonePages) { + $chapter = $chapterMap->get($chapter_id); + if ($chapter) { + $chapter->setAttribute('pages', collect($pages)->sortBy($this->bookChildSortFunc())); + } else { + $lonePages = $lonePages->concat($pages); + } + }); + + $all->each(function (Entity $entity) { + $entity->setRelation('book', $this->book); + }); + + return collect($chapters)->concat($lonePages)->sortBy($this->bookChildSortFunc()); + } + + /** + * Function for providing a sorting score for an entity in relation to the + * other items within the book. + */ + protected function bookChildSortFunc(): callable + { + return function (Entity $entity) { + if (isset($entity['draft']) && $entity['draft']) { + return -100; + } + return $entity['priority'] ?? 0; + }; + } + + /** + * Get the visible pages within this book. + */ + protected function getPages(bool $showDrafts = false): Collection + { + $query = Page::visible()->where('book_id', '=', $this->book->id); + + if (!$showDrafts) { + $query->where('draft', '=', false); + } + + return $query->get(); + } + + /** + * Sort the books content using the given map. + * The map is a single-dimension collection of objects in the following format: + * { + * +"id": "294" (ID of item) + * +"sort": 1 (Sort order index) + * +"parentChapter": false (ID of parent chapter, as string, or false) + * +"type": "page" (Entity type of item) + * +"book": "1" (Id of book to place item in) + * } + * + * Returns a list of books that were involved in the operation. + * @throws SortOperationException + */ + public function sortUsingMap(Collection $sortMap): Collection + { + // Load models into map + $this->loadModelsIntoSortMap($sortMap); + $booksInvolved = $this->getBooksInvolvedInSort($sortMap); + + // Perform the sort + $sortMap->each(function ($mapItem) { + $this->applySortUpdates($mapItem); + }); + + // Update permissions and activity. + $booksInvolved->each(function (Book $book) { + $book->rebuildPermissions(); + }); + + return $booksInvolved; + } + + /** + * Using the given sort map item, detect changes for the related model + * and update it if required. + */ + protected function applySortUpdates(\stdClass $sortMapItem) + { + /** @var BookChild $model */ + $model = $sortMapItem->model; + + $priorityChanged = intval($model->priority) !== intval($sortMapItem->sort); + $bookChanged = intval($model->book_id) !== intval($sortMapItem->book); + $chapterChanged = ($sortMapItem->type === 'page') && intval($model->chapter_id) !== $sortMapItem->parentChapter; + + if ($bookChanged) { + $model->changeBook($sortMapItem->book); + } + + if ($chapterChanged) { + $model->chapter_id = intval($sortMapItem->parentChapter); + $model->save(); + } + + if ($priorityChanged) { + $model->priority = intval($sortMapItem->sort); + $model->save(); + } + } + + /** + * Load models from the database into the given sort map. + */ + protected function loadModelsIntoSortMap(Collection $sortMap): void + { + $keyMap = $sortMap->keyBy(function (\stdClass $sortMapItem) { + return $sortMapItem->type . ':' . $sortMapItem->id; + }); + $pageIds = $sortMap->where('type', '=', 'page')->pluck('id'); + $chapterIds = $sortMap->where('type', '=', 'chapter')->pluck('id'); + + $pages = Page::visible()->whereIn('id', $pageIds)->get(); + $chapters = Chapter::visible()->whereIn('id', $chapterIds)->get(); + + foreach ($pages as $page) { + $sortItem = $keyMap->get('page:' . $page->id); + $sortItem->model = $page; + } + + foreach ($chapters as $chapter) { + $sortItem = $keyMap->get('chapter:' . $chapter->id); + $sortItem->model = $chapter; + } + } + + /** + * Get the books involved in a sort. + * The given sort map should have its models loaded first. + * @throws SortOperationException + */ + protected function getBooksInvolvedInSort(Collection $sortMap): Collection + { + $bookIdsInvolved = collect([$this->book->id]); + $bookIdsInvolved = $bookIdsInvolved->concat($sortMap->pluck('book')); + $bookIdsInvolved = $bookIdsInvolved->concat($sortMap->pluck('model.book_id')); + $bookIdsInvolved = $bookIdsInvolved->unique()->toArray(); + + $books = Book::hasPermission('update')->whereIn('id', $bookIdsInvolved)->get(); + + if (count($books) !== count($bookIdsInvolved)) { + throw new SortOperationException("Could not find all books requested in sort operation"); + } + + return $books; + } +} diff --git a/app/Entities/EntityContextManager.php b/app/Entities/Managers/EntityContext.php similarity index 53% rename from app/Entities/EntityContextManager.php rename to app/Entities/Managers/EntityContext.php index 20be0de2b..551cd1a10 100644 --- a/app/Entities/EntityContextManager.php +++ b/app/Entities/Managers/EntityContext.php @@ -1,44 +1,38 @@ -session = $session; - $this->entityRepo = $entityRepo; } /** * Get the current bookshelf context for the given book. - * @param Book $book - * @return Bookshelf|null */ - public function getContextualShelfForBook(Book $book) + public function getContextualShelfForBook(Book $book): ?Bookshelf { $contextBookshelfId = $this->session->get($this->KEY_SHELF_CONTEXT_ID, null); - if (is_int($contextBookshelfId)) { - /** @var Bookshelf $shelf */ - $shelf = $this->entityRepo->getById('bookshelf', $contextBookshelfId); - - if ($shelf && $shelf->contains($book)) { - return $shelf; - } + if (!is_int($contextBookshelfId)) { + return null; } - return null; + + $shelf = Bookshelf::visible()->find($contextBookshelfId); + $shelfContainsBook = $shelf && $shelf->contains($book); + + return $shelfContainsBook ? $shelf : null; } /** diff --git a/app/Entities/Managers/PageContent.php b/app/Entities/Managers/PageContent.php new file mode 100644 index 000000000..36bc2445c --- /dev/null +++ b/app/Entities/Managers/PageContent.php @@ -0,0 +1,304 @@ +page = $page; + } + + /** + * Update the content of the page with new provided HTML. + */ + public function setNewHTML(string $html) + { + $this->page->html = $this->formatHtml($html); + $this->page->text = $this->toPlainText(); + } + + /** + * Formats a page's html to be tagged correctly within the system. + */ + protected function formatHtml(string $htmlText): string + { + if ($htmlText == '') { + return $htmlText; + } + + libxml_use_internal_errors(true); + $doc = new DOMDocument(); + $doc->loadHTML(mb_convert_encoding($htmlText, 'HTML-ENTITIES', 'UTF-8')); + + $container = $doc->documentElement; + $body = $container->childNodes->item(0); + $childNodes = $body->childNodes; + + // Set ids on top-level nodes + $idMap = []; + foreach ($childNodes as $index => $childNode) { + $this->setUniqueId($childNode, $idMap); + } + + // Ensure no duplicate ids within child items + $xPath = new DOMXPath($doc); + $idElems = $xPath->query('//body//*//*[@id]'); + foreach ($idElems as $domElem) { + $this->setUniqueId($domElem, $idMap); + } + + // Generate inner html as a string + $html = ''; + foreach ($childNodes as $childNode) { + $html .= $doc->saveHTML($childNode); + } + + return $html; + } + + /** + * Set a unique id on the given DOMElement. + * A map for existing ID's should be passed in to check for current existence. + * @param DOMElement $element + * @param array $idMap + */ + protected function setUniqueId($element, array &$idMap) + { + if (get_class($element) !== 'DOMElement') { + return; + } + + // Overwrite id if not a BookStack custom id + $existingId = $element->getAttribute('id'); + if (strpos($existingId, 'bkmrk') === 0 && !isset($idMap[$existingId])) { + $idMap[$existingId] = true; + return; + } + + // Create an unique id for the element + // Uses the content as a basis to ensure output is the same every time + // the same content is passed through. + $contentId = 'bkmrk-' . mb_substr(strtolower(preg_replace('/\s+/', '-', trim($element->nodeValue))), 0, 20); + $newId = urlencode($contentId); + $loopIndex = 0; + + while (isset($idMap[$newId])) { + $newId = urlencode($contentId . '-' . $loopIndex); + $loopIndex++; + } + + $element->setAttribute('id', $newId); + $idMap[$newId] = true; + } + + /** + * Get a plain-text visualisation of this page. + */ + protected function toPlainText(): string + { + $html = $this->render(true); + return strip_tags($html); + } + + /** + * Render the page for viewing + */ + public function render(bool $blankIncludes = false) : string + { + $content = $this->page->html; + + if (!config('app.allow_content_scripts')) { + $content = $this->escapeScripts($content); + } + + if ($blankIncludes) { + $content = $this->blankPageIncludes($content); + } else { + $content = $this->parsePageIncludes($content); + } + + return $content; + } + + /** + * Parse the headers on the page to get a navigation menu + */ + public function getNavigation(string $htmlContent): array + { + if (empty($htmlContent)) { + return []; + } + + libxml_use_internal_errors(true); + $doc = new DOMDocument(); + $doc->loadHTML(mb_convert_encoding($htmlContent, 'HTML-ENTITIES', 'UTF-8')); + $xPath = new DOMXPath($doc); + $headers = $xPath->query("//h1|//h2|//h3|//h4|//h5|//h6"); + + return $headers ? $this->headerNodesToLevelList($headers) : []; + } + + /** + * Convert a DOMNodeList into an array of readable header attributes + * with levels normalised to the lower header level. + */ + protected function headerNodesToLevelList(DOMNodeList $nodeList): array + { + $tree = collect($nodeList)->map(function ($header) { + $text = trim(str_replace("\xc2\xa0", '', $header->nodeValue)); + $text = mb_substr($text, 0, 100); + + return [ + 'nodeName' => strtolower($header->nodeName), + 'level' => intval(str_replace('h', '', $header->nodeName)), + 'link' => '#' . $header->getAttribute('id'), + 'text' => $text, + ]; + })->filter(function ($header) { + return mb_strlen($header['text']) > 0; + }); + + // Shift headers if only smaller headers have been used + $levelChange = ($tree->pluck('level')->min() - 1); + $tree = $tree->map(function ($header) use ($levelChange) { + $header['level'] -= ($levelChange); + return $header; + }); + + return $tree->toArray(); + } + + /** + * Remove any page include tags within the given HTML. + */ + protected function blankPageIncludes(string $html) : string + { + return preg_replace("/{{@\s?([0-9].*?)}}/", '', $html); + } + + /** + * Parse any include tags "{{@#section}}" to be part of the page. + */ + protected function parsePageIncludes(string $html) : string + { + $matches = []; + preg_match_all("/{{@\s?([0-9].*?)}}/", $html, $matches); + + foreach ($matches[1] as $index => $includeId) { + $fullMatch = $matches[0][$index]; + $splitInclude = explode('#', $includeId, 2); + + // Get page id from reference + $pageId = intval($splitInclude[0]); + if (is_nan($pageId)) { + continue; + } + + // Find page and skip this if page not found + $matchedPage = Page::visible()->find($pageId); + if ($matchedPage === null) { + $html = str_replace($fullMatch, '', $html); + continue; + } + + // If we only have page id, just insert all page html and continue. + if (count($splitInclude) === 1) { + $html = str_replace($fullMatch, $matchedPage->html, $html); + continue; + } + + // Create and load HTML into a document + $innerContent = $this->fetchSectionOfPage($matchedPage, $splitInclude[1]); + $html = str_replace($fullMatch, trim($innerContent), $html); + } + + return $html; + } + + + /** + * Fetch the content from a specific section of the given page. + */ + protected function fetchSectionOfPage(Page $page, string $sectionId): string + { + $topLevelTags = ['table', 'ul', 'ol']; + $doc = new DOMDocument(); + libxml_use_internal_errors(true); + $doc->loadHTML(mb_convert_encoding(''.$page->html.'', 'HTML-ENTITIES', 'UTF-8')); + + // Search included content for the id given and blank out if not exists. + $matchingElem = $doc->getElementById($sectionId); + if ($matchingElem === null) { + return ''; + } + + // Otherwise replace the content with the found content + // Checks if the top-level wrapper should be included by matching on tag types + $innerContent = ''; + $isTopLevel = in_array(strtolower($matchingElem->nodeName), $topLevelTags); + if ($isTopLevel) { + $innerContent .= $doc->saveHTML($matchingElem); + } else { + foreach ($matchingElem->childNodes as $childNode) { + $innerContent .= $doc->saveHTML($childNode); + } + } + libxml_clear_errors(); + + return $innerContent; + } + + /** + * Escape script tags within HTML content. + */ + protected function escapeScripts(string $html) : string + { + if (empty($html)) { + return $html; + } + + libxml_use_internal_errors(true); + $doc = new DOMDocument(); + $doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8')); + $xPath = new DOMXPath($doc); + + // Remove standard script tags + $scriptElems = $xPath->query('//script'); + foreach ($scriptElems as $scriptElem) { + $scriptElem->parentNode->removeChild($scriptElem); + } + + // Remove data or JavaScript iFrames + $badIframes = $xPath->query('//*[contains(@src, \'data:\')] | //*[contains(@src, \'javascript:\')] | //*[@srcdoc]'); + foreach ($badIframes as $badIframe) { + $badIframe->parentNode->removeChild($badIframe); + } + + // Remove 'on*' attributes + $onAttributes = $xPath->query('//@*[starts-with(name(), \'on\')]'); + foreach ($onAttributes as $attr) { + /** @var \DOMAttr $attr*/ + $attrName = $attr->nodeName; + $attr->parentNode->removeAttribute($attrName); + } + + $html = ''; + $topElems = $doc->documentElement->childNodes->item(0)->childNodes; + foreach ($topElems as $child) { + $html .= $doc->saveHTML($child); + } + + return $html; + } +} diff --git a/app/Entities/Managers/PageEditActivity.php b/app/Entities/Managers/PageEditActivity.php new file mode 100644 index 000000000..cebbf8720 --- /dev/null +++ b/app/Entities/Managers/PageEditActivity.php @@ -0,0 +1,74 @@ +page = $page; + } + + /** + * Check if there's active editing being performed on this page. + * @return bool + */ + public function hasActiveEditing(): bool + { + return $this->activePageEditingQuery(60)->count() > 0; + } + + /** + * Get a notification message concerning the editing activity on the page. + */ + public function activeEditingMessage(): string + { + $pageDraftEdits = $this->activePageEditingQuery(60)->get(); + $count = $pageDraftEdits->count(); + + $userMessage = $count > 1 ? trans('entities.pages_draft_edit_active.start_a', ['count' => $count]): trans('entities.pages_draft_edit_active.start_b', ['userName' => $pageDraftEdits->first()->createdBy->name]); + $timeMessage = trans('entities.pages_draft_edit_active.time_b', ['minCount'=> 60]); + return trans('entities.pages_draft_edit_active.message', ['start' => $userMessage, 'time' => $timeMessage]); + } + + /** + * Get the message to show when the user will be editing one of their drafts. + * @param PageRevision $draft + * @return string + */ + public function getEditingActiveDraftMessage(PageRevision $draft): string + { + $message = trans('entities.pages_editing_draft_notification', ['timeDiff' => $draft->updated_at->diffForHumans()]); + if ($draft->page->updated_at->timestamp <= $draft->updated_at->timestamp) { + return $message; + } + return $message . "\n" . trans('entities.pages_draft_edited_notification'); + } + + /** + * A query to check for active update drafts on a particular page + * within the last given many minutes. + */ + protected function activePageEditingQuery(int $withinMinutes): Builder + { + $checkTime = Carbon::now()->subMinutes($withinMinutes); + $query = PageRevision::query() + ->where('type', '=', 'update_draft') + ->where('page_id', '=', $this->page->id) + ->where('updated_at', '>', $this->page->updated_at) + ->where('created_by', '!=', user()->id) + ->where('updated_at', '>=', $checkTime) + ->with('createdBy'); + + return $query; + } +} diff --git a/app/Entities/Managers/TrashCan.php b/app/Entities/Managers/TrashCan.php new file mode 100644 index 000000000..1a32294fc --- /dev/null +++ b/app/Entities/Managers/TrashCan.php @@ -0,0 +1,109 @@ +destroyCommonRelations($shelf); + $shelf->delete(); + } + + /** + * Remove a book from the system. + * @throws NotifyException + * @throws BindingResolutionException + */ + public function destroyBook(Book $book) + { + foreach ($book->pages as $page) { + $this->destroyPage($page); + } + + foreach ($book->chapters as $chapter) { + $this->destroyChapter($chapter); + } + + $this->destroyCommonRelations($book); + $book->delete(); + } + + /** + * Remove a page from the system. + * @throws NotifyException + */ + public function destroyPage(Page $page) + { + // Check if set as custom homepage & remove setting if not used or throw error if active + $customHome = setting('app-homepage', '0:'); + if (intval($page->id) === intval(explode(':', $customHome)[0])) { + if (setting('app-homepage-type') === 'page') { + throw new NotifyException(trans('errors.page_custom_home_deletion'), $page->getUrl()); + } + setting()->remove('app-homepage'); + } + + $this->destroyCommonRelations($page); + + // Delete Attached Files + $attachmentService = app(AttachmentService::class); + foreach ($page->attachments as $attachment) { + $attachmentService->deleteFile($attachment); + } + + $page->delete(); + } + + /** + * Remove a chapter from the system. + * @throws Exception + */ + public function destroyChapter(Chapter $chapter) + { + if (count($chapter->pages) > 0) { + foreach ($chapter->pages as $page) { + $page->chapter_id = 0; + $page->save(); + } + } + + $this->destroyCommonRelations($chapter); + $chapter->delete(); + } + + /** + * Update entity relations to remove or update outstanding connections. + */ + protected function destroyCommonRelations(Entity $entity) + { + Activity::removeEntity($entity); + $entity->views()->delete(); + $entity->permissions()->delete(); + $entity->tags()->delete(); + $entity->comments()->delete(); + $entity->jointPermissions()->delete(); + $entity->searchTerms()->delete(); + + if ($entity instanceof HasCoverImage && $entity->cover) { + $imageService = app()->make(ImageService::class); + $imageService->destroy($entity->cover); + } + } +} diff --git a/app/Entities/Page.php b/app/Entities/Page.php index c32417418..76dc628fb 100644 --- a/app/Entities/Page.php +++ b/app/Entities/Page.php @@ -1,8 +1,25 @@ belongsTo(Book::class); - } - /** * Get the parent item - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ - public function parent() + public function parent(): Entity { - return $this->chapter_id ? $this->chapter() : $this->book(); + return $this->chapter_id ? $this->chapter : $this->book; } /** * Get the chapter that this page is in, If applicable. - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + * @return BelongsTo */ public function chapter() { @@ -72,12 +79,12 @@ class Page extends Entity */ public function revisions() { - return $this->hasMany(PageRevision::class)->where('type', '=', 'version')->orderBy('created_at', 'desc'); + return $this->hasMany(PageRevision::class)->where('type', '=', 'version')->orderBy('created_at', 'desc')->orderBy('id', 'desc'); } /** * Get the attachments assigned to this page. - * @return \Illuminate\Database\Eloquent\Relations\HasMany + * @return HasMany */ public function attachments() { @@ -95,27 +102,17 @@ class Page extends Entity $midText = $this->draft ? '/draft/' : '/page/'; $idComponent = $this->draft ? $this->id : urlencode($this->slug); + $url = '/books/' . urlencode($bookSlug) . $midText . $idComponent; if ($path !== false) { - return url('/books/' . urlencode($bookSlug) . $midText . $idComponent . '/' . trim($path, '/')); + $url .= '/' . trim($path, '/'); } - return url('/books/' . urlencode($bookSlug) . $midText . $idComponent); - } - - /** - * Return a generalised, common raw query that can be 'unioned' across entities. - * @param bool $withContent - * @return string - */ - public function entityRawQuery($withContent = false) - { - $htmlQuery = $withContent ? 'html' : "'' as html"; - return "'BookStack\\\\Page' as entity_type, id, id as entity_id, slug, name, {$this->textField} as text, {$htmlQuery}, book_id, priority, chapter_id, draft, created_by, updated_by, updated_at, created_at"; + return url($url); } /** * Get the current revision for the page if existing - * @return \BookStack\Entities\PageRevision|null + * @return PageRevision|null */ public function getCurrentRevision() { diff --git a/app/Entities/PageRevision.php b/app/Entities/PageRevision.php index d30147bfc..13dc713ba 100644 --- a/app/Entities/PageRevision.php +++ b/app/Entities/PageRevision.php @@ -2,7 +2,21 @@ use BookStack\Auth\User; use BookStack\Model; +use Carbon\Carbon; +/** + * Class PageRevision + * @property int $page_id + * @property string $slug + * @property string $book_slug + * @property int $created_by + * @property Carbon $created_at + * @property string $type + * @property string $summary + * @property string $markdown + * @property string $html + * @property int $revision_number + */ class PageRevision extends Model { protected $fillable = ['name', 'html', 'text', 'markdown', 'summary']; @@ -41,13 +55,18 @@ class PageRevision extends Model /** * Get the previous revision for the same page if existing - * @return \BookStack\PageRevision|null + * @return \BookStack\Entities\PageRevision|null */ public function getPrevious() { - if ($id = static::where('page_id', '=', $this->page_id)->where('id', '<', $this->id)->max('id')) { - return static::find($id); + $id = static::newQuery()->where('page_id', '=', $this->page_id) + ->where('id', '<', $this->id) + ->max('id'); + + if ($id) { + return static::query()->find($id); } + return null; } diff --git a/app/Entities/Repos/BaseRepo.php b/app/Entities/Repos/BaseRepo.php new file mode 100644 index 000000000..23f07f820 --- /dev/null +++ b/app/Entities/Repos/BaseRepo.php @@ -0,0 +1,119 @@ +tagRepo = $tagRepo; + $this->imageRepo = $imageRepo; + } + + /** + * Create a new entity in the system + */ + public function create(Entity $entity, array $input) + { + $entity->fill($input); + $entity->forceFill([ + 'created_by' => user()->id, + 'updated_by' => user()->id, + ]); + $entity->refreshSlug(); + $entity->save(); + + if (isset($input['tags'])) { + $this->tagRepo->saveTagsToEntity($entity, $input['tags']); + } + + $entity->rebuildPermissions(); + $entity->indexForSearch(); + } + + /** + * Update the given entity. + */ + public function update(Entity $entity, array $input) + { + $entity->fill($input); + $entity->updated_by = user()->id; + + if ($entity->isDirty('name')) { + $entity->refreshSlug(); + } + + $entity->save(); + + if (isset($input['tags'])) { + $this->tagRepo->saveTagsToEntity($entity, $input['tags']); + } + + $entity->rebuildPermissions(); + $entity->indexForSearch(); + } + + /** + * Update the given items' cover image, or clear it. + * @throws ImageUploadException + * @throws \Exception + */ + public function updateCoverImage(HasCoverImage $entity, UploadedFile $coverImage = null, bool $removeImage = false) + { + if ($coverImage) { + $this->imageRepo->destroyImage($entity->cover); + $image = $this->imageRepo->saveNew($coverImage, 'cover_book', $entity->id, 512, 512, true); + $entity->cover()->associate($image); + $entity->save(); + } + + if ($removeImage) { + $this->imageRepo->destroyImage($entity->cover); + $entity->image_id = 0; + $entity->save(); + } + } + + /** + * Update the permissions of an entity. + */ + public function updatePermissions(Entity $entity, bool $restricted, Collection $permissions = null) + { + $entity->restricted = $restricted; + $entity->permissions()->delete(); + + if (!is_null($permissions)) { + $entityPermissionData = $permissions->flatMap(function ($restrictions, $roleId) { + return collect($restrictions)->keys()->map(function ($action) use ($roleId) { + return [ + 'role_id' => $roleId, + 'action' => strtolower($action), + ] ; + }); + }); + + $entity->permissions()->createMany($entityPermissionData); + } + + $entity->save(); + $entity->rebuildPermissions(); + } +} diff --git a/app/Entities/Repos/BookRepo.php b/app/Entities/Repos/BookRepo.php new file mode 100644 index 000000000..7fcc80fac --- /dev/null +++ b/app/Entities/Repos/BookRepo.php @@ -0,0 +1,134 @@ +baseRepo = $baseRepo; + $this->tagRepo = $tagRepo; + $this->imageRepo = $imageRepo; + } + + /** + * Get all books in a paginated format. + */ + public function getAllPaginated(int $count = 20, string $sort = 'name', string $order = 'asc'): LengthAwarePaginator + { + return Book::visible()->orderBy($sort, $order)->paginate($count); + } + + /** + * Get the books that were most recently viewed by this user. + */ + public function getRecentlyViewed(int $count = 20): Collection + { + return Book::visible()->withLastView() + ->having('last_viewed_at', '>', 0) + ->orderBy('last_viewed_at', 'desc') + ->take($count)->get(); + } + + /** + * Get the most popular books in the system. + */ + public function getPopular(int $count = 20): Collection + { + return Book::visible()->withViewCount() + ->having('view_count', '>', 0) + ->orderBy('view_count', 'desc') + ->take($count)->get(); + } + + /** + * Get the most recently created books from the system. + */ + public function getRecentlyCreated(int $count = 20): Collection + { + return Book::visible()->orderBy('created_at', 'desc') + ->take($count)->get(); + } + + /** + * Get a book by its slug. + */ + public function getBySlug(string $slug): Book + { + $book = Book::visible()->where('slug', '=', $slug)->first(); + + if ($book === null) { + throw new NotFoundException(trans('errors.book_not_found')); + } + + return $book; + } + + /** + * Create a new book in the system + */ + public function create(array $input): Book + { + $book = new Book(); + $this->baseRepo->create($book, $input); + return $book; + } + + /** + * Update the given book. + */ + public function update(Book $book, array $input): Book + { + $this->baseRepo->update($book, $input); + return $book; + } + + /** + * Update the given book's cover image, or clear it. + * @throws ImageUploadException + * @throws Exception + */ + public function updateCoverImage(Book $book, UploadedFile $coverImage = null, bool $removeImage = false) + { + $this->baseRepo->updateCoverImage($book, $coverImage, $removeImage); + } + + /** + * Update the permissions of a book. + */ + public function updatePermissions(Book $book, bool $restricted, Collection $permissions = null) + { + $this->baseRepo->updatePermissions($book, $restricted, $permissions); + } + + /** + * Remove a book from the system. + * @throws NotifyException + * @throws BindingResolutionException + */ + public function destroy(Book $book) + { + $trashCan = new TrashCan(); + $trashCan->destroyBook($book); + } +} diff --git a/app/Entities/Repos/BookshelfRepo.php b/app/Entities/Repos/BookshelfRepo.php new file mode 100644 index 000000000..03b54f009 --- /dev/null +++ b/app/Entities/Repos/BookshelfRepo.php @@ -0,0 +1,173 @@ +baseRepo = $baseRepo; + } + + /** + * Get all bookshelves in a paginated format. + */ + public function getAllPaginated(int $count = 20, string $sort = 'name', string $order = 'asc'): LengthAwarePaginator + { + return Bookshelf::visible()->with('visibleBooks') + ->orderBy($sort, $order)->paginate($count); + } + + /** + * Get the bookshelves that were most recently viewed by this user. + */ + public function getRecentlyViewed(int $count = 20): Collection + { + return Bookshelf::visible()->withLastView() + ->having('last_viewed_at', '>', 0) + ->orderBy('last_viewed_at', 'desc') + ->take($count)->get(); + } + + /** + * Get the most popular bookshelves in the system. + */ + public function getPopular(int $count = 20): Collection + { + return Bookshelf::visible()->withViewCount() + ->having('view_count', '>', 0) + ->orderBy('view_count', 'desc') + ->take($count)->get(); + } + + /** + * Get the most recently created bookshelves from the system. + */ + public function getRecentlyCreated(int $count = 20): Collection + { + return Bookshelf::visible()->orderBy('created_at', 'desc') + ->take($count)->get(); + } + + /** + * Get a shelf by its slug. + */ + public function getBySlug(string $slug): Bookshelf + { + $shelf = Bookshelf::visible()->where('slug', '=', $slug)->first(); + + if ($shelf === null) { + throw new NotFoundException(trans('errors.bookshelf_not_found')); + } + + return $shelf; + } + + /** + * Create a new shelf in the system. + */ + public function create(array $input, array $bookIds): Bookshelf + { + $shelf = new Bookshelf(); + $this->baseRepo->create($shelf, $input); + $this->updateBooks($shelf, $bookIds); + return $shelf; + } + + /** + * Create a new shelf in the system. + */ + public function update(Bookshelf $shelf, array $input, array $bookIds): Bookshelf + { + $this->baseRepo->update($shelf, $input); + $this->updateBooks($shelf, $bookIds); + return $shelf; + } + + /** + * Update which books are assigned to this shelf by + * syncing the given book ids. + * Function ensures the books are visible to the current user and existing. + */ + protected function updateBooks(Bookshelf $shelf, array $bookIds) + { + $numericIDs = collect($bookIds)->map(function ($id) { + return intval($id); + }); + + $syncData = Book::visible() + ->whereIn('id', $bookIds) + ->get(['id'])->pluck('id')->mapWithKeys(function ($bookId) use ($numericIDs) { + return [$bookId => ['order' => $numericIDs->search($bookId)]]; + }); + + $shelf->books()->sync($syncData); + } + + /** + * Update the given shelf cover image, or clear it. + * @throws ImageUploadException + * @throws Exception + */ + public function updateCoverImage(Bookshelf $shelf, UploadedFile $coverImage = null, bool $removeImage = false) + { + $this->baseRepo->updateCoverImage($shelf, $coverImage, $removeImage); + } + + /** + * Update the permissions of a bookshelf. + */ + public function updatePermissions(Bookshelf $shelf, bool $restricted, Collection $permissions = null) + { + $this->baseRepo->updatePermissions($shelf, $restricted, $permissions); + } + + /** + * Copy down the permissions of the given shelf to all child books. + */ + public function copyDownPermissions(Bookshelf $shelf, $checkUserPermissions = true): int + { + $shelfPermissions = $shelf->permissions()->get(['role_id', 'action'])->toArray(); + $shelfBooks = $shelf->books()->get(['id', 'restricted']); + $updatedBookCount = 0; + + /** @var Book $book */ + foreach ($shelfBooks as $book) { + if ($checkUserPermissions && !userCan('restrictions-manage', $book)) { + continue; + } + $book->permissions()->delete(); + $book->restricted = $shelf->restricted; + $book->permissions()->createMany($shelfPermissions); + $book->save(); + $book->rebuildPermissions(); + $updatedBookCount++; + } + + return $updatedBookCount; + } + + /** + * Remove a bookshelf from the system. + * @throws Exception + */ + public function destroy(Bookshelf $shelf) + { + $trashCan = new TrashCan(); + $trashCan->destroyShelf($shelf); + } +} diff --git a/app/Entities/Repos/ChapterRepo.php b/app/Entities/Repos/ChapterRepo.php new file mode 100644 index 000000000..c6f3a2d2f --- /dev/null +++ b/app/Entities/Repos/ChapterRepo.php @@ -0,0 +1,108 @@ +baseRepo = $baseRepo; + } + + /** + * Get a chapter via the slug. + * @throws NotFoundException + */ + public function getBySlug(string $bookSlug, string $chapterSlug): Chapter + { + $chapter = Chapter::visible()->whereSlugs($bookSlug, $chapterSlug)->first(); + + if ($chapter === null) { + throw new NotFoundException(trans('errors.chapter_not_found')); + } + + return $chapter; + } + + /** + * Create a new chapter in the system. + */ + public function create(array $input, Book $parentBook): Chapter + { + $chapter = new Chapter(); + $chapter->book_id = $parentBook->id; + $chapter->priority = (new BookContents($parentBook))->getLastPriority() + 1; + $this->baseRepo->create($chapter, $input); + return $chapter; + } + + /** + * Update the given chapter. + */ + public function update(Chapter $chapter, array $input): Chapter + { + $this->baseRepo->update($chapter, $input); + return $chapter; + } + + /** + * Update the permissions of a chapter. + */ + public function updatePermissions(Chapter $chapter, bool $restricted, Collection $permissions = null) + { + $this->baseRepo->updatePermissions($chapter, $restricted, $permissions); + } + + /** + * Remove a chapter from the system. + * @throws Exception + */ + public function destroy(Chapter $chapter) + { + $trashCan = new TrashCan(); + $trashCan->destroyChapter($chapter); + } + + /** + * Move the given chapter into a new parent book. + * The $parentIdentifier must be a string of the following format: + * 'book:' (book:5) + * @throws MoveOperationException + */ + public function move(Chapter $chapter, string $parentIdentifier): Book + { + $stringExploded = explode(':', $parentIdentifier); + $entityType = $stringExploded[0]; + $entityId = intval($stringExploded[1]); + + if ($entityType !== 'book') { + throw new MoveOperationException('Chapters can only be moved into books'); + } + + $parent = Book::visible()->where('id', '=', $entityId)->first(); + if ($parent === null) { + throw new MoveOperationException('Book to move chapter into not found'); + } + + $chapter->changeBook($parent->id); + $chapter->rebuildPermissions(); + return $parent; + } +} diff --git a/app/Entities/Repos/EntityRepo.php b/app/Entities/Repos/EntityRepo.php deleted file mode 100644 index 996873bcc..000000000 --- a/app/Entities/Repos/EntityRepo.php +++ /dev/null @@ -1,924 +0,0 @@ -entityProvider = $entityProvider; - $this->viewService = $viewService; - $this->permissionService = $permissionService; - $this->tagRepo = $tagRepo; - $this->searchService = $searchService; - } - - /** - * Base query for searching entities via permission system - * @param string $type - * @param bool $allowDrafts - * @param string $permission - * @return \Illuminate\Database\Query\Builder - */ - protected function entityQuery($type, $allowDrafts = false, $permission = 'view') - { - $q = $this->permissionService->enforceEntityRestrictions($type, $this->entityProvider->get($type), $permission); - if (strtolower($type) === 'page' && !$allowDrafts) { - $q = $q->where('draft', '=', false); - } - return $q; - } - - /** - * Check if an entity with the given id exists. - * @param $type - * @param $id - * @return bool - */ - public function exists($type, $id) - { - return $this->entityQuery($type)->where('id', '=', $id)->exists(); - } - - /** - * Get an entity by ID - * @param string $type - * @param integer $id - * @param bool $allowDrafts - * @param bool $ignorePermissions - * @return Entity - */ - public function getById($type, $id, $allowDrafts = false, $ignorePermissions = false) - { - $query = $this->entityQuery($type, $allowDrafts); - - if ($ignorePermissions) { - $query = $this->entityProvider->get($type)->newQuery(); - } - - return $query->find($id); - } - - /** - * @param string $type - * @param []int $ids - * @param bool $allowDrafts - * @param bool $ignorePermissions - * @return Builder[]|\Illuminate\Database\Eloquent\Collection|Collection - */ - public function getManyById($type, $ids, $allowDrafts = false, $ignorePermissions = false) - { - $query = $this->entityQuery($type, $allowDrafts); - - if ($ignorePermissions) { - $query = $this->entityProvider->get($type)->newQuery(); - } - - return $query->whereIn('id', $ids)->get(); - } - - /** - * Get an entity by its url slug. - * @param string $type - * @param string $slug - * @param string|bool $bookSlug - * @return Entity - * @throws NotFoundException - */ - public function getBySlug($type, $slug, $bookSlug = false) - { - $q = $this->entityQuery($type)->where('slug', '=', $slug); - - if (strtolower($type) === 'chapter' || strtolower($type) === 'page') { - $q = $q->where('book_id', '=', function ($query) use ($bookSlug) { - $query->select('id') - ->from($this->entityProvider->book->getTable()) - ->where('slug', '=', $bookSlug)->limit(1); - }); - } - $entity = $q->first(); - if ($entity === null) { - throw new NotFoundException(trans('errors.' . strtolower($type) . '_not_found')); - } - return $entity; - } - - - /** - * Get all entities of a type with the given permission, limited by count unless count is false. - * @param string $type - * @param integer|bool $count - * @param string $permission - * @return Collection - */ - public function getAll($type, $count = 20, $permission = 'view') - { - $q = $this->entityQuery($type, false, $permission)->orderBy('name', 'asc'); - if ($count !== false) { - $q = $q->take($count); - } - return $q->get(); - } - - /** - * Get all entities in a paginated format - * @param $type - * @param int $count - * @param string $sort - * @param string $order - * @param null|callable $queryAddition - * @return LengthAwarePaginator - */ - public function getAllPaginated($type, int $count = 10, string $sort = 'name', string $order = 'asc', $queryAddition = null) - { - $query = $this->entityQuery($type); - $query = $this->addSortToQuery($query, $sort, $order); - if ($queryAddition) { - $queryAddition($query); - } - return $query->paginate($count); - } - - /** - * Add sorting operations to an entity query. - * @param Builder $query - * @param string $sort - * @param string $order - * @return Builder - */ - protected function addSortToQuery(Builder $query, string $sort = 'name', string $order = 'asc') - { - $order = ($order === 'asc') ? 'asc' : 'desc'; - $propertySorts = ['name', 'created_at', 'updated_at']; - - if (in_array($sort, $propertySorts)) { - return $query->orderBy($sort, $order); - } - - return $query; - } - - /** - * Get the most recently created entities of the given type. - * @param string $type - * @param int $count - * @param int $page - * @param bool|callable $additionalQuery - * @return Collection - */ - public function getRecentlyCreated($type, $count = 20, $page = 0, $additionalQuery = false) - { - $query = $this->permissionService->enforceEntityRestrictions($type, $this->entityProvider->get($type)) - ->orderBy('created_at', 'desc'); - if (strtolower($type) === 'page') { - $query = $query->where('draft', '=', false); - } - if ($additionalQuery !== false && is_callable($additionalQuery)) { - $additionalQuery($query); - } - return $query->skip($page * $count)->take($count)->get(); - } - - /** - * Get the most recently updated entities of the given type. - * @param string $type - * @param int $count - * @param int $page - * @param bool|callable $additionalQuery - * @return Collection - */ - public function getRecentlyUpdated($type, $count = 20, $page = 0, $additionalQuery = false) - { - $query = $this->permissionService->enforceEntityRestrictions($type, $this->entityProvider->get($type)) - ->orderBy('updated_at', 'desc'); - if (strtolower($type) === 'page') { - $query = $query->where('draft', '=', false); - } - if ($additionalQuery !== false && is_callable($additionalQuery)) { - $additionalQuery($query); - } - return $query->skip($page * $count)->take($count)->get(); - } - - /** - * Get the most recently viewed entities. - * @param string|bool $type - * @param int $count - * @param int $page - * @return mixed - */ - public function getRecentlyViewed($type, $count = 10, $page = 0) - { - $filter = is_bool($type) ? false : $this->entityProvider->get($type); - return $this->viewService->getUserRecentlyViewed($count, $page, $filter); - } - - /** - * Get the latest pages added to the system with pagination. - * @param string $type - * @param int $count - * @return mixed - */ - public function getRecentlyCreatedPaginated($type, $count = 20) - { - return $this->entityQuery($type)->orderBy('created_at', 'desc')->paginate($count); - } - - /** - * Get the latest pages added to the system with pagination. - * @param string $type - * @param int $count - * @return mixed - */ - public function getRecentlyUpdatedPaginated($type, $count = 20) - { - return $this->entityQuery($type)->orderBy('updated_at', 'desc')->paginate($count); - } - - /** - * Get the most popular entities base on all views. - * @param string $type - * @param int $count - * @param int $page - * @return mixed - */ - public function getPopular(string $type, int $count = 10, int $page = 0) - { - return $this->viewService->getPopular($count, $page, $type); - } - - /** - * Get draft pages owned by the current user. - * @param int $count - * @param int $page - * @return Collection - */ - public function getUserDraftPages($count = 20, $page = 0) - { - return $this->entityProvider->page->where('draft', '=', true) - ->where('created_by', '=', user()->id) - ->orderBy('updated_at', 'desc') - ->skip($count * $page)->take($count)->get(); - } - - /** - * Get the number of entities the given user has created. - * @param string $type - * @param User $user - * @return int - */ - public function getUserTotalCreated(string $type, User $user) - { - return $this->entityProvider->get($type) - ->where('created_by', '=', $user->id)->count(); - } - - /** - * Get the child items for a chapter sorted by priority but - * with draft items floated to the top. - * @param Bookshelf $bookshelf - * @return \Illuminate\Database\Eloquent\Collection|static[] - */ - public function getBookshelfChildren(Bookshelf $bookshelf) - { - return $this->permissionService->enforceEntityRestrictions('book', $bookshelf->books())->get(); - } - - /** - * Get the direct children of a book. - * @param Book $book - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getBookDirectChildren(Book $book) - { - $pages = $this->permissionService->enforceEntityRestrictions('page', $book->directPages())->get(); - $chapters = $this->permissionService->enforceEntityRestrictions('chapters', $book->chapters())->get(); - return collect()->concat($pages)->concat($chapters)->sortBy('priority')->sortByDesc('draft'); - } - - /** - * Get all child objects of a book. - * Returns a sorted collection of Pages and Chapters. - * Loads the book slug onto child elements to prevent access database access for getting the slug. - * @param Book $book - * @param bool $filterDrafts - * @param bool $renderPages - * @return mixed - */ - public function getBookChildren(Book $book, $filterDrafts = false, $renderPages = false) - { - $q = $this->permissionService->bookChildrenQuery($book->id, $filterDrafts, $renderPages)->get(); - $entities = []; - $parents = []; - $tree = []; - - foreach ($q as $index => $rawEntity) { - if ($rawEntity->entity_type === $this->entityProvider->page->getMorphClass()) { - $entities[$index] = $this->entityProvider->page->newFromBuilder($rawEntity); - if ($renderPages) { - $entities[$index]->html = $rawEntity->html; - $entities[$index]->html = $this->renderPage($entities[$index]); - }; - } else if ($rawEntity->entity_type === $this->entityProvider->chapter->getMorphClass()) { - $entities[$index] = $this->entityProvider->chapter->newFromBuilder($rawEntity); - $key = $entities[$index]->entity_type . ':' . $entities[$index]->id; - $parents[$key] = $entities[$index]; - $parents[$key]->setAttribute('pages', collect()); - } - if ($entities[$index]->chapter_id === 0 || $entities[$index]->chapter_id === '0') { - $tree[] = $entities[$index]; - } - $entities[$index]->book = $book; - } - - foreach ($entities as $entity) { - if ($entity->chapter_id === 0 || $entity->chapter_id === '0') { - continue; - } - $parentKey = $this->entityProvider->chapter->getMorphClass() . ':' . $entity->chapter_id; - if (!isset($parents[$parentKey])) { - $tree[] = $entity; - continue; - } - $chapter = $parents[$parentKey]; - $chapter->pages->push($entity); - } - - return collect($tree); - } - - /** - * Get the child items for a chapter sorted by priority but - * with draft items floated to the top. - * @param Chapter $chapter - * @return \Illuminate\Database\Eloquent\Collection|static[] - */ - public function getChapterChildren(Chapter $chapter) - { - return $this->permissionService->enforceEntityRestrictions('page', $chapter->pages()) - ->orderBy('draft', 'DESC')->orderBy('priority', 'ASC')->get(); - } - - - /** - * Get the next sequential priority for a new child element in the given book. - * @param Book $book - * @return int - */ - public function getNewBookPriority(Book $book) - { - $lastElem = $this->getBookChildren($book)->pop(); - return $lastElem ? $lastElem->priority + 1 : 0; - } - - /** - * Get a new priority for a new page to be added to the given chapter. - * @param Chapter $chapter - * @return int - */ - public function getNewChapterPriority(Chapter $chapter) - { - $lastPage = $chapter->pages('DESC')->first(); - return $lastPage !== null ? $lastPage->priority + 1 : 0; - } - - /** - * Find a suitable slug for an entity. - * @param string $type - * @param string $name - * @param bool|integer $currentId - * @param bool|integer $bookId Only pass if type is not a book - * @return string - */ - public function findSuitableSlug($type, $name, $currentId = false, $bookId = false) - { - $slug = $this->nameToSlug($name); - while ($this->slugExists($type, $slug, $currentId, $bookId)) { - $slug .= '-' . substr(md5(rand(1, 500)), 0, 3); - } - return $slug; - } - - /** - * Check if a slug already exists in the database. - * @param string $type - * @param string $slug - * @param bool|integer $currentId - * @param bool|integer $bookId - * @return bool - */ - protected function slugExists($type, $slug, $currentId = false, $bookId = false) - { - $query = $this->entityProvider->get($type)->where('slug', '=', $slug); - if (strtolower($type) === 'page' || strtolower($type) === 'chapter') { - $query = $query->where('book_id', '=', $bookId); - } - if ($currentId) { - $query = $query->where('id', '!=', $currentId); - } - return $query->count() > 0; - } - - /** - * Updates entity restrictions from a request - * @param Request $request - * @param Entity $entity - * @throws Throwable - */ - public function updateEntityPermissionsFromRequest(Request $request, Entity $entity) - { - $entity->restricted = $request->get('restricted', '') === 'true'; - $entity->permissions()->delete(); - - if ($request->filled('restrictions')) { - foreach ($request->get('restrictions') as $roleId => $restrictions) { - foreach ($restrictions as $action => $value) { - $entity->permissions()->create([ - 'role_id' => $roleId, - 'action' => strtolower($action) - ]); - } - } - } - - $entity->save(); - $this->permissionService->buildJointPermissionsForEntity($entity); - } - - - - /** - * Create a new entity from request input. - * Used for books and chapters. - * @param string $type - * @param array $input - * @param bool|Book $book - * @return Entity - */ - public function createFromInput($type, $input = [], $book = false) - { - $isChapter = strtolower($type) === 'chapter'; - $entityModel = $this->entityProvider->get($type)->newInstance($input); - $entityModel->slug = $this->findSuitableSlug($type, $entityModel->name, false, $isChapter ? $book->id : false); - $entityModel->created_by = user()->id; - $entityModel->updated_by = user()->id; - $isChapter ? $book->chapters()->save($entityModel) : $entityModel->save(); - - if (isset($input['tags'])) { - $this->tagRepo->saveTagsToEntity($entityModel, $input['tags']); - } - - $this->permissionService->buildJointPermissionsForEntity($entityModel); - $this->searchService->indexEntity($entityModel); - return $entityModel; - } - - /** - * Update entity details from request input. - * Used for books and chapters - * @param string $type - * @param Entity $entityModel - * @param array $input - * @return Entity - */ - public function updateFromInput($type, Entity $entityModel, $input = []) - { - if ($entityModel->name !== $input['name']) { - $entityModel->slug = $this->findSuitableSlug($type, $input['name'], $entityModel->id); - } - $entityModel->fill($input); - $entityModel->updated_by = user()->id; - $entityModel->save(); - - if (isset($input['tags'])) { - $this->tagRepo->saveTagsToEntity($entityModel, $input['tags']); - } - - $this->permissionService->buildJointPermissionsForEntity($entityModel); - $this->searchService->indexEntity($entityModel); - return $entityModel; - } - - /** - * Sync the books assigned to a shelf from a comma-separated list - * of book IDs. - * @param Bookshelf $shelf - * @param string $books - */ - public function updateShelfBooks(Bookshelf $shelf, string $books) - { - $ids = explode(',', $books); - - // Check books exist and match ordering - $bookIds = $this->entityQuery('book')->whereIn('id', $ids)->get(['id'])->pluck('id'); - $syncData = []; - foreach ($ids as $index => $id) { - if ($bookIds->contains($id)) { - $syncData[$id] = ['order' => $index]; - } - } - - $shelf->books()->sync($syncData); - } - - /** - * Append a Book to a BookShelf. - * @param Bookshelf $shelf - * @param Book $book - */ - public function appendBookToShelf(Bookshelf $shelf, Book $book) - { - if ($shelf->contains($book)) { - return; - } - - $maxOrder = $shelf->books()->max('order'); - $shelf->books()->attach($book->id, ['order' => $maxOrder + 1]); - } - - /** - * Change the book that an entity belongs to. - * @param string $type - * @param integer $newBookId - * @param Entity $entity - * @param bool $rebuildPermissions - * @return Entity - */ - public function changeBook($type, $newBookId, Entity $entity, $rebuildPermissions = false) - { - $entity->book_id = $newBookId; - // Update related activity - foreach ($entity->activity as $activity) { - $activity->book_id = $newBookId; - $activity->save(); - } - $entity->slug = $this->findSuitableSlug($type, $entity->name, $entity->id, $newBookId); - $entity->save(); - - // Update all child pages if a chapter - if (strtolower($type) === 'chapter') { - foreach ($entity->pages as $page) { - $this->changeBook('page', $newBookId, $page, false); - } - } - - // Update permissions if applicable - if ($rebuildPermissions) { - $entity->load('book'); - $this->permissionService->buildJointPermissionsForEntity($entity->book); - } - - return $entity; - } - - /** - * Alias method to update the book jointPermissions in the PermissionService. - * @param Book $book - */ - public function buildJointPermissionsForBook(Book $book) - { - $this->permissionService->buildJointPermissionsForEntity($book); - } - - /** - * Format a name as a url slug. - * @param $name - * @return string - */ - protected function nameToSlug($name) - { - $slug = preg_replace('/[\+\/\\\?\@\}\{\.\,\=\[\]\#\&\!\*\'\;\:\$\%]/', '', mb_strtolower($name)); - $slug = preg_replace('/\s{2,}/', ' ', $slug); - $slug = str_replace(' ', '-', $slug); - if ($slug === "") { - $slug = substr(md5(rand(1, 500)), 0, 5); - } - return $slug; - } - - /** - * Render the page for viewing - * @param Page $page - * @param bool $blankIncludes - * @return string - */ - public function renderPage(Page $page, bool $blankIncludes = false) : string - { - $content = $page->html; - - if (!config('app.allow_content_scripts')) { - $content = $this->escapeScripts($content); - } - - if ($blankIncludes) { - $content = $this->blankPageIncludes($content); - } else { - $content = $this->parsePageIncludes($content); - } - - return $content; - } - - /** - * Remove any page include tags within the given HTML. - * @param string $html - * @return string - */ - protected function blankPageIncludes(string $html) : string - { - return preg_replace("/{{@\s?([0-9].*?)}}/", '', $html); - } - - /** - * Parse any include tags "{{@#section}}" to be part of the page. - * @param string $html - * @return mixed|string - */ - protected function parsePageIncludes(string $html) : string - { - $matches = []; - preg_match_all("/{{@\s?([0-9].*?)}}/", $html, $matches); - - $topLevelTags = ['table', 'ul', 'ol']; - foreach ($matches[1] as $index => $includeId) { - $splitInclude = explode('#', $includeId, 2); - $pageId = intval($splitInclude[0]); - if (is_nan($pageId)) { - continue; - } - - $matchedPage = $this->getById('page', $pageId); - if ($matchedPage === null) { - $html = str_replace($matches[0][$index], '', $html); - continue; - } - - if (count($splitInclude) === 1) { - $html = str_replace($matches[0][$index], $matchedPage->html, $html); - continue; - } - - $doc = new DOMDocument(); - libxml_use_internal_errors(true); - $doc->loadHTML(mb_convert_encoding(''.$matchedPage->html.'', 'HTML-ENTITIES', 'UTF-8')); - $matchingElem = $doc->getElementById($splitInclude[1]); - if ($matchingElem === null) { - $html = str_replace($matches[0][$index], '', $html); - continue; - } - $innerContent = ''; - $isTopLevel = in_array(strtolower($matchingElem->nodeName), $topLevelTags); - if ($isTopLevel) { - $innerContent .= $doc->saveHTML($matchingElem); - } else { - foreach ($matchingElem->childNodes as $childNode) { - $innerContent .= $doc->saveHTML($childNode); - } - } - libxml_clear_errors(); - $html = str_replace($matches[0][$index], trim($innerContent), $html); - } - - return $html; - } - - /** - * Escape script tags within HTML content. - * @param string $html - * @return string - */ - protected function escapeScripts(string $html) : string - { - if ($html == '') { - return $html; - } - - libxml_use_internal_errors(true); - $doc = new DOMDocument(); - $doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8')); - $xPath = new DOMXPath($doc); - - // Remove standard script tags - $scriptElems = $xPath->query('//script'); - foreach ($scriptElems as $scriptElem) { - $scriptElem->parentNode->removeChild($scriptElem); - } - - // Remove data or JavaScript iFrames - $badIframes = $xPath->query('//*[contains(@src, \'data:\')] | //*[contains(@src, \'javascript:\')] | //*[@srcdoc]'); - foreach ($badIframes as $badIframe) { - $badIframe->parentNode->removeChild($badIframe); - } - - // Remove 'on*' attributes - $onAttributes = $xPath->query('//@*[starts-with(name(), \'on\')]'); - foreach ($onAttributes as $attr) { - /** @var \DOMAttr $attr*/ - $attrName = $attr->nodeName; - $attr->parentNode->removeAttribute($attrName); - } - - $html = ''; - $topElems = $doc->documentElement->childNodes->item(0)->childNodes; - foreach ($topElems as $child) { - $html .= $doc->saveHTML($child); - } - - return $html; - } - - /** - * Search for image usage within page content. - * @param $imageString - * @return mixed - */ - public function searchForImage($imageString) - { - $pages = $this->entityQuery('page')->where('html', 'like', '%' . $imageString . '%')->get(['id', 'name', 'slug', 'book_id']); - foreach ($pages as $page) { - $page->url = $page->getUrl(); - $page->html = ''; - $page->text = ''; - } - return count($pages) > 0 ? $pages : false; - } - - /** - * Destroy a bookshelf instance - * @param Bookshelf $shelf - * @throws Throwable - */ - public function destroyBookshelf(Bookshelf $shelf) - { - $this->destroyEntityCommonRelations($shelf); - $shelf->delete(); - } - - /** - * Destroy the provided book and all its child entities. - * @param Book $book - * @throws NotifyException - * @throws Throwable - */ - public function destroyBook(Book $book) - { - foreach ($book->pages as $page) { - $this->destroyPage($page); - } - foreach ($book->chapters as $chapter) { - $this->destroyChapter($chapter); - } - $this->destroyEntityCommonRelations($book); - $book->delete(); - } - - /** - * Destroy a chapter and its relations. - * @param Chapter $chapter - * @throws Throwable - */ - public function destroyChapter(Chapter $chapter) - { - if (count($chapter->pages) > 0) { - foreach ($chapter->pages as $page) { - $page->chapter_id = 0; - $page->save(); - } - } - $this->destroyEntityCommonRelations($chapter); - $chapter->delete(); - } - - /** - * Destroy a given page along with its dependencies. - * @param Page $page - * @throws NotifyException - * @throws Throwable - */ - public function destroyPage(Page $page) - { - // Check if set as custom homepage & remove setting if not used or throw error if active - $customHome = setting('app-homepage', '0:'); - if (intval($page->id) === intval(explode(':', $customHome)[0])) { - if (setting('app-homepage-type') === 'page') { - throw new NotifyException(trans('errors.page_custom_home_deletion'), $page->getUrl()); - } - setting()->remove('app-homepage'); - } - - $this->destroyEntityCommonRelations($page); - - // Delete Attached Files - $attachmentService = app(AttachmentService::class); - foreach ($page->attachments as $attachment) { - $attachmentService->deleteFile($attachment); - } - - $page->delete(); - } - - /** - * Destroy or handle the common relations connected to an entity. - * @param Entity $entity - * @throws Throwable - */ - protected function destroyEntityCommonRelations(Entity $entity) - { - Activity::removeEntity($entity); - $entity->views()->delete(); - $entity->permissions()->delete(); - $entity->tags()->delete(); - $entity->comments()->delete(); - $this->permissionService->deleteJointPermissionsForEntity($entity); - $this->searchService->deleteEntityTerms($entity); - } - - /** - * Copy the permissions of a bookshelf to all child books. - * Returns the number of books that had permissions updated. - * @param Bookshelf $bookshelf - * @return int - * @throws Throwable - */ - public function copyBookshelfPermissions(Bookshelf $bookshelf) - { - $shelfPermissions = $bookshelf->permissions()->get(['role_id', 'action'])->toArray(); - $shelfBooks = $bookshelf->books()->get(); - $updatedBookCount = 0; - - foreach ($shelfBooks as $book) { - if (!userCan('restrictions-manage', $book)) { - continue; - } - $book->permissions()->delete(); - $book->restricted = $bookshelf->restricted; - $book->permissions()->createMany($shelfPermissions); - $book->save(); - $this->permissionService->buildJointPermissionsForEntity($book); - $updatedBookCount++; - } - - return $updatedBookCount; - } -} diff --git a/app/Entities/Repos/PageRepo.php b/app/Entities/Repos/PageRepo.php index ed142eb61..e49eeb1ef 100644 --- a/app/Entities/Repos/PageRepo.php +++ b/app/Entities/Repos/PageRepo.php @@ -3,91 +3,199 @@ use BookStack\Entities\Book; use BookStack\Entities\Chapter; use BookStack\Entities\Entity; +use BookStack\Entities\Managers\BookContents; +use BookStack\Entities\Managers\PageContent; +use BookStack\Entities\Managers\TrashCan; use BookStack\Entities\Page; use BookStack\Entities\PageRevision; -use Carbon\Carbon; -use DOMDocument; -use DOMElement; -use DOMXPath; +use BookStack\Exceptions\MoveOperationException; +use BookStack\Exceptions\NotFoundException; +use BookStack\Exceptions\NotifyException; +use BookStack\Exceptions\PermissionsException; +use Illuminate\Database\Eloquent\Builder; +use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Support\Collection; -class PageRepo extends EntityRepo +class PageRepo { + protected $baseRepo; + /** - * Get page by slug. - * @param string $pageSlug - * @param string $bookSlug - * @return Page - * @throws \BookStack\Exceptions\NotFoundException + * PageRepo constructor. */ - public function getPageBySlug(string $pageSlug, string $bookSlug) + public function __construct(BaseRepo $baseRepo) { - return $this->getBySlug('page', $pageSlug, $bookSlug); + $this->baseRepo = $baseRepo; } /** - * Search through page revisions and retrieve the last page in the - * current book that has a slug equal to the one given. - * @param string $pageSlug - * @param string $bookSlug - * @return null|Page + * Get a page by ID. + * @throws NotFoundException */ - public function getPageByOldSlug(string $pageSlug, string $bookSlug) + public function getById(int $id): Page { - $revision = $this->entityProvider->pageRevision->where('slug', '=', $pageSlug) - ->whereHas('page', function ($query) { - $this->permissionService->enforceEntityRestrictions('page', $query); + $page = Page::visible()->with(['book'])->find($id); + + if (!$page) { + throw new NotFoundException(trans('errors.page_not_found')); + } + + return $page; + } + + /** + * Get a page its book and own slug. + * @throws NotFoundException + */ + public function getBySlug(string $bookSlug, string $pageSlug): Page + { + $page = Page::visible()->whereSlugs($bookSlug, $pageSlug)->first(); + + if (!$page) { + throw new NotFoundException(trans('errors.page_not_found')); + } + + return $page; + } + + /** + * Get a page by its old slug but checking the revisions table + * for the last revision that matched the given page and book slug. + */ + public function getByOldSlug(string $bookSlug, string $pageSlug): ?Page + { + $revision = PageRevision::query() + ->whereHas('page', function (Builder $query) { + $query->visible(); }) + ->where('slug', '=', $pageSlug) ->where('type', '=', 'version') ->where('book_slug', '=', $bookSlug) ->orderBy('created_at', 'desc') - ->with('page')->first(); - return $revision !== null ? $revision->page : null; + ->with('page') + ->first(); + return $revision ? $revision->page : null; } /** - * Updates a page with any fillable data and saves it into the database. - * @param Page $page - * @param int $book_id - * @param array $input - * @return Page - * @throws \Exception + * Get pages that have been marked as a template. */ - public function updatePage(Page $page, int $book_id, array $input) + public function getTemplates(int $count = 10, int $page = 1, string $search = ''): LengthAwarePaginator + { + $query = Page::visible() + ->where('template', '=', true) + ->orderBy('name', 'asc') + ->skip(($page - 1) * $count) + ->take($count); + + if ($search) { + $query->where('name', 'like', '%' . $search . '%'); + } + + $paginator = $query->paginate($count, ['*'], 'page', $page); + $paginator->withPath('/templates'); + + return $paginator; + } + + /** + * Get a parent item via slugs. + */ + public function getParentFromSlugs(string $bookSlug, string $chapterSlug = null): Entity + { + if ($chapterSlug !== null) { + return $chapter = Chapter::visible()->whereSlugs($bookSlug, $chapterSlug)->firstOrFail(); + } + + return Book::visible()->where('slug', '=', $bookSlug)->firstOrFail(); + } + + /** + * Get the draft copy of the given page for the current user. + */ + public function getUserDraft(Page $page): ?PageRevision + { + $revision = $this->getUserDraftQuery($page)->first(); + return $revision; + } + + /** + * Get a new draft page belonging to the given parent entity. + */ + public function getNewDraftPage(Entity $parent) + { + $page = (new Page())->forceFill([ + 'name' => trans('entities.pages_initial_name'), + 'created_by' => user()->id, + 'updated_by' => user()->id, + 'draft' => true, + ]); + + if ($parent instanceof Chapter) { + $page->chapter_id = $parent->id; + $page->book_id = $parent->book_id; + } else { + $page->book_id = $parent->id; + } + + $page->save(); + $page->refresh()->rebuildPermissions(); + return $page; + } + + /** + * Publish a draft page to make it a live, non-draft page. + */ + public function publishDraft(Page $draft, array $input): Page + { + $this->baseRepo->update($draft, $input); + if (isset($input['template']) && userCan('templates-manage')) { + $draft->template = ($input['template'] === 'true'); + } + + $pageContent = new PageContent($draft); + $pageContent->setNewHTML($input['html']); + $draft->draft = false; + $draft->revision_count = 1; + $draft->priority = $this->getNewPriority($draft); + $draft->refreshSlug(); + $draft->save(); + + $this->savePageRevision($draft, trans('entities.pages_initial_revision')); + $draft->indexForSearch(); + return $draft->refresh(); + } + + /** + * Update a page in the system. + */ + public function update(Page $page, array $input): Page { // Hold the old details to compare later $oldHtml = $page->html; $oldName = $page->name; - // Prevent slug being updated if no name change - if ($page->name !== $input['name']) { - $page->slug = $this->findSuitableSlug('page', $input['name'], $page->id, $book_id); - } - - // Save page tags if present - if (isset($input['tags'])) { - $this->tagRepo->saveTagsToEntity($page, $input['tags']); - } - if (isset($input['template']) && userCan('templates-manage')) { $page->template = ($input['template'] === 'true'); } + $this->baseRepo->update($page, $input); + // Update with new details - $userId = user()->id; $page->fill($input); - $page->html = $this->formatHtml($input['html']); - $page->text = $this->pageToPlainText($page); + $pageContent = new PageContent($page); + $pageContent->setNewHTML($input['html']); + $page->revision_count++; + if (setting('app-editor') !== 'markdown') { $page->markdown = ''; } - $page->updated_by = $userId; - $page->revision_count++; + $page->save(); // Remove all update drafts for this user & page. - $this->userUpdatePageDraftsQuery($page, $userId)->delete(); + $this->getUserDraftQuery($page)->delete(); // Save a revision after updating $summary = $input['summary'] ?? null; @@ -95,24 +203,20 @@ class PageRepo extends EntityRepo $this->savePageRevision($page, $summary); } - $this->searchService->indexEntity($page); - return $page; } /** * Saves a page revision into the system. - * @param Page $page - * @param null|string $summary - * @return PageRevision - * @throws \Exception */ - public function savePageRevision(Page $page, string $summary = null) + protected function savePageRevision(Page $page, string $summary = null) { - $revision = $this->entityProvider->pageRevision->newInstance($page->toArray()); + $revision = new PageRevision($page->toArray()); + if (setting('app-editor') !== 'markdown') { $revision->markdown = ''; } + $revision->page_id = $page->id; $revision->slug = $page->slug; $revision->book_slug = $page->book->slug; @@ -123,164 +227,29 @@ class PageRepo extends EntityRepo $revision->revision_number = $page->revision_count; $revision->save(); - $revisionLimit = config('app.revision_limit'); - if ($revisionLimit !== false) { - $revisionsToDelete = $this->entityProvider->pageRevision->where('page_id', '=', $page->id) - ->orderBy('created_at', 'desc')->skip(intval($revisionLimit))->take(10)->get(['id']); - if ($revisionsToDelete->count() > 0) { - $this->entityProvider->pageRevision->whereIn('id', $revisionsToDelete->pluck('id'))->delete(); - } - } - + $this->deleteOldRevisions($page); return $revision; } - /** - * Formats a page's html to be tagged correctly within the system. - * @param string $htmlText - * @return string - */ - protected function formatHtml(string $htmlText) - { - if ($htmlText == '') { - return $htmlText; - } - - libxml_use_internal_errors(true); - $doc = new DOMDocument(); - $doc->loadHTML(mb_convert_encoding($htmlText, 'HTML-ENTITIES', 'UTF-8')); - - $container = $doc->documentElement; - $body = $container->childNodes->item(0); - $childNodes = $body->childNodes; - - // Set ids on top-level nodes - $idMap = []; - foreach ($childNodes as $index => $childNode) { - $this->setUniqueId($childNode, $idMap); - } - - // Ensure no duplicate ids within child items - $xPath = new DOMXPath($doc); - $idElems = $xPath->query('//body//*//*[@id]'); - foreach ($idElems as $domElem) { - $this->setUniqueId($domElem, $idMap); - } - - // Generate inner html as a string - $html = ''; - foreach ($childNodes as $childNode) { - $html .= $doc->saveHTML($childNode); - } - - return $html; - } - - /** - * Set a unique id on the given DOMElement. - * A map for existing ID's should be passed in to check for current existence. - * @param DOMElement $element - * @param array $idMap - */ - protected function setUniqueId($element, array &$idMap) - { - if (get_class($element) !== 'DOMElement') { - return; - } - - // Overwrite id if not a BookStack custom id - $existingId = $element->getAttribute('id'); - if (strpos($existingId, 'bkmrk') === 0 && !isset($idMap[$existingId])) { - $idMap[$existingId] = true; - return; - } - - // Create an unique id for the element - // Uses the content as a basis to ensure output is the same every time - // the same content is passed through. - $contentId = 'bkmrk-' . mb_substr(strtolower(preg_replace('/\s+/', '-', trim($element->nodeValue))), 0, 20); - $newId = urlencode($contentId); - $loopIndex = 0; - - while (isset($idMap[$newId])) { - $newId = urlencode($contentId . '-' . $loopIndex); - $loopIndex++; - } - - $element->setAttribute('id', $newId); - $idMap[$newId] = true; - } - - /** - * Get the plain text version of a page's content. - * @param \BookStack\Entities\Page $page - * @return string - */ - protected function pageToPlainText(Page $page) : string - { - $html = $this->renderPage($page, true); - return strip_tags($html); - } - - /** - * Get a new draft page instance. - * @param Book $book - * @param Chapter|null $chapter - * @return \BookStack\Entities\Page - * @throws \Throwable - */ - public function getDraftPage(Book $book, Chapter $chapter = null) - { - $page = $this->entityProvider->page->newInstance(); - $page->name = trans('entities.pages_initial_name'); - $page->created_by = user()->id; - $page->updated_by = user()->id; - $page->draft = true; - - if ($chapter) { - $page->chapter_id = $chapter->id; - } - - $book->pages()->save($page); - $page = $this->entityProvider->page->find($page->id); - $this->permissionService->buildJointPermissionsForEntity($page); - return $page; - } - /** * Save a page update draft. - * @param Page $page - * @param array $data - * @return PageRevision|Page */ - public function updatePageDraft(Page $page, array $data = []) + public function updatePageDraft(Page $page, array $input) { // If the page itself is a draft simply update that if ($page->draft) { - $page->fill($data); - if (isset($data['html'])) { - $page->text = $this->pageToPlainText($page); + $page->fill($input); + if (isset($input['html'])) { + $content = new PageContent($page); + $content->setNewHTML($input['html']); } $page->save(); return $page; } // Otherwise save the data to a revision - $userId = user()->id; - $drafts = $this->userUpdatePageDraftsQuery($page, $userId)->get(); - - if ($drafts->count() > 0) { - $draft = $drafts->first(); - } else { - $draft = $this->entityProvider->pageRevision->newInstance(); - $draft->page_id = $page->id; - $draft->slug = $page->slug; - $draft->book_slug = $page->book->slug; - $draft->created_by = $userId; - $draft->type = 'update_draft'; - } - - $draft->fill($data); + $draft = $this->getPageRevisionToUpdate($page); + $draft->fill($input); if (setting('app-editor') !== 'markdown') { $draft->markdown = ''; } @@ -290,225 +259,78 @@ class PageRepo extends EntityRepo } /** - * Publish a draft page to make it a normal page. - * Sets the slug and updates the content. - * @param Page $draftPage - * @param array $input - * @return Page - * @throws \Exception + * Destroy a page from the system. + * @throws NotifyException */ - public function publishPageDraft(Page $draftPage, array $input) + public function destroy(Page $page) { - $draftPage->fill($input); - - // Save page tags if present - if (isset($input['tags'])) { - $this->tagRepo->saveTagsToEntity($draftPage, $input['tags']); - } - - if (isset($input['template']) && userCan('templates-manage')) { - $draftPage->template = ($input['template'] === 'true'); - } - - $draftPage->slug = $this->findSuitableSlug('page', $draftPage->name, false, $draftPage->book->id); - $draftPage->html = $this->formatHtml($input['html']); - $draftPage->text = $this->pageToPlainText($draftPage); - $draftPage->draft = false; - $draftPage->revision_count = 1; - - $draftPage->save(); - $this->savePageRevision($draftPage, trans('entities.pages_initial_revision')); - $this->searchService->indexEntity($draftPage); - return $draftPage; - } - - /** - * The base query for getting user update drafts. - * @param Page $page - * @param $userId - * @return mixed - */ - protected function userUpdatePageDraftsQuery(Page $page, int $userId) - { - return $this->entityProvider->pageRevision->where('created_by', '=', $userId) - ->where('type', 'update_draft') - ->where('page_id', '=', $page->id) - ->orderBy('created_at', 'desc'); - } - - /** - * Get the latest updated draft revision for a particular page and user. - * @param Page $page - * @param $userId - * @return PageRevision|null - */ - public function getUserPageDraft(Page $page, int $userId) - { - return $this->userUpdatePageDraftsQuery($page, $userId)->first(); - } - - /** - * Get the notification message that informs the user that they are editing a draft page. - * @param PageRevision $draft - * @return string - */ - public function getUserPageDraftMessage(PageRevision $draft) - { - $message = trans('entities.pages_editing_draft_notification', ['timeDiff' => $draft->updated_at->diffForHumans()]); - if ($draft->page->updated_at->timestamp <= $draft->updated_at->timestamp) { - return $message; - } - return $message . "\n" . trans('entities.pages_draft_edited_notification'); - } - - /** - * A query to check for active update drafts on a particular page. - * @param Page $page - * @param int $minRange - * @return mixed - */ - protected function activePageEditingQuery(Page $page, int $minRange = null) - { - $query = $this->entityProvider->pageRevision->where('type', '=', 'update_draft') - ->where('page_id', '=', $page->id) - ->where('updated_at', '>', $page->updated_at) - ->where('created_by', '!=', user()->id) - ->with('createdBy'); - - if ($minRange !== null) { - $query = $query->where('updated_at', '>=', Carbon::now()->subMinutes($minRange)); - } - - return $query; - } - - /** - * Check if a page is being actively editing. - * Checks for edits since last page updated. - * Passing in a minuted range will check for edits - * within the last x minutes. - * @param Page $page - * @param int $minRange - * @return bool - */ - public function isPageEditingActive(Page $page, int $minRange = null) - { - $draftSearch = $this->activePageEditingQuery($page, $minRange); - return $draftSearch->count() > 0; - } - - /** - * Get a notification message concerning the editing activity on a particular page. - * @param Page $page - * @param int $minRange - * @return string - */ - public function getPageEditingActiveMessage(Page $page, int $minRange = null) - { - $pageDraftEdits = $this->activePageEditingQuery($page, $minRange)->get(); - - $userMessage = $pageDraftEdits->count() > 1 ? trans('entities.pages_draft_edit_active.start_a', ['count' => $pageDraftEdits->count()]): trans('entities.pages_draft_edit_active.start_b', ['userName' => $pageDraftEdits->first()->createdBy->name]); - $timeMessage = $minRange === null ? trans('entities.pages_draft_edit_active.time_a') : trans('entities.pages_draft_edit_active.time_b', ['minCount'=>$minRange]); - return trans('entities.pages_draft_edit_active.message', ['start' => $userMessage, 'time' => $timeMessage]); - } - - /** - * Parse the headers on the page to get a navigation menu - * @param string $pageContent - * @return array - */ - public function getPageNav(string $pageContent) - { - if ($pageContent == '') { - return []; - } - libxml_use_internal_errors(true); - $doc = new DOMDocument(); - $doc->loadHTML(mb_convert_encoding($pageContent, 'HTML-ENTITIES', 'UTF-8')); - $xPath = new DOMXPath($doc); - $headers = $xPath->query("//h1|//h2|//h3|//h4|//h5|//h6"); - - if (is_null($headers)) { - return []; - } - - $tree = collect($headers)->map(function($header) { - $text = trim(str_replace("\xc2\xa0", '', $header->nodeValue)); - $text = mb_substr($text, 0, 100); - - return [ - 'nodeName' => strtolower($header->nodeName), - 'level' => intval(str_replace('h', '', $header->nodeName)), - 'link' => '#' . $header->getAttribute('id'), - 'text' => $text, - ]; - })->filter(function($header) { - return mb_strlen($header['text']) > 0; - }); - - // Shift headers if only smaller headers have been used - $levelChange = ($tree->pluck('level')->min() - 1); - $tree = $tree->map(function ($header) use ($levelChange) { - $header['level'] -= ($levelChange); - return $header; - }); - - return $tree->toArray(); + $trashCan = new TrashCan(); + $trashCan->destroyPage($page); } /** * Restores a revision's content back into a page. - * @param Page $page - * @param Book $book - * @param int $revisionId - * @return Page - * @throws \Exception */ - public function restorePageRevision(Page $page, Book $book, int $revisionId) + public function restoreRevision(Page $page, int $revisionId): Page { $page->revision_count++; $this->savePageRevision($page); + $revision = $page->revisions()->where('id', '=', $revisionId)->first(); $page->fill($revision->toArray()); - $page->slug = $this->findSuitableSlug('page', $page->name, $page->id, $book->id); - $page->text = $this->pageToPlainText($page); + $content = new PageContent($page); + $content->setNewHTML($page->html); $page->updated_by = user()->id; + $page->refreshSlug(); $page->save(); - $this->searchService->indexEntity($page); + + $page->indexForSearch(); return $page; } /** - * Change the page's parent to the given entity. - * @param Page $page - * @param Entity $parent - * @throws \Throwable + * Move the given page into a new parent book or chapter. + * The $parentIdentifier must be a string of the following format: + * 'book:' (book:5) + * @throws MoveOperationException + * @throws PermissionsException */ - public function changePageParent(Page $page, Entity $parent) + public function move(Page $page, string $parentIdentifier): Book { - $book = $parent->isA('book') ? $parent : $parent->book; - $page->chapter_id = $parent->isA('chapter') ? $parent->id : 0; - $page->save(); - if ($page->book->id !== $book->id) { - $page = $this->changeBook('page', $book->id, $page); + $parent = $this->findParentByIdentifier($parentIdentifier); + if ($parent === null) { + throw new MoveOperationException('Book or chapter to move page into not found'); } - $page->load('book'); - $this->permissionService->buildJointPermissionsForEntity($book); + + if (!userCan('page-create', $parent)) { + throw new PermissionsException('User does not have permission to create a page within the new parent'); + } + + $page->chapter_id = ($parent instanceof Chapter) ? $parent->id : null; + $page->changeBook($parent instanceof Book ? $parent->id : $parent->book->id); + $page->rebuildPermissions(); + + return ($parent instanceof Book ? $parent : $parent->book); } /** - * Create a copy of a page in a new location with a new name. - * @param \BookStack\Entities\Page $page - * @param \BookStack\Entities\Entity $newParent - * @param string $newName - * @return \BookStack\Entities\Page - * @throws \Throwable + * Copy an existing page in the system. + * Optionally providing a new parent via string identifier and a new name. + * @throws MoveOperationException + * @throws PermissionsException */ - public function copyPage(Page $page, Entity $newParent, string $newName = '') + public function copy(Page $page, string $parentIdentifier = null, string $newName = null): Page { - $newBook = $newParent->isA('book') ? $newParent : $newParent->book; - $newChapter = $newParent->isA('chapter') ? $newParent : null; - $copyPage = $this->getDraftPage($newBook, $newChapter); + $parent = $parentIdentifier ? $this->findParentByIdentifier($parentIdentifier) : $page->parent(); + if ($parent === null) { + throw new MoveOperationException('Book or chapter to move page into not found'); + } + + if (!userCan('page-create', $parent)) { + throw new PermissionsException('User does not have permission to create a page within the new parent'); + } + + $copyPage = $this->getNewDraftPage($parent); $pageData = $page->getAttributes(); // Update name @@ -524,38 +346,116 @@ class PageRepo extends EntityRepo } } - // Set priority - if ($newParent->isA('chapter')) { - $pageData['priority'] = $this->getNewChapterPriority($newParent); - } else { - $pageData['priority'] = $this->getNewBookPriority($newParent); - } - - return $this->publishPageDraft($copyPage, $pageData); + return $this->publishDraft($copyPage, $pageData); } /** - * Get pages that have been marked as templates. - * @param int $count - * @param int $page - * @param string $search - * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + * Find a page parent entity via a identifier string in the format: + * {type}:{id} + * Example: (book:5) + * @throws MoveOperationException */ - public function getPageTemplates(int $count = 10, int $page = 1, string $search = '') + protected function findParentByIdentifier(string $identifier): ?Entity { - $query = $this->entityQuery('page') - ->where('template', '=', true) - ->orderBy('name', 'asc') - ->skip( ($page - 1) * $count) - ->take($count); + $stringExploded = explode(':', $identifier); + $entityType = $stringExploded[0]; + $entityId = intval($stringExploded[1]); - if ($search) { - $query->where('name', 'like', '%' . $search . '%'); + if ($entityType !== 'book' && $entityType !== 'chapter') { + throw new MoveOperationException('Pages can only be in books or chapters'); } - $paginator = $query->paginate($count, ['*'], 'page', $page); - $paginator->withPath('/templates'); + $parentClass = $entityType === 'book' ? Book::class : Chapter::class; + return $parentClass::visible()->where('id', '=', $entityId)->first(); + } - return $paginator; + /** + * Update the permissions of a page. + */ + public function updatePermissions(Page $page, bool $restricted, Collection $permissions = null) + { + $this->baseRepo->updatePermissions($page, $restricted, $permissions); + } + + /** + * Change the page's parent to the given entity. + */ + protected function changeParent(Page $page, Entity $parent) + { + $book = ($parent instanceof Book) ? $parent : $parent->book; + $page->chapter_id = ($parent instanceof Chapter) ? $parent->id : 0; + $page->save(); + + if ($page->book->id !== $book->id) { + $page->changeBook($book->id); + } + + $page->load('book'); + $book->rebuildPermissions(); + } + + /** + * Get a page revision to update for the given page. + * Checks for an existing revisions before providing a fresh one. + */ + protected function getPageRevisionToUpdate(Page $page): PageRevision + { + $drafts = $this->getUserDraftQuery($page)->get(); + if ($drafts->count() > 0) { + return $drafts->first(); + } + + $draft = new PageRevision(); + $draft->page_id = $page->id; + $draft->slug = $page->slug; + $draft->book_slug = $page->book->slug; + $draft->created_by = user()->id; + $draft->type = 'update_draft'; + return $draft; + } + + /** + * Delete old revisions, for the given page, from the system. + */ + protected function deleteOldRevisions(Page $page) + { + $revisionLimit = config('app.revision_limit'); + if ($revisionLimit === false) { + return; + } + + $revisionsToDelete = PageRevision::query() + ->where('page_id', '=', $page->id) + ->orderBy('created_at', 'desc') + ->skip(intval($revisionLimit)) + ->take(10) + ->get(['id']); + if ($revisionsToDelete->count() > 0) { + PageRevision::query()->whereIn('id', $revisionsToDelete->pluck('id'))->delete(); + } + } + + /** + * Get a new priority for a page + */ + protected function getNewPriority(Page $page): int + { + if ($page->parent() instanceof Chapter) { + $lastPage = $page->parent()->pages('desc')->first(); + return $lastPage ? $lastPage->priority + 1 : 0; + } + + return (new BookContents($page->book))->getLastPriority() + 1; + } + + /** + * Get the query to find the user's draft copies of the given page. + */ + protected function getUserDraftQuery(Page $page) + { + return PageRevision::query()->where('created_by', '=', user()->id) + ->where('type', 'update_draft') + ->where('page_id', '=', $page->id) + ->orderBy('created_at', 'desc'); } } diff --git a/app/Entities/SearchService.php b/app/Entities/SearchService.php index 9e7cfdd0c..ee9b87786 100644 --- a/app/Entities/SearchService.php +++ b/app/Entities/SearchService.php @@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Query\Builder; use Illuminate\Database\Query\JoinClause; use Illuminate\Support\Collection; +use Illuminate\Support\Str; class SearchService { @@ -210,7 +211,7 @@ class SearchService // Handle filters foreach ($terms['filters'] as $filterTerm => $filterValue) { - $functionName = camel_case('filter_' . $filterTerm); + $functionName = Str::camel('filter_' . $filterTerm); if (method_exists($this, $functionName)) { $this->$functionName($entitySelect, $entity, $filterValue); } @@ -514,7 +515,7 @@ class SearchService protected function filterSortBy(EloquentBuilder $query, Entity $model, $input) { - $functionName = camel_case('sort_by_' . $input); + $functionName = Str::camel('sort_by_' . $input); if (method_exists($this, $functionName)) { $this->$functionName($query, $model); } diff --git a/app/Entities/SlugGenerator.php b/app/Entities/SlugGenerator.php new file mode 100644 index 000000000..459a5264a --- /dev/null +++ b/app/Entities/SlugGenerator.php @@ -0,0 +1,62 @@ +entity = $entity; + } + + /** + * Generate a fresh slug for the given entity. + * The slug will generated so it does not conflict within the same parent item. + */ + public function generate(): string + { + $slug = $this->formatNameAsSlug($this->entity->name); + while ($this->slugInUse($slug)) { + $slug .= '-' . substr(md5(rand(1, 500)), 0, 3); + } + return $slug; + } + + /** + * Format a name as a url slug. + */ + protected function formatNameAsSlug(string $name): string + { + $slug = preg_replace('/[\+\/\\\?\@\}\{\.\,\=\[\]\#\&\!\*\'\;\:\$\%]/', '', mb_strtolower($name)); + $slug = preg_replace('/\s{2,}/', ' ', $slug); + $slug = str_replace(' ', '-', $slug); + if ($slug === "") { + $slug = substr(md5(rand(1, 500)), 0, 5); + } + return $slug; + } + + /** + * Check if a slug is already in-use for this + * type of model within the same parent. + */ + protected function slugInUse(string $slug): bool + { + $query = $this->entity->newQuery()->where('slug', '=', $slug); + + if ($this->entity instanceof BookChild) { + $query->where('book_id', '=', $this->entity->book_id); + } + + if ($this->entity->id) { + $query->where('id', '!=', $this->entity->id); + } + + return $query->count() > 0; + } +} diff --git a/app/Exceptions/ApiAuthException.php b/app/Exceptions/ApiAuthException.php new file mode 100644 index 000000000..cc68ba8cf --- /dev/null +++ b/app/Exceptions/ApiAuthException.php @@ -0,0 +1,7 @@ +isApiRequest($request)) { + return $this->renderApiException($e); + } + // Handle notify exceptions which will redirect to the // specified location then show a notification message. if ($this->isExceptionType($e, NotifyException::class)) { - session()->flash('error', $this->getOriginalMessage($e)); + $message = $this->getOriginalMessage($e); + if (!empty($message)) { + session()->flash('error', $message); + } return redirect($e->redirectLocation); } @@ -70,6 +80,41 @@ class Handler extends ExceptionHandler return parent::render($request, $e); } + /** + * Check if the given request is an API request. + */ + protected function isApiRequest(Request $request): bool + { + return strpos($request->path(), 'api/') === 0; + } + + /** + * Render an exception when the API is in use. + */ + protected function renderApiException(Exception $e): JsonResponse + { + $code = $e->getCode() === 0 ? 500 : $e->getCode(); + $headers = []; + if ($e instanceof HttpException) { + $code = $e->getStatusCode(); + $headers = $e->getHeaders(); + } + + $responseData = [ + 'error' => [ + 'message' => $e->getMessage(), + ] + ]; + + if ($e instanceof ValidationException) { + $responseData['error']['validation'] = $e->errors(); + $code = $e->status; + } + + $responseData['error']['code'] = $code; + return new JsonResponse($responseData, $code, $headers); + } + /** * Check the exception chain to compare against the original exception type. * @param Exception $e diff --git a/app/Exceptions/JsonDebugException.php b/app/Exceptions/JsonDebugException.php new file mode 100644 index 000000000..6314533ce --- /dev/null +++ b/app/Exceptions/JsonDebugException.php @@ -0,0 +1,25 @@ +data = $data; + } + + /** + * Covert this exception into a response. + */ + public function render() + { + return response()->json($this->data); + } +} \ No newline at end of file diff --git a/app/Exceptions/LoginAttemptEmailNeededException.php b/app/Exceptions/LoginAttemptEmailNeededException.php new file mode 100644 index 000000000..7ffb0c065 --- /dev/null +++ b/app/Exceptions/LoginAttemptEmailNeededException.php @@ -0,0 +1,6 @@ +userId = $userId; parent::__construct($message); } - - -} \ No newline at end of file +} diff --git a/app/Exceptions/UserTokenNotFoundException.php b/app/Exceptions/UserTokenNotFoundException.php index 08c1fd830..3ed53f72a 100644 --- a/app/Exceptions/UserTokenNotFoundException.php +++ b/app/Exceptions/UserTokenNotFoundException.php @@ -1,3 +1,6 @@ toResponse(); + } + + /** + * Get the validation rules for this controller. + */ + public function getValdationRules(): array + { + 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 new file mode 100644 index 000000000..84ddd5215 --- /dev/null +++ b/app/Http/Controllers/Api/ApiDocsController.php @@ -0,0 +1,47 @@ +getDocs(); + return view('api-docs.index', [ + 'docs' => $docs, + ]); + } + + /** + * Show a JSON view of the API docs data. + */ + public function json() { + $docs = $this->getDocs(); + return response()->json($docs); + } + + /** + * Get the base docs data. + * Checks and uses the system cache for quick re-fetching. + */ + protected function getDocs(): Collection + { + $appVersion = trim(file_get_contents(base_path('version'))); + $cacheKey = 'api-docs::' . $appVersion; + if (Cache::has($cacheKey) && config('app.env') === 'production') { + $docs = Cache::get($cacheKey); + } else { + $docs = (new ApiDocsGenerator())->generate(); + Cache::put($cacheKey, $docs, 60*24); + } + + return $docs; + } + +} diff --git a/app/Http/Controllers/Api/BooksApiController.php b/app/Http/Controllers/Api/BooksApiController.php new file mode 100644 index 000000000..ac4ea171c --- /dev/null +++ b/app/Http/Controllers/Api/BooksApiController.php @@ -0,0 +1,101 @@ + [ + 'name' => 'required|string|max:255', + 'description' => 'string|max:1000', + ], + 'update' => [ + 'name' => 'string|min:1|max:255', + 'description' => 'string|max:1000', + ], + ]; + + /** + * BooksApiController constructor. + */ + public function __construct(BookRepo $bookRepo) + { + $this->bookRepo = $bookRepo; + } + + /** + * Get a listing of books visible to the user. + */ + public function list() + { + $books = Book::visible(); + return $this->apiListingResponse($books, [ + 'id', 'name', 'slug', 'description', 'created_at', 'updated_at', 'created_by', 'updated_by', 'image_id', + ]); + } + + /** + * Create a new book in the system. + * @throws ValidationException + */ + public function create(Request $request) + { + $this->checkPermission('book-create-all'); + $requestData = $this->validate($request, $this->rules['create']); + + $book = $this->bookRepo->create($requestData); + Activity::add($book, 'book_create', $book->id); + + return response()->json($book); + } + + /** + * View the details of a single book. + */ + public function read(string $id) + { + $book = Book::visible()->with(['tags', 'cover', 'createdBy', 'updatedBy'])->findOrFail($id); + return response()->json($book); + } + + /** + * Update the details of a single book. + * @throws ValidationException + */ + public function update(Request $request, string $id) + { + $book = Book::visible()->findOrFail($id); + $this->checkOwnablePermission('book-update', $book); + + $requestData = $this->validate($request, $this->rules['update']); + $book = $this->bookRepo->update($book, $requestData); + Activity::add($book, 'book_update', $book->id); + + return response()->json($book); + } + + /** + * Delete a single book from the system. + * @throws NotifyException + * @throws BindingResolutionException + */ + public function delete(string $id) + { + $book = Book::visible()->findOrFail($id); + $this->checkOwnablePermission('book-delete', $book); + + $this->bookRepo->destroy($book); + Activity::addMessage('book_delete', $book->name); + + return response('', 204); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/AttachmentController.php b/app/Http/Controllers/AttachmentController.php index 0289f8e1d..8f5da49ed 100644 --- a/app/Http/Controllers/AttachmentController.php +++ b/app/Http/Controllers/AttachmentController.php @@ -1,37 +1,37 @@ attachmentService = $attachmentService; $this->attachment = $attachment; - $this->entityRepo = $entityRepo; + $this->pageRepo = $pageRepo; parent::__construct(); } /** * Endpoint at which attachments are uploaded to. - * @param Request $request - * @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response + * @throws ValidationException + * @throws NotFoundException */ public function upload(Request $request) { @@ -41,7 +41,7 @@ class AttachmentController extends Controller ]); $pageId = $request->get('uploaded_to'); - $page = $this->entityRepo->getById('page', $pageId, true); + $page = $this->pageRepo->getById($pageId); $this->checkPermission('attachment-create-all'); $this->checkOwnablePermission('page-update', $page); @@ -59,11 +59,10 @@ class AttachmentController extends Controller /** * Update an uploaded attachment. - * @param int $attachmentId - * @param Request $request - * @return mixed + * @throws ValidationException + * @throws NotFoundException */ - public function uploadUpdate($attachmentId, Request $request) + public function uploadUpdate(Request $request, $attachmentId) { $this->validate($request, [ 'uploaded_to' => 'required|integer|exists:pages,id', @@ -71,7 +70,7 @@ class AttachmentController extends Controller ]); $pageId = $request->get('uploaded_to'); - $page = $this->entityRepo->getById('page', $pageId, true); + $page = $this->pageRepo->getById($pageId); $attachment = $this->attachment->findOrFail($attachmentId); $this->checkOwnablePermission('page-update', $page); @@ -94,11 +93,10 @@ class AttachmentController extends Controller /** * Update the details of an existing file. - * @param $attachmentId - * @param Request $request - * @return Attachment|mixed + * @throws ValidationException + * @throws NotFoundException */ - public function update($attachmentId, Request $request) + public function update(Request $request, $attachmentId) { $this->validate($request, [ 'uploaded_to' => 'required|integer|exists:pages,id', @@ -107,7 +105,7 @@ class AttachmentController extends Controller ]); $pageId = $request->get('uploaded_to'); - $page = $this->entityRepo->getById('page', $pageId, true); + $page = $this->pageRepo->getById($pageId); $attachment = $this->attachment->findOrFail($attachmentId); $this->checkOwnablePermission('page-update', $page); @@ -123,8 +121,8 @@ class AttachmentController extends Controller /** * Attach a link to a page. - * @param Request $request - * @return mixed + * @throws ValidationException + * @throws NotFoundException */ public function attachLink(Request $request) { @@ -135,7 +133,7 @@ class AttachmentController extends Controller ]); $pageId = $request->get('uploaded_to'); - $page = $this->entityRepo->getById('page', $pageId, true); + $page = $this->pageRepo->getById($pageId); $this->checkPermission('attachment-create-all'); $this->checkOwnablePermission('page-update', $page); @@ -149,29 +147,26 @@ class AttachmentController extends Controller /** * Get the attachments for a specific page. - * @param $pageId - * @return mixed */ - public function listForPage($pageId) + public function listForPage(int $pageId) { - $page = $this->entityRepo->getById('page', $pageId, true); + $page = $this->pageRepo->getById($pageId); $this->checkOwnablePermission('page-view', $page); return response()->json($page->attachments); } /** * Update the attachment sorting. - * @param $pageId - * @param Request $request - * @return mixed + * @throws ValidationException + * @throws NotFoundException */ - public function sortForPage($pageId, Request $request) + public function sortForPage(Request $request, int $pageId) { $this->validate($request, [ 'files' => 'required|array', 'files.*.id' => 'required|integer', ]); - $page = $this->entityRepo->getById('page', $pageId); + $page = $this->pageRepo->getById($pageId); $this->checkOwnablePermission('page-update', $page); $attachments = $request->get('files'); @@ -181,16 +176,15 @@ class AttachmentController extends Controller /** * Get an attachment from storage. - * @param $attachmentId - * @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Symfony\Component\HttpFoundation\Response - * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + * @throws FileNotFoundException * @throws NotFoundException */ - public function get($attachmentId) + public function get(int $attachmentId) { $attachment = $this->attachment->findOrFail($attachmentId); - $page = $this->entityRepo->getById('page', $attachment->uploaded_to); - if ($page === null) { + try { + $page = $this->pageRepo->getById($attachment->uploaded_to); + } catch (NotFoundException $exception) { throw new NotFoundException(trans('errors.attachment_not_found')); } @@ -208,9 +202,9 @@ class AttachmentController extends Controller * Delete a specific attachment in the system. * @param $attachmentId * @return mixed - * @throws \Exception + * @throws Exception */ - public function delete($attachmentId) + public function delete(int $attachmentId) { $attachment = $this->attachment->findOrFail($attachmentId); $this->checkOwnablePermission('attachment-delete', $attachment); diff --git a/app/Http/Controllers/Auth/ConfirmEmailController.php b/app/Http/Controllers/Auth/ConfirmEmailController.php index 3e240b94e..099558eb7 100644 --- a/app/Http/Controllers/Auth/ConfirmEmailController.php +++ b/app/Http/Controllers/Auth/ConfirmEmailController.php @@ -64,16 +64,15 @@ class ConfirmEmailController extends Controller try { $userId = $this->emailConfirmationService->checkTokenAndGetUserId($token); } catch (Exception $exception) { - if ($exception instanceof UserTokenNotFoundException) { - session()->flash('error', trans('errors.email_confirmation_invalid')); + $this->showErrorNotification(trans('errors.email_confirmation_invalid')); return redirect('/register'); } if ($exception instanceof UserTokenExpiredException) { $user = $this->userRepo->getById($exception->userId); $this->emailConfirmationService->sendConfirmation($user); - session()->flash('error', trans('errors.email_confirmation_expired')); + $this->showErrorNotification(trans('errors.email_confirmation_expired')); return redirect('/register/confirm'); } @@ -85,7 +84,7 @@ class ConfirmEmailController extends Controller $user->save(); auth()->login($user); - session()->flash('success', trans('auth.email_confirm_success')); + $this->showSuccessNotification(trans('auth.email_confirm_success')); $this->emailConfirmationService->deleteByUser($user); return redirect('/'); @@ -107,12 +106,11 @@ class ConfirmEmailController extends Controller try { $this->emailConfirmationService->sendConfirmation($user); } catch (Exception $e) { - session()->flash('error', trans('auth.email_confirm_send_error')); + $this->showErrorNotification(trans('auth.email_confirm_send_error')); return redirect('/register/confirm'); } - session()->flash('success', trans('auth.email_confirm_resent')); + $this->showSuccessNotification(trans('auth.email_confirm_resent')); return redirect('/register/confirm'); } - } diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php index a0cbae9c6..a60fcc1c9 100644 --- a/app/Http/Controllers/Auth/ForgotPasswordController.php +++ b/app/Http/Controllers/Auth/ForgotPasswordController.php @@ -30,6 +30,7 @@ class ForgotPasswordController extends Controller public function __construct() { $this->middleware('guest'); + $this->middleware('guard:standard'); parent::__construct(); } @@ -53,7 +54,7 @@ class ForgotPasswordController extends Controller if ($response === Password::RESET_LINK_SENT) { $message = trans('auth.reset_password_sent_success', ['email' => $request->get('email')]); - session()->flash('success', $message); + $this->showSuccessNotification($message); return back()->with('status', trans($response)); } diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index c739fd9a3..ea584a3b6 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -2,12 +2,11 @@ namespace BookStack\Http\Controllers\Auth; -use BookStack\Auth\Access\LdapService; use BookStack\Auth\Access\SocialAuthService; -use BookStack\Auth\UserRepo; -use BookStack\Exceptions\AuthException; +use BookStack\Exceptions\LoginAttemptEmailNeededException; +use BookStack\Exceptions\LoginAttemptException; +use BookStack\Exceptions\UserRegistrationException; use BookStack\Http\Controllers\Controller; -use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Foundation\Auth\AuthenticatesUsers; use Illuminate\Http\Request; @@ -27,32 +26,23 @@ class LoginController extends Controller use AuthenticatesUsers; /** - * Where to redirect users after login. - * - * @var string + * Redirection paths */ protected $redirectTo = '/'; - protected $redirectPath = '/'; protected $redirectAfterLogout = '/login'; protected $socialAuthService; - protected $ldapService; - protected $userRepo; /** * Create a new controller instance. - * - * @param \BookStack\Auth\\BookStack\Auth\Access\SocialAuthService $socialAuthService - * @param LdapService $ldapService - * @param \BookStack\Auth\UserRepo $userRepo */ - public function __construct(SocialAuthService $socialAuthService, LdapService $ldapService, UserRepo $userRepo) + public function __construct(SocialAuthService $socialAuthService) { - $this->middleware('guest', ['only' => ['getLogin', 'postLogin']]); + $this->middleware('guest', ['only' => ['getLogin', 'login']]); + $this->middleware('guard:standard,ldap', ['only' => ['login', 'logout']]); + $this->socialAuthService = $socialAuthService; - $this->ldapService = $ldapService; - $this->userRepo = $userRepo; $this->redirectPath = url('/'); $this->redirectAfterLogout = url('/login'); parent::__construct(); @@ -64,55 +54,15 @@ class LoginController extends Controller } /** - * Overrides the action when a user is authenticated. - * If the user authenticated but does not exist in the user table we create them. - * @param Request $request - * @param Authenticatable $user - * @return \Illuminate\Http\RedirectResponse - * @throws AuthException - * @throws \BookStack\Exceptions\LdapException + * Get the needed authorization credentials from the request. */ - protected function authenticated(Request $request, Authenticatable $user) + protected function credentials(Request $request) { - // Explicitly log them out for now if they do no exist. - if (!$user->exists) { - auth()->logout($user); - } - - if (!$user->exists && $user->email === null && !$request->filled('email')) { - $request->flash(); - session()->flash('request-email', true); - return redirect('/login'); - } - - if (!$user->exists && $user->email === null && $request->filled('email')) { - $user->email = $request->get('email'); - } - - if (!$user->exists) { - // Check for users with same email already - $alreadyUser = $user->newQuery()->where('email', '=', $user->email)->count() > 0; - if ($alreadyUser) { - throw new AuthException(trans('errors.error_user_exists_different_creds', ['email' => $user->email])); - } - - $user->save(); - $this->userRepo->attachDefaultRole($user); - auth()->login($user); - } - - // Sync LDAP groups if required - if ($this->ldapService->shouldSyncGroups()) { - $this->ldapService->syncGroups($user, $request->get($this->username())); - } - - return redirect()->intended('/'); + return $request->only('username', 'email', 'password'); } /** * Show the application login form. - * @param Request $request - * @return \Illuminate\Http\Response */ public function getLogin(Request $request) { @@ -126,18 +76,90 @@ class LoginController extends Controller ]); } - return view('auth.login', ['socialDrivers' => $socialDrivers, 'authMethod' => $authMethod]); + return view('auth.login', [ + 'socialDrivers' => $socialDrivers, + 'authMethod' => $authMethod, + ]); } /** - * Redirect to the relevant social site. - * @param $socialDriver - * @return \Symfony\Component\HttpFoundation\RedirectResponse - * @throws \BookStack\Exceptions\SocialDriverNotConfigured + * Handle a login request to the application. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse + * + * @throws \Illuminate\Validation\ValidationException */ - public function getSocialLogin($socialDriver) + public function login(Request $request) { - session()->put('social-callback', 'login'); - return $this->socialAuthService->startLogIn($socialDriver); + $this->validateLogin($request); + + // If the class is using the ThrottlesLogins trait, we can automatically throttle + // the login attempts for this application. We'll key this by the username and + // the IP address of the client making these requests into this application. + if (method_exists($this, 'hasTooManyLoginAttempts') && + $this->hasTooManyLoginAttempts($request)) { + $this->fireLockoutEvent($request); + + return $this->sendLockoutResponse($request); + } + + try { + if ($this->attemptLogin($request)) { + return $this->sendLoginResponse($request); + } + } catch (LoginAttemptException $exception) { + return $this->sendLoginAttemptExceptionResponse($exception, $request); + } + + // If the login attempt was unsuccessful we will increment the number of attempts + // to login and redirect the user back to the login form. Of course, when this + // user surpasses their maximum number of attempts they will get locked out. + $this->incrementLoginAttempts($request); + + return $this->sendFailedLoginResponse($request); } + + /** + * Validate the user login request. + * + * @param \Illuminate\Http\Request $request + * @return void + * + * @throws \Illuminate\Validation\ValidationException + */ + protected function validateLogin(Request $request) + { + $rules = ['password' => 'required|string']; + $authMethod = config('auth.method'); + + if ($authMethod === 'standard') { + $rules['email'] = 'required|email'; + } + + if ($authMethod === 'ldap') { + $rules['username'] = 'required|string'; + $rules['email'] = 'email'; + } + + $request->validate($rules); + } + + /** + * Send a response when a login attempt exception occurs. + */ + protected function sendLoginAttemptExceptionResponse(LoginAttemptException $exception, Request $request) + { + if ($exception instanceof LoginAttemptEmailNeededException) { + $request->flash(); + session()->flash('request-email', true); + } + + if ($message = $exception->getMessage()) { + $this->showWarningNotification($message); + } + + return redirect('/login'); + } + } diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index c411f2363..0bdeef9e6 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -2,23 +2,14 @@ namespace BookStack\Http\Controllers\Auth; -use BookStack\Auth\Access\EmailConfirmationService; +use BookStack\Auth\Access\RegistrationService; use BookStack\Auth\Access\SocialAuthService; -use BookStack\Auth\SocialAccount; use BookStack\Auth\User; -use BookStack\Auth\UserRepo; -use BookStack\Exceptions\SocialDriverNotConfigured; -use BookStack\Exceptions\SocialSignInAccountNotUsed; -use BookStack\Exceptions\SocialSignInException; use BookStack\Exceptions\UserRegistrationException; use BookStack\Http\Controllers\Controller; -use Exception; use Illuminate\Foundation\Auth\RegistersUsers; -use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; -use Illuminate\Http\Response; -use Illuminate\Routing\Redirector; -use Laravel\Socialite\Contracts\User as SocialUser; +use Illuminate\Support\Facades\Hash; use Validator; class RegisterController extends Controller @@ -37,8 +28,7 @@ class RegisterController extends Controller use RegistersUsers; protected $socialAuthService; - protected $emailConfirmationService; - protected $userRepo; + protected $registrationService; /** * Where to redirect users after login / registration. @@ -50,17 +40,15 @@ class RegisterController extends Controller /** * Create a new controller instance. - * - * @param SocialAuthService $socialAuthService - * @param EmailConfirmationService $emailConfirmationService - * @param UserRepo $userRepo */ - public function __construct(SocialAuthService $socialAuthService, EmailConfirmationService $emailConfirmationService, UserRepo $userRepo) + public function __construct(SocialAuthService $socialAuthService, RegistrationService $registrationService) { - $this->middleware('guest')->only(['getRegister', 'postRegister', 'socialRegister']); + $this->middleware('guest'); + $this->middleware('guard:standard'); + $this->socialAuthService = $socialAuthService; - $this->emailConfirmationService = $emailConfirmationService; - $this->userRepo = $userRepo; + $this->registrationService = $registrationService; + $this->redirectTo = url('/'); $this->redirectPath = url('/'); parent::__construct(); @@ -69,7 +57,6 @@ class RegisterController extends Controller /** * Get a validator for an incoming registration request. * - * @param array $data * @return \Illuminate\Contracts\Validation\Validator */ protected function validator(array $data) @@ -77,46 +64,45 @@ class RegisterController extends Controller return Validator::make($data, [ 'name' => 'required|min:2|max:255', 'email' => 'required|email|max:255|unique:users', - 'password' => 'required|min:6', + 'password' => 'required|min:8', ]); } - /** - * Check whether or not registrations are allowed in the app settings. - * @throws UserRegistrationException - */ - protected function checkRegistrationAllowed() - { - if (!setting('registration-enabled')) { - throw new UserRegistrationException(trans('auth.registrations_disabled'), '/login'); - } - } - /** * Show the application registration form. - * @return Response * @throws UserRegistrationException */ public function getRegister() { - $this->checkRegistrationAllowed(); + $this->registrationService->ensureRegistrationAllowed(); $socialDrivers = $this->socialAuthService->getActiveDrivers(); - return view('auth.register', ['socialDrivers' => $socialDrivers]); + return view('auth.register', [ + 'socialDrivers' => $socialDrivers, + ]); } /** * Handle a registration request for the application. - * @param Request|Request $request - * @return RedirectResponse|Redirector * @throws UserRegistrationException */ public function postRegister(Request $request) { - $this->checkRegistrationAllowed(); + $this->registrationService->ensureRegistrationAllowed(); $this->validator($request->all())->validate(); - $userData = $request->all(); - return $this->registerUser($userData); + + try { + $user = $this->registrationService->registerUser($userData); + auth()->login($user); + } catch (UserRegistrationException $exception) { + if ($exception->getMessage()) { + $this->showErrorNotification($exception->getMessage()); + } + return redirect($exception->redirectLocation); + } + + $this->showSuccessNotification(trans('auth.register_success')); + return redirect($this->redirectPath()); } /** @@ -129,140 +115,8 @@ class RegisterController extends Controller return User::create([ 'name' => $data['name'], 'email' => $data['email'], - 'password' => bcrypt($data['password']), + 'password' => Hash::make($data['password']), ]); } - /** - * The registrations flow for all users. - * @param array $userData - * @param bool|false|SocialAccount $socialAccount - * @param bool $emailVerified - * @return RedirectResponse|Redirector - * @throws UserRegistrationException - */ - protected function registerUser(array $userData, $socialAccount = false, $emailVerified = false) - { - $registrationRestrict = setting('registration-restrict'); - - if ($registrationRestrict) { - $restrictedEmailDomains = explode(',', str_replace(' ', '', $registrationRestrict)); - $userEmailDomain = $domain = mb_substr(mb_strrchr($userData['email'], "@"), 1); - if (!in_array($userEmailDomain, $restrictedEmailDomains)) { - throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), '/register'); - } - } - - $newUser = $this->userRepo->registerNew($userData, $emailVerified); - if ($socialAccount) { - $newUser->socialAccounts()->save($socialAccount); - } - - if ($this->emailConfirmationService->confirmationRequired() && !$emailVerified) { - $newUser->save(); - - try { - $this->emailConfirmationService->sendConfirmation($newUser); - } catch (Exception $e) { - session()->flash('error', trans('auth.email_confirm_send_error')); - } - - return redirect('/register/confirm'); - } - - auth()->login($newUser); - session()->flash('success', trans('auth.register_success')); - return redirect($this->redirectPath()); - } - - /** - * Redirect to the social site for authentication intended to register. - * @param $socialDriver - * @return mixed - * @throws UserRegistrationException - * @throws SocialDriverNotConfigured - */ - public function socialRegister($socialDriver) - { - $this->checkRegistrationAllowed(); - session()->put('social-callback', 'register'); - return $this->socialAuthService->startRegister($socialDriver); - } - - /** - * The callback for social login services. - * @param $socialDriver - * @param Request $request - * @return RedirectResponse|Redirector - * @throws SocialSignInException - * @throws UserRegistrationException - * @throws SocialDriverNotConfigured - */ - public function socialCallback($socialDriver, Request $request) - { - if (!session()->has('social-callback')) { - throw new SocialSignInException(trans('errors.social_no_action_defined'), '/login'); - } - - // Check request for error information - if ($request->has('error') && $request->has('error_description')) { - throw new SocialSignInException(trans('errors.social_login_bad_response', [ - 'socialAccount' => $socialDriver, - 'error' => $request->get('error_description'), - ]), '/login'); - } - - $action = session()->pull('social-callback'); - - // Attempt login or fall-back to register if allowed. - $socialUser = $this->socialAuthService->getSocialUser($socialDriver); - if ($action == 'login') { - try { - return $this->socialAuthService->handleLoginCallback($socialDriver, $socialUser); - } catch (SocialSignInAccountNotUsed $exception) { - if ($this->socialAuthService->driverAutoRegisterEnabled($socialDriver)) { - return $this->socialRegisterCallback($socialDriver, $socialUser); - } - throw $exception; - } - } - - if ($action == 'register') { - return $this->socialRegisterCallback($socialDriver, $socialUser); - } - - return redirect()->back(); - } - - /** - * Detach a social account from a user. - * @param $socialDriver - * @return RedirectResponse|Redirector - */ - public function detachSocialAccount($socialDriver) - { - return $this->socialAuthService->detachSocialAccount($socialDriver); - } - - /** - * Register a new user after a registration callback. - * @param string $socialDriver - * @param SocialUser $socialUser - * @return RedirectResponse|Redirector - * @throws UserRegistrationException - */ - protected function socialRegisterCallback(string $socialDriver, SocialUser $socialUser) - { - $socialUser = $this->socialAuthService->handleRegistrationCallback($socialDriver, $socialUser); - $socialAccount = $this->socialAuthService->fillSocialAccount($socialDriver, $socialUser); - $emailVerified = $this->socialAuthService->driverAutoConfirmEmailEnabled($socialDriver); - - // Create an array of the user data to create a new user instance - $userData = [ - 'name' => $socialUser->getName(), - 'email' => $socialUser->getEmail(), - 'password' => str_random(30) - ]; - return $this->registerUser($userData, $socialAccount, $emailVerified); - } } diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php index 56f1cf026..214647cd5 100644 --- a/app/Http/Controllers/Auth/ResetPasswordController.php +++ b/app/Http/Controllers/Auth/ResetPasswordController.php @@ -4,6 +4,7 @@ namespace BookStack\Http\Controllers\Auth; use BookStack\Http\Controllers\Controller; use Illuminate\Foundation\Auth\ResetsPasswords; +use Illuminate\Http\Request; class ResetPasswordController extends Controller { @@ -30,19 +31,21 @@ class ResetPasswordController extends Controller public function __construct() { $this->middleware('guest'); + $this->middleware('guard:standard'); parent::__construct(); } /** * Get the response for a successful password reset. * - * @param string $response + * @param Request $request + * @param string $response * @return \Illuminate\Http\Response */ - protected function sendResetResponse($response) + protected function sendResetResponse(Request $request, $response) { $message = trans('auth.reset_password_success'); - session()->flash('success', $message); + $this->showSuccessNotification($message); return redirect($this->redirectPath()) ->with('status', trans($response)); } diff --git a/app/Http/Controllers/Auth/Saml2Controller.php b/app/Http/Controllers/Auth/Saml2Controller.php new file mode 100644 index 000000000..7ffcc572b --- /dev/null +++ b/app/Http/Controllers/Auth/Saml2Controller.php @@ -0,0 +1,87 @@ +samlService = $samlService; + $this->middleware('guard:saml2'); + } + + /** + * Start the login flow via SAML2. + */ + public function login() + { + $loginDetails = $this->samlService->login(); + session()->flash('saml2_request_id', $loginDetails['id']); + + return redirect($loginDetails['url']); + } + + /** + * Start the logout flow via SAML2. + */ + public function logout() + { + $logoutDetails = $this->samlService->logout(); + + if ($logoutDetails['id']) { + session()->flash('saml2_logout_request_id', $logoutDetails['id']); + } + + return redirect($logoutDetails['url']); + } + + /* + * Get the metadata for this SAML2 service provider. + */ + public function metadata() + { + $metaData = $this->samlService->metadata(); + return response()->make($metaData, 200, [ + 'Content-Type' => 'text/xml' + ]); + } + + /** + * Single logout service. + * Handle logout requests and responses. + */ + public function sls() + { + $requestId = session()->pull('saml2_logout_request_id', null); + $redirect = $this->samlService->processSlsResponse($requestId) ?? '/'; + return redirect($redirect); + } + + /** + * Assertion Consumer Service. + * Processes the SAML response from the IDP. + */ + public function acs() + { + $requestId = session()->pull('saml2_request_id', null); + + $user = $this->samlService->processAcsResponse($requestId); + if ($user === null) { + $this->showErrorNotification(trans('errors.saml_fail_authed', ['system' => config('saml2.name')])); + return redirect('/login'); + } + + return redirect()->intended(); + } + +} diff --git a/app/Http/Controllers/Auth/SocialController.php b/app/Http/Controllers/Auth/SocialController.php new file mode 100644 index 000000000..ae7a1bc06 --- /dev/null +++ b/app/Http/Controllers/Auth/SocialController.php @@ -0,0 +1,132 @@ +middleware('guest')->only(['getRegister', 'postRegister']); + $this->socialAuthService = $socialAuthService; + $this->registrationService = $registrationService; + } + + + /** + * Redirect to the relevant social site. + * @throws \BookStack\Exceptions\SocialDriverNotConfigured + */ + public function getSocialLogin(string $socialDriver) + { + session()->put('social-callback', 'login'); + return $this->socialAuthService->startLogIn($socialDriver); + } + + /** + * Redirect to the social site for authentication intended to register. + * @throws SocialDriverNotConfigured + * @throws UserRegistrationException + */ + public function socialRegister(string $socialDriver) + { + $this->registrationService->ensureRegistrationAllowed(); + session()->put('social-callback', 'register'); + return $this->socialAuthService->startRegister($socialDriver); + } + + /** + * The callback for social login services. + * @throws SocialSignInException + * @throws SocialDriverNotConfigured + * @throws UserRegistrationException + */ + public function socialCallback(Request $request, string $socialDriver) + { + if (!session()->has('social-callback')) { + throw new SocialSignInException(trans('errors.social_no_action_defined'), '/login'); + } + + // Check request for error information + if ($request->has('error') && $request->has('error_description')) { + throw new SocialSignInException(trans('errors.social_login_bad_response', [ + 'socialAccount' => $socialDriver, + 'error' => $request->get('error_description'), + ]), '/login'); + } + + $action = session()->pull('social-callback'); + + // Attempt login or fall-back to register if allowed. + $socialUser = $this->socialAuthService->getSocialUser($socialDriver); + if ($action === 'login') { + try { + return $this->socialAuthService->handleLoginCallback($socialDriver, $socialUser); + } catch (SocialSignInAccountNotUsed $exception) { + if ($this->socialAuthService->driverAutoRegisterEnabled($socialDriver)) { + return $this->socialRegisterCallback($socialDriver, $socialUser); + } + throw $exception; + } + } + + if ($action === 'register') { + return $this->socialRegisterCallback($socialDriver, $socialUser); + } + + return redirect()->back(); + } + + /** + * Detach a social account from a user. + */ + public function detachSocialAccount(string $socialDriver) + { + $this->socialAuthService->detachSocialAccount($socialDriver); + session()->flash('success', trans('settings.users_social_disconnected', ['socialAccount' => Str::title($socialDriver)])); + return redirect(user()->getEditUrl()); + } + + /** + * Register a new user after a registration callback. + * @throws UserRegistrationException + */ + protected function socialRegisterCallback(string $socialDriver, SocialUser $socialUser) + { + $socialUser = $this->socialAuthService->handleRegistrationCallback($socialDriver, $socialUser); + $socialAccount = $this->socialAuthService->fillSocialAccount($socialDriver, $socialUser); + $emailVerified = $this->socialAuthService->driverAutoConfirmEmailEnabled($socialDriver); + + // Create an array of the user data to create a new user instance + $userData = [ + 'name' => $socialUser->getName(), + 'email' => $socialUser->getEmail(), + 'password' => Str::random(32) + ]; + + $user = $this->registrationService->registerUser($userData, $socialAccount, $emailVerified); + 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 5d9373f45..c61b1c42b 100644 --- a/app/Http/Controllers/Auth/UserInviteController.php +++ b/app/Http/Controllers/Auth/UserInviteController.php @@ -8,11 +8,9 @@ use BookStack\Exceptions\UserTokenExpiredException; use BookStack\Exceptions\UserTokenNotFoundException; use BookStack\Http\Controllers\Controller; use Exception; -use Illuminate\Contracts\View\Factory; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Routing\Redirector; -use Illuminate\View\View; class UserInviteController extends Controller { @@ -21,22 +19,20 @@ class UserInviteController extends Controller /** * Create a new controller instance. - * - * @param UserInviteService $inviteService - * @param UserRepo $userRepo */ public function __construct(UserInviteService $inviteService, UserRepo $userRepo) { + $this->middleware('guest'); + $this->middleware('guard:standard'); + $this->inviteService = $inviteService; $this->userRepo = $userRepo; - $this->middleware('guest'); + parent::__construct(); } /** * Show the page for the user to set the password for their account. - * @param string $token - * @return Factory|View|RedirectResponse * @throws Exception */ public function showSetPassword(string $token) @@ -54,15 +50,12 @@ class UserInviteController extends Controller /** * Sets the password for an invited user and then grants them access. - * @param string $token - * @param Request $request - * @return RedirectResponse|Redirector * @throws Exception */ - public function setPassword(string $token, Request $request) + public function setPassword(Request $request, string $token) { $this->validate($request, [ - 'password' => 'required|min:6' + 'password' => 'required|min:8' ]); try { @@ -77,7 +70,7 @@ class UserInviteController extends Controller $user->save(); auth()->login($user); - session()->flash('success', trans('auth.user_invite_success', ['appName' => setting('app-name')])); + $this->showSuccessNotification(trans('auth.user_invite_success', ['appName' => setting('app-name')])); $this->inviteService->deleteByUser($user); return redirect('/'); @@ -85,7 +78,6 @@ class UserInviteController extends Controller /** * Check and validate the exception thrown when checking an invite token. - * @param Exception $exception * @return RedirectResponse|Redirector * @throws Exception */ @@ -96,11 +88,10 @@ class UserInviteController extends Controller } if ($exception instanceof UserTokenExpiredException) { - session()->flash('error', trans('errors.invite_token_expired')); + $this->showErrorNotification(trans('errors.invite_token_expired')); return redirect('/password/email'); } throw $exception; } - } diff --git a/app/Http/Controllers/BookController.php b/app/Http/Controllers/BookController.php index a990eed9a..e7d788d91 100644 --- a/app/Http/Controllers/BookController.php +++ b/app/Http/Controllers/BookController.php @@ -1,67 +1,46 @@ entityRepo = $entityRepo; - $this->userRepo = $userRepo; - $this->exportService = $exportService; + public function __construct(EntityContext $entityContextManager, BookRepo $bookRepo) + { + $this->bookRepo = $bookRepo; $this->entityContextManager = $entityContextManager; - $this->imageRepo = $imageRepo; parent::__construct(); } /** * Display a listing of the book. - * @return Response */ public function index() { - $view = setting()->getUser($this->currentUser, 'books_view_type', config('app.views.books')); - $sort = setting()->getUser($this->currentUser, 'books_sort', 'name'); - $order = setting()->getUser($this->currentUser, 'books_sort_order', 'asc'); - $sortOptions = [ - 'name' => trans('common.sort_name'), - 'created_at' => trans('common.sort_created_at'), - 'updated_at' => trans('common.sort_updated_at'), - ]; + $view = setting()->getForCurrentUser('books_view_type', config('app.views.books')); + $sort = setting()->getForCurrentUser('books_sort', 'name'); + $order = setting()->getForCurrentUser('books_sort_order', 'asc'); - $books = $this->entityRepo->getAllPaginated('book', 18, $sort, $order); - $recents = $this->signedIn ? $this->entityRepo->getRecentlyViewed('book', 4, 0) : false; - $popular = $this->entityRepo->getPopular('book', 4, 0); - $new = $this->entityRepo->getRecentlyCreated('book', 4, 0); + $books = $this->bookRepo->getAllPaginated(18, $sort, $order); + $recents = $this->isSignedIn() ? $this->bookRepo->getRecentlyViewed(4) : false; + $popular = $this->bookRepo->getPopular(4); + $new = $this->bookRepo->getRecentlyCreated(4); $this->entityContextManager->clearShelfContext(); @@ -74,25 +53,22 @@ class BookController extends Controller 'view' => $view, 'sort' => $sort, 'order' => $order, - 'sortOptions' => $sortOptions, ]); } /** * Show the form for creating a new book. - * @param string $shelfSlug - * @return Response - * @throws \BookStack\Exceptions\NotFoundException */ public function create(string $shelfSlug = null) { + $this->checkPermission('book-create-all'); + $bookshelf = null; if ($shelfSlug !== null) { - $bookshelf = $this->entityRepo->getBySlug('bookshelf', $shelfSlug); + $bookshelf = Bookshelf::visible()->where('slug', '=', $shelfSlug)->firstOrFail(); $this->checkOwnablePermission('bookshelf-update', $bookshelf); } - $this->checkPermission('book-create-all'); $this->setPageTitle(trans('entities.books_create')); return view('books.create', [ 'bookshelf' => $bookshelf @@ -101,12 +77,8 @@ class BookController extends Controller /** * Store a newly created book in storage. - * - * @param Request $request - * @param string $shelfSlug - * @return Response - * @throws \BookStack\Exceptions\NotFoundException - * @throws \BookStack\Exceptions\ImageUploadException + * @throws ImageUploadException + * @throws ValidationException */ public function store(Request $request, string $shelfSlug = null) { @@ -114,21 +86,21 @@ class BookController extends Controller $this->validate($request, [ 'name' => 'required|string|max:255', 'description' => 'string|max:1000', - 'image' => $this->imageRepo->getImageValidationRules(), + 'image' => $this->getImageValidationRules(), ]); $bookshelf = null; if ($shelfSlug !== null) { - $bookshelf = $this->entityRepo->getBySlug('bookshelf', $shelfSlug); + $bookshelf = Bookshelf::visible()->where('slug', '=', $shelfSlug)->firstOrFail(); $this->checkOwnablePermission('bookshelf-update', $bookshelf); } - $book = $this->entityRepo->createFromInput('book', $request->all()); - $this->bookUpdateActions($book, $request); + $book = $this->bookRepo->create($request->all()); + $this->bookRepo->updateCoverImage($book, $request->file('image', null)); Activity::add($book, 'book_create', $book->id); if ($bookshelf) { - $this->entityRepo->appendBookToShelf($bookshelf, $book); + $bookshelf->appendBook($book); Activity::add($bookshelf, 'bookshelf_update'); } @@ -137,17 +109,11 @@ class BookController extends Controller /** * Display the specified book. - * @param $slug - * @param Request $request - * @return Response - * @throws \BookStack\Exceptions\NotFoundException */ - public function show($slug, Request $request) + public function show(Request $request, string $slug) { - $book = $this->entityRepo->getBySlug('book', $slug); - $this->checkOwnablePermission('book-view', $book); - - $bookChildren = $this->entityRepo->getBookChildren($book); + $book = $this->bookRepo->getBySlug($slug); + $bookChildren = (new BookContents($book))->getTree(true); Views::add($book); if ($request->has('shelf')) { @@ -165,12 +131,10 @@ class BookController extends Controller /** * Show the form for editing the specified book. - * @param $slug - * @return Response */ - public function edit($slug) + public function edit(string $slug) { - $book = $this->entityRepo->getBySlug('book', $slug); + $book = $this->bookRepo->getBySlug($slug); $this->checkOwnablePermission('book-update', $book); $this->setPageTitle(trans('entities.books_edit_named', ['bookName'=>$book->getShortName()])); return view('books.edit', ['book' => $book, 'current' => $book]); @@ -178,254 +142,83 @@ class BookController extends Controller /** * Update the specified book in storage. - * @param Request $request - * @param $slug - * @return Response - * @throws \BookStack\Exceptions\ImageUploadException - * @throws \BookStack\Exceptions\NotFoundException + * @throws ImageUploadException + * @throws ValidationException + * @throws Throwable */ public function update(Request $request, string $slug) { - $book = $this->entityRepo->getBySlug('book', $slug); + $book = $this->bookRepo->getBySlug($slug); $this->checkOwnablePermission('book-update', $book); $this->validate($request, [ 'name' => 'required|string|max:255', 'description' => 'string|max:1000', - 'image' => $this->imageRepo->getImageValidationRules(), + 'image' => $this->getImageValidationRules(), ]); - $book = $this->entityRepo->updateFromInput('book', $book, $request->all()); - $this->bookUpdateActions($book, $request); + $book = $this->bookRepo->update($book, $request->all()); + $resetCover = $request->has('image_reset'); + $this->bookRepo->updateCoverImage($book, $request->file('image', null), $resetCover); - Activity::add($book, 'book_update', $book->id); - - return redirect($book->getUrl()); - } - - /** - * Shows the page to confirm deletion - * @param $bookSlug - * @return \Illuminate\View\View - */ - public function showDelete($bookSlug) - { - $book = $this->entityRepo->getBySlug('book', $bookSlug); - $this->checkOwnablePermission('book-delete', $book); - $this->setPageTitle(trans('entities.books_delete_named', ['bookName'=>$book->getShortName()])); - return view('books.delete', ['book' => $book, 'current' => $book]); - } - - /** - * Shows the view which allows pages to be re-ordered and sorted. - * @param string $bookSlug - * @return \Illuminate\View\View - * @throws \BookStack\Exceptions\NotFoundException - */ - public function sort($bookSlug) - { - $book = $this->entityRepo->getBySlug('book', $bookSlug); - $this->checkOwnablePermission('book-update', $book); - - $bookChildren = $this->entityRepo->getBookChildren($book, true); - - $this->setPageTitle(trans('entities.books_sort_named', ['bookName'=>$book->getShortName()])); - return view('books.sort', ['book' => $book, 'current' => $book, 'bookChildren' => $bookChildren]); - } - - /** - * Shows the sort box for a single book. - * Used via AJAX when loading in extra books to a sort. - * @param $bookSlug - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View - */ - public function getSortItem($bookSlug) - { - $book = $this->entityRepo->getBySlug('book', $bookSlug); - $bookChildren = $this->entityRepo->getBookChildren($book); - return view('books.sort-box', ['book' => $book, 'bookChildren' => $bookChildren]); - } - - /** - * Saves an array of sort mapping to pages and chapters. - * @param string $bookSlug - * @param Request $request - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector - */ - public function saveSort($bookSlug, Request $request) - { - $book = $this->entityRepo->getBySlug('book', $bookSlug); - $this->checkOwnablePermission('book-update', $book); - - // Return if no map sent - if (!$request->filled('sort-tree')) { - return redirect($book->getUrl()); - } - - // Sort pages and chapters - $sortMap = collect(json_decode($request->get('sort-tree'))); - $bookIdsInvolved = collect([$book->id]); - - // Load models into map - $sortMap->each(function ($mapItem) use ($bookIdsInvolved) { - $mapItem->type = ($mapItem->type === 'page' ? 'page' : 'chapter'); - $mapItem->model = $this->entityRepo->getById($mapItem->type, $mapItem->id); - // Store source and target books - $bookIdsInvolved->push(intval($mapItem->model->book_id)); - $bookIdsInvolved->push(intval($mapItem->book)); - }); - - // Get the books involved in the sort - $bookIdsInvolved = $bookIdsInvolved->unique()->toArray(); - $booksInvolved = $this->entityRepo->getManyById('book', $bookIdsInvolved, false, true); - // Throw permission error if invalid ids or inaccessible books given. - if (count($bookIdsInvolved) !== count($booksInvolved)) { - $this->showPermissionError(); - } - // Check permissions of involved books - $booksInvolved->each(function (Book $book) { - $this->checkOwnablePermission('book-update', $book); - }); - - // Perform the sort - $sortMap->each(function ($mapItem) { - $model = $mapItem->model; - - $priorityChanged = intval($model->priority) !== intval($mapItem->sort); - $bookChanged = intval($model->book_id) !== intval($mapItem->book); - $chapterChanged = ($mapItem->type === 'page') && intval($model->chapter_id) !== $mapItem->parentChapter; - - if ($bookChanged) { - $this->entityRepo->changeBook($mapItem->type, $mapItem->book, $model); - } - if ($chapterChanged) { - $model->chapter_id = intval($mapItem->parentChapter); - $model->save(); - } - if ($priorityChanged) { - $model->priority = intval($mapItem->sort); - $model->save(); - } - }); - - // Rebuild permissions and add activity for involved books. - $booksInvolved->each(function (Book $book) { - $this->entityRepo->buildJointPermissionsForBook($book); - Activity::add($book, 'book_sort', $book->id); - }); + Activity::add($book, 'book_update', $book->id); return redirect($book->getUrl()); } /** - * Remove the specified book from storage. - * @param $bookSlug - * @return Response + * Shows the page to confirm deletion. */ - public function destroy($bookSlug) + public function showDelete(string $bookSlug) { - $book = $this->entityRepo->getBySlug('book', $bookSlug); + $book = $this->bookRepo->getBySlug($bookSlug); $this->checkOwnablePermission('book-delete', $book); - Activity::addMessage('book_delete', 0, $book->name); + $this->setPageTitle(trans('entities.books_delete_named', ['bookName' => $book->getShortName()])); + return view('books.delete', ['book' => $book, 'current' => $book]); + } - if ($book->cover) { - $this->imageRepo->destroyImage($book->cover); - } - $this->entityRepo->destroyBook($book); + /** + * Remove the specified book from the system. + * @throws Throwable + * @throws NotifyException + */ + public function destroy(string $bookSlug) + { + $book = $this->bookRepo->getBySlug($bookSlug); + $this->checkOwnablePermission('book-delete', $book); + + Activity::addMessage('book_delete', $book->name); + $this->bookRepo->destroy($book); return redirect('/books'); } /** - * Show the Restrictions view. - * @param $bookSlug - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + * Show the permissions view. */ - public function showPermissions($bookSlug) + public function showPermissions(string $bookSlug) { - $book = $this->entityRepo->getBySlug('book', $bookSlug); + $book = $this->bookRepo->getBySlug($bookSlug); $this->checkOwnablePermission('restrictions-manage', $book); - $roles = $this->userRepo->getRestrictableRoles(); + return view('books.permissions', [ 'book' => $book, - 'roles' => $roles ]); } /** * Set the restrictions for this book. - * @param $bookSlug - * @param Request $request - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector - * @throws \BookStack\Exceptions\NotFoundException - * @throws \Throwable + * @throws Throwable */ - public function permissions($bookSlug, Request $request) + public function permissions(Request $request, string $bookSlug) { - $book = $this->entityRepo->getBySlug('book', $bookSlug); + $book = $this->bookRepo->getBySlug($bookSlug); $this->checkOwnablePermission('restrictions-manage', $book); - $this->entityRepo->updateEntityPermissionsFromRequest($request, $book); - session()->flash('success', trans('entities.books_permissions_updated')); + + $restricted = $request->get('restricted') === 'true'; + $permissions = $request->filled('restrictions') ? collect($request->get('restrictions')) : null; + $this->bookRepo->updatePermissions($book, $restricted, $permissions); + + $this->showSuccessNotification(trans('entities.books_permissions_updated')); return redirect($book->getUrl()); } - - /** - * Export a book as a PDF file. - * @param string $bookSlug - * @return mixed - */ - public function exportPdf($bookSlug) - { - $book = $this->entityRepo->getBySlug('book', $bookSlug); - $pdfContent = $this->exportService->bookToPdf($book); - return $this->downloadResponse($pdfContent, $bookSlug . '.pdf'); - } - - /** - * Export a book as a contained HTML file. - * @param string $bookSlug - * @return mixed - */ - public function exportHtml($bookSlug) - { - $book = $this->entityRepo->getBySlug('book', $bookSlug); - $htmlContent = $this->exportService->bookToContainedHtml($book); - return $this->downloadResponse($htmlContent, $bookSlug . '.html'); - } - - /** - * Export a book as a plain text file. - * @param $bookSlug - * @return mixed - */ - public function exportPlainText($bookSlug) - { - $book = $this->entityRepo->getBySlug('book', $bookSlug); - $textContent = $this->exportService->bookToPlainText($book); - return $this->downloadResponse($textContent, $bookSlug . '.txt'); - } - - /** - * Common actions to run on book update. - * Handles updating the cover image. - * @param Book $book - * @param Request $request - * @throws \BookStack\Exceptions\ImageUploadException - */ - protected function bookUpdateActions(Book $book, Request $request) - { - // Update the cover image if in request - if ($request->has('image')) { - $this->imageRepo->destroyImage($book->cover); - $newImage = $request->file('image'); - $image = $this->imageRepo->saveNew($newImage, 'cover_book', $book->id, 512, 512, true); - $book->image_id = $image->id; - $book->save(); - } - - if ($request->has('image_reset')) { - $this->imageRepo->destroyImage($book->cover); - $book->image_id = 0; - $book->save(); - } - } } diff --git a/app/Http/Controllers/BookExportController.php b/app/Http/Controllers/BookExportController.php new file mode 100644 index 000000000..cfa3d6a3a --- /dev/null +++ b/app/Http/Controllers/BookExportController.php @@ -0,0 +1,56 @@ +bookRepo = $bookRepo; + $this->exportService = $exportService; + parent::__construct(); + } + + /** + * Export a book as a PDF file. + * @throws Throwable + */ + public function pdf(string $bookSlug) + { + $book = $this->bookRepo->getBySlug($bookSlug); + $pdfContent = $this->exportService->bookToPdf($book); + return $this->downloadResponse($pdfContent, $bookSlug . '.pdf'); + } + + /** + * Export a book as a contained HTML file. + * @throws Throwable + */ + public function html(string $bookSlug) + { + $book = $this->bookRepo->getBySlug($bookSlug); + $htmlContent = $this->exportService->bookToContainedHtml($book); + return $this->downloadResponse($htmlContent, $bookSlug . '.html'); + } + + /** + * Export a book as a plain text file. + */ + public function plainText(string $bookSlug) + { + $book = $this->bookRepo->getBySlug($bookSlug); + $textContent = $this->exportService->bookToPlainText($book); + return $this->downloadResponse($textContent, $bookSlug . '.txt'); + } +} diff --git a/app/Http/Controllers/BookSortController.php b/app/Http/Controllers/BookSortController.php new file mode 100644 index 000000000..f5fb6f255 --- /dev/null +++ b/app/Http/Controllers/BookSortController.php @@ -0,0 +1,82 @@ +bookRepo = $bookRepo; + parent::__construct(); + } + + /** + * Shows the view which allows pages to be re-ordered and sorted. + */ + public function show(string $bookSlug) + { + $book = $this->bookRepo->getBySlug($bookSlug); + $this->checkOwnablePermission('book-update', $book); + + $bookChildren = (new BookContents($book))->getTree(false); + + $this->setPageTitle(trans('entities.books_sort_named', ['bookName'=>$book->getShortName()])); + return view('books.sort', ['book' => $book, 'current' => $book, 'bookChildren' => $bookChildren]); + } + + /** + * Shows the sort box for a single book. + * Used via AJAX when loading in extra books to a sort. + */ + public function showItem(string $bookSlug) + { + $book = $this->bookRepo->getBySlug($bookSlug); + $bookChildren = (new BookContents($book))->getTree(); + return view('books.sort-box', ['book' => $book, 'bookChildren' => $bookChildren]); + } + + /** + * Sorts a book using a given mapping array. + */ + public function update(Request $request, string $bookSlug) + { + $book = $this->bookRepo->getBySlug($bookSlug); + $this->checkOwnablePermission('book-update', $book); + + // Return if no map sent + if (!$request->filled('sort-tree')) { + return redirect($book->getUrl()); + } + + $sortMap = collect(json_decode($request->get('sort-tree'))); + $bookContents = new BookContents($book); + $booksInvolved = collect(); + + try { + $booksInvolved = $bookContents->sortUsingMap($sortMap); + } catch (SortOperationException $exception) { + $this->showPermissionError(); + } + + // Rebuild permissions and add activity for involved books. + $booksInvolved->each(function (Book $book) { + Activity::add($book, 'book_sort', $book->id); + }); + + return redirect($book->getUrl()); + } +} diff --git a/app/Http/Controllers/BookshelfController.php b/app/Http/Controllers/BookshelfController.php index bcf2e12df..57e67dc00 100644 --- a/app/Http/Controllers/BookshelfController.php +++ b/app/Http/Controllers/BookshelfController.php @@ -1,34 +1,30 @@ entityRepo = $entityRepo; - $this->userRepo = $userRepo; + $this->bookshelfRepo = $bookshelfRepo; $this->entityContextManager = $entityContextManager; $this->imageRepo = $imageRepo; parent::__construct(); @@ -36,27 +32,22 @@ class BookshelfController extends Controller /** * Display a listing of the book. - * @return Response */ public function index() { - $view = setting()->getUser($this->currentUser, 'bookshelves_view_type', config('app.views.bookshelves', 'grid')); - $sort = setting()->getUser($this->currentUser, 'bookshelves_sort', 'name'); - $order = setting()->getUser($this->currentUser, 'bookshelves_sort_order', 'asc'); + $view = setting()->getForCurrentUser('bookshelves_view_type', config('app.views.bookshelves', 'grid')); + $sort = setting()->getForCurrentUser('bookshelves_sort', 'name'); + $order = setting()->getForCurrentUser('bookshelves_sort_order', 'asc'); $sortOptions = [ 'name' => trans('common.sort_name'), 'created_at' => trans('common.sort_created_at'), 'updated_at' => trans('common.sort_updated_at'), ]; - $shelves = $this->entityRepo->getAllPaginated('bookshelf', 18, $sort, $order); - foreach ($shelves as $shelf) { - $shelf->books = $this->entityRepo->getBookshelfChildren($shelf); - } - - $recents = $this->signedIn ? $this->entityRepo->getRecentlyViewed('bookshelf', 4, 0) : false; - $popular = $this->entityRepo->getPopular('bookshelf', 4, 0); - $new = $this->entityRepo->getRecentlyCreated('bookshelf', 4, 0); + $shelves = $this->bookshelfRepo->getAllPaginated(18, $sort, $order); + $recents = $this->isSignedIn() ? $this->bookshelfRepo->getRecentlyViewed(4) : false; + $popular = $this->bookshelfRepo->getPopular(4); + $new = $this->bookshelfRepo->getRecentlyCreated(4); $this->entityContextManager->clearShelfContext(); $this->setPageTitle(trans('entities.shelves')); @@ -74,21 +65,19 @@ class BookshelfController extends Controller /** * Show the form for creating a new bookshelf. - * @return Response */ public function create() { $this->checkPermission('bookshelf-create-all'); - $books = $this->entityRepo->getAll('book', false, 'update'); + $books = Book::hasPermission('update')->get(); $this->setPageTitle(trans('entities.shelves_create')); return view('shelves.create', ['books' => $books]); } /** * Store a newly created bookshelf in storage. - * @param Request $request - * @return Response - * @throws \BookStack\Exceptions\ImageUploadException + * @throws ValidationException + * @throws ImageUploadException */ public function store(Request $request) { @@ -96,80 +85,63 @@ class BookshelfController extends Controller $this->validate($request, [ 'name' => 'required|string|max:255', 'description' => 'string|max:1000', - 'image' => $this->imageRepo->getImageValidationRules(), + 'image' => $this->getImageValidationRules(), ]); - $shelf = $this->entityRepo->createFromInput('bookshelf', $request->all()); - $this->shelfUpdateActions($shelf, $request); + $bookIds = explode(',', $request->get('books', '')); + $shelf = $this->bookshelfRepo->create($request->all(), $bookIds); + $this->bookshelfRepo->updateCoverImage($shelf); Activity::add($shelf, 'bookshelf_create'); return redirect($shelf->getUrl()); } - /** - * Display the specified bookshelf. - * @param String $slug - * @return Response - * @throws \BookStack\Exceptions\NotFoundException + * Display the bookshelf of the given slug. + * @throws NotFoundException */ public function show(string $slug) { - /** @var Bookshelf $shelf */ - $shelf = $this->entityRepo->getBySlug('bookshelf', $slug); + $shelf = $this->bookshelfRepo->getBySlug($slug); $this->checkOwnablePermission('book-view', $shelf); - $books = $this->entityRepo->getBookshelfChildren($shelf); Views::add($shelf); $this->entityContextManager->setShelfContext($shelf->id); $this->setPageTitle($shelf->getShortName()); - return view('shelves.show', [ 'shelf' => $shelf, - 'books' => $books, 'activity' => Activity::entityActivity($shelf, 20, 1) ]); } /** * Show the form for editing the specified bookshelf. - * @param $slug - * @return Response - * @throws \BookStack\Exceptions\NotFoundException */ public function edit(string $slug) { - $shelf = $this->entityRepo->getBySlug('bookshelf', $slug); /** @var $shelf Bookshelf */ + $shelf = $this->bookshelfRepo->getBySlug($slug); $this->checkOwnablePermission('bookshelf-update', $shelf); - $shelfBooks = $this->entityRepo->getBookshelfChildren($shelf); - $shelfBookIds = $shelfBooks->pluck('id'); - $books = $this->entityRepo->getAll('book', false, 'update'); - $books = $books->filter(function ($book) use ($shelfBookIds) { - return !$shelfBookIds->contains($book->id); - }); + $shelfBookIds = $shelf->books()->get(['id'])->pluck('id'); + $books = Book::hasPermission('update')->whereNotIn('id', $shelfBookIds)->get(); $this->setPageTitle(trans('entities.shelves_edit_named', ['name' => $shelf->getShortName()])); return view('shelves.edit', [ 'shelf' => $shelf, 'books' => $books, - 'shelfBooks' => $shelfBooks, ]); } - /** * Update the specified bookshelf in storage. - * @param Request $request - * @param string $slug - * @return Response - * @throws \BookStack\Exceptions\NotFoundException - * @throws \BookStack\Exceptions\ImageUploadException + * @throws ValidationException + * @throws ImageUploadException + * @throws NotFoundException */ public function update(Request $request, string $slug) { - $shelf = $this->entityRepo->getBySlug('bookshelf', $slug); /** @var $bookshelf Bookshelf */ + $shelf = $this->bookshelfRepo->getBySlug($slug); $this->checkOwnablePermission('bookshelf-update', $shelf); $this->validate($request, [ 'name' => 'required|string|max:255', @@ -177,24 +149,22 @@ class BookshelfController extends Controller 'image' => $this->imageRepo->getImageValidationRules(), ]); - $shelf = $this->entityRepo->updateFromInput('bookshelf', $shelf, $request->all()); - $this->shelfUpdateActions($shelf, $request); - Activity::add($shelf, 'bookshelf_update'); + $bookIds = explode(',', $request->get('books', '')); + $shelf = $this->bookshelfRepo->update($shelf, $request->all(), $bookIds); + $resetCover = $request->has('image_reset'); + $this->bookshelfRepo->updateCoverImage($shelf, $request->file('image', null), $resetCover); + Activity::add($shelf, 'bookshelf_update'); - return redirect($shelf->getUrl()); + return redirect($shelf->getUrl()); } - /** * Shows the page to confirm deletion - * @param $slug - * @return \Illuminate\View\View - * @throws \BookStack\Exceptions\NotFoundException */ public function showDelete(string $slug) { - $shelf = $this->entityRepo->getBySlug('bookshelf', $slug); /** @var $shelf Bookshelf */ + $shelf = $this->bookshelfRepo->getBySlug($slug); $this->checkOwnablePermission('bookshelf-delete', $shelf); $this->setPageTitle(trans('entities.shelves_delete_named', ['name' => $shelf->getShortName()])); @@ -203,101 +173,58 @@ class BookshelfController extends Controller /** * Remove the specified bookshelf from storage. - * @param string $slug - * @return Response - * @throws \BookStack\Exceptions\NotFoundException - * @throws \Throwable + * @throws Exception */ public function destroy(string $slug) { - $shelf = $this->entityRepo->getBySlug('bookshelf', $slug); /** @var $shelf Bookshelf */ + $shelf = $this->bookshelfRepo->getBySlug($slug); $this->checkOwnablePermission('bookshelf-delete', $shelf); - Activity::addMessage('bookshelf_delete', 0, $shelf->name); - if ($shelf->cover) { - $this->imageRepo->destroyImage($shelf->cover); - } - $this->entityRepo->destroyBookshelf($shelf); + Activity::addMessage('bookshelf_delete', $shelf->name); + $this->bookshelfRepo->destroy($shelf); return redirect('/shelves'); } /** * Show the permissions view. - * @param string $slug - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View - * @throws \BookStack\Exceptions\NotFoundException */ public function showPermissions(string $slug) { - $shelf = $this->entityRepo->getBySlug('bookshelf', $slug); + $shelf = $this->bookshelfRepo->getBySlug($slug); $this->checkOwnablePermission('restrictions-manage', $shelf); - $roles = $this->userRepo->getRestrictableRoles(); return view('shelves.permissions', [ 'shelf' => $shelf, - 'roles' => $roles ]); } /** * Set the permissions for this bookshelf. - * @param string $slug - * @param Request $request - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector - * @throws \BookStack\Exceptions\NotFoundException - * @throws \Throwable */ - public function permissions(string $slug, Request $request) + public function permissions(Request $request, string $slug) { - $shelf = $this->entityRepo->getBySlug('bookshelf', $slug); + $shelf = $this->bookshelfRepo->getBySlug($slug); $this->checkOwnablePermission('restrictions-manage', $shelf); - $this->entityRepo->updateEntityPermissionsFromRequest($request, $shelf); - session()->flash('success', trans('entities.shelves_permissions_updated')); + $restricted = $request->get('restricted') === 'true'; + $permissions = $request->filled('restrictions') ? collect($request->get('restrictions')) : null; + $this->bookshelfRepo->updatePermissions($shelf, $restricted, $permissions); + + $this->showSuccessNotification(trans('entities.shelves_permissions_updated')); return redirect($shelf->getUrl()); } /** * Copy the permissions of a bookshelf to the child books. - * @param string $slug - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector - * @throws \BookStack\Exceptions\NotFoundException */ public function copyPermissions(string $slug) { - $shelf = $this->entityRepo->getBySlug('bookshelf', $slug); + $shelf = $this->bookshelfRepo->getBySlug($slug); $this->checkOwnablePermission('restrictions-manage', $shelf); - $updateCount = $this->entityRepo->copyBookshelfPermissions($shelf); - session()->flash('success', trans('entities.shelves_copy_permission_success', ['count' => $updateCount])); + $updateCount = $this->bookshelfRepo->copyDownPermissions($shelf); + $this->showSuccessNotification(trans('entities.shelves_copy_permission_success', ['count' => $updateCount])); return redirect($shelf->getUrl()); } - - /** - * Common actions to run on bookshelf update. - * @param Bookshelf $shelf - * @param Request $request - * @throws \BookStack\Exceptions\ImageUploadException - */ - protected function shelfUpdateActions(Bookshelf $shelf, Request $request) - { - // Update the books that the shelf references - $this->entityRepo->updateShelfBooks($shelf, $request->get('books', '')); - - // Update the cover image if in request - if ($request->has('image')) { - $newImage = $request->file('image'); - $this->imageRepo->destroyImage($shelf->cover); - $image = $this->imageRepo->saveNew($newImage, 'cover_shelf', $shelf->id, 512, 512, true); - $shelf->image_id = $image->id; - $shelf->save(); - } - - if ($request->has('image_reset')) { - $this->imageRepo->destroyImage($shelf->cover); - $shelf->image_id = 0; - $shelf->save(); - } - } } diff --git a/app/Http/Controllers/ChapterController.php b/app/Http/Controllers/ChapterController.php index c19e45694..135597910 100644 --- a/app/Http/Controllers/ChapterController.php +++ b/app/Http/Controllers/ChapterController.php @@ -1,83 +1,74 @@ entityRepo = $entityRepo; - $this->userRepo = $userRepo; - $this->exportService = $exportService; + $this->chapterRepo = $chapterRepo; parent::__construct(); } /** * Show the form for creating a new chapter. - * @param $bookSlug - * @return Response */ - public function create($bookSlug) + public function create(string $bookSlug) { - $book = $this->entityRepo->getBySlug('book', $bookSlug); + $book = Book::visible()->where('slug', '=', $bookSlug)->firstOrFail(); $this->checkOwnablePermission('chapter-create', $book); + $this->setPageTitle(trans('entities.chapters_create')); return view('chapters.create', ['book' => $book, 'current' => $book]); } /** * Store a newly created chapter in storage. - * @param $bookSlug - * @param Request $request - * @return Response + * @throws ValidationException */ - public function store($bookSlug, Request $request) + public function store(Request $request, string $bookSlug) { $this->validate($request, [ 'name' => 'required|string|max:255' ]); - $book = $this->entityRepo->getBySlug('book', $bookSlug); + $book = Book::visible()->where('slug', '=', $bookSlug)->firstOrFail(); $this->checkOwnablePermission('chapter-create', $book); - $input = $request->all(); - $input['priority'] = $this->entityRepo->getNewBookPriority($book); - $chapter = $this->entityRepo->createFromInput('chapter', $input, $book); + $chapter = $this->chapterRepo->create($request->all(), $book); Activity::add($chapter, 'chapter_create', $book->id); + return redirect($chapter->getUrl()); } /** * Display the specified chapter. - * @param $bookSlug - * @param $chapterSlug - * @return Response */ - public function show($bookSlug, $chapterSlug) + public function show(string $bookSlug, string $chapterSlug) { - $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); + $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $this->checkOwnablePermission('chapter-view', $chapter); - $sidebarTree = $this->entityRepo->getBookChildren($chapter->book); + + $sidebarTree = (new BookContents($chapter->book))->getTree(); + $pages = $chapter->getVisiblePages(); Views::add($chapter); + $this->setPageTitle($chapter->getShortName()); - $pages = $this->entityRepo->getChapterChildren($chapter); return view('chapters.show', [ 'book' => $chapter->book, 'chapter' => $chapter, @@ -89,79 +80,71 @@ class ChapterController extends Controller /** * Show the form for editing the specified chapter. - * @param $bookSlug - * @param $chapterSlug - * @return Response */ - public function edit($bookSlug, $chapterSlug) + public function edit(string $bookSlug, string $chapterSlug) { - $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); + $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $this->checkOwnablePermission('chapter-update', $chapter); + $this->setPageTitle(trans('entities.chapters_edit_named', ['chapterName' => $chapter->getShortName()])); return view('chapters.edit', ['book' => $chapter->book, 'chapter' => $chapter, 'current' => $chapter]); } /** * Update the specified chapter in storage. - * @param Request $request - * @param $bookSlug - * @param $chapterSlug - * @return Response - * @throws \BookStack\Exceptions\NotFoundException + * @throws NotFoundException */ - public function update(Request $request, $bookSlug, $chapterSlug) + public function update(Request $request, string $bookSlug, string $chapterSlug) { - $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); + $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $this->checkOwnablePermission('chapter-update', $chapter); - $this->entityRepo->updateFromInput('chapter', $chapter, $request->all()); + $this->chapterRepo->update($chapter, $request->all()); Activity::add($chapter, 'chapter_update', $chapter->book->id); + return redirect($chapter->getUrl()); } /** * Shows the page to confirm deletion of this chapter. - * @param $bookSlug - * @param $chapterSlug - * @return \Illuminate\View\View + * @throws NotFoundException */ - public function showDelete($bookSlug, $chapterSlug) + public function showDelete(string $bookSlug, string $chapterSlug) { - $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); + $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $this->checkOwnablePermission('chapter-delete', $chapter); + $this->setPageTitle(trans('entities.chapters_delete_named', ['chapterName' => $chapter->getShortName()])); return view('chapters.delete', ['book' => $chapter->book, 'chapter' => $chapter, 'current' => $chapter]); } /** * Remove the specified chapter from storage. - * @param $bookSlug - * @param $chapterSlug - * @return Response + * @throws NotFoundException + * @throws Throwable */ - public function destroy($bookSlug, $chapterSlug) + public function destroy(string $bookSlug, string $chapterSlug) { - $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); - $book = $chapter->book; + $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $this->checkOwnablePermission('chapter-delete', $chapter); - Activity::addMessage('chapter_delete', $book->id, $chapter->name); - $this->entityRepo->destroyChapter($chapter); - return redirect($book->getUrl()); + + Activity::addMessage('chapter_delete', $chapter->name, $chapter->book->id); + $this->chapterRepo->destroy($chapter); + + return redirect($chapter->book->getUrl()); } /** * Show the page for moving a chapter. - * @param $bookSlug - * @param $chapterSlug - * @return mixed - * @throws \BookStack\Exceptions\NotFoundException + * @throws NotFoundException */ - public function showMove($bookSlug, $chapterSlug) + public function showMove(string $bookSlug, string $chapterSlug) { - $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); + $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $this->setPageTitle(trans('entities.chapters_move_named', ['chapterName' => $chapter->getShortName()])); $this->checkOwnablePermission('chapter-update', $chapter); $this->checkOwnablePermission('chapter-delete', $chapter); + return view('chapters.move', [ 'chapter' => $chapter, 'book' => $chapter->book @@ -170,15 +153,11 @@ class ChapterController extends Controller /** * Perform the move action for a chapter. - * @param $bookSlug - * @param $chapterSlug - * @param Request $request - * @return mixed - * @throws \BookStack\Exceptions\NotFoundException + * @throws NotFoundException */ - public function move($bookSlug, $chapterSlug, Request $request) + public function move(Request $request, string $bookSlug, string $chapterSlug) { - $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); + $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $this->checkOwnablePermission('chapter-update', $chapter); $this->checkOwnablePermission('chapter-delete', $chapter); @@ -187,100 +166,47 @@ class ChapterController extends Controller return redirect($chapter->getUrl()); } - $stringExploded = explode(':', $entitySelection); - $entityType = $stringExploded[0]; - $entityId = intval($stringExploded[1]); - - $parent = false; - - if ($entityType == 'book') { - $parent = $this->entityRepo->getById('book', $entityId); - } - - if ($parent === false || $parent === null) { - session()->flash('error', trans('errors.selected_book_not_found')); + try { + $newBook = $this->chapterRepo->move($chapter, $entitySelection); + } catch (MoveOperationException $exception) { + $this->showErrorNotification(trans('errors.selected_book_not_found')); return redirect()->back(); } - $this->entityRepo->changeBook('chapter', $parent->id, $chapter, true); - Activity::add($chapter, 'chapter_move', $chapter->book->id); - session()->flash('success', trans('entities.chapter_move_success', ['bookName' => $parent->name])); + Activity::add($chapter, 'chapter_move', $newBook->id); + $this->showSuccessNotification(trans('entities.chapter_move_success', ['bookName' => $newBook->name])); return redirect($chapter->getUrl()); } /** * Show the Restrictions view. - * @param $bookSlug - * @param $chapterSlug - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View - * @throws \BookStack\Exceptions\NotFoundException + * @throws NotFoundException */ - public function showPermissions($bookSlug, $chapterSlug) + public function showPermissions(string $bookSlug, string $chapterSlug) { - $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); + $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $this->checkOwnablePermission('restrictions-manage', $chapter); - $roles = $this->userRepo->getRestrictableRoles(); + return view('chapters.permissions', [ 'chapter' => $chapter, - 'roles' => $roles ]); } /** * Set the restrictions for this chapter. - * @param $bookSlug - * @param $chapterSlug - * @param Request $request - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector - * @throws \BookStack\Exceptions\NotFoundException - * @throws \Throwable + * @throws NotFoundException */ - public function permissions($bookSlug, $chapterSlug, Request $request) + public function permissions(Request $request, string $bookSlug, string $chapterSlug) { - $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); + $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $this->checkOwnablePermission('restrictions-manage', $chapter); - $this->entityRepo->updateEntityPermissionsFromRequest($request, $chapter); - session()->flash('success', trans('entities.chapters_permissions_success')); + + $restricted = $request->get('restricted') === 'true'; + $permissions = $request->filled('restrictions') ? collect($request->get('restrictions')) : null; + $this->chapterRepo->updatePermissions($chapter, $restricted, $permissions); + + $this->showSuccessNotification(trans('entities.chapters_permissions_success')); return redirect($chapter->getUrl()); } - - /** - * Exports a chapter to pdf . - * @param string $bookSlug - * @param string $chapterSlug - * @return \Illuminate\Http\Response - */ - public function exportPdf($bookSlug, $chapterSlug) - { - $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); - $pdfContent = $this->exportService->chapterToPdf($chapter); - return $this->downloadResponse($pdfContent, $chapterSlug . '.pdf'); - } - - /** - * Export a chapter to a self-contained HTML file. - * @param string $bookSlug - * @param string $chapterSlug - * @return \Illuminate\Http\Response - */ - public function exportHtml($bookSlug, $chapterSlug) - { - $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); - $containedHtml = $this->exportService->chapterToContainedHtml($chapter); - return $this->downloadResponse($containedHtml, $chapterSlug . '.html'); - } - - /** - * Export a chapter to a simple plaintext .txt file. - * @param string $bookSlug - * @param string $chapterSlug - * @return \Illuminate\Http\Response - */ - public function exportPlainText($bookSlug, $chapterSlug) - { - $chapter = $this->entityRepo->getBySlug('chapter', $chapterSlug, $bookSlug); - $chapterText = $this->exportService->chapterToPlainText($chapter); - return $this->downloadResponse($chapterText, $chapterSlug . '.txt'); - } } diff --git a/app/Http/Controllers/ChapterExportController.php b/app/Http/Controllers/ChapterExportController.php new file mode 100644 index 000000000..0c86f8548 --- /dev/null +++ b/app/Http/Controllers/ChapterExportController.php @@ -0,0 +1,58 @@ +chapterRepo = $chapterRepo; + $this->exportService = $exportService; + parent::__construct(); + } + + /** + * Exports a chapter to pdf. + * @throws NotFoundException + * @throws Throwable + */ + public function pdf(string $bookSlug, string $chapterSlug) + { + $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); + $pdfContent = $this->exportService->chapterToPdf($chapter); + return $this->downloadResponse($pdfContent, $chapterSlug . '.pdf'); + } + + /** + * Export a chapter to a self-contained HTML file. + * @throws NotFoundException + * @throws Throwable + */ + public function html(string $bookSlug, string $chapterSlug) + { + $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); + $containedHtml = $this->exportService->chapterToContainedHtml($chapter); + return $this->downloadResponse($containedHtml, $chapterSlug . '.html'); + } + + /** + * Export a chapter to a simple plaintext .txt file. + * @throws NotFoundException + */ + public function plainText(string $bookSlug, string $chapterSlug) + { + $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); + $chapterText = $this->exportService->chapterToPlainText($chapter); + return $this->downloadResponse($chapterText, $chapterSlug . '.txt'); + } +} diff --git a/app/Http/Controllers/CommentController.php b/app/Http/Controllers/CommentController.php index 860b50762..068358d72 100644 --- a/app/Http/Controllers/CommentController.php +++ b/app/Http/Controllers/CommentController.php @@ -2,44 +2,36 @@ use Activity; use BookStack\Actions\CommentRepo; -use BookStack\Entities\Repos\EntityRepo; -use Illuminate\Database\Eloquent\ModelNotFoundException; +use BookStack\Entities\Page; use Illuminate\Http\Request; +use Illuminate\Validation\ValidationException; class CommentController extends Controller { - protected $entityRepo; protected $commentRepo; /** * CommentController constructor. - * @param \BookStack\Entities\Repos\EntityRepo $entityRepo - * @param \BookStack\Actions\CommentRepo $commentRepo */ - public function __construct(EntityRepo $entityRepo, CommentRepo $commentRepo) + public function __construct(CommentRepo $commentRepo) { - $this->entityRepo = $entityRepo; $this->commentRepo = $commentRepo; parent::__construct(); } /** * Save a new comment for a Page - * @param Request $request - * @param integer $pageId - * @param null|integer $commentId - * @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response + * @throws ValidationException */ - public function savePageComment(Request $request, $pageId, $commentId = null) + public function savePageComment(Request $request, int $pageId, int $commentId = null) { $this->validate($request, [ 'text' => 'required|string', 'html' => 'required|string', ]); - try { - $page = $this->entityRepo->getById('page', $pageId, true); - } catch (ModelNotFoundException $e) { + $page = Page::visible()->find($pageId); + if ($page === null) { return response('Not found', 404); } @@ -59,11 +51,9 @@ class CommentController extends Controller /** * Update an existing comment. - * @param Request $request - * @param integer $commentId - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + * @throws ValidationException */ - public function update(Request $request, $commentId) + public function update(Request $request, int $commentId) { $this->validate($request, [ 'text' => 'required|string', @@ -80,13 +70,12 @@ class CommentController extends Controller /** * Delete a comment from the system. - * @param integer $id - * @return \Illuminate\Http\JsonResponse */ - public function destroy($id) + public function destroy(int $id) { $comment = $this->commentRepo->getById($id); $this->checkOwnablePermission('comment-delete', $comment); + $this->commentRepo->delete($comment); return response()->json(['message' => trans('entities.comment_deleted')]); } diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 5bc62c601..b9576f2fe 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -2,7 +2,6 @@ namespace BookStack\Http\Controllers; -use BookStack\Auth\User; use BookStack\Ownable; use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Foundation\Validation\ValidatesRequests; @@ -14,42 +13,27 @@ abstract class Controller extends BaseController { use DispatchesJobs, ValidatesRequests; - /** - * @var User static - */ - protected $currentUser; - /** - * @var bool - */ - protected $signedIn; - /** * Controller constructor. */ public function __construct() { - $this->middleware(function ($request, $next) { + // + } - // Get a user instance for the current user - $user = user(); - - // Share variables with controllers - $this->currentUser = $user; - $this->signedIn = auth()->check(); - - // Share variables with views - view()->share('signedIn', $this->signedIn); - view()->share('currentUser', $user); - - return $next($request); - }); + /** + * Check if the current user is signed in. + */ + protected function isSignedIn(): bool + { + return auth()->check(); } /** * Stops the application and shows a permission error if * the application is in demo mode. */ - protected function preventAccessForDemoUsers() + protected function preventAccessInDemoMode() { if (config('app.env') === 'demo') { $this->showPermissionError(); @@ -75,7 +59,7 @@ abstract class Controller extends BaseController $response = response()->json(['error' => trans('errors.permissionJson')], 403); } else { $response = redirect('/'); - session()->flash('error', trans('errors.permission')); + $this->showErrorNotification(trans('errors.permission')); } throw new HttpResponseException($response); @@ -133,7 +117,7 @@ abstract class Controller extends BaseController protected function checkPermissionOrCurrentUser(string $permissionName, int $userId) { return $this->checkPermissionOr($permissionName, function () use ($userId) { - return $userId === $this->currentUser->id; + return $userId === user()->id; }); } @@ -145,7 +129,7 @@ abstract class Controller extends BaseController */ protected function jsonError($messageText = "", $statusCode = 500) { - return response()->json(['message' => $messageText], $statusCode); + return response()->json(['message' => $messageText, 'status' => 'error'], $statusCode); } /** @@ -178,4 +162,39 @@ abstract class Controller extends BaseController 'Content-Disposition' => 'attachment; filename="' . $fileName . '"' ]); } + + /** + * Show a positive, successful notification to the user on next view load. + * @param string $message + */ + protected function showSuccessNotification(string $message) + { + session()->flash('success', $message); + } + + /** + * Show a warning notification to the user on next view load. + * @param string $message + */ + protected function showWarningNotification(string $message) + { + session()->flash('warning', $message); + } + + /** + * Show an error notification to the user on next view load. + * @param string $message + */ + protected function showErrorNotification(string $message) + { + session()->flash('error', $message); + } + + /** + * Get the validation rules for image files. + */ + protected function getImageValidationRules(): string + { + return 'image_extension|no_double_extension|mimes:jpeg,png,gif,bmp,webp,tiff'; + } } diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index d2c75f956..260952fd1 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -1,23 +1,16 @@ entityRepo = $entityRepo; - parent::__construct(); - } /** * Display the homepage. @@ -26,10 +19,20 @@ class HomeController extends Controller public function index() { $activity = Activity::latest(10); - $draftPages = $this->signedIn ? $this->entityRepo->getUserDraftPages(6) : []; + $draftPages = []; + + if ($this->isSignedIn()) { + $draftPages = Page::visible()->where('draft', '=', true) + ->where('created_by', '=', user()->id) + ->orderBy('updated_at', 'desc')->take(6)->get(); + } + $recentFactor = count($draftPages) > 0 ? 0.5 : 1; - $recents = $this->signedIn ? Views::getUserRecentlyViewed(12*$recentFactor, 0) : $this->entityRepo->getRecentlyCreated('book', 12*$recentFactor); - $recentlyUpdatedPages = $this->entityRepo->getRecentlyUpdated('page', 12); + $recents = $this->isSignedIn() ? + Views::getUserRecentlyViewed(12*$recentFactor, 0) + : Book::visible()->orderBy('created_at', 'desc')->take(12 * $recentFactor)->get(); + $recentlyUpdatedPages = Page::visible()->where('draft', false) + ->orderBy('updated_at', 'desc')->take(12)->get(); $homepageOptions = ['default', 'books', 'bookshelves', 'page']; $homepageOption = setting('app-homepage-type', 'default'); @@ -47,9 +50,9 @@ class HomeController extends Controller // Add required list ordering & sorting for books & shelves views. if ($homepageOption === 'bookshelves' || $homepageOption === 'books') { $key = $homepageOption; - $view = setting()->getUser($this->currentUser, $key . '_view_type', config('app.views.' . $key)); - $sort = setting()->getUser($this->currentUser, $key . '_sort', 'name'); - $order = setting()->getUser($this->currentUser, $key . '_sort_order', 'asc'); + $view = setting()->getForCurrentUser($key . '_view_type', config('app.views.' . $key)); + $sort = setting()->getForCurrentUser($key . '_sort', 'name'); + $order = setting()->getForCurrentUser($key . '_sort_order', 'asc'); $sortOptions = [ 'name' => trans('common.sort_name'), @@ -66,16 +69,18 @@ class HomeController extends Controller } if ($homepageOption === 'bookshelves') { - $shelves = $this->entityRepo->getAllPaginated('bookshelf', 18, $commonData['sort'], $commonData['order']); + $shelfRepo = app(BookshelfRepo::class); + $shelves = app(BookshelfRepo::class)->getAllPaginated(18, $commonData['sort'], $commonData['order']); foreach ($shelves as $shelf) { - $shelf->books = $this->entityRepo->getBookshelfChildren($shelf); + $shelf->books = $shelf->visibleBooks; } $data = array_merge($commonData, ['shelves' => $shelves]); return view('common.home-shelves', $data); } if ($homepageOption === 'books') { - $books = $this->entityRepo->getAllPaginated('book', 18, $commonData['sort'], $commonData['order']); + $bookRepo = app(BookRepo::class); + $books = $bookRepo->getAllPaginated(18, $commonData['sort'], $commonData['order']); $data = array_merge($commonData, ['books' => $books]); return view('common.home-book', $data); } @@ -83,8 +88,9 @@ class HomeController extends Controller if ($homepageOption === 'page') { $homepageSetting = setting('app-homepage', '0:'); $id = intval(explode(':', $homepageSetting)[0]); - $customHomepage = $this->entityRepo->getById('page', $id, false, true); - $this->entityRepo->renderPage($customHomepage, true); + $customHomepage = Page::query()->where('draft', '=', false)->findOrFail($id); + $pageContent = new PageContent($customHomepage); + $customHomepage->html = $pageContent->render(true); return view('common.home-custom', array_merge($commonData, ['customHomepage' => $customHomepage])); } diff --git a/app/Http/Controllers/Images/ImageController.php b/app/Http/Controllers/Images/ImageController.php index 024003f87..9c67704dd 100644 --- a/app/Http/Controllers/Images/ImageController.php +++ b/app/Http/Controllers/Images/ImageController.php @@ -1,6 +1,6 @@ validate($request, [ 'name' => 'required|min:2|string' @@ -69,16 +69,21 @@ class ImageController extends Controller /** * Show the usage of an image on pages. - * @param \BookStack\Entities\Repos\EntityRepo $entityRepo - * @param $id - * @return \Illuminate\Http\JsonResponse */ - public function usage(EntityRepo $entityRepo, $id) + public function usage(int $id) { $image = $this->imageRepo->getById($id); $this->checkImagePermission($image); - $pageSearch = $entityRepo->searchForImage($image->url); - return response()->json($pageSearch); + + $pages = Page::visible()->where('html', 'like', '%' . $image->url . '%')->get(['id', 'name', 'slug', 'book_id']); + foreach ($pages as $page) { + $page->url = $page->getUrl(); + $page->html = ''; + $page->text = ''; + } + $result = count($pages) > 0 ? $pages : false; + + return response()->json($result); } /** diff --git a/app/Http/Controllers/PageController.php b/app/Http/Controllers/PageController.php index ad1e32665..b216c19a8 100644 --- a/app/Http/Controllers/PageController.php +++ b/app/Http/Controllers/PageController.php @@ -1,61 +1,46 @@ pageRepo = $pageRepo; - $this->exportService = $exportService; - $this->userRepo = $userRepo; parent::__construct(); } /** * Show the form for creating a new page. - * @param string $bookSlug - * @param string $chapterSlug - * @return Response - * @internal param bool $pageSlug - * @throws NotFoundException + * @throws Throwable */ - public function create($bookSlug, $chapterSlug = null) + public function create(string $bookSlug, string $chapterSlug = null) { - if ($chapterSlug !== null) { - $chapter = $this->pageRepo->getBySlug('chapter', $chapterSlug, $bookSlug); - $book = $chapter->book; - } else { - $chapter = null; - $book = $this->pageRepo->getBySlug('book', $bookSlug); - } - - $parent = $chapter ? $chapter : $book; + $parent = $this->pageRepo->getParentFromSlugs($bookSlug, $chapterSlug); $this->checkOwnablePermission('page-create', $parent); // Redirect to draft edit screen if signed in - if ($this->signedIn) { - $draft = $this->pageRepo->getDraftPage($book, $chapter); + if ($this->isSignedIn()) { + $draft = $this->pageRepo->getNewDraftPage($parent); return redirect($draft->getUrl()); } @@ -66,51 +51,38 @@ class PageController extends Controller /** * Create a new page as a guest user. - * @param Request $request - * @param string $bookSlug - * @param string|null $chapterSlug - * @return mixed - * @throws NotFoundException + * @throws ValidationException */ - public function createAsGuest(Request $request, $bookSlug, $chapterSlug = null) + public function createAsGuest(Request $request, string $bookSlug, string $chapterSlug = null) { $this->validate($request, [ 'name' => 'required|string|max:255' ]); - if ($chapterSlug !== null) { - $chapter = $this->pageRepo->getBySlug('chapter', $chapterSlug, $bookSlug); - $book = $chapter->book; - } else { - $chapter = null; - $book = $this->pageRepo->getBySlug('book', $bookSlug); - } - - $parent = $chapter ? $chapter : $book; + $parent = $this->pageRepo->getParentFromSlugs($bookSlug, $chapterSlug); $this->checkOwnablePermission('page-create', $parent); - $page = $this->pageRepo->getDraftPage($book, $chapter); - $this->pageRepo->publishPageDraft($page, [ + $page = $this->pageRepo->getNewDraftPage($parent); + $this->pageRepo->publishDraft($page, [ 'name' => $request->get('name'), 'html' => '' ]); + return redirect($page->getUrl('/edit')); } /** * Show form to continue editing a draft page. - * @param string $bookSlug - * @param int $pageId - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + * @throws NotFoundException */ - public function editDraft($bookSlug, $pageId) + public function editDraft(string $bookSlug, int $pageId) { - $draft = $this->pageRepo->getById('page', $pageId, true); - $this->checkOwnablePermission('page-create', $draft->parent); + $draft = $this->pageRepo->getById($pageId); + $this->checkOwnablePermission('page-create', $draft->parent()); $this->setPageTitle(trans('entities.pages_edit_draft')); - $draftsEnabled = $this->signedIn; - $templates = $this->pageRepo->getPageTemplates(10); + $draftsEnabled = $this->isSignedIn(); + $templates = $this->pageRepo->getTemplates(10); return view('pages.edit', [ 'page' => $draft, @@ -123,63 +95,50 @@ class PageController extends Controller /** * Store a new page by changing a draft into a page. - * @param Request $request - * @param string $bookSlug - * @param int $pageId - * @return Response + * @throws NotFoundException + * @throws ValidationException */ - public function store(Request $request, $bookSlug, $pageId) + public function store(Request $request, string $bookSlug, int $pageId) { $this->validate($request, [ 'name' => 'required|string|max:255' ]); + $draftPage = $this->pageRepo->getById($pageId); + $this->checkOwnablePermission('page-create', $draftPage->parent()); - $input = $request->all(); - $draftPage = $this->pageRepo->getById('page', $pageId, true); - $book = $draftPage->book; + $page = $this->pageRepo->publishDraft($draftPage, $request->all()); + Activity::add($page, 'page_create', $draftPage->book->id); - $parent = $draftPage->parent; - $this->checkOwnablePermission('page-create', $parent); - - if ($parent->isA('chapter')) { - $input['priority'] = $this->pageRepo->getNewChapterPriority($parent); - } else { - $input['priority'] = $this->pageRepo->getNewBookPriority($parent); - } - - $page = $this->pageRepo->publishPageDraft($draftPage, $input); - - Activity::add($page, 'page_create', $book->id); return redirect($page->getUrl()); } /** * Display the specified page. * If the page is not found via the slug the revisions are searched for a match. - * @param string $bookSlug - * @param string $pageSlug - * @return Response * @throws NotFoundException */ - public function show($bookSlug, $pageSlug) + public function show(string $bookSlug, string $pageSlug) { try { - $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); + $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); } catch (NotFoundException $e) { - $page = $this->pageRepo->getPageByOldSlug($pageSlug, $bookSlug); + $page = $this->pageRepo->getByOldSlug($bookSlug, $pageSlug); + if ($page === null) { throw $e; } + return redirect($page->getUrl()); } $this->checkOwnablePermission('page-view', $page); - $page->html = $this->pageRepo->renderPage($page); - $sidebarTree = $this->pageRepo->getBookChildren($page->book); - $pageNav = $this->pageRepo->getPageNav($page->html); + $pageContent = (new PageContent($page)); + $page->html = $pageContent->render(); + $sidebarTree = (new BookContents($page->book))->getTree(); + $pageNav = $pageContent->getNavigation($page->html); - // check if the comment's are enabled + // Check if page comments are enabled $commentsEnabled = !setting('app-disable-comments'); if ($commentsEnabled) { $page->load(['comments.createdBy']); @@ -188,7 +147,8 @@ class PageController extends Controller Views::add($page); $this->setPageTitle($page->getShortName()); return view('pages.show', [ - 'page' => $page,'book' => $page->book, + 'page' => $page, + 'book' => $page->book, 'current' => $page, 'sidebarTree' => $sidebarTree, 'commentsEnabled' => $commentsEnabled, @@ -198,52 +158,47 @@ class PageController extends Controller /** * Get page from an ajax request. - * @param int $pageId - * @return \Illuminate\Http\JsonResponse + * @throws NotFoundException */ - public function getPageAjax($pageId) + public function getPageAjax(int $pageId) { - $page = $this->pageRepo->getById('page', $pageId); + $page = $this->pageRepo->getById($pageId); return response()->json($page); } /** * Show the form for editing the specified page. - * @param string $bookSlug - * @param string $pageSlug - * @return Response * @throws NotFoundException */ - public function edit($bookSlug, $pageSlug) + public function edit(string $bookSlug, string $pageSlug) { - $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); + $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); $this->checkOwnablePermission('page-update', $page); - $this->setPageTitle(trans('entities.pages_editing_named', ['pageName'=>$page->getShortName()])); + $page->isDraft = false; + $editActivity = new PageEditActivity($page); // Check for active editing $warnings = []; - if ($this->pageRepo->isPageEditingActive($page, 60)) { - $warnings[] = $this->pageRepo->getPageEditingActiveMessage($page, 60); + if ($editActivity->hasActiveEditing()) { + $warnings[] = $editActivity->activeEditingMessage(); } // Check for a current draft version for this user - $userPageDraft = $this->pageRepo->getUserPageDraft($page, $this->currentUser->id); - if ($userPageDraft !== null) { - $page->name = $userPageDraft->name; - $page->html = $userPageDraft->html; - $page->markdown = $userPageDraft->markdown; + $userDraft = $this->pageRepo->getUserDraft($page); + if ($userDraft !== null) { + $page->forceFill($userDraft->only(['name', 'html', 'markdown'])); $page->isDraft = true; - $warnings [] = $this->pageRepo->getUserPageDraftMessage($userPageDraft); + $warnings[] = $editActivity->getEditingActiveDraftMessage($userDraft); } if (count($warnings) > 0) { - session()->flash('warning', implode("\n", $warnings)); + $this->showWarningNotification(implode("\n", $warnings)); } - $draftsEnabled = $this->signedIn; - $templates = $this->pageRepo->getPageTemplates(10); - + $templates = $this->pageRepo->getTemplates(10); + $draftsEnabled = $this->isSignedIn(); + $this->setPageTitle(trans('entities.pages_editing_named', ['pageName' => $page->getShortName()])); return view('pages.edit', [ 'page' => $page, 'book' => $page->book, @@ -255,39 +210,34 @@ class PageController extends Controller /** * Update the specified page in storage. - * @param Request $request - * @param string $bookSlug - * @param string $pageSlug - * @return Response + * @throws ValidationException + * @throws NotFoundException */ - public function update(Request $request, $bookSlug, $pageSlug) + public function update(Request $request, string $bookSlug, string $pageSlug) { $this->validate($request, [ 'name' => 'required|string|max:255' ]); - $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); + $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); $this->checkOwnablePermission('page-update', $page); - $this->pageRepo->updatePage($page, $page->book->id, $request->all()); + + $this->pageRepo->update($page, $request->all()); Activity::add($page, 'page_update', $page->book->id); + return redirect($page->getUrl()); } /** * Save a draft update as a revision. - * @param Request $request - * @param int $pageId - * @return \Illuminate\Http\JsonResponse + * @throws NotFoundException */ - public function saveDraft(Request $request, $pageId) + public function saveDraft(Request $request, int $pageId) { - $page = $this->pageRepo->getById('page', $pageId, true); + $page = $this->pageRepo->getById($pageId); $this->checkOwnablePermission('page-update', $page); - if (!$this->signedIn) { - return response()->json([ - 'status' => 'error', - 'message' => trans('errors.guests_cannot_save_drafts'), - ], 500); + if (!$this->isSignedIn()) { + return $this->jsonError(trans('errors.guests_cannot_save_drafts'), 500); } $draft = $this->pageRepo->updatePageDraft($page, $request->only(['name', 'html', 'markdown'])); @@ -301,253 +251,99 @@ class PageController extends Controller } /** - * Redirect from a special link url which - * uses the page id rather than the name. - * @param int $pageId - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + * Redirect from a special link url which uses the page id rather than the name. + * @throws NotFoundException */ - public function redirectFromLink($pageId) + public function redirectFromLink(int $pageId) { - $page = $this->pageRepo->getById('page', $pageId); + $page = $this->pageRepo->getById($pageId); return redirect($page->getUrl()); } /** * Show the deletion page for the specified page. - * @param string $bookSlug - * @param string $pageSlug - * @return \Illuminate\View\View + * @throws NotFoundException */ - public function showDelete($bookSlug, $pageSlug) + public function showDelete(string $bookSlug, string $pageSlug) { - $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); + $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); $this->checkOwnablePermission('page-delete', $page); $this->setPageTitle(trans('entities.pages_delete_named', ['pageName'=>$page->getShortName()])); - return view('pages.delete', ['book' => $page->book, 'page' => $page, 'current' => $page]); + return view('pages.delete', [ + 'book' => $page->book, + 'page' => $page, + 'current' => $page + ]); } - /** * Show the deletion page for the specified page. - * @param string $bookSlug - * @param int $pageId - * @return \Illuminate\View\View * @throws NotFoundException */ - public function showDeleteDraft($bookSlug, $pageId) + public function showDeleteDraft(string $bookSlug, int $pageId) { - $page = $this->pageRepo->getById('page', $pageId, true); + $page = $this->pageRepo->getById($pageId); $this->checkOwnablePermission('page-update', $page); $this->setPageTitle(trans('entities.pages_delete_draft_named', ['pageName'=>$page->getShortName()])); - return view('pages.delete', ['book' => $page->book, 'page' => $page, 'current' => $page]); + return view('pages.delete', [ + 'book' => $page->book, + 'page' => $page, + 'current' => $page + ]); } /** * Remove the specified page from storage. - * @param string $bookSlug - * @param string $pageSlug - * @return Response - * @internal param int $id + * @throws NotFoundException + * @throws Throwable + * @throws NotifyException */ - public function destroy($bookSlug, $pageSlug) + public function destroy(string $bookSlug, string $pageSlug) { - $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); - $book = $page->book; + $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); $this->checkOwnablePermission('page-delete', $page); - $this->pageRepo->destroyPage($page); - Activity::addMessage('page_delete', $book->id, $page->name); - session()->flash('success', trans('entities.pages_delete_success')); - return redirect($book->getUrl()); + $book = $page->book; + $parent = $page->chapter ?? $book; + $this->pageRepo->destroy($page); + Activity::addMessage('page_delete', $page->name, $book->id); + + $this->showSuccessNotification(trans('entities.pages_delete_success')); + return redirect($parent->getUrl()); } /** * Remove the specified draft page from storage. - * @param string $bookSlug - * @param int $pageId - * @return Response * @throws NotFoundException + * @throws NotifyException + * @throws Throwable */ - public function destroyDraft($bookSlug, $pageId) + public function destroyDraft(string $bookSlug, int $pageId) { - $page = $this->pageRepo->getById('page', $pageId, true); + $page = $this->pageRepo->getById($pageId); $book = $page->book; + $chapter = $page->chapter; $this->checkOwnablePermission('page-update', $page); - session()->flash('success', trans('entities.pages_delete_draft_success')); - $this->pageRepo->destroyPage($page); + + $this->pageRepo->destroy($page); + + $this->showSuccessNotification(trans('entities.pages_delete_draft_success')); + + if ($chapter && userCan('view', $chapter)) { + return redirect($chapter->getUrl()); + } return redirect($book->getUrl()); } /** - * Shows the last revisions for this page. - * @param string $bookSlug - * @param string $pageSlug - * @return \Illuminate\View\View - * @throws NotFoundException - */ - public function showRevisions($bookSlug, $pageSlug) - { - $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); - $this->setPageTitle(trans('entities.pages_revisions_named', ['pageName'=>$page->getShortName()])); - return view('pages.revisions', ['page' => $page, 'current' => $page]); - } - - /** - * Shows a preview of a single revision - * @param string $bookSlug - * @param string $pageSlug - * @param int $revisionId - * @return \Illuminate\View\View - */ - public function showRevision($bookSlug, $pageSlug, $revisionId) - { - $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); - $revision = $page->revisions()->where('id', '=', $revisionId)->first(); - if ($revision === null) { - abort(404); - } - - $page->fill($revision->toArray()); - $this->setPageTitle(trans('entities.pages_revision_named', ['pageName' => $page->getShortName()])); - - return view('pages.revision', [ - 'page' => $page, - 'book' => $page->book, - 'diff' => null, - 'revision' => $revision - ]); - } - - /** - * Shows the changes of a single revision - * @param string $bookSlug - * @param string $pageSlug - * @param int $revisionId - * @return \Illuminate\View\View - */ - public function showRevisionChanges($bookSlug, $pageSlug, $revisionId) - { - $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); - $revision = $page->revisions()->where('id', '=', $revisionId)->first(); - if ($revision === null) { - abort(404); - } - - $prev = $revision->getPrevious(); - $prevContent = ($prev === null) ? '' : $prev->html; - $diff = (new Htmldiff)->diff($prevContent, $revision->html); - - $page->fill($revision->toArray()); - $this->setPageTitle(trans('entities.pages_revision_named', ['pageName'=>$page->getShortName()])); - - return view('pages.revision', [ - 'page' => $page, - 'book' => $page->book, - 'diff' => $diff, - 'revision' => $revision - ]); - } - - /** - * Restores a page using the content of the specified revision. - * @param string $bookSlug - * @param string $pageSlug - * @param int $revisionId - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector - */ - public function restoreRevision($bookSlug, $pageSlug, $revisionId) - { - $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); - $this->checkOwnablePermission('page-update', $page); - $page = $this->pageRepo->restorePageRevision($page, $page->book, $revisionId); - Activity::add($page, 'page_restore', $page->book->id); - return redirect($page->getUrl()); - } - - - /** - * Deletes a revision using the id of the specified revision. - * @param string $bookSlug - * @param string $pageSlug - * @param int $revId - * @throws NotFoundException - * @throws BadRequestException - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector - */ - public function destroyRevision($bookSlug, $pageSlug, $revId) - { - $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); - $this->checkOwnablePermission('page-delete', $page); - - $revision = $page->revisions()->where('id', '=', $revId)->first(); - if ($revision === null) { - throw new NotFoundException("Revision #{$revId} not found"); - } - - // Get the current revision for the page - $currentRevision = $page->getCurrentRevision(); - - // Check if its the latest revision, cannot delete latest revision. - if (intval($currentRevision->id) === intval($revId)) { - session()->flash('error', trans('entities.revision_cannot_delete_latest')); - return response()->view('pages.revisions', ['page' => $page, 'book' => $page->book, 'current' => $page], 400); - } - - $revision->delete(); - session()->flash('success', trans('entities.revision_delete_success')); - return redirect($page->getUrl('/revisions')); - } - - /** - * Exports a page to a PDF. - * https://github.com/barryvdh/laravel-dompdf - * @param string $bookSlug - * @param string $pageSlug - * @return \Illuminate\Http\Response - */ - public function exportPdf($bookSlug, $pageSlug) - { - $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); - $page->html = $this->pageRepo->renderPage($page); - $pdfContent = $this->exportService->pageToPdf($page); - return $this->downloadResponse($pdfContent, $pageSlug . '.pdf'); - } - - /** - * Export a page to a self-contained HTML file. - * @param string $bookSlug - * @param string $pageSlug - * @return \Illuminate\Http\Response - */ - public function exportHtml($bookSlug, $pageSlug) - { - $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); - $page->html = $this->pageRepo->renderPage($page); - $containedHtml = $this->exportService->pageToContainedHtml($page); - return $this->downloadResponse($containedHtml, $pageSlug . '.html'); - } - - /** - * Export a page to a simple plaintext .txt file. - * @param string $bookSlug - * @param string $pageSlug - * @return \Illuminate\Http\Response - */ - public function exportPlainText($bookSlug, $pageSlug) - { - $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); - $pageText = $this->exportService->pageToPlainText($page); - return $this->downloadResponse($pageText, $pageSlug . '.txt'); - } - - /** - * Show a listing of recently created pages - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + * Show a listing of recently created pages. */ public function showRecentlyUpdated() { - // TODO - Still exist? - $pages = $this->pageRepo->getRecentlyUpdatedPaginated('page', 20)->setPath(url('/pages/recently-updated')); + $pages = Page::visible()->orderBy('updated_at', 'desc') + ->paginate(20) + ->setPath(url('/pages/recently-updated')); + return view('pages.detailed-listing', [ 'title' => trans('entities.recently_updated_pages'), 'pages' => $pages @@ -556,14 +352,11 @@ class PageController extends Controller /** * Show the view to choose a new parent to move a page into. - * @param string $bookSlug - * @param string $pageSlug - * @return mixed * @throws NotFoundException */ - public function showMove($bookSlug, $pageSlug) + public function showMove(string $bookSlug, string $pageSlug) { - $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); + $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); $this->checkOwnablePermission('page-update', $page); $this->checkOwnablePermission('page-delete', $page); return view('pages.move', [ @@ -573,16 +366,13 @@ class PageController extends Controller } /** - * Does the action of moving the location of a page - * @param string $bookSlug - * @param string $pageSlug - * @param Request $request - * @return mixed + * Does the action of moving the location of a page. * @throws NotFoundException + * @throws Throwable */ - public function move($bookSlug, $pageSlug, Request $request) + public function move(Request $request, string $bookSlug, string $pageSlug) { - $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); + $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); $this->checkOwnablePermission('page-update', $page); $this->checkOwnablePermission('page-delete', $page); @@ -591,37 +381,29 @@ class PageController extends Controller return redirect($page->getUrl()); } - $stringExploded = explode(':', $entitySelection); - $entityType = $stringExploded[0]; - $entityId = intval($stringExploded[1]); - - try { - $parent = $this->pageRepo->getById($entityType, $entityId); - } catch (\Exception $e) { - session()->flash(trans('entities.selected_book_chapter_not_found')); + $parent = $this->pageRepo->move($page, $entitySelection); + } catch (Exception $exception) { + if ($exception instanceof PermissionsException) { + $this->showPermissionError(); + } + + $this->showErrorNotification(trans('errors.selected_book_chapter_not_found')); return redirect()->back(); } - $this->checkOwnablePermission('page-create', $parent); - - $this->pageRepo->changePageParent($page, $parent); Activity::add($page, 'page_move', $page->book->id); - session()->flash('success', trans('entities.pages_move_success', ['parentName' => $parent->name])); - + $this->showSuccessNotification(trans('entities.pages_move_success', ['parentName' => $parent->name])); return redirect($page->getUrl()); } /** * Show the view to copy a page. - * @param string $bookSlug - * @param string $pageSlug - * @return mixed * @throws NotFoundException */ - public function showCopy($bookSlug, $pageSlug) + public function showCopy(string $bookSlug, string $pageSlug) { - $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); + $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); $this->checkOwnablePermission('page-view', $page); session()->flashInput(['name' => $page->name]); return view('pages.copy', [ @@ -630,78 +412,65 @@ class PageController extends Controller ]); } + /** * Create a copy of a page within the requested target destination. - * @param string $bookSlug - * @param string $pageSlug - * @param Request $request - * @return mixed * @throws NotFoundException + * @throws Throwable */ - public function copy($bookSlug, $pageSlug, Request $request) + public function copy(Request $request, string $bookSlug, string $pageSlug) { - $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); + $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); $this->checkOwnablePermission('page-view', $page); - $entitySelection = $request->get('entity_selection', null); - if ($entitySelection === null || $entitySelection === '') { - $parent = $page->chapter ? $page->chapter : $page->book; - } else { - $stringExploded = explode(':', $entitySelection); - $entityType = $stringExploded[0]; - $entityId = intval($stringExploded[1]); + $entitySelection = $request->get('entity_selection', null) ?? null; + $newName = $request->get('name', null); - try { - $parent = $this->pageRepo->getById($entityType, $entityId); - } catch (\Exception $e) { - session()->flash(trans('entities.selected_book_chapter_not_found')); - return redirect()->back(); + try { + $pageCopy = $this->pageRepo->copy($page, $entitySelection, $newName); + } catch (Exception $exception) { + if ($exception instanceof PermissionsException) { + $this->showPermissionError(); } + + $this->showErrorNotification(trans('errors.selected_book_chapter_not_found')); + return redirect()->back(); } - $this->checkOwnablePermission('page-create', $parent); - - $pageCopy = $this->pageRepo->copyPage($page, $parent, $request->get('name', '')); - Activity::add($pageCopy, 'page_create', $pageCopy->book->id); - session()->flash('success', trans('entities.pages_copy_success')); + $this->showSuccessNotification(trans('entities.pages_copy_success')); return redirect($pageCopy->getUrl()); } /** * Show the Permissions view. - * @param string $bookSlug - * @param string $pageSlug - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View * @throws NotFoundException */ - public function showPermissions($bookSlug, $pageSlug) + public function showPermissions(string $bookSlug, string $pageSlug) { - $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); + $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); $this->checkOwnablePermission('restrictions-manage', $page); - $roles = $this->userRepo->getRestrictableRoles(); return view('pages.permissions', [ 'page' => $page, - 'roles' => $roles ]); } /** * Set the permissions for this page. - * @param string $bookSlug - * @param string $pageSlug - * @param Request $request - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector * @throws NotFoundException - * @throws \Throwable + * @throws Throwable */ - public function permissions($bookSlug, $pageSlug, Request $request) + public function permissions(Request $request, string $bookSlug, string $pageSlug) { - $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug); + $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); $this->checkOwnablePermission('restrictions-manage', $page); - $this->pageRepo->updateEntityPermissionsFromRequest($request, $page); - session()->flash('success', trans('entities.pages_permissions_success')); + + $restricted = $request->get('restricted') === 'true'; + $permissions = $request->filled('restrictions') ? collect($request->get('restrictions')) : null; + $this->pageRepo->updatePermissions($page, $restricted, $permissions); + + $this->showSuccessNotification(trans('entities.pages_permissions_success')); return redirect($page->getUrl()); } } diff --git a/app/Http/Controllers/PageExportController.php b/app/Http/Controllers/PageExportController.php new file mode 100644 index 000000000..3b02ea224 --- /dev/null +++ b/app/Http/Controllers/PageExportController.php @@ -0,0 +1,66 @@ +pageRepo = $pageRepo; + $this->exportService = $exportService; + parent::__construct(); + } + + /** + * Exports a page to a PDF. + * https://github.com/barryvdh/laravel-dompdf + * @throws NotFoundException + * @throws Throwable + */ + public function pdf(string $bookSlug, string $pageSlug) + { + $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); + $page->html = (new PageContent($page))->render(); + $pdfContent = $this->exportService->pageToPdf($page); + return $this->downloadResponse($pdfContent, $pageSlug . '.pdf'); + } + + /** + * Export a page to a self-contained HTML file. + * @throws NotFoundException + * @throws Throwable + */ + public function html(string $bookSlug, string $pageSlug) + { + $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); + $page->html = (new PageContent($page))->render(); + $containedHtml = $this->exportService->pageToContainedHtml($page); + return $this->downloadResponse($containedHtml, $pageSlug . '.html'); + } + + /** + * Export a page to a simple plaintext .txt file. + * @throws NotFoundException + */ + public function plainText(string $bookSlug, string $pageSlug) + { + $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); + $pageText = $this->exportService->pageToPlainText($page); + return $this->downloadResponse($pageText, $pageSlug . '.txt'); + } +} diff --git a/app/Http/Controllers/PageRevisionController.php b/app/Http/Controllers/PageRevisionController.php new file mode 100644 index 000000000..3c65b50ac --- /dev/null +++ b/app/Http/Controllers/PageRevisionController.php @@ -0,0 +1,128 @@ +pageRepo = $pageRepo; + parent::__construct(); + } + + /** + * Shows the last revisions for this page. + * @throws NotFoundException + */ + public function index(string $bookSlug, string $pageSlug) + { + $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); + $this->setPageTitle(trans('entities.pages_revisions_named', ['pageName'=>$page->getShortName()])); + return view('pages.revisions', [ + 'page' => $page, + 'current' => $page + ]); + } + + /** + * Shows a preview of a single revision. + * @throws NotFoundException + */ + public function show(string $bookSlug, string $pageSlug, int $revisionId) + { + $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); + $revision = $page->revisions()->where('id', '=', $revisionId)->first(); + if ($revision === null) { + throw new NotFoundException(); + } + + $page->fill($revision->toArray()); + + $this->setPageTitle(trans('entities.pages_revision_named', ['pageName' => $page->getShortName()])); + return view('pages.revision', [ + 'page' => $page, + 'book' => $page->book, + 'diff' => null, + 'revision' => $revision + ]); + } + + /** + * Shows the changes of a single revision. + * @throws NotFoundException + */ + public function changes(string $bookSlug, string $pageSlug, int $revisionId) + { + $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); + $revision = $page->revisions()->where('id', '=', $revisionId)->first(); + if ($revision === null) { + throw new NotFoundException(); + } + + $prev = $revision->getPrevious(); + $prevContent = $prev->html ?? ''; + $diff = (new Htmldiff)->diff($prevContent, $revision->html); + + $page->fill($revision->toArray()); + $this->setPageTitle(trans('entities.pages_revision_named', ['pageName'=>$page->getShortName()])); + + return view('pages.revision', [ + 'page' => $page, + 'book' => $page->book, + 'diff' => $diff, + 'revision' => $revision + ]); + } + + /** + * Restores a page using the content of the specified revision. + * @throws NotFoundException + */ + public function restore(string $bookSlug, string $pageSlug, int $revisionId) + { + $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); + $this->checkOwnablePermission('page-update', $page); + + $page = $this->pageRepo->restoreRevision($page, $revisionId); + + Activity::add($page, 'page_restore', $page->book->id); + return redirect($page->getUrl()); + } + + /** + * Deletes a revision using the id of the specified revision. + * @throws NotFoundException + */ + public function destroy(string $bookSlug, string $pageSlug, int $revId) + { + $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); + $this->checkOwnablePermission('page-delete', $page); + + $revision = $page->revisions()->where('id', '=', $revId)->first(); + if ($revision === null) { + throw new NotFoundException("Revision #{$revId} not found"); + } + + // Get the current revision for the page + $currentRevision = $page->getCurrentRevision(); + + // Check if its the latest revision, cannot delete latest revision. + if (intval($currentRevision->id) === intval($revId)) { + $this->showErrorNotification(trans('entities.revision_cannot_delete_latest')); + return redirect($page->getUrl('/revisions')); + } + + $revision->delete(); + $this->showSuccessNotification(trans('entities.revision_delete_success')); + return redirect($page->getUrl('/revisions')); + } +} diff --git a/app/Http/Controllers/PageTemplateController.php b/app/Http/Controllers/PageTemplateController.php index 05943351a..eaa1a8ae2 100644 --- a/app/Http/Controllers/PageTemplateController.php +++ b/app/Http/Controllers/PageTemplateController.php @@ -11,8 +11,7 @@ class PageTemplateController extends Controller protected $pageRepo; /** - * PageTemplateController constructor. - * @param $pageRepo + * PageTemplateController constructor */ public function __construct(PageRepo $pageRepo) { @@ -22,14 +21,12 @@ class PageTemplateController extends Controller /** * Fetch a list of templates from the system. - * @param Request $request - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View */ public function list(Request $request) { $page = $request->get('page', 1); $search = $request->get('search', ''); - $templates = $this->pageRepo->getPageTemplates(10, $page, $search); + $templates = $this->pageRepo->getTemplates(10, $page, $search); if ($search) { $templates->appends(['search' => $search]); @@ -42,13 +39,11 @@ class PageTemplateController extends Controller /** * Get the content of a template. - * @param $templateId - * @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response * @throws NotFoundException */ - public function get($templateId) + public function get(int $templateId) { - $page = $this->pageRepo->getById('page', $templateId); + $page = $this->pageRepo->getById($templateId); if (!$page->template) { throw new NotFoundException(); @@ -59,5 +54,4 @@ class PageTemplateController extends Controller 'markdown' => $page->markdown, ]); } - } diff --git a/app/Http/Controllers/PermissionController.php b/app/Http/Controllers/PermissionController.php index 9893d5993..148ae5cd6 100644 --- a/app/Http/Controllers/PermissionController.php +++ b/app/Http/Controllers/PermissionController.php @@ -53,7 +53,7 @@ class PermissionController extends Controller ]); $this->permissionsRepo->saveNewRole($request->all()); - session()->flash('success', trans('settings.role_create_success')); + $this->showSuccessNotification(trans('settings.role_create_success')); return redirect('/settings/roles'); } @@ -75,12 +75,13 @@ class PermissionController extends Controller /** * Updates a user role. - * @param $id * @param Request $request + * @param $id * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector * @throws PermissionsException + * @throws \Illuminate\Validation\ValidationException */ - public function updateRole($id, Request $request) + public function updateRole(Request $request, $id) { $this->checkPermission('user-roles-manage'); $this->validate($request, [ @@ -89,7 +90,7 @@ class PermissionController extends Controller ]); $this->permissionsRepo->updateRole($id, $request->all()); - session()->flash('success', trans('settings.role_update_success')); + $this->showSuccessNotification(trans('settings.role_update_success')); return redirect('/settings/roles'); } @@ -112,22 +113,22 @@ class PermissionController extends Controller /** * Delete a role from the system, * Migrate from a previous role if set. - * @param $id * @param Request $request + * @param $id * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ - public function deleteRole($id, Request $request) + public function deleteRole(Request $request, $id) { $this->checkPermission('user-roles-manage'); try { $this->permissionsRepo->deleteRole($id, $request->get('migrate_role_id')); } catch (PermissionsException $e) { - session()->flash('error', $e->getMessage()); + $this->showErrorNotification($e->getMessage()); return redirect()->back(); } - session()->flash('success', trans('settings.role_delete_success')); + $this->showSuccessNotification(trans('settings.role_delete_success')); return redirect('/settings/roles'); } } diff --git a/app/Http/Controllers/SearchController.php b/app/Http/Controllers/SearchController.php index 1691ee9b0..a5cd7ad6b 100644 --- a/app/Http/Controllers/SearchController.php +++ b/app/Http/Controllers/SearchController.php @@ -1,35 +1,27 @@ entityRepo = $entityRepo; $this->viewService = $viewService; $this->searchService = $searchService; $this->entityContextManager = $entityContextManager; @@ -38,9 +30,6 @@ class SearchController extends Controller /** * Searches all entities. - * @param Request $request - * @return View - * @internal param string $searchTerm */ public function search(Request $request) { @@ -64,12 +53,8 @@ class SearchController extends Controller /** * Searches all entities within a book. - * @param Request $request - * @param integer $bookId - * @return View - * @internal param string $searchTerm */ - public function searchBook(Request $request, $bookId) + public function searchBook(Request $request, int $bookId) { $term = $request->get('term', ''); $results = $this->searchService->searchBook($bookId, $term); @@ -78,12 +63,8 @@ class SearchController extends Controller /** * Searches all entities within a chapter. - * @param Request $request - * @param integer $chapterId - * @return View - * @internal param string $searchTerm */ - public function searchChapter(Request $request, $chapterId) + public function searchChapter(Request $request, int $chapterId) { $term = $request->get('term', ''); $results = $this->searchService->searchChapter($chapterId, $term); @@ -93,8 +74,6 @@ class SearchController extends Controller /** * Search for a list of entities and return a partial HTML response of matching entities. * Returns the most popular entities if no search is provided. - * @param Request $request - * @return mixed */ public function searchEntitiesAjax(Request $request) { @@ -115,15 +94,13 @@ class SearchController extends Controller /** * Search siblings items in the system. - * @param Request $request - * @return Factory|View|mixed */ public function searchSiblings(Request $request) { $type = $request->get('entity_type', null); $id = $request->get('entity_id', null); - $entity = $this->entityRepo->getById($type, $id); + $entity = Entity::getEntityInstance($type)->newQuery()->visible()->find($id); if (!$entity) { return $this->jsonError(trans('errors.entity_not_found'), 404); } @@ -132,12 +109,12 @@ class SearchController extends Controller // Page in chapter if ($entity->isA('page') && $entity->chapter) { - $entities = $this->entityRepo->getChapterChildren($entity->chapter); + $entities = $entity->chapter->visiblePages(); } // Page in book or chapter if (($entity->isA('page') && !$entity->chapter) || $entity->isA('chapter')) { - $entities = $this->entityRepo->getBookDirectChildren($entity->book); + $entities = $entity->book->getDirectChildren(); } // Book @@ -145,15 +122,15 @@ class SearchController extends Controller if ($entity->isA('book')) { $contextShelf = $this->entityContextManager->getContextualShelfForBook($entity); if ($contextShelf) { - $entities = $this->entityRepo->getBookshelfChildren($contextShelf); + $entities = $contextShelf->visibleBooks()->get(); } else { - $entities = $this->entityRepo->getAll('book'); + $entities = Book::visible()->get(); } } // Shelve if ($entity->isA('bookshelf')) { - $entities = $this->entityRepo->getAll('bookshelf'); + $entities = Bookshelf::visible()->get(); } return view('partials.entity-list-basic', ['entities' => $entities, 'style' => 'compact']); diff --git a/app/Http/Controllers/SettingController.php b/app/Http/Controllers/SettingController.php index 650833c7f..892b2d9cf 100644 --- a/app/Http/Controllers/SettingController.php +++ b/app/Http/Controllers/SettingController.php @@ -1,11 +1,10 @@ preventAccessForDemoUsers(); + $this->preventAccessInDemoMode(); $this->checkPermission('settings-manage'); $this->validate($request, [ 'app_logo' => $this->imageRepo->getImageValidationRules(), @@ -76,13 +70,13 @@ class SettingController extends Controller setting()->remove('app-logo'); } - session()->flash('success', trans('settings.settings_save_success')); - return redirect('/settings'); + $this->showSuccessNotification(trans('settings.settings_save_success')); + $redirectLocation = '/settings#' . $request->get('section', ''); + return redirect(rtrim($redirectLocation, '#')); } /** * Show the page for application maintenance. - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View */ public function showMaintenance() { @@ -97,9 +91,6 @@ class SettingController extends Controller /** * Action to clean-up images in the system. - * @param Request $request - * @param ImageService $imageService - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ public function cleanupImages(Request $request, ImageService $imageService) { @@ -111,16 +102,29 @@ class SettingController extends Controller $imagesToDelete = $imageService->deleteUnusedImages($checkRevisions, $dryRun); $deleteCount = count($imagesToDelete); if ($deleteCount === 0) { - session()->flash('warning', trans('settings.maint_image_cleanup_nothing_found')); + $this->showWarningNotification(trans('settings.maint_image_cleanup_nothing_found')); return redirect('/settings/maintenance')->withInput(); } if ($dryRun) { session()->flash('cleanup-images-warning', trans('settings.maint_image_cleanup_warning', ['count' => $deleteCount])); } else { - session()->flash('success', trans('settings.maint_image_cleanup_success', ['count' => $deleteCount])); + $this->showSuccessNotification(trans('settings.maint_image_cleanup_success', ['count' => $deleteCount])); } return redirect('/settings/maintenance#image-cleanup')->withInput(); } + + /** + * Action to send a test e-mail to the current user. + */ + public function sendTestEmail() + { + $this->checkPermission('settings-manage'); + + user()->notify(new TestEmail()); + $this->showSuccessNotification(trans('settings.maint_send_test_email_success', ['address' => user()->email])); + + return redirect('/settings/maintenance#image-cleanup')->withInput(); + } } diff --git a/app/Http/Controllers/UserApiTokenController.php b/app/Http/Controllers/UserApiTokenController.php new file mode 100644 index 000000000..55675233c --- /dev/null +++ b/app/Http/Controllers/UserApiTokenController.php @@ -0,0 +1,139 @@ +checkPermission('access-api'); + $this->checkPermissionOrCurrentUser('users-manage', $userId); + + $user = User::query()->findOrFail($userId); + return view('users.api-tokens.create', [ + 'user' => $user, + ]); + } + + /** + * Store a new API token in the system. + */ + public function store(Request $request, int $userId) + { + $this->checkPermission('access-api'); + $this->checkPermissionOrCurrentUser('users-manage', $userId); + + $this->validate($request, [ + 'name' => 'required|max:250', + 'expires_at' => 'date_format:Y-m-d', + ]); + + $user = User::query()->findOrFail($userId); + $secret = Str::random(32); + + $token = (new ApiToken())->forceFill([ + 'name' => $request->get('name'), + 'token_id' => Str::random(32), + 'secret' => Hash::make($secret), + 'user_id' => $user->id, + 'expires_at' => $request->get('expires_at') ?: ApiToken::defaultExpiry(), + ]); + + while (ApiToken::query()->where('token_id', '=', $token->token_id)->exists()) { + $token->token_id = Str::random(32); + } + + $token->save(); + + session()->flash('api-token-secret:' . $token->id, $secret); + $this->showSuccessNotification(trans('settings.user_api_token_create_success')); + return redirect($user->getEditUrl('/api-tokens/' . $token->id)); + } + + /** + * Show the details for a user API token, with access to edit. + */ + public function edit(int $userId, int $tokenId) + { + [$user, $token] = $this->checkPermissionAndFetchUserToken($userId, $tokenId); + $secret = session()->pull('api-token-secret:' . $token->id, null); + + return view('users.api-tokens.edit', [ + 'user' => $user, + 'token' => $token, + 'model' => $token, + 'secret' => $secret, + ]); + } + + /** + * Update the API token. + */ + public function update(Request $request, int $userId, int $tokenId) + { + $this->validate($request, [ + 'name' => 'required|max:250', + 'expires_at' => 'date_format:Y-m-d', + ]); + + [$user, $token] = $this->checkPermissionAndFetchUserToken($userId, $tokenId); + $token->fill([ + 'name' => $request->get('name'), + 'expires_at' => $request->get('expires_at') ?: ApiToken::defaultExpiry(), + ])->save(); + + $this->showSuccessNotification(trans('settings.user_api_token_update_success')); + return redirect($user->getEditUrl('/api-tokens/' . $token->id)); + } + + /** + * Show the delete view for this token. + */ + public function delete(int $userId, int $tokenId) + { + [$user, $token] = $this->checkPermissionAndFetchUserToken($userId, $tokenId); + return view('users.api-tokens.delete', [ + 'user' => $user, + 'token' => $token, + ]); + } + + /** + * Destroy a token from the system. + */ + public function destroy(int $userId, int $tokenId) + { + [$user, $token] = $this->checkPermissionAndFetchUserToken($userId, $tokenId); + $token->delete(); + + $this->showSuccessNotification(trans('settings.user_api_token_delete_success')); + return redirect($user->getEditUrl('#api_tokens')); + } + + /** + * Check the permission for the current user and return an array + * where the first item is the user in context and the second item is their + * API token in context. + */ + protected function checkPermissionAndFetchUserToken(int $userId, int $tokenId): array + { + $this->checkPermissionOr('users-manage', function () use ($userId) { + return $userId === user()->id && userCan('access-api'); + }); + + $user = User::query()->findOrFail($userId); + $token = ApiToken::query()->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 c9d2560ba..207466f38 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -8,6 +8,7 @@ use BookStack\Exceptions\UserUpdateException; use BookStack\Uploads\ImageRepo; use Illuminate\Http\Request; use Illuminate\Http\Response; +use Illuminate\Support\Str; class UserController extends Controller { @@ -92,7 +93,7 @@ class UserController extends Controller $user = $this->user->fill($request->all()); if ($authMethod === 'standard') { - $user->password = bcrypt($request->get('password', str_random(32))); + $user->password = bcrypt($request->get('password', Str::random(32))); } elseif ($authMethod === 'ldap') { $user->external_auth_id = $request->get('external_auth_id'); } @@ -115,22 +116,24 @@ class UserController extends Controller /** * Show the form for editing the specified user. - * @param int $id - * @param \BookStack\Auth\Access\SocialAuthService $socialAuthService - * @return Response */ - public function edit($id, SocialAuthService $socialAuthService) + public function edit(int $id, SocialAuthService $socialAuthService) { $this->checkPermissionOrCurrentUser('users-manage', $id); - $user = $this->user->findOrFail($id); + $user = $this->user->newQuery()->with(['apiTokens'])->findOrFail($id); $authMethod = ($user->system_name) ? 'system' : config('auth.method'); $activeSocialDrivers = $socialAuthService->getActiveDrivers(); $this->setPageTitle(trans('settings.user_profile')); $roles = $this->userRepo->getAllRoles(); - return view('users.edit', ['user' => $user, 'activeSocialDrivers' => $activeSocialDrivers, 'authMethod' => $authMethod, 'roles' => $roles]); + return view('users.edit', [ + 'user' => $user, + 'activeSocialDrivers' => $activeSocialDrivers, + 'authMethod' => $authMethod, + 'roles' => $roles + ]); } /** @@ -143,7 +146,7 @@ class UserController extends Controller */ public function update(Request $request, $id) { - $this->preventAccessForDemoUsers(); + $this->preventAccessInDemoMode(); $this->checkPermissionOrCurrentUser('users-manage', $id); $this->validate($request, [ @@ -176,7 +179,7 @@ class UserController extends Controller } // External auth id updates - if ($this->currentUser->can('users-manage') && $request->filled('external_auth_id')) { + if (user()->can('users-manage') && $request->filled('external_auth_id')) { $user->external_auth_id = $request->get('external_auth_id'); } @@ -201,7 +204,7 @@ class UserController extends Controller } $user->save(); - session()->flash('success', trans('settings.users_edit_success')); + $this->showSuccessNotification(trans('settings.users_edit_success')); $redirectUrl = userCan('users-manage') ? '/settings/users' : ('/settings/users/' . $user->id); return redirect($redirectUrl); @@ -229,23 +232,23 @@ class UserController extends Controller */ public function destroy($id) { - $this->preventAccessForDemoUsers(); + $this->preventAccessInDemoMode(); $this->checkPermissionOrCurrentUser('users-manage', $id); $user = $this->userRepo->getById($id); if ($this->userRepo->isOnlyAdmin($user)) { - session()->flash('error', trans('errors.users_cannot_delete_only_admin')); + $this->showErrorNotification(trans('errors.users_cannot_delete_only_admin')); return redirect($user->getEditUrl()); } if ($user->system_name === 'public') { - session()->flash('error', trans('errors.users_cannot_delete_guest')); + $this->showErrorNotification(trans('errors.users_cannot_delete_guest')); return redirect($user->getEditUrl()); } $this->userRepo->destroy($user); - session()->flash('success', trans('settings.users_delete_success')); + $this->showSuccessNotification(trans('settings.users_delete_success')); return redirect('/settings/users'); } @@ -260,7 +263,7 @@ class UserController extends Controller $user = $this->userRepo->getById($id); $userActivity = $this->userRepo->getActivity($user); - $recentlyCreated = $this->userRepo->getRecentlyCreated($user, 5, 0); + $recentlyCreated = $this->userRepo->getRecentlyCreated($user, 5); $assetCounts = $this->userRepo->getAssetCounts($user); return view('users.profile', [ @@ -273,22 +276,22 @@ class UserController extends Controller /** * Update the user's preferred book-list display setting. - * @param $id * @param Request $request + * @param $id * @return \Illuminate\Http\RedirectResponse */ - public function switchBookView($id, Request $request) + public function switchBookView(Request $request, $id) { return $this->switchViewType($id, $request, 'books'); } /** * Update the user's preferred shelf-list display setting. - * @param $id * @param Request $request + * @param $id * @return \Illuminate\Http\RedirectResponse */ - public function switchShelfView($id, Request $request) + public function switchShelfView(Request $request, $id) { return $this->switchViewType($id, $request, 'bookshelves'); } @@ -318,12 +321,12 @@ class UserController extends Controller /** * Change the stored sort type for a particular view. + * @param Request $request * @param string $id * @param string $type - * @param Request $request * @return \Illuminate\Http\RedirectResponse */ - public function changeSort(string $id, string $type, Request $request) + public function changeSort(Request $request, string $id, string $type) { $validSortTypes = ['books', 'bookshelves']; if (!in_array($type, $validSortTypes)) { @@ -334,12 +337,12 @@ class UserController extends Controller /** * Update the stored section expansion preference for the given user. + * @param Request $request * @param string $id * @param string $key - * @param Request $request * @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response */ - public function updateExpansionPreference(string $id, string $key, Request $request) + public function updateExpansionPreference(Request $request, string $id, string $key) { $this->checkPermissionOrCurrentUser('users-manage', $id); $keyWhitelist = ['home-details']; diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index cd894de95..4517deb90 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -6,13 +6,10 @@ class Kernel extends HttpKernel { /** * The application's global HTTP middleware stack. - * * These middleware are run during every request to your application. - * - * @var array */ protected $middleware = [ - \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class, + \BookStack\Http\Middleware\CheckForMaintenanceMode::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \BookStack\Http\Middleware\TrimStrings::class, \BookStack\Http\Middleware\TrustProxies::class, @@ -29,13 +26,16 @@ class Kernel extends HttpKernel \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, + \Illuminate\Routing\Middleware\ThrottleRequests::class, \BookStack\Http\Middleware\VerifyCsrfToken::class, - \Illuminate\Routing\Middleware\SubstituteBindings::class, - \BookStack\Http\Middleware\Localization::class + \BookStack\Http\Middleware\Localization::class, + \BookStack\Http\Middleware\GlobalViewData::class, ], 'api' => [ - 'throttle:60,1', - 'bindings', + \BookStack\Http\Middleware\ThrottleApiRequests::class, + \BookStack\Http\Middleware\EncryptCookies::class, + \BookStack\Http\Middleware\StartSessionIfCookieExists::class, + \BookStack\Http\Middleware\ApiAuthenticate::class, ], ]; @@ -46,10 +46,10 @@ class Kernel extends HttpKernel */ protected $routeMiddleware = [ 'auth' => \BookStack\Http\Middleware\Authenticate::class, - 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \BookStack\Http\Middleware\RedirectIfAuthenticated::class, - 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, - 'perm' => \BookStack\Http\Middleware\PermissionMiddleware::class + 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, + 'perm' => \BookStack\Http\Middleware\PermissionMiddleware::class, + 'guard' => \BookStack\Http\Middleware\CheckGuard::class, ]; } diff --git a/app/Http/Middleware/ApiAuthenticate.php b/app/Http/Middleware/ApiAuthenticate.php new file mode 100644 index 000000000..15962b3b0 --- /dev/null +++ b/app/Http/Middleware/ApiAuthenticate.php @@ -0,0 +1,66 @@ +ensureAuthorizedBySessionOrToken(); + } catch (UnauthorizedException $exception) { + return $this->unauthorisedResponse($exception->getMessage(), $exception->getCode()); + } + + return $next($request); + } + + /** + * Ensure the current user can access authenticated API routes, either via existing session + * authentication or via API Token authentication. + * @throws UnauthorizedException + */ + protected function ensureAuthorizedBySessionOrToken(): void + { + // Return if the user is already found to be signed in via session-based auth. + // This is to make it easy to browser the API via browser after just logging into the system. + if (signedInUser()) { + $this->ensureEmailConfirmedIfRequested(); + if (!auth()->user()->can('access-api')) { + throw new ApiAuthException(trans('errors.api_user_no_api_permission'), 403); + } + return; + } + + // Set our api guard to be the default for this request lifecycle. + auth()->shouldUse('api'); + + // Validate the token and it's users API access + auth()->authenticate(); + $this->ensureEmailConfirmedIfRequested(); + } + + /** + * Provide a standard API unauthorised response. + */ + protected function unauthorisedResponse(string $message, int $code) + { + return response()->json([ + 'error' => [ + 'code' => $code, + 'message' => $message, + ] + ], $code); + } +} diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php index d840a9b2e..9a8affa88 100644 --- a/app/Http/Middleware/Authenticate.php +++ b/app/Http/Middleware/Authenticate.php @@ -3,38 +3,19 @@ namespace BookStack\Http\Middleware; use Closure; -use Illuminate\Contracts\Auth\Guard; +use Illuminate\Http\Request; class Authenticate { - /** - * The Guard implementation. - * @var Guard - */ - protected $auth; - - /** - * Create a new filter instance. - * @param Guard $auth - */ - public function __construct(Guard $auth) - { - $this->auth = $auth; - } + use ChecksForEmailConfirmation; /** * Handle an incoming request. - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @return mixed */ - public function handle($request, Closure $next) + public function handle(Request $request, Closure $next) { - if ($this->auth->check()) { - $requireConfirmation = (setting('registration-confirmation') || setting('registration-restrict')); - if ($requireConfirmation && !$this->auth->user()->email_confirmed) { - return redirect('/register/confirm/awaiting'); - } + if ($this->awaitingEmailConfirmation()) { + return $this->emailConfirmationErrorResponse($request); } if (!hasAppAccess()) { @@ -47,4 +28,22 @@ class Authenticate return $next($request); } + + /** + * Provide an error response for when the current user's email is not confirmed + * in a system which requires it. + */ + protected function emailConfirmationErrorResponse(Request $request) + { + if ($request->wantsJson()) { + return response()->json([ + 'error' => [ + 'code' => 401, + 'message' => trans('errors.email_confirmation_awaiting') + ] + ], 401); + } + + return redirect('/register/confirm/awaiting'); + } } diff --git a/app/Http/Middleware/CheckForMaintenanceMode.php b/app/Http/Middleware/CheckForMaintenanceMode.php new file mode 100644 index 000000000..0c7683836 --- /dev/null +++ b/app/Http/Middleware/CheckForMaintenanceMode.php @@ -0,0 +1,17 @@ +flash('error', trans('errors.permission')); + return redirect('/'); + } + + return $next($request); + } +} diff --git a/app/Http/Middleware/ChecksForEmailConfirmation.php b/app/Http/Middleware/ChecksForEmailConfirmation.php new file mode 100644 index 000000000..4b1732810 --- /dev/null +++ b/app/Http/Middleware/ChecksForEmailConfirmation.php @@ -0,0 +1,36 @@ +awaitingEmailConfirmation()) { + throw new UnauthorizedException(trans('errors.email_confirmation_awaiting')); + } + } + + /** + * Check if email confirmation is required and the current user is awaiting confirmation. + */ + protected function awaitingEmailConfirmation(): bool + { + if (auth()->check()) { + $requireConfirmation = (setting('registration-confirmation') || setting('registration-restrict')); + if ($requireConfirmation && !auth()->user()->email_confirmed) { + return true; + } + } + + return false; + } +} \ No newline at end of file diff --git a/app/Http/Middleware/GlobalViewData.php b/app/Http/Middleware/GlobalViewData.php new file mode 100644 index 000000000..bc132dfc3 --- /dev/null +++ b/app/Http/Middleware/GlobalViewData.php @@ -0,0 +1,27 @@ +share('signedIn', auth()->check()); + view()->share('currentUser', user()); + + return $next($request); + } +} diff --git a/app/Http/Middleware/Localization.php b/app/Http/Middleware/Localization.php index b5e702781..f36d72725 100644 --- a/app/Http/Middleware/Localization.php +++ b/app/Http/Middleware/Localization.php @@ -19,6 +19,7 @@ class Localization */ protected $localeMap = [ 'ar' => 'ar', + 'da' => 'da_DK', 'de' => 'de_DE', 'de_informal' => 'de_DE', 'en' => 'en_GB', @@ -27,7 +28,7 @@ class Localization 'fr' => 'fr_FR', 'it' => 'it_IT', 'ja' => 'ja', - 'kr' => 'ko_KR', + 'ko' => 'ko_KR', 'nl' => 'nl_NL', 'pl' => 'pl_PL', 'pt_BR' => 'pt_BR', @@ -37,6 +38,7 @@ class Localization 'uk' => 'uk_UA', 'zh_CN' => 'zh_CN', 'zh_TW' => 'zh_TW', + 'tr' => 'tr_TR', ]; /** diff --git a/app/Http/Middleware/PermissionMiddleware.php b/app/Http/Middleware/PermissionMiddleware.php index 28ffff643..d0bb4f79e 100644 --- a/app/Http/Middleware/PermissionMiddleware.php +++ b/app/Http/Middleware/PermissionMiddleware.php @@ -19,7 +19,7 @@ class PermissionMiddleware { if (!$request->user() || !$request->user()->can($permission)) { - Session::flash('error', trans('errors.permission')); + session()->flash('error', trans('errors.permission')); return redirect()->back(); } diff --git a/app/Http/Middleware/StartSessionIfCookieExists.php b/app/Http/Middleware/StartSessionIfCookieExists.php new file mode 100644 index 000000000..456508d98 --- /dev/null +++ b/app/Http/Middleware/StartSessionIfCookieExists.php @@ -0,0 +1,22 @@ +cookies->has($sessionCookieName)) { + return parent::handle($request, $next); + } + + return $next($request); + } +} diff --git a/app/Http/Middleware/ThrottleApiRequests.php b/app/Http/Middleware/ThrottleApiRequests.php new file mode 100644 index 000000000..d08840cd1 --- /dev/null +++ b/app/Http/Middleware/ThrottleApiRequests.php @@ -0,0 +1,18 @@ + 'FORWARDED', - Request::HEADER_X_FORWARDED_FOR => 'X_FORWARDED_FOR', - Request::HEADER_X_FORWARDED_HOST => 'X_FORWARDED_HOST', - Request::HEADER_X_FORWARDED_PORT => 'X_FORWARDED_PORT', - Request::HEADER_X_FORWARDED_PROTO => 'X_FORWARDED_PROTO', - ]; + protected $headers = Request::HEADER_X_FORWARDED_ALL; /** * Handle the request, Set the correct user-configured proxy information. @@ -34,7 +28,7 @@ class TrustProxies extends Middleware * @param Closure $next * @return mixed */ - public function handle($request, Closure $next) + public function handle(Request $request, Closure $next) { $setProxies = config('app.proxies'); if ($setProxies !== '**' && $setProxies !== '*' && $setProxies !== '') { diff --git a/app/Http/Middleware/VerifyCsrfToken.php b/app/Http/Middleware/VerifyCsrfToken.php index 291b8326f..bdeb26554 100644 --- a/app/Http/Middleware/VerifyCsrfToken.php +++ b/app/Http/Middleware/VerifyCsrfToken.php @@ -6,12 +6,19 @@ use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware; class VerifyCsrfToken extends Middleware { + /** + * Indicates whether the XSRF-TOKEN cookie should be set on the response. + * + * @var bool + */ + protected $addHttpCookie = true; + /** * The URIs that should be excluded from CSRF verification. * * @var array */ protected $except = [ - // + 'saml2/*' ]; } diff --git a/app/Http/Request.php b/app/Http/Request.php index bd2761a0b..183686f67 100644 --- a/app/Http/Request.php +++ b/app/Http/Request.php @@ -22,5 +22,4 @@ class Request extends LaravelRequest return $base; } - -} \ No newline at end of file +} diff --git a/app/Notifications/TestEmail.php b/app/Notifications/TestEmail.php new file mode 100644 index 000000000..7fce1c19c --- /dev/null +++ b/app/Notifications/TestEmail.php @@ -0,0 +1,18 @@ +newMailMessage() + ->subject(trans('settings.maint_send_test_email_mail_subject')) + ->greeting(trans('settings.maint_send_test_email_mail_greeting')) + ->line(trans('settings.maint_send_test_email_mail_text')); + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index b46a716cc..3a1b4f42e 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -48,7 +48,7 @@ class AppServiceProvider extends ServiceProvider return ""; }); - Blade::directive('exposeTranslations', function($expression) { + Blade::directive('exposeTranslations', function ($expression) { return "startPush('translations'); ?>" . "" . '' . "\n" . diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index 6e5b6ffde..fe52df168 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -3,7 +3,13 @@ namespace BookStack\Providers; use Auth; +use BookStack\Api\ApiTokenGuard; +use BookStack\Auth\Access\ExternalBaseUserProvider; +use BookStack\Auth\Access\Guards\LdapSessionGuard; +use BookStack\Auth\Access\Guards\Saml2SessionGuard; use BookStack\Auth\Access\LdapService; +use BookStack\Auth\Access\RegistrationService; +use BookStack\Auth\UserRepo; use Illuminate\Support\ServiceProvider; class AuthServiceProvider extends ServiceProvider @@ -15,7 +21,30 @@ class AuthServiceProvider extends ServiceProvider */ public function boot() { - // + Auth::extend('api-token', function ($app, $name, array $config) { + return new ApiTokenGuard($app['request']); + }); + + Auth::extend('ldap-session', function ($app, $name, array $config) { + $provider = Auth::createUserProvider($config['provider']); + return new LdapSessionGuard( + $name, + $provider, + $this->app['session.store'], + $app[LdapService::class], + $app[RegistrationService::class] + ); + }); + + Auth::extend('saml2-session', function ($app, $name, array $config) { + $provider = Auth::createUserProvider($config['provider']); + return new Saml2SessionGuard( + $name, + $provider, + $this->app['session.store'], + $app[RegistrationService::class] + ); + }); } /** @@ -25,8 +54,8 @@ class AuthServiceProvider extends ServiceProvider */ public function register() { - Auth::provider('ldap', function ($app, array $config) { - return new LdapUserProvider($config['model'], $app[LdapService::class]); + Auth::provider('external-users', function ($app, array $config) { + return new ExternalBaseUserProvider($config['model']); }); } } diff --git a/app/Providers/CustomFacadeProvider.php b/app/Providers/CustomFacadeProvider.php index e7bde5290..b4158187c 100644 --- a/app/Providers/CustomFacadeProvider.php +++ b/app/Providers/CustomFacadeProvider.php @@ -4,6 +4,7 @@ namespace BookStack\Providers; use BookStack\Actions\ActivityService; use BookStack\Actions\ViewService; +use BookStack\Auth\Permissions\PermissionService; use BookStack\Settings\SettingService; use BookStack\Uploads\ImageService; use Illuminate\Support\ServiceProvider; @@ -27,20 +28,24 @@ class CustomFacadeProvider extends ServiceProvider */ public function register() { - $this->app->bind('activity', function () { + $this->app->singleton('activity', function () { return $this->app->make(ActivityService::class); }); - $this->app->bind('views', function () { + $this->app->singleton('views', function () { return $this->app->make(ViewService::class); }); - $this->app->bind('setting', function () { + $this->app->singleton('setting', function () { return $this->app->make(SettingService::class); }); - $this->app->bind('images', function () { + $this->app->singleton('images', function () { return $this->app->make(ImageService::class); }); + + $this->app->singleton('permissions', function () { + return $this->app->make(PermissionService::class); + }); } } diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index c4c39d534..a37780e52 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -34,7 +34,7 @@ class RouteServiceProvider extends ServiceProvider public function map() { $this->mapWebRoutes(); -// $this->mapApiRoutes(); + $this->mapApiRoutes(); } /** * Define the "web" routes for the application. @@ -63,7 +63,7 @@ class RouteServiceProvider extends ServiceProvider { Route::group([ 'middleware' => 'api', - 'namespace' => $this->namespace, + 'namespace' => $this->namespace . '\Api', 'prefix' => 'api', ], function ($router) { require base_path('routes/api.php'); diff --git a/app/Providers/TranslationServiceProvider.php b/app/Providers/TranslationServiceProvider.php index 7d51cc73d..9ff607afe 100644 --- a/app/Providers/TranslationServiceProvider.php +++ b/app/Providers/TranslationServiceProvider.php @@ -1,31 +1,21 @@ registerLoader(); - - $this->app->singleton('translator', function ($app) { - $loader = $app['translation.loader']; - - // When registering the translator component, we'll need to set the default - // locale as well as the fallback locale. So, we'll grab the application - // configuration so we can easily get both of these values from there. - $locale = $app['config']['app.locale']; - - $trans = new Translator($loader, $locale); - - $trans->setFallback($app['config']['app.fallback_locale']); - - return $trans; + $this->app->singleton('translation.loader', function ($app) { + 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 dede8fcc4..1c053b384 100644 --- a/app/Settings/SettingService.php +++ b/app/Settings/SettingService.php @@ -98,12 +98,6 @@ class SettingService */ protected function getValueFromStore($key, $default) { - // Check for an overriding value - $overrideValue = $this->getOverrideValue($key); - if ($overrideValue !== null) { - return $overrideValue; - } - // Check the cache $cacheKey = $this->cachePrefix . $key; $cacheVal = $this->cache->get($cacheKey, null); @@ -255,20 +249,4 @@ class SettingService { return $this->setting->where('setting_key', '=', $key)->first(); } - - - /** - * Returns an override value for a setting based on certain app conditions. - * Used where certain configuration options overrule others. - * Returns null if no override value is available. - * @param $key - * @return bool|null - */ - protected function getOverrideValue($key) - { - if ($key === 'registration-enabled' && config('auth.method') === 'ldap') { - return false; - } - return null; - } } diff --git a/app/Translation/FileLoader.php b/app/Translation/FileLoader.php new file mode 100644 index 000000000..f0f895da5 --- /dev/null +++ b/app/Translation/FileLoader.php @@ -0,0 +1,30 @@ +loadJsonPaths($locale); + } + + if (is_null($namespace) || $namespace === '*') { + $themeTranslations = $this->loadPath(theme_path('lang'), $locale, $group); + $originalTranslations = $this->loadPath($this->path, $locale, $group); + return array_merge($originalTranslations, $themeTranslations); + } + + return $this->loadNamespaced($locale, $group, $namespace); + } +} \ No newline at end of file diff --git a/app/Translation/Translator.php b/app/Translation/Translator.php deleted file mode 100644 index 032f43ff7..000000000 --- a/app/Translation/Translator.php +++ /dev/null @@ -1,72 +0,0 @@ - 'de', - ]; - - /** - * Get the translation for a given key. - * - * @param string $key - * @param array $replace - * @param string $locale - * @return string|array|null - */ - public function trans($key, array $replace = [], $locale = null) - { - $translation = $this->get($key, $replace, $locale); - - if (is_array($translation)) { - $translation = $this->mergeBackupTranslations($translation, $key, $locale); - } - - return $translation; - } - - /** - * Merge the fallback translations, and base translations if existing, - * into the provided core key => value array of translations content. - * @param array $translationArray - * @param string $key - * @param null $locale - * @return array - */ - protected function mergeBackupTranslations(array $translationArray, string $key, $locale = null) - { - $fallback = $this->get($key, [], $this->fallback); - $baseLocale = $this->getBaseLocale($locale ?? $this->locale); - $baseTranslations = $baseLocale ? $this->get($key, [], $baseLocale) : []; - - return array_replace_recursive($fallback, $baseTranslations, $translationArray); - } - - /** - * Get the array of locales to be checked. - * - * @param string|null $locale - * @return array - */ - protected function localeArray($locale) - { - $primaryLocale = $locale ?: $this->locale; - return array_filter([$primaryLocale, $this->getBaseLocale($primaryLocale), $this->fallback]); - } - - /** - * Get the locale to extend for the given locale. - * - * @param string $locale - * @return string|null - */ - protected function getBaseLocale($locale) - { - return $this->baseLocaleMap[$locale] ?? null; - } -} diff --git a/app/Uploads/Attachment.php b/app/Uploads/Attachment.php index 8720d3c09..3f0b447df 100644 --- a/app/Uploads/Attachment.php +++ b/app/Uploads/Attachment.php @@ -13,7 +13,7 @@ class Attachment extends Ownable */ public function getFileName() { - if (str_contains($this->name, '.')) { + if (strpos($this->name, '.') !== false) { return $this->name; } return $this->name . '.' . $this->extension; diff --git a/app/Uploads/AttachmentService.php b/app/Uploads/AttachmentService.php index 6e875a1e7..ae4fb6e96 100644 --- a/app/Uploads/AttachmentService.php +++ b/app/Uploads/AttachmentService.php @@ -2,6 +2,7 @@ use BookStack\Exceptions\FileUploadException; use Exception; +use Illuminate\Support\Str; use Symfony\Component\HttpFoundation\File\UploadedFile; class AttachmentService extends UploadService @@ -185,9 +186,9 @@ class AttachmentService extends UploadService $storage = $this->getStorage(); $basePath = 'uploads/files/' . Date('Y-m-M') . '/'; - $uploadFileName = str_random(16) . '.' . $uploadedFile->getClientOriginalExtension(); + $uploadFileName = Str::random(16) . '.' . $uploadedFile->getClientOriginalExtension(); while ($storage->exists($basePath . $uploadFileName)) { - $uploadFileName = str_random(3) . $uploadFileName; + $uploadFileName = Str::random(3) . $uploadFileName; } $attachmentPath = $basePath . $uploadFileName; diff --git a/app/Uploads/Image.php b/app/Uploads/Image.php index 6fa5db2a5..c76979d7c 100644 --- a/app/Uploads/Image.php +++ b/app/Uploads/Image.php @@ -8,6 +8,7 @@ class Image extends Ownable { protected $fillable = ['name']; + protected $hidden = []; /** * Get a thumbnail for this image. diff --git a/app/Uploads/ImageRepo.php b/app/Uploads/ImageRepo.php index da0b7d379..01b65f882 100644 --- a/app/Uploads/ImageRepo.php +++ b/app/Uploads/ImageRepo.php @@ -2,6 +2,8 @@ use BookStack\Auth\Permissions\PermissionService; use BookStack\Entities\Page; +use BookStack\Exceptions\ImageUploadException; +use Exception; use Illuminate\Database\Eloquent\Builder; use Symfony\Component\HttpFoundation\File\UploadedFile; @@ -15,10 +17,6 @@ class ImageRepo /** * ImageRepo constructor. - * @param Image $image - * @param ImageService $imageService - * @param \BookStack\Auth\Permissions\PermissionService $permissionService - * @param \BookStack\Entities\Page $page */ public function __construct( Image $image, @@ -35,10 +33,8 @@ class ImageRepo /** * Get an image with the given id. - * @param $id - * @return Image */ - public function getById($id) + public function getById($id): Image { return $this->image->findOrFail($id); } @@ -46,13 +42,8 @@ class ImageRepo /** * Execute a paginated query, returning in a standard format. * Also runs the query through the restriction system. - * @param $query - * @param int $page - * @param int $pageSize - * @param bool $filterOnPage - * @return array */ - private function returnPaginated($query, $page = 1, $pageSize = 24) + private function returnPaginated($query, $page = 1, $pageSize = 24): array { $images = $query->orderBy('created_at', 'desc')->skip($pageSize * ($page - 1))->take($pageSize + 1)->get(); $hasMore = count($images) > $pageSize; @@ -71,13 +62,6 @@ class ImageRepo /** * Fetch a list of images in a paginated format, filtered by image type. * Can be filtered by uploaded to and also by name. - * @param string $type - * @param int $page - * @param int $pageSize - * @param int $uploadedTo - * @param string|null $search - * @param callable|null $whereClause - * @return array */ public function getPaginatedByType( string $type, @@ -86,7 +70,8 @@ class ImageRepo int $uploadedTo = null, string $search = null, callable $whereClause = null - ) { + ): array + { $imageQuery = $this->image->newQuery()->where('type', '=', strtolower($type)); if ($uploadedTo !== null) { @@ -109,13 +94,6 @@ class ImageRepo /** * Get paginated gallery images within a specific page or book. - * @param string $type - * @param string $filterType - * @param int $page - * @param int $pageSize - * @param int|null $uploadedTo - * @param string|null $search - * @return array */ public function getEntityFiltered( string $type, @@ -124,7 +102,8 @@ class ImageRepo int $pageSize = 24, int $uploadedTo = null, string $search = null - ) { + ): array + { $contextPage = $this->page->findOrFail($uploadedTo); $parentFilter = null; @@ -144,16 +123,9 @@ class ImageRepo /** * Save a new image into storage and return the new image. - * @param UploadedFile $uploadFile - * @param string $type - * @param int $uploadedTo - * @param int|null $resizeWidth - * @param int|null $resizeHeight - * @param bool $keepRatio - * @return Image - * @throws \BookStack\Exceptions\ImageUploadException + * @throws ImageUploadException */ - public function saveNew(UploadedFile $uploadFile, $type, $uploadedTo = 0, int $resizeWidth = null, int $resizeHeight = null, bool $keepRatio = true) + public function saveNew(UploadedFile $uploadFile, string $type, int $uploadedTo = 0, int $resizeWidth = null, int $resizeHeight = null, bool $keepRatio = true): Image { $image = $this->imageService->saveNewFromUpload($uploadFile, $type, $uploadedTo, $resizeWidth, $resizeHeight, $keepRatio); $this->loadThumbs($image); @@ -161,29 +133,22 @@ class ImageRepo } /** - * Save a drawing the the database; - * @param string $base64Uri - * @param int $uploadedTo - * @return Image - * @throws \BookStack\Exceptions\ImageUploadException + * Save a drawing the the database. + * @throws ImageUploadException */ - public function saveDrawing(string $base64Uri, int $uploadedTo) + public function saveDrawing(string $base64Uri, int $uploadedTo): Image { $name = 'Drawing-' . user()->getShortName(40) . '-' . strval(time()) . '.png'; - $image = $this->imageService->saveNewFromBase64Uri($base64Uri, $name, 'drawio', $uploadedTo); - return $image; + return $this->imageService->saveNewFromBase64Uri($base64Uri, $name, 'drawio', $uploadedTo); } /** * Update the details of an image via an array of properties. - * @param Image $image - * @param array $updateDetails - * @return Image - * @throws \BookStack\Exceptions\ImageUploadException - * @throws \Exception + * @throws ImageUploadException + * @throws Exception */ - public function updateImageDetails(Image $image, $updateDetails) + public function updateImageDetails(Image $image, $updateDetails): Image { $image->fill($updateDetails); $image->save(); @@ -191,14 +156,11 @@ class ImageRepo return $image; } - /** * Destroys an Image object along with its revisions, files and thumbnails. - * @param Image $image - * @return bool - * @throws \Exception + * @throws Exception */ - public function destroyImage(Image $image = null) + public function destroyImage(Image $image = null): bool { if ($image) { $this->imageService->destroy($image); @@ -208,8 +170,7 @@ class ImageRepo /** * Destroy all images of a certain type. - * @param string $imageType - * @throws \Exception + * @throws Exception */ public function destroyByType(string $imageType) { @@ -222,9 +183,7 @@ class ImageRepo /** * Load thumbnails onto an image object. - * @param Image $image - * @throws \BookStack\Exceptions\ImageUploadException - * @throws \Exception + * @throws Exception */ protected function loadThumbs(Image $image) { @@ -238,42 +197,33 @@ class ImageRepo * Get the thumbnail for an image. * If $keepRatio is true only the width will be used. * Checks the cache then storage to avoid creating / accessing the filesystem on every check. - * @param Image $image - * @param int $width - * @param int $height - * @param bool $keepRatio - * @return string - * @throws \BookStack\Exceptions\ImageUploadException - * @throws \Exception + * @throws Exception */ - protected function getThumbnail(Image $image, $width = 220, $height = 220, $keepRatio = false) + protected function getThumbnail(Image $image, ?int $width = 220, ?int $height = 220, bool $keepRatio = false): ?string { try { return $this->imageService->getThumbnail($image, $width, $height, $keepRatio); - } catch (\Exception $exception) { + } catch (Exception $exception) { return null; } } /** * Get the raw image data from an Image. - * @param Image $image - * @return null|string */ - public function getImageData(Image $image) + public function getImageData(Image $image): ?string { try { return $this->imageService->getImageData($image); - } catch (\Exception $exception) { + } catch (Exception $exception) { return null; } } /** * Get the validation rules for image files. - * @return string */ - public function getImageValidationRules() + public function getImageValidationRules(): string { return 'image_extension|no_double_extension|mimes:jpeg,png,gif,bmp,webp,tiff'; } diff --git a/app/Uploads/ImageService.php b/app/Uploads/ImageService.php index 860230d00..756149fe7 100644 --- a/app/Uploads/ImageService.php +++ b/app/Uploads/ImageService.php @@ -7,6 +7,7 @@ use DB; use Exception; use Illuminate\Contracts\Cache\Repository as Cache; use Illuminate\Contracts\Filesystem\Factory as FileSystem; +use Illuminate\Support\Str; use Intervention\Image\Exception\NotSupportedException; use Intervention\Image\ImageManager; use phpDocumentor\Reflection\Types\Integer; @@ -140,12 +141,12 @@ class ImageService extends UploadService $imagePath = '/uploads/images/' . $type . '/' . Date('Y-m') . '/'; while ($storage->exists($imagePath . $imageName)) { - $imageName = str_random(3) . $imageName; + $imageName = Str::random(3) . $imageName; } $fullPath = $imagePath . $imageName; if ($secureUploads) { - $fullPath = $imagePath . str_random(16) . '-' . $imageName; + $fullPath = $imagePath . Str::random(16) . '-' . $imageName; } try { @@ -220,7 +221,7 @@ class ImageService extends UploadService $storage->put($thumbFilePath, $thumbData); $storage->setVisibility($thumbFilePath, 'public'); - $this->cache->put('images-' . $image->id . '-' . $thumbFilePath, $thumbFilePath, 60 * 72); + $this->cache->put('images-' . $image->id . '-' . $thumbFilePath, $thumbFilePath, 60 * 60 * 72); return $this->getPublicUrl($thumbFilePath); } @@ -253,7 +254,16 @@ class ImageService extends UploadService } else { $thumb->fit($width, $height); } - return (string)$thumb->encode(); + + $thumbData = (string)$thumb->encode(); + + // Use original image data if we're keeping the ratio + // and the resizing does not save any space. + if ($keepRatio && strlen($thumbData) > strlen($imageData)) { + return $imageData; + } + + return $thumbData; } /** diff --git a/app/helpers.php b/app/helpers.php index f36f2e59d..65da1853b 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -12,7 +12,7 @@ use BookStack\Settings\SettingService; * @return string * @throws Exception */ -function versioned_asset($file = '') : string +function versioned_asset(string $file = ''): string { static $version = null; @@ -35,25 +35,23 @@ function versioned_asset($file = '') : string * Defaults to public 'Guest' user if not logged in. * @return User */ -function user() : User +function user(): User { return auth()->user() ?: User::getDefault(); } /** * Check if current user is a signed in user. - * @return bool */ -function signedInUser() : bool +function signedInUser(): bool { return auth()->user() && !auth()->user()->isDefault(); } /** * Check if the current user has general access. - * @return bool */ -function hasAppAccess() : bool +function hasAppAccess(): bool { return !auth()->guest() || setting('app-public'); } @@ -62,11 +60,8 @@ function hasAppAccess() : bool * Check if the current user has a permission. * If an ownable element is passed in the jointPermissions are checked against * that particular item. - * @param string $permission - * @param Ownable $ownable - * @return bool */ -function userCan(string $permission, Ownable $ownable = null) : bool +function userCan(string $permission, Ownable $ownable = null): bool { if ($ownable === null) { return user() && user()->can($permission); @@ -84,7 +79,7 @@ function userCan(string $permission, Ownable $ownable = null) : bool * @param string|null $entityClass * @return bool */ -function userCanOnAny(string $permission, string $entityClass = null) : bool +function userCanOnAny(string $permission, string $entityClass = null): bool { $permissionService = app(PermissionService::class); return $permissionService->checkUserHasPermissionOnAnything($permission, $entityClass); @@ -92,11 +87,11 @@ function userCanOnAny(string $permission, string $entityClass = null) : bool /** * Helper to access system settings. - * @param $key - * @param bool $default + * @param string $key + * @param $default * @return bool|string|SettingService */ -function setting($key = null, $default = false) +function setting(string $key = null, $default = false) { $settingService = resolve(SettingService::class); if (is_null($key)) { @@ -110,7 +105,7 @@ function setting($key = null, $default = false) * @param string $path * @return string */ -function theme_path($path = '') : string +function theme_path(string $path = ''): string { $theme = config('view.theme'); if (!$theme) { @@ -130,7 +125,7 @@ function theme_path($path = '') : string * @param array $attrs * @return mixed */ -function icon($name, $attrs = []) +function icon(string $name, array $attrs = []): string { $attrs = array_merge([ 'class' => 'svg-icon', @@ -142,7 +137,7 @@ function icon($name, $attrs = []) $attrString .= $attrName . '="' . $attr . '" '; } - $iconPath = resource_path('assets/icons/' . $name . '.svg'); + $iconPath = resource_path('icons/' . $name . '.svg'); $themeIconPath = theme_path('icons/' . $name . '.svg'); if ($themeIconPath && file_exists($themeIconPath)) { $iconPath = $themeIconPath; @@ -158,12 +153,12 @@ function icon($name, $attrs = []) * Generate a url with multiple parameters for sorting purposes. * Works out the logic to set the correct sorting direction * Discards empty parameters and allows overriding. - * @param $path + * @param string $path * @param array $data * @param array $overrideData * @return string */ -function sortUrl($path, $data, $overrideData = []) +function sortUrl(string $path, array $data, array $overrideData = []): string { $queryStringSections = []; $queryData = array_merge($data, $overrideData); diff --git a/bootstrap/app.php b/bootstrap/app.php index 516980cc1..6538aa81c 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -11,8 +11,8 @@ | */ -$app = new \BookStack\Application( - realpath(__DIR__.'/../') +$app = new BookStack\Application( + dirname(__DIR__) ); /* diff --git a/composer.json b/composer.json index 61bb8509e..0edf7bae8 100644 --- a/composer.json +++ b/composer.json @@ -5,46 +5,48 @@ "license": "MIT", "type": "project", "require": { - "php": ">=7.0.5", - "ext-json": "*", - "ext-tidy": "*", - "ext-dom": "*", - "ext-xml": "*", - "ext-mbstring": "*", - "ext-gd": "*", + "php": "^7.2", "ext-curl": "*", - "laravel/framework": "~5.5.44", - "fideloper/proxy": "~3.3", - "intervention/image": "^2.4", - "laravel/socialite": "3.0.x-dev", - "league/flysystem-aws-s3-v3": "^1.0", - "barryvdh/laravel-dompdf": "^0.8.1", - "predis/predis": "^1.1", + "ext-dom": "*", + "ext-gd": "*", + "ext-json": "*", + "ext-mbstring": "*", + "ext-tidy": "*", + "ext-xml": "*", + "barryvdh/laravel-dompdf": "^0.8.5", + "barryvdh/laravel-snappy": "^0.4.5", + "doctrine/dbal": "^2.9", + "fideloper/proxy": "^4.0", "gathercontent/htmldiff": "^0.2.1", - "barryvdh/laravel-snappy": "^0.4.0", - "socialiteproviders/slack": "^3.0", + "intervention/image": "^2.5", + "laravel/framework": "^6.12", + "laravel/socialite": "^4.2", + "league/flysystem-aws-s3-v3": "^1.0", + "onelogin/php-saml": "^3.3", + "predis/predis": "^1.1", + "socialiteproviders/discord": "^2.0", + "socialiteproviders/gitlab": "^3.0", "socialiteproviders/microsoft-azure": "^3.0", "socialiteproviders/okta": "^1.0", - "socialiteproviders/gitlab": "^3.0", - "socialiteproviders/twitch": "^3.0", - "socialiteproviders/discord": "^2.0", - "doctrine/dbal": "^2.5" + "socialiteproviders/slack": "^3.0", + "socialiteproviders/twitch": "^5.0", + "facade/ignition": "^1.4", + "nunomaduro/collision": "^3.0" }, "require-dev": { - "filp/whoops": "~2.0", - "fzaninotto/faker": "~1.4", - "mockery/mockery": "~1.0", - "phpunit/phpunit": "~6.0", - "symfony/css-selector": "3.1.*", - "symfony/dom-crawler": "3.1.*", - "laravel/browser-kit-testing": "^2.0", - "barryvdh/laravel-ide-helper": "^2.4.1", - "barryvdh/laravel-debugbar": "^3.1.0", - "squizlabs/php_codesniffer": "^3.2" + "barryvdh/laravel-debugbar": "^3.2.8", + "barryvdh/laravel-ide-helper": "^2.6.4", + "fzaninotto/faker": "^1.4", + "laravel/browser-kit-testing": "^5.1", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^8.0", + "squizlabs/php_codesniffer": "^3.4", + "wnx/laravel-stats": "^2.0" }, "autoload": { "classmap": [ - "database" + "database/seeds", + "database/factories" ], "psr-4": { "BookStack\\": "app/" @@ -57,37 +59,45 @@ }, "scripts": { "post-root-package-install": [ - "php -r \"file_exists('.env') || copy('.env.example', '.env');\"" + "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" ], "post-create-project-cmd": [ - "php artisan key:generate" + "@php artisan key:generate --ansi" ], "pre-update-cmd": [ - "php -r \"!file_exists('bootstrap/cache/services.php') || @unlink('bootstrap/cache/services.php');\"", - "php -r \"!file_exists('bootstrap/cache/compiled.php') || @unlink('bootstrap/cache/compiled.php');\"" + "@php -r \"!file_exists('bootstrap/cache/services.php') || @unlink('bootstrap/cache/services.php');\"", + "@php -r \"!file_exists('bootstrap/cache/compiled.php') || @unlink('bootstrap/cache/compiled.php');\"" ], "pre-install-cmd": [ - "php -r \"!file_exists('bootstrap/cache/services.php') || @unlink('bootstrap/cache/services.php');\"", - "php -r \"!file_exists('bootstrap/cache/compiled.php') || @unlink('bootstrap/cache/compiled.php');\"" + "@php -r \"!file_exists('bootstrap/cache/services.php') || @unlink('bootstrap/cache/services.php');\"", + "@php -r \"!file_exists('bootstrap/cache/compiled.php') || @unlink('bootstrap/cache/compiled.php');\"" ], "post-install-cmd": [ - "php artisan cache:clear", - "php artisan view:clear" + "@php artisan cache:clear", + "@php artisan view:clear" ], "post-autoload-dump": [ "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", - "@php artisan package:discover" + "@php artisan package:discover --ansi" ], "refresh-test-database": [ - "php artisan migrate:refresh --database=mysql_testing", - "php artisan db:seed --class=DummyContentSeeder --database=mysql_testing" + "@php artisan migrate:refresh --database=mysql_testing", + "@php artisan db:seed --class=DummyContentSeeder --database=mysql_testing" ] }, "config": { "optimize-autoloader": true, "preferred-install": "dist", + "sort-packages": true, "platform": { - "php": "7.0.5" + "php": "7.2.0" } - } + }, + "extra": { + "laravel": { + "dont-discover": [] + } + }, + "minimum-stability": "dev", + "prefer-stable": true } diff --git a/composer.lock b/composer.lock index d7734ce1a..c35b3f962 100644 --- a/composer.lock +++ b/composer.lock @@ -1,34 +1,33 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0946a07729a7a1bfef9bac185a870afd", + "content-hash": "309610dc13c0d46ca7553ee264a88d29", "packages": [ { "name": "aws/aws-sdk-php", - "version": "3.86.2", + "version": "3.133.6", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "50224232ac7a4e2a6fa4ebbe0281e5b7503acf76" + "reference": "cd7bd2fdd159146ef6c7eeb90b73fae4fd11da57" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/50224232ac7a4e2a6fa4ebbe0281e5b7503acf76", - "reference": "50224232ac7a4e2a6fa4ebbe0281e5b7503acf76", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/cd7bd2fdd159146ef6c7eeb90b73fae4fd11da57", + "reference": "cd7bd2fdd159146ef6c7eeb90b73fae4fd11da57", "shasum": "" }, "require": { "ext-json": "*", "ext-pcre": "*", "ext-simplexml": "*", - "ext-spl": "*", - "guzzlehttp/guzzle": "^5.3.3|^6.2.1", - "guzzlehttp/promises": "~1.0", + "guzzlehttp/guzzle": "^5.3.3|^6.2.1|^7.0", + "guzzlehttp/promises": "^1.0", "guzzlehttp/psr7": "^1.4.1", - "mtdowling/jmespath.php": "~2.2", + "mtdowling/jmespath.php": "^2.5", "php": ">=5.5" }, "require-dev": { @@ -42,7 +41,9 @@ "ext-sockets": "*", "nette/neon": "^2.3", "phpunit/phpunit": "^4.8.35|^5.4.3", - "psr/cache": "^1.0" + "psr/cache": "^1.0", + "psr/simple-cache": "^1.0", + "sebastian/comparator": "^1.2.3" }, "suggest": { "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", @@ -87,25 +88,25 @@ "s3", "sdk" ], - "time": "2019-01-18T21:10:44+00:00" + "time": "2020-01-24T19:11:35+00:00" }, { "name": "barryvdh/laravel-dompdf", - "version": "v0.8.3", + "version": "v0.8.5", "source": { "type": "git", "url": "https://github.com/barryvdh/laravel-dompdf.git", - "reference": "46781d0304277845a19c09c169bc595fd182cce4" + "reference": "7393732b2f3a3ee357974cbb0c46c9b65b84dad1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/46781d0304277845a19c09c169bc595fd182cce4", - "reference": "46781d0304277845a19c09c169bc595fd182cce4", + "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/7393732b2f3a3ee357974cbb0c46c9b65b84dad1", + "reference": "7393732b2f3a3ee357974cbb0c46c9b65b84dad1", "shasum": "" }, "require": { "dompdf/dompdf": "^0.8", - "illuminate/support": "5.5.x|5.6.x|5.7.x", + "illuminate/support": "^5.5|^6", "php": ">=7" }, "type": "library", @@ -143,25 +144,25 @@ "laravel", "pdf" ], - "time": "2018-08-31T13:25:44+00:00" + "time": "2019-08-23T14:30:33+00:00" }, { "name": "barryvdh/laravel-snappy", - "version": "v0.4.3", + "version": "v0.4.6", "source": { "type": "git", "url": "https://github.com/barryvdh/laravel-snappy.git", - "reference": "62bb5017b7004bf3e48bfed3d5c00d3dc6e60478" + "reference": "94d53c88fa58baa4573c5854663ebc9955f21265" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-snappy/zipball/62bb5017b7004bf3e48bfed3d5c00d3dc6e60478", - "reference": "62bb5017b7004bf3e48bfed3d5c00d3dc6e60478", + "url": "https://api.github.com/repos/barryvdh/laravel-snappy/zipball/94d53c88fa58baa4573c5854663ebc9955f21265", + "reference": "94d53c88fa58baa4573c5854663ebc9955f21265", "shasum": "" }, "require": { - "illuminate/filesystem": "5.5.x|5.6.x|5.7.x", - "illuminate/support": "5.5.x|5.6.x|5.7.x", + "illuminate/filesystem": "5.5.x|5.6.x|5.7.x|5.8.x|6.*", + "illuminate/support": "5.5.x|5.6.x|5.7.x|5.8.x|6.*", "knplabs/knp-snappy": "^1", "php": ">=7" }, @@ -195,7 +196,7 @@ "email": "barryvdh@gmail.com" } ], - "description": "Snappy PDF/Image for Laravel 4", + "description": "Snappy PDF/Image for Laravel", "keywords": [ "image", "laravel", @@ -204,7 +205,7 @@ "wkhtmltoimage", "wkhtmltopdf" ], - "time": "2018-09-06T10:14:15+00:00" + "time": "2019-10-02T23:27:09+00:00" }, { "name": "cogpowered/finediff", @@ -257,103 +258,40 @@ ], "time": "2014-05-19T10:25:02+00:00" }, - { - "name": "doctrine/annotations", - "version": "v1.4.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "54cacc9b81758b14e3ce750f205a393d52339e97" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/54cacc9b81758b14e3ce750f205a393d52339e97", - "reference": "54cacc9b81758b14e3ce750f205a393d52339e97", - "shasum": "" - }, - "require": { - "doctrine/lexer": "1.*", - "php": "^5.6 || ^7.0" - }, - "require-dev": { - "doctrine/cache": "1.*", - "phpunit/phpunit": "^5.7" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Docblock Annotations Parser", - "homepage": "http://www.doctrine-project.org", - "keywords": [ - "annotations", - "docblock", - "parser" - ], - "time": "2017-02-24T16:22:25+00:00" - }, { "name": "doctrine/cache", - "version": "v1.6.2", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/doctrine/cache.git", - "reference": "eb152c5100571c7a45470ff2a35095ab3f3b900b" + "reference": "382e7f4db9a12dc6c19431743a2b096041bcdd62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/eb152c5100571c7a45470ff2a35095ab3f3b900b", - "reference": "eb152c5100571c7a45470ff2a35095ab3f3b900b", + "url": "https://api.github.com/repos/doctrine/cache/zipball/382e7f4db9a12dc6c19431743a2b096041bcdd62", + "reference": "382e7f4db9a12dc6c19431743a2b096041bcdd62", "shasum": "" }, "require": { - "php": "~5.5|~7.0" + "php": "~7.1" }, "conflict": { "doctrine/common": ">2.2,<2.4" }, "require-dev": { - "phpunit/phpunit": "~4.8|~5.0", - "predis/predis": "~1.0", - "satooshi/php-coveralls": "~0.6" + "alcaeus/mongo-php-adapter": "^1.1", + "doctrine/coding-standard": "^6.0", + "mongodb/mongodb": "^1.1", + "phpunit/phpunit": "^7.0", + "predis/predis": "~1.0" + }, + "suggest": { + "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6.x-dev" + "dev-master": "1.9.x-dev" } }, "autoload": { @@ -366,6 +304,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -374,10 +316,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -387,44 +325,64 @@ "email": "schmittjoh@gmail.com" } ], - "description": "Caching library offering an object-oriented API for many cache backends", - "homepage": "http://www.doctrine-project.org", + "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", + "homepage": "https://www.doctrine-project.org/projects/cache.html", "keywords": [ + "abstraction", + "apcu", "cache", - "caching" + "caching", + "couchdb", + "memcached", + "php", + "redis", + "xcache" ], - "time": "2017-07-22T12:49:21+00:00" + "time": "2019-11-29T15:36:20+00:00" }, { - "name": "doctrine/collections", - "version": "v1.4.0", + "name": "doctrine/dbal", + "version": "v2.10.1", "source": { "type": "git", - "url": "https://github.com/doctrine/collections.git", - "reference": "1a4fb7e902202c33cce8c55989b945612943c2ba" + "url": "https://github.com/doctrine/dbal.git", + "reference": "c2b8e6e82732a64ecde1cddf9e1e06cb8556e3d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/collections/zipball/1a4fb7e902202c33cce8c55989b945612943c2ba", - "reference": "1a4fb7e902202c33cce8c55989b945612943c2ba", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/c2b8e6e82732a64ecde1cddf9e1e06cb8556e3d8", + "reference": "c2b8e6e82732a64ecde1cddf9e1e06cb8556e3d8", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "doctrine/cache": "^1.0", + "doctrine/event-manager": "^1.0", + "ext-pdo": "*", + "php": "^7.2" }, "require-dev": { - "doctrine/coding-standard": "~0.1@dev", - "phpunit/phpunit": "^5.7" + "doctrine/coding-standard": "^6.0", + "jetbrains/phpstorm-stubs": "^2019.1", + "phpstan/phpstan": "^0.11.3", + "phpunit/phpunit": "^8.4.1", + "symfony/console": "^2.0.5|^3.0|^4.0|^5.0" }, + "suggest": { + "symfony/console": "For helpful console commands such as SQL execution and import of files." + }, + "bin": [ + "bin/doctrine-dbal" + ], "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "2.10.x-dev", + "dev-develop": "3.0.x-dev" } }, "autoload": { - "psr-0": { - "Doctrine\\Common\\Collections\\": "lib/" + "psr-4": { + "Doctrine\\DBAL\\": "lib/Doctrine/DBAL" } }, "notification-url": "https://packagist.org/downloads/", @@ -432,6 +390,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -440,57 +402,64 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" } ], - "description": "Collections Abstraction library", - "homepage": "http://www.doctrine-project.org", + "description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.", + "homepage": "https://www.doctrine-project.org/projects/dbal.html", "keywords": [ - "array", - "collections", - "iterator" + "abstraction", + "database", + "db2", + "dbal", + "mariadb", + "mssql", + "mysql", + "oci8", + "oracle", + "pdo", + "pgsql", + "postgresql", + "queryobject", + "sasql", + "sql", + "sqlanywhere", + "sqlite", + "sqlserver", + "sqlsrv" ], - "time": "2017-01-03T10:49:41+00:00" + "time": "2020-01-04T12:56:21+00:00" }, { - "name": "doctrine/common", - "version": "v2.7.3", + "name": "doctrine/event-manager", + "version": "1.1.0", "source": { "type": "git", - "url": "https://github.com/doctrine/common.git", - "reference": "4acb8f89626baafede6ee5475bc5844096eba8a9" + "url": "https://github.com/doctrine/event-manager.git", + "reference": "629572819973f13486371cb611386eb17851e85c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/common/zipball/4acb8f89626baafede6ee5475bc5844096eba8a9", - "reference": "4acb8f89626baafede6ee5475bc5844096eba8a9", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/629572819973f13486371cb611386eb17851e85c", + "reference": "629572819973f13486371cb611386eb17851e85c", "shasum": "" }, "require": { - "doctrine/annotations": "1.*", - "doctrine/cache": "1.*", - "doctrine/collections": "1.*", - "doctrine/inflector": "1.*", - "doctrine/lexer": "1.*", - "php": "~5.6|~7.0" + "php": "^7.1" + }, + "conflict": { + "doctrine/common": "<2.9@dev" }, "require-dev": { - "phpunit/phpunit": "^5.4.6" + "doctrine/coding-standard": "^6.0", + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { @@ -503,6 +472,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -511,10 +484,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -522,106 +491,39 @@ { "name": "Johannes Schmitt", "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" } ], - "description": "Common Library for Doctrine projects", - "homepage": "http://www.doctrine-project.org", + "description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.", + "homepage": "https://www.doctrine-project.org/projects/event-manager.html", "keywords": [ - "annotations", - "collections", - "eventmanager", - "persistence", - "spl" + "event", + "event dispatcher", + "event manager", + "event system", + "events" ], - "time": "2017-07-22T08:35:12+00:00" - }, - { - "name": "doctrine/dbal", - "version": "v2.5.13", - "source": { - "type": "git", - "url": "https://github.com/doctrine/dbal.git", - "reference": "729340d8d1eec8f01bff708e12e449a3415af873" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/729340d8d1eec8f01bff708e12e449a3415af873", - "reference": "729340d8d1eec8f01bff708e12e449a3415af873", - "shasum": "" - }, - "require": { - "doctrine/common": ">=2.4,<2.8-dev", - "php": ">=5.3.2" - }, - "require-dev": { - "phpunit/phpunit": "4.*", - "symfony/console": "2.*||^3.0" - }, - "suggest": { - "symfony/console": "For helpful console commands such as SQL execution and import of files." - }, - "bin": [ - "bin/doctrine-dbal" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.5.x-dev" - } - }, - "autoload": { - "psr-0": { - "Doctrine\\DBAL\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - } - ], - "description": "Database Abstraction Layer", - "homepage": "http://www.doctrine-project.org", - "keywords": [ - "database", - "dbal", - "persistence", - "queryobject" - ], - "time": "2017-07-22T20:44:48+00:00" + "time": "2019-11-10T09:48:07+00:00" }, { "name": "doctrine/inflector", - "version": "v1.2.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "e11d84c6e018beedd929cff5220969a3c6d1d462" + "reference": "ec3a55242203ffa6a4b27c58176da97ff0a7aec1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/e11d84c6e018beedd929cff5220969a3c6d1d462", - "reference": "e11d84c6e018beedd929cff5220969a3c6d1d462", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/ec3a55242203ffa6a4b27c58176da97ff0a7aec1", + "reference": "ec3a55242203ffa6a4b27c58176da97ff0a7aec1", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.1" }, "require-dev": { "phpunit/phpunit": "^6.2" @@ -629,7 +531,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "1.3.x-dev" } }, "autoload": { @@ -642,6 +544,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -650,10 +556,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -671,34 +573,39 @@ "singularize", "string" ], - "time": "2017-07-22T12:18:28+00:00" + "time": "2019-10-30T19:59:35+00:00" }, { "name": "doctrine/lexer", - "version": "v1.0.1", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" + "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", - "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", + "reference": "5242d66dbeb21a30dd8a3e66bf7a73b66e05e1f6", "shasum": "" }, "require": { - "php": ">=5.3.2" + "php": "^7.2" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "phpstan/phpstan": "^0.11.8", + "phpunit/phpunit": "^8.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { - "psr-0": { - "Doctrine\\Common\\Lexer\\": "lib/" + "psr-4": { + "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" } }, "notification-url": "https://packagist.org/downloads/", @@ -706,51 +613,54 @@ "MIT" ], "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, { "name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com" }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, { "name": "Johannes Schmitt", "email": "schmittjoh@gmail.com" } ], - "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", - "homepage": "http://www.doctrine-project.org", + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", "keywords": [ + "annotations", + "docblock", "lexer", - "parser" + "parser", + "php" ], - "time": "2014-09-09T13:34:57+00:00" + "time": "2019-10-30T14:39:59+00:00" }, { "name": "dompdf/dompdf", - "version": "v0.8.3", + "version": "v0.8.4", "source": { "type": "git", "url": "https://github.com/dompdf/dompdf.git", - "reference": "75f13c700009be21a1965dc2c5b68a8708c22ba2" + "reference": "8f49b3b01693f51037dd50da81090beba1b5c005" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/dompdf/zipball/75f13c700009be21a1965dc2c5b68a8708c22ba2", - "reference": "75f13c700009be21a1965dc2c5b68a8708c22ba2", + "url": "https://api.github.com/repos/dompdf/dompdf/zipball/8f49b3b01693f51037dd50da81090beba1b5c005", + "reference": "8f49b3b01693f51037dd50da81090beba1b5c005", "shasum": "" }, "require": { "ext-dom": "*", "ext-mbstring": "*", - "phenx/php-font-lib": "0.5.*", - "phenx/php-svg-lib": "0.3.*", - "php": ">=5.4.0" + "phenx/php-font-lib": "^0.5.1", + "phenx/php-svg-lib": "^0.3.3", + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^4.8|^5.5|^6.5", - "squizlabs/php_codesniffer": "2.*" + "phpunit/phpunit": "^7.5", + "squizlabs/php_codesniffer": "^3.5" }, "suggest": { "ext-gd": "Needed to process images", @@ -791,29 +701,84 @@ ], "description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter", "homepage": "https://github.com/dompdf/dompdf", - "time": "2018-12-14T02:40:31+00:00" + "time": "2020-01-20T17:00:46+00:00" }, { - "name": "egulias/email-validator", - "version": "2.1.7", + "name": "dragonmantank/cron-expression", + "version": "v2.3.0", "source": { "type": "git", - "url": "https://github.com/egulias/EmailValidator.git", - "reference": "709f21f92707308cdf8f9bcfa1af4cb26586521e" + "url": "https://github.com/dragonmantank/cron-expression.git", + "reference": "72b6fbf76adb3cf5bc0db68559b33d41219aba27" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/709f21f92707308cdf8f9bcfa1af4cb26586521e", - "reference": "709f21f92707308cdf8f9bcfa1af4cb26586521e", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/72b6fbf76adb3cf5bc0db68559b33d41219aba27", + "reference": "72b6fbf76adb3cf5bc0db68559b33d41219aba27", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.4|^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-4": { + "Cron\\": "src/Cron/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Chris Tankersley", + "email": "chris@ctankersley.com", + "homepage": "https://github.com/dragonmantank" + } + ], + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": [ + "cron", + "schedule" + ], + "time": "2019-03-31T00:38:28+00:00" + }, + { + "name": "egulias/email-validator", + "version": "2.1.15", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "e834eea5306d85d67de5a05db5882911d5b29357" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/e834eea5306d85d67de5a05db5882911d5b29357", + "reference": "e834eea5306d85d67de5a05db5882911d5b29357", "shasum": "" }, "require": { "doctrine/lexer": "^1.0.1", - "php": ">= 5.5" + "php": ">=5.5", + "symfony/polyfill-intl-idn": "^1.10" }, "require-dev": { - "dominicsayers/isemail": "dev-master", - "phpunit/phpunit": "^4.8.35||^5.7||^6.0", + "dominicsayers/isemail": "^3.0.7", + "phpunit/phpunit": "^4.8.36|^7.5.15", "satooshi/php-coveralls": "^1.0.1" }, "suggest": { @@ -822,7 +787,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "2.1.x-dev" } }, "autoload": { @@ -848,33 +813,154 @@ "validation", "validator" ], - "time": "2018-12-04T22:38:24+00:00" + "time": "2020-01-20T21:40:59+00:00" }, { - "name": "erusev/parsedown", - "version": "1.7.1", + "name": "facade/flare-client-php", + "version": "1.3.1", "source": { "type": "git", - "url": "https://github.com/erusev/parsedown.git", - "reference": "92e9c27ba0e74b8b028b111d1b6f956a15c01fc1" + "url": "https://github.com/facade/flare-client-php.git", + "reference": "24444ea0e1556f0a4b5fc8e61802caf72ae9a408" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/erusev/parsedown/zipball/92e9c27ba0e74b8b028b111d1b6f956a15c01fc1", - "reference": "92e9c27ba0e74b8b028b111d1b6f956a15c01fc1", + "url": "https://api.github.com/repos/facade/flare-client-php/zipball/24444ea0e1556f0a4b5fc8e61802caf72ae9a408", + "reference": "24444ea0e1556f0a4b5fc8e61802caf72ae9a408", "shasum": "" }, "require": { - "ext-mbstring": "*", - "php": ">=5.3.0" + "facade/ignition-contracts": "~1.0", + "illuminate/pipeline": "~5.5|~5.6|~5.7|~5.8|^6.0", + "php": "^7.1", + "symfony/http-foundation": "~3.3|~4.1", + "symfony/var-dumper": "^3.4|^4.0|^5.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35" + "larapack/dd": "^1.1", + "phpunit/phpunit": "^7.5.16", + "spatie/phpunit-snapshot-assertions": "^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Facade\\FlareClient\\": "src" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Send PHP errors to Flare", + "homepage": "https://github.com/facade/flare-client-php", + "keywords": [ + "exception", + "facade", + "flare", + "reporting" + ], + "time": "2019-12-15T18:28:38+00:00" + }, + { + "name": "facade/ignition", + "version": "1.16.0", + "source": { + "type": "git", + "url": "https://github.com/facade/ignition.git", + "reference": "37f094775814b68d0c6cc8b8ff3c3be243f20725" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facade/ignition/zipball/37f094775814b68d0c6cc8b8ff3c3be243f20725", + "reference": "37f094775814b68d0c6cc8b8ff3c3be243f20725", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "facade/flare-client-php": "^1.3", + "facade/ignition-contracts": "^1.0", + "filp/whoops": "^2.4", + "illuminate/support": "~5.5.0 || ~5.6.0 || ~5.7.0 || ~5.8.0 || ^6.0", + "monolog/monolog": "^1.12 || ^2.0", + "php": "^7.1", + "scrivo/highlight.php": "^9.15", + "symfony/console": "^3.4 || ^4.0", + "symfony/var-dumper": "^3.4 || ^4.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.14", + "mockery/mockery": "^1.2", + "orchestra/testbench": "^3.5 || ^3.6 || ^3.7 || ^3.8 || ^4.0" + }, + "suggest": { + "laravel/telescope": "^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "v2.x-dev" + }, + "laravel": { + "providers": [ + "Facade\\Ignition\\IgnitionServiceProvider" + ], + "aliases": { + "Flare": "Facade\\Ignition\\Facades\\Flare" + } + } + }, + "autoload": { + "psr-4": { + "Facade\\Ignition\\": "src" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A beautiful error page for Laravel applications.", + "homepage": "https://github.com/facade/ignition", + "keywords": [ + "error", + "flare", + "laravel", + "page" + ], + "time": "2020-01-21T17:46:02+00:00" + }, + { + "name": "facade/ignition-contracts", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/facade/ignition-contracts.git", + "reference": "f445db0fb86f48e205787b2592840dd9c80ded28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facade/ignition-contracts/zipball/f445db0fb86f48e205787b2592840dd9c80ded28", + "reference": "f445db0fb86f48e205787b2592840dd9c80ded28", + "shasum": "" + }, + "require": { + "php": "^7.1" }, "type": "library", "autoload": { - "psr-0": { - "Parsedown": "" + "psr-4": { + "Facade\\IgnitionContracts\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -883,47 +969,46 @@ ], "authors": [ { - "name": "Emanuil Rusev", - "email": "hello@erusev.com", - "homepage": "http://erusev.com" + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://flareapp.io", + "role": "Developer" } ], - "description": "Parser for Markdown.", - "homepage": "http://parsedown.org", + "description": "Solution contracts for Ignition", + "homepage": "https://github.com/facade/ignition-contracts", "keywords": [ - "markdown", - "parser" + "contracts", + "flare", + "ignition" ], - "time": "2018-03-08T01:11:30+00:00" + "time": "2019-08-30T14:06:08+00:00" }, { "name": "fideloper/proxy", - "version": "3.3.4", + "version": "4.2.2", "source": { "type": "git", "url": "https://github.com/fideloper/TrustedProxy.git", - "reference": "9cdf6f118af58d89764249bbcc7bb260c132924f" + "reference": "790194d5d3da89a713478875d2e2d05855a90a81" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fideloper/TrustedProxy/zipball/9cdf6f118af58d89764249bbcc7bb260c132924f", - "reference": "9cdf6f118af58d89764249bbcc7bb260c132924f", + "url": "https://api.github.com/repos/fideloper/TrustedProxy/zipball/790194d5d3da89a713478875d2e2d05855a90a81", + "reference": "790194d5d3da89a713478875d2e2d05855a90a81", "shasum": "" }, "require": { - "illuminate/contracts": "~5.0", + "illuminate/contracts": "^5.0|^6.0|^7.0", "php": ">=5.4.0" }, "require-dev": { - "illuminate/http": "~5.0", - "mockery/mockery": "~0.9.3", - "phpunit/phpunit": "^5.7" + "illuminate/http": "^5.0|^6.0|^7.0", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { - "branch-alias": { - "dev-master": "3.3-dev" - }, "laravel": { "providers": [ "Fideloper\\Proxy\\TrustedProxyServiceProvider" @@ -951,7 +1036,68 @@ "proxy", "trusted proxy" ], - "time": "2017-06-15T17:19:42+00:00" + "time": "2019-12-20T13:11:11+00:00" + }, + { + "name": "filp/whoops", + "version": "2.7.1", + "source": { + "type": "git", + "url": "https://github.com/filp/whoops.git", + "reference": "fff6f1e4f36be0e0d0b84d66b413d9dcb0c49130" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filp/whoops/zipball/fff6f1e4f36be0e0d0b84d66b413d9dcb0c49130", + "reference": "fff6f1e4f36be0e0d0b84d66b413d9dcb0c49130", + "shasum": "" + }, + "require": { + "php": "^5.5.9 || ^7.0", + "psr/log": "^1.0.1" + }, + "require-dev": { + "mockery/mockery": "^0.9 || ^1.0", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0", + "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0 || ^5.0" + }, + "suggest": { + "symfony/var-dumper": "Pretty print complex values better with var-dumper available", + "whoops/soap": "Formats errors as SOAP responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-4": { + "Whoops\\": "src/Whoops/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Filipe Dobreira", + "homepage": "https://github.com/filp", + "role": "Developer" + } + ], + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", + "keywords": [ + "error", + "exception", + "handling", + "library", + "throwable", + "whoops" + ], + "time": "2020-01-15T10:00:00+00:00" }, { "name": "gathercontent/htmldiff", @@ -1004,44 +1150,46 @@ }, { "name": "guzzlehttp/guzzle", - "version": "6.3.3", + "version": "6.5.2", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" + "reference": "43ece0e75098b7ecd8d13918293029e555a50f82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", - "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/43ece0e75098b7ecd8d13918293029e555a50f82", + "reference": "43ece0e75098b7ecd8d13918293029e555a50f82", "shasum": "" }, "require": { + "ext-json": "*", "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.4", + "guzzlehttp/psr7": "^1.6.1", "php": ">=5.5" }, "require-dev": { "ext-curl": "*", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", - "psr/log": "^1.0" + "psr/log": "^1.1" }, "suggest": { + "ext-intl": "Required for Internationalized Domain Name (IDN) support", "psr/log": "Required for using the Log middleware" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "6.3-dev" + "dev-master": "6.5-dev" } }, "autoload": { - "files": [ - "src/functions_include.php" - ], "psr-4": { "GuzzleHttp\\": "src/" - } + }, + "files": [ + "src/functions_include.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1065,7 +1213,7 @@ "rest", "web service" ], - "time": "2018-04-22T15:46:56+00:00" + "time": "2019-12-23T11:57:10+00:00" }, { "name": "guzzlehttp/promises", @@ -1120,33 +1268,37 @@ }, { "name": "guzzlehttp/psr7", - "version": "1.5.2", + "version": "1.6.1", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "9f83dded91781a01c63574e387eaa769be769115" + "reference": "239400de7a173fe9901b9ac7c06497751f00727a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/9f83dded91781a01c63574e387eaa769be769115", - "reference": "9f83dded91781a01c63574e387eaa769be769115", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", + "reference": "239400de7a173fe9901b9ac7c06497751f00727a", "shasum": "" }, "require": { "php": ">=5.4.0", "psr/http-message": "~1.0", - "ralouphie/getallheaders": "^2.0.5" + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" }, "provide": { "psr/http-message-implementation": "1.0" }, "require-dev": { + "ext-zlib": "*", "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" }, + "suggest": { + "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.5-dev" + "dev-master": "1.6-dev" } }, "autoload": { @@ -1183,20 +1335,20 @@ "uri", "url" ], - "time": "2018-12-04T20:46:45+00:00" + "time": "2019-07-01T23:21:34+00:00" }, { "name": "intervention/image", - "version": "2.4.2", + "version": "2.5.1", "source": { "type": "git", "url": "https://github.com/Intervention/image.git", - "reference": "e82d274f786e3d4b866a59b173f42e716f0783eb" + "reference": "abbf18d5ab8367f96b3205ca3c89fb2fa598c69e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Intervention/image/zipball/e82d274f786e3d4b866a59b173f42e716f0783eb", - "reference": "e82d274f786e3d4b866a59b173f42e716f0783eb", + "url": "https://api.github.com/repos/Intervention/image/zipball/abbf18d5ab8367f96b3205ca3c89fb2fa598c69e", + "reference": "abbf18d5ab8367f96b3205ca3c89fb2fa598c69e", "shasum": "" }, "require": { @@ -1253,29 +1405,117 @@ "thumbnail", "watermark" ], - "time": "2018-05-29T14:19:03+00:00" + "time": "2019-11-02T09:15:47+00:00" }, { - "name": "knplabs/knp-snappy", - "version": "v1.0.4", + "name": "jakub-onderka/php-console-color", + "version": "v0.2", "source": { "type": "git", - "url": "https://github.com/KnpLabs/snappy.git", - "reference": "144c4ecd1ccaeda936bf832b93079efc490e6850" + "url": "https://github.com/JakubOnderka/PHP-Console-Color.git", + "reference": "d5deaecff52a0d61ccb613bb3804088da0307191" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/KnpLabs/snappy/zipball/144c4ecd1ccaeda936bf832b93079efc490e6850", - "reference": "144c4ecd1ccaeda936bf832b93079efc490e6850", + "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/d5deaecff52a0d61ccb613bb3804088da0307191", + "reference": "d5deaecff52a0d61ccb613bb3804088da0307191", "shasum": "" }, "require": { - "php": ">=5.6", - "psr/log": "^1.0", - "symfony/process": "~2.3 || ~3.0 || ~4.0" + "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "~4.8.36" + "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" + } + ], + "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", + "time": "2018-09-29T18:48:56+00:00" + }, + { + "name": "knplabs/knp-snappy", + "version": "v1.2.1", + "source": { + "type": "git", + "url": "https://github.com/KnpLabs/snappy.git", + "reference": "7bac60fb729147b7ccd8532c07df3f52a4afa8a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/KnpLabs/snappy/zipball/7bac60fb729147b7ccd8532c07df3f52a4afa8a4", + "reference": "7bac60fb729147b7ccd8532c07df3f52a4afa8a4", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/log": "^1.0", + "symfony/process": "~3.4||~4.3||~5.0" + }, + "require-dev": { + "phpunit/phpunit": "~7.4" }, "suggest": { "h4cc/wkhtmltoimage-amd64": "Provides wkhtmltoimage-amd64 binary for Linux-compatible machines, use version `~0.12` as dependency", @@ -1287,7 +1527,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { @@ -1319,46 +1559,53 @@ "thumbnail", "wkhtmltopdf" ], - "time": "2018-01-22T19:40:51+00:00" + "time": "2020-01-20T08:30:30+00:00" }, { "name": "laravel/framework", - "version": "v5.5.44", + "version": "v6.12.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "00615aa27eb98f0ee6fb9f2160c6c60ae04abd1b" + "reference": "8e189a8dee7ff76bf50acb7e80aa1a36afaf54d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/00615aa27eb98f0ee6fb9f2160c6c60ae04abd1b", - "reference": "00615aa27eb98f0ee6fb9f2160c6c60ae04abd1b", + "url": "https://api.github.com/repos/laravel/framework/zipball/8e189a8dee7ff76bf50acb7e80aa1a36afaf54d4", + "reference": "8e189a8dee7ff76bf50acb7e80aa1a36afaf54d4", "shasum": "" }, "require": { - "doctrine/inflector": "~1.1", - "erusev/parsedown": "~1.7", + "doctrine/inflector": "^1.1", + "dragonmantank/cron-expression": "^2.0", + "egulias/email-validator": "^2.1.10", + "ext-json": "*", "ext-mbstring": "*", "ext-openssl": "*", + "league/commonmark": "^1.1", + "league/commonmark-ext-table": "^2.1", "league/flysystem": "^1.0.8", - "monolog/monolog": "~1.12", - "mtdowling/cron-expression": "~1.0", - "nesbot/carbon": "^1.24.1", - "php": ">=7.0", - "psr/container": "~1.0", + "monolog/monolog": "^1.12|^2.0", + "nesbot/carbon": "^2.0", + "opis/closure": "^3.1", + "php": "^7.2", + "psr/container": "^1.0", "psr/simple-cache": "^1.0", - "ramsey/uuid": "~3.0", - "swiftmailer/swiftmailer": "~6.0", - "symfony/console": "~3.3", - "symfony/debug": "~3.3", - "symfony/finder": "~3.3", - "symfony/http-foundation": "~3.3", - "symfony/http-kernel": "~3.3", - "symfony/process": "~3.3", - "symfony/routing": "~3.3", - "symfony/var-dumper": "~3.3", - "tijsverkoyen/css-to-inline-styles": "~2.2", - "vlucas/phpdotenv": "~2.2" + "ramsey/uuid": "^3.7", + "swiftmailer/swiftmailer": "^6.0", + "symfony/console": "^4.3.4", + "symfony/debug": "^4.3.4", + "symfony/finder": "^4.3.4", + "symfony/http-foundation": "^4.3.4", + "symfony/http-kernel": "^4.3.4", + "symfony/process": "^4.3.4", + "symfony/routing": "^4.3.4", + "symfony/var-dumper": "^4.3.4", + "tijsverkoyen/css-to-inline-styles": "^2.2.1", + "vlucas/phpdotenv": "^3.3" + }, + "conflict": { + "tightenco/collect": "<5.5.33" }, "replace": { "illuminate/auth": "self.version", @@ -1388,44 +1635,50 @@ "illuminate/support": "self.version", "illuminate/translation": "self.version", "illuminate/validation": "self.version", - "illuminate/view": "self.version", - "tightenco/collect": "<5.5.33" + "illuminate/view": "self.version" }, "require-dev": { - "aws/aws-sdk-php": "~3.0", - "doctrine/dbal": "~2.5", - "filp/whoops": "^2.1.4", - "mockery/mockery": "~1.0", - "orchestra/testbench-core": "3.5.*", - "pda/pheanstalk": "~3.0", - "phpunit/phpunit": "~6.0", + "aws/aws-sdk-php": "^3.0", + "doctrine/dbal": "^2.6", + "filp/whoops": "^2.4", + "guzzlehttp/guzzle": "^6.3", + "league/flysystem-cached-adapter": "^1.0", + "mockery/mockery": "^1.3.1", + "moontoast/math": "^1.1", + "orchestra/testbench-core": "^4.0", + "pda/pheanstalk": "^4.0", + "phpunit/phpunit": "^7.5.15|^8.4|^9.0", "predis/predis": "^1.1.1", - "symfony/css-selector": "~3.3", - "symfony/dom-crawler": "~3.3" + "symfony/cache": "^4.3.4" }, "suggest": { - "aws/aws-sdk-php": "Required to use the SQS queue driver and SES mail driver (~3.0).", - "doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.5).", + "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.0).", + "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6).", + "ext-gd": "Required to use Illuminate\\Http\\Testing\\FileFactory::image().", + "ext-memcached": "Required to use the memcache cache driver.", "ext-pcntl": "Required to use all features of the queue worker.", "ext-posix": "Required to use all features of the queue worker.", - "fzaninotto/faker": "Required to use the eloquent factory builder (~1.4).", - "guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers and the ping methods on schedules (~6.0).", - "laravel/tinker": "Required to use the tinker console command (~1.0).", - "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).", - "league/flysystem-cached-adapter": "Required to use Flysystem caching (~1.0).", - "league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0).", - "nexmo/client": "Required to use the Nexmo transport (~1.0).", - "pda/pheanstalk": "Required to use the beanstalk queue driver (~3.0).", - "predis/predis": "Required to use the redis cache and queue drivers (~1.0).", - "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (~3.0).", - "symfony/css-selector": "Required to use some of the crawler integration testing tools (~3.3).", - "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (~3.3).", - "symfony/psr-http-message-bridge": "Required to psr7 bridging features (~1.0)." + "ext-redis": "Required to use the Redis cache and queue drivers.", + "filp/whoops": "Required for friendly error pages in development (^2.4).", + "fzaninotto/faker": "Required to use the eloquent factory builder (^1.4).", + "guzzlehttp/guzzle": "Required to use the Mailgun mail driver and the ping methods on schedules (^6.0).", + "laravel/tinker": "Required to use the tinker console command (^1.0).", + "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^1.0).", + "league/flysystem-cached-adapter": "Required to use the Flysystem cache (^1.0).", + "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (^1.0).", + "moontoast/math": "Required to use ordered UUIDs (^1.1).", + "nyholm/psr7": "Required to use PSR-7 bridging features (^1.2).", + "pda/pheanstalk": "Required to use the beanstalk queue driver (^4.0).", + "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^4.0).", + "symfony/cache": "Required to PSR-6 cache bridge (^4.3.4).", + "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^1.2).", + "wildbit/swiftmailer-postmark": "Required to use Postmark mail driver (^3.0)." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.5-dev" + "dev-master": "6.x-dev" } }, "autoload": { @@ -1453,38 +1706,39 @@ "framework", "laravel" ], - "time": "2018-10-04T14:51:24+00:00" + "time": "2020-01-21T15:10:03+00:00" }, { "name": "laravel/socialite", - "version": "3.0.x-dev", + "version": "v4.3.1", "source": { "type": "git", "url": "https://github.com/laravel/socialite.git", - "reference": "79316f36641f1916a50ab14d368acdf1d97e46de" + "reference": "2d670d5b100ef2dc72dc578126b2b97985791f52" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/socialite/zipball/79316f36641f1916a50ab14d368acdf1d97e46de", - "reference": "79316f36641f1916a50ab14d368acdf1d97e46de", + "url": "https://api.github.com/repos/laravel/socialite/zipball/2d670d5b100ef2dc72dc578126b2b97985791f52", + "reference": "2d670d5b100ef2dc72dc578126b2b97985791f52", "shasum": "" }, "require": { + "ext-json": "*", "guzzlehttp/guzzle": "~6.0", - "illuminate/contracts": "~5.4", - "illuminate/http": "~5.4", - "illuminate/support": "~5.4", + "illuminate/http": "~5.7.0|~5.8.0|^6.0|^7.0", + "illuminate/support": "~5.7.0|~5.8.0|^6.0|^7.0", "league/oauth1-client": "~1.0", - "php": ">=5.6.4" + "php": "^7.1.3" }, "require-dev": { - "mockery/mockery": "~0.9", - "phpunit/phpunit": "~4.0|~5.0" + "illuminate/contracts": "~5.7.0|~5.8.0|^6.0|^7.0", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^7.0|^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "4.0-dev" }, "laravel": { "providers": [ @@ -1516,20 +1770,156 @@ "laravel", "oauth" ], - "time": "2018-12-21T14:06:32+00:00" + "time": "2019-11-26T17:39:15+00:00" }, { - "name": "league/flysystem", - "version": "1.0.49", + "name": "league/commonmark", + "version": "1.2.2", "source": { "type": "git", - "url": "https://github.com/thephpleague/flysystem.git", - "reference": "a63cc83d8a931b271be45148fa39ba7156782ffd" + "url": "https://github.com/thephpleague/commonmark.git", + "reference": "34cf4ddb3892c715ae785c880e6691d839cff88d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/a63cc83d8a931b271be45148fa39ba7156782ffd", - "reference": "a63cc83d8a931b271be45148fa39ba7156782ffd", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/34cf4ddb3892c715ae785c880e6691d839cff88d", + "reference": "34cf4ddb3892c715ae785c880e6691d839cff88d", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1" + }, + "replace": { + "colinodell/commonmark-php": "*" + }, + "require-dev": { + "cebe/markdown": "~1.0", + "commonmark/commonmark.js": "0.29.1", + "erusev/parsedown": "~1.0", + "ext-json": "*", + "michelf/php-markdown": "~1.4", + "mikehaertl/php-shellcommand": "^1.4", + "phpstan/phpstan-shim": "^0.11.5", + "phpunit/phpunit": "^7.5", + "scrutinizer/ocular": "^1.5", + "symfony/finder": "^4.2" + }, + "suggest": { + "league/commonmark-extras": "Library of useful extensions including smart punctuation" + }, + "bin": [ + "bin/commonmark" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "League\\CommonMark\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "PHP Markdown parser based on the CommonMark spec", + "homepage": "https://commonmark.thephpleague.com", + "keywords": [ + "commonmark", + "markdown", + "parser" + ], + "time": "2020-01-16T01:18:13+00:00" + }, + { + "name": "league/commonmark-ext-table", + "version": "v2.1.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/commonmark-ext-table.git", + "reference": "3228888ea69636e855efcf6636ff8e6316933fe7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/commonmark-ext-table/zipball/3228888ea69636e855efcf6636ff8e6316933fe7", + "reference": "3228888ea69636e855efcf6636ff8e6316933fe7", + "shasum": "" + }, + "require": { + "league/commonmark": "~0.19.3|^1.0", + "php": "^7.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.14", + "phpstan/phpstan": "~0.11", + "phpunit/phpunit": "^7.0|^8.0", + "symfony/var-dumper": "^4.0", + "vimeo/psalm": "^3.0" + }, + "type": "commonmark-extension", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-4": { + "League\\CommonMark\\Ext\\Table\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Martin Hasoň", + "email": "martin.hason@gmail.com" + }, + { + "name": "Webuni s.r.o.", + "homepage": "https://www.webuni.cz" + }, + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com" + } + ], + "description": "Table extension for league/commonmark", + "homepage": "https://github.com/thephpleague/commonmark-ext-table", + "keywords": [ + "commonmark", + "extension", + "markdown", + "table" + ], + "time": "2019-09-26T13:28:33+00:00" + }, + { + "name": "league/flysystem", + "version": "1.0.63", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "8132daec326565036bc8e8d1876f77ec183a7bd6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/8132daec326565036bc8e8d1876f77ec183a7bd6", + "reference": "8132daec326565036bc8e8d1876f77ec183a7bd6", "shasum": "" }, "require": { @@ -1600,20 +1990,20 @@ "sftp", "storage" ], - "time": "2018-11-23T23:41:29+00:00" + "time": "2020-01-04T16:30:31+00:00" }, { "name": "league/flysystem-aws-s3-v3", - "version": "1.0.21", + "version": "1.0.23", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git", - "reference": "43523fec10a831ea48bedb3277e3f3fa218f4e49" + "reference": "15b0cdeab7240bf8e8bffa85ae5275bbc3692bf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/43523fec10a831ea48bedb3277e3f3fa218f4e49", - "reference": "43523fec10a831ea48bedb3277e3f3fa218f4e49", + "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/15b0cdeab7240bf8e8bffa85ae5275bbc3692bf4", + "reference": "15b0cdeab7240bf8e8bffa85ae5275bbc3692bf4", "shasum": "" }, "require": { @@ -1647,7 +2037,7 @@ } ], "description": "Flysystem adapter for the AWS S3 SDK v3.x", - "time": "2018-10-08T07:53:55+00:00" + "time": "2019-06-05T17:18:29+00:00" }, { "name": "league/oauth1-client", @@ -1714,21 +2104,21 @@ }, { "name": "monolog/monolog", - "version": "1.24.0", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266" + "reference": "c861fcba2ca29404dc9e617eedd9eff4616986b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", - "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c861fcba2ca29404dc9e617eedd9eff4616986b8", + "reference": "c861fcba2ca29404dc9e617eedd9eff4616986b8", "shasum": "" }, "require": { - "php": ">=5.3.0", - "psr/log": "~1.0" + "php": "^7.2", + "psr/log": "^1.0.1" }, "provide": { "psr/log-implementation": "1.0.0" @@ -1736,33 +2126,36 @@ "require-dev": { "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", - "graylog2/gelf-php": "~1.0", - "jakub-onderka/php-parallel-lint": "0.9", + "elasticsearch/elasticsearch": "^6.0", + "graylog2/gelf-php": "^1.4.2", + "jakub-onderka/php-parallel-lint": "^0.9", "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", - "phpunit/phpunit": "~4.5", - "phpunit/phpunit-mock-objects": "2.3.0", + "phpspec/prophecy": "^1.6.1", + "phpunit/phpunit": "^8.3", + "predis/predis": "^1.1", + "rollbar/rollbar": "^1.3", "ruflin/elastica": ">=0.90 <3.0", - "sentry/sentry": "^0.13", "swiftmailer/swiftmailer": "^5.3|^6.0" }, "suggest": { "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", - "ext-mongo": "Allow sending log messages to a MongoDB server", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", - "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", "php-console/php-console": "Allow sending log messages to Google Chrome", "rollbar/rollbar": "Allow sending log messages to Rollbar", - "ruflin/elastica": "Allow sending log messages to an Elastic Search server", - "sentry/sentry": "Allow sending log messages to a Sentry server" + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "2.x-dev" } }, "autoload": { @@ -1788,71 +2181,29 @@ "logging", "psr-3" ], - "time": "2018-11-05T09:00:11+00:00" - }, - { - "name": "mtdowling/cron-expression", - "version": "v1.2.1", - "source": { - "type": "git", - "url": "https://github.com/mtdowling/cron-expression.git", - "reference": "9504fa9ea681b586028adaaa0877db4aecf32bad" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/9504fa9ea681b586028adaaa0877db4aecf32bad", - "reference": "9504fa9ea681b586028adaaa0877db4aecf32bad", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.0|~5.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Cron\\": "src/Cron/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", - "keywords": [ - "cron", - "schedule" - ], - "time": "2017-01-23T04:29:33+00:00" + "time": "2019-12-20T14:22:59+00:00" }, { "name": "mtdowling/jmespath.php", - "version": "2.4.0", + "version": "2.5.0", "source": { "type": "git", "url": "https://github.com/jmespath/jmespath.php.git", - "reference": "adcc9531682cf87dfda21e1fd5d0e7a41d292fac" + "reference": "52168cb9472de06979613d365c7f1ab8798be895" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/adcc9531682cf87dfda21e1fd5d0e7a41d292fac", - "reference": "adcc9531682cf87dfda21e1fd5d0e7a41d292fac", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/52168cb9472de06979613d365c7f1ab8798be895", + "reference": "52168cb9472de06979613d365c7f1ab8798be895", "shasum": "" }, "require": { - "php": ">=5.4.0" + "php": ">=5.4.0", + "symfony/polyfill-mbstring": "^1.4" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "composer/xdebug-handler": "^1.2", + "phpunit/phpunit": "^4.8.36|^7.5.15" }, "bin": [ "bin/jp.php" @@ -1860,7 +2211,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "2.5-dev" } }, "autoload": { @@ -1887,35 +2238,43 @@ "json", "jsonpath" ], - "time": "2016-12-03T22:08:25+00:00" + "time": "2019-12-30T18:03:34+00:00" }, { "name": "nesbot/carbon", - "version": "1.36.2", + "version": "2.29.1", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "cd324b98bc30290f233dd0e75e6ce49f7ab2a6c9" + "reference": "e509be5bf2d703390e69e14496d9a1168452b0a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/cd324b98bc30290f233dd0e75e6ce49f7ab2a6c9", - "reference": "cd324b98bc30290f233dd0e75e6ce49f7ab2a6c9", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/e509be5bf2d703390e69e14496d9a1168452b0a2", + "reference": "e509be5bf2d703390e69e14496d9a1168452b0a2", "shasum": "" }, "require": { - "php": ">=5.3.9", - "symfony/translation": "~2.6 || ~3.0 || ~4.0" + "ext-json": "*", + "php": "^7.1.8 || ^8.0", + "symfony/translation": "^3.4 || ^4.0 || ^5.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7" - }, - "suggest": { - "friendsofphp/php-cs-fixer": "Needed for the `composer phpcs` command. Allow to automatically fix code style.", - "phpstan/phpstan": "Needed for the `composer phpstan` command. Allow to detect potential errors." + "friendsofphp/php-cs-fixer": "^2.14 || ^3.0", + "kylekatarnls/multi-tester": "^1.1", + "phpmd/phpmd": "^2.8", + "phpstan/phpstan": "^0.11", + "phpunit/phpunit": "^7.5 || ^8.0", + "squizlabs/php_codesniffer": "^3.4" }, + "bin": [ + "bin/carbon" + ], "type": "library", "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + }, "laravel": { "providers": [ "Carbon\\Laravel\\ServiceProvider" @@ -1924,7 +2283,7 @@ }, "autoload": { "psr-4": { - "": "src/" + "Carbon\\": "src/Carbon/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1936,16 +2295,195 @@ "name": "Brian Nesbitt", "email": "brian@nesbot.com", "homepage": "http://nesbot.com" + }, + { + "name": "kylekatarnls", + "homepage": "http://github.com/kylekatarnls" } ], - "description": "A simple API extension for DateTime.", + "description": "An API extension for DateTime that supports 281 different languages.", "homepage": "http://carbon.nesbot.com", "keywords": [ "date", "datetime", "time" ], - "time": "2018-12-28T10:07:33+00:00" + "time": "2020-01-21T09:36:43+00:00" + }, + { + "name": "nunomaduro/collision", + "version": "v3.0.1", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/collision.git", + "reference": "af42d339fe2742295a54f6fdd42aaa6f8c4aca68" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/af42d339fe2742295a54f6fdd42aaa6f8c4aca68", + "reference": "af42d339fe2742295a54f6fdd42aaa6f8c4aca68", + "shasum": "" + }, + "require": { + "filp/whoops": "^2.1.4", + "jakub-onderka/php-console-highlighter": "0.3.*|0.4.*", + "php": "^7.1", + "symfony/console": "~2.8|~3.3|~4.0" + }, + "require-dev": { + "laravel/framework": "5.8.*", + "nunomaduro/larastan": "^0.3.0", + "phpstan/phpstan": "^0.11", + "phpunit/phpunit": "~8.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "NunoMaduro\\Collision\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Cli error handling for console/command-line PHP applications.", + "keywords": [ + "artisan", + "cli", + "command-line", + "console", + "error", + "handling", + "laravel", + "laravel-zero", + "php", + "symfony" + ], + "time": "2019-03-07T21:35:13+00:00" + }, + { + "name": "onelogin/php-saml", + "version": "3.4.1", + "source": { + "type": "git", + "url": "https://github.com/onelogin/php-saml.git", + "reference": "5fbf3486704ac9835b68184023ab54862c95f213" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/onelogin/php-saml/zipball/5fbf3486704ac9835b68184023ab54862c95f213", + "reference": "5fbf3486704ac9835b68184023ab54862c95f213", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "robrichards/xmlseclibs": ">=3.0.4" + }, + "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" + }, + "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)" + }, + "type": "library", + "autoload": { + "psr-4": { + "OneLogin\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "OneLogin PHP SAML Toolkit", + "homepage": "https://developers.onelogin.com/saml/php", + "keywords": [ + "SAML2", + "onelogin", + "saml" + ], + "time": "2019-11-25T17:30:07+00:00" + }, + { + "name": "opis/closure", + "version": "3.5.1", + "source": { + "type": "git", + "url": "https://github.com/opis/closure.git", + "reference": "93ebc5712cdad8d5f489b500c59d122df2e53969" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/opis/closure/zipball/93ebc5712cdad8d5f489b500c59d122df2e53969", + "reference": "93ebc5712cdad8d5f489b500c59d122df2e53969", + "shasum": "" + }, + "require": { + "php": "^5.4 || ^7.0" + }, + "require-dev": { + "jeremeamia/superclosure": "^2.0", + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.5.x-dev" + } + }, + "autoload": { + "psr-4": { + "Opis\\Closure\\": "src/" + }, + "files": [ + "functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marius Sarca", + "email": "marius.sarca@gmail.com" + }, + { + "name": "Sorin Sarca", + "email": "sarca_sorin@hotmail.com" + } + ], + "description": "A library that can be used to serialize closures (anonymous functions) and arbitrary objects.", + "homepage": "https://opis.io/closure", + "keywords": [ + "anonymous functions", + "closure", + "function", + "serializable", + "serialization", + "serialize" + ], + "time": "2019-11-29T22:36:02+00:00" }, { "name": "paragonie/random_compat", @@ -2031,28 +2569,28 @@ }, { "name": "phenx/php-svg-lib", - "version": "v0.3.2", + "version": "v0.3.3", "source": { "type": "git", "url": "https://github.com/PhenX/php-svg-lib.git", - "reference": "ccc46ef6340d4b8a4a68047e68d8501ea961442c" + "reference": "5fa61b65e612ce1ae15f69b3d223cb14ecc60e32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PhenX/php-svg-lib/zipball/ccc46ef6340d4b8a4a68047e68d8501ea961442c", - "reference": "ccc46ef6340d4b8a4a68047e68d8501ea961442c", + "url": "https://api.github.com/repos/PhenX/php-svg-lib/zipball/5fa61b65e612ce1ae15f69b3d223cb14ecc60e32", + "reference": "5fa61b65e612ce1ae15f69b3d223cb14ecc60e32", "shasum": "" }, "require": { - "sabberworm/php-css-parser": "8.1.*" + "sabberworm/php-css-parser": "^8.3" }, "require-dev": { - "phpunit/phpunit": "~5.0" + "phpunit/phpunit": "^5.5|^6.5" }, "type": "library", "autoload": { - "psr-0": { - "Svg\\": "src/" + "psr-4": { + "Svg\\": "src/Svg" } }, "notification-url": "https://packagist.org/downloads/", @@ -2067,7 +2605,62 @@ ], "description": "A library to read, parse and export to PDF SVG files.", "homepage": "https://github.com/PhenX/php-svg-lib", - "time": "2018-06-03T10:10:03+00:00" + "time": "2019-09-11T20:02:13+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.7.2", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959", + "reference": "77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959", + "shasum": "" + }, + "require": { + "php": "^5.5.9 || ^7.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.3", + "phpunit/phpunit": "^4.8.35 || ^5.0 || ^6.0 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "time": "2019-12-15T19:35:24+00:00" }, { "name": "predis/predis", @@ -2220,16 +2813,16 @@ }, { "name": "psr/log", - "version": "1.1.0", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd" + "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", - "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", + "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801", + "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801", "shasum": "" }, "require": { @@ -2238,7 +2831,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { @@ -2263,7 +2856,7 @@ "psr", "psr-3" ], - "time": "2018-11-20T15:27:04+00:00" + "time": "2019-11-01T11:05:21+00:00" }, { "name": "psr/simple-cache", @@ -2315,24 +2908,24 @@ }, { "name": "ralouphie/getallheaders", - "version": "2.0.5", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/ralouphie/getallheaders.git", - "reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa" + "reference": "120b605dfeb996808c31b6477290a714d356e822" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/5601c8a83fbba7ef674a7369456d12f1e0d0eafa", - "reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", "shasum": "" }, "require": { - "php": ">=5.3" + "php": ">=5.6" }, "require-dev": { - "phpunit/phpunit": "~3.7.0", - "satooshi/php-coveralls": ">=1.0" + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" }, "type": "library", "autoload": { @@ -2351,48 +2944,50 @@ } ], "description": "A polyfill for getallheaders.", - "time": "2016-02-11T07:05:27+00:00" + "time": "2019-03-08T08:55:37+00:00" }, { "name": "ramsey/uuid", - "version": "3.8.0", + "version": "3.9.2", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "d09ea80159c1929d75b3f9c60504d613aeb4a1e3" + "reference": "7779489a47d443f845271badbdcedfe4df8e06fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/d09ea80159c1929d75b3f9c60504d613aeb4a1e3", - "reference": "d09ea80159c1929d75b3f9c60504d613aeb4a1e3", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/7779489a47d443f845271badbdcedfe4df8e06fb", + "reference": "7779489a47d443f845271badbdcedfe4df8e06fb", "shasum": "" }, "require": { - "paragonie/random_compat": "^1.0|^2.0|9.99.99", - "php": "^5.4 || ^7.0", + "ext-json": "*", + "paragonie/random_compat": "^1 | ^2 | 9.99.99", + "php": "^5.4 | ^7 | ^8", "symfony/polyfill-ctype": "^1.8" }, "replace": { "rhumsaa/uuid": "self.version" }, "require-dev": { - "codeception/aspect-mock": "^1.0 | ~2.0.0", - "doctrine/annotations": "~1.2.0", - "goaop/framework": "1.0.0-alpha.2 | ^1.0 | ~2.1.0", - "ircmaxell/random-lib": "^1.1", - "jakub-onderka/php-parallel-lint": "^0.9.0", - "mockery/mockery": "^0.9.9", + "codeception/aspect-mock": "^1 | ^2", + "doctrine/annotations": "^1.2", + "goaop/framework": "1.0.0-alpha.2 | ^1 | ^2.1", + "jakub-onderka/php-parallel-lint": "^1", + "mockery/mockery": "^0.9.11 | ^1", "moontoast/math": "^1.1", - "php-mock/php-mock-phpunit": "^0.3|^1.1", - "phpunit/phpunit": "^4.7|^5.0|^6.5", - "squizlabs/php_codesniffer": "^2.3" + "paragonie/random-lib": "^2", + "php-mock/php-mock-phpunit": "^0.3 | ^1.1", + "phpunit/phpunit": "^4.8 | ^5.4 | ^6.5", + "squizlabs/php_codesniffer": "^3.5" }, "suggest": { "ext-ctype": "Provides support for PHP Ctype functions", "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", + "ext-openssl": "Provides the OpenSSL extension for use with the OpenSslGenerator", "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", - "ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter", "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).", + "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid", "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." }, @@ -2405,13 +3000,21 @@ "autoload": { "psr-4": { "Ramsey\\Uuid\\": "src/" - } + }, + "files": [ + "src/functions.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + }, { "name": "Marijn Huizendveld", "email": "marijn.huizendveld@gmail.com" @@ -2419,11 +3022,6 @@ { "name": "Thibaud Fabre", "email": "thibaud@aztech.io" - }, - { - "name": "Ben Ramsey", - "email": "ben@benramsey.com", - "homepage": "https://benramsey.com" } ], "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", @@ -2433,27 +3031,66 @@ "identifier", "uuid" ], - "time": "2018-07-19T23:38:55+00:00" + "time": "2019-12-17T08:18:51+00:00" }, { - "name": "sabberworm/php-css-parser", - "version": "8.1.0", + "name": "robrichards/xmlseclibs", + "version": "3.0.4", "source": { "type": "git", - "url": "https://github.com/sabberworm/PHP-CSS-Parser.git", - "reference": "850cbbcbe7fbb155387a151ea562897a67e242ef" + "url": "https://github.com/robrichards/xmlseclibs.git", + "reference": "0a53d3c3aa87564910cae4ed01416441d3ae0db5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sabberworm/PHP-CSS-Parser/zipball/850cbbcbe7fbb155387a151ea562897a67e242ef", - "reference": "850cbbcbe7fbb155387a151ea562897a67e242ef", + "url": "https://api.github.com/repos/robrichards/xmlseclibs/zipball/0a53d3c3aa87564910cae4ed01416441d3ae0db5", + "reference": "0a53d3c3aa87564910cae4ed01416441d3ae0db5", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "php": ">= 5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "RobRichards\\XMLSecLibs\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "A PHP library for XML Security", + "homepage": "https://github.com/robrichards/xmlseclibs", + "keywords": [ + "security", + "signature", + "xml", + "xmldsig" + ], + "time": "2019-11-05T11:44:22+00:00" + }, + { + "name": "sabberworm/php-css-parser", + "version": "8.3.0", + "source": { + "type": "git", + "url": "https://github.com/sabberworm/PHP-CSS-Parser.git", + "reference": "91bcc3e3fdb7386c9a2e0e0aa09ca75cc43f121f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sabberworm/PHP-CSS-Parser/zipball/91bcc3e3fdb7386c9a2e0e0aa09ca75cc43f121f", + "reference": "91bcc3e3fdb7386c9a2e0e0aa09ca75cc43f121f", "shasum": "" }, "require": { "php": ">=5.3.2" }, "require-dev": { - "phpunit/phpunit": "*" + "codacy/coverage": "^1.4", + "phpunit/phpunit": "~4.8" }, "type": "library", "autoload": { @@ -2477,7 +3114,75 @@ "parser", "stylesheet" ], - "time": "2016-07-19T19:14:21+00:00" + "time": "2019-02-22T07:42:52+00:00" + }, + { + "name": "scrivo/highlight.php", + "version": "v9.17.1.0", + "source": { + "type": "git", + "url": "https://github.com/scrivo/highlight.php.git", + "reference": "5451a9ad6d638559cf2a092880f935c39776134e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/scrivo/highlight.php/zipball/5451a9ad6d638559cf2a092880f935c39776134e", + "reference": "5451a9ad6d638559cf2a092880f935c39776134e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "php": ">=5.4" + }, + "require-dev": { + "phpunit/phpunit": "^4.8|^5.7", + "symfony/finder": "^3.4", + "symfony/var-dumper": "^3.4" + }, + "suggest": { + "ext-dom": "Needed to make use of the features in the utilities namespace" + }, + "type": "library", + "autoload": { + "psr-0": { + "Highlight\\": "", + "HighlightUtilities\\": "" + }, + "files": [ + "HighlightUtilities/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Geert Bergman", + "homepage": "http://www.scrivo.org/", + "role": "Project Author" + }, + { + "name": "Vladimir Jimenez", + "homepage": "https://allejo.io", + "role": "Maintainer" + }, + { + "name": "Martin Folkers", + "homepage": "https://twobrain.io", + "role": "Contributor" + } + ], + "description": "Server side syntax highlighter that supports 185 languages. It's a PHP port of highlight.js", + "keywords": [ + "code", + "highlight", + "highlight.js", + "highlight.php", + "syntax" + ], + "time": "2019-12-13T21:54:06+00:00" }, { "name": "socialiteproviders/discord", @@ -2555,19 +3260,20 @@ }, { "name": "socialiteproviders/manager", - "version": "v3.3.4", + "version": "v3.4.3", "source": { "type": "git", "url": "https://github.com/SocialiteProviders/Manager.git", - "reference": "58b72a667da292a1d0a0b1e6e9aeda4053617030" + "reference": "09903d33429f9f6c0da32c545c036a3e18964bbf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/SocialiteProviders/Manager/zipball/58b72a667da292a1d0a0b1e6e9aeda4053617030", - "reference": "58b72a667da292a1d0a0b1e6e9aeda4053617030", + "url": "https://api.github.com/repos/SocialiteProviders/Manager/zipball/09903d33429f9f6c0da32c545c036a3e18964bbf", + "reference": "09903d33429f9f6c0da32c545c036a3e18964bbf", "shasum": "" }, "require": { + "illuminate/support": "~5.4|~5.7.0|~5.8.0|^6.0", "laravel/socialite": "~3.0|~4.0", "php": "^5.6 || ^7.0" }, @@ -2600,10 +3306,14 @@ { "name": "Anton Komarev", "email": "a.komarev@cybercog.su" + }, + { + "name": "Miguel Piedrafita", + "email": "soy@miguelpiedrafita.com" } ], "description": "Easily add new or override built-in providers in Laravel Socialite.", - "time": "2019-01-16T07:58:54+00:00" + "time": "2019-09-25T06:06:35+00:00" }, { "name": "socialiteproviders/microsoft-azure", @@ -2681,16 +3391,16 @@ }, { "name": "socialiteproviders/slack", - "version": "v3.0.3", + "version": "v3.1", "source": { "type": "git", "url": "https://github.com/SocialiteProviders/Slack.git", - "reference": "8d5d0c0c916adf2af6b406679130441db0afc387" + "reference": "d46826640fbeae8f34328d99c358404a1e1050a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/SocialiteProviders/Slack/zipball/8d5d0c0c916adf2af6b406679130441db0afc387", - "reference": "8d5d0c0c916adf2af6b406679130441db0afc387", + "url": "https://api.github.com/repos/SocialiteProviders/Slack/zipball/d46826640fbeae8f34328d99c358404a1e1050a3", + "reference": "d46826640fbeae8f34328d99c358404a1e1050a3", "shasum": "" }, "require": { @@ -2714,25 +3424,25 @@ } ], "description": "Slack OAuth2 Provider for Laravel Socialite", - "time": "2017-04-10T05:10:48+00:00" + "time": "2019-01-11T19:48:14+00:00" }, { "name": "socialiteproviders/twitch", - "version": "v3.0.0", + "version": "v5.1", "source": { "type": "git", "url": "https://github.com/SocialiteProviders/Twitch.git", - "reference": "a7ad148c0b42d0c607d8a034b6e47faf5fc85e93" + "reference": "f9b1f90a94f539e1b29e84ee0f731f42d59f3213" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/SocialiteProviders/Twitch/zipball/a7ad148c0b42d0c607d8a034b6e47faf5fc85e93", - "reference": "a7ad148c0b42d0c607d8a034b6e47faf5fc85e93", + "url": "https://api.github.com/repos/SocialiteProviders/Twitch/zipball/f9b1f90a94f539e1b29e84ee0f731f42d59f3213", + "reference": "f9b1f90a94f539e1b29e84ee0f731f42d59f3213", "shasum": "" }, "require": { "php": "^5.6 || ^7.0", - "socialiteproviders/manager": "~3.0" + "socialiteproviders/manager": "~2.0 || ~3.0" }, "type": "library", "autoload": { @@ -2751,29 +3461,32 @@ } ], "description": "Twitch OAuth2 Provider for Laravel Socialite", - "time": "2017-01-25T09:48:29+00:00" + "time": "2019-07-01T10:35:46+00:00" }, { "name": "swiftmailer/swiftmailer", - "version": "v6.1.3", + "version": "v6.2.3", "source": { "type": "git", "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "8ddcb66ac10c392d3beb54829eef8ac1438595f4" + "reference": "149cfdf118b169f7840bbe3ef0d4bc795d1780c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/8ddcb66ac10c392d3beb54829eef8ac1438595f4", - "reference": "8ddcb66ac10c392d3beb54829eef8ac1438595f4", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/149cfdf118b169f7840bbe3ef0d4bc795d1780c9", + "reference": "149cfdf118b169f7840bbe3ef0d4bc795d1780c9", "shasum": "" }, "require": { "egulias/email-validator": "~2.0", - "php": ">=7.0.0" + "php": ">=7.0.0", + "symfony/polyfill-iconv": "^1.0", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" }, "require-dev": { "mockery/mockery": "~0.9.1", - "symfony/phpunit-bridge": "~3.3@dev" + "symfony/phpunit-bridge": "^3.4.19|^4.1.8" }, "suggest": { "ext-intl": "Needed to support internationalized email addresses", @@ -2782,7 +3495,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "6.1-dev" + "dev-master": "6.2-dev" } }, "autoload": { @@ -2810,49 +3523,56 @@ "mail", "mailer" ], - "time": "2018-09-11T07:12:52+00:00" + "time": "2019-11-12T09:31:26+00:00" }, { "name": "symfony/console", - "version": "v3.3.6", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "b0878233cb5c4391347e5495089c7af11b8e6201" + "reference": "e9ee09d087e2c88eaf6e5fc0f5c574f64d100e4f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/b0878233cb5c4391347e5495089c7af11b8e6201", - "reference": "b0878233cb5c4391347e5495089c7af11b8e6201", + "url": "https://api.github.com/repos/symfony/console/zipball/e9ee09d087e2c88eaf6e5fc0f5c574f64d100e4f", + "reference": "e9ee09d087e2c88eaf6e5fc0f5c574f64d100e4f", "shasum": "" }, "require": { - "php": ">=5.5.9", - "symfony/debug": "~2.8|~3.0", - "symfony/polyfill-mbstring": "~1.0" + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/service-contracts": "^1.1|^2" }, "conflict": { - "symfony/dependency-injection": "<3.3" + "symfony/dependency-injection": "<3.4", + "symfony/event-dispatcher": "<4.3|>=5", + "symfony/lock": "<4.4", + "symfony/process": "<3.3" + }, + "provide": { + "psr/log-implementation": "1.0" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~3.3", - "symfony/dependency-injection": "~3.3", - "symfony/event-dispatcher": "~2.8|~3.0", - "symfony/filesystem": "~2.8|~3.0", - "symfony/http-kernel": "~2.8|~3.0", - "symfony/process": "~2.8|~3.0" + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/event-dispatcher": "^4.3", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^4.3|^5.0" }, "suggest": { "psr/log": "For using the console logger", "symfony/event-dispatcher": "", - "symfony/filesystem": "", + "symfony/lock": "", "symfony/process": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -2879,29 +3599,29 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2017-07-29T21:27:59+00:00" + "time": "2020-01-10T21:54:01+00:00" }, { "name": "symfony/css-selector", - "version": "v3.1.10", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "722a87478a72d95dc2a3bcf41dc9c2d13fd4cb2d" + "reference": "a167b1860995b926d279f9bb538f873e3bfa3465" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/722a87478a72d95dc2a3bcf41dc9c2d13fd4cb2d", - "reference": "722a87478a72d95dc2a3bcf41dc9c2d13fd4cb2d", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/a167b1860995b926d279f9bb538f873e3bfa3465", + "reference": "a167b1860995b926d279f9bb538f873e3bfa3465", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": "^7.1.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -2917,14 +3637,14 @@ "MIT" ], "authors": [ - { - "name": "Jean-François Simon", - "email": "jeanfrancois.simon@sensiolabs.com" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" @@ -2932,36 +3652,36 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2017-01-02T20:31:54+00:00" + "time": "2020-01-04T13:00:46+00:00" }, { "name": "symfony/debug", - "version": "v3.3.6", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "7c13ae8ce1e2adbbd574fc39de7be498e1284e13" + "reference": "89c3fd5c299b940333bc6fe9f1b8db1b0912c759" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/7c13ae8ce1e2adbbd574fc39de7be498e1284e13", - "reference": "7c13ae8ce1e2adbbd574fc39de7be498e1284e13", + "url": "https://api.github.com/repos/symfony/debug/zipball/89c3fd5c299b940333bc6fe9f1b8db1b0912c759", + "reference": "89c3fd5c299b940333bc6fe9f1b8db1b0912c759", "shasum": "" }, "require": { - "php": ">=5.5.9", + "php": "^7.1.3", "psr/log": "~1.0" }, "conflict": { - "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + "symfony/http-kernel": "<3.4" }, "require-dev": { - "symfony/http-kernel": "~2.8|~3.0" + "symfony/http-kernel": "^3.4|^4.0|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -2988,34 +3708,97 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2017-07-28T15:27:31+00:00" + "time": "2020-01-08T17:29:02+00:00" }, { - "name": "symfony/event-dispatcher", - "version": "v3.3.6", + "name": "symfony/error-handler", + "version": "v4.4.3", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "67535f1e3fd662bdc68d7ba317c93eecd973617e" + "url": "https://github.com/symfony/error-handler.git", + "reference": "a59789092e40ad08465dc2cdc55651be503d0d5a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/67535f1e3fd662bdc68d7ba317c93eecd973617e", - "reference": "67535f1e3fd662bdc68d7ba317c93eecd973617e", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/a59789092e40ad08465dc2cdc55651be503d0d5a", + "reference": "a59789092e40ad08465dc2cdc55651be503d0d5a", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": "^7.1.3", + "psr/log": "~1.0", + "symfony/debug": "^4.4", + "symfony/var-dumper": "^4.4|^5.0" + }, + "require-dev": { + "symfony/http-kernel": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony ErrorHandler Component", + "homepage": "https://symfony.com", + "time": "2020-01-08T17:29:02+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v4.4.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "9e3de195e5bc301704dd6915df55892f6dfc208b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/9e3de195e5bc301704dd6915df55892f6dfc208b", + "reference": "9e3de195e5bc301704dd6915df55892f6dfc208b", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/event-dispatcher-contracts": "^1.1" }, "conflict": { - "symfony/dependency-injection": "<3.3" + "symfony/dependency-injection": "<3.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0", - "symfony/dependency-injection": "~3.3", - "symfony/expression-language": "~2.8|~3.0", - "symfony/stopwatch": "~2.8|~3.0" + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/dependency-injection": "", @@ -3024,7 +3807,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3051,29 +3834,87 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2017-06-09T14:53:08+00:00" + "time": "2020-01-10T21:54:01+00:00" }, { - "name": "symfony/finder", - "version": "v3.3.6", + "name": "symfony/event-dispatcher-contracts", + "version": "v1.1.7", "source": { "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "baea7f66d30854ad32988c11a09d7ffd485810c4" + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/baea7f66d30854ad32988c11a09d7ffd485810c4", - "reference": "baea7f66d30854ad32988c11a09d7ffd485810c4", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/c43ab685673fb6c8d84220c77897b1d6cdbe1d18", + "reference": "c43ab685673fb6c8d84220c77897b1d6cdbe1d18", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": "^7.1.3" + }, + "suggest": { + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-09-17T09:54:03+00:00" + }, + { + "name": "symfony/finder", + "version": "v4.4.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "3a50be43515590faf812fbd7708200aabc327ec3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/3a50be43515590faf812fbd7708200aabc327ec3", + "reference": "3a50be43515590faf812fbd7708200aabc327ec3", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" } }, "autoload": { @@ -3100,33 +3941,35 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2017-06-01T21:01:25+00:00" + "time": "2020-01-04T13:00:46+00:00" }, { "name": "symfony/http-foundation", - "version": "v3.3.6", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "49e8cd2d59a7aa9bfab19e46de680c76e500a031" + "reference": "c33998709f3fe9b8e27e0277535b07fbf6fde37a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/49e8cd2d59a7aa9bfab19e46de680c76e500a031", - "reference": "49e8cd2d59a7aa9bfab19e46de680c76e500a031", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/c33998709f3fe9b8e27e0277535b07fbf6fde37a", + "reference": "c33998709f3fe9b8e27e0277535b07fbf6fde37a", "shasum": "" }, "require": { - "php": ">=5.5.9", + "php": "^7.1.3", + "symfony/mime": "^4.3|^5.0", "symfony/polyfill-mbstring": "~1.1" }, "require-dev": { - "symfony/expression-language": "~2.8|~3.0" + "predis/predis": "~1.0", + "symfony/expression-language": "^3.4|^4.0|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3153,66 +3996,70 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2017-07-21T11:04:46+00:00" + "time": "2020-01-04T13:00:46+00:00" }, { "name": "symfony/http-kernel", - "version": "v3.3.6", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "db10d05f1d95e4168e638db7a81c79616f568ea5" + "reference": "16f2aa3c54b08483fba5375938f60b1ff83b6bd2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/db10d05f1d95e4168e638db7a81c79616f568ea5", - "reference": "db10d05f1d95e4168e638db7a81c79616f568ea5", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/16f2aa3c54b08483fba5375938f60b1ff83b6bd2", + "reference": "16f2aa3c54b08483fba5375938f60b1ff83b6bd2", "shasum": "" }, "require": { - "php": ">=5.5.9", + "php": "^7.1.3", "psr/log": "~1.0", - "symfony/debug": "~2.8|~3.0", - "symfony/event-dispatcher": "~2.8|~3.0", - "symfony/http-foundation": "~3.3" + "symfony/error-handler": "^4.4", + "symfony/event-dispatcher": "^4.4", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php73": "^1.9" }, "conflict": { - "symfony/config": "<2.8", - "symfony/dependency-injection": "<3.3", - "symfony/var-dumper": "<3.3", + "symfony/browser-kit": "<4.3", + "symfony/config": "<3.4", + "symfony/console": ">=5", + "symfony/dependency-injection": "<4.3", + "symfony/translation": "<4.2", "twig/twig": "<1.34|<2.4,>=2" }, + "provide": { + "psr/log-implementation": "1.0" + }, "require-dev": { "psr/cache": "~1.0", - "symfony/browser-kit": "~2.8|~3.0", - "symfony/class-loader": "~2.8|~3.0", - "symfony/config": "~2.8|~3.0", - "symfony/console": "~2.8|~3.0", - "symfony/css-selector": "~2.8|~3.0", - "symfony/dependency-injection": "~3.3", - "symfony/dom-crawler": "~2.8|~3.0", - "symfony/expression-language": "~2.8|~3.0", - "symfony/finder": "~2.8|~3.0", - "symfony/process": "~2.8|~3.0", - "symfony/routing": "~2.8|~3.0", - "symfony/stopwatch": "~2.8|~3.0", - "symfony/templating": "~2.8|~3.0", - "symfony/translation": "~2.8|~3.0", - "symfony/var-dumper": "~3.3" + "symfony/browser-kit": "^4.3|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^4.3|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.2|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "twig/twig": "^1.34|^2.4|^3.0" }, "suggest": { "symfony/browser-kit": "", - "symfony/class-loader": "", "symfony/config": "", "symfony/console": "", - "symfony/dependency-injection": "", - "symfony/finder": "", - "symfony/var-dumper": "" + "symfony/dependency-injection": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3239,20 +4086,82 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", - "time": "2017-08-01T10:25:59+00:00" + "time": "2020-01-21T13:23:17+00:00" }, { - "name": "symfony/polyfill-ctype", - "version": "v1.10.0", + "name": "symfony/mime", + "version": "v4.4.3", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "e3d826245268269cd66f8326bd8bc066687b4a19" + "url": "https://github.com/symfony/mime.git", + "reference": "225034620ecd4b34fd826e9983d85e2b7a359094" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19", - "reference": "e3d826245268269cd66f8326bd8bc066687b4a19", + "url": "https://api.github.com/repos/symfony/mime/zipball/225034620ecd4b34fd826e9983d85e2b7a359094", + "reference": "225034620ecd4b34fd826e9983d85e2b7a359094", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "symfony/mailer": "<4.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10", + "symfony/dependency-injection": "^3.4|^4.1|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A library to manipulate MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "time": "2020-01-04T13:00:46+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.13.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", + "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", "shasum": "" }, "require": { @@ -3264,7 +4173,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9-dev" + "dev-master": "1.13-dev" } }, "autoload": { @@ -3280,13 +4189,13 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - }, { "name": "Gert de Pagter", "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony polyfill for ctype functions", @@ -3297,20 +4206,141 @@ "polyfill", "portable" ], - "time": "2018-08-06T14:22:27+00:00" + "time": "2019-11-27T13:56:44+00:00" }, { - "name": "symfony/polyfill-mbstring", - "version": "v1.10.0", + "name": "symfony/polyfill-iconv", + "version": "v1.13.1", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "c79c051f5b3a46be09205c73b80b346e4153e494" + "url": "https://github.com/symfony/polyfill-iconv.git", + "reference": "a019efccc03f1a335af6b4f20c30f5ea8060be36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494", - "reference": "c79c051f5b3a46be09205c73b80b346e4153e494", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/a019efccc03f1a335af6b4f20c30f5ea8060be36", + "reference": "a019efccc03f1a335af6b4f20c30f5ea8060be36", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-iconv": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.13-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Iconv\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Iconv extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "iconv", + "polyfill", + "portable", + "shim" + ], + "time": "2019-11-27T13:56:44+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.13.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "6f9c239e61e1b0c9229a28ff89a812dc449c3d46" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/6f9c239e61e1b0c9229a28ff89a812dc449c3d46", + "reference": "6f9c239e61e1b0c9229a28ff89a812dc449c3d46", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/polyfill-mbstring": "^1.3", + "symfony/polyfill-php72": "^1.9" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.13-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "time": "2019-11-27T13:56:44+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.13.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7b4aab9743c30be783b73de055d24a39cf4b954f", + "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f", "shasum": "" }, "require": { @@ -3322,7 +4352,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9-dev" + "dev-master": "1.13-dev" } }, "autoload": { @@ -3356,29 +4386,142 @@ "portable", "shim" ], - "time": "2018-09-21T13:07:52+00:00" + "time": "2019-11-27T14:18:11+00:00" }, { - "name": "symfony/process", - "version": "v3.3.6", + "name": "symfony/polyfill-php72", + "version": "v1.13.1", "source": { "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "07432804942b9f6dd7b7377faf9920af5f95d70a" + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "66fea50f6cb37a35eea048d75a7d99a45b586038" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/07432804942b9f6dd7b7377faf9920af5f95d70a", - "reference": "07432804942b9f6dd7b7377faf9920af5f95d70a", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/66fea50f6cb37a35eea048d75a7d99a45b586038", + "reference": "66fea50f6cb37a35eea048d75a7d99a45b586038", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": ">=5.3.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "1.13-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2019-11-27T13:56:44+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.13.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "4b0e2222c55a25b4541305a053013d5647d3a25f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/4b0e2222c55a25b4541305a053013d5647d3a25f", + "reference": "4b0e2222c55a25b4541305a053013d5647d3a25f", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.13-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2019-11-27T16:25:15+00:00" + }, + { + "name": "symfony/process", + "version": "v4.4.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "f5697ab4cb14a5deed7473819e63141bf5352c36" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/f5697ab4cb14a5deed7473819e63141bf5352c36", + "reference": "f5697ab4cb14a5deed7473819e63141bf5352c36", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" } }, "autoload": { @@ -3405,44 +4548,42 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2017-07-13T13:05:09+00:00" + "time": "2020-01-09T09:50:08+00:00" }, { "name": "symfony/routing", - "version": "v3.3.6", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "4aee1a917fd4859ff8b51b9fd1dfb790a5ecfa26" + "reference": "7bf4e38573728e317b926ca4482ad30470d0e86a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/4aee1a917fd4859ff8b51b9fd1dfb790a5ecfa26", - "reference": "4aee1a917fd4859ff8b51b9fd1dfb790a5ecfa26", + "url": "https://api.github.com/repos/symfony/routing/zipball/7bf4e38573728e317b926ca4482ad30470d0e86a", + "reference": "7bf4e38573728e317b926ca4482ad30470d0e86a", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": "^7.1.3" }, "conflict": { - "symfony/config": "<2.8", - "symfony/dependency-injection": "<3.3", - "symfony/yaml": "<3.3" + "symfony/config": "<4.2", + "symfony/dependency-injection": "<3.4", + "symfony/yaml": "<3.4" }, "require-dev": { - "doctrine/annotations": "~1.0", - "doctrine/common": "~2.2", + "doctrine/annotations": "~1.2", "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0", - "symfony/dependency-injection": "~3.3", - "symfony/expression-language": "~2.8|~3.0", - "symfony/http-foundation": "~2.8|~3.0", - "symfony/yaml": "~3.3" + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { "doctrine/annotations": "For using the annotation loader", "symfony/config": "For using the all-in-one router or any loader", - "symfony/dependency-injection": "For loading routes from a service", "symfony/expression-language": "For using expression matching", "symfony/http-foundation": "For using a Symfony Request object", "symfony/yaml": "For using the YAML loader" @@ -3450,7 +4591,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3483,45 +4624,114 @@ "uri", "url" ], - "time": "2017-07-21T17:43:13+00:00" + "time": "2020-01-08T17:29:02+00:00" }, { - "name": "symfony/translation", - "version": "v3.3.6", + "name": "symfony/service-contracts", + "version": "v1.1.8", "source": { "type": "git", - "url": "https://github.com/symfony/translation.git", - "reference": "35dd5fb003c90e8bd4d8cabdf94bf9c96d06fdc3" + "url": "https://github.com/symfony/service-contracts.git", + "reference": "ffc7f5692092df31515df2a5ecf3b7302b3ddacf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/35dd5fb003c90e8bd4d8cabdf94bf9c96d06fdc3", - "reference": "35dd5fb003c90e8bd4d8cabdf94bf9c96d06fdc3", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/ffc7f5692092df31515df2a5ecf3b7302b3ddacf", + "reference": "ffc7f5692092df31515df2a5ecf3b7302b3ddacf", "shasum": "" }, "require": { - "php": ">=5.5.9", - "symfony/polyfill-mbstring": "~1.0" + "php": "^7.1.3", + "psr/container": "^1.0" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-10-14T12:27:06+00:00" + }, + { + "name": "symfony/translation", + "version": "v4.4.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "f5d2ac46930238b30a9c2f1b17c905f3697d808c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/f5d2ac46930238b30a9c2f1b17c905f3697d808c", + "reference": "f5d2ac46930238b30a9c2f1b17c905f3697d808c", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^1.1.6|^2" }, "conflict": { - "symfony/config": "<2.8", - "symfony/yaml": "<3.3" + "symfony/config": "<3.4", + "symfony/dependency-injection": "<3.4", + "symfony/http-kernel": "<4.4", + "symfony/yaml": "<3.4" + }, + "provide": { + "symfony/translation-implementation": "1.0" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0", - "symfony/intl": "^2.8.18|^3.2.5", - "symfony/yaml": "~3.3" + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/finder": "~2.8|~3.0|~4.0|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/intl": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1.2|^2", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { - "psr/log": "To use logging capability in translator", + "psr/log-implementation": "To use logging capability in translator", "symfony/config": "", "symfony/yaml": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3548,41 +4758,106 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2017-06-24T16:45:30+00:00" + "time": "2020-01-15T13:29:06+00:00" }, { - "name": "symfony/var-dumper", - "version": "v3.3.6", + "name": "symfony/translation-contracts", + "version": "v1.1.7", "source": { "type": "git", - "url": "https://github.com/symfony/var-dumper.git", - "reference": "b2623bccb969ad595c2090f9be498b74670d0663" + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "364518c132c95642e530d9b2d217acbc2ccac3e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b2623bccb969ad595c2090f9be498b74670d0663", - "reference": "b2623bccb969ad595c2090f9be498b74670d0663", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/364518c132c95642e530d9b2d217acbc2ccac3e6", + "reference": "364518c132c95642e530d9b2d217acbc2ccac3e6", "shasum": "" }, "require": { - "php": ">=5.5.9", - "symfony/polyfill-mbstring": "~1.0" - }, - "conflict": { - "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0" - }, - "require-dev": { - "ext-iconv": "*", - "twig/twig": "~1.34|~2.4" + "php": "^7.1.3" }, "suggest": { - "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", - "ext-symfony_debug": "" + "symfony/translation-implementation": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-09-17T11:12:18+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v4.4.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "7cfa470bc3b1887a7b2a47c0a702a84ad614fa92" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/7cfa470bc3b1887a7b2a47c0a702a84ad614fa92", + "reference": "7cfa470bc3b1887a7b2a47c0a702a84ad614fa92", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.34|^2.4|^3.0" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" } }, "autoload": { @@ -3616,25 +4891,27 @@ "debug", "dump" ], - "time": "2017-07-28T06:06:09+00:00" + "time": "2020-01-04T13:00:46+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", - "version": "2.2.1", + "version": "2.2.2", "source": { "type": "git", "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", - "reference": "0ed4a2ea4e0902dac0489e6436ebcd5bbcae9757" + "reference": "dda2ee426acd6d801d5b7fd1001cde9b5f790e15" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/0ed4a2ea4e0902dac0489e6436ebcd5bbcae9757", - "reference": "0ed4a2ea4e0902dac0489e6436ebcd5bbcae9757", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/dda2ee426acd6d801d5b7fd1001cde9b5f790e15", + "reference": "dda2ee426acd6d801d5b7fd1001cde9b5f790e15", "shasum": "" }, "require": { + "ext-dom": "*", + "ext-libxml": "*", "php": "^5.5 || ^7.0", - "symfony/css-selector": "^2.7 || ^3.0 || ^4.0" + "symfony/css-selector": "^2.7 || ^3.0 || ^4.0 || ^5.0" }, "require-dev": { "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" @@ -3663,32 +4940,34 @@ ], "description": "CssToInlineStyles is a class that enables you to convert HTML-pages/files into HTML-pages/files with inline styles. This is very useful when you're sending emails.", "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", - "time": "2017-11-27T11:13:29+00:00" + "time": "2019-10-24T08:53:34+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v2.5.2", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "cfd5dc225767ca154853752abc93aeec040fcf36" + "reference": "1bdf24f065975594f6a117f0f1f6cabf1333b156" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/cfd5dc225767ca154853752abc93aeec040fcf36", - "reference": "cfd5dc225767ca154853752abc93aeec040fcf36", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/1bdf24f065975594f6a117f0f1f6cabf1333b156", + "reference": "1bdf24f065975594f6a117f0f1f6cabf1333b156", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": "^5.4 || ^7.0", + "phpoption/phpoption": "^1.5", + "symfony/polyfill-ctype": "^1.9" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.0" + "phpunit/phpunit": "^4.8.35 || ^5.0 || ^6.0 || ^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "3.6-dev" } }, "autoload": { @@ -3701,10 +4980,15 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "homepage": "https://gjcampbell.co.uk/" + }, { "name": "Vance Lucas", "email": "vance@vancelucas.com", - "homepage": "http://www.vancelucas.com" + "homepage": "https://vancelucas.com/" } ], "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", @@ -3713,28 +4997,28 @@ "env", "environment" ], - "time": "2018-10-30T17:29:25+00:00" + "time": "2019-09-10T21:37:39+00:00" } ], "packages-dev": [ { "name": "barryvdh/laravel-debugbar", - "version": "v3.2.1", + "version": "v3.2.8", "source": { "type": "git", "url": "https://github.com/barryvdh/laravel-debugbar.git", - "reference": "9d5caf43c5f3a3aea2178942f281054805872e7c" + "reference": "18208d64897ab732f6c04a19b319fe8f1d57a9c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/9d5caf43c5f3a3aea2178942f281054805872e7c", - "reference": "9d5caf43c5f3a3aea2178942f281054805872e7c", + "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/18208d64897ab732f6c04a19b319fe8f1d57a9c0", + "reference": "18208d64897ab732f6c04a19b319fe8f1d57a9c0", "shasum": "" }, "require": { - "illuminate/routing": "5.5.x|5.6.x|5.7.x", - "illuminate/session": "5.5.x|5.6.x|5.7.x", - "illuminate/support": "5.5.x|5.6.x|5.7.x", + "illuminate/routing": "^5.5|^6", + "illuminate/session": "^5.5|^6", + "illuminate/support": "^5.5|^6", "maximebf/debugbar": "~1.15.0", "php": ">=7.0", "symfony/debug": "^3|^4", @@ -3783,46 +5067,43 @@ "profiler", "webprofiler" ], - "time": "2018-11-09T08:37:55+00:00" + "time": "2019-08-29T07:01:03+00:00" }, { "name": "barryvdh/laravel-ide-helper", - "version": "v2.5.3", + "version": "v2.6.6", "source": { "type": "git", "url": "https://github.com/barryvdh/laravel-ide-helper.git", - "reference": "3d7f1240896a075aa23b13f82dfcbe165dadeef2" + "reference": "b91b959364d97af658f268c733c75dccdbff197e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/3d7f1240896a075aa23b13f82dfcbe165dadeef2", - "reference": "3d7f1240896a075aa23b13f82dfcbe165dadeef2", + "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/b91b959364d97af658f268c733c75dccdbff197e", + "reference": "b91b959364d97af658f268c733c75dccdbff197e", "shasum": "" }, "require": { "barryvdh/reflection-docblock": "^2.0.6", "composer/composer": "^1.6", - "illuminate/console": "^5.5,<5.8", - "illuminate/filesystem": "^5.5,<5.8", - "illuminate/support": "^5.5,<5.8", + "doctrine/dbal": "~2.3", + "illuminate/console": "^5.5|^6", + "illuminate/filesystem": "^5.5|^6", + "illuminate/support": "^5.5|^6", "php": ">=7" }, "require-dev": { - "doctrine/dbal": "~2.3", - "illuminate/config": "^5.1,<5.8", - "illuminate/view": "^5.1,<5.8", + "illuminate/config": "^5.5|^6", + "illuminate/view": "^5.5|^6", "phpro/grumphp": "^0.14", "phpunit/phpunit": "4.*", "scrutinizer/ocular": "~1.1", "squizlabs/php_codesniffer": "^3" }, - "suggest": { - "doctrine/dbal": "Load information from the database about models for phpdocs (~2.3)" - }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.6-dev" }, "laravel": { "providers": [ @@ -3857,7 +5138,7 @@ "phpstorm", "sublime" ], - "time": "2018-12-19T12:12:05+00:00" + "time": "2019-10-30T20:53:27+00:00" }, { "name": "barryvdh/reflection-docblock", @@ -3910,27 +5191,27 @@ }, { "name": "composer/ca-bundle", - "version": "1.1.3", + "version": "1.2.6", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "8afa52cd417f4ec417b4bfe86b68106538a87660" + "reference": "47fe531de31fca4a1b997f87308e7d7804348f7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/8afa52cd417f4ec417b4bfe86b68106538a87660", - "reference": "8afa52cd417f4ec417b4bfe86b68106538a87660", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/47fe531de31fca4a1b997f87308e7d7804348f7e", + "reference": "47fe531de31fca4a1b997f87308e7d7804348f7e", "shasum": "" }, "require": { "ext-openssl": "*", "ext-pcre": "*", - "php": "^5.3.2 || ^7.0" + "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5", + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8", "psr/log": "^1.0", - "symfony/process": "^2.5 || ^3.0 || ^4.0" + "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" }, "type": "library", "extra": { @@ -3962,20 +5243,20 @@ "ssl", "tls" ], - "time": "2018-10-18T06:09:13+00:00" + "time": "2020-01-13T10:02:55+00:00" }, { "name": "composer/composer", - "version": "1.8.0", + "version": "1.9.2", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "d8aef3af866b28786ce9b8647e52c42496436669" + "reference": "7a04aa0201ddaa0b3cf64d41022bd8cdcd7fafeb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/d8aef3af866b28786ce9b8647e52c42496436669", - "reference": "d8aef3af866b28786ce9b8647e52c42496436669", + "url": "https://api.github.com/repos/composer/composer/zipball/7a04aa0201ddaa0b3cf64d41022bd8cdcd7fafeb", + "reference": "7a04aa0201ddaa0b3cf64d41022bd8cdcd7fafeb", "shasum": "" }, "require": { @@ -4011,7 +5292,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -4035,35 +5316,34 @@ "homepage": "http://seld.be" } ], - "description": "Composer helps you declare, manage and install dependencies of PHP projects, ensuring you have the right stack everywhere.", + "description": "Composer helps you declare, manage and install dependencies of PHP projects. It ensures you have the right stack everywhere.", "homepage": "https://getcomposer.org/", "keywords": [ "autoload", "dependency", "package" ], - "time": "2018-12-03T09:31:16+00:00" + "time": "2020-01-14T15:30:32+00:00" }, { "name": "composer/semver", - "version": "1.4.2", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573" + "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/c7cb9a2095a074d131b65a8a0cd294479d785573", - "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573", + "url": "https://api.github.com/repos/composer/semver/zipball/c6bea70230ef4dd483e6bbcab6005f682ed3a8de", + "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "^4.5 || ^5.0.5", - "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" + "phpunit/phpunit": "^4.5 || ^5.0.5" }, "type": "library", "extra": { @@ -4104,28 +5384,27 @@ "validation", "versioning" ], - "time": "2016-08-30T16:08:34+00:00" + "time": "2020-01-13T12:06:48+00:00" }, { "name": "composer/spdx-licenses", - "version": "1.5.0", + "version": "1.5.2", "source": { "type": "git", "url": "https://github.com/composer/spdx-licenses.git", - "reference": "7a9556b22bd9d4df7cad89876b00af58ef20d3a2" + "reference": "7ac1e6aec371357df067f8a688c3d6974df68fa5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/7a9556b22bd9d4df7cad89876b00af58ef20d3a2", - "reference": "7a9556b22bd9d4df7cad89876b00af58ef20d3a2", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/7ac1e6aec371357df067f8a688c3d6974df68fa5", + "reference": "7ac1e6aec371357df067f8a688c3d6974df68fa5", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0" + "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5", - "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 7" }, "type": "library", "extra": { @@ -4165,28 +5444,28 @@ "spdx", "validator" ], - "time": "2018-11-01T09:45:54+00:00" + "time": "2019-07-29T10:31:59+00:00" }, { "name": "composer/xdebug-handler", - "version": "1.3.1", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "dc523135366eb68f22268d069ea7749486458562" + "reference": "cbe23383749496fe0f373345208b79568e4bc248" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/dc523135366eb68f22268d069ea7749486458562", - "reference": "dc523135366eb68f22268d069ea7749486458562", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/cbe23383749496fe0f373345208b79568e4bc248", + "reference": "cbe23383749496fe0f373345208b79568e4bc248", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0", + "php": "^5.3.2 || ^7.0 || ^8.0", "psr/log": "^1.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8" }, "type": "library", "autoload": { @@ -4204,41 +5483,43 @@ "email": "john-stevenson@blueyonder.co.uk" } ], - "description": "Restarts a process without xdebug.", + "description": "Restarts a process without Xdebug.", "keywords": [ "Xdebug", "performance" ], - "time": "2018-11-29T10:59:02+00:00" + "time": "2019-11-06T16:40:04+00:00" }, { "name": "doctrine/instantiator", - "version": "1.0.5", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + "reference": "ae466f726242e637cebdd526a7d991b9433bacf1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1", + "reference": "ae466f726242e637cebdd526a7d991b9433bacf1", "shasum": "" }, "require": { - "php": ">=5.3,<8.0-DEV" + "php": "^7.1" }, "require-dev": { - "athletic/athletic": "~0.1.8", + "doctrine/coding-standard": "^6.0", "ext-pdo": "*", "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" + "phpbench/phpbench": "^0.13", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-shim": "^0.11", + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -4258,86 +5539,25 @@ } ], "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", "keywords": [ "constructor", "instantiate" ], - "time": "2015-06-14T21:17:01+00:00" - }, - { - "name": "filp/whoops", - "version": "2.3.1", - "source": { - "type": "git", - "url": "https://github.com/filp/whoops.git", - "reference": "bc0fd11bc455cc20ee4b5edabc63ebbf859324c7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/bc0fd11bc455cc20ee4b5edabc63ebbf859324c7", - "reference": "bc0fd11bc455cc20ee4b5edabc63ebbf859324c7", - "shasum": "" - }, - "require": { - "php": "^5.5.9 || ^7.0", - "psr/log": "^1.0.1" - }, - "require-dev": { - "mockery/mockery": "^0.9 || ^1.0", - "phpunit/phpunit": "^4.8.35 || ^5.7", - "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0" - }, - "suggest": { - "symfony/var-dumper": "Pretty print complex values better with var-dumper available", - "whoops/soap": "Formats errors as SOAP responses" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.2-dev" - } - }, - "autoload": { - "psr-4": { - "Whoops\\": "src/Whoops/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Filipe Dobreira", - "homepage": "https://github.com/filp", - "role": "Developer" - } - ], - "description": "php error handling for cool kids", - "homepage": "https://filp.github.io/whoops/", - "keywords": [ - "error", - "exception", - "handling", - "library", - "throwable", - "whoops" - ], - "time": "2018-10-23T09:00:00+00:00" + "time": "2019-10-21T16:45:58+00:00" }, { "name": "fzaninotto/faker", - "version": "v1.8.0", + "version": "v1.9.1", "source": { "type": "git", "url": "https://github.com/fzaninotto/Faker.git", - "reference": "f72816b43e74063c8b10357394b6bba8cb1c10de" + "reference": "fc10d778e4b84d5bd315dad194661e091d307c6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/f72816b43e74063c8b10357394b6bba8cb1c10de", - "reference": "f72816b43e74063c8b10357394b6bba8cb1c10de", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/fc10d778e4b84d5bd315dad194661e091d307c6f", + "reference": "fc10d778e4b84d5bd315dad194661e091d307c6f", "shasum": "" }, "require": { @@ -4346,12 +5566,12 @@ "require-dev": { "ext-intl": "*", "phpunit/phpunit": "^4.8.35 || ^5.7", - "squizlabs/php_codesniffer": "^1.5" + "squizlabs/php_codesniffer": "^2.9.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -4374,7 +5594,7 @@ "faker", "fixtures" ], - "time": "2018-07-12T10:23:15+00:00" + "time": "2019-12-12T13:22:17+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -4426,23 +5646,23 @@ }, { "name": "justinrainbow/json-schema", - "version": "5.2.8", + "version": "5.2.9", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "dcb6e1006bb5fd1e392b4daa68932880f37550d4" + "reference": "44c6787311242a979fa15c704327c20e7221a0e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/dcb6e1006bb5fd1e392b4daa68932880f37550d4", - "reference": "dcb6e1006bb5fd1e392b4daa68932880f37550d4", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/44c6787311242a979fa15c704327c20e7221a0e4", + "reference": "44c6787311242a979fa15c704327c20e7221a0e4", "shasum": "" }, "require": { "php": ">=5.3.3" }, "require-dev": { - "friendsofphp/php-cs-fixer": "~2.2.20", + "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", "json-schema/json-schema-test-suite": "1.2.0", "phpunit/phpunit": "^4.8.35" }, @@ -4488,32 +5708,45 @@ "json", "schema" ], - "time": "2019-01-14T23:55:14+00:00" + "time": "2019-09-25T14:49:45+00:00" }, { "name": "laravel/browser-kit-testing", - "version": "v2.0.1", + "version": "v5.1.3", "source": { "type": "git", "url": "https://github.com/laravel/browser-kit-testing.git", - "reference": "f0bb9f200ec35f9d876ded6eacfbc60868d311b9" + "reference": "cb0cf22cf38fe8796842adc8b9ad550ded2a1377" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/browser-kit-testing/zipball/f0bb9f200ec35f9d876ded6eacfbc60868d311b9", - "reference": "f0bb9f200ec35f9d876ded6eacfbc60868d311b9", + "url": "https://api.github.com/repos/laravel/browser-kit-testing/zipball/cb0cf22cf38fe8796842adc8b9ad550ded2a1377", + "reference": "cb0cf22cf38fe8796842adc8b9ad550ded2a1377", "shasum": "" }, "require": { - "php": ">=5.5.9", - "phpunit/phpunit": "~6.0", - "symfony/css-selector": "~3.1", - "symfony/dom-crawler": "~3.1" + "ext-dom": "*", + "ext-json": "*", + "illuminate/contracts": "~5.7.0|~5.8.0|^6.0", + "illuminate/database": "~5.7.0|~5.8.0|^6.0", + "illuminate/http": "~5.7.0|~5.8.0|^6.0", + "illuminate/support": "~5.7.0|~5.8.0|^6.0", + "mockery/mockery": "^1.0", + "php": ">=7.1.3", + "phpunit/phpunit": "^7.0|^8.0", + "symfony/console": "^4.2", + "symfony/css-selector": "^4.2", + "symfony/dom-crawler": "^4.2", + "symfony/http-foundation": "^4.2", + "symfony/http-kernel": "^4.2" + }, + "require-dev": { + "laravel/framework": "~5.7.0|~5.8.0|^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -4531,34 +5764,34 @@ "email": "taylor@laravel.com" } ], - "description": "Provides backwards compatibility for BrowserKit testing in Laravel 5.4.", + "description": "Provides backwards compatibility for BrowserKit testing in the latest Laravel release.", "keywords": [ "laravel", "testing" ], - "time": "2017-06-21T11:44:53+00:00" + "time": "2019-07-30T14:57:44+00:00" }, { "name": "maximebf/debugbar", - "version": "v1.15.0", + "version": "v1.15.1", "source": { "type": "git", "url": "https://github.com/maximebf/php-debugbar.git", - "reference": "30e7d60937ee5f1320975ca9bc7bcdd44d500f07" + "reference": "6c4277f6117e4864966c9cb58fb835cee8c74a1e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/30e7d60937ee5f1320975ca9bc7bcdd44d500f07", - "reference": "30e7d60937ee5f1320975ca9bc7bcdd44d500f07", + "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/6c4277f6117e4864966c9cb58fb835cee8c74a1e", + "reference": "6c4277f6117e4864966c9cb58fb835cee8c74a1e", "shasum": "" }, "require": { - "php": ">=5.3.0", + "php": ">=5.6", "psr/log": "^1.0", - "symfony/var-dumper": "^2.6|^3.0|^4.0" + "symfony/var-dumper": "^2.6|^3|^4" }, "require-dev": { - "phpunit/phpunit": "^4.0|^5.0" + "phpunit/phpunit": "^5" }, "suggest": { "kriswallsmith/assetic": "The best way to manage assets", @@ -4568,7 +5801,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.14-dev" + "dev-master": "1.15-dev" } }, "autoload": { @@ -4597,20 +5830,20 @@ "debug", "debugbar" ], - "time": "2017-12-15T11:13:46+00:00" + "time": "2019-09-24T14:55:42+00:00" }, { "name": "mockery/mockery", - "version": "1.2.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/mockery/mockery.git", - "reference": "100633629bf76d57430b86b7098cd6beb996a35a" + "reference": "f69bbde7d7a75d6b2862d9ca8fab1cd28014b4be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/100633629bf76d57430b86b7098cd6beb996a35a", - "reference": "100633629bf76d57430b86b7098cd6beb996a35a", + "url": "https://api.github.com/repos/mockery/mockery/zipball/f69bbde7d7a75d6b2862d9ca8fab1cd28014b4be", + "reference": "f69bbde7d7a75d6b2862d9ca8fab1cd28014b4be", "shasum": "" }, "require": { @@ -4619,12 +5852,12 @@ "php": ">=5.6.0" }, "require-dev": { - "phpunit/phpunit": "~5.7.10|~6.5|~7.0" + "phpunit/phpunit": "~5.7.10|~6.5|~7.0|~8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.3.x-dev" } }, "autoload": { @@ -4662,29 +5895,32 @@ "test double", "testing" ], - "time": "2018-10-02T21:52:37+00:00" + "time": "2019-12-26T09:49:15+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.7.0", + "version": "1.9.5", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" + "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/b2c28789e80a97badd14145fda39b545d83ca3ef", + "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.1" + }, + "replace": { + "myclabs/deep-copy": "self.version" }, "require-dev": { "doctrine/collections": "^1.0", "doctrine/common": "^2.6", - "phpunit/phpunit": "^4.1" + "phpunit/phpunit": "^7.1" }, "type": "library", "autoload": { @@ -4707,26 +5943,26 @@ "object", "object graph" ], - "time": "2017-10-19T19:58:43+00:00" + "time": "2020-01-17T21:11:47+00:00" }, { "name": "phar-io/manifest", - "version": "1.0.1", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", - "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", "shasum": "" }, "require": { "ext-dom": "*", "ext-phar": "*", - "phar-io/version": "^1.0.1", + "phar-io/version": "^2.0", "php": "^5.6 || ^7.0" }, "type": "library", @@ -4747,35 +5983,35 @@ "authors": [ { "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" + "role": "Developer", + "email": "arne@blankerts.de" }, { "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" + "role": "Developer", + "email": "sebastian@phpeople.de" }, { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" + "role": "Developer", + "email": "sebastian@phpunit.de" } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2017-03-05T18:14:27+00:00" + "time": "2018-07-08T19:23:20+00:00" }, { "name": "phar-io/version", - "version": "1.0.1", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", - "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", + "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", "shasum": "" }, "require": { @@ -4809,39 +6045,37 @@ } ], "description": "Library for handling version information and constraints", - "time": "2017-03-05T17:38:23+00:00" + "time": "2018-07-08T19:19:57+00:00" }, { "name": "phpdocumentor/reflection-common", - "version": "1.0.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", "shasum": "" }, "require": { - "php": ">=5.5" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^4.6" + "phpunit/phpunit": "~6" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src" - ] + "phpDocumentor\\Reflection\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -4863,31 +6097,32 @@ "reflection", "static analysis" ], - "time": "2017-09-11T18:02:19+00:00" + "time": "2018-08-07T13:53:10+00:00" }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.3.0", + "version": "4.3.4", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08" + "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/da3fd972d6bafd628114f7e7e036f45944b62e9c", + "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c", "shasum": "" }, "require": { "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0.0", - "phpdocumentor/type-resolver": "^0.4.0", + "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", + "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", "webmozart/assert": "^1.0" }, "require-dev": { - "doctrine/instantiator": "~1.0.5", + "doctrine/instantiator": "^1.0.5", "mockery/mockery": "^1.0", + "phpdocumentor/type-resolver": "0.4.*", "phpunit/phpunit": "^6.4" }, "type": "library", @@ -4914,41 +6149,40 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2017-11-30T07:14:17+00:00" + "time": "2019-12-28T18:55:12+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "0.4.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" + "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", - "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", + "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", "shasum": "" }, "require": { - "php": "^5.5 || ^7.0", - "phpdocumentor/reflection-common": "^1.0" + "php": "^7.1", + "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^5.2||^4.8.24" + "ext-tokenizer": "^7.1", + "mockery/mockery": "~1", + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] + "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -4961,42 +6195,92 @@ "email": "me@mikevanriel.com" } ], - "time": "2017-07-14T14:27:02+00:00" + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "time": "2019-08-22T18:11:29+00:00" }, { - "name": "phpspec/prophecy", - "version": "1.8.0", + "name": "phploc/phploc", + "version": "5.0.0", "source": { "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" + "url": "https://github.com/sebastianbergmann/phploc.git", + "reference": "5b714ccb7cb8ca29ccf9caf6eb1aed0131d3a884" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", - "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", + "url": "https://api.github.com/repos/sebastianbergmann/phploc/zipball/5b714ccb7cb8ca29ccf9caf6eb1aed0131d3a884", + "reference": "5b714ccb7cb8ca29ccf9caf6eb1aed0131d3a884", + "shasum": "" + }, + "require": { + "php": "^7.2", + "sebastian/finder-facade": "^1.1", + "sebastian/version": "^2.0", + "symfony/console": "^4.0" + }, + "bin": [ + "phploc" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.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": "A tool for quickly measuring the size of a PHP project.", + "homepage": "https://github.com/sebastianbergmann/phploc", + "time": "2019-03-16T10:41:19+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.10.2", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/b4400efc9d206e83138e2bb97ed7f5b14b831cd9", + "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", - "sebastian/comparator": "^1.1|^2.0|^3.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0" + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", + "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0" }, "require-dev": { - "phpspec/phpspec": "^2.5|^3.2", + "phpspec/phpspec": "^2.5 || ^3.2", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8.x-dev" + "dev-master": "1.10.x-dev" } }, "autoload": { - "psr-0": { - "Prophecy\\": "src/" + "psr-4": { + "Prophecy\\": "src/Prophecy" } }, "notification-url": "https://packagist.org/downloads/", @@ -5024,44 +6308,44 @@ "spy", "stub" ], - "time": "2018-08-05T17:53:17+00:00" + "time": "2020-01-20T15:57:02+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "5.3.2", + "version": "7.0.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "c89677919c5dd6d3b3852f230a663118762218ac" + "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c89677919c5dd6d3b3852f230a663118762218ac", - "reference": "c89677919c5dd6d3b3852f230a663118762218ac", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f1884187926fbb755a9aaf0b3836ad3165b478bf", + "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf", "shasum": "" }, "require": { "ext-dom": "*", "ext-xmlwriter": "*", - "php": "^7.0", - "phpunit/php-file-iterator": "^1.4.2", + "php": "^7.2", + "phpunit/php-file-iterator": "^2.0.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^2.0.1", + "phpunit/php-token-stream": "^3.1.1", "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^3.0", + "sebastian/environment": "^4.2.2", "sebastian/version": "^2.0.1", - "theseer/tokenizer": "^1.1" + "theseer/tokenizer": "^1.1.3" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^8.2.2" }, "suggest": { - "ext-xdebug": "^2.5.5" + "ext-xdebug": "^2.7.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.3.x-dev" + "dev-master": "7.0-dev" } }, "autoload": { @@ -5087,29 +6371,32 @@ "testing", "xunit" ], - "time": "2018-04-06T15:36:58+00:00" + "time": "2019-11-20T13:55:58+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "1.4.5", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + "reference": "050bedf145a257b1ff02746c31894800e5122946" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946", + "reference": "050bedf145a257b1ff02746c31894800e5122946", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -5124,7 +6411,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -5134,7 +6421,7 @@ "filesystem", "iterator" ], - "time": "2017-11-27T13:52:08+00:00" + "time": "2018-09-13T20:33:42+00:00" }, { "name": "phpunit/php-text-template", @@ -5179,28 +6466,28 @@ }, { "name": "phpunit/php-timer", - "version": "1.0.9", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.1-dev" } }, "autoload": { @@ -5215,7 +6502,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -5224,33 +6511,33 @@ "keywords": [ "timer" ], - "time": "2017-02-26T11:10:40+00:00" + "time": "2019-06-07T04:22:29+00:00" }, { "name": "phpunit/php-token-stream", - "version": "2.0.2", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "791198a2c6254db10131eecfe8c06670700904db" + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", - "reference": "791198a2c6254db10131eecfe8c06670700904db", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.2.4" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -5273,57 +6560,56 @@ "keywords": [ "tokenizer" ], - "time": "2017-11-27T05:48:46+00:00" + "time": "2019-09-17T06:23:10+00:00" }, { "name": "phpunit/phpunit", - "version": "6.5.13", + "version": "8.5.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "0973426fb012359b2f18d3bd1e90ef1172839693" + "reference": "018b6ac3c8ab20916db85fa91bf6465acb64d1e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0973426fb012359b2f18d3bd1e90ef1172839693", - "reference": "0973426fb012359b2f18d3bd1e90ef1172839693", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/018b6ac3c8ab20916db85fa91bf6465acb64d1e0", + "reference": "018b6ac3c8ab20916db85fa91bf6465acb64d1e0", "shasum": "" }, "require": { + "doctrine/instantiator": "^1.2.0", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", - "myclabs/deep-copy": "^1.6.1", - "phar-io/manifest": "^1.0.1", - "phar-io/version": "^1.0", - "php": "^7.0", - "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^5.3", - "phpunit/php-file-iterator": "^1.4.3", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.9.1", + "phar-io/manifest": "^1.0.3", + "phar-io/version": "^2.0.1", + "php": "^7.2", + "phpspec/prophecy": "^1.8.1", + "phpunit/php-code-coverage": "^7.0.7", + "phpunit/php-file-iterator": "^2.0.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^1.0.9", - "phpunit/phpunit-mock-objects": "^5.0.9", - "sebastian/comparator": "^2.1", - "sebastian/diff": "^2.0", - "sebastian/environment": "^3.1", - "sebastian/exporter": "^3.1", - "sebastian/global-state": "^2.0", + "phpunit/php-timer": "^2.1.2", + "sebastian/comparator": "^3.0.2", + "sebastian/diff": "^3.0.2", + "sebastian/environment": "^4.2.2", + "sebastian/exporter": "^3.1.1", + "sebastian/global-state": "^3.0.0", "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^1.0", + "sebastian/resource-operations": "^2.0.1", + "sebastian/type": "^1.1.3", "sebastian/version": "^2.0.1" }, - "conflict": { - "phpdocumentor/reflection-docblock": "3.0.2", - "phpunit/dbunit": "<3.0" - }, "require-dev": { "ext-pdo": "*" }, "suggest": { + "ext-soap": "*", "ext-xdebug": "*", - "phpunit/php-invoker": "^1.1" + "phpunit/php-invoker": "^2.0.0" }, "bin": [ "phpunit" @@ -5331,7 +6617,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "6.5.x-dev" + "dev-master": "8.5-dev" } }, "autoload": { @@ -5357,66 +6643,7 @@ "testing", "xunit" ], - "time": "2018-09-08T15:10:43+00:00" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "5.0.10", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/cd1cf05c553ecfec36b170070573e540b67d3f1f", - "reference": "cd1cf05c553ecfec36b170070573e540b67d3f1f", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.5", - "php": "^7.0", - "phpunit/php-text-template": "^1.2.1", - "sebastian/exporter": "^3.1" - }, - "conflict": { - "phpunit/phpunit": "<6.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.5.11" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0.x-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": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "time": "2018-08-09T05:50:03+00:00" + "time": "2020-01-08T08:49:49+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -5465,30 +6692,30 @@ }, { "name": "sebastian/comparator", - "version": "2.1.3", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9" + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9", - "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", "shasum": "" }, "require": { - "php": "^7.0", - "sebastian/diff": "^2.0 || ^3.0", + "php": "^7.1", + "sebastian/diff": "^3.0", "sebastian/exporter": "^3.1" }, "require-dev": { - "phpunit/phpunit": "^6.4" + "phpunit/phpunit": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -5525,32 +6752,33 @@ "compare", "equality" ], - "time": "2018-02-01T13:46:46+00:00" + "time": "2018-07-12T15:12:46+00:00" }, { "name": "sebastian/diff", - "version": "2.0.1", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd" + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", - "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.2" + "phpunit/phpunit": "^7.5 || ^8.0", + "symfony/process": "^2 || ^3.3 || ^4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -5575,34 +6803,40 @@ "description": "Diff implementation", "homepage": "https://github.com/sebastianbergmann/diff", "keywords": [ - "diff" + "diff", + "udiff", + "unidiff", + "unified diff" ], - "time": "2017-08-03T08:09:46+00:00" + "time": "2019-02-04T06:01:07+00:00" }, { "name": "sebastian/environment", - "version": "3.1.0", + "version": "4.2.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" + "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", - "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/464c90d7bdf5ad4e8a6aea15c091fec0603d4368", + "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.1" + "phpunit/phpunit": "^7.5" + }, + "suggest": { + "ext-posix": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1.x-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -5627,20 +6861,20 @@ "environment", "hhvm" ], - "time": "2017-07-01T08:51:00+00:00" + "time": "2019-11-20T08:46:58+00:00" }, { "name": "sebastian/exporter", - "version": "3.1.0", + "version": "3.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" + "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e", + "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e", "shasum": "" }, "require": { @@ -5667,6 +6901,10 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" @@ -5675,17 +6913,13 @@ "name": "Volker Dusch", "email": "github@wallbash.com" }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, { "name": "Adam Harvey", "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" } ], "description": "Provides the functionality to export PHP variables for visualization", @@ -5694,27 +6928,73 @@ "export", "exporter" ], - "time": "2017-04-03T13:19:02+00:00" + "time": "2019-09-14T09:02:43+00:00" }, { - "name": "sebastian/global-state", - "version": "2.0.0", + "name": "sebastian/finder-facade", + "version": "1.2.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" + "url": "https://github.com/sebastianbergmann/finder-facade.git", + "reference": "167c45d131f7fc3d159f56f191a0a22228765e16" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "url": "https://api.github.com/repos/sebastianbergmann/finder-facade/zipball/167c45d131f7fc3d159f56f191a0a22228765e16", + "reference": "167c45d131f7fc3d159f56f191a0a22228765e16", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.1", + "symfony/finder": "^2.3|^3.0|^4.0|^5.0", + "theseer/fdomdocument": "^1.6" + }, + "type": "library", + "extra": { + "branch-alias": [] + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FinderFacade is a convenience wrapper for Symfony's Finder component.", + "homepage": "https://github.com/sebastianbergmann/finder-facade", + "time": "2020-01-16T08:08:45+00:00" + }, + { + "name": "sebastian/global-state", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4", + "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4", + "shasum": "" + }, + "require": { + "php": "^7.2", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "ext-dom": "*", + "phpunit/phpunit": "^8.0" }, "suggest": { "ext-uopz": "*" @@ -5722,7 +7002,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -5745,7 +7025,7 @@ "keywords": [ "global state" ], - "time": "2017-04-27T15:39:26+00:00" + "time": "2019-02-01T05:30:01+00:00" }, { "name": "sebastian/object-enumerator", @@ -5894,25 +7174,25 @@ }, { "name": "sebastian/resource-operations", - "version": "1.0.0", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9", + "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9", "shasum": "" }, "require": { - "php": ">=5.6.0" + "php": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -5932,7 +7212,53 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28T20:34:47+00:00" + "time": "2018-10-04T04:07:39+00:00" + }, + { + "name": "sebastian/type", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/3aaaa15fa71d27650d62a948be022fe3b48541a3", + "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3", + "shasum": "" + }, + "require": { + "php": "^7.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.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": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "time": "2019-07-02T08:10:15+00:00" }, { "name": "sebastian/version", @@ -5979,16 +7305,16 @@ }, { "name": "seld/jsonlint", - "version": "1.7.1", + "version": "1.7.2", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "d15f59a67ff805a44c50ea0516d2341740f81a38" + "reference": "e2e5d290e4d2a4f0eb449f510071392e00e10d19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/d15f59a67ff805a44c50ea0516d2341740f81a38", - "reference": "d15f59a67ff805a44c50ea0516d2341740f81a38", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/e2e5d290e4d2a4f0eb449f510071392e00e10d19", + "reference": "e2e5d290e4d2a4f0eb449f510071392e00e10d19", "shasum": "" }, "require": { @@ -6024,20 +7350,20 @@ "parser", "validator" ], - "time": "2018-01-24T12:46:19+00:00" + "time": "2019-10-24T14:27:39+00:00" }, { "name": "seld/phar-utils", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/Seldaek/phar-utils.git", - "reference": "7009b5139491975ef6486545a39f3e6dad5ac30a" + "reference": "84715761c35808076b00908a20317a3a8a67d17e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/7009b5139491975ef6486545a39f3e6dad5ac30a", - "reference": "7009b5139491975ef6486545a39f3e6dad5ac30a", + "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/84715761c35808076b00908a20317a3a8a67d17e", + "reference": "84715761c35808076b00908a20317a3a8a67d17e", "shasum": "" }, "require": { @@ -6068,20 +7394,20 @@ "keywords": [ "phra" ], - "time": "2015-10-13T18:44:15+00:00" + "time": "2020-01-13T10:41:09+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.4.0", + "version": "3.5.3", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "379deb987e26c7cd103a7b387aea178baec96e48" + "reference": "557a1fc7ac702c66b0bbfe16ab3d55839ef724cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/379deb987e26c7cd103a7b387aea178baec96e48", - "reference": "379deb987e26c7cd103a7b387aea178baec96e48", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/557a1fc7ac702c66b0bbfe16ab3d55839ef724cb", + "reference": "557a1fc7ac702c66b0bbfe16ab3d55839ef724cb", "shasum": "" }, "require": { @@ -6114,33 +7440,38 @@ } ], "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "http://www.squizlabs.com/php-codesniffer", + "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", "keywords": [ "phpcs", "standards" ], - "time": "2018-12-19T23:57:18+00:00" + "time": "2019-12-04T04:46:47+00:00" }, { "name": "symfony/dom-crawler", - "version": "v3.1.10", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "7eede2a901a19928494194f7d1815a77b9a473a0" + "reference": "b66fe8ccc850ea11c4cd31677706c1219768bea1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/7eede2a901a19928494194f7d1815a77b9a473a0", - "reference": "7eede2a901a19928494194f7d1815a77b9a473a0", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/b66fe8ccc850ea11c4cd31677706c1219768bea1", + "reference": "b66fe8ccc850ea11c4cd31677706c1219768bea1", "shasum": "" }, "require": { - "php": ">=5.5.9", + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0" }, + "conflict": { + "masterminds/html5": "<2.6" + }, "require-dev": { - "symfony/css-selector": "~2.8|~3.0" + "masterminds/html5": "^2.6", + "symfony/css-selector": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/css-selector": "" @@ -6148,7 +7479,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -6175,29 +7506,30 @@ ], "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", - "time": "2017-01-21T17:13:55+00:00" + "time": "2020-01-04T13:00:46+00:00" }, { "name": "symfony/filesystem", - "version": "v3.3.6", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "427987eb4eed764c3b6e38d52a0f87989e010676" + "reference": "266c9540b475f26122b61ef8b23dd9198f5d1cfd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/427987eb4eed764c3b6e38d52a0f87989e010676", - "reference": "427987eb4eed764c3b6e38d52a0f87989e010676", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/266c9540b475f26122b61ef8b23dd9198f5d1cfd", + "reference": "266c9540b475f26122b61ef8b23dd9198f5d1cfd", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": "^7.1.3", + "symfony/polyfill-ctype": "~1.8" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -6224,20 +7556,60 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2017-07-11T07:17:58+00:00" + "time": "2020-01-21T08:20:44+00:00" }, { - "name": "theseer/tokenizer", - "version": "1.1.0", + "name": "theseer/fdomdocument", + "version": "1.6.6", "source": { "type": "git", - "url": "https://github.com/theseer/tokenizer.git", - "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" + "url": "https://github.com/theseer/fDOMDocument.git", + "reference": "6e8203e40a32a9c770bcb62fe37e68b948da6dca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", - "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "url": "https://api.github.com/repos/theseer/fDOMDocument/zipball/6e8203e40a32a9c770bcb62fe37e68b948da6dca", + "reference": "6e8203e40a32a9c770bcb62fe37e68b948da6dca", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "lib-libxml": "*", + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "role": "lead", + "email": "arne@blankerts.de" + } + ], + "description": "The classes contained within this repository extend the standard DOM to use exceptions at all occasions of errors instead of PHP warnings or notices. They also add various custom methods and shortcuts for convenience and to simplify the usage of DOM.", + "homepage": "https://github.com/theseer/fDOMDocument", + "time": "2017-06-30T11:53:12+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", "shasum": "" }, "require": { @@ -6259,41 +7631,38 @@ "authors": [ { "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" + "role": "Developer", + "email": "arne@blankerts.de" } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2017-04-07T12:08:54+00:00" + "time": "2019-06-13T22:48:21+00:00" }, { "name": "webmozart/assert", - "version": "1.4.0", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9" + "reference": "573381c0a64f155a0d9a23f4b0c797194805b925" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9", - "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9", + "url": "https://api.github.com/repos/webmozart/assert/zipball/573381c0a64f155a0d9a23f4b0c797194805b925", + "reference": "573381c0a64f155a0d9a23f4b0c797194805b925", "shasum": "" }, "require": { "php": "^5.3.3 || ^7.0", "symfony/polyfill-ctype": "^1.8" }, + "conflict": { + "vimeo/psalm": "<3.6.0" + }, "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" + "phpunit/phpunit": "^4.8.36 || ^7.5.13" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, "autoload": { "psr-4": { "Webmozart\\Assert\\": "src/" @@ -6315,28 +7684,89 @@ "check", "validate" ], - "time": "2018-12-25T11:19:39+00:00" + "time": "2019-11-24T13:36:37+00:00" + }, + { + "name": "wnx/laravel-stats", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/stefanzweifel/laravel-stats.git", + "reference": "1b3c60bfbf81233973cbc2a63be4e6f83b2d6205" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/stefanzweifel/laravel-stats/zipball/1b3c60bfbf81233973cbc2a63be4e6f83b2d6205", + "reference": "1b3c60bfbf81233973cbc2a63be4e6f83b2d6205", + "shasum": "" + }, + "require": { + "illuminate/console": "~5.8.0|^6.0", + "illuminate/support": "~5.8.0|^6.0", + "php": ">=7.2.0", + "phploc/phploc": "~4.0|~5.0", + "symfony/finder": "~3.3|~4.0" + }, + "require-dev": { + "laravel/browser-kit-testing": "~2.0|~3.0|~4.0|~5.0", + "laravel/dusk": "~3.0|~4.0|~5.0", + "mockery/mockery": "^1.1", + "orchestra/testbench": "^3.8", + "phpunit/phpunit": "6.*|7.*|8.*" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Wnx\\LaravelStats\\StatsServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Wnx\\LaravelStats\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Stefan Zweifel", + "email": "hello@stefanzweifel.io", + "homepage": "https://stefanzweifel.io", + "role": "Developer" + } + ], + "description": "Get insights about your Laravel Project", + "homepage": "https://github.com/stefanzweifel/laravel-stats", + "keywords": [ + "laravel", + "statistics", + "stats", + "wnx" + ], + "time": "2019-09-01T14:18:49+00:00" } ], "aliases": [], - "minimum-stability": "stable", - "stability-flags": { - "laravel/socialite": 20 - }, - "prefer-stable": false, + "minimum-stability": "dev", + "stability-flags": [], + "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": ">=7.0.5", - "ext-json": "*", - "ext-tidy": "*", + "php": "^7.2", + "ext-curl": "*", "ext-dom": "*", - "ext-xml": "*", - "ext-mbstring": "*", "ext-gd": "*", - "ext-curl": "*" + "ext-json": "*", + "ext-mbstring": "*", + "ext-tidy": "*", + "ext-xml": "*" }, "platform-dev": [], "platform-overrides": { - "php": "7.0.5" + "php": "7.2.0" } } diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 000000000..634a5772f --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,7 @@ +project_identifier: bookstack +base_path: . +preserve_hierarchy: false +files: + - source: /resources/lang/en/*.php + translation: /resources/lang/%two_letters_code%/%original_file_name% + type: php diff --git a/database/factories/ModelFactory.php b/database/factories/ModelFactory.php index de6b0b276..ddf3c295d 100644 --- a/database/factories/ModelFactory.php +++ b/database/factories/ModelFactory.php @@ -15,8 +15,8 @@ $factory->define(\BookStack\Auth\User::class, function ($faker) { return [ 'name' => $faker->name, 'email' => $faker->email, - 'password' => str_random(10), - 'remember_token' => str_random(10), + 'password' => Str::random(10), + 'remember_token' => Str::random(10), 'email_confirmed' => 1 ]; }); @@ -24,7 +24,7 @@ $factory->define(\BookStack\Auth\User::class, function ($faker) { $factory->define(\BookStack\Entities\Bookshelf::class, function ($faker) { return [ 'name' => $faker->sentence, - 'slug' => str_random(10), + 'slug' => Str::random(10), 'description' => $faker->paragraph ]; }); @@ -32,7 +32,7 @@ $factory->define(\BookStack\Entities\Bookshelf::class, function ($faker) { $factory->define(\BookStack\Entities\Book::class, function ($faker) { return [ 'name' => $faker->sentence, - 'slug' => str_random(10), + 'slug' => Str::random(10), 'description' => $faker->paragraph ]; }); @@ -40,7 +40,7 @@ $factory->define(\BookStack\Entities\Book::class, function ($faker) { $factory->define(\BookStack\Entities\Chapter::class, function ($faker) { return [ 'name' => $faker->sentence, - 'slug' => str_random(10), + 'slug' => Str::random(10), 'description' => $faker->paragraph ]; }); @@ -49,7 +49,7 @@ $factory->define(\BookStack\Entities\Page::class, function ($faker) { $html = '

' . implode('

', $faker->paragraphs(5)) . '

'; return [ 'name' => $faker->sentence, - 'slug' => str_random(10), + 'slug' => Str::random(10), 'html' => $html, 'text' => strip_tags($html), 'revision_count' => 1 diff --git a/database/migrations/2019_07_07_112515_add_template_support.php b/database/migrations/2019_07_07_112515_add_template_support.php index a54508198..3fcc68227 100644 --- a/database/migrations/2019_07_07_112515_add_template_support.php +++ b/database/migrations/2019_07_07_112515_add_template_support.php @@ -46,9 +46,9 @@ class AddTemplateSupport extends Migration // Remove templates-manage permission $templatesManagePermission = DB::table('role_permissions') - ->where('name', '=', 'templates_manage')->first(); + ->where('name', '=', 'templates-manage')->first(); DB::table('permission_role')->where('permission_id', '=', $templatesManagePermission->id)->delete(); - DB::table('role_permissions')->where('name', '=', 'templates_manage')->delete(); + DB::table('role_permissions')->where('name', '=', 'templates-manage')->delete(); } } diff --git a/database/migrations/2019_12_29_120917_add_api_auth.php b/database/migrations/2019_12_29_120917_add_api_auth.php new file mode 100644 index 000000000..eff88247f --- /dev/null +++ b/database/migrations/2019_12_29_120917_add_api_auth.php @@ -0,0 +1,60 @@ +increments('id'); + $table->string('name'); + $table->string('token_id')->unique(); + $table->string('secret'); + $table->integer('user_id')->unsigned()->index(); + $table->date('expires_at')->index(); + $table->nullableTimestamps(); + }); + + // Add access-api permission + $adminRoleId = DB::table('roles')->where('system_name', '=', 'admin')->first()->id; + $permissionId = DB::table('role_permissions')->insertGetId([ + 'name' => 'access-api', + 'display_name' => 'Access system API', + 'created_at' => Carbon::now()->toDateTimeString(), + 'updated_at' => Carbon::now()->toDateTimeString() + ]); + DB::table('permission_role')->insert([ + 'role_id' => $adminRoleId, + 'permission_id' => $permissionId + ]); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // Remove API tokens table + Schema::dropIfExists('api_tokens'); + + // Remove access-api permission + $apiAccessPermission = DB::table('role_permissions') + ->where('name', '=', 'access-api')->first(); + + DB::table('permission_role')->where('permission_id', '=', $apiAccessPermission->id)->delete(); + DB::table('role_permissions')->where('name', '=', 'access-api')->delete(); + } +} diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php index 988ea2100..d86cb0ddd 100644 --- a/database/seeds/DatabaseSeeder.php +++ b/database/seeds/DatabaseSeeder.php @@ -6,7 +6,7 @@ use Illuminate\Database\Eloquent\Model; class DatabaseSeeder extends Seeder { /** - * Run the database seeds. + * Seed the application's database. * * @return void */ diff --git a/database/seeds/DummyContentSeeder.php b/database/seeds/DummyContentSeeder.php index ce3cd1307..6d902a196 100644 --- a/database/seeds/DummyContentSeeder.php +++ b/database/seeds/DummyContentSeeder.php @@ -1,6 +1,16 @@ create(); - $editorRole = \BookStack\Auth\Role::getRole('editor'); + $editorUser = factory(User::class)->create(); + $editorRole = Role::getRole('editor'); $editorUser->attachRole($editorRole); // Create a viewer user - $viewerUser = factory(\BookStack\Auth\User::class)->create(); - $role = \BookStack\Auth\Role::getRole('viewer'); + $viewerUser = factory(User::class)->create(); + $role = Role::getRole('viewer'); $viewerUser->attachRole($role); $byData = ['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]; factory(\BookStack\Entities\Book::class, 5)->create($byData) ->each(function($book) use ($editorUser, $byData) { - $chapters = factory(\BookStack\Entities\Chapter::class, 3)->create($byData) + $chapters = factory(Chapter::class, 3)->create($byData) ->each(function($chapter) use ($editorUser, $book, $byData){ - $pages = factory(\BookStack\Entities\Page::class, 3)->make(array_merge($byData, ['book_id' => $book->id])); + $pages = factory(Page::class, 3)->make(array_merge($byData, ['book_id' => $book->id])); $chapter->pages()->saveMany($pages); }); - $pages = factory(\BookStack\Entities\Page::class, 3)->make($byData); + $pages = factory(Page::class, 3)->make($byData); $book->chapters()->saveMany($chapters); $book->pages()->saveMany($pages); }); - $largeBook = factory(\BookStack\Entities\Book::class)->create(array_merge($byData, ['name' => 'Large book' . str_random(10)])); - $pages = factory(\BookStack\Entities\Page::class, 200)->make($byData); - $chapters = factory(\BookStack\Entities\Chapter::class, 50)->make($byData); + $largeBook = factory(\BookStack\Entities\Book::class)->create(array_merge($byData, ['name' => 'Large book' . Str::random(10)])); + $pages = factory(Page::class, 200)->make($byData); + $chapters = factory(Chapter::class, 50)->make($byData); $largeBook->pages()->saveMany($pages); $largeBook->chapters()->saveMany($chapters); - $shelves = factory(\BookStack\Entities\Bookshelf::class, 10)->create($byData); + $shelves = factory(Bookshelf::class, 10)->create($byData); $largeBook->shelves()->attach($shelves->pluck('id')); - app(\BookStack\Auth\Permissions\PermissionService::class)->buildJointPermissions(); - app(\BookStack\Entities\SearchService::class)->indexAllEntities(); + // Assign API permission to editor role and create an API key + $apiPermission = RolePermission::getByName('access-api'); + $editorRole->attachPermission($apiPermission); + $token = (new ApiToken())->forceFill([ + 'user_id' => $editorUser->id, + 'name' => 'Testing API key', + 'expires_at' => ApiToken::defaultExpiry(), + 'secret' => Hash::make('password'), + 'token_id' => 'apitoken', + ]); + $token->save(); + + app(PermissionService::class)->buildJointPermissions(); + app(SearchService::class)->indexAllEntities(); } } diff --git a/database/seeds/LargeContentSeeder.php b/database/seeds/LargeContentSeeder.php index 136b6cb6a..4db10395a 100644 --- a/database/seeds/LargeContentSeeder.php +++ b/database/seeds/LargeContentSeeder.php @@ -1,6 +1,13 @@ create(); - $editorRole = \BookStack\Auth\Role::getRole('editor'); + $editorUser = factory(User::class)->create(); + $editorRole = Role::getRole('editor'); $editorUser->attachRole($editorRole); - $largeBook = factory(\BookStack\Entities\Book::class)->create(['name' => 'Large book' . str_random(10), 'created_by' => $editorUser->id, 'updated_by' => $editorUser->id]); - $pages = factory(\BookStack\Entities\Page::class, 200)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]); - $chapters = factory(\BookStack\Entities\Chapter::class, 50)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]); + $largeBook = factory(\BookStack\Entities\Book::class)->create(['name' => 'Large book' . Str::random(10), 'created_by' => $editorUser->id, 'updated_by' => $editorUser->id]); + $pages = factory(Page::class, 200)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]); + $chapters = factory(Chapter::class, 50)->make(['created_by' => $editorUser->id, 'updated_by' => $editorUser->id]); $largeBook->pages()->saveMany($pages); $largeBook->chapters()->saveMany($chapters); - app(\BookStack\Auth\Permissions\PermissionService::class)->buildJointPermissions(); - app(\BookStack\Entities\SearchService::class)->indexAllEntities(); + app(PermissionService::class)->buildJointPermissions(); + app(SearchService::class)->indexAllEntities(); } } diff --git a/dev/api/requests/books-create.json b/dev/api/requests/books-create.json new file mode 100644 index 000000000..4a6626619 --- /dev/null +++ b/dev/api/requests/books-create.json @@ -0,0 +1,4 @@ +{ + "name": "My own book", + "description": "This is my own little book" +} \ No newline at end of file diff --git a/dev/api/requests/books-update.json b/dev/api/requests/books-update.json new file mode 100644 index 000000000..fc67d5fcc --- /dev/null +++ b/dev/api/requests/books-update.json @@ -0,0 +1,4 @@ +{ + "name": "My updated book", + "description": "This is my book with updated details" +} \ No newline at end of file diff --git a/dev/api/responses/books-create.json b/dev/api/responses/books-create.json new file mode 100644 index 000000000..0b4336ab2 --- /dev/null +++ b/dev/api/responses/books-create.json @@ -0,0 +1,10 @@ +{ + "name": "My new book", + "description": "This is a book created via the API", + "created_by": 1, + "updated_by": 1, + "slug": "my-new-book", + "updated_at": "2020-01-12 14:05:11", + "created_at": "2020-01-12 14:05:11", + "id": 15 +} \ No newline at end of file diff --git a/dev/api/responses/books-list.json b/dev/api/responses/books-list.json new file mode 100644 index 000000000..29e83b1c0 --- /dev/null +++ b/dev/api/responses/books-list.json @@ -0,0 +1,27 @@ +{ + "data": [ + { + "id": 1, + "name": "BookStack User Guide", + "slug": "bookstack-user-guide", + "description": "This is a general guide on using BookStack on a day-to-day basis.", + "created_at": "2019-05-05 21:48:46", + "updated_at": "2019-12-11 20:57:31", + "created_by": 1, + "updated_by": 1, + "image_id": 3 + }, + { + "id": 2, + "name": "Inventore inventore quia voluptatem.", + "slug": "inventore-inventore-quia-voluptatem", + "description": "Veniam nihil voluptas enim laborum corporis quos sint. Ab rerum voluptas ut iste voluptas magni quibusdam ut. Amet omnis enim voluptate neque facilis.", + "created_at": "2019-05-05 22:10:14", + "updated_at": "2019-12-11 20:57:23", + "created_by": 4, + "updated_by": 3, + "image_id": 34 + } + ], + "total": 14 +} \ No newline at end of file diff --git a/dev/api/responses/books-read.json b/dev/api/responses/books-read.json new file mode 100644 index 000000000..e0570444f --- /dev/null +++ b/dev/api/responses/books-read.json @@ -0,0 +1,47 @@ +{ + "id": 16, + "name": "My own book", + "slug": "my-own-book", + "description": "This is my own little book", + "created_at": "2020-01-12 14:09:59", + "updated_at": "2020-01-12 14:11:51", + "created_by": { + "id": 1, + "name": "Admin", + "created_at": "2019-05-05 21:15:13", + "updated_at": "2019-12-16 12:18:37", + "image_id": 48 + }, + "updated_by": { + "id": 1, + "name": "Admin", + "created_at": "2019-05-05 21:15:13", + "updated_at": "2019-12-16 12:18:37", + "image_id": 48 + }, + "image_id": 452, + "tags": [ + { + "id": 13, + "entity_id": 16, + "entity_type": "BookStack\\Book", + "name": "Category", + "value": "Guide", + "order": 0, + "created_at": "2020-01-12 14:11:51", + "updated_at": "2020-01-12 14:11:51" + } + ], + "cover": { + "id": 452, + "name": "sjovall_m117hUWMu40.jpg", + "url": "http:\/\/bookstack.local\/uploads\/images\/cover_book\/2020-01\/sjovall_m117hUWMu40.jpg", + "created_at": "2020-01-12 14:11:51", + "updated_at": "2020-01-12 14:11:51", + "created_by": 1, + "updated_by": 1, + "path": "\/uploads\/images\/cover_book\/2020-01\/sjovall_m117hUWMu40.jpg", + "type": "cover_book", + "uploaded_to": 16 + } +} \ No newline at end of file diff --git a/dev/api/responses/books-update.json b/dev/api/responses/books-update.json new file mode 100644 index 000000000..8f20b5b9f --- /dev/null +++ b/dev/api/responses/books-update.json @@ -0,0 +1,11 @@ +{ + "id": 16, + "name": "My own book", + "slug": "my-own-book", + "description": "This is my own little book - updated", + "created_at": "2020-01-12 14:09:59", + "updated_at": "2020-01-12 14:16:10", + "created_by": 1, + "updated_by": 1, + "image_id": 452 +} \ No newline at end of file diff --git a/dev/docker/Dockerfile b/dev/docker/Dockerfile index 82ea2b6f6..8816615cf 100644 --- a/dev/docker/Dockerfile +++ b/dev/docker/Dockerfile @@ -4,7 +4,7 @@ ENV APACHE_DOCUMENT_ROOT /app/public WORKDIR /app RUN apt-get update -y \ - && apt-get install -y libtidy-dev libpng-dev libldap2-dev libxml++2.6-dev wait-for-it \ + && apt-get install -y git zip unzip libtidy-dev libpng-dev libldap2-dev libxml++2.6-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 \ && a2enmod rewrite \ diff --git a/package-lock.json b/package-lock.json index 3330ad5c7..7142eebd2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -197,21 +197,15 @@ "dev": true }, "acorn": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", - "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", - "dev": true - }, - "acorn-dynamic-import": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", - "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz", + "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==", "dev": true }, "ajv": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", - "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -221,15 +215,15 @@ } }, "ajv-errors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.0.tgz", - "integrity": "sha1-7PAh+hCP0X37Xms4Py3SM+Mf/Fk=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", "dev": true }, "ajv-keywords": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.1.0.tgz", - "integrity": "sha1-rCsnk5xUPpXSwG5/f1wnvkqlQ74=", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", "dev": true }, "amdefine": { @@ -406,9 +400,9 @@ "dev": true }, "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "dev": true }, "async-foreach": { @@ -417,6 +411,12 @@ "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", "dev": true }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -436,9 +436,9 @@ "dev": true }, "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz", + "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==", "dev": true }, "balanced-match": { @@ -499,19 +499,13 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true } } }, "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", "dev": true }, "bcrypt-pbkdf": { @@ -524,17 +518,27 @@ } }, "big.js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true }, "binary-extensions": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.10.0.tgz", - "integrity": "sha1-muuabF6IY4qtFx4Wf1kAq+JINdA=", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, "block-stream": { "version": "0.0.9", "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", @@ -545,9 +549,9 @@ } }, "bluebird": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", - "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, "bn.js": { @@ -636,14 +640,6 @@ "des.js": "^1.0.0", "inherits": "^2.0.1", "safe-buffer": "^5.1.2" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } } }, "browserify-rsa": { @@ -681,9 +677,9 @@ } }, "buffer": { - "version": "4.9.1", - "resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", "dev": true, "requires": { "base64-js": "^1.0.2", @@ -716,31 +712,32 @@ "dev": true }, "cacache": { - "version": "11.3.2", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz", - "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==", + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz", + "integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==", "dev": true, "requires": { - "bluebird": "^3.5.3", + "bluebird": "^3.5.5", "chownr": "^1.1.1", "figgy-pudding": "^3.5.1", - "glob": "^7.1.3", + "glob": "^7.1.4", "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", "lru-cache": "^5.1.1", "mississippi": "^3.0.0", "mkdirp": "^0.5.1", "move-concurrently": "^1.0.1", "promise-inflight": "^1.0.1", - "rimraf": "^2.6.2", + "rimraf": "^2.6.3", "ssri": "^6.0.1", "unique-filename": "^1.1.1", "y18n": "^4.0.0" }, "dependencies": { "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", "dev": true }, "lru-cache": { @@ -759,9 +756,9 @@ "dev": true }, "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true } } @@ -825,9 +822,9 @@ } }, "chokidar": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz", - "integrity": "sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "dev": true, "requires": { "anymatch": "^2.0.0", @@ -845,9 +842,9 @@ } }, "chownr": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", - "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", + "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==", "dev": true }, "chrome-trace-event": { @@ -914,23 +911,14 @@ } }, "clone-deep": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz", - "integrity": "sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "dev": true, "requires": { - "for-own": "^1.0.0", "is-plain-object": "^2.0.4", - "kind-of": "^6.0.0", - "shallow-clone": "^1.0.0" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" } }, "code-point-at": { @@ -940,9 +928,9 @@ "dev": true }, "codemirror": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.47.0.tgz", - "integrity": "sha512-kV49Fr+NGFHFc/Imsx6g180hSlkGhuHxTSDDmDHOuyln0MQYFLixDY4+bFkBVeCEiepYfDimAF/e++9jPJk4QA==" + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.50.0.tgz", + "integrity": "sha512-32LAmGcBNhKtJP4WGgkcaCVQDyChAyaWA6jasg778ziZzo3PWBuhpAQIJMO8//Id45RoaLyXjuhcRUBoS8Vg+Q==" }, "collection-visit": { "version": "1.0.0", @@ -979,9 +967,9 @@ } }, "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, "commondir": { @@ -1015,13 +1003,10 @@ } }, "console-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", - "dev": true, - "requires": { - "date-now": "^0.1.4" - } + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true }, "console-control-strings": { "version": "1.1.0", @@ -1128,56 +1113,23 @@ } }, "css-loader": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-2.1.1.tgz", - "integrity": "sha512-OcKJU/lt232vl1P9EEDamhoO9iKY3tIjY5GU+XDLblAykTdgs6Ux9P1hTHve8nFKy5KPpOXOsVI/hIwi3841+w==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.4.0.tgz", + "integrity": "sha512-JornYo4RAXl1Mzt0lOSVPmArzAMV3rGY2VuwtaDc732WTWjdwTaeS19nCGWMcSCf305Q396lhhDAJEWWM0SgPQ==", "dev": true, "requires": { - "camelcase": "^5.2.0", - "icss-utils": "^4.1.0", + "camelcase": "^5.3.1", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", "loader-utils": "^1.2.3", "normalize-path": "^3.0.0", - "postcss": "^7.0.14", + "postcss": "^7.0.23", "postcss-modules-extract-imports": "^2.0.0", - "postcss-modules-local-by-default": "^2.0.6", - "postcss-modules-scope": "^2.1.0", - "postcss-modules-values": "^2.0.0", - "postcss-value-parser": "^3.3.0", - "schema-utils": "^1.0.0" - }, - "dependencies": { - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true - }, - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "loader-utils": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", - "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^2.0.0", - "json5": "^1.0.1" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } + "postcss-modules-local-by-default": "^3.0.2", + "postcss-modules-scope": "^2.1.1", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.0.2", + "schema-utils": "^2.6.0" } }, "cssesc": { @@ -1196,9 +1148,9 @@ } }, "cyclist": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", - "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", "dev": true }, "dashdash": { @@ -1210,12 +1162,6 @@ "assert-plus": "^1.0.0" } }, - "date-now": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", - "dev": true - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -1284,12 +1230,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true } } }, @@ -1311,9 +1251,9 @@ "dev": true }, "des.js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", - "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", "dev": true, "requires": { "inherits": "^2.0.1", @@ -1371,9 +1311,9 @@ } }, "elliptic": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", - "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", + "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", "dev": true, "requires": { "bn.js": "^4.4.0", @@ -1385,6 +1325,12 @@ "minimalistic-crypto-utils": "^1.0.0" } }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "emojis-list": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", @@ -1392,29 +1338,41 @@ "dev": true }, "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, "requires": { "once": "^1.4.0" } }, "enhanced-resolve": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", - "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz", + "integrity": "sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA==", "dev": true, "requires": { "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", + "memory-fs": "^0.5.0", "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } } }, "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", + "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==" }, "errno": { "version": "0.1.7", @@ -1484,9 +1442,9 @@ } }, "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, "events": { @@ -1668,12 +1626,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true } } }, @@ -1690,9 +1642,9 @@ "dev": true }, "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, "figgy-pudding": { @@ -1701,6 +1653,13 @@ "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", "dev": true }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -1736,66 +1695,25 @@ } }, "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { - "locate-path": "^3.0.0" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", "dev": true, "requires": { "detect-file": "^1.0.0", - "is-glob": "^3.1.0", + "is-glob": "^4.0.0", "micromatch": "^3.0.4", "resolve-dir": "^1.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } } }, "flush-write-stream": { @@ -1806,38 +1724,6 @@ "requires": { "inherits": "^2.0.3", "readable-stream": "^2.3.6" - }, - "dependencies": { - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } } }, "for-in": { @@ -1846,15 +1732,6 @@ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "dev": true, - "requires": { - "for-in": "^1.0.1" - } - }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -1910,14 +1787,15 @@ "dev": true }, "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.11.tgz", + "integrity": "sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==", "dev": true, "optional": true, "requires": { + "bindings": "^1.5.0", "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" + "node-pre-gyp": "*" }, "dependencies": { "abbrev": { @@ -1965,7 +1843,7 @@ } }, "chownr": { - "version": "1.1.1", + "version": "1.1.3", "bundled": true, "dev": true, "optional": true @@ -1995,7 +1873,7 @@ "optional": true }, "debug": { - "version": "4.1.1", + "version": "3.2.6", "bundled": true, "dev": true, "optional": true, @@ -2022,12 +1900,12 @@ "optional": true }, "fs-minipass": { - "version": "1.2.5", + "version": "1.2.7", "bundled": true, "dev": true, "optional": true, "requires": { - "minipass": "^2.2.1" + "minipass": "^2.6.0" } }, "fs.realpath": { @@ -2053,7 +1931,7 @@ } }, "glob": { - "version": "7.1.3", + "version": "7.1.6", "bundled": true, "dev": true, "optional": true, @@ -2082,7 +1960,7 @@ } }, "ignore-walk": { - "version": "3.0.1", + "version": "3.0.3", "bundled": true, "dev": true, "optional": true, @@ -2101,7 +1979,7 @@ } }, "inherits": { - "version": "2.0.3", + "version": "2.0.4", "bundled": true, "dev": true, "optional": true @@ -2143,7 +2021,7 @@ "optional": true }, "minipass": { - "version": "2.3.5", + "version": "2.9.0", "bundled": true, "dev": true, "optional": true, @@ -2153,12 +2031,12 @@ } }, "minizlib": { - "version": "1.2.1", + "version": "1.3.3", "bundled": true, "dev": true, "optional": true, "requires": { - "minipass": "^2.2.1" + "minipass": "^2.9.0" } }, "mkdirp": { @@ -2171,24 +2049,24 @@ } }, "ms": { - "version": "2.1.1", + "version": "2.1.2", "bundled": true, "dev": true, "optional": true }, "needle": { - "version": "2.3.0", + "version": "2.4.0", "bundled": true, "dev": true, "optional": true, "requires": { - "debug": "^4.1.0", + "debug": "^3.2.6", "iconv-lite": "^0.4.4", "sax": "^1.2.4" } }, "node-pre-gyp": { - "version": "0.12.0", + "version": "0.14.0", "bundled": true, "dev": true, "optional": true, @@ -2202,7 +2080,7 @@ "rc": "^1.2.7", "rimraf": "^2.6.1", "semver": "^5.3.0", - "tar": "^4" + "tar": "^4.4.2" } }, "nopt": { @@ -2216,13 +2094,22 @@ } }, "npm-bundled": { - "version": "1.0.6", + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", "bundled": true, "dev": true, "optional": true }, "npm-packlist": { - "version": "1.4.1", + "version": "1.4.7", "bundled": true, "dev": true, "optional": true, @@ -2293,7 +2180,7 @@ "optional": true }, "process-nextick-args": { - "version": "2.0.0", + "version": "2.0.1", "bundled": true, "dev": true, "optional": true @@ -2334,7 +2221,7 @@ } }, "rimraf": { - "version": "2.6.3", + "version": "2.7.1", "bundled": true, "dev": true, "optional": true, @@ -2361,7 +2248,7 @@ "optional": true }, "semver": { - "version": "5.7.0", + "version": "5.7.1", "bundled": true, "dev": true, "optional": true @@ -2414,18 +2301,18 @@ "optional": true }, "tar": { - "version": "4.4.8", + "version": "4.4.13", "bundled": true, "dev": true, "optional": true, "requires": { "chownr": "^1.1.1", "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", "mkdirp": "^0.5.0", "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" + "yallist": "^3.0.3" } }, "util-deprecate": { @@ -2450,7 +2337,7 @@ "optional": true }, "yallist": { - "version": "3.0.3", + "version": "3.1.1", "bundled": true, "dev": true, "optional": true @@ -2537,9 +2424,9 @@ } }, "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -2572,14 +2459,25 @@ } }, "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", "dev": true, "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" + "global-prefix": "^3.0.0" + }, + "dependencies": { + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + } + } } }, "global-prefix": { @@ -2596,9 +2494,9 @@ } }, "globule": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", - "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.0.tgz", + "integrity": "sha512-YlD4kdMqRCQHrhVdonet4TdRtv1/sZKepvoxNT4Nrhrp5HI8XFfc8kFlGlBn2myBo80aGp8Eft259mbcUJhgSg==", "dev": true, "requires": { "glob": "~7.1.1", @@ -2767,12 +2665,6 @@ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", "dev": true }, - "icss-replace-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", - "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", - "dev": true - }, "icss-utils": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", @@ -2831,10 +2723,10 @@ "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", "dev": true }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", "dev": true }, "inflight": { @@ -2848,9 +2740,9 @@ } }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, "ini": { @@ -2878,6 +2770,17 @@ "dev": true, "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "is-arrayish": { @@ -2923,6 +2826,17 @@ "dev": true, "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "is-date-object": { @@ -2996,6 +2910,17 @@ "dev": true, "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "is-plain-obj": { @@ -3122,10 +3047,13 @@ "dev": true }, "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } }, "jsonify": { "version": "0.0.0", @@ -3146,13 +3074,10 @@ } }, "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true }, "lcid": { "version": "1.0.0", @@ -3164,22 +3089,22 @@ } }, "linkify-it": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz", - "integrity": "sha1-2UpGSPmxwXnWT6lykSaL22zpQ08=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", "requires": { "uc.micro": "^1.0.1" } }, "livereload": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/livereload/-/livereload-0.8.0.tgz", - "integrity": "sha512-Hi5Na6VIK3e8zlgOS50fu+iOTKWj5hM0BE7NKpZkwnfWTnktTjA38ZUXa2NlJww8/GrdVhpnxdqlLad5fkO27g==", + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/livereload/-/livereload-0.8.2.tgz", + "integrity": "sha512-8wCvhiCL4cGVoT3U5xoe+UjpiiVZLrlOvr6dbhb1VlyC5QarhrlyRRt4z7EMGO4KSgXj+tKF/dr284F28/wI+g==", "dev": true, "requires": { "chokidar": "^2.1.5", "opts": ">= 1.2.0", - "ws": "^1.1.5" + "ws": "^6.2.1" } }, "load-json-file": { @@ -3210,14 +3135,14 @@ "dev": true }, "loader-utils": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", - "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", "dev": true, "requires": { - "big.js": "^3.1.3", + "big.js": "^5.2.2", "emojis-list": "^2.0.0", - "json5": "^0.5.0" + "json5": "^1.0.1" } }, "locate-path": { @@ -3228,18 +3153,20 @@ "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } } }, "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true - }, - "lodash.tail": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz", - "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=", + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, "loud-rejection": { @@ -3317,12 +3244,12 @@ } }, "markdown-it": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", - "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", + "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", "requires": { "argparse": "^1.0.7", - "entities": "~1.1.1", + "entities": "~2.0.0", "linkify-it": "^2.0.0", "mdurl": "^1.0.1", "uc.micro": "^1.0.5" @@ -3342,14 +3269,6 @@ "hash-base": "^3.0.0", "inherits": "^2.0.1", "safe-buffer": "^5.1.2" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } } }, "mdurl": { @@ -3400,14 +3319,6 @@ "read-pkg-up": "^1.0.1", "redent": "^1.0.0", "trim-newlines": "^1.0.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } } }, "micromatch": { @@ -3429,14 +3340,6 @@ "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } } }, "miller-rabin": { @@ -3450,18 +3353,18 @@ } }, "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "version": "1.42.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", + "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==", "dev": true }, "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "version": "2.1.25", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", + "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", "dev": true, "requires": { - "mime-db": "1.40.0" + "mime-db": "1.42.0" } }, "mimic-fn": { @@ -3471,15 +3374,28 @@ "dev": true }, "mini-css-extract-plugin": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.7.0.tgz", - "integrity": "sha512-RQIw6+7utTYn8DBGsf/LpRgZCJMpZt+kuawJ/fju0KiOL6nAaTBNmCJwS7HtwSCXfS47gCkmtBFS7HdsquhdxQ==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz", + "integrity": "sha512-lp3GeY7ygcgAmVIcRPBVhIkf8Us7FZjA+ILpal44qLdSu11wmjKQ3d9k15lfD7pO4esu9eUIAW7qiYIBppv40A==", "dev": true, "requires": { "loader-utils": "^1.1.0", "normalize-url": "1.9.1", "schema-utils": "^1.0.0", "webpack-sources": "^1.1.0" + }, + "dependencies": { + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } } }, "minimalistic-assert": { @@ -3504,9 +3420,9 @@ } }, "minimist": { - "version": "0.0.8", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, "mississippi": { @@ -3528,9 +3444,9 @@ } }, "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, "requires": { "for-in": "^1.0.2", @@ -3548,24 +3464,6 @@ } } }, - "mixin-object": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", - "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", - "dev": true, - "requires": { - "for-in": "^0.1.3", - "is-extendable": "^0.1.1" - }, - "dependencies": { - "for-in": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", - "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=", - "dev": true - } - } - }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", @@ -3573,6 +3471,14 @@ "dev": true, "requires": { "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } } }, "move-concurrently": { @@ -3618,20 +3524,12 @@ "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } } }, "neo-async": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz", - "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", "dev": true }, "nice-try": { @@ -3669,9 +3567,9 @@ } }, "node-libs-browser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.0.tgz", - "integrity": "sha512-5MQunG/oyOaBdttrL40dA7bUfPORLRWMUJLQtMg7nluxUvk5XwnLdL9twQHFAjRx/y7mIMkLKT9++qPbbk6BZA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", "dev": true, "requires": { "assert": "^1.1.1", @@ -3684,7 +3582,7 @@ "events": "^3.0.0", "https-browserify": "^1.0.0", "os-browserify": "^0.3.0", - "path-browserify": "0.0.0", + "path-browserify": "0.0.1", "process": "^0.11.10", "punycode": "^1.2.4", "querystring-es3": "^0.2.0", @@ -3696,13 +3594,21 @@ "tty-browserify": "0.0.0", "url": "^0.11.0", "util": "^0.11.0", - "vm-browserify": "0.0.4" + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } } }, "node-sass": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.12.0.tgz", - "integrity": "sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.0.tgz", + "integrity": "sha512-W1XBrvoJ1dy7VsvTAS5q1V45lREbTlZQqFbiHb3R3OTTCma0XBtuG6xZ6Z4506nR4lmHPTqVRwxT6KgtWC97CA==", "dev": true, "requires": { "async-foreach": "^0.1.3", @@ -3712,7 +3618,7 @@ "get-stdin": "^4.0.1", "glob": "^7.0.3", "in-publish": "^2.0.0", - "lodash": "^4.17.11", + "lodash": "^4.17.15", "meow": "^3.7.0", "mkdirp": "^0.5.1", "nan": "^2.13.2", @@ -3928,6 +3834,15 @@ "requires": { "is-descriptor": "^0.1.0" } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } } } }, @@ -3964,16 +3879,10 @@ "wrappy": "1" } }, - "options": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", - "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", - "dev": true - }, "opts": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/opts/-/opts-1.2.6.tgz", - "integrity": "sha1-0YXAQlz9652h0YKQi2W1wCOP67M=", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/opts/-/opts-1.2.7.tgz", + "integrity": "sha512-hwZhzGGG/GQ7igxAVFOEun2N4fWul31qE9nfBdCnZGQCB5+L7tN9xZ+94B4aUpLOJx/of3zZs5XsuubayQYQjA==", "dev": true }, "os-browserify": { @@ -4032,9 +3941,9 @@ "dev": true }, "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -4062,20 +3971,20 @@ "dev": true }, "parallel-transform": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", - "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", "dev": true, "requires": { - "cyclist": "~0.2.2", + "cyclist": "^1.0.1", "inherits": "^2.0.3", "readable-stream": "^2.1.5" } }, "parse-asn1": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", - "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", "dev": true, "requires": { "asn1.js": "^4.0.0", @@ -4108,9 +4017,9 @@ "dev": true }, "path-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", - "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", "dev": true }, "path-dirname": { @@ -4120,10 +4029,13 @@ "dev": true }, "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } }, "path-is-absolute": { "version": "1.0.1", @@ -4209,6 +4121,17 @@ "dev": true, "requires": { "find-up": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + } } }, "posix-character-classes": { @@ -4218,9 +4141,9 @@ "dev": true }, "postcss": { - "version": "7.0.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.16.tgz", - "integrity": "sha512-MOo8zNSlIqh22Uaa3drkdIAgUGEL+AD1ESiSdmElLUmE2uVDo1QloiT/IfW9qRw8Gw+Y/w69UVMGwbufMSftxA==", + "version": "7.0.25", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.25.tgz", + "integrity": "sha512-NXXVvWq9icrm/TgQC0O6YVFi4StfJz46M1iNd/h6B26Nvh/HKI+q4YZtFN/EjcInZliEscO/WL10BXnc1E5nwg==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -4271,20 +4194,21 @@ } }, "postcss-modules-local-by-default": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz", - "integrity": "sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.2.tgz", + "integrity": "sha512-jM/V8eqM4oJ/22j0gx4jrp63GSvDH6v86OqyTHHUvk4/k1vceipZsaymiZ5PvocqZOl5SFHiFJqjs3la0wnfIQ==", "dev": true, "requires": { - "postcss": "^7.0.6", - "postcss-selector-parser": "^6.0.0", - "postcss-value-parser": "^3.3.1" + "icss-utils": "^4.1.1", + "postcss": "^7.0.16", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.0.0" } }, "postcss-modules-scope": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz", - "integrity": "sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.1.1.tgz", + "integrity": "sha512-OXRUPecnHCg8b9xWvldG/jUpRIGPNRka0r4D4j0ESUU2/5IOnpsjfPPmDprM3Ih8CgZ8FXjWqaniK5v4rWt3oQ==", "dev": true, "requires": { "postcss": "^7.0.6", @@ -4292,12 +4216,12 @@ } }, "postcss-modules-values": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz", - "integrity": "sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", + "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", "dev": true, "requires": { - "icss-replace-symbols": "^1.1.0", + "icss-utils": "^4.0.0", "postcss": "^7.0.6" } }, @@ -4313,9 +4237,9 @@ } }, "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz", + "integrity": "sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ==", "dev": true }, "prepend-http": { @@ -4331,9 +4255,9 @@ "dev": true }, "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, "promise-inflight": { @@ -4355,9 +4279,9 @@ "dev": true }, "psl": { - "version": "1.1.32", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.32.tgz", - "integrity": "sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.6.0.tgz", + "integrity": "sha512-SYKKmVel98NCOYXpkwUqZqh0ahZeeKfmisiLIcEZdsb+WbLv02g/dI5BUmZnIyOe7RzZtLax81nnb2HbvC2tzA==", "dev": true }, "public-encrypt": { @@ -4372,14 +4296,6 @@ "parse-asn1": "^5.0.0", "randombytes": "^2.0.1", "safe-buffer": "^5.1.2" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } } }, "pump": { @@ -4416,9 +4332,9 @@ } }, "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, "qs": { @@ -4487,41 +4403,20 @@ "requires": { "find-up": "^1.0.0", "read-pkg": "^1.0.0" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - } } }, "readable-stream": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", + "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", + "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, @@ -4563,9 +4458,9 @@ "dev": true }, "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", "dev": true }, "repeat-string": { @@ -4609,14 +4504,6 @@ "tough-cookie": "~2.4.3", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } } }, "require-directory": { @@ -4648,6 +4535,19 @@ "requires": { "expand-tilde": "^2.0.0", "global-modules": "^1.0.0" + }, + "dependencies": { + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + } } }, "resolve-from": { @@ -4669,12 +4569,12 @@ "dev": true }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "ripemd160": { @@ -4697,9 +4597,9 @@ } }, "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, "safe-regex": { @@ -4730,28 +4630,34 @@ } }, "sass-loader": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.1.0.tgz", - "integrity": "sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-8.0.0.tgz", + "integrity": "sha512-+qeMu563PN7rPdit2+n5uuYVR0SSVwm0JsOUsaJXzgYcClWSlmX0iHDnmeOobPkf5kUglVot3QS6SyLyaQoJ4w==", "dev": true, "requires": { - "clone-deep": "^2.0.1", - "loader-utils": "^1.0.1", - "lodash.tail": "^4.1.1", - "neo-async": "^2.5.0", - "pify": "^3.0.0", - "semver": "^5.5.0" + "clone-deep": "^4.0.1", + "loader-utils": "^1.2.3", + "neo-async": "^2.6.1", + "schema-utils": "^2.1.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.1.tgz", + "integrity": "sha512-0WXHDs1VDJyo+Zqs9TKLKyD/h7yDpHUhEFsM2CzkICFdoX1av+GBq/J2xRTFfsQO5kBfhZzANf2VcIm84jqDbg==", "dev": true, "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1" } }, "scss-tokenizer": { @@ -4787,9 +4693,9 @@ "dev": true }, "serialize-javascript": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.7.0.tgz", - "integrity": "sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", + "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", "dev": true }, "set-blocking": { @@ -4799,9 +4705,9 @@ "dev": true }, "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -4838,22 +4744,12 @@ } }, "shallow-clone": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", - "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "dev": true, "requires": { - "is-extendable": "^0.1.1", - "kind-of": "^5.0.0", - "mixin-object": "^2.0.1" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } + "kind-of": "^6.0.2" } }, "shebang-command": { @@ -4979,12 +4875,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true } } }, @@ -4995,6 +4885,17 @@ "dev": true, "requires": { "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "sort-keys": { @@ -5007,14 +4908,14 @@ } }, "sortablejs": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.9.0.tgz", - "integrity": "sha512-Ot6bYJ6PoqPmpsqQYXjn1+RKrY2NWQvQt/o4jfd/UYwVWndyO5EPO8YHbnm5HIykf8ENsm4JUrdAvolPT86yYA==" + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.10.1.tgz", + "integrity": "sha512-N6r7GrVmO8RW1rn0cTdvK3JR0BcqecAJ0PmYMCL3ZuqTH3pY+9QyqkmJSkkLyyDvd+AJnwaxTP22Ybr/83V9hQ==" }, "source-list-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", - "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", "dev": true }, "source-map": { @@ -5037,9 +4938,9 @@ } }, "source-map-support": { - "version": "0.5.12", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", - "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -5185,44 +5086,12 @@ "readable-stream": "^2.3.6", "to-arraybuffer": "^1.0.0", "xtend": "^4.0.0" - }, - "dependencies": { - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } } }, "stream-shift": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", "dev": true }, "strict-uri-encode": { @@ -5254,9 +5123,9 @@ } }, "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -5296,13 +5165,13 @@ } }, "style-loader": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", - "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.1.1.tgz", + "integrity": "sha512-oIVF12trRq0od4Yojg7q0K3Lq/O6Ix/AYgVosykrVg+kWxxxUyk8KhKCCmekyGSUiVK1xxlAQymLWWdh6S9lOg==", "dev": true, "requires": { - "loader-utils": "^1.1.0", - "schema-utils": "^1.0.0" + "loader-utils": "^1.2.3", + "schema-utils": "^2.0.1" } }, "supports-color": { @@ -5332,65 +5201,43 @@ } }, "terser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.0.0.tgz", - "integrity": "sha512-dOapGTU0hETFl1tCo4t56FN+2jffoKyER9qBGoUFyZ6y7WLoKT0bF+lAYi6B6YsILcGF3q1C2FBh8QcKSCgkgA==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.4.3.tgz", + "integrity": "sha512-0ikKraVtRDKGzHrzkCv5rUNDzqlhmhowOBqC0XqUHFpW+vJ45+20/IFBcebwKfiS2Z9fJin6Eo+F1zLZsxi8RA==", "dev": true, "requires": { - "commander": "^2.19.0", + "commander": "^2.20.0", "source-map": "~0.6.1", - "source-map-support": "~0.5.10" + "source-map-support": "~0.5.12" } }, "terser-webpack-plugin": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.3.0.tgz", - "integrity": "sha512-W2YWmxPjjkUcOWa4pBEv4OP4er1aeQJlSo2UhtCFQCuRXEHjOFscO8VyWHj9JLlA0RzQb8Y2/Ta78XZvT54uGg==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz", + "integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==", "dev": true, "requires": { - "cacache": "^11.3.2", - "find-cache-dir": "^2.0.0", + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", "is-wsl": "^1.1.0", - "loader-utils": "^1.2.3", "schema-utils": "^1.0.0", - "serialize-javascript": "^1.7.0", + "serialize-javascript": "^2.1.2", "source-map": "^0.6.1", - "terser": "^4.0.0", - "webpack-sources": "^1.3.0", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", "worker-farm": "^1.7.0" }, "dependencies": { - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true - }, - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "dev": true, "requires": { - "minimist": "^1.2.0" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" } - }, - "loader-utils": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", - "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^2.0.0", - "json5": "^1.0.1" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true } } }, @@ -5402,44 +5249,12 @@ "requires": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" - }, - "dependencies": { - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } } }, "timers-browserify": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", - "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", + "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", "dev": true, "requires": { "setimmediate": "^1.0.4" @@ -5463,6 +5278,17 @@ "dev": true, "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "to-regex": { @@ -5495,6 +5321,14 @@ "requires": { "psl": "^1.1.24", "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } } }, "trim-newlines": { @@ -5513,9 +5347,9 @@ } }, "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", "dev": true }, "tty-browserify": { @@ -5546,49 +5380,20 @@ "dev": true }, "uc.micro": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.5.tgz", - "integrity": "sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg==" - }, - "ultron": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", - "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=", - "dev": true + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" }, "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } + "set-value": "^2.0.1" } }, "uniq": { @@ -5607,9 +5412,9 @@ } }, "unique-slug": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.1.tgz", - "integrity": "sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", "dev": true, "requires": { "imurmurhash": "^0.1.4" @@ -5656,9 +5461,9 @@ } }, "upath": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", - "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", "dev": true }, "uri-js": { @@ -5668,14 +5473,6 @@ "dev": true, "requires": { "punycode": "^2.1.0" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - } } }, "urix": { @@ -5715,6 +5512,14 @@ "dev": true, "requires": { "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } } }, "util-deprecate": { @@ -5724,9 +5529,9 @@ "dev": true }, "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", "dev": true }, "v8-compile-cache": { @@ -5757,25 +5562,22 @@ } }, "vm-browserify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", - "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", - "dev": true, - "requires": { - "indexof": "0.0.1" - } + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true }, "vue": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.10.tgz", - "integrity": "sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==" + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.11.tgz", + "integrity": "sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ==" }, "vuedraggable": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-2.21.0.tgz", - "integrity": "sha512-UDp0epjaZikuInoJA9rlEIJaSTQThabq0R9x7TqBdl0qGVFKKzo6glP6ubfzWBmV4iRIfbSOs2DV06s3B5h5tA==", + "version": "2.23.2", + "resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-2.23.2.tgz", + "integrity": "sha512-PgHCjUpxEAEZJq36ys49HfQmXglattf/7ofOzUrW2/rRdG7tu6fK84ir14t1jYv4kdXewTEa2ieKEAhhEMdwkQ==", "requires": { - "sortablejs": "^1.9.0" + "sortablejs": "^1.10.1" } }, "watchpack": { @@ -5787,140 +5589,108 @@ "chokidar": "^2.0.2", "graceful-fs": "^4.1.2", "neo-async": "^2.5.0" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } } }, "webpack": { - "version": "4.32.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.32.2.tgz", - "integrity": "sha512-F+H2Aa1TprTQrpodRAWUMJn7A8MgDx82yQiNvYMaj3d1nv3HetKU0oqEulL9huj8enirKi8KvEXQ3QtuHF89Zg==", + "version": "4.41.4", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.4.tgz", + "integrity": "sha512-Lc+2uB6NjpCWsHI3trkoISOI64h9QYIXenbEWj3bn3oyjfB1lEBXjWAfAyY2sM0rZn41oD5V91OLwKRwS6Wp8Q==", "dev": true, "requires": { "@webassemblyjs/ast": "1.8.5", "@webassemblyjs/helper-module-context": "1.8.5", "@webassemblyjs/wasm-edit": "1.8.5", "@webassemblyjs/wasm-parser": "1.8.5", - "acorn": "^6.0.5", - "acorn-dynamic-import": "^4.0.0", - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0", - "chrome-trace-event": "^1.0.0", + "acorn": "^6.2.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^4.1.0", - "eslint-scope": "^4.0.0", + "eslint-scope": "^4.0.3", "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.3.0", - "loader-utils": "^1.1.0", - "memory-fs": "~0.4.1", - "micromatch": "^3.1.8", - "mkdirp": "~0.5.0", - "neo-async": "^2.5.0", - "node-libs-browser": "^2.0.0", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.1", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", "schema-utils": "^1.0.0", - "tapable": "^1.1.0", - "terser-webpack-plugin": "^1.1.0", - "watchpack": "^1.5.0", - "webpack-sources": "^1.3.0" + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.6.0", + "webpack-sources": "^1.4.1" }, "dependencies": { - "is-accessor-descriptor": { + "schema-utils": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, "requires": { - "kind-of": "^6.0.0" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, "webpack-cli": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.2.tgz", - "integrity": "sha512-FLkobnaJJ+03j5eplxlI0TUxhGCOdfewspIGuvDVtpOlrAuKMFC57K42Ukxqs1tn8947/PM6tP95gQc0DCzRYA==", + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.10.tgz", + "integrity": "sha512-u1dgND9+MXaEt74sJR4PR7qkPxXUSQ0RXYq8x1L6Jg1MYVEmGPrH6Ah6C4arD4r0J1P5HKjRqpab36k0eIzPqg==", "dev": true, "requires": { - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "enhanced-resolve": "^4.1.0", - "findup-sync": "^2.0.0", - "global-modules": "^1.0.0", - "import-local": "^2.0.0", - "interpret": "^1.1.0", - "loader-utils": "^1.1.0", - "supports-color": "^5.5.0", - "v8-compile-cache": "^2.0.2", - "yargs": "^12.0.5" + "chalk": "2.4.2", + "cross-spawn": "6.0.5", + "enhanced-resolve": "4.1.0", + "findup-sync": "3.0.0", + "global-modules": "2.0.0", + "import-local": "2.0.0", + "interpret": "1.2.0", + "loader-utils": "1.2.3", + "supports-color": "6.1.0", + "v8-compile-cache": "2.0.3", + "yargs": "13.2.4" }, "dependencies": { "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" } }, "cross-spawn": { @@ -5936,6 +5706,32 @@ "which": "^1.2.9" } }, + "enhanced-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", + "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "tapable": "^1.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, "invert-kv": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", @@ -5968,23 +5764,39 @@ "mem": "^4.0.0" } }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { + "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "strip-ansi": "^5.1.0" } }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" } }, "which-module": { @@ -5993,30 +5805,46 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, - "yargs": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "dev": true, "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yargs": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", + "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==", + "dev": true, + "requires": { + "cliui": "^5.0.0", "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", + "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", - "string-width": "^2.0.0", + "string-width": "^3.0.0", "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" + "y18n": "^4.0.0", + "yargs-parser": "^13.1.0" } }, "yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", "dev": true, "requires": { "camelcase": "^5.0.0", @@ -6026,9 +5854,9 @@ } }, "webpack-sources": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz", - "integrity": "sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", "dev": true, "requires": { "source-list-map": "^2.0.0", @@ -6085,19 +5913,18 @@ "dev": true }, "ws": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", - "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", "dev": true, "requires": { - "options": ">=0.0.5", - "ultron": "1.0.x" + "async-limiter": "~1.0.0" } }, "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "dev": true }, "y18n": { diff --git a/package.json b/package.json index 0d1afbb0c..8877cb9e8 100644 --- a/package.json +++ b/package.json @@ -10,25 +10,25 @@ "permissions": "chown -R $USER:$USER bootstrap/cache storage public/uploads" }, "devDependencies": { - "css-loader": "^2.1.1", - "livereload": "^0.8.0", - "mini-css-extract-plugin": "^0.7.0", - "node-sass": "^4.12.0", + "css-loader": "^3.4.0", + "livereload": "^0.8.2", + "mini-css-extract-plugin": "^0.9.0", + "node-sass": "^4.13.0", "npm-run-all": "^4.1.5", - "sass-loader": "^7.1.0", - "style-loader": "^0.23.1", - "webpack": "^4.32.2", - "webpack-cli": "^3.3.2" + "sass-loader": "^8.0.0", + "style-loader": "^1.1.1", + "webpack": "^4.41.4", + "webpack-cli": "^3.3.10" }, "dependencies": { "clipboard": "^2.0.4", - "codemirror": "^5.47.0", + "codemirror": "^5.50.0", "dropzone": "^5.5.1", - "markdown-it": "^8.4.2", + "markdown-it": "^10.0.0", "markdown-it-task-lists": "^2.1.1", - "sortablejs": "^1.9.0", - "vue": "^2.6.10", - "vuedraggable": "^2.21.0" + "sortablejs": "^1.10.1", + "vue": "^2.6.11", + "vuedraggable": "^2.23.2" }, "browser": { "vue": "vue/dist/vue.common.js" diff --git a/phpunit.xml b/phpunit.xml index 53722a71b..85538c446 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -7,8 +7,7 @@ convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" - stopOnFailure="false" - syntaxCheck="false"> + stopOnFailure="false"> ./tests/ @@ -20,32 +19,37 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/web.config b/public/web.config new file mode 100644 index 000000000..474eb6898 --- /dev/null +++ b/public/web.config @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/readme.md b/readme.md index 2efc6b160..fb26cede3 100644 --- a/readme.md +++ b/readme.md @@ -2,7 +2,7 @@ [![GitHub release](https://img.shields.io/github/release/BookStackApp/BookStack.svg)](https://github.com/BookStackApp/BookStack/releases/latest) [![license](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/BookStackApp/BookStack/blob/master/LICENSE) -[![Build Status](https://travis-ci.org/BookStackApp/BookStack.svg)](https://travis-ci.org/BookStackApp/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) A platform for storing and organising information and documentation. General information and documentation for BookStack can be found at https://www.bookstackapp.com/. @@ -107,22 +107,11 @@ The docker-compose setup runs an instance of [MailHog](https://github.com/mailho ## 🌎 Translations -All text strings can be found in the `resources/lang` folder where each language option has its own folder. To add a new language you should copy the `en` folder to an new folder (eg. `fr` for french) then go through and translate all text strings in those files, leaving the keys and file-names intact. If a language string is missing then the `en` translation will be used. To show the language option in the user preferences language drop-down you will need to add your language to the options found at the bottom of the `resources/lang/en/settings.php` file. A system-wide language can also be set in the `.env` file like so: `APP_LANG=en`. +Translations for text within BookStack is managed through the [BookStack project on Crowdin](https://crowdin.com/project/bookstack). Some strings have colon-prefixed variables in such as `:userName`. Leave these values as they are as they will be replaced at run-time. Crowdin is the preferred way to provide translations, otherwise the raw translations files can be found within the `resources/lang` path. -You will also need to add the language to the `locales` array in the `config/app.php` file. +If you'd like a new language to be added to Crowdin, for you to be able to provide translations for, please [open a new issue here](https://github.com/BookStackApp/BookStack/issues/new?template=language_request.md). -There is a script available which compares translation content to `en` files to see what items are missing or redundant. This can be ran like so from your BookStack install folder: - -```bash -# Syntax -php resources/lang/check.php - -# Examples -php resources/lang/check.php fr -php resources/lang/check.php pt_BR -``` - -Some strings have colon-prefixed variables in such as `:userName`. Leave these values as they are as they will be replaced at run-time. +Please note, translations in BookStack are provided to the "Crowdin Global Translation Memory" which helps BookStack and other projects with finding translations. If you are not happy with contributing to this then providing translations to BookStack, even manually via GitHub, is not advised. ## 🎁 Contributing, Issues & Pull Requests @@ -156,6 +145,8 @@ The BookStack source is provided under the MIT License. The libraries used by, a The great people that have worked to build and improve BookStack can [be seen here](https://github.com/BookStackApp/BookStack/graphs/contributors). +The wonderful people that have provided translations, either through GitHub or via Crowdin [can be seen here](https://github.com/BookStackApp/BookStack/blob/master/.github/translators.txt). + These are the great open-source projects used to help build BookStack: * [Laravel](http://laravel.com/) @@ -174,3 +165,5 @@ These are the great open-source projects used to help build BookStack: * [Laravel IDE helper](https://github.com/barryvdh/laravel-ide-helper) * [WKHTMLtoPDF](http://wkhtmltopdf.org/index.html) * [Draw.io](https://github.com/jgraph/drawio) +* [Laravel Stats](https://github.com/stefanzweifel/laravel-stats) +* [OneLogin's SAML PHP Toolkit](https://github.com/onelogin/php-saml) \ No newline at end of file diff --git a/resources/assets/js/components/overlay.js b/resources/assets/js/components/overlay.js deleted file mode 100644 index ad6a01061..000000000 --- a/resources/assets/js/components/overlay.js +++ /dev/null @@ -1,56 +0,0 @@ - -class Overlay { - - constructor(elem) { - this.container = elem; - elem.addEventListener('click', event => { - if (event.target === elem) return this.hide(); - }); - - window.addEventListener('keyup', event => { - if (event.key === 'Escape') { - this.hide(); - } - }); - - let closeButtons = elem.querySelectorAll('.popup-header-close'); - for (let i=0; i < closeButtons.length; i++) { - closeButtons[i].addEventListener('click', this.hide.bind(this)); - } - } - - hide() { this.toggle(false); } - show() { this.toggle(true); } - - toggle(show = true) { - let start = Date.now(); - let duration = 240; - - function setOpacity() { - let elapsedTime = (Date.now() - start); - let targetOpacity = show ? (elapsedTime / duration) : 1-(elapsedTime / duration); - this.container.style.opacity = targetOpacity; - if (elapsedTime > duration) { - this.container.style.display = show ? 'flex' : 'none'; - if (show) { - this.focusOnBody(); - } - this.container.style.opacity = ''; - } else { - requestAnimationFrame(setOpacity.bind(this)); - } - } - - requestAnimationFrame(setOpacity.bind(this)); - } - - focusOnBody() { - const body = this.container.querySelector('.popup-body'); - if (body) { - body.focus(); - } - } - -} - -export default Overlay; \ No newline at end of file diff --git a/resources/assets/js/services/events.js b/resources/assets/js/services/events.js deleted file mode 100644 index 1f97d0cb8..000000000 --- a/resources/assets/js/services/events.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Simple global events manager - */ -class Events { - constructor() { - this.listeners = {}; - this.stack = []; - } - - emit(eventName, eventData) { - this.stack.push({name: eventName, data: eventData}); - if (typeof this.listeners[eventName] === 'undefined') return this; - let eventsToStart = this.listeners[eventName]; - for (let i = 0; i < eventsToStart.length; i++) { - let event = eventsToStart[i]; - event(eventData); - } - return this; - } - - listen(eventName, callback) { - if (typeof this.listeners[eventName] === 'undefined') this.listeners[eventName] = []; - this.listeners[eventName].push(callback); - return this; - } -} - -export default Events; \ No newline at end of file diff --git a/resources/assets/icons/add-circle.svg b/resources/icons/add-circle.svg similarity index 100% rename from resources/assets/icons/add-circle.svg rename to resources/icons/add-circle.svg diff --git a/resources/assets/icons/add.svg b/resources/icons/add.svg similarity index 100% rename from resources/assets/icons/add.svg rename to resources/icons/add.svg diff --git a/resources/assets/icons/attach.svg b/resources/icons/attach.svg similarity index 100% rename from resources/assets/icons/attach.svg rename to resources/icons/attach.svg diff --git a/resources/assets/icons/auth/azure.svg b/resources/icons/auth/azure.svg similarity index 100% rename from resources/assets/icons/auth/azure.svg rename to resources/icons/auth/azure.svg diff --git a/resources/assets/icons/auth/discord.svg b/resources/icons/auth/discord.svg similarity index 100% rename from resources/assets/icons/auth/discord.svg rename to resources/icons/auth/discord.svg diff --git a/resources/assets/icons/auth/facebook.svg b/resources/icons/auth/facebook.svg similarity index 100% rename from resources/assets/icons/auth/facebook.svg rename to resources/icons/auth/facebook.svg diff --git a/resources/assets/icons/auth/github.svg b/resources/icons/auth/github.svg similarity index 100% rename from resources/assets/icons/auth/github.svg rename to resources/icons/auth/github.svg diff --git a/resources/assets/icons/auth/gitlab.svg b/resources/icons/auth/gitlab.svg similarity index 100% rename from resources/assets/icons/auth/gitlab.svg rename to resources/icons/auth/gitlab.svg diff --git a/resources/assets/icons/auth/google.svg b/resources/icons/auth/google.svg similarity index 100% rename from resources/assets/icons/auth/google.svg rename to resources/icons/auth/google.svg diff --git a/resources/assets/icons/auth/okta.svg b/resources/icons/auth/okta.svg similarity index 100% rename from resources/assets/icons/auth/okta.svg rename to resources/icons/auth/okta.svg diff --git a/resources/assets/icons/auth/slack.svg b/resources/icons/auth/slack.svg similarity index 100% rename from resources/assets/icons/auth/slack.svg rename to resources/icons/auth/slack.svg diff --git a/resources/assets/icons/auth/twitch.svg b/resources/icons/auth/twitch.svg similarity index 100% rename from resources/assets/icons/auth/twitch.svg rename to resources/icons/auth/twitch.svg diff --git a/resources/assets/icons/auth/twitter.svg b/resources/icons/auth/twitter.svg similarity index 100% rename from resources/assets/icons/auth/twitter.svg rename to resources/icons/auth/twitter.svg diff --git a/resources/assets/icons/back.svg b/resources/icons/back.svg similarity index 100% rename from resources/assets/icons/back.svg rename to resources/icons/back.svg diff --git a/resources/assets/icons/book.svg b/resources/icons/book.svg similarity index 100% rename from resources/assets/icons/book.svg rename to resources/icons/book.svg diff --git a/resources/assets/icons/books.svg b/resources/icons/books.svg similarity index 100% rename from resources/assets/icons/books.svg rename to resources/icons/books.svg diff --git a/resources/assets/icons/bookshelf.svg b/resources/icons/bookshelf.svg similarity index 100% rename from resources/assets/icons/bookshelf.svg rename to resources/icons/bookshelf.svg diff --git a/resources/assets/icons/cancel.svg b/resources/icons/cancel.svg similarity index 100% rename from resources/assets/icons/cancel.svg rename to resources/icons/cancel.svg diff --git a/resources/assets/icons/caret-down.svg b/resources/icons/caret-down.svg similarity index 100% rename from resources/assets/icons/caret-down.svg rename to resources/icons/caret-down.svg diff --git a/resources/assets/icons/caret-left-circle.svg b/resources/icons/caret-left-circle.svg similarity index 100% rename from resources/assets/icons/caret-left-circle.svg rename to resources/icons/caret-left-circle.svg diff --git a/resources/assets/icons/caret-right-circle.svg b/resources/icons/caret-right-circle.svg similarity index 100% rename from resources/assets/icons/caret-right-circle.svg rename to resources/icons/caret-right-circle.svg diff --git a/resources/assets/icons/caret-right.svg b/resources/icons/caret-right.svg similarity index 100% rename from resources/assets/icons/caret-right.svg rename to resources/icons/caret-right.svg diff --git a/resources/assets/icons/chapter.svg b/resources/icons/chapter.svg similarity index 100% rename from resources/assets/icons/chapter.svg rename to resources/icons/chapter.svg diff --git a/resources/assets/icons/check-circle.svg b/resources/icons/check-circle.svg similarity index 100% rename from resources/assets/icons/check-circle.svg rename to resources/icons/check-circle.svg diff --git a/resources/assets/icons/check.svg b/resources/icons/check.svg similarity index 100% rename from resources/assets/icons/check.svg rename to resources/icons/check.svg diff --git a/resources/assets/icons/chevron-down.svg b/resources/icons/chevron-down.svg similarity index 100% rename from resources/assets/icons/chevron-down.svg rename to resources/icons/chevron-down.svg diff --git a/resources/assets/icons/chevron-right.svg b/resources/icons/chevron-right.svg similarity index 100% rename from resources/assets/icons/chevron-right.svg rename to resources/icons/chevron-right.svg diff --git a/resources/assets/icons/chevron-up.svg b/resources/icons/chevron-up.svg similarity index 100% rename from resources/assets/icons/chevron-up.svg rename to resources/icons/chevron-up.svg diff --git a/resources/assets/icons/close.svg b/resources/icons/close.svg similarity index 100% rename from resources/assets/icons/close.svg rename to resources/icons/close.svg diff --git a/resources/assets/icons/comment.svg b/resources/icons/comment.svg similarity index 100% rename from resources/assets/icons/comment.svg rename to resources/icons/comment.svg diff --git a/resources/assets/icons/copy.svg b/resources/icons/copy.svg similarity index 100% rename from resources/assets/icons/copy.svg rename to resources/icons/copy.svg diff --git a/resources/assets/icons/danger.svg b/resources/icons/danger.svg similarity index 100% rename from resources/assets/icons/danger.svg rename to resources/icons/danger.svg diff --git a/resources/assets/icons/delete.svg b/resources/icons/delete.svg similarity index 100% rename from resources/assets/icons/delete.svg rename to resources/icons/delete.svg diff --git a/resources/assets/icons/drawing.svg b/resources/icons/drawing.svg similarity index 100% rename from resources/assets/icons/drawing.svg rename to resources/icons/drawing.svg diff --git a/resources/assets/icons/edit.svg b/resources/icons/edit.svg similarity index 100% rename from resources/assets/icons/edit.svg rename to resources/icons/edit.svg diff --git a/resources/assets/icons/expand-text.svg b/resources/icons/expand-text.svg similarity index 100% rename from resources/assets/icons/expand-text.svg rename to resources/icons/expand-text.svg diff --git a/resources/assets/icons/export.svg b/resources/icons/export.svg similarity index 100% rename from resources/assets/icons/export.svg rename to resources/icons/export.svg diff --git a/resources/assets/icons/file.svg b/resources/icons/file.svg similarity index 100% rename from resources/assets/icons/file.svg rename to resources/icons/file.svg diff --git a/resources/assets/icons/folder.svg b/resources/icons/folder.svg similarity index 100% rename from resources/assets/icons/folder.svg rename to resources/icons/folder.svg diff --git a/resources/icons/fullscreen.svg b/resources/icons/fullscreen.svg new file mode 100644 index 000000000..d00b574ff --- /dev/null +++ b/resources/icons/fullscreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/assets/icons/grid.svg b/resources/icons/grid.svg similarity index 100% rename from resources/assets/icons/grid.svg rename to resources/icons/grid.svg diff --git a/resources/assets/icons/grip.svg b/resources/icons/grip.svg similarity index 100% rename from resources/assets/icons/grip.svg rename to resources/icons/grip.svg diff --git a/resources/assets/icons/history.svg b/resources/icons/history.svg similarity index 100% rename from resources/assets/icons/history.svg rename to resources/icons/history.svg diff --git a/resources/assets/icons/image.svg b/resources/icons/image.svg similarity index 100% rename from resources/assets/icons/image.svg rename to resources/icons/image.svg diff --git a/resources/assets/icons/images.svg b/resources/icons/images.svg similarity index 100% rename from resources/assets/icons/images.svg rename to resources/icons/images.svg diff --git a/resources/assets/icons/include.svg b/resources/icons/include.svg similarity index 100% rename from resources/assets/icons/include.svg rename to resources/icons/include.svg diff --git a/resources/assets/icons/info-filled.svg b/resources/icons/info-filled.svg similarity index 100% rename from resources/assets/icons/info-filled.svg rename to resources/icons/info-filled.svg diff --git a/resources/assets/icons/info.svg b/resources/icons/info.svg similarity index 100% rename from resources/assets/icons/info.svg rename to resources/icons/info.svg diff --git a/resources/assets/icons/link.svg b/resources/icons/link.svg similarity index 100% rename from resources/assets/icons/link.svg rename to resources/icons/link.svg diff --git a/resources/assets/icons/list.svg b/resources/icons/list.svg similarity index 100% rename from resources/assets/icons/list.svg rename to resources/icons/list.svg diff --git a/resources/assets/icons/lock-open.svg b/resources/icons/lock-open.svg similarity index 100% rename from resources/assets/icons/lock-open.svg rename to resources/icons/lock-open.svg diff --git a/resources/assets/icons/lock.svg b/resources/icons/lock.svg similarity index 100% rename from resources/assets/icons/lock.svg rename to resources/icons/lock.svg diff --git a/resources/assets/icons/login.svg b/resources/icons/login.svg similarity index 100% rename from resources/assets/icons/login.svg rename to resources/icons/login.svg diff --git a/resources/assets/icons/logout.svg b/resources/icons/logout.svg similarity index 100% rename from resources/assets/icons/logout.svg rename to resources/icons/logout.svg diff --git a/resources/assets/icons/more.svg b/resources/icons/more.svg similarity index 100% rename from resources/assets/icons/more.svg rename to resources/icons/more.svg diff --git a/resources/assets/icons/new-user.svg b/resources/icons/new-user.svg similarity index 100% rename from resources/assets/icons/new-user.svg rename to resources/icons/new-user.svg diff --git a/resources/assets/icons/open-book.svg b/resources/icons/open-book.svg similarity index 100% rename from resources/assets/icons/open-book.svg rename to resources/icons/open-book.svg diff --git a/resources/assets/icons/page.svg b/resources/icons/page.svg similarity index 100% rename from resources/assets/icons/page.svg rename to resources/icons/page.svg diff --git a/resources/assets/icons/permission.svg b/resources/icons/permission.svg similarity index 100% rename from resources/assets/icons/permission.svg rename to resources/icons/permission.svg diff --git a/resources/assets/icons/popular.svg b/resources/icons/popular.svg similarity index 100% rename from resources/assets/icons/popular.svg rename to resources/icons/popular.svg diff --git a/resources/assets/icons/reply.svg b/resources/icons/reply.svg similarity index 100% rename from resources/assets/icons/reply.svg rename to resources/icons/reply.svg diff --git a/resources/icons/saml2.svg b/resources/icons/saml2.svg new file mode 100644 index 000000000..a9a2994a7 --- /dev/null +++ b/resources/icons/saml2.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/resources/assets/icons/save.svg b/resources/icons/save.svg similarity index 100% rename from resources/assets/icons/save.svg rename to resources/icons/save.svg diff --git a/resources/assets/icons/search.svg b/resources/icons/search.svg similarity index 100% rename from resources/assets/icons/search.svg rename to resources/icons/search.svg diff --git a/resources/assets/icons/settings.svg b/resources/icons/settings.svg similarity index 100% rename from resources/assets/icons/settings.svg rename to resources/icons/settings.svg diff --git a/resources/assets/icons/sort-down.svg b/resources/icons/sort-down.svg similarity index 100% rename from resources/assets/icons/sort-down.svg rename to resources/icons/sort-down.svg diff --git a/resources/assets/icons/sort-up.svg b/resources/icons/sort-up.svg similarity index 100% rename from resources/assets/icons/sort-up.svg rename to resources/icons/sort-up.svg diff --git a/resources/assets/icons/sort.svg b/resources/icons/sort.svg similarity index 100% rename from resources/assets/icons/sort.svg rename to resources/icons/sort.svg diff --git a/resources/assets/icons/spanner.svg b/resources/icons/spanner.svg similarity index 100% rename from resources/assets/icons/spanner.svg rename to resources/icons/spanner.svg diff --git a/resources/assets/icons/star-circle.svg b/resources/icons/star-circle.svg similarity index 100% rename from resources/assets/icons/star-circle.svg rename to resources/icons/star-circle.svg diff --git a/resources/assets/icons/star.svg b/resources/icons/star.svg similarity index 100% rename from resources/assets/icons/star.svg rename to resources/icons/star.svg diff --git a/resources/assets/icons/swap-vertical.svg b/resources/icons/swap-vertical.svg similarity index 100% rename from resources/assets/icons/swap-vertical.svg rename to resources/icons/swap-vertical.svg diff --git a/resources/assets/icons/tag.svg b/resources/icons/tag.svg similarity index 100% rename from resources/assets/icons/tag.svg rename to resources/icons/tag.svg diff --git a/resources/assets/icons/template.svg b/resources/icons/template.svg similarity index 100% rename from resources/assets/icons/template.svg rename to resources/icons/template.svg diff --git a/resources/assets/icons/time.svg b/resources/icons/time.svg similarity index 100% rename from resources/assets/icons/time.svg rename to resources/icons/time.svg diff --git a/resources/assets/icons/user.svg b/resources/icons/user.svg similarity index 100% rename from resources/assets/icons/user.svg rename to resources/icons/user.svg diff --git a/resources/assets/icons/users-add.svg b/resources/icons/users-add.svg similarity index 100% rename from resources/assets/icons/users-add.svg rename to resources/icons/users-add.svg diff --git a/resources/assets/icons/users.svg b/resources/icons/users.svg similarity index 100% rename from resources/assets/icons/users.svg rename to resources/icons/users.svg diff --git a/resources/assets/icons/view.svg b/resources/icons/view.svg similarity index 100% rename from resources/assets/icons/view.svg rename to resources/icons/view.svg diff --git a/resources/assets/icons/warning.svg b/resources/icons/warning.svg similarity index 100% rename from resources/assets/icons/warning.svg rename to resources/icons/warning.svg diff --git a/resources/assets/js/components/back-to-top.js b/resources/js/components/back-to-top.js similarity index 100% rename from resources/assets/js/components/back-to-top.js rename to resources/js/components/back-to-top.js diff --git a/resources/assets/js/components/book-sort.js b/resources/js/components/book-sort.js similarity index 100% rename from resources/assets/js/components/book-sort.js rename to resources/js/components/book-sort.js diff --git a/resources/assets/js/components/breadcrumb-listing.js b/resources/js/components/breadcrumb-listing.js similarity index 100% rename from resources/assets/js/components/breadcrumb-listing.js rename to resources/js/components/breadcrumb-listing.js diff --git a/resources/assets/js/components/chapter-toggle.js b/resources/js/components/chapter-toggle.js similarity index 100% rename from resources/assets/js/components/chapter-toggle.js rename to resources/js/components/chapter-toggle.js diff --git a/resources/js/components/code-highlighter.js b/resources/js/components/code-highlighter.js new file mode 100644 index 000000000..db6112887 --- /dev/null +++ b/resources/js/components/code-highlighter.js @@ -0,0 +1,10 @@ +import Code from "../services/code" +class CodeHighlighter { + + constructor(elem) { + Code.highlightWithin(elem); + } + +} + +export default CodeHighlighter; \ No newline at end of file diff --git a/resources/assets/js/components/collapsible.js b/resources/js/components/collapsible.js similarity index 81% rename from resources/assets/js/components/collapsible.js rename to resources/js/components/collapsible.js index 464f394c1..a630f38f2 100644 --- a/resources/assets/js/components/collapsible.js +++ b/resources/js/components/collapsible.js @@ -12,8 +12,8 @@ class Collapsible { this.content = elem.querySelector('[collapsible-content]'); if (!this.trigger) return; - this.trigger.addEventListener('click', this.toggle.bind(this)); + this.openIfContainsError(); } open() { @@ -36,6 +36,13 @@ class Collapsible { } } + openIfContainsError() { + const error = this.content.querySelector('.text-neg'); + if (error) { + this.open(); + } + } + } export default Collapsible; \ No newline at end of file diff --git a/resources/assets/js/components/custom-checkbox.js b/resources/js/components/custom-checkbox.js similarity index 100% rename from resources/assets/js/components/custom-checkbox.js rename to resources/js/components/custom-checkbox.js diff --git a/resources/js/components/details-highlighter.js b/resources/js/components/details-highlighter.js new file mode 100644 index 000000000..18c5165fa --- /dev/null +++ b/resources/js/components/details-highlighter.js @@ -0,0 +1,18 @@ +import Code from "../services/code" +class DetailsHighlighter { + + constructor(elem) { + this.elem = elem; + this.dealtWith = false; + elem.addEventListener('toggle', this.onToggle.bind(this)); + } + + onToggle() { + if (this.dealtWith) return; + + Code.highlightWithin(this.elem); + this.dealtWith = true; + } +} + +export default DetailsHighlighter; \ No newline at end of file diff --git a/resources/assets/js/components/dropdown.js b/resources/js/components/dropdown.js similarity index 100% rename from resources/assets/js/components/dropdown.js rename to resources/js/components/dropdown.js diff --git a/resources/assets/js/components/editor-toolbox.js b/resources/js/components/editor-toolbox.js similarity index 100% rename from resources/assets/js/components/editor-toolbox.js rename to resources/js/components/editor-toolbox.js diff --git a/resources/assets/js/components/entity-permissions-editor.js b/resources/js/components/entity-permissions-editor.js similarity index 100% rename from resources/assets/js/components/entity-permissions-editor.js rename to resources/js/components/entity-permissions-editor.js diff --git a/resources/assets/js/components/entity-selector-popup.js b/resources/js/components/entity-selector-popup.js similarity index 100% rename from resources/assets/js/components/entity-selector-popup.js rename to resources/js/components/entity-selector-popup.js diff --git a/resources/assets/js/components/entity-selector.js b/resources/js/components/entity-selector.js similarity index 100% rename from resources/assets/js/components/entity-selector.js rename to resources/js/components/entity-selector.js diff --git a/resources/assets/js/components/expand-toggle.js b/resources/js/components/expand-toggle.js similarity index 100% rename from resources/assets/js/components/expand-toggle.js rename to resources/js/components/expand-toggle.js diff --git a/resources/assets/js/components/header-mobile-toggle.js b/resources/js/components/header-mobile-toggle.js similarity index 100% rename from resources/assets/js/components/header-mobile-toggle.js rename to resources/js/components/header-mobile-toggle.js diff --git a/resources/assets/js/components/homepage-control.js b/resources/js/components/homepage-control.js similarity index 100% rename from resources/assets/js/components/homepage-control.js rename to resources/js/components/homepage-control.js diff --git a/resources/assets/js/components/image-picker.js b/resources/js/components/image-picker.js similarity index 100% rename from resources/assets/js/components/image-picker.js rename to resources/js/components/image-picker.js diff --git a/resources/assets/js/components/index.js b/resources/js/components/index.js similarity index 92% rename from resources/assets/js/components/index.js rename to resources/js/components/index.js index 14cf08ae2..112827330 100644 --- a/resources/assets/js/components/index.js +++ b/resources/js/components/index.js @@ -26,9 +26,12 @@ import permissionsTable from "./permissions-table"; import customCheckbox from "./custom-checkbox"; import bookSort from "./book-sort"; import settingAppColorPicker from "./setting-app-color-picker"; +import settingColorPicker from "./setting-color-picker"; import entityPermissionsEditor from "./entity-permissions-editor"; import templateManager from "./template-manager"; import newUserPassword from "./new-user-password"; +import detailsHighlighter from "./details-highlighter"; +import codeHighlighter from "./code-highlighter"; const componentMapping = { 'dropdown': dropdown, @@ -59,9 +62,12 @@ const componentMapping = { 'custom-checkbox': customCheckbox, 'book-sort': bookSort, 'setting-app-color-picker': settingAppColorPicker, + 'setting-color-picker': settingColorPicker, 'entity-permissions-editor': entityPermissionsEditor, 'template-manager': templateManager, 'new-user-password': newUserPassword, + 'details-highlighter': detailsHighlighter, + 'code-highlighter': codeHighlighter, }; window.components = {}; diff --git a/resources/assets/js/components/list-sort-control.js b/resources/js/components/list-sort-control.js similarity index 100% rename from resources/assets/js/components/list-sort-control.js rename to resources/js/components/list-sort-control.js diff --git a/resources/assets/js/components/markdown-editor.js b/resources/js/components/markdown-editor.js similarity index 94% rename from resources/assets/js/components/markdown-editor.js rename to resources/js/components/markdown-editor.js index c89a7ad8b..25d6bde47 100644 --- a/resources/assets/js/components/markdown-editor.js +++ b/resources/js/components/markdown-editor.js @@ -1,6 +1,7 @@ import MarkdownIt from "markdown-it"; import mdTasksLists from 'markdown-it-task-lists'; import code from '../services/code'; +import Clipboard from "../services/clipboard"; import {debounce} from "../services/util"; import DrawIO from "../services/drawio"; @@ -30,6 +31,12 @@ class MarkdownEditor { this.displayDoc = this.display.contentDocument; this.init(); }); + + window.$events.emitPublic(elem, 'editor-markdown::setup', { + markdownIt: this.markdown, + displayEl: this.display, + codeMirrorInstance: this.cm, + }); } init() { @@ -69,6 +76,7 @@ class MarkdownEditor { return; } if (action === 'insertDrawing') this.actionStartDrawing(); + if (action === 'fullscreen') this.actionFullScreen(); }); // Mobile section toggling @@ -209,20 +217,16 @@ class MarkdownEditor { // Handle image paste cm.on('paste', (cm, event) => { - const clipboardItems = event.clipboardData.items; - if (!event.clipboardData || !clipboardItems) return; + const clipboard = new Clipboard(event.clipboardData || event.dataTransfer); - // Don't handle if clipboard includes text content - for (let clipboardItem of clipboardItems) { - if (clipboardItem.type.includes('text/')) { - return; - } + // Don't handle the event ourselves if no items exist of contains table-looking data + if (!clipboard.hasItems() || clipboard.containsTabularData()) { + return; } - for (let clipboardItem of clipboardItems) { - if (clipboardItem.type.includes("image")) { - uploadImage(clipboardItem.getAsFile()); - } + const images = clipboard.getImages(); + for (const image of images) { + uploadImage(image); } }); @@ -240,13 +244,15 @@ class MarkdownEditor { }); } - if (event.dataTransfer && event.dataTransfer.files && event.dataTransfer.files.length > 0) { + const clipboard = new Clipboard(event.dataTransfer); + if (clipboard.hasItems()) { const cursorPos = cm.coordsChar({left: event.pageX, top: event.pageY}); cm.setCursor(cursorPos); event.stopPropagation(); event.preventDefault(); - for (let i = 0; i < event.dataTransfer.files.length; i++) { - uploadImage(event.dataTransfer.files[i]); + const images = clipboard.getImages(); + for (const image of images) { + uploadImage(image); } } @@ -475,6 +481,13 @@ class MarkdownEditor { }); } + // Make the editor full screen + actionFullScreen() { + const alreadyFullscreen = this.elem.classList.contains('fullscreen'); + this.elem.classList.toggle('fullscreen', !alreadyFullscreen); + document.body.classList.toggle('markdown-fullscreen', !alreadyFullscreen); + } + // Scroll to a specified text scrollToText(searchText) { if (!searchText) { diff --git a/resources/assets/js/components/new-user-password.js b/resources/js/components/new-user-password.js similarity index 100% rename from resources/assets/js/components/new-user-password.js rename to resources/js/components/new-user-password.js diff --git a/resources/assets/js/components/notification.js b/resources/js/components/notification.js similarity index 100% rename from resources/assets/js/components/notification.js rename to resources/js/components/notification.js diff --git a/resources/js/components/overlay.js b/resources/js/components/overlay.js new file mode 100644 index 000000000..6963ba9d1 --- /dev/null +++ b/resources/js/components/overlay.js @@ -0,0 +1,43 @@ +import {fadeIn, fadeOut} from "../services/animations"; + +class Overlay { + + constructor(elem) { + this.container = elem; + elem.addEventListener('click', event => { + if (event.target === elem) return this.hide(); + }); + + window.addEventListener('keyup', event => { + if (event.key === 'Escape') { + this.hide(); + } + }); + + let closeButtons = elem.querySelectorAll('.popup-header-close'); + for (let i=0; i < closeButtons.length; i++) { + closeButtons[i].addEventListener('click', this.hide.bind(this)); + } + } + + hide(onComplete = null) { this.toggle(false, onComplete); } + show(onComplete = null) { this.toggle(true, onComplete); } + + toggle(show = true, onComplete) { + if (show) { + fadeIn(this.container, 240, onComplete); + } else { + fadeOut(this.container, 240, onComplete); + } + } + + focusOnBody() { + const body = this.container.querySelector('.popup-body'); + if (body) { + body.focus(); + } + } + +} + +export default Overlay; \ No newline at end of file diff --git a/resources/assets/js/components/page-comments.js b/resources/js/components/page-comments.js similarity index 100% rename from resources/assets/js/components/page-comments.js rename to resources/js/components/page-comments.js diff --git a/resources/assets/js/components/page-display.js b/resources/js/components/page-display.js similarity index 100% rename from resources/assets/js/components/page-display.js rename to resources/js/components/page-display.js diff --git a/resources/assets/js/components/page-picker.js b/resources/js/components/page-picker.js similarity index 100% rename from resources/assets/js/components/page-picker.js rename to resources/js/components/page-picker.js diff --git a/resources/assets/js/components/permissions-table.js b/resources/js/components/permissions-table.js similarity index 100% rename from resources/assets/js/components/permissions-table.js rename to resources/js/components/permissions-table.js diff --git a/resources/assets/js/components/setting-app-color-picker.js b/resources/js/components/setting-app-color-picker.js similarity index 83% rename from resources/assets/js/components/setting-app-color-picker.js rename to resources/js/components/setting-app-color-picker.js index 6c0c0b31d..ee894c932 100644 --- a/resources/assets/js/components/setting-app-color-picker.js +++ b/resources/js/components/setting-app-color-picker.js @@ -6,11 +6,16 @@ class SettingAppColorPicker { this.colorInput = elem.querySelector('input[type=color]'); this.lightColorInput = elem.querySelector('input[name="setting-app-color-light"]'); this.resetButton = elem.querySelector('[setting-app-color-picker-reset]'); + this.defaultButton = elem.querySelector('[setting-app-color-picker-default]'); this.colorInput.addEventListener('change', this.updateColor.bind(this)); this.colorInput.addEventListener('input', this.updateColor.bind(this)); this.resetButton.addEventListener('click', event => { - this.colorInput.value = '#206ea7'; + this.colorInput.value = this.colorInput.dataset.current; + this.updateColor(); + }); + this.defaultButton.addEventListener('click', event => { + this.colorInput.value = this.colorInput.dataset.default; this.updateColor(); }); } @@ -53,4 +58,4 @@ class SettingAppColorPicker { } -export default SettingAppColorPicker; \ No newline at end of file +export default SettingAppColorPicker; diff --git a/resources/js/components/setting-color-picker.js b/resources/js/components/setting-color-picker.js new file mode 100644 index 000000000..4d8ce0f93 --- /dev/null +++ b/resources/js/components/setting-color-picker.js @@ -0,0 +1,18 @@ + +class SettingColorPicker { + + constructor(elem) { + this.elem = elem; + this.colorInput = elem.querySelector('input[type=color]'); + this.resetButton = elem.querySelector('[setting-color-picker-reset]'); + this.defaultButton = elem.querySelector('[setting-color-picker-default]'); + this.resetButton.addEventListener('click', event => { + this.colorInput.value = this.colorInput.dataset.current; + }); + this.defaultButton.addEventListener('click', event => { + this.colorInput.value = this.colorInput.dataset.default; + }); + } +} + +export default SettingColorPicker; diff --git a/resources/assets/js/components/shelf-sort.js b/resources/js/components/shelf-sort.js similarity index 100% rename from resources/assets/js/components/shelf-sort.js rename to resources/js/components/shelf-sort.js diff --git a/resources/assets/js/components/sidebar.js b/resources/js/components/sidebar.js similarity index 100% rename from resources/assets/js/components/sidebar.js rename to resources/js/components/sidebar.js diff --git a/resources/assets/js/components/template-manager.js b/resources/js/components/template-manager.js similarity index 100% rename from resources/assets/js/components/template-manager.js rename to resources/js/components/template-manager.js diff --git a/resources/assets/js/components/toggle-switch.js b/resources/js/components/toggle-switch.js similarity index 100% rename from resources/assets/js/components/toggle-switch.js rename to resources/js/components/toggle-switch.js diff --git a/resources/assets/js/components/tri-layout.js b/resources/js/components/tri-layout.js similarity index 100% rename from resources/assets/js/components/tri-layout.js rename to resources/js/components/tri-layout.js diff --git a/resources/assets/js/components/wysiwyg-editor.js b/resources/js/components/wysiwyg-editor.js similarity index 95% rename from resources/assets/js/components/wysiwyg-editor.js rename to resources/js/components/wysiwyg-editor.js index c03c0d2aa..b9e3340a8 100644 --- a/resources/assets/js/components/wysiwyg-editor.js +++ b/resources/js/components/wysiwyg-editor.js @@ -1,5 +1,6 @@ import Code from "../services/code"; import DrawIO from "../services/drawio"; +import Clipboard from "../services/clipboard"; /** * Handle pasting images from clipboard. @@ -8,30 +9,33 @@ import DrawIO from "../services/drawio"; * @param editor */ function editorPaste(event, editor, wysiwygComponent) { - const clipboardItems = event.clipboardData.items; - if (!event.clipboardData || !clipboardItems) return; + const clipboard = new Clipboard(event.clipboardData || event.dataTransfer); - // Don't handle if clipboard includes text content - for (let clipboardItem of clipboardItems) { - if (clipboardItem.type.includes('text/')) { - return; - } + // Don't handle the event ourselves if no items exist of contains table-looking data + if (!clipboard.hasItems() || clipboard.containsTabularData()) { + return; } - for (let clipboardItem of clipboardItems) { - if (!clipboardItem.type.includes("image")) { - continue; - } + const images = clipboard.getImages(); + for (const imageFile of images) { const id = "image-" + Math.random().toString(16).slice(2); const loadingImage = window.baseUrl('/loading.gif'); - const file = clipboardItem.getAsFile(); + event.preventDefault(); setTimeout(() => { editor.insertContent(`

`); - uploadImageFile(file, wysiwygComponent).then(resp => { - editor.dom.setAttrib(id, 'src', resp.thumbs.display); + uploadImageFile(imageFile, wysiwygComponent).then(resp => { + const safeName = resp.name.replace(/"/g, ''); + const newImageHtml = `${safeName}`; + + const newEl = editor.dom.create('a', { + target: '_blank', + href: resp.url, + }, newImageHtml); + + editor.dom.replace(newEl, id); }).catch(err => { editor.dom.remove(id); window.$events.emit('error', trans('errors.image_upload_error')); @@ -160,7 +164,7 @@ function codePlugin() { let cmInstance = editorElem.CodeMirror; if (cmInstance) { Code.setContent(cmInstance, code); - Code.setMode(cmInstance, lang); + Code.setMode(cmInstance, lang, code); } let textArea = selectedNode.querySelector('textarea'); if (textArea) textArea.textContent = code; @@ -412,6 +416,7 @@ class WysiwygEditor { this.loadPlugins(); this.tinyMceConfig = this.getTinyMceConfig(); + window.$events.emitPublic(elem, 'editor-tinymce::pre-init', {config: this.tinyMceConfig}); window.tinymce.init(this.tinyMceConfig); } @@ -633,6 +638,10 @@ class WysiwygEditor { }); } + if (!event.isDefaultPrevented()) { + editorPaste(event, editor, context); + } + wrap = null; }); @@ -654,6 +663,8 @@ class WysiwygEditor { // Paste image-uploads editor.on('paste', event => editorPaste(event, editor, context)); + // Custom handler hook + window.$events.emitPublic(context.elem, 'editor-tinymce::setup', {editor}); } }; } diff --git a/resources/assets/js/index.js b/resources/js/index.js similarity index 100% rename from resources/assets/js/index.js rename to resources/js/index.js diff --git a/resources/assets/js/services/animations.js b/resources/js/services/animations.js similarity index 90% rename from resources/assets/js/services/animations.js rename to resources/js/services/animations.js index b6158ea5f..278a765d5 100644 --- a/resources/assets/js/services/animations.js +++ b/resources/js/services/animations.js @@ -5,6 +5,22 @@ */ const animateStylesCleanupMap = new WeakMap(); +/** + * Fade in the given element. + * @param {Element} element + * @param {Number} animTime + * @param {Function|null} onComplete + */ +export function fadeIn(element, animTime = 400, onComplete = null) { + cleanupExistingElementAnimation(element); + element.style.display = 'block'; + animateStyles(element, { + opacity: ['0', '1'] + }, animTime, () => { + if (onComplete) onComplete(); + }); +} + /** * Fade out the given element. * @param {Element} element diff --git a/resources/js/services/clipboard.js b/resources/js/services/clipboard.js new file mode 100644 index 000000000..da921e515 --- /dev/null +++ b/resources/js/services/clipboard.js @@ -0,0 +1,54 @@ + +class Clipboard { + + /** + * Constructor + * @param {DataTransfer} clipboardData + */ + constructor(clipboardData) { + this.data = clipboardData; + } + + /** + * Check if the clipboard has any items. + */ + hasItems() { + return Boolean(this.data) && Boolean(this.data.types) && this.data.types.length > 0; + } + + /** + * Check if the given event has tabular-looking data in the clipboard. + * @return {boolean} + */ + containsTabularData() { + const rtfData = this.data.getData( 'text/rtf'); + return rtfData && rtfData.includes('\\trowd'); + } + + /** + * Get the images that are in the clipboard data. + * @return {Array} + */ + getImages() { + const types = this.data.types; + const files = this.data.files; + const images = []; + + for (const type of types) { + if (type.includes('image')) { + const item = this.data.getData(type); + images.push(item.getAsFile()); + } + } + + for (const file of files) { + if (file.type.includes('image')) { + images.push(file); + } + } + + return images; + } +} + +export default Clipboard; \ No newline at end of file diff --git a/resources/assets/js/services/code.js b/resources/js/services/code.js similarity index 69% rename from resources/assets/js/services/code.js rename to resources/js/services/code.js index 1e0e48289..718ef5721 100644 --- a/resources/assets/js/services/code.js +++ b/resources/js/services/code.js @@ -16,6 +16,7 @@ import 'codemirror/mode/mllike/mllike'; import 'codemirror/mode/nginx/nginx'; import 'codemirror/mode/php/php'; import 'codemirror/mode/powershell/powershell'; +import 'codemirror/mode/properties/properties'; import 'codemirror/mode/python/python'; import 'codemirror/mode/ruby/ruby'; import 'codemirror/mode/rust/rust'; @@ -24,10 +25,14 @@ import 'codemirror/mode/sql/sql'; import 'codemirror/mode/toml/toml'; import 'codemirror/mode/xml/xml'; import 'codemirror/mode/yaml/yaml'; +import 'codemirror/mode/pascal/pascal'; // Addons import 'codemirror/addon/scroll/scrollpastend'; +// Mapping of possible languages or formats from user input to their codemirror modes. +// Value can be a mode string or a function that will receive the code content & return the mode string. +// The function option is used in the event the exact mode could be dynamic depending on the code. const modeMap = { css: 'css', c: 'text/x-csrc', @@ -42,6 +47,7 @@ const modeMap = { haskell: 'haskell', hs: 'haskell', html: 'htmlmixed', + ini: 'properties', javascript: 'javascript', json: {name: 'javascript', json: true}, js: 'javascript', @@ -54,8 +60,13 @@ const modeMap = { ml: 'mllike', nginx: 'nginx', powershell: 'powershell', + properties: 'properties', ocaml: 'mllike', - php: 'php', + pascal: 'text/x-pascal', + pas: 'text/x-pascal', + php: (content) => { + return content.includes('/gi ,'\n'); + const content = elem.textContent; + let mode = ''; if (innerCodeElem !== null) { - let langName = innerCodeElem.className.replace('language-', ''); - mode = getMode(langName); + const langName = innerCodeElem.className.replace('language-', ''); + mode = getMode(langName, content); } - elem.innerHTML = elem.innerHTML.replace(//gi ,'\n'); - let content = elem.textContent.trim(); - let cm = CodeMirror(function(elt) { + const cm = CodeMirror(function(elt) { elem.parentNode.replaceChild(elt, elem); }, { value: content, mode: mode, lineNumbers: true, + lineWrapping: false, theme: getTheme(), readOnly: true }); @@ -136,12 +160,24 @@ function addCopyIcon(cmInstance) { /** * Search for a codemirror code based off a user suggestion - * @param suggestion + * @param {String} suggestion + * @param {String} content * @returns {string} */ -function getMode(suggestion) { +function getMode(suggestion, content) { suggestion = suggestion.trim().replace(/^\./g, '').toLowerCase(); - return (typeof modeMap[suggestion] !== 'undefined') ? modeMap[suggestion] : ''; + + const modeMapType = typeof modeMap[suggestion]; + + if (modeMapType === 'undefined') { + return ''; + } + + if (modeMapType === 'function') { + return modeMap[suggestion](content); + } + + return modeMap[suggestion]; } /** @@ -149,7 +185,7 @@ function getMode(suggestion) { * @returns {*|string} */ function getTheme() { - return window.codeTheme || 'base16-light'; + return window.codeTheme || 'default'; } /** @@ -159,8 +195,8 @@ function getTheme() { * @returns {{wrap: Element, editor: *}} */ function wysiwygView(elem) { - let doc = elem.ownerDocument; - let codeElem = elem.querySelector('code'); + const doc = elem.ownerDocument; + const codeElem = elem.querySelector('code'); let lang = (elem.className || '').replace('language-', ''); if (lang === '' && codeElem) { @@ -168,9 +204,9 @@ function wysiwygView(elem) { } elem.innerHTML = elem.innerHTML.replace(//gi ,'\n'); - let content = elem.textContent; - let newWrap = doc.createElement('div'); - let newTextArea = doc.createElement('textarea'); + const content = elem.textContent; + const newWrap = doc.createElement('div'); + const newTextArea = doc.createElement('textarea'); newWrap.className = 'CodeMirrorContainer'; newWrap.setAttribute('data-lang', lang); @@ -186,8 +222,9 @@ function wysiwygView(elem) { newWrap.appendChild(elt); }, { value: content, - mode: getMode(lang), + mode: getMode(lang, content), lineNumbers: true, + lineWrapping: false, theme: getTheme(), readOnly: true }); @@ -204,17 +241,17 @@ function wysiwygView(elem) { * @returns {*} */ function popupEditor(elem, modeSuggestion) { - let content = elem.textContent; + const content = elem.textContent; return CodeMirror(function(elt) { elem.parentNode.insertBefore(elt, elem); elem.style.display = 'none'; }, { value: content, - mode: getMode(modeSuggestion), + mode: getMode(modeSuggestion, content), lineNumbers: true, - theme: getTheme(), - lineWrapping: true + lineWrapping: false, + theme: getTheme() }); } @@ -223,8 +260,8 @@ function popupEditor(elem, modeSuggestion) { * @param cmInstance * @param modeSuggestion */ -function setMode(cmInstance, modeSuggestion) { - cmInstance.setOption('mode', getMode(modeSuggestion)); +function setMode(cmInstance, modeSuggestion, content) { + cmInstance.setOption('mode', getMode(modeSuggestion, content)); } /** @@ -235,29 +272,40 @@ function setMode(cmInstance, modeSuggestion) { function setContent(cmInstance, codeContent) { cmInstance.setValue(codeContent); setTimeout(() => { - cmInstance.refresh(); + updateLayout(cmInstance); }, 10); } /** - * Get a CodeMirror instace to use for the markdown editor. + * Update the layout (codemirror refresh) of a cm instance. + * @param cmInstance + */ +function updateLayout(cmInstance) { + cmInstance.refresh(); +} + +/** + * Get a CodeMirror instance to use for the markdown editor. * @param {HTMLElement} elem * @returns {*} */ function markdownEditor(elem) { - let content = elem.textContent; + const content = elem.textContent; + const config = { + value: content, + mode: "markdown", + lineNumbers: true, + lineWrapping: true, + theme: getTheme(), + scrollPastEnd: true, + }; + + window.$events.emitPublic(elem, 'editor-markdown-cm::pre-init', {config}); return CodeMirror(function (elt) { elem.parentNode.insertBefore(elt, elem); elem.style.display = 'none'; - }, { - value: content, - mode: "markdown", - lineNumbers: true, - theme: getTheme(), - lineWrapping: true, - scrollPastEnd: true, - }); + }, config); } /** @@ -271,10 +319,12 @@ function getMetaKey() { export default { highlight: highlight, + highlightWithin: highlightWithin, wysiwygView: wysiwygView, popupEditor: popupEditor, setMode: setMode, setContent: setContent, + updateLayout: updateLayout, markdownEditor: markdownEditor, getMetaKey: getMetaKey, }; diff --git a/resources/assets/js/services/dates.js b/resources/js/services/dates.js similarity index 100% rename from resources/assets/js/services/dates.js rename to resources/js/services/dates.js diff --git a/resources/assets/js/services/dom.js b/resources/js/services/dom.js similarity index 100% rename from resources/assets/js/services/dom.js rename to resources/js/services/dom.js diff --git a/resources/assets/js/services/drawio.js b/resources/js/services/drawio.js similarity index 100% rename from resources/assets/js/services/drawio.js rename to resources/js/services/drawio.js diff --git a/resources/js/services/events.js b/resources/js/services/events.js new file mode 100644 index 000000000..fa3ed7fdf --- /dev/null +++ b/resources/js/services/events.js @@ -0,0 +1,55 @@ +/** + * Simple global events manager + */ +class Events { + constructor() { + this.listeners = {}; + this.stack = []; + } + + /** + * Emit a custom event for any handlers to pick-up. + * @param {String} eventName + * @param {*} eventData + * @returns {Events} + */ + emit(eventName, eventData) { + this.stack.push({name: eventName, data: eventData}); + if (typeof this.listeners[eventName] === 'undefined') return this; + let eventsToStart = this.listeners[eventName]; + for (let i = 0; i < eventsToStart.length; i++) { + let event = eventsToStart[i]; + event(eventData); + } + return this; + } + + /** + * Listen to a custom event and run the given callback when that event occurs. + * @param {String} eventName + * @param {Function} callback + * @returns {Events} + */ + listen(eventName, callback) { + if (typeof this.listeners[eventName] === 'undefined') this.listeners[eventName] = []; + this.listeners[eventName].push(callback); + return this; + } + + /** + * Emit an event for public use. + * Sends the event via the native DOM event handling system. + * @param {Element} targetElement + * @param {String} eventName + * @param {Object} eventData + */ + emitPublic(targetElement, eventName, eventData) { + const event = new CustomEvent(eventName, { + detail: eventData, + bubbles: true + }); + targetElement.dispatchEvent(event); + } +} + +export default Events; \ No newline at end of file diff --git a/resources/assets/js/services/http.js b/resources/js/services/http.js similarity index 100% rename from resources/assets/js/services/http.js rename to resources/js/services/http.js diff --git a/resources/assets/js/services/translations.js b/resources/js/services/translations.js similarity index 100% rename from resources/assets/js/services/translations.js rename to resources/js/services/translations.js diff --git a/resources/assets/js/services/util.js b/resources/js/services/util.js similarity index 100% rename from resources/assets/js/services/util.js rename to resources/js/services/util.js diff --git a/resources/assets/js/vues/attachment-manager.js b/resources/js/vues/attachment-manager.js similarity index 100% rename from resources/assets/js/vues/attachment-manager.js rename to resources/js/vues/attachment-manager.js diff --git a/resources/assets/js/vues/code-editor.js b/resources/js/vues/code-editor.js similarity index 82% rename from resources/assets/js/vues/code-editor.js rename to resources/js/vues/code-editor.js index c6df6b1a5..48b4e1766 100644 --- a/resources/assets/js/vues/code-editor.js +++ b/resources/js/vues/code-editor.js @@ -3,13 +3,15 @@ import codeLib from "../services/code"; const methods = { show() { if (!this.editor) this.editor = codeLib.popupEditor(this.$refs.editor, this.language); - this.$refs.overlay.components.overlay.show(); + this.$refs.overlay.components.overlay.show(() => { + codeLib.updateLayout(this.editor); + }); }, hide() { this.$refs.overlay.components.overlay.hide(); }, updateEditorMode(language) { - codeLib.setMode(this.editor, language); + codeLib.setMode(this.editor, language, this.editor.getValue()); }, updateLanguage(lang) { this.language = lang; diff --git a/resources/assets/js/vues/components/autosuggest.js b/resources/js/vues/components/autosuggest.js similarity index 100% rename from resources/assets/js/vues/components/autosuggest.js rename to resources/js/vues/components/autosuggest.js diff --git a/resources/assets/js/vues/components/dropzone.js b/resources/js/vues/components/dropzone.js similarity index 100% rename from resources/assets/js/vues/components/dropzone.js rename to resources/js/vues/components/dropzone.js diff --git a/resources/assets/js/vues/entity-dashboard.js b/resources/js/vues/entity-dashboard.js similarity index 100% rename from resources/assets/js/vues/entity-dashboard.js rename to resources/js/vues/entity-dashboard.js diff --git a/resources/assets/js/vues/image-manager.js b/resources/js/vues/image-manager.js similarity index 100% rename from resources/assets/js/vues/image-manager.js rename to resources/js/vues/image-manager.js diff --git a/resources/assets/js/vues/page-editor.js b/resources/js/vues/page-editor.js similarity index 100% rename from resources/assets/js/vues/page-editor.js rename to resources/js/vues/page-editor.js diff --git a/resources/assets/js/vues/search.js b/resources/js/vues/search.js similarity index 100% rename from resources/assets/js/vues/search.js rename to resources/js/vues/search.js diff --git a/resources/assets/js/vues/tag-manager.js b/resources/js/vues/tag-manager.js similarity index 100% rename from resources/assets/js/vues/tag-manager.js rename to resources/js/vues/tag-manager.js diff --git a/resources/assets/js/vues/vues.js b/resources/js/vues/vues.js similarity index 100% rename from resources/assets/js/vues/vues.js rename to resources/js/vues/vues.js diff --git a/resources/lang/ar/activities.php b/resources/lang/ar/activities.php index fd13b16aa..348eba398 100644 --- a/resources/lang/ar/activities.php +++ b/resources/lang/ar/activities.php @@ -1,12 +1,10 @@ 'تم إنشاء صفحة', 'page_create_notification' => 'تم إنشاء الصفحة بنجاح', @@ -37,6 +35,14 @@ return [ 'book_sort' => 'تم سرد الكتاب', 'book_sort_notification' => 'تمت إعادة سرد الكتاب بنجاح', + // 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', + // Other 'commented_on' => 'تم التعليق', ]; diff --git a/resources/lang/ar/auth.php b/resources/lang/ar/auth.php index bad0910a2..d9ed5cf27 100644 --- a/resources/lang/ar/auth.php +++ b/resources/lang/ar/auth.php @@ -1,21 +1,15 @@ 'البيانات المعطاة لا توافق سجلاتنا.', 'throttle' => 'تجاوزت الحد الأقصى من المحاولات. الرجاء المحاولة مرة أخرى بعد :seconds seconds.', - /** - * Login & Register - */ + // Login & Register 'sign_up' => 'إنشاء حساب', 'log_in' => 'تسجيل الدخول', 'log_in_with' => 'تسجيل الدخول باستخدام :socialDriver', @@ -27,11 +21,13 @@ return [ 'email' => 'البريد الإلكتروني', 'password' => 'كلمة المرور', 'password_confirm' => 'تأكيد كلمة المرور', - 'password_hint' => 'يجب أن تكون أكثر من 5 حروف', + 'password_hint' => 'يجب أن تكون أكثر من 7 حروف', 'forgot_password' => 'نسيت كلمة المرور؟', 'remember_me' => 'تذكرني', 'ldap_email_hint' => 'الرجاء إدخال عنوان بريد إلكتروني لاستخدامه مع الحساب.', 'create_account' => 'إنشاء حساب', + 'already_have_account' => 'Already have an account?', + 'dont_have_account' => 'Don\'t have an account?', 'social_login' => 'تسجيل الدخول باستخدام حسابات التواصل الاجتماعي', 'social_registration' => 'إنشاء حساب باستخدام حسابات التواصل الاجتماعي', 'social_registration_text' => 'إنشاء حساب والدخول باستخدام خدمة أخرى.', @@ -43,23 +39,18 @@ return [ 'register_success' => 'شكراً لإنشاء حسابكم! تم تسجيلكم ودخولكم للحساب الخاص بكم.', - /** - * Password Reset - */ + // Password Reset 'reset_password' => 'استعادة كلمة المرور', 'reset_password_send_instructions' => 'أدخل بريدك الإلكتروني بالأسفل وسيتم إرسال رسالة برابط لاستعادة كلمة المرور.', 'reset_password_send_button' => 'أرسل رابط الاستعادة', 'reset_password_sent_success' => 'تم إرسال رابط استعادة كلمة المرور إلى :email.', 'reset_password_success' => 'تمت استعادة كلمة المرور بنجاح.', - 'email_reset_subject' => 'استعد كلمة المرور الخاصة بتطبيق :appName', 'email_reset_text' => 'تم إرسال هذه الرسالة بسبب تلقينا لطلب استعادة كلمة المرور الخاصة بحسابكم.', 'email_reset_not_requested' => 'إذا لم يتم طلب استعادة كلمة المرور من قبلكم, فلا حاجة لاتخاذ أية خطوات.', - /** - * Email Confirmation - */ + // Email Confirmation 'email_confirm_subject' => 'تأكيد بريدكم الإلكتروني لتطبيق :appName', 'email_confirm_greeting' => 'شكرا لانضمامكم إلى :appName!', 'email_confirm_text' => 'الرجاء تأكيد بريدكم الإلكتروني بالضغط على الزر أدناه:', @@ -73,4 +64,14 @@ return [ 'email_not_confirmed_click_link' => 'الرجاء الضغط على الرابط المرسل إلى بريدكم الإلكتروني بعد تسجيلكم.', 'email_not_confirmed_resend' => 'إذا لم يتم إيجاد الرسالة, بإمكانكم إعادة إرسال رسالة التأكيد عن طريق تعبئة النموذج أدناه.', 'email_not_confirmed_resend_button' => 'إعادة إرسال رسالة التأكيد', + + // 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!' ]; \ No newline at end of file diff --git a/resources/lang/ar/common.php b/resources/lang/ar/common.php index 9c978b454..90c4e5159 100644 --- a/resources/lang/ar/common.php +++ b/resources/lang/ar/common.php @@ -1,31 +1,30 @@ 'إلغاء', 'confirm' => 'تأكيد', 'back' => 'رجوع', 'save' => 'حفظ', 'continue' => 'استمرار', 'select' => 'تحديد', + 'toggle_all' => 'Toggle All', 'more' => 'المزيد', - /** - * Form Labels - */ + // Form Labels 'name' => 'الاسم', 'description' => 'الوصف', 'role' => 'الدور', 'cover_image' => 'صورة الغلاف', 'cover_image_description' => 'الصورة يجب أن تكون مقاربة لحجم 440×250 بكسل.', - /** - * Actions - */ + // Actions 'actions' => 'إجراءات', 'view' => 'عرض', + 'view_all' => 'View All', 'create' => 'إنشاء', 'update' => 'تحديث', 'edit' => 'تعديل', @@ -39,10 +38,18 @@ return [ 'reset' => 'إعادة تعيين', 'remove' => 'إزالة', 'add' => 'إضافة', + 'fullscreen' => 'Fullscreen', - /** - * Misc - */ + // 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', + + // Misc 'deleted_user' => 'حذف مستخدم', 'no_activity' => 'لا يوجد نشاط لعرضه', 'no_items' => 'لا توجد عناصر متوفرة', @@ -52,16 +59,19 @@ return [ 'details' => 'التفاصيل', 'grid_view' => 'عرض شبكي', 'list_view' => 'عرض منسدل', + 'default' => 'Default', + 'breadcrumb' => 'Breadcrumb', - /** - * Header - */ + // Header + 'profile_menu' => 'Profile Menu', 'view_profile' => 'عرض الملف الشخصي', 'edit_profile' => 'تعديل الملف الشخصي', - /** - * Email Content - */ + // Layout tabs + 'tab_info' => 'Info', + 'tab_content' => 'Content', + + // Email Content 'email_action_help' => 'إذا واجهتكم مشكلة بضغط زر ":actionText" فبإمكانكم نسخ الرابط أدناه ولصقه بالمتصفح:', 'email_rights' => 'جميع الحقوق محفوظة', -]; \ No newline at end of file +]; diff --git a/resources/lang/ar/components.php b/resources/lang/ar/components.php index f98558935..aa3935bd9 100644 --- a/resources/lang/ar/components.php +++ b/resources/lang/ar/components.php @@ -1,9 +1,10 @@ 'تحديد صورة', 'image_all' => 'الكل', 'image_all_title' => 'عرض جميع الصور', @@ -24,9 +25,7 @@ return [ 'image_delete_success' => 'تم حذف الصورة بنجاح', 'image_upload_remove' => 'إزالة', - /** - * Code editor - */ + // Code Editor 'code_editor' => 'تعديل الشفرة', 'code_language' => 'لغة الشفرة', 'code_content' => 'محتويات الشفرة', diff --git a/resources/lang/ar/entities.php b/resources/lang/ar/entities.php index 55099380d..9278c8cf3 100644 --- a/resources/lang/ar/entities.php +++ b/resources/lang/ar/entities.php @@ -1,14 +1,17 @@ 'أنشئت مؤخراً', 'recently_created_pages' => 'صفحات أنشئت مؤخراً', 'recently_updated_pages' => 'صفحات حُدثت مؤخراً', 'recently_created_chapters' => 'فصول أنشئت مؤخراً', 'recently_created_books' => 'كتب أنشئت مؤخراً', + 'recently_created_shelves' => 'Recently Created Shelves', 'recently_update' => 'حُدثت مؤخراً', 'recently_viewed' => 'عُرضت مؤخراً', 'recent_activity' => 'نشاطات حديثة', @@ -19,7 +22,7 @@ return [ 'meta_created_name' => 'أنشئ :timeLength بواسطة :user', 'meta_updated' => 'مُحدث :timeLength', 'meta_updated_name' => 'مُحدث :timeLength بواسطة :user', - 'entity_select' => 'Entity Select', // جار البحث عن الترجمة الأنسب + 'entity_select' => 'Entity Select', 'images' => 'صور', 'my_recent_drafts' => 'مسوداتي الحديثة', 'my_recently_viewed' => 'ما عرضته مؤخراً', @@ -31,17 +34,13 @@ return [ 'export_pdf' => 'ملف PDF', 'export_text' => 'ملف نص عادي', - /** - * Permissions and restrictions - */ + // Permissions and restrictions 'permissions' => 'الأذونات', 'permissions_intro' => 'في حال التفعيل, ستتم تبدية هذه الأذونات على أذونات الأدوار.', 'permissions_enable' => 'تفعيل الأذونات المخصصة', 'permissions_save' => 'حفظ الأذونات', - /** - * Search // - */ + // Search 'search_results' => 'نتائج البحث', 'search_total_results_found' => 'عدد النتائج :count|مجموع النتائج :count', 'search_clear' => 'مسح البحث', @@ -52,11 +51,13 @@ return [ 'search_content_type' => 'نوع المحتوى', 'search_exact_matches' => 'نتائج مطابقة تماماً', 'search_tags' => 'بحث الوسوم', + 'search_options' => 'Options', 'search_viewed_by_me' => 'تم استعراضها من قبلي', 'search_not_viewed_by_me' => 'لم يتم استعراضها من قبلي', 'search_permissions_set' => 'حزمة الأذونات', 'search_created_by_me' => 'أنشئت بواسطتي', 'search_updated_by_me' => 'حُدثت بواسطتي', + 'search_date_options' => 'Date Options', 'search_updated_before' => 'حدثت قبل', 'search_updated_after' => 'حدثت بعد', 'search_created_before' => 'أنشئت قبل', @@ -64,9 +65,39 @@ return [ 'search_set_date' => 'تحديد التاريخ', 'search_update' => 'تحديث البحث', - /** - * Books - */ + // 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', + + // Books 'book' => 'كتاب', 'books' => 'كتب', 'x_books' => ':count كتاب|:count كتب', @@ -74,6 +105,7 @@ return [ 'books_popular' => 'كتب رائجة', 'books_recent' => 'كتب حديثة', 'books_new' => 'كتب جديدة', + 'books_new_action' => 'New Book', 'books_popular_empty' => 'الكتب الأكثر رواجاً ستظهر هنا.', 'books_new_empty' => 'الكتب المنشأة مؤخراً ستظهر هنا.', 'books_create' => 'إنشاء كتاب جديد', @@ -89,7 +121,6 @@ return [ 'books_permissions_updated' => 'تم تحديث أذونات الكتاب', 'books_empty_contents' => 'لم يتم إنشاء أي صفحات أو فصول لهذا الكتاب.', 'books_empty_create_page' => 'إنشاء صفحة جديدة', - 'books_empty_or' => 'أو', 'books_empty_sort_current_book' => 'فرز الكتاب الحالي', 'books_empty_add_chapter' => 'إضافة فصل', 'books_permissions_active' => 'أذونات الكتاب مفعلة', @@ -97,12 +128,15 @@ return [ 'books_navigation' => 'تصفح الكتاب', 'books_sort' => 'فرز محتويات الكتاب', 'books_sort_named' => 'فرز كتاب :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' => 'عرض كتب أخرى', 'books_sort_save' => 'حفظ الترتيب الجديد', - /** - * Chapters - */ + // Chapters 'chapter' => 'فصل', 'chapters' => 'فصول', 'x_chapters' => ':count فصل|:count فصول', @@ -125,9 +159,7 @@ return [ 'chapters_permissions_success' => 'تم تحديث أذونات الفصل', 'chapters_search_this' => 'البحث في هذا الفصل', - /** - * Pages - */ + // Pages 'page' => 'صفحة', 'pages' => 'صفحات', 'x_pages' => ':count صفحة|:count صفحات', @@ -144,7 +176,7 @@ return [ 'pages_delete_confirm' => 'تأكيد حذف الصفحة؟', 'pages_delete_draft_confirm' => 'تأكيد حذف المسودة؟', 'pages_editing_named' => ':pageName قيد التعديل', - 'pages_edit_toggle_header' => 'إظهار / إخفاء الترويسة', + 'pages_edit_draft_options' => 'Draft Options', 'pages_edit_save_draft' => 'حفظ المسودة', 'pages_edit_draft' => 'تعديل مسودة الصفحة', 'pages_editing_draft' => 'المسودة قيد التعديل', @@ -161,7 +193,7 @@ return [ 'pages_md_editor' => 'المحرر', 'pages_md_preview' => 'معاينة', 'pages_md_insert_image' => 'إدخال صورة', - 'pages_md_insert_link' => 'Insert Entity Link', // جار البحث عن الترجمة الأنسب + 'pages_md_insert_link' => 'Insert Entity Link', 'pages_md_insert_drawing' => 'إدخال رسمة', 'pages_not_in_chapter' => 'صفحة ليست في فصل', 'pages_move' => 'نقل الصفحة', @@ -178,6 +210,8 @@ return [ 'pages_revisions_created_by' => 'أنشئ بواسطة', 'pages_revisions_date' => 'تاريخ المراجعة', 'pages_revisions_number' => '#', + 'pages_revisions_numbered' => 'Revision #:id', + 'pages_revisions_numbered_changes' => 'Revision #:id Changes', 'pages_revisions_changelog' => 'سجل التعديل', 'pages_revisions_changes' => 'التعديلات', 'pages_revisions_current' => 'النسخة الحالية', @@ -196,21 +230,24 @@ return [ 'start_b' => ':userName بدأ بتعديل هذه الصفحة', 'time_a' => 'منذ أن تم تحديث هذه الصفحة', 'time_b' => 'في آخر :minCount دقيقة/دقائق', - 'message' => ':start :time. Take care not to overwrite each other\'s updates!', // جار البحث عن الترجمة الأنسب + 'message' => ':start :time. Take care not to overwrite each other\'s updates!', ], 'pages_draft_discarded' => 'تم التخلص من المسودة. تم تحديث المحرر بمحتوى الصفحة الحالي', + 'pages_specific' => 'Specific Page', + 'pages_is_template' => 'Page Template', - /** - * Editor sidebar - */ + // Editor Sidebar 'page_tags' => 'وسوم الصفحة', 'chapter_tags' => 'وسوم الفصل', 'book_tags' => 'وسوم الكتاب', + 'shelf_tags' => 'Shelf Tags', 'tag' => 'وسم', 'tags' => 'وسوم', + 'tag_name' => 'Tag Name', 'tag_value' => 'قيمة الوسم (اختياري)', 'tags_explain' => "إضافة الوسوم تساعد بترتيب وتقسيم المحتوى. \n من الممكن وضع قيمة لكل وسم لترتيب أفضل وأدق.", 'tags_add' => 'إضافة وسم آخر', + 'tags_remove' => 'Remove this tag', 'attachments' => 'المرفقات', 'attachments_explain' => 'ارفع بعض الملفات أو أرفق بعض الروابط لعرضها بصفحتك. ستكون الملفات والروابط معروضة في الشريط الجانبي للصفحة.', 'attachments_explain_instant_save' => 'سيتم حفظ التغييرات هنا بلحظتها', @@ -224,7 +261,7 @@ return [ 'attachments_explain_link' => 'بالإمكان إرفاق رابط في حال عدم تفضيل رفع ملف. قد يكون الرابط لصفحة أخرى أو لملف في أحد خدمات التخزين السحابي.', 'attachments_link_name' => 'اسم الرابط', 'attachment_link' => 'رابط المرفق', - 'attachments_link_url' => 'Link to file', // جار البحث عن الترجمة الأنسب - هل المقصود الربط بالملف أو رابط يشير إلى ملف + 'attachments_link_url' => 'Link to file', 'attachments_link_url_hint' => 'رابط الموقع أو الملف', 'attach' => 'Attach', 'attachments_edit_file' => 'تعديل الملف', @@ -236,19 +273,22 @@ return [ 'attachments_file_uploaded' => 'تم رفع الملف بنجاح', 'attachments_file_updated' => 'تم تحديث الملف بنجاح', 'attachments_link_attached' => 'تم إرفاق الرابط بالصفحة بنجاح', + '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 View + 'profile_user_for_x' => 'User for :time', 'profile_created_content' => 'المحتوى المنشأ', 'profile_not_created_pages' => 'لم يتم إنشاء أي صفحات بواسطة :userName', 'profile_not_created_chapters' => 'لم يتم إنشاء أي فصول بواسطة :userName', 'profile_not_created_books' => 'لم يتم إنشاء أي كتب بواسطة :userName', + 'profile_not_created_shelves' => ':userName has not created any shelves', - /** - * Comments - */ + // Comments 'comment' => 'تعليق', 'comments' => 'تعليقات', 'comment_add' => 'إضافة تعليق', @@ -265,4 +305,10 @@ return [ 'comment_updated_success' => 'تم تحديث التعليق', 'comment_delete_confirm' => 'تأكيد حذف التعليق؟', 'comment_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/ar/errors.php b/resources/lang/ar/errors.php index 6be77a1b4..c1f53e171 100644 --- a/resources/lang/ar/errors.php +++ b/resources/lang/ar/errors.php @@ -1,11 +1,9 @@ 'لم يؤذن لك بالدخول للصفحة المطلوبة.', 'permissionJson' => 'لم يؤذن لك بعمل الإجراء المطلوب.', @@ -15,10 +13,16 @@ return [ 'email_already_confirmed' => 'تم تأكيد البريد الإلكتروني من قبل, الرجاء محاولة تسجيل الدخول.', 'email_confirmation_invalid' => 'رابط التأكيد غير صحيح أو قد تم استخدامه من قبل, الرجاء محاولة التسجيل من جديد.', 'email_confirmation_expired' => 'صلاحية رابط التأكيد انتهت, تم إرسال رسالة تأكيد جديدة لعنوان البريد الإلكتروني.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'فشل الوصول إلى LDAP باستخدام الربط المجهول', 'ldap_fail_authed' => 'فشل الوصول إلى LDAP باستخدام dn و password المعطاة', 'ldap_extension_not_installed' => 'لم يتم تثبيت إضافة LDAP PHP', 'ldap_cannot_connect' => 'لا يمكن الاتصال بخادم ldap, فشل الاتصال المبدئي', + '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' => 'لم يتم تعريف أي إجراء', 'social_login_bad_response' => "حصل خطأ خلال تسجيل الدخول باستخدام :socialAccount \n:error", 'social_account_in_use' => 'حساب :socialAccount قيد الاستخدام حالياً, الرجاء محاولة الدخول باستخدام خيار :socialAccount.', @@ -27,8 +31,9 @@ return [ 'social_account_already_used_existing' => 'حساب :socialAccount مستخدَم من قبل مستخدم آخر.', 'social_account_not_used' => 'حساب :socialAccount غير مرتبط بأي مستخدم. الرجاء ربطه من خلال إعدادات ملفكم. ', 'social_account_register_instructions' => 'إذا لم يكن لديكم حساب فيمكنكم التجسيل باستخدام خيار :socialAccount.', - 'social_driver_not_found' => 'Social driver not found', // جار البحث عن الترجمة الأنسب - 'social_driver_not_configured' => 'Your :socialAccount social settings are not configured correctly.', // جار البحث عن الترجمة الأنسب + '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.', // System 'path_not_writable' => 'لا يمكن الرفع إلى مسار :filePath. الرجاء التأكد من قابلية الكتابة إلى الخادم.', @@ -41,7 +46,7 @@ return [ 'file_upload_timeout' => 'انتهت عملية تحميل الملف.', // Attachments - 'attachment_page_mismatch' => 'Page mismatch during attachment update', // جار البحث عن الترجمة الأنسب + 'attachment_page_mismatch' => 'Page mismatch during attachment update', 'attachment_not_found' => 'لم يتم العثور على المرفق', // Pages @@ -49,7 +54,8 @@ return [ 'page_custom_home_deletion' => 'لا يمكن حذف الصفحة إذا كانت محددة كصفحة رئيسية', // Entities - 'entity_not_found' => 'Entity not found', // جار البحث عن الترجمة الأنسب + 'entity_not_found' => 'Entity not found', + 'bookshelf_not_found' => 'Bookshelf not found', 'book_not_found' => 'لم يتم العثور على الكتاب', 'page_not_found' => 'لم يتم العثور على الصفحة', 'chapter_not_found' => 'لم يتم العثور على الفصل', @@ -65,6 +71,7 @@ return [ 'role_cannot_be_edited' => 'لا يمكن تعديل هذا الدور', 'role_system_cannot_be_deleted' => 'هذا الدور خاص بالنظام ولا يمكن حذفه', 'role_registration_default_cannot_delete' => 'لا يمكن حذف الدور إذا كان مسجل كالدور الأساسي بعد تسجيل الحساب', + '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.', // Comments 'comment_list' => 'حصل خطأ خلال جلب التعليقات.', @@ -80,4 +87,13 @@ return [ 'error_occurred' => 'حدث خطأ', 'app_down' => ':appName لا يعمل حالياً', 'back_soon' => 'سيعود للعمل قريباً.', + + // 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', + ]; diff --git a/resources/lang/ar/pagination.php b/resources/lang/ar/pagination.php index 9a1276a8d..4ba36f6df 100644 --- a/resources/lang/ar/pagination.php +++ b/resources/lang/ar/pagination.php @@ -1,18 +1,11 @@ '« السابق', 'next' => 'التالي »', diff --git a/resources/lang/ar/passwords.php b/resources/lang/ar/passwords.php index 6af597f79..23a8a7e74 100644 --- a/resources/lang/ar/passwords.php +++ b/resources/lang/ar/passwords.php @@ -1,18 +1,11 @@ 'يجب أن تتكون كلمة المرور من ستة أحرف على الأقل وأن تطابق التأكيد.', 'user' => "لم يتم العثور على مستخدم بعنوان البريد الإلكتروني المعطى.", 'token' => 'رابط تجديد كلمة المرور غير صحيح.', diff --git a/resources/lang/ar/settings.php b/resources/lang/ar/settings.php index 850776a59..c3216aa07 100755 --- a/resources/lang/ar/settings.php +++ b/resources/lang/ar/settings.php @@ -1,80 +1,94 @@ 'الإعدادات', 'settings_save' => 'حفظ الإعدادات', 'settings_save_success' => 'تم حفظ الإعدادات', - /** - * App settings - */ - - 'app_settings' => 'إعدادات التطبيق', + // App Settings + 'app_customization' => 'Customization', + 'app_features_security' => 'Features & Security', 'app_name' => 'اسم التطبيق', 'app_name_desc' => 'سيتم عرض هذا الاسم في الترويسة وفي أي رسالة بريد إلكتروني.', 'app_name_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' => 'السماح بالعرض على العامة؟', 'app_secure_images' => 'تفعيل حماية أكبر لرفع الصور؟', + 'app_secure_images_toggle' => 'Enable higher security image uploads', 'app_secure_images_desc' => 'لتحسين أداء النظام, ستكون جميع الصور متاحة للعامة. هذا الخيار يضيف سلسلة من الحروف والأرقام العشوائية صعبة التخمين إلى رابط الصورة. الرجاء التأكد من تعطيل فهرسة المسارات لمنع الوصول السهل.', 'app_editor' => 'محرر الصفحة', 'app_editor_desc' => 'الرجاء اختيار محرر النص الذي سيستخدم من قبل جميع المستخدمين لتحرير الصفحات.', - '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' => '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' => 'شعار التطبيق', 'app_logo_desc' => 'يجب أن تكون الصورة بارتفاع 43 بكسل.
سيتم تصغير الصور الأكبر من ذلك.', 'app_primary_color' => 'اللون الأساسي للتطبيق', 'app_primary_color_desc' => 'يجب أن تكون القيمة من نوع hex.
اترك الخانة فارغة للرجوع للون الافتراضي.', 'app_homepage' => 'الصفحة الرئيسية للتطبيق', 'app_homepage_desc' => 'الرجاء اختيار صفحة لتصبح الصفحة الرئيسية بدل من الافتراضية. سيتم تجاهل جميع الأذونات الخاصة بالصفحة المختارة.', - 'app_homepage_default' => 'شكل الصفحة الافتراضية المختارة', - 'app_homepage_books' => 'أو من الممكن اختيار صفحة الكتب كصفحة رئيسية. سيتم استبدالها بأي صفحة سابقة تم اختيارها كصفحة رئيسية.', + 'app_homepage_select' => 'Select a page', 'app_disable_comments' => 'تعطيل التعليقات', + 'app_disable_comments_toggle' => 'Disable comments', 'app_disable_comments_desc' => 'تعطيل التعليقات على جميع الصفحات داخل التطبيق. التعليقات الموجودة من الأصل لن تكون ظاهرة.', - /** - * Registration settings - */ + // 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' => 'إعدادات التسجيل', - 'reg_allow' => 'السماح بالتسجيل؟', + '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' => 'دور المستخدم الأساسي بعد التسجيل', - 'reg_confirm_email' => 'فرض التأكيد عن طريق البريد الإلكتروني؟', + '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' => 'إذا تم استخدام قيود للمجال سيصبح التأكيد عن طريق البريد الإلكتروني إلزامي وسيتم تجاهل القيمة أسفله.', 'reg_confirm_restrict_domain' => 'تقييد التسجيل على مجال محدد', - '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_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' => 'لم يتم اختيار أي قيود', - /** - * Maintenance settings - */ - + // Maintenance settings 'maint' => 'الصيانة', 'maint_image_cleanup' => 'تنظيف الصور', - '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_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' => 'تجاهل الصور في المراجعات', '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.', - /** - * Role settings - */ - + // Role Settings 'roles' => 'الأدوار', 'role_user_roles' => 'أدوار المستخدمين', 'role_create' => 'إنشاء دور جديد', 'role_create_success' => 'تم إنشاء الدور بنجاح', 'role_delete' => 'حذف الدور', 'role_delete_confirm' => 'سيتم حذف الدور المسمى \':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_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' => "لا تقم بترجيل المستخدمين", 'role_delete_sure' => 'تأكيد حذف الدور؟', 'role_delete_success' => 'تم حذف الدور بنجاح', @@ -82,33 +96,42 @@ return [ 'role_details' => 'تفاصيل الدور', 'role_name' => 'اسم الدور', 'role_desc' => 'وصف مختصر للدور', - 'role_external_auth_id' => 'External Authentication IDs', // جار البحث عن الترجمة الأنسب + 'role_external_auth_id' => 'External Authentication IDs', '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_settings' => 'إدارة إعدادات التطبيق', - 'role_asset' => 'Asset Permissions', // جار البحث عن الترجمة الأنسب - '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' => 'Asset Permissions', + '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' => 'الكل', 'role_own' => 'Own', - 'role_controlled_by_asset' => 'Controlled by the asset they are uploaded to', // جار البحث عن الترجمة الأنسب + 'role_controlled_by_asset' => 'Controlled by the asset they are uploaded to', 'role_save' => 'حفظ الدور', 'role_update_success' => 'تم تحديث الدور بنجاح', 'role_users' => 'مستخدمون داخل هذا الدور', 'role_users_none' => 'لم يتم تعيين أي مستخدمين لهذا الدور', - /** - * Users - */ - + // Users 'users' => 'المستخدمون', 'user_profile' => 'ملف المستخدم', 'users_add_new' => 'إضافة مستخدم جديد', 'users_search' => 'بحث عن مستخدم', + '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' => 'أدوار المستخدمين', - 'users_external_auth_id' => 'External Authentication ID', // جار البحث عن الترجمة الأنسب + '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' => 'الرجاء ملئ الحقل أدناه فقط في حال أردتم تغيير كلمة المرور:', 'users_system_public' => 'هذا المستخدم يمثل أي ضيف يقوم بزيارة شيء يخصك. لا يمكن استخدامه لتسجيل الدخول ولكن يتم تعيينه تلقائياً.', 'users_delete' => 'حذف المستخدم', @@ -122,10 +145,67 @@ return [ 'users_avatar' => 'صورة المستخدم', 'users_avatar_desc' => 'يجب أن تكون الصورة مربعة ومقاربة لحجم 256 بكسل', 'users_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' => 'الحسابات الاجتماعية', - 'users_social_accounts_info' => 'Here you can connect your other accounts for quicker and easier login. Disconnecting an account here does not previously authorized access. Revoke access from your profile settings on the connected social account.', // جار البحث عن الترجمة الأنسب + 'users_social_accounts_info' => 'Here you can connect your other accounts for quicker and easier login. Disconnecting an account here does not previously authorized access. Revoke access from your profile settings on the connected social account.', 'users_social_connect' => 'ربط الحساب', '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', + + // 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' => 'العربية', + 'da' => 'Dansk', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// ]; diff --git a/resources/lang/ar/validation.php b/resources/lang/ar/validation.php index 47035a97d..7d6d13e81 100644 --- a/resources/lang/ar/validation.php +++ b/resources/lang/ar/validation.php @@ -1,25 +1,20 @@ 'يجب الموافقة على :attribute.', 'active_url' => ':attribute ليس رابط صالح.', 'after' => 'يجب أن يكون التاريخ :attribute بعد :date.', 'alpha' => 'يجب أن يقتصر :attribute على الحروف فقط.', 'alpha_dash' => 'يجب أن يقتصر :attribute على حروف أو أرقام أو شرطات فقط.', 'alpha_num' => 'يجب أن يقتصر :attribute على الحروف والأرقام فقط.', - 'array' => 'The :attribute must be an array.', // جار البحث عن الترجمة الأنسب + 'array' => 'The :attribute must be an array.', 'before' => 'يجب أن يكون التاريخ :attribute قبل :date.', 'between' => [ 'numeric' => 'يجب أن يكون :attribute بين :min و :max.', @@ -27,7 +22,7 @@ return [ 'string' => 'يجب أن يكون :attribute بين :min و :max حرف / حروف.', 'array' => 'يجب أن يكون :attribute بين :min و :max عنصر / عناصر.', ], - 'boolean' => 'The :attribute field must be true or false.', // جار البحث عن الترجمة الأنسب + 'boolean' => 'The :attribute field must be true or false.', 'confirmed' => ':attribute غير مطابق.', 'date' => ':attribute ليس تاريخ صالح.', 'date_format' => ':attribute لا يطابق الصيغة :format.', @@ -35,12 +30,41 @@ return [ 'digits' => 'يجب أن يكون :attribute بعدد :digits خانات.', 'digits_between' => 'يجب أن يكون :attribute بعدد خانات بين :min و :max.', 'email' => 'يجب أن يكون :attribute عنوان بريد إلكتروني صالح.', + 'ends_with' => 'The :attribute must end with one of the following: :values', 'filled' => 'حقل :attribute مطلوب.', + '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.', + ], + '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.', + ], 'exists' => ':attribute المحدد غير صالح.', 'image' => 'يجب أن يكون :attribute صورة.', + 'image_extension' => 'The :attribute must have a valid & supported image extension.', 'in' => ':attribute المحدد غير صالح.', 'integer' => 'يجب أن يكون :attribute عدد صحيح.', 'ip' => 'يجب أن يكون :attribute عنوان IP صالح.', + '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.', + '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.', + ], + '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.', + ], 'max' => [ 'numeric' => 'يجب ألا يكون :attribute أكبر من :max.', 'file' => 'يجب ألا يكون :attribute أكبر من :max كيلو بايت.', @@ -54,7 +78,9 @@ 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 رقم.', 'regex' => 'صيغة :attribute غير صالحة.', 'required' => 'حقل :attribute مطلوب.', @@ -70,39 +96,19 @@ return [ 'string' => 'يجب أن يكون :attribute بعدد :size حرف / حروف.', 'array' => 'يجب أن يحتوي :attribute على :size عنصر / عناصر.', ], - 'string' => 'The :attribute must be a string.', // جار البحث عن الترجمة الأنسب + 'string' => 'The :attribute must be a string.', 'timezone' => 'يجب أن تكون :attribute منطقة صالحة.', 'unique' => 'تم حجز :attribute من قبل.', 'url' => 'صيغة :attribute غير صالحة.', + 'uploaded' => 'The file could not be uploaded. The server may not accept files of this size.', - /* - |-------------------------------------------------------------------------- - | Custom Validation Language Lines - |-------------------------------------------------------------------------- - | - | Here you may specify custom validation messages for attributes using the - | convention "attribute.rule" to name the lines. This makes it quick to - | specify a specific custom language line for a given attribute rule. - | - */ - + // Custom validation lines 'custom' => [ 'password-confirm' => [ 'required_with' => 'يجب تأكيد كلمة المرور', ], ], - /* - |-------------------------------------------------------------------------- - | Custom Validation Attributes - |-------------------------------------------------------------------------- - | - | The following language lines are used to swap attribute place-holders - | with something more reader friendly such as E-Mail Address instead - | of "email". This simply helps us make messages a little cleaner. - | - */ - + // Custom validation attributes 'attributes' => [], - ]; diff --git a/resources/lang/check.php b/resources/lang/check.php deleted file mode 100755 index 92a7b1eaf..000000000 --- a/resources/lang/check.php +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env php - $enStr) { - if (strpos($enKey, 'settings.language_select.') === 0) { - unset($langContent[$enKey]); - continue; - } - if (!isset($langContent[$enKey])) { - $missingLangStrings[$enKey] = $enStr; - continue; - } - unset($langContent[$enKey]); -} - -if (count($missingLangStrings) > 0) { - info("\n========================"); - info("Missing language content"); - info("========================"); - outputFlatArray($missingLangStrings, $lang); -} - -if (count($langContent) > 0) { - info("\n=========================="); - info("Redundant language content"); - info("=========================="); - outputFlatArray($langContent, $lang); -} - -function outputFlatArray($arr, $lang) { - $grouped = []; - foreach ($arr as $key => $val) { - $explodedKey = explode('.', $key); - $group = $explodedKey[0]; - $path = implode('.', array_slice($explodedKey, 1)); - if (!isset($grouped[$group])) $grouped[$group] = []; - $grouped[$group][$path] = $val; - } - foreach ($grouped as $filename => $arr) { - echo "\e[36m" . $lang . '/' . $filename . ".php\e[0m\n"; - echo json_encode($arr, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE) . "\n"; - } -} - -function formatLang($lang) { - $langParts = explode('_', strtoupper($lang)); - $langParts[0] = strtolower($langParts[0]); - return implode('_', $langParts); -} - -function loadLang(string $lang) { - $dir = __DIR__ . "/{$lang}"; - if (!file_exists($dir)) { - errorOut("Expected directory '{$dir}' does not exist"); - } - $files = scandir($dir); - $data = []; - foreach ($files as $file) { - if (substr($file, -4) !== '.php') continue; - $fileData = include ($dir . '/' . $file); - $name = substr($file, 0, -4); - $data[$name] = $fileData; - } - return flattenArray($data); -} - -function flattenArray(array $arr) { - $data = []; - foreach ($arr as $key => $arrItem) { - if (!is_array($arrItem)) { - $data[$key] = $arrItem; - continue; - } - - $toUse = flattenArray($arrItem); - foreach ($toUse as $innerKey => $item) { - $data[$key . '.' . $innerKey] = $item; - } - } - return $data; -} - -function info($text) { - echo "\e[34m" . $text . "\e[0m\n"; -} - -function errorOut($text) { - echo "\e[31m" . $text . "\e[0m\n"; - exit(1); -} \ No newline at end of file diff --git a/resources/lang/cs/auth.php b/resources/lang/cs/auth.php index 69d6f0b97..fbda0150d 100644 --- a/resources/lang/cs/auth.php +++ b/resources/lang/cs/auth.php @@ -21,11 +21,13 @@ return [ 'email' => 'Email', 'password' => 'Heslo', 'password_confirm' => 'Potvrdit heslo', - 'password_hint' => 'Musí mít víc než 5 znaků', + 'password_hint' => 'Musí mít víc než 7 znaků', 'forgot_password' => 'Zapomněli jste heslo?', 'remember_me' => 'Neodhlašovat', 'ldap_email_hint' => 'Zadejte email, který chcete přiřadit k tomuto účtu.', 'create_account' => 'Vytvořit účet', + 'already_have_account' => 'Already have an account?', + 'dont_have_account' => 'Don\'t have an account?', 'social_login' => 'Přihlášení přes sociální sítě', 'social_registration' => 'Registrace přes sociální sítě', 'social_registration_text' => 'Registrovat a přihlásit se přes jinou službu', @@ -62,4 +64,14 @@ return [ 'email_not_confirmed_click_link' => 'Klikněte na odkaz v emailu který jsme vám zaslali ihned po registraci.', 'email_not_confirmed_resend' => 'Pokud nemůžete nalézt email v příchozí poště, můžete si jej nechat poslat znovu pomocí formuláře níže.', 'email_not_confirmed_resend_button' => 'Znovu poslat email pro potvrzení emailové adresy', + + // 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!' ]; \ No newline at end of file diff --git a/resources/lang/cs/common.php b/resources/lang/cs/common.php index b06e587d6..52d596838 100644 --- a/resources/lang/cs/common.php +++ b/resources/lang/cs/common.php @@ -11,6 +11,7 @@ return [ 'save' => 'Uložit', 'continue' => 'Pokračovat', 'select' => 'Zvolit', + 'toggle_all' => 'Toggle All', 'more' => 'Více', // Form Labels @@ -23,6 +24,7 @@ return [ // Actions 'actions' => 'Akce', 'view' => 'Pohled', + 'view_all' => 'View All', 'create' => 'Vytvořit', 'update' => 'Aktualizovat', 'edit' => 'Upravit', @@ -36,6 +38,16 @@ return [ 'reset' => 'Reset', 'remove' => 'Odstranit', 'add' => 'Přidat', + 'fullscreen' => 'Fullscreen', + + // 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', // Misc 'deleted_user' => 'Smazaný uživatel', @@ -48,12 +60,18 @@ return [ 'grid_view' => 'Zobrazit dlaždice', 'list_view' => 'Zobrazit seznam', 'default' => 'Výchozí', + 'breadcrumb' => 'Breadcrumb', // Header + 'profile_menu' => 'Profile Menu', 'view_profile' => 'Ukázat profil', 'edit_profile' => 'Upravit profil', + // Layout tabs + 'tab_info' => 'Info', + 'tab_content' => 'Content', + // Email Content 'email_action_help' => 'Pokud se vám nedaří kliknout na tlačítko ":actionText", zkopírujte odkaz níže přímo do webového prohlížeče:', 'email_rights' => 'Všechna práva vyhrazena', -]; \ No newline at end of file +]; diff --git a/resources/lang/cs/entities.php b/resources/lang/cs/entities.php index dbf34850f..579d49127 100644 --- a/resources/lang/cs/entities.php +++ b/resources/lang/cs/entities.php @@ -11,6 +11,7 @@ return [ 'recently_updated_pages' => 'Nedávno aktualizované stránky', 'recently_created_chapters' => 'Nedávno vytvořené kapitoly', 'recently_created_books' => 'Nedávno vytvořené knihy', + 'recently_created_shelves' => 'Recently Created Shelves', 'recently_update' => 'Nedávno aktualizované', 'recently_viewed' => 'Nedávno prohlížené', 'recent_activity' => 'Nedávné činnosti', @@ -67,11 +68,13 @@ return [ // Shelves 'shelf' => 'Knihovna', 'shelves' => 'Knihovny', + 'x_shelves' => ':count Shelf|:count Shelves', 'shelves_long' => 'Knihovny', 'shelves_empty' => 'Žádné knihovny nebyly vytvořeny', 'shelves_create' => 'Vytvořit novou knihovnu', 'shelves_popular' => 'Populární knihovny', 'shelves_new' => 'Nové knihovny', + 'shelves_new_action' => 'New Shelf', 'shelves_popular_empty' => 'Nejpopulárnější knihovny se objeví zde.', 'shelves_new_empty' => 'Nejnovější knihovny se objeví zde.', 'shelves_save' => 'Uložit knihovnu', @@ -102,6 +105,7 @@ return [ 'books_popular' => 'Populární knihy', 'books_recent' => 'Nedávné knihy', 'books_new' => 'Nové knihy', + 'books_new_action' => 'New Book', 'books_popular_empty' => 'Zde budou zobrazeny nejpopulárnější knihy.', 'books_new_empty' => 'Zde budou zobrazeny nově vytvořené knihy.', 'books_create' => 'Vytvořit novou knihu', @@ -117,7 +121,6 @@ return [ 'books_permissions_updated' => 'Práva knihy upravena', 'books_empty_contents' => 'V této knize nebyly vytvořeny žádné stránky ani kapitoly.', 'books_empty_create_page' => 'Vytvořit novou stránku', - 'books_empty_or' => 'nebo', 'books_empty_sort_current_book' => 'Seřadit tuto knihu', 'books_empty_add_chapter' => 'Přidat kapitolu', 'books_permissions_active' => 'Účinná práva knihy', @@ -125,6 +128,11 @@ return [ 'books_navigation' => 'Obsah knihy', 'books_sort' => 'Seřadit obsah knihy', 'books_sort_named' => 'Seřadit knihu :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' => 'Ukázat ostatní knihy', 'books_sort_save' => 'Uložit nové pořadí', @@ -168,7 +176,7 @@ return [ 'pages_delete_confirm' => 'Opravdu chcete tuto stránku smazat?', 'pages_delete_draft_confirm' => 'Opravdu chcete tento koncept stránky smazat?', 'pages_editing_named' => 'Úpravy stránky :pageName', - 'pages_edit_toggle_header' => 'Ukázat hlavičku', + 'pages_edit_draft_options' => 'Draft Options', 'pages_edit_save_draft' => 'Uložit koncept', 'pages_edit_draft' => 'Upravit koncept stránky', 'pages_editing_draft' => 'Úpravy konceptu', @@ -202,6 +210,8 @@ return [ 'pages_revisions_created_by' => 'Vytvořeno uživatelem', 'pages_revisions_date' => 'Datum revize', 'pages_revisions_number' => '#', + 'pages_revisions_numbered' => 'Revision #:id', + 'pages_revisions_numbered_changes' => 'Revision #:id Changes', 'pages_revisions_changelog' => 'Komentáře změn', 'pages_revisions_changes' => 'Změny', 'pages_revisions_current' => 'Aktuální verze', @@ -224,6 +234,7 @@ return [ ], 'pages_draft_discarded' => 'Koncept zahozen. Editor nyní obsahuje aktuální verzi stránky.', 'pages_specific' => 'Konkrétní stránka', + 'pages_is_template' => 'Page Template', // Editor Sidebar 'page_tags' => 'Štítky stránky', @@ -232,9 +243,11 @@ return [ 'shelf_tags' => 'Štítky knihovny', 'tag' => 'Štítek', 'tags' => 'Štítky', + 'tag_name' => 'Tag Name', 'tag_value' => 'Hodnota Štítku (volitelné)', 'tags_explain' => "Přidejte si štítky pro lepší kategorizaci knih. \n Štítky mohou nést i hodnotu pro detailnější klasifikaci.", 'tags_add' => 'Přidat další štítek', + 'tags_remove' => 'Remove this tag', 'attachments' => 'Přílohy', 'attachments_explain' => 'Nahrajte soubory nebo připojte odkazy, které se zobrazí na stránce. Budou k nalezení v postranní liště.', 'attachments_explain_instant_save' => 'Změny zde provedené se okamžitě ukládají.', @@ -260,6 +273,12 @@ return [ 'attachments_file_uploaded' => 'Soubor byl úspěšně nahrán', 'attachments_file_updated' => 'Soubor byl úspěšně aktualizován', 'attachments_link_attached' => 'Odkaz úspěšně přiložen ke stránce', + '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' => 'Uživatelem již :time', @@ -267,6 +286,7 @@ return [ 'profile_not_created_pages' => ':userName nevytvořil/a žádný obsah', 'profile_not_created_chapters' => ':userName nevytvořil/a žádné kapitoly', 'profile_not_created_books' => ':userName nevytvořil/a žádné knihy', + 'profile_not_created_shelves' => ':userName has not created any shelves', // Comments 'comment' => 'Komentář', @@ -288,7 +308,7 @@ return [ // Revision 'revision_delete_confirm' => 'Opravdu chcete smazat tuto revizi?', + 'revision_restore_confirm' => 'Are you sure you want to restore this revision? The current page contents will be replaced.', 'revision_delete_success' => 'Revize smazána', 'revision_cannot_delete_latest' => 'Nelze smazat poslední revizi.' - ]; \ No newline at end of file diff --git a/resources/lang/cs/errors.php b/resources/lang/cs/errors.php index bd9c62bc1..ebcf3f44e 100644 --- a/resources/lang/cs/errors.php +++ b/resources/lang/cs/errors.php @@ -13,10 +13,16 @@ return [ 'email_already_confirmed' => 'Emailová adresa již byla potvrzena. Zkuste se přihlásit.', 'email_confirmation_invalid' => 'Tento potvrzovací odkaz již neplatí nebo už byl použit. Zkuste prosím registraci znovu.', 'email_confirmation_expired' => 'Potvrzovací odkaz už neplatí, email s novým odkazem už byl poslán.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'Přístup k adresáři LDAP jako anonymní uživatel (anonymous bind) selhal', 'ldap_fail_authed' => 'Přístup k adresáři LDAP pomocí zadaného jména (dn) a hesla selhal', 'ldap_extension_not_installed' => 'Není nainstalováno rozšíření LDAP pro PHP', 'ldap_cannot_connect' => 'Nelze se připojit k adresáři LDAP. Prvotní připojení selhalo.', + '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' => 'Nebyla zvolena žádá akce', 'social_login_bad_response' => "Nastala chyba během přihlašování přes :socialAccount \n:error", 'social_account_in_use' => 'Tento účet na :socialAccount se již používá. Pokuste se s ním přihlásit volbou Přihlásit přes :socialAccount.', @@ -27,13 +33,14 @@ return [ 'social_account_register_instructions' => 'Pokud ještě nemáte náš účet, můžete se zaregistrovat pomocí vašeho účtu na :socialAccount.', 'social_driver_not_found' => 'Doplněk pro tohoto správce identity nebyl nalezen.', 'social_driver_not_configured' => 'Nastavení vašeho účtu na :socialAccount není správné. :socialAccount musí mít vaše svolení pro naší aplikaci vás přihlásit.', + 'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.', // System 'path_not_writable' => 'Nelze zapisovat na cestu k souboru :filePath. Zajistěte aby se dalo nahrávat na server.', 'cannot_get_image_from_url' => 'Nelze získat obrázek z adresy :url', 'cannot_create_thumbs' => 'Server nedokáže udělat náhledy. Zkontrolujte, že rozšíření GD pro PHP je nainstalováno.', 'server_upload_limit' => 'Server nepovoluje nahrávat tak veliké soubory. Zkuste prosím menší soubor.', - 'uploaded' => 'Server nepovoluje nahrávat tak veliké soubory. Zkuste prosím menší soubor.', //TODO to je nějaký podezřelý + 'uploaded' => 'Server nepovoluje nahrávat tak veliké soubory. Zkuste prosím menší soubor.', 'image_upload_error' => 'Nastala chyba během nahrávání souboru', 'image_upload_type_error' => 'Typ nahrávaného obrázku je neplatný.', 'file_upload_timeout' => 'Nahrávání souboru trvalo příliš dlouho a tak bylo ukončeno.', @@ -71,7 +78,7 @@ return [ 'cannot_add_comment_to_draft' => 'Nemůžete přidávat komentáře ke konceptu.', 'comment_add' => 'Při přidávání / aktualizaci komentáře nastala chyba.', 'comment_delete' => 'Při mazání komentáře nastala chyba.', - 'empty_comment' => 'Nemůžete přidat prázdný komentář.', //This has a deep thinking value + 'empty_comment' => 'Nemůžete přidat prázdný komentář.', // Error pages '404_page_not_found' => 'Stránka nenalezena', @@ -81,4 +88,12 @@ return [ 'app_down' => ':appName je momentálně vypnutá', 'back_soon' => 'Brzy naběhne.', + // 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', + ]; diff --git a/resources/lang/cs/pagination.php b/resources/lang/cs/pagination.php index de9821522..6281ff058 100644 --- a/resources/lang/cs/pagination.php +++ b/resources/lang/cs/pagination.php @@ -6,7 +6,7 @@ */ return [ - 'previous' => '« Pedchoz', - 'next' => 'Dal »', + 'previous' => '\'« P', + 'next' => 'Dal', ]; diff --git a/resources/lang/cs/settings.php b/resources/lang/cs/settings.php index 1881dffae..7488560a7 100644 --- a/resources/lang/cs/settings.php +++ b/resources/lang/cs/settings.php @@ -12,17 +12,24 @@ return [ 'settings_save_success' => 'Nastavení bylo uloženo', // App Settings - 'app_settings' => 'Nastavení aplikace', + 'app_customization' => 'Customization', + 'app_features_security' => 'Features & Security', 'app_name' => 'Název aplikace', 'app_name_desc' => 'Název se bude zobrazovat v záhlaví této aplikace a v odesílaných emailech.', 'app_name_header' => 'Zobrazovát název aplikace v záhlaví?', + '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' => 'Povolit prohlížení veřejností?', 'app_secure_images' => 'Nahrávat obrázky neveřejně a zabezpečeně?', + 'app_secure_images_toggle' => 'Enable higher security image uploads', 'app_secure_images_desc' => 'Z výkonnostních důvodů jsou všechny obrázky veřejné. Tato volba přidá do adresy obrázku náhodné číslo, aby nikdo neodhadnul adresu obrázku. Zajistěte ať adresáře nikomu nezobrazují seznam souborů.', 'app_editor' => 'Editor stránek', 'app_editor_desc' => 'Zvolte který editor budou užívat všichni uživatelé k úpravě stránek.', 'app_custom_html' => 'Vlastní HTML kód pro sekci hlavičky ().', 'app_custom_html_desc' => 'Cokoliv sem napíšete bude přidáno na konec sekce v každém místě této aplikace. To se hodí pro přidávání nebo změnu CSS stylů nebo přidání kódu pro analýzu používání (např.: google analytics.).', + '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' => 'Logo aplikace', 'app_logo_desc' => 'Obrázek by měl mít 43 pixelů na výšku.
Větší obrázky zmenšíme na tuto velikost.', 'app_primary_color' => 'Hlavní barva aplikace', @@ -31,13 +38,27 @@ return [ 'app_homepage_desc' => 'Zvolte pohled který se objeví jako úvodní stránka po přihlášení. Pokud zvolíte stránku, její specifická oprávnění budou ignorována (výjimka z výjimky 😜).', 'app_homepage_select' => 'Zvolte stránku', 'app_disable_comments' => 'Zakázání komentářů', + 'app_disable_comments_toggle' => 'Disable comments', 'app_disable_comments_desc' => 'Zakáže komentáře napříč všemi stránkami. Existující komentáře se přestanou zobrazovat.', + // 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' => 'Nastavení registrace', - 'reg_allow' => 'Povolit registrace?', + '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' => 'Role přiřazená po registraci', - 'reg_confirm_email' => 'Vyžadovat ověření emailové adresy?', + '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' => 'Pokud zapnete omezení emailové domény, tak bude ověřování emailové adresy vyžadováno vždy.', 'reg_confirm_restrict_domain' => 'Omezit registraci podle domény', 'reg_confirm_restrict_domain_desc' => 'Zadejte emailové domény, kterým bude povolena registrace uživatelů. Oddělujete čárkou. Uživatelům bude odeslán email s odkazem pro potvrzení vlastnictví emailové adresy. Bez potvrzení nebudou moci aplikaci používat.
Pozn.: Uživatelé si mohou emailovou adresu změnit po úspěšné registraci.', @@ -50,9 +71,15 @@ return [ 'maint_image_cleanup_ignore_revisions' => 'Ignorovat obrázky v revizích', 'maint_image_cleanup_run' => 'Spustit pročištění', 'maint_image_cleanup_warning' => 'Nalezeno :count potenciálně nepoužitých obrázků. Jste si jistí, že je chcete smazat?', - 'maint_image_cleanup_success' => 'Potenciálně nepoužité obrázky byly smazány. Celkem :count.', 'maint_image_cleanup_nothing_found' => 'Žádné potenciálně nepoužité obrázky nebyly nalezeny. Nic nebylo smazáno.', + '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.', // Role Settings 'roles' => 'Role', @@ -75,6 +102,8 @@ return [ 'role_manage_roles' => 'Správa rolí a jejich práv', 'role_manage_entity_permissions' => 'Správa práv všech knih, kapitol a stránek', 'role_manage_own_entity_permissions' => 'Správa práv vlastních knih, kapitol a stránek', + 'role_manage_page_templates' => 'Manage page templates', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Správa nastavení aplikace', 'role_asset' => 'Práva děl', 'role_asset_desc' => 'Tato práva řídí přístup k dílům v rámci systému. Specifická práva na knihách, kapitolách a stránkách překryjí tato nastavení.', @@ -92,8 +121,17 @@ return [ 'user_profile' => 'Profil uživatele', 'users_add_new' => 'Přidat nového uživatele', 'users_search' => 'Vyhledávání uživatelů', + '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' => 'Uživatelské role', + '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' => 'Přihlašovací identifikátory třetích stran', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Vyplňujte pouze v případě, že chcete heslo změnit:', 'users_system_public' => 'Symbolizuje libovolného veřejného návštěvníka, který navštívil vaší aplikaci. Nelze ho použít k přihlášení ale je přiřazen automaticky veřejnosti.', 'users_delete' => 'Smazat uživatele', @@ -107,11 +145,67 @@ return [ 'users_avatar' => 'Uživatelský obrázek', 'users_avatar_desc' => 'Obrázek by měl být čtverec 256 pixelů široký. Bude oříznut do kruhu.', 'users_preferred_language' => 'Upřednostňovaný jazyk', + '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' => 'Přidružené účty ze sociálních sítí', - 'users_social_accounts_info' => 'Zde můžete přidat vaše účty ze sociálních sítí pro pohodlnější přihlašování. Zrušení přidružení zde neznamená, že tato aplikace pozbude práva číst detaily z vašeho účtu. Zakázat této aplikaci přístup k detailům vašeho účtu musíte přímo ve vašem profilu na dané sociální síti.', - + 'users_social_accounts_info' => 'Zde můžete přidat vaše účty ze sociálních sítí pro pohodlnější přihlašování. Zrušení přidružení zde neznamená, že tato aplikace pozbude práva číst detaily z vašeho účtu. Zakázat této aplikaci přístup k detailům vašeho účtu musíte přímo ve vašem profilu na dané sociální síti.', 'users_social_connect' => 'Přidružit účet', 'users_social_disconnect' => 'Zrušit přidružení', 'users_social_connected' => 'Účet :socialAccount byl úspěšně přidružen k vašemu profilu.', - 'users_social_disconnected' => 'Přidružení účtu :socialAccount k vašemu profilu bylo úspěšně zrušeno.' + 'users_social_disconnected' => 'Přidružení účtu :socialAccount k vašemu profilu bylo úspěšně zrušeno.', + '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' => 'العربية', + 'da' => 'Dansk', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// ]; diff --git a/resources/lang/cs/validation.php b/resources/lang/cs/validation.php index 3e47fb0c3..13a8f790f 100644 --- a/resources/lang/cs/validation.php +++ b/resources/lang/cs/validation.php @@ -1,27 +1,21 @@ ':attribute musí být přijat.', 'active_url' => ':attribute není platnou URL adresou.', 'after' => ':attribute musí být datum po :date.', - 'after_or_equal' => ':attribute musí být datum :date nebo pozdější.', 'alpha' => ':attribute může obsahovat pouze písmena.', 'alpha_dash' => ':attribute může obsahovat pouze písmena, číslice, pomlčky a podtržítka. České znaky (á, é, í, ó, ú, ů, ž, š, č, ř, ď, ť, ň) nejsou podporovány.', 'alpha_num' => ':attribute může obsahovat pouze písmena a číslice.', 'array' => ':attribute musí být pole.', 'before' => ':attribute musí být datum před :date.', - 'before_or_equal' => 'Datum :attribute musí být před nebo rovno :date.', 'between' => [ 'numeric' => ':attribute musí být hodnota mezi :min a :max.', 'file' => ':attribute musí být větší než :min a menší než :max Kilobytů.', @@ -31,16 +25,12 @@ return [ 'boolean' => ':attribute musí být true nebo false', 'confirmed' => ':attribute nesouhlasí.', 'date' => ':attribute musí být platné datum.', - 'date_equals' => 'The :attribute must be a date equal to :date.', 'date_format' => ':attribute není platný formát data podle :format.', 'different' => ':attribute a :other se musí lišit.', 'digits' => ':attribute musí být :digits pozic dlouhé.', 'digits_between' => ':attribute musí být dlouhé nejméně :min a nejvíce :max pozic.', - 'dimensions' => ':attribute má neplatné rozměry.', - 'distinct' => ':attribute má duplicitní hodnotu.', 'email' => ':attribute není platný formát.', - 'exists' => 'Zvolená hodnota pro :attribute není platná.', - 'file' => ':attribute musí být soubor.', + 'ends_with' => 'The :attribute must end with one of the following: :values', 'filled' => ':attribute musí být vyplněno.', 'gt' => [ 'numeric' => ':attribute musí být větší než :value.', @@ -54,9 +44,10 @@ return [ 'string' => 'Počet znaků :attribute musí být větší nebo rovno :value.', 'array' => 'Pole :attribute musí mít :value prvků nebo více.', ], + 'exists' => 'Zvolená hodnota pro :attribute není platná.', 'image' => ':attribute musí být obrázek.', + 'image_extension' => 'The :attribute must have a valid & supported image extension.', 'in' => 'Zvolená hodnota pro :attribute je neplatná.', - 'in_array' => ':attribute není obsažen v :other.', 'integer' => ':attribute musí být celé číslo.', 'ip' => ':attribute musí být platnou IP adresou.', 'ipv4' => ':attribute musí být platná IPv4 adresa.', @@ -81,21 +72,19 @@ return [ 'array' => ':attribute nemůže obsahovat více než :max prvků.', ], 'mimes' => ':attribute musí být jeden z následujících datových typů :values.', - 'mimetypes' => ':attribute musí být jeden z následujících datových typů :values.', 'min' => [ 'numeric' => ':attribute musí být větší než :min.', 'file' => ':attribute musí být větší než :min kB.', 'string' => ':attribute musí být delší než :min znaků.', 'array' => ':attribute musí obsahovat více než :min prvků.', ], + 'no_double_extension' => 'The :attribute must only have a single file extension.', 'not_in' => 'Zvolená hodnota pro :attribute je neplatná.', 'not_regex' => ':attribute musí být regulární výraz.', 'numeric' => ':attribute musí být číslo.', - 'present' => ':attribute musí být vyplněno.', 'regex' => ':attribute nemá správný formát.', 'required' => ':attribute musí být vyplněno.', 'required_if' => ':attribute musí být vyplněno pokud :other je :value.', - 'required_unless' => ':attribute musí být vyplněno dokud :other je v :values.', 'required_with' => ':attribute musí být vyplněno pokud :values je vyplněno.', 'required_with_all' => ':attribute musí být vyplněno pokud :values je zvoleno.', 'required_without' => ':attribute musí být vyplněno pokud :values není vyplněno.', @@ -107,46 +96,19 @@ return [ 'string' => ':attribute musí být přesně :size znaků dlouhý.', 'array' => ':attribute musí obsahovat právě :size prvků.', ], - 'starts_with' => 'The :attribute must start with one of the following: :values', 'string' => ':attribute musí být řetězec znaků.', 'timezone' => ':attribute musí být platná časová zóna.', 'unique' => ':attribute musí být unikátní.', - 'uploaded' => 'Nahrávání :attribute se nezdařilo.', 'url' => 'Formát :attribute je neplatný.', - 'uuid' => ':attribute musí být validní UUID.', - - /* - |-------------------------------------------------------------------------- - | Custom Validation Language Lines - |-------------------------------------------------------------------------- - | - | Here you may specify custom validation messages for attributes using the - | convention "attribute.rule" to name the lines. This makes it quick to - | specify a specific custom language line for a given attribute rule. - | - */ + 'uploaded' => 'Nahrávání :attribute se nezdařilo.', + // Custom validation lines 'custom' => [ - 'attribute-name' => [ - 'rule-name' => 'custom-message', - ], 'password-confirm' => [ 'required_with' => 'Password confirmation required', ], ], - /* - |-------------------------------------------------------------------------- - | Custom Validation Attributes - |-------------------------------------------------------------------------- - | - | The following language lines are used to swap attribute place-holders - | with something more reader friendly such as E-Mail Address instead - | of "email". This simply helps us make messages a little cleaner. - | - */ - - 'attributes' => [ - 'password' => 'heslo', - ], + // Custom validation attributes + 'attributes' => [], ]; diff --git a/resources/lang/da/activities.php b/resources/lang/da/activities.php new file mode 100644 index 000000000..a72e9210b --- /dev/null +++ b/resources/lang/da/activities.php @@ -0,0 +1,48 @@ + 'oprettede side', + 'page_create_notification' => 'Siden blev oprettet', + 'page_update' => 'opdaterede side', + 'page_update_notification' => 'Siden blev opdateret', + 'page_delete' => 'slettede side', + 'page_delete_notification' => 'Siden blev slettet', + 'page_restore' => 'gendannede side', + 'page_restore_notification' => 'Siden blev gendannet', + 'page_move' => 'flyttede side', + + // Chapters + 'chapter_create' => 'oprettede kapitel', + 'chapter_create_notification' => 'Kapitel blev oprettet', + 'chapter_update' => 'opdaterede kapitel', + 'chapter_update_notification' => 'Kapitel blev opdateret', + 'chapter_delete' => 'slettede kapitel', + 'chapter_delete_notification' => 'Kapitel blev slettet', + 'chapter_move' => 'flyttede kapitel', + + // Books + 'book_create' => 'oprettede bog', + 'book_create_notification' => 'Bogen blev oprettet', + 'book_update' => 'opdaterede bog', + 'book_update_notification' => 'Bogen blev opdateret', + 'book_delete' => 'slettede bog', + 'book_delete_notification' => 'Bogen blev slettet', + 'book_sort' => 'sorterede bogen', + 'book_sort_notification' => 'Bogen blev re-sorteret', + + // Bookshelves + 'bookshelf_create' => 'oprettede bogreol', + 'bookshelf_create_notification' => 'Bogreolen blev oprettet', + 'bookshelf_update' => 'opdaterede bogreolen', + 'bookshelf_update_notification' => 'Bogreolen blev opdateret', + 'bookshelf_delete' => 'slettede bogreol', + 'bookshelf_delete_notification' => 'Bogreolen blev opdateret', + + // Other + 'commented_on' => 'kommenterede til', +]; diff --git a/resources/lang/da/auth.php b/resources/lang/da/auth.php new file mode 100644 index 000000000..fe1b62079 --- /dev/null +++ b/resources/lang/da/auth.php @@ -0,0 +1,77 @@ + 'Det indtastede stemmer ikke overens med vores registrering.', + 'throttle' => 'For mange mislykkede loginforsøg. Prøv igen om :seconds seconds.', + + // Login & Register + 'sign_up' => 'Registrér', + 'log_in' => 'Log ind', + 'log_in_with' => 'Log ind med :socialDriver', + 'sign_up_with' => 'Registrér med :socialDriver', + 'logout' => 'Log ud', + + 'name' => 'Navn', + 'username' => 'Brugernavn', + 'email' => 'E-mail', + 'password' => 'Adgangskode', + 'password_confirm' => 'Bekræft adgangskode', + 'password_hint' => 'Skal være på mindst 8 karakterer', + 'forgot_password' => 'Glemt Adgangskode?', + 'remember_me' => 'Husk Mig', + 'ldap_email_hint' => 'Angiv venligst din kontos e-mail.', + 'create_account' => 'Opret Konto', + 'already_have_account' => 'Har du allerede en konto?', + 'dont_have_account' => 'Har du ikke en konto?', + 'social_login' => 'Social Log ind', + 'social_registration' => 'Social Registrering', + 'social_registration_text' => 'Registrér og log ind med anden service.', + + 'register_thanks' => 'Tak for registreringen!', + 'register_confirm' => 'Check venligst din e-mail og klik deri på bekræftelses knappen for at tilgå :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.', + + + // 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_success' => 'A password reset link has been sent to :email.', + '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.', + + + // 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_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', + + // 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!' +]; \ No newline at end of file diff --git a/resources/lang/da/common.php b/resources/lang/da/common.php new file mode 100644 index 000000000..be37d11ae --- /dev/null +++ b/resources/lang/da/common.php @@ -0,0 +1,77 @@ + 'Annuller', + 'confirm' => 'Bekræft', + 'back' => 'Tilbage', + 'save' => 'Gem', + 'continue' => 'Fortsæt', + 'select' => 'Vælg', + 'toggle_all' => 'Vælg/Fravælg alle', + 'more' => 'Mere', + + // Form Labels + 'name' => 'Navn', + 'description' => 'Beskrivelse', + 'role' => 'Rolle', + 'cover_image' => 'Coverbillede', + 'cover_image_description' => 'This image should be approx 440x250px.', + + // Actions + 'actions' => 'Actions', + 'view' => 'Vis', + 'view_all' => 'Vis alle', + 'create' => 'Opret', + 'update' => 'Opdater', + 'edit' => 'Rediger', + 'sort' => 'Sorter', + 'move' => 'Flyt', + 'copy' => 'Kopier', + 'reply' => 'Besvar', + 'delete' => 'Slet', + 'search' => 'Søg', + 'search_clear' => 'Ryd søgning', + 'reset' => 'Nulstil', + 'remove' => 'Fjern', + 'add' => 'Tilføj', + 'fullscreen' => 'Fuld skærm', + + // Sort Options + 'sort_options' => 'Sorteringsindstillinger', + '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', + + // 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', + + // Header + 'profile_menu' => 'Profile Menu', + 'view_profile' => 'View Profile', + 'edit_profile' => 'Edit Profile', + + // Layout tabs + 'tab_info' => 'Info', + 'tab_content' => 'Content', + + // 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', +]; diff --git a/resources/lang/da/errors.php b/resources/lang/da/errors.php new file mode 100644 index 000000000..e92dab45c --- /dev/null +++ b/resources/lang/da/errors.php @@ -0,0 +1,99 @@ + 'Du har ikke tilladelse til at tilgå den efterspurgte side.', + 'permissionJson' => 'Du har ikke tilladelse til at udføre den valgte handling.', + + // Auth + 'error_user_exists_different_creds' => 'En bruger med email :email eksistere allerede, men med andre legitimationsoplysninger.', + 'email_already_confirmed' => 'Email er allerede bekræftet. Prøv at logge ind.', + 'email_confirmation_invalid' => 'Denne bekræftelsestoken er ikke gyldig eller er allerede blevet brugt. Prøv at registrere dig igen.', + 'email_confirmation_expired' => 'Bekræftelsestoken er udløbet. En ny bekræftelsesmail er blevet sendt.', + '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 adgang fejlede med de givne DN & kodeord oplysninger', + 'ldap_extension_not_installed' => 'LDAP PHP udvidelse er ikke installeret', + 'ldap_cannot_connect' => 'Kan ikke forbinde til ldap server. Indledende forbindelse mislykkedes', + 'saml_already_logged_in' => 'Allerede logget ind', + 'saml_user_not_registered' => 'Brugeren :name er ikke registreret, og automatisk registrering er slået fra', + '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.', + + // 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.', + + // Attachments + 'attachment_page_mismatch' => 'Page mismatch during attachment update', + 'attachment_not_found' => 'Attachment not found', + + // 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', + + // 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', + + // Users + 'users_cannot_delete_only_admin' => 'You cannot delete the only admin', + 'users_cannot_delete_guest' => 'You cannot delete the guest user', + + // 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.', + + // 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.', + + // Error pages + '404_page_not_found' => 'Page Not Found', + 'sorry_page_not_found' => 'Sorry, The page you were looking for could not be found.', + '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.', + + // 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', + +]; diff --git a/resources/lang/da/passwords.php b/resources/lang/da/passwords.php new file mode 100644 index 000000000..b4ace5513 --- /dev/null +++ b/resources/lang/da/passwords.php @@ -0,0 +1,15 @@ + 'Adgangskoder skal være mindst otte tegn og svare til bekræftelsen.', + 'user' => "Vi kan ikke finde en bruger med den e-mail adresse.", + 'token' => 'Denne adgangskode nulstillingstoken er ugyldig.', + 'sent' => 'Vi har sendt dig en e-mail med et link til at nulstille adgangskoden!', + 'reset' => 'Dit kodeord er blevet nulstillet!', + +]; diff --git a/resources/lang/da/settings.php b/resources/lang/da/settings.php new file mode 100644 index 000000000..b653f0950 --- /dev/null +++ b/resources/lang/da/settings.php @@ -0,0 +1,211 @@ + 'Indstillinger', + 'settings_save' => 'Gem indstillinger', + 'settings_save_success' => 'Indstillinger gemt', + + // 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' => 'Offentlig adgang', + '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' => 'Tillad offentlig adgang', + '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' => 'Vælg en side', + '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' => 'Sidefarve', + 'page_draft_color' => 'Page Draft Color', + + // Registration Settings + 'reg_settings' => 'Registrering', + 'reg_enable' => 'Aktivér tilmelding', + 'reg_enable_toggle' => 'Aktivér tilmelding', + '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 bekræftelse', + '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' => 'Vedligeholdelse', + '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.', + + // Role Settings + 'roles' => 'Roller', + 'role_user_roles' => 'Brugerroller', + 'role_create' => 'Opret en ny rolle', + 'role_create_success' => 'Rollen blev oprette korrekt', + 'role_delete' => 'Slet rolle', + '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' => 'Rediger rolle', + 'role_details' => 'Role Details', + 'role_name' => 'Rollenavn', + 'role_desc' => 'Short Description of Role', + 'role_external_auth_id' => 'External Authentication IDs', + 'role_system' => 'System Permissions', + 'role_manage_users' => 'Administrere brugere', + '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', + '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' => 'Alle', + 'role_own' => 'Eget', + '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' => 'Brugere', + 'user_profile' => 'Brugerprofil', + 'users_add_new' => 'Tilføj ny bruger', + 'users_search' => 'Søg efter brugere', + 'users_details' => 'Brugeroplysninger', + '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' => 'Brugerroller', + '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' => 'Ekstern godkendelses 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 kontoen blev knyttet til din profil.', + 'users_social_disconnected' => ':socialAccount kontoen blev afbrudt fra din profil.', + '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' => 'العربية', + 'da' => 'Dansk', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// +]; diff --git a/resources/lang/de/activities.php b/resources/lang/de/activities.php index 35b2c9f8a..fadf5d638 100644 --- a/resources/lang/de/activities.php +++ b/resources/lang/de/activities.php @@ -1,44 +1,42 @@ 'erstellt Seite', + 'page_create' => 'erstellte Seite', 'page_create_notification' => 'Die Seite wurde erfolgreich erstellt.', - 'page_update' => 'aktualisiert Seite', + 'page_update' => 'aktualisierte Seite', 'page_update_notification' => 'Die Seite wurde erfolgreich aktualisiert.', - 'page_delete' => 'löscht Seite', + 'page_delete' => 'gelöschte Seite', 'page_delete_notification' => 'Die Seite wurde erfolgreich gelöscht.', - 'page_restore' => 'stellt Seite wieder her', + 'page_restore' => 'wiederhergestellte Seite', 'page_restore_notification' => 'Die Seite wurde erfolgreich wiederhergestellt.', - 'page_move' => 'verschiebt Seite', + 'page_move' => 'Seite verschoben', // Chapters - 'chapter_create' => 'erstellt Kapitel', + 'chapter_create' => 'erstellte Kapitel', 'chapter_create_notification' => 'Das Kapitel wurde erfolgreich erstellt.', - 'chapter_update' => 'aktualisiert Kapitel', + 'chapter_update' => 'aktualisierte Kapitel', 'chapter_update_notification' => 'Das Kapitel wurde erfolgreich aktualisiert.', - 'chapter_delete' => 'löscht Kapitel', + 'chapter_delete' => 'löschte Kapitel', 'chapter_delete_notification' => 'Das Kapitel wurde erfolgreich gelöscht.', - 'chapter_move' => 'verschiebt Kapitel', + 'chapter_move' => 'verschob Kapitel', // Books - 'book_create' => 'erstellt Buch', + 'book_create' => 'erstellte Buch', 'book_create_notification' => 'Das Buch wurde erfolgreich erstellt.', - 'book_update' => 'aktualisiert Buch', + 'book_update' => 'aktualisierte Buch', 'book_update_notification' => 'Das Buch wurde erfolgreich aktualisiert.', - 'book_delete' => 'löscht Buch', + 'book_delete' => 'löschte Buch', 'book_delete_notification' => 'Das Buch wurde erfolgreich gelöscht.', - 'book_sort' => 'sortiert Buch', + 'book_sort' => 'sortierte Buch', 'book_sort_notification' => 'Das Buch wurde erfolgreich umsortiert.', // Bookshelves - 'bookshelf_create' => 'erstellt Bücherregal', + 'bookshelf_create' => 'erstellt Bücherregal', 'bookshelf_create_notification' => 'Das Bücherregal wurde erfolgreich erstellt', 'bookshelf_update' => 'aktualisiert Bücherregal', 'bookshelf_update_notification' => 'Das Bücherregal wurde erfolgreich aktualisiert', diff --git a/resources/lang/de/auth.php b/resources/lang/de/auth.php index 46d4070b8..7216ffe48 100644 --- a/resources/lang/de/auth.php +++ b/resources/lang/de/auth.php @@ -1,31 +1,27 @@ 'Die eingegebenen Anmeldedaten sind ungültig.', 'throttle' => 'Zu viele Anmeldeversuche. Bitte versuchen Sie es in :seconds Sekunden erneut.', - /** - * Login & Register - */ + + // Login & Register 'sign_up' => 'Registrieren', 'log_in' => 'Anmelden', 'log_in_with' => 'Anmelden mit :socialDriver', 'sign_up_with' => 'Registrieren mit :socialDriver', 'logout' => 'Abmelden', + 'name' => 'Name', 'username' => 'Benutzername', 'email' => 'E-Mail', 'password' => 'Passwort', 'password_confirm' => 'Passwort bestätigen', - 'password_hint' => 'Mindestlänge: 5 Zeichen', + 'password_hint' => 'Mindestlänge: 7 Zeichen', 'forgot_password' => 'Passwort vergessen?', 'remember_me' => 'Angemeldet bleiben', 'ldap_email_hint' => 'Bitte geben Sie eine E-Mail-Adresse ein, um diese mit dem Account zu nutzen.', @@ -35,14 +31,15 @@ return [ 'social_login' => 'Mit Sozialem Netzwerk anmelden', 'social_registration' => 'Mit Sozialem Netzwerk registrieren', 'social_registration_text' => 'Mit einer dieser Dienste registrieren oder anmelden', + 'register_thanks' => 'Vielen Dank für Ihre Registrierung!', 'register_confirm' => 'Bitte prüfen Sie Ihren Posteingang und bestätigen Sie die Registrierung.', 'registrations_disabled' => 'Eine Registrierung ist momentan nicht möglich', 'registration_email_domain_invalid' => 'Sie können sich mit dieser E-Mail nicht registrieren.', 'register_success' => 'Vielen Dank für Ihre Registrierung! Die Daten sind gespeichert und Sie sind angemeldet.', - /** - * Password Reset - */ + + + // Password Reset 'reset_password' => 'Passwort vergessen', 'reset_password_send_instructions' => 'Bitte geben Sie Ihre E-Mail-Adresse ein. Danach erhalten Sie eine E-Mail mit einem Link zum Zurücksetzen Ihres Passwortes.', 'reset_password_send_button' => 'Passwort zurücksetzen', @@ -51,9 +48,9 @@ return [ 'email_reset_subject' => 'Passwort zurücksetzen für :appName', 'email_reset_text' => 'Sie erhalten diese E-Mail, weil jemand versucht hat, Ihr Passwort zurückzusetzen.', 'email_reset_not_requested' => 'Wenn Sie das nicht waren, brauchen Sie nichts weiter zu tun.', - /** - * Email Confirmation - */ + + + // Email Confirmation 'email_confirm_subject' => 'Bestätigen Sie Ihre E-Mail-Adresse für :appName', 'email_confirm_greeting' => 'Danke, dass Sie sich für :appName registriert haben!', 'email_confirm_text' => 'Bitte bestätigen Sie Ihre E-Mail-Adresse, indem Sie auf die Schaltfläche klicken:', @@ -61,9 +58,20 @@ return [ 'email_confirm_send_error' => 'Leider konnte die für die Registrierung notwendige E-Mail zur bestätigung Ihrer E-Mail-Adresse nicht versandt werden. Bitte kontaktieren Sie den Systemadministrator!', 'email_confirm_success' => 'Ihre E-Mail-Adresse wurde bestätigt!', 'email_confirm_resent' => 'Bestätigungs-E-Mail wurde erneut versendet, bitte überprüfen Sie Ihren Posteingang.', + 'email_not_confirmed' => 'E-Mail-Adresse ist nicht bestätigt', 'email_not_confirmed_text' => 'Ihre E-Mail-Adresse ist bisher nicht bestätigt.', 'email_not_confirmed_click_link' => 'Bitte klicken Sie auf den Link in der E-Mail, die Sie nach der Registrierung erhalten haben.', 'email_not_confirmed_resend' => 'Wenn Sie die E-Mail nicht erhalten haben, können Sie die Nachricht erneut anfordern. Füllen Sie hierzu bitte das folgende Formular aus:', 'email_not_confirmed_resend_button' => 'Bestätigungs-E-Mail erneut senden', -]; + + // User Invite + 'user_invite_email_subject' => 'Du wurdest eingeladen :appName beizutreten!', + 'user_invite_email_greeting' => 'Ein Konto wurde für Sie auf :appName erstellt.', + 'user_invite_email_text' => 'Klicken Sie auf die Schaltfläche unten, um ein Passwort festzulegen und Zugriff zu erhalten:', + 'user_invite_email_action' => 'Account-Passwort festlegen', + 'user_invite_page_welcome' => 'Willkommen bei :appName!', + 'user_invite_page_text' => 'Um die Anmeldung abzuschließen und Zugriff auf :appName zu bekommen muss noch ein Passwort festgelegt werden. Dieses wird in Zukunft zum Einloggen benötigt.', + 'user_invite_page_confirm_button' => 'Passwort wiederholen', + 'user_invite_success' => 'Passwort gesetzt, Sie haben nun Zugriff auf :appName!' +]; \ No newline at end of file diff --git a/resources/lang/de/common.php b/resources/lang/de/common.php index 97b48ce4d..402e2b36d 100644 --- a/resources/lang/de/common.php +++ b/resources/lang/de/common.php @@ -1,9 +1,10 @@ 'Abbrechen', 'confirm' => 'Bestätigen', 'back' => 'Zurück', @@ -13,18 +14,14 @@ return [ 'toggle_all' => 'Alle umschalten', 'more' => 'Mehr', - /** - * Form Labels - */ + // Form Labels 'name' => 'Name', 'description' => 'Beschreibung', 'role' => 'Rolle', 'cover_image' => 'Titelbild', 'cover_image_description' => 'Das Bild sollte eine Auflösung von 440x250px haben.', - - /** - * Actions - */ + + // Actions 'actions' => 'Aktionen', 'view' => 'Anzeigen', 'view_all' => 'Alle anzeigen', @@ -41,15 +38,18 @@ return [ 'reset' => 'Zurücksetzen', 'remove' => 'Entfernen', 'add' => 'Hinzufügen', + 'fullscreen' => 'Vollbild', // Sort Options + 'sort_options' => 'Sortieroptionen', + 'sort_direction_toggle' => 'Sortierreihenfolge umkehren', + 'sort_ascending' => 'Aufsteigend sortieren', + 'sort_descending' => 'Absteigend sortieren', 'sort_name' => 'Name', 'sort_created_at' => 'Erstellungsdatum', 'sort_updated_at' => 'Aktualisierungsdatum', - /** - * Misc - */ + // Misc 'deleted_user' => 'Gelöschte Benutzer', 'no_activity' => 'Keine Aktivitäten zum Anzeigen', 'no_items' => 'Keine Einträge gefunden.', @@ -60,10 +60,10 @@ return [ 'grid_view' => 'Gitteransicht', 'list_view' => 'Listenansicht', 'default' => 'Voreinstellung', + 'breadcrumb' => 'Brotkrumen', - /** - * Header - */ + // Header + 'profile_menu' => 'Profilmenü', 'view_profile' => 'Profil ansehen', 'edit_profile' => 'Profil bearbeiten', @@ -71,9 +71,7 @@ return [ 'tab_info' => 'Info', 'tab_content' => 'Inhalt', - /** - * Email Content - */ + // 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', ]; diff --git a/resources/lang/de/components.php b/resources/lang/de/components.php index af07f2698..4e56722a8 100644 --- a/resources/lang/de/components.php +++ b/resources/lang/de/components.php @@ -1,8 +1,10 @@ 'Bild auswählen', 'image_all' => 'Alle', 'image_all_title' => 'Alle Bilder anzeigen', @@ -22,9 +24,8 @@ return [ 'image_update_success' => 'Bilddetails erfolgreich aktualisiert', 'image_delete_success' => 'Bild erfolgreich gelöscht', 'image_upload_remove' => 'Entfernen', - /** - * Code editor - */ + + // Code Editor 'code_editor' => 'Code editieren', 'code_language' => 'Code Sprache', 'code_content' => 'Code Inhalt', diff --git a/resources/lang/de/entities.php b/resources/lang/de/entities.php index d67419543..e666c664c 100644 --- a/resources/lang/de/entities.php +++ b/resources/lang/de/entities.php @@ -1,8 +1,11 @@ 'Kürzlich angelegt', 'recently_created_pages' => 'Kürzlich angelegte Seiten', 'recently_updated_pages' => 'Kürzlich aktualisierte Seiten', @@ -30,16 +33,14 @@ return [ 'export_html' => 'HTML-Datei', 'export_pdf' => 'PDF-Datei', 'export_text' => 'Textdatei', - /** - * Permissions and restrictions - */ + + // Permissions and restrictions 'permissions' => 'Berechtigungen', 'permissions_intro' => 'Wenn individuelle Berechtigungen aktiviert werden, überschreiben diese Einstellungen durch Rollen zugewiesene Berechtigungen.', 'permissions_enable' => 'Individuelle Berechtigungen aktivieren', 'permissions_save' => 'Berechtigungen speichern', - /** - * Search - */ + + // Search 'search_results' => 'Suchergebnisse', 'search_total_results_found' => ':count Ergebnis gefunden|:count Ergebnisse gesamt', 'search_clear' => 'Filter löschen', @@ -64,9 +65,7 @@ return [ 'search_set_date' => 'Datum auswählen', 'search_update' => 'Suche aktualisieren', - /* - * Shelves - */ + // Shelves 'shelf' => 'Regal', 'shelves' => 'Regale', 'x_shelves' => ':count Regal|:count Regale', @@ -98,9 +97,7 @@ return [ 'shelves_copy_permissions_explain' => 'Hiermit werden die Berechtigungen des aktuellen Regals auf alle enthaltenen Bücher übertragen. Überprüfen Sie vor der Aktivierung, ob alle Berechtigungsänderungen am aktuellen Regal gespeichert wurden.', 'shelves_copy_permission_success' => 'Regal-Berechtigungen wurden zu :count Büchern kopiert', - /** - * Books - */ + // Books 'book' => 'Buch', 'books' => 'Bücher', 'x_books' => ':count Buch|:count Bücher', @@ -138,9 +135,8 @@ return [ 'books_sort_chapters_last' => 'Kapitel zuletzt', 'books_sort_show_other' => 'Andere Bücher anzeigen', 'books_sort_save' => 'Neue Reihenfolge speichern', - /** - * Chapters - */ + + // Chapters 'chapter' => 'Kapitel', 'chapters' => 'Kapitel', 'x_chapters' => ':count Kapitel', @@ -157,17 +153,13 @@ return [ 'chapters_move' => 'Kapitel verschieben', 'chapters_move_named' => 'Kapitel ":chapterName" verschieben', 'chapter_move_success' => 'Das Kapitel wurde in das Buch ":bookName" verschoben.', - 'pages_copy' => 'Seite kopieren', - 'pages_copy_desination' => 'Ziel', - 'pages_copy_success' => 'Seite erfolgreich kopiert', 'chapters_permissions' => 'Kapitel-Berechtigungen', 'chapters_empty' => 'Aktuell sind keine Kapitel diesem Buch hinzugefügt worden.', 'chapters_permissions_active' => 'Kapitel-Berechtigungen aktiv', 'chapters_permissions_success' => 'Kapitel-Berechtigungenen aktualisisert', 'chapters_search_this' => 'Dieses Kapitel durchsuchen', - /** - * Pages - */ + + // Pages 'page' => 'Seite', 'pages' => 'Seiten', 'x_pages' => ':count Seite|:count Seiten', @@ -184,7 +176,7 @@ return [ 'pages_delete_confirm' => 'Sind Sie sicher, dass Sie diese Seite löschen möchen?', 'pages_delete_draft_confirm' => 'Sind Sie sicher, dass Sie diesen Seitenentwurf löschen möchten?', 'pages_editing_named' => 'Seite ":pageName" bearbeiten', - 'pages_edit_toggle_header' => 'Hauptmenü anzeigen/verstecken', + 'pages_edit_draft_options' => 'Entwurfsoptionen', 'pages_edit_save_draft' => 'Entwurf speichern', 'pages_edit_draft' => 'Seitenentwurf bearbeiten', 'pages_editing_draft' => 'Seitenentwurf bearbeiten', @@ -206,6 +198,9 @@ return [ 'pages_not_in_chapter' => 'Seite ist in keinem Kapitel', 'pages_move' => 'Seite verschieben', 'pages_move_success' => 'Seite nach ":parentName" verschoben', + 'pages_copy' => 'Seite kopieren', + 'pages_copy_desination' => 'Ziel', + 'pages_copy_success' => 'Seite erfolgreich kopiert', 'pages_permissions' => 'Seiten Berechtigungen', 'pages_permissions_success' => 'Seiten Berechtigungen aktualisiert', 'pages_revision' => 'Version', @@ -215,6 +210,8 @@ return [ 'pages_revisions_created_by' => 'Erstellt von', 'pages_revisions_date' => 'Versionsdatum', 'pages_revisions_number' => '#', + 'pages_revisions_numbered' => 'Revision #:id', + 'pages_revisions_numbered_changes' => 'Revision #:id Änderungen', 'pages_revisions_changelog' => 'Änderungsprotokoll', 'pages_revisions_changes' => 'Änderungen', 'pages_revisions_current' => 'Aktuelle Version', @@ -236,18 +233,21 @@ return [ 'message' => ':start :time. Achten Sie darauf, keine Änderungen von anderen Benutzern zu überschreiben!', ], 'pages_draft_discarded' => 'Entwurf verworfen. Der aktuelle Seiteninhalt wurde geladen.', - /** - * Editor sidebar - */ + 'pages_specific' => 'Spezifische Seite', + 'pages_is_template' => 'Seitenvorlage', + + // Editor Sidebar 'page_tags' => 'Seiten-Schlagwörter', 'chapter_tags' => 'Kapitel-Schlagwörter', 'book_tags' => 'Buch-Schlagwörter', 'shelf_tags' => 'Regal-Schlagwörter', 'tag' => 'Schlagwort', 'tags' => 'Schlagwörter', + 'tag_name' => 'Schlagwort Name', 'tag_value' => 'Inhalt (Optional)', 'tags_explain' => "Fügen Sie Schlagwörter hinzu, um Ihren Inhalt zu kategorisieren.\nSie können einen erklärenden Inhalt hinzufügen, um eine genauere Unterteilung vorzunehmen.", 'tags_add' => 'Weiteres Schlagwort hinzufügen', + 'tags_remove' => 'Diesen Tag entfernen', 'attachments' => 'Anhänge', 'attachments_explain' => 'Sie können auf Ihrer Seite Dateien hochladen oder Links hinzufügen. Diese werden in der Seitenleiste angezeigt.', 'attachments_explain_instant_save' => 'Änderungen werden direkt gespeichert.', @@ -273,18 +273,22 @@ return [ 'attachments_file_uploaded' => 'Datei erfolgreich hochgeladen', 'attachments_file_updated' => 'Datei erfolgreich aktualisiert', 'attachments_link_attached' => 'Link erfolgreich der Seite hinzugefügt', - /** - * Profile View - */ + 'templates' => 'Vorlagen', + 'templates_set_as_template' => 'Seite ist eine Vorlage', + 'templates_explain_set_as_template' => 'Sie können diese Seite als Vorlage festlegen, damit deren Inhalt beim Erstellen anderer Seiten verwendet werden kann. Andere Benutzer können diese Vorlage verwenden, wenn sie die Zugriffsrechte für diese Seite haben.', + 'templates_replace_content' => 'Seiteninhalt ersetzen', + 'templates_append_content' => 'An Seiteninhalt anhängen', + 'templates_prepend_content' => 'Seiteninhalt voranstellen', + + // Profile View 'profile_user_for_x' => 'Benutzer seit :time', 'profile_created_content' => 'Erstellte Inhalte', 'profile_not_created_pages' => ':userName hat noch keine Seiten erstellt.', 'profile_not_created_chapters' => ':userName hat noch keine Kapitel erstellt.', 'profile_not_created_books' => ':userName hat noch keine Bücher erstellt.', 'profile_not_created_shelves' => ':userName hat noch keine Regale erstellt.', - /** - * Comments - */ + + // Comments 'comment' => 'Kommentar', 'comments' => 'Kommentare', 'comment_add' => 'Kommentieren', @@ -302,11 +306,9 @@ return [ 'comment_delete_confirm' => 'Möchten Sie diesen Kommentar wirklich löschen?', 'comment_in_reply_to' => 'Antwort auf :commentId', - /** - * Revision - */ + // Revision 'revision_delete_confirm' => 'Sind Sie sicher, dass Sie diese Revision löschen wollen?', 'revision_restore_confirm' => 'Sind Sie sicher, dass Sie diese Revision wiederherstellen wollen? Der aktuelle Seiteninhalt wird ersetzt.', 'revision_delete_success' => 'Revision gelöscht', 'revision_cannot_delete_latest' => 'Die letzte Version kann nicht gelöscht werden.' -]; +]; \ No newline at end of file diff --git a/resources/lang/de/errors.php b/resources/lang/de/errors.php index 362641bc8..1b81bf36e 100644 --- a/resources/lang/de/errors.php +++ b/resources/lang/de/errors.php @@ -1,20 +1,28 @@ 'Sie haben keine Berechtigung, auf diese Seite zuzugreifen.', 'permissionJson' => 'Sie haben keine Berechtigung, die angeforderte Aktion auszuführen.', + // Auth 'error_user_exists_different_creds' => 'Ein Benutzer mit der E-Mail-Adresse :email ist bereits mit anderen Anmeldedaten registriert.', 'email_already_confirmed' => 'Die E-Mail-Adresse ist bereits bestätigt. Bitte melden Sie sich an.', 'email_confirmation_invalid' => 'Der Bestätigungslink ist nicht gültig oder wurde bereits verwendet. Bitte registrieren Sie sich erneut.', 'email_confirmation_expired' => 'Der Bestätigungslink ist abgelaufen. Es wurde eine neue Bestätigungs-E-Mail gesendet.', + 'email_confirmation_awaiting' => 'Die E-Mail-Adresse für das verwendete Konto muss bestätigt werden', 'ldap_fail_anonymous' => 'Anonymer LDAP-Zugriff ist fehlgeschlafgen', 'ldap_fail_authed' => 'LDAP-Zugriff mit DN und Passwort ist fehlgeschlagen', 'ldap_extension_not_installed' => 'LDAP-PHP-Erweiterung ist nicht installiert.', 'ldap_cannot_connect' => 'Die Verbindung zum LDAP-Server ist fehlgeschlagen. Beim initialen Verbindungsaufbau trat ein Fehler auf.', + 'saml_already_logged_in' => 'Sie sind bereits angemeldet', + 'saml_user_not_registered' => 'Kein Benutzer mit ID :name registriert und die automatische Registrierung ist deaktiviert', + 'saml_no_email_address' => 'Es konnte keine E-Mail-Adresse für diesen Benutzer in den vom externen Authentifizierungssystem zur Verfügung gestellten Daten gefunden werden', + 'saml_invalid_response_id' => 'Die Anfrage vom externen Authentifizierungssystem wird von einem von dieser Anwendung gestarteten Prozess nicht erkannt. Das Zurückgehen nach einem Login könnte dieses Problem verursachen.', + 'saml_fail_authed' => 'Anmeldung mit :system fehlgeschlagen, System konnte keine erfolgreiche Autorisierung bereitstellen', 'social_no_action_defined' => 'Es ist keine Aktion definiert', 'social_login_bad_response' => "Fehler bei der :socialAccount-Anmeldung: \n:error", 'social_account_in_use' => 'Dieses :socialAccount-Konto wird bereits verwendet. Bitte melden Sie sich mit dem :socialAccount-Konto an.', @@ -25,6 +33,8 @@ return [ 'social_account_register_instructions' => 'Wenn Sie bisher keinen Social-Media Konto besitzen, können Sie ein solches Konto mit der :socialAccount Option anlegen.', 'social_driver_not_found' => 'Treiber für Social-Media-Konten nicht gefunden', 'social_driver_not_configured' => 'Ihr :socialAccount-Konto ist nicht korrekt konfiguriert.', + 'invite_token_expired' => 'Dieser Einladungslink ist abgelaufen. Sie können stattdessen versuchen, Ihr Passwort zurückzusetzen.', + // System 'path_not_writable' => 'Die Datei kann nicht in den angegebenen Pfad :filePath hochgeladen werden. Stellen Sie sicher, dass dieser Ordner auf dem Server beschreibbar ist.', 'cannot_get_image_from_url' => 'Bild konnte nicht von der URL :url geladen werden.', @@ -38,21 +48,25 @@ return [ // Attachments 'attachment_page_mismatch' => 'Die Seite stimmte nach dem Hochladen des Anhangs nicht überein.', 'attachment_not_found' => 'Anhang konnte nicht gefunden werden.', + // Pages 'page_draft_autosave_fail' => 'Fehler beim Speichern des Entwurfs. Stellen Sie sicher, dass Sie mit dem Internet verbunden sind, bevor Sie den Entwurf dieser Seite speichern.', 'page_custom_home_deletion' => 'Eine als Startseite gesetzte Seite kann nicht gelöscht werden.', + // Entities 'entity_not_found' => 'Eintrag nicht gefunden', - 'book_not_found' => 'Buch nicht gefunden', 'bookshelf_not_found' => 'Regal nicht gefunden', + 'book_not_found' => 'Buch nicht gefunden', 'page_not_found' => 'Seite nicht gefunden', 'chapter_not_found' => 'Kapitel nicht gefunden', 'selected_book_not_found' => 'Das gewählte Buch wurde nicht gefunden.', 'selected_book_chapter_not_found' => 'Das gewählte Buch oder Kapitel wurde nicht gefunden.', 'guests_cannot_save_drafts' => 'Gäste können keine Entwürfe speichern', + // Users 'users_cannot_delete_only_admin' => 'Sie können den einzigen Administrator nicht löschen.', 'users_cannot_delete_guest' => 'Sie können den Gast-Benutzer nicht löschen', + // Roles 'role_cannot_be_edited' => 'Diese Rolle kann nicht bearbeitet werden.', 'role_system_cannot_be_deleted' => 'Dies ist eine Systemrolle und kann nicht gelöscht werden', @@ -65,11 +79,21 @@ return [ 'comment_add' => 'Beim Hinzufügen des Kommentars ist ein Fehler aufgetreten.', 'comment_delete' => 'Beim Löschen des Kommentars ist ein Fehler aufgetreten.', 'empty_comment' => 'Kann keinen leeren Kommentar hinzufügen', + // Error pages '404_page_not_found' => 'Seite nicht gefunden', 'sorry_page_not_found' => 'Entschuldigung. Die Seite, die Sie angefordert haben, wurde nicht gefunden.', 'return_home' => 'Zurück zur Startseite', 'error_occurred' => 'Es ist ein Fehler aufgetreten', 'app_down' => ':appName befindet sich aktuell im Wartungsmodus.', - 'back_soon' => 'Wir werden so schnell wie möglich wieder online sein.' + 'back_soon' => 'Wir werden so schnell wie möglich wieder online sein.', + + // API errors + 'api_no_authorization_found' => 'Kein Autorisierungs-Token für die Anfrage gefunden', + 'api_bad_authorization_format' => 'Ein Autorisierungs-Token wurde auf die Anfrage gefunden, aber das Format schien falsch zu sein', + 'api_user_token_not_found' => 'Es wurde kein passender API-Token für den angegebenen Autorisierungs-Token gefunden', + 'api_incorrect_token_secret' => 'Das für den angegebenen API-Token angegebene Kennwort ist falsch', + 'api_user_no_api_permission' => 'Der Besitzer des verwendeten API-Token hat keine Berechtigung für API-Aufrufe', + 'api_user_token_expired' => 'Das verwendete Autorisierungs-Token ist abgelaufen', + ]; diff --git a/resources/lang/de/pagination.php b/resources/lang/de/pagination.php index 6ed0e30f0..577767137 100644 --- a/resources/lang/de/pagination.php +++ b/resources/lang/de/pagination.php @@ -1,18 +1,11 @@ '« Vorherige', 'next' => 'Nächste »', diff --git a/resources/lang/de/passwords.php b/resources/lang/de/passwords.php index 440c5f92d..74149a7ed 100644 --- a/resources/lang/de/passwords.php +++ b/resources/lang/de/passwords.php @@ -1,20 +1,13 @@ 'Passwörter müssen aus mindestens sechs Zeichen bestehen und mit der eingegebenen Wiederholung übereinstimmen.', - 'user' => 'Es wurde kein Benutzer mit dieser E-Mail-Adresse gefunden.', + 'user' => "Es wurde kein Benutzer mit dieser E-Mail-Adresse gefunden.", 'token' => 'Dieser Link zum Zurücksetzen des Passwortes ist ungültig!', 'sent' => 'Der Link zum Zurücksetzen Ihres Passwortes wurde Ihnen per E-Mail zugesendet.', 'reset' => 'Ihr Passwort wurde zurückgesetzt!', diff --git a/resources/lang/de/settings.php b/resources/lang/de/settings.php index 11050924e..98a04b062 100644 --- a/resources/lang/de/settings.php +++ b/resources/lang/de/settings.php @@ -1,16 +1,17 @@ 'Einstellungen', 'settings_save' => 'Einstellungen speichern', 'settings_save_success' => 'Einstellungen gespeichert', - /** - * App settings - */ + + // App Settings 'app_customization' => 'Personalisierung', 'app_features_security' => 'Funktionen & Sicherheit', 'app_name' => 'Anwendungsname', @@ -20,55 +21,70 @@ return [ 'app_public_access_desc' => 'Wenn Sie diese Option aktivieren, können Besucher, die nicht angemeldet sind, auf Inhalte in Ihrer BookStack-Instanz zugreifen.', 'app_public_access_desc_guest' => 'Der Zugang für öffentliche Besucher kann über den Benutzer "Guest" gesteuert werden.', 'app_public_access_toggle' => 'Öffentlichen Zugriff erlauben', - 'app_public_viewing' => 'Öffentliche Ansicht erlauben?', 'app_secure_images' => 'Erhöhte Sicherheit für hochgeladene Bilder aktivieren?', + 'app_secure_images_toggle' => 'Aktiviere Bild-Upload höherer Sicherheit', 'app_secure_images_desc' => 'Aus Leistungsgründen sind alle Bilder öffentlich sichtbar. Diese Option fügt zufällige, schwer zu eratene, Zeichenketten zu Bild-URLs hinzu. Stellen sie sicher, dass Verzeichnisindizes deaktiviert sind, um einen einfachen Zugriff zu verhindern.', 'app_editor' => 'Seiteneditor', 'app_editor_desc' => 'Wählen Sie den Editor aus, der von allen Benutzern genutzt werden soll, um Seiten zu editieren.', 'app_custom_html' => 'Benutzerdefinierter HTML Inhalt', 'app_custom_html_desc' => 'Jeder Inhalt, der hier hinzugefügt wird, wird am Ende der Sektion jeder Seite eingefügt. Diese kann praktisch sein, um CSS Styles anzupassen oder Analytics-Code hinzuzufügen.', + 'app_custom_html_disabled_notice' => 'Benutzerdefinierte HTML-Kopfzeileninhalte sind auf dieser Einstellungsseite deaktiviert, um sicherzustellen, dass alle Änderungen rückgängig gemacht werden können.', 'app_logo' => 'Anwendungslogo', - 'app_logo_desc' => "Dieses Bild sollte 43px hoch sein.\nGrößere Bilder werden verkleinert.", + 'app_logo_desc' => 'Dieses Bild sollte 43px hoch sein. +Größere Bilder werden verkleinert.', 'app_primary_color' => 'Primäre Anwendungsfarbe', - 'app_primary_color_desc' => "Dies sollte ein HEX Wert sein.\nWenn Sie nicht eingeben, wird die Anwendung auf die Standardfarbe zurückgesetzt.", + 'app_primary_color_desc' => 'Dies sollte ein HEX Wert sein. +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_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.', - /** - * Registration settings - */ + + // Color settings + 'content_colors' => 'Inhaltsfarben', + 'content_colors_desc' => 'Legt Farben für alle Elemente in der Seitenorganisationshierarchie fest. Die Auswahl von Farben mit einer ähnlichen Helligkeit wie die Standardfarben wird zur Lesbarkeit empfohlen.', + 'bookshelf_color' => 'Regalfarbe', + 'book_color' => 'Buchfarbe', + 'chapter_color' => 'Kapitelfarbe', + 'page_color' => 'Seitenfarbe', + 'page_draft_color' => 'Seitenentwurfsfarbe', + + // Registration Settings 'reg_settings' => 'Registrierungseinstellungen', 'reg_enable' => 'Registrierung erlauben?', 'reg_enable_toggle' => 'Registrierung erlauben', 'reg_enable_desc' => 'Wenn die Registrierung erlaubt ist, kann sich der Benutzer als Anwendungsbenutzer anmelden. Bei der Registrierung erhält er eine einzige, voreingestellte Benutzerrolle.', 'reg_default_role' => 'Standard-Benutzerrolle nach Registrierung', + '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' => 'Bestätigung per E-Mail', 'reg_email_confirmation_toggle' => 'Bestätigung per E-Mail erforderlich', 'reg_confirm_email_desc' => 'Falls die Einschränkung für Domains genutzt wird, ist die Bestätigung per E-Mail zwingend erforderlich und der untenstehende Wert wird ignoriert.', 'reg_confirm_restrict_domain' => 'Registrierung auf bestimmte Domains einschränken', - 'reg_confirm_restrict_domain_desc' => "Fügen sie eine durch Komma getrennte Liste von Domains hinzu, auf die die Registrierung eingeschränkt werden soll. Benutzern wird eine E-Mail gesendet, um ihre E-Mail Adresse zu bestätigen, bevor sie diese Anwendung nutzen können.\nHinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung ändern.", + 'reg_confirm_restrict_domain_desc' => 'Fügen sie eine durch Komma getrennte Liste von Domains hinzu, auf die die Registrierung eingeschränkt werden soll. Benutzern wird eine E-Mail gesendet, um ihre E-Mail Adresse zu bestätigen, bevor sie diese Anwendung nutzen können. +Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung ändern.', 'reg_confirm_restrict_domain_placeholder' => 'Keine Einschränkung gesetzt', - /** - * Maintenance settings - */ - + // Maintenance settings '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_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_image_cleanup_ignore_revisions' => 'Bilder in Versionen ignorieren', '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.', 'maint_image_cleanup_nothing_found' => 'Keine unbenutzen Bilder gefunden. Nichts zu löschen!', + 'maint_send_test_email' => 'Test Email versenden', + 'maint_send_test_email_desc' => 'Dies sendet eine Test E-Mail an Ihre in Ihrem Profil angegebene E-Mail-Adresse.', + 'maint_send_test_email_run' => 'Sende eine Test E-Mail', + 'maint_send_test_email_success' => 'E-Mail wurde an :address gesendet', + '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 Sie diese E-Mail Benachrichtigung erhalten haben, scheinen Ihre E-Mail-Einstellungen korrekt konfiguriert zu sein.', - /** - * Role settings - */ + // Role Settings 'roles' => 'Rollen', 'role_user_roles' => 'Benutzer-Rollen', 'role_create' => 'Neue Rolle anlegen', @@ -89,6 +105,8 @@ return [ 'role_manage_roles' => 'Rollen und Rollen-Berechtigungen verwalten', 'role_manage_entity_permissions' => 'Alle Buch-, Kapitel- und Seiten-Berechtigungen verwalten', 'role_manage_own_entity_permissions' => 'Nur Berechtigungen eigener Bücher, Kapitel und Seiten verwalten', + 'role_manage_page_templates' => 'Seitenvorlagen verwalten', + 'role_access_api' => 'Systemzugriffs-API', 'role_manage_settings' => 'Globaleinstellungen verwalten', 'role_asset' => 'Berechtigungen', 'role_asset_desc' => 'Diese Berechtigungen gelten für den Standard-Zugriff innerhalb des Systems. Berechtigungen für Bücher, Kapitel und Seiten überschreiben diese Berechtigungenen.', @@ -100,9 +118,8 @@ return [ 'role_update_success' => 'Rolle erfolgreich gespeichert', 'role_users' => 'Dieser Rolle zugeordnete Benutzer', 'role_users_none' => 'Bisher sind dieser Rolle keine Benutzer zugeordnet', - /** - * Users - */ + + // Users 'users' => 'Benutzer', 'user_profile' => 'Benutzerprofil', 'users_add_new' => 'Benutzer hinzufügen', @@ -114,8 +131,10 @@ return [ 'users_role_desc' => 'Wählen Sie aus, welchen Rollen dieser Benutzer zugeordnet werden soll. Wenn ein Benutzer mehreren Rollen zugeordnet ist, werden die Berechtigungen dieser Rollen gestapelt und er erhält alle Fähigkeiten der zugewiesenen Rollen.', 'users_password' => 'Benutzerpasswort', 'users_password_desc' => 'Legen Sie ein Passwort fest, mit dem Sie sich anmelden möchten. Diese muss mindestens 5 Zeichen lang sein.', + 'users_send_invite_text' => 'Sie können diesem Benutzer eine Einladungs-E-Mail senden, die es ihm erlaubt, sein eigenes Passwort zu setzen, andernfalls können Sie sein Passwort selbst setzen.', + 'users_send_invite_option' => 'Benutzer-Einladungs-E-Mail senden', 'users_external_auth_id' => 'Externe Authentifizierungs-ID', - 'users_external_auth_id_desc' => 'Dies ist die ID, die verwendet wird, um diesen Benutzer bei der Kommunikation mit Ihrem LDAP-System abzugleichen.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Füllen Sie die folgenden Felder nur aus, wenn Sie Ihr Passwort ändern möchten:', 'users_system_public' => 'Dieser Benutzer repräsentiert alle unangemeldeten Benutzer, die diese Seite betrachten. Er kann nicht zum Anmelden benutzt werden, sondern wird automatisch zugeordnet.', 'users_delete' => 'Benutzer löschen', @@ -136,4 +155,60 @@ return [ 'users_social_disconnect' => 'Social-Media-Konto lösen', 'users_social_connected' => ':socialAccount-Konto wurde erfolgreich mit dem Profil verknüpft.', 'users_social_disconnected' => ':socialAccount-Konto wurde erfolgreich vom Profil gelöst.', + 'users_api_tokens' => 'API-Token', + 'users_api_tokens_none' => 'Für diesen Benutzer wurden keine API-Token erstellt', + 'users_api_tokens_create' => 'Token erstellen', + 'users_api_tokens_expires' => 'Endet', + 'users_api_tokens_docs' => 'API Dokumentation', + + // API Tokens + 'user_api_token_create' => 'Neuen API-Token erstellen', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Geben Sie Ihrem Token einen aussagekräftigen Namen als spätere Erinnerung an seinen Verwendungszweck.', + 'user_api_token_expiry' => 'Ablaufdatum', + 'user_api_token_expiry_desc' => 'Legen Sie ein Datum fest, an dem dieser Token abläuft. Nach diesem Datum funktionieren Anfragen, die mit diesem Token gestellt werden, nicht mehr. Wenn Sie dieses Feld leer lassen, wird ein Ablaufdatum von 100 Jahren in der Zukunft festgelegt.', + 'user_api_token_create_secret_message' => 'Unmittelbar nach der Erstellung dieses Tokens wird eine "Token ID" & ein "Token Kennwort" generiert und angezeigt. Das Kennwort wird nur ein einziges Mal angezeigt. Stellen Sie also sicher, dass Sie den Inhalt an einen sicheren Ort kopieren, bevor Sie fortfahren.', + 'user_api_token_create_success' => 'API-Token erfolgreich erstellt', + 'user_api_token_update_success' => 'API-Token erfolgreich aktualisiert', + 'user_api_token' => 'API-Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'Dies ist ein nicht editierbarer, vom System generierter Identifikator für diesen Token, welcher bei API-Anfragen angegeben werden muss.', + 'user_api_token_secret' => 'Token Kennwort', + 'user_api_token_secret_desc' => 'Dies ist ein systemgeneriertes Kennwort für diesen Token, das bei API-Anfragen zur Verfügung gestellt werden muss. Es wird nur dieses eine Mal angezeigt, deshalb kopieren Sie diesen Wert an einen sicheren und geschützten Ort.', + 'user_api_token_created' => 'Token erstellt :timeAgo', + 'user_api_token_updated' => 'Token aktualisiert :timeAgo', + 'user_api_token_delete' => 'Lösche Token', + 'user_api_token_delete_warning' => 'Dies löscht den API-Token mit dem Namen \':tokenName\' vollständig aus dem System.', + 'user_api_token_delete_confirm' => 'Sind Sie sicher, dass Sie diesen API-Token löschen möchten?', + 'user_api_token_delete_success' => 'API-Token erfolgreich gelöscht', + + //! 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' => 'العربية', + 'da' => 'Dänisch', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// ]; diff --git a/resources/lang/de/validation.php b/resources/lang/de/validation.php index 84faeebb7..b6105d192 100644 --- a/resources/lang/de/validation.php +++ b/resources/lang/de/validation.php @@ -1,18 +1,13 @@ ':attribute muss akzeptiert werden.', 'active_url' => ':attribute ist keine valide URL.', 'after' => ':attribute muss ein Datum nach :date sein.', @@ -35,13 +30,41 @@ return [ 'digits' => ':attribute muss :digits Stellen haben.', 'digits_between' => ':attribute muss zwischen :min und :max Stellen haben.', 'email' => ':attribute muss eine valide E-Mail-Adresse sein.', + 'ends_with' => ':attribute muss mit einem der folgenden Werte: :values enden', 'filled' => ':attribute ist erforderlich.', + 'gt' => [ + 'numeric' => ':attribute muss größer als :value sein.', + 'file' => ':attribute muss mindestens :value Kilobytes groß sein.', + 'string' => ':attribute muss mehr als :value Zeichen haben.', + 'array' => ':attribute muss mindestens :value Elemente haben.', + ], + 'gte' => [ + 'numeric' => ':attribute muss größer-gleich :value sein.', + 'file' => ':attribute muss mindestens :value Kilobytes groß sein.', + 'string' => ':attribute muss mindestens :value Zeichen enthalten.', + 'array' => ':attribute muss :value Elemente oder mehr haben.', + ], 'exists' => ':attribute ist ungültig.', 'image' => ':attribute muss ein Bild sein.', 'image_extension' => ':attribute muss eine gültige und unterstützte Bild-Dateiendung haben.', 'in' => ':attribute ist ungültig.', 'integer' => ':attribute muss eine Zahl sein.', 'ip' => ':attribute muss eine valide IP-Adresse sein.', + 'ipv4' => ':attribute muss eine gültige IPv4 Adresse sein.', + 'ipv6' => ':attribute muss eine gültige IPv6-Adresse sein.', + 'json' => 'Das Attribut muss eine gültige JSON-Zeichenfolge sein.', + 'lt' => [ + 'numeric' => ':attribute muss kleiner sein :value sein.', + 'file' => ':attribute muss kleiner als :value Kilobytes sein.', + 'string' => ':attribute muss weniger als :value Zeichen haben.', + 'array' => ':attribute muss weniger als :value Elemente haben.', + ], + 'lte' => [ + 'numeric' => ':attribute muss kleiner oder gleich :value sein.', + 'file' => ':attribute muss kleiner oder gleich :value Kilobytes sein.', + 'string' => ':attribute darf höchstens :value Zeichen besitzen.', + 'array' => ':attribute darf höchstens :value Elemente haben.', + ], 'max' => [ 'numeric' => ':attribute darf nicht größer als :max sein.', 'file' => ':attribute darf nicht größer als :max Kilobyte sein.', @@ -57,6 +80,7 @@ return [ ], '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.', 'regex' => ':attribute ist in einem ungültigen Format.', 'required' => ':attribute ist erforderlich.', @@ -78,37 +102,13 @@ return [ 'url' => ':attribute ist kein valides Format.', 'uploaded' => 'Die Datei konnte nicht hochgeladen werden. Der Server akzeptiert möglicherweise keine Dateien dieser Größe.', - /* - |-------------------------------------------------------------------------- - | Custom Validation Language Lines - |-------------------------------------------------------------------------- - | - | Here you may specify custom validation messages for attributes using the - | convention "attribute.rule" to name lines. This makes it quick to - | specify a specific custom language line for a given attribute rule. - | - */ - + // Custom validation lines 'custom' => [ - 'attribute-name' => [ - 'rule-name' => 'custom-message', - ], 'password-confirm' => [ 'required_with' => 'Passwortbestätigung erforderlich', ], ], - /* - |-------------------------------------------------------------------------- - | Custom Validation Attributes - |-------------------------------------------------------------------------- - | - | following language lines are used to swap attribute place-holders - | with something more reader friendly such as E-Mail Address instead - | of "email". This simply helps us make messages a little cleaner. - | - */ - + // Custom validation attributes 'attributes' => [], - ]; diff --git a/resources/lang/de_informal/activities.php b/resources/lang/de_informal/activities.php index c82c9e0c4..170a19108 100644 --- a/resources/lang/de_informal/activities.php +++ b/resources/lang/de_informal/activities.php @@ -1,6 +1,48 @@ 'erstellt Seite', + 'page_create_notification' => 'Die Seite wurde erfolgreich erstellt.', + 'page_update' => 'aktualisiert Seite', + 'page_update_notification' => 'Die Seite wurde erfolgreich aktualisiert.', + 'page_delete' => 'löscht Seite', + 'page_delete_notification' => 'Die Seite wurde erfolgreich gelöscht.', + 'page_restore' => 'stellt Seite wieder her', + 'page_restore_notification' => 'Die Seite wurde erfolgreich wiederhergestellt.', + 'page_move' => 'verschiebt Seite', + + // Chapters + 'chapter_create' => 'erstellt Kapitel', + 'chapter_create_notification' => 'Das Kapitel wurde erfolgreich erstellt.', + 'chapter_update' => 'aktualisiert Kapitel', + 'chapter_update_notification' => 'Das Kapitel wurde erfolgreich aktualisiert.', + 'chapter_delete' => 'löscht Kapitel', + 'chapter_delete_notification' => 'Das Kapitel wurde erfolgreich gelöscht.', + 'chapter_move' => 'verschiebt Kapitel', + + // Books + 'book_create' => 'erstellt Buch', + 'book_create_notification' => 'Das Buch wurde erfolgreich erstellt.', + 'book_update' => 'aktualisiert Buch', + 'book_update_notification' => 'Das Buch wurde erfolgreich aktualisiert.', + 'book_delete' => 'löscht Buch', + 'book_delete_notification' => 'Das Buch wurde erfolgreich gelöscht.', + 'book_sort' => 'sortiert Buch', + 'book_sort_notification' => 'Das Buch wurde erfolgreich umsortiert.', + + // Bookshelves + 'bookshelf_create' => 'erstellt Bücherregal', + 'bookshelf_create_notification' => 'Das Bücherregal wurde erfolgreich erstellt', + 'bookshelf_update' => 'aktualisiert Bücherregal', + 'bookshelf_update_notification' => 'Das Bücherregal wurde erfolgreich aktualisiert', + 'bookshelf_delete' => 'löscht Bücherregal', + 'bookshelf_delete_notification' => 'Das Bücherregal wurde erfolgreich gelöscht', + + // Other + 'commented_on' => 'kommentiert', +]; diff --git a/resources/lang/de_informal/auth.php b/resources/lang/de_informal/auth.php index de9ef91a4..c91cd4129 100644 --- a/resources/lang/de_informal/auth.php +++ b/resources/lang/de_informal/auth.php @@ -1,47 +1,77 @@ 'Die eingegebenen Anmeldedaten sind ungültig.', 'throttle' => 'Zu viele Anmeldeversuche. Bitte versuche es in :seconds Sekunden erneut.', - /** - * Login & Register - */ + // Login & Register + 'sign_up' => 'Registrieren', + 'log_in' => 'Anmelden', + 'log_in_with' => 'Anmelden mit :socialDriver', + 'sign_up_with' => 'Registrieren mit :socialDriver', + 'logout' => 'Abmelden', + + 'name' => 'Name', + 'username' => 'Benutzername', + 'email' => 'E-Mail', + 'password' => 'Passwort', + 'password_confirm' => 'Passwort bestätigen', + 'password_hint' => 'Mindestlänge: 7 Zeichen', + 'forgot_password' => 'Passwort vergessen?', + 'remember_me' => 'Angemeldet bleiben', 'ldap_email_hint' => 'Bitte gib eine E-Mail-Adresse ein, um diese mit dem Account zu nutzen.', + 'create_account' => 'Account registrieren', + 'already_have_account' => 'Bereits ein Konto erstellt?', + 'dont_have_account' => 'Noch kein Konto erstellt?', + 'social_login' => 'Mit Sozialem Netzwerk anmelden', + 'social_registration' => 'Mit Sozialem Netzwerk registrieren', + 'social_registration_text' => 'Mit einer dieser Dienste registrieren oder anmelden', + + 'register_thanks' => 'Vielen Dank für Ihre Registrierung!', 'register_confirm' => 'Bitte prüfe Deinen Posteingang und bestätig die Registrierung.', + 'registrations_disabled' => 'Eine Registrierung ist momentan nicht möglich', 'registration_email_domain_invalid' => 'Du kannst dich mit dieser E-Mail nicht registrieren.', 'register_success' => 'Vielen Dank für Deine Registrierung! Die Daten sind gespeichert und Du bist angemeldet.', - /** - * Password Reset - */ + + // Password Reset + 'reset_password' => 'Passwort vergessen', 'reset_password_send_instructions' => 'Bitte gib Deine E-Mail-Adresse ein. Danach erhältst Du eine E-Mail mit einem Link zum Zurücksetzen Deines Passwortes.', + 'reset_password_send_button' => 'Passwort zurücksetzen', 'reset_password_sent_success' => 'Eine E-Mail mit dem Link zum Zurücksetzen Deines Passwortes wurde an :email gesendet.', 'reset_password_success' => 'Dein Passwort wurde erfolgreich zurückgesetzt.', + 'email_reset_subject' => 'Passwort zurücksetzen für :appName', 'email_reset_text' => 'Du erhältsts diese E-Mail, weil jemand versucht hat, Dein Passwort zurückzusetzen.', 'email_reset_not_requested' => 'Wenn Du das nicht warst, brauchst Du nichts weiter zu tun.', - /** - * Email Confirmation - */ + + // Email Confirmation 'email_confirm_subject' => 'Bestätige Deine E-Mail-Adresse für :appName', 'email_confirm_greeting' => 'Danke, dass Du dich für :appName registrierst hast!', 'email_confirm_text' => 'Bitte bestätige Deine E-Mail-Adresse, indem Du auf die Schaltfläche klickst:', + 'email_confirm_action' => 'E-Mail-Adresse bestätigen', 'email_confirm_send_error' => 'Leider konnte die für die Registrierung notwendige E-Mail zur Bestätigung Deine E-Mail-Adresse nicht versandt werden. Bitte kontaktiere den Systemadministrator!', 'email_confirm_success' => 'Deine E-Mail-Adresse wurde bestätigt!', 'email_confirm_resent' => 'Bestätigungs-E-Mail wurde erneut versendet, bitte überprüfe Deinen Posteingang.', + + 'email_not_confirmed' => 'E-Mail-Adresse ist nicht bestätigt', 'email_not_confirmed_text' => 'Deine E-Mail-Adresse ist bisher nicht bestätigt.', 'email_not_confirmed_click_link' => 'Bitte klicke auf den Link in der E-Mail, die Du nach der Registrierung erhalten hast.', 'email_not_confirmed_resend' => 'Wenn Du die E-Mail nicht erhalten hast, kannst Du die Nachricht erneut anfordern. Fülle hierzu bitte das folgende Formular aus:', + 'email_not_confirmed_resend_button' => 'Bestätigungs-E-Mail erneut senden', + + // User Invite + 'user_invite_email_subject' => 'Du wurdest eingeladen :appName beizutreten!', + 'user_invite_email_greeting' => 'Ein Konto wurde für Sie auf :appName erstellt.', + 'user_invite_email_text' => 'Klicken Sie auf die Schaltfläche unten, um ein Passwort festzulegen und Zugriff zu erhalten:', + 'user_invite_email_action' => 'Account-Passwort festlegen', + 'user_invite_page_welcome' => 'Willkommen bei :appName!', + 'user_invite_page_text' => 'Um die Anmeldung abzuschließen und Zugriff auf :appName zu bekommen muss noch ein Passwort festgelegt werden. Dieses wird in Zukunft zum Einloggen benötigt.', + 'user_invite_page_confirm_button' => 'Passwort wiederholen', + 'user_invite_success' => 'Passwort gesetzt, Sie haben nun Zugriff auf :appName!' ]; \ No newline at end of file diff --git a/resources/lang/de_informal/common.php b/resources/lang/de_informal/common.php index d80fa9dcf..1fb2d6f78 100644 --- a/resources/lang/de_informal/common.php +++ b/resources/lang/de_informal/common.php @@ -1,9 +1,77 @@ 'Abbrechen', + 'confirm' => 'Bestätigen', + 'back' => 'Zurück', + 'save' => 'Speichern', + 'continue' => 'Weiter', + 'select' => 'Auswählen', + 'toggle_all' => 'Alle umschalten', + 'more' => 'Mehr', + + // Form Labels + 'name' => 'Name', + 'description' => 'Beschreibung', + 'role' => 'Rolle', + 'cover_image' => 'Titelbild', + 'cover_image_description' => 'Das Bild sollte eine Auflösung von 440x250px haben.', + + // Actions + 'actions' => 'Aktionen', + 'view' => 'Anzeigen', + 'view_all' => 'Alle anzeigen', + 'create' => 'Anlegen', + 'update' => 'Aktualisieren', + 'edit' => 'Bearbeiten', + 'sort' => 'Sortieren', + 'move' => 'Verschieben', + 'copy' => 'Kopieren', + 'reply' => 'Antworten', + 'delete' => 'Löschen', + 'search' => 'Suchen', + 'search_clear' => 'Suche löschen', + 'reset' => 'Zurücksetzen', + 'remove' => 'Entfernen', + 'add' => 'Hinzufügen', + 'fullscreen' => 'Vollbild', + + // Sort Options + 'sort_options' => 'Sortieroptionen', + 'sort_direction_toggle' => 'Sortierreihenfolge umkehren', + 'sort_ascending' => 'Aufsteigend sortieren', + 'sort_descending' => 'Absteigend sortieren', + 'sort_name' => 'Name', + 'sort_created_at' => 'Erstellungsdatum', + 'sort_updated_at' => 'Aktualisierungsdatum', + + // Misc + 'deleted_user' => 'Gelöschte Benutzer', + 'no_activity' => 'Keine Aktivitäten zum Anzeigen', + 'no_items' => 'Keine Einträge gefunden.', + 'back_to_top' => 'nach oben', + 'toggle_details' => 'Details zeigen/verstecken', + 'toggle_thumbnails' => 'Thumbnails zeigen/verstecken', + 'details' => 'Details', + 'grid_view' => 'Gitteransicht', + 'list_view' => 'Listenansicht', + 'default' => 'Voreinstellung', + 'breadcrumb' => 'Brotkrumen', + + // Header + 'profile_menu' => 'Profilmenü', + 'view_profile' => 'Profil ansehen', + 'edit_profile' => 'Profil bearbeiten', + + // Layout tabs + 'tab_info' => 'Info', + 'tab_content' => 'Inhalt', + + // Email Content 'email_action_help' => 'Sollte es beim Anklicken der Schaltfläche ":action_text" Probleme geben, öffne die folgende URL in Deinem Browser:', -]; \ No newline at end of file + 'email_rights' => 'Alle Rechte vorbehalten', +]; diff --git a/resources/lang/de_informal/components.php b/resources/lang/de_informal/components.php index 31cc9ca1b..4d98235a4 100644 --- a/resources/lang/de_informal/components.php +++ b/resources/lang/de_informal/components.php @@ -1,10 +1,33 @@ 'Bild auswählen', + 'image_all' => 'Alle', + 'image_all_title' => 'Alle Bilder anzeigen', + 'image_book_title' => 'Zeige alle Bilder, die in dieses Buch hochgeladen wurden', + 'image_page_title' => 'Zeige alle Bilder, die auf diese Seite hochgeladen wurden', + 'image_search_hint' => 'Nach Bildnamen suchen', + 'image_uploaded' => 'Hochgeladen am :uploadedDate', + 'image_load_more' => 'Mehr', + 'image_image_name' => 'Bildname', + 'image_delete_used' => 'Dieses Bild wird auf den folgenden Seiten benutzt. ', 'image_delete_confirm' => 'Bitte klicke erneut auf löschen, wenn Du dieses Bild wirklich entfernen möchtest.', + 'image_select_image' => 'Bild auswählen', 'image_dropzone' => 'Ziehe Bilder hierher oder klicke hier, um ein Bild auszuwählen', -]; \ No newline at end of file + 'images_deleted' => 'Bilder gelöscht', + 'image_preview' => 'Bildvorschau', + 'image_upload_success' => 'Bild erfolgreich hochgeladen', + 'image_update_success' => 'Bilddetails erfolgreich aktualisiert', + 'image_delete_success' => 'Bild erfolgreich gelöscht', + 'image_upload_remove' => 'Entfernen', + + // Code Editor + 'code_editor' => 'Code editieren', + 'code_language' => 'Code Sprache', + 'code_content' => 'Code Inhalt', + 'code_save' => 'Code speichern', +]; diff --git a/resources/lang/de_informal/entities.php b/resources/lang/de_informal/entities.php index 1decdd7b7..e0cbedf91 100644 --- a/resources/lang/de_informal/entities.php +++ b/resources/lang/de_informal/entities.php @@ -1,38 +1,230 @@ 'Kürzlich angelegt', + 'recently_created_pages' => 'Kürzlich angelegte Seiten', + 'recently_updated_pages' => 'Kürzlich aktualisierte Seiten', + 'recently_created_chapters' => 'Kürzlich angelegte Kapitel', + 'recently_created_books' => 'Kürzlich angelegte Bücher', + 'recently_created_shelves' => 'Kürzlich angelegte Regale', + 'recently_update' => 'Kürzlich aktualisiert', + 'recently_viewed' => 'Kürzlich angesehen', + 'recent_activity' => 'Kürzliche Aktivität', + 'create_now' => 'Jetzt anlegen', + 'revisions' => 'Versionen', + 'meta_revision' => 'Version #:revisionCount', + 'meta_created' => 'Erstellt: :timeLength', + 'meta_created_name' => 'Erstellt: :timeLength von :user', + 'meta_updated' => 'Zuletzt aktualisiert: :timeLength', + 'meta_updated_name' => 'Zuletzt aktualisiert: :timeLength 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' => 'Du hast bisher keine Seiten angesehen.', 'no_pages_recently_created' => 'Du hast bisher keine Seiten angelegt.', 'no_pages_recently_updated' => 'Du hast bisher keine Seiten aktualisiert.', + 'export' => 'Exportieren', + 'export_html' => 'HTML-Datei', + 'export_pdf' => 'PDF-Datei', + 'export_text' => 'Textdatei', - /** - * Shelves - */ + // Permissions and restrictions + 'permissions' => 'Berechtigungen', + 'permissions_intro' => 'Wenn individuelle Berechtigungen aktiviert werden, überschreiben diese Einstellungen durch Rollen zugewiesene Berechtigungen.', + 'permissions_enable' => 'Individuelle Berechtigungen aktivieren', + 'permissions_save' => 'Berechtigungen speichern', + + // Search + 'search_results' => 'Suchergebnisse', + 'search_total_results_found' => ':count Ergebnis gefunden|:count Ergebnisse gesamt', + 'search_clear' => 'Filter löschen', + 'search_no_pages' => 'Keine Seiten gefunden', + 'search_for_term' => 'Nach :term suchen', + 'search_more' => 'Mehr Ergebnisse', + 'search_filters' => 'Filter', + 'search_content_type' => 'Inhaltstyp', + 'search_exact_matches' => 'Exakte Treffer', + 'search_tags' => 'Nach Schlagwort suchen', + 'search_options' => 'Optionen', + 'search_viewed_by_me' => 'Schon von mir angesehen', + 'search_not_viewed_by_me' => 'Noch nicht von mir angesehen', + 'search_permissions_set' => 'Berechtigungen gesetzt', + 'search_created_by_me' => 'Von mir erstellt', + 'search_updated_by_me' => 'Von mir aktualisiert', + 'search_date_options' => 'Datums Optionen', + 'search_updated_before' => 'Aktualisiert vor', + 'search_updated_after' => 'Aktualisiert nach', + 'search_created_before' => 'Erstellt vor', + 'search_created_after' => 'Erstellt nach', + 'search_set_date' => 'Datum auswählen', + 'search_update' => 'Suche aktualisieren', + + // Shelves + 'shelf' => 'Regal', + 'shelves' => 'Regale', + 'x_shelves' => ':count Regal|:count Regale', + 'shelves_long' => 'Bücherregal', + 'shelves_empty' => 'Es wurden noch keine Regale angelegt', + 'shelves_create' => 'Erzeuge ein Regal', + 'shelves_popular' => 'Beliebte Regale', + 'shelves_new' => 'Kürzlich erstellte Regale', + 'shelves_new_action' => 'Neues Regal', + 'shelves_popular_empty' => 'Die beliebtesten Regale werden hier angezeigt.', + 'shelves_new_empty' => 'Die neusten Regale werden hier angezeigt.', + 'shelves_save' => 'Regal speichern', + 'shelves_books' => 'Bücher in diesem Regal', + 'shelves_add_books' => 'Buch zu diesem Regal hinzufügen', + 'shelves_drag_books' => 'Bücher hier hin ziehen um sie dem Regal hinzuzufügen', + 'shelves_empty_contents' => 'Diesem Regal sind keine Bücher zugewiesen', + 'shelves_edit_and_assign' => 'Regal bearbeiten um Bücher hinzuzufügen', + 'shelves_edit_named' => 'Bücherregal :name bearbeiten', + 'shelves_edit' => 'Bücherregal bearbeiten', + 'shelves_delete' => 'Bücherregal löschen', + 'shelves_delete_named' => 'Bücherregal :name löschen', 'shelves_delete_explain' => "Du bist im Begriff das Bücherregal mit dem Namen ':name' zu löschen. Enthaltene Bücher werden nicht gelöscht.", 'shelves_delete_confirmation' => 'Bist du sicher, dass du dieses Bücherregal löschen willst?', + 'shelves_permissions' => 'Regal-Berechtigungen', + 'shelves_permissions_updated' => 'Regal-Berechtigungen aktualisiert', + 'shelves_permissions_active' => 'Regal-Berechtigungen aktiv', + 'shelves_copy_permissions_to_books' => 'Kopiere die Berechtigungen zum Buch', + 'shelves_copy_permissions' => 'Berechtigungen kopieren', 'shelves_copy_permissions_explain' => 'Hiermit werden die Berechtigungen des aktuellen Regals auf alle enthaltenen Bücher übertragen. Überprüfe vor der Aktivierung, ob alle Berechtigungsänderungen am aktuellen Regal gespeichert wurden.', - - /** - * Books - */ + 'shelves_copy_permission_success' => 'Regal-Berechtigungen wurden zu :count Büchern kopiert', + + // Books + 'book' => 'Buch', + 'books' => 'Bücher', + 'x_books' => ':count Buch|:count Bücher', + 'books_empty' => 'Keine Bücher vorhanden', + 'books_popular' => 'Beliebte Bücher', + 'books_recent' => 'Kürzlich angesehene Bücher', + 'books_new' => 'Neue Bücher', + 'books_new_action' => 'Neues Buch', + 'books_popular_empty' => 'Die beliebtesten Bücher werden hier angezeigt.', + 'books_new_empty' => 'Die neusten Bücher werden hier angezeigt.', + 'books_create' => 'Neues Buch erstellen', + 'books_delete' => 'Buch löschen', + 'books_delete_named' => 'Buch ":bookName" löschen', + 'books_delete_explain' => 'Das Buch ":bookName" wird gelöscht und alle zugehörigen Kapitel und Seiten entfernt.', 'books_delete_confirmation' => 'Bist Du sicher, dass Du dieses Buch löschen möchtest?', + 'books_edit' => 'Buch bearbeiten', + 'books_edit_named' => 'Buch ":bookName" bearbeiten', + 'books_form_book_name' => 'Name des Buches', + 'books_save' => 'Buch speichern', + 'books_permissions' => 'Buch-Berechtigungen', + 'books_permissions_updated' => 'Buch-Berechtigungen aktualisiert', + 'books_empty_contents' => 'Es sind noch keine Seiten oder Kapitel zu diesem Buch hinzugefügt worden.', + 'books_empty_create_page' => 'Neue Seite anlegen', + 'books_empty_sort_current_book' => 'Aktuelles Buch sortieren', + 'books_empty_add_chapter' => 'Neues Kapitel hinzufügen', + 'books_permissions_active' => 'Buch-Berechtigungen aktiv', + 'books_search_this' => 'Dieses Buch durchsuchen', + 'books_navigation' => 'Buchnavigation', + 'books_sort' => 'Buchinhalte sortieren', + 'books_sort_named' => 'Buch ":bookName" sortieren', + 'books_sort_name' => 'Sortieren nach Namen', + 'books_sort_created' => 'Sortieren nach Erstellungsdatum', + 'books_sort_updated' => 'Sortieren nach Aktualisierungsdatum', + 'books_sort_chapters_first' => 'Kapitel zuerst', + 'books_sort_chapters_last' => 'Kapitel zuletzt', + 'books_sort_show_other' => 'Andere Bücher anzeigen', + 'books_sort_save' => 'Neue Reihenfolge speichern', - /** - * Chapters - */ + // Chapters + 'chapter' => 'Kapitel', + 'chapters' => 'Kapitel', + 'x_chapters' => ':count Kapitel', + 'chapters_popular' => 'Beliebte Kapitel', + 'chapters_new' => 'Neues Kapitel', + 'chapters_create' => 'Neues Kapitel anlegen', + 'chapters_delete' => 'Kapitel entfernen', + 'chapters_delete_named' => 'Kapitel ":chapterName" entfernen', + 'chapters_delete_explain' => 'Das Kapitel ":chapterName" wird gelöscht und alle zugehörigen Seiten dem übergeordneten Buch zugeordnet.', 'chapters_delete_confirm' => 'Bist Du sicher, dass Du dieses Kapitel löschen möchtest?', + 'chapters_edit' => 'Kapitel bearbeiten', + 'chapters_edit_named' => 'Kapitel ":chapterName" bearbeiten', + 'chapters_save' => 'Kapitel speichern', + 'chapters_move' => 'Kapitel verschieben', + 'chapters_move_named' => 'Kapitel ":chapterName" verschieben', + 'chapter_move_success' => 'Das Kapitel wurde in das Buch ":bookName" verschoben.', + 'chapters_permissions' => 'Kapitel-Berechtigungen', + 'chapters_empty' => 'Aktuell sind keine Kapitel diesem Buch hinzugefügt worden.', + 'chapters_permissions_active' => 'Kapitel-Berechtigungen aktiv', + 'chapters_permissions_success' => 'Kapitel-Berechtigungenen aktualisisert', + 'chapters_search_this' => 'Dieses Kapitel durchsuchen', - /** - * Pages - */ + // Pages + 'page' => 'Seite', + 'pages' => 'Seiten', + 'x_pages' => ':count Seite|:count Seiten', + 'pages_popular' => 'Beliebte Seiten', + 'pages_new' => 'Neue Seite', + 'pages_attachments' => 'Anhänge', + 'pages_navigation' => 'Seitennavigation', + 'pages_delete' => 'Seite löschen', + 'pages_delete_named' => 'Seite ":pageName" löschen', + 'pages_delete_draft_named' => 'Seitenentwurf von ":pageName" löschen', + 'pages_delete_draft' => 'Seitenentwurf löschen', + 'pages_delete_success' => 'Seite gelöscht', + 'pages_delete_draft_success' => 'Seitenentwurf gelöscht', 'pages_delete_confirm' => 'Bist Du sicher, dass Du diese Seite löschen möchtest?', 'pages_delete_draft_confirm' => 'Bist Du sicher, dass Du diesen Seitenentwurf löschen möchtest?', + 'pages_editing_named' => 'Seite ":pageName" bearbeiten', + 'pages_edit_draft_options' => 'Entwurfsoptionen', + 'pages_edit_save_draft' => 'Entwurf speichern', + 'pages_edit_draft' => 'Seitenentwurf bearbeiten', + 'pages_editing_draft' => 'Seitenentwurf bearbeiten', + 'pages_editing_page' => 'Seite bearbeiten', + 'pages_edit_draft_save_at' => 'Entwurf gespeichert um ', + 'pages_edit_delete_draft' => 'Entwurf löschen', + 'pages_edit_discard_draft' => 'Entwurf verwerfen', + 'pages_edit_set_changelog' => 'Änderungsprotokoll hinzufügen', 'pages_edit_enter_changelog_desc' => 'Bitte gib eine kurze Zusammenfassung Deiner Änderungen ein', + 'pages_edit_enter_changelog' => 'Änderungsprotokoll eingeben', + 'pages_save' => 'Seite speichern', + 'pages_title' => 'Seitentitel', + 'pages_name' => 'Seitenname', + 'pages_md_editor' => 'Redakteur', + 'pages_md_preview' => 'Vorschau', + 'pages_md_insert_image' => 'Bild einfügen', + 'pages_md_insert_link' => 'Link zu einem Objekt einfügen', + 'pages_md_insert_drawing' => 'Zeichnung einfügen', + 'pages_not_in_chapter' => 'Seite ist in keinem Kapitel', + 'pages_move' => 'Seite verschieben', + 'pages_move_success' => 'Seite nach ":parentName" verschoben', + 'pages_copy' => 'Seite kopieren', + 'pages_copy_desination' => 'Ziel', + 'pages_copy_success' => 'Seite erfolgreich kopiert', + 'pages_permissions' => 'Seiten Berechtigungen', + 'pages_permissions_success' => 'Seiten Berechtigungen aktualisiert', + 'pages_revision' => 'Version', + 'pages_revisions' => 'Seitenversionen', + 'pages_revisions_named' => 'Seitenversionen von ":pageName"', + 'pages_revision_named' => 'Seitenversion von ":pageName"', + 'pages_revisions_created_by' => 'Erstellt von', + 'pages_revisions_date' => 'Versionsdatum', + 'pages_revisions_number' => '#', + 'pages_revisions_numbered' => 'Revision #:id', + 'pages_revisions_numbered_changes' => 'Revision #:id Änderungen', + 'pages_revisions_changelog' => 'Änderungsprotokoll', + 'pages_revisions_changes' => 'Änderungen', + 'pages_revisions_current' => 'Aktuelle Version', + 'pages_revisions_preview' => 'Vorschau', + 'pages_revisions_restore' => 'Wiederherstellen', + 'pages_revisions_none' => 'Diese Seite hat keine älteren Versionen.', + 'pages_copy_link' => 'Link kopieren', + 'pages_edit_content_link' => 'Inhalt bearbeiten', + 'pages_permissions_active' => 'Seiten-Berechtigungen aktiv', + 'pages_initial_revision' => 'Erste Veröffentlichung', + 'pages_initial_name' => 'Neue Seite', 'pages_editing_draft_notification' => 'Du bearbeitest momenten einen Entwurf, der zuletzt :timeDiff gespeichert wurde.', + 'pages_draft_edited_notification' => 'Diese Seite wurde seit diesem Zeitpunkt verändert. Wir empfehlen Ihnen, diesen Entwurf zu verwerfen.', 'pages_draft_edit_active' => [ 'start_a' => ':count Benutzer bearbeiten derzeit diese Seite.', 'start_b' => ':userName bearbeitet jetzt diese Seite.', @@ -40,25 +232,83 @@ return [ 'time_b' => 'in den letzten :minCount Minuten', 'message' => ':start :time. Achte darauf, keine Änderungen von anderen Benutzern zu überschreiben!', ], + 'pages_draft_discarded' => 'Entwurf verworfen. Der aktuelle Seiteninhalt wurde geladen.', + 'pages_specific' => 'Spezifische Seite', + 'pages_is_template' => 'Seitenvorlage', - /** - * Editor sidebar - */ + // Editor Sidebar + 'page_tags' => 'Seiten-Schlagwörter', + 'chapter_tags' => 'Kapitel-Schlagwörter', + 'book_tags' => 'Buch-Schlagwörter', + 'shelf_tags' => 'Regal-Schlagwörter', + 'tag' => 'Schlagwort', + 'tags' => 'Schlagwörter', + 'tag_name' => 'Schlagwort Name', + 'tag_value' => 'Inhalt (Optional)', 'tags_explain' => "Füge Schlagwörter hinzu, um ihren Inhalt zu kategorisieren.\nDu kannst einen erklärenden Inhalt hinzufügen, um eine genauere Unterteilung vorzunehmen.", + 'tags_add' => 'Weiteres Schlagwort hinzufügen', + 'tags_remove' => 'Diesen Tag entfernen', + 'attachments' => 'Anhänge', 'attachments_explain' => 'Du kannst auf Deiner Seite Dateien hochladen oder Links hinzufügen. Diese werden in der Seitenleiste angezeigt.', + 'attachments_explain_instant_save' => 'Änderungen werden direkt gespeichert.', + 'attachments_items' => 'Angefügte Elemente', + 'attachments_upload' => 'Datei hochladen', + 'attachments_link' => 'Link hinzufügen', + 'attachments_set_link' => 'Link setzen', 'attachments_delete_confirm' => 'Klicke erneut auf löschen, um diesen Anhang zu entfernen.', 'attachments_dropzone' => 'Ziehe Dateien hierher oder klicke hier, um eine Datei auszuwählen', + 'attachments_no_files' => 'Es wurden bisher keine Dateien hochgeladen.', 'attachments_explain_link' => 'Wenn Du keine Datei hochladen möchtest, kannst Du stattdessen einen Link hinzufügen. Dieser Link kann auf eine andere Seite oder eine Datei im Internet verweisen.', + 'attachments_link_name' => 'Link-Name', + 'attachment_link' => 'Link zum Anhang', + 'attachments_link_url' => 'Link zu einer Datei', + 'attachments_link_url_hint' => 'URL einer Seite oder Datei', + 'attach' => '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', + 'attachments_order_updated' => 'Reihenfolge der Anhänge aktualisiert', + 'attachments_updated_success' => 'Anhangdetails aktualisiert', + 'attachments_deleted' => 'Anhang gelöscht', + 'attachments_file_uploaded' => 'Datei erfolgreich hochgeladen', + 'attachments_file_updated' => 'Datei erfolgreich aktualisiert', + 'attachments_link_attached' => 'Link erfolgreich der Seite hinzugefügt', + 'templates' => 'Vorlagen', + 'templates_set_as_template' => 'Seite ist eine Vorlage', + 'templates_explain_set_as_template' => 'Sie können diese Seite als Vorlage festlegen, damit deren Inhalt beim Erstellen anderer Seiten verwendet werden kann. Andere Benutzer können diese Vorlage verwenden, wenn sie die Zugriffsrechte für diese Seite haben.', + 'templates_replace_content' => 'Seiteninhalt ersetzen', + 'templates_append_content' => 'An Seiteninhalt anhängen', + 'templates_prepend_content' => 'Seiteninhalt voranstellen', - /** - * Comments - */ + // Profile View + 'profile_user_for_x' => 'Benutzer seit :time', + 'profile_created_content' => 'Erstellte Inhalte', + 'profile_not_created_pages' => ':userName hat noch keine Seiten erstellt.', + 'profile_not_created_chapters' => ':userName hat noch keine Kapitel erstellt.', + 'profile_not_created_books' => ':userName hat noch keine Bücher erstellt.', + 'profile_not_created_shelves' => ':userName hat noch keine Regale erstellt.', + + // Comments + 'comment' => 'Kommentar', + 'comments' => 'Kommentare', + 'comment_add' => 'Kommentieren', 'comment_placeholder' => 'Gib hier Deine Kommentare ein (Markdown unterstützt)', + 'comment_count' => '{0} Keine Kommentare|{1} 1 Kommentar|[2,*] :count Kommentare', + 'comment_save' => 'Kommentar speichern', + 'comment_saving' => 'Kommentar wird gespeichert...', + 'comment_deleting' => 'Kommentar wird gelöscht...', + 'comment_new' => 'Neuer Kommentar', + 'comment_created' => ':createDiff kommentiert', + 'comment_updated' => ':updateDiff aktualisiert von :username', + 'comment_deleted_success' => 'Kommentar gelöscht', + 'comment_created_success' => 'Kommentar hinzugefügt', + 'comment_updated_success' => 'Kommentar aktualisiert', 'comment_delete_confirm' => 'Möchtst Du diesen Kommentar wirklich löschen?', + 'comment_in_reply_to' => 'Antwort auf :commentId', - /** - * Revision - */ + // Revision 'revision_delete_confirm' => 'Bist Du sicher, dass Du diese Revision löschen möchtest?', -]; + 'revision_restore_confirm' => 'Sind Sie sicher, dass Sie diese Revision wiederherstellen wollen? Der aktuelle Seiteninhalt wird ersetzt.', + 'revision_delete_success' => 'Revision gelöscht', + 'revision_cannot_delete_latest' => 'Die letzte Version kann nicht gelöscht werden.' +]; \ No newline at end of file diff --git a/resources/lang/de_informal/errors.php b/resources/lang/de_informal/errors.php index 924deee0d..a5dac12eb 100644 --- a/resources/lang/de_informal/errors.php +++ b/resources/lang/de_informal/errors.php @@ -1,32 +1,99 @@ 'Du hast keine Berechtigung, auf diese Seite zuzugreifen.', 'permissionJson' => 'Du hast keine Berechtigung, die angeforderte Aktion auszuführen.', // Auth + 'error_user_exists_different_creds' => 'Ein Benutzer mit der E-Mail-Adresse :email ist bereits mit anderen Anmeldedaten registriert.', 'email_already_confirmed' => 'Die E-Mail-Adresse ist bereits bestätigt. Bitte melde dich an.', 'email_confirmation_invalid' => 'Der Bestätigungslink ist nicht gültig oder wurde bereits verwendet. Bitte registriere dich erneut.', + 'email_confirmation_expired' => 'Der Bestätigungslink ist abgelaufen. Es wurde eine neue Bestätigungs-E-Mail gesendet.', + 'email_confirmation_awaiting' => 'Die E-Mail-Adresse für das verwendete Konto muss bestätigt werden', + 'ldap_fail_anonymous' => 'Anonymer LDAP-Zugriff ist fehlgeschlafgen', + 'ldap_fail_authed' => 'LDAP-Zugriff mit DN und Passwort ist fehlgeschlagen', + 'ldap_extension_not_installed' => 'LDAP-PHP-Erweiterung ist nicht installiert.', + 'ldap_cannot_connect' => 'Die Verbindung zum LDAP-Server ist fehlgeschlagen. Beim initialen Verbindungsaufbau trat ein Fehler auf.', + 'saml_already_logged_in' => 'Du bist bereits angemeldet', + 'saml_user_not_registered' => 'Kein Benutzer mit ID :name registriert und die automatische Registrierung ist deaktiviert', + 'saml_no_email_address' => 'Es konnte keine E-Mail-Adresse für diesen Benutzer in den vom externen Authentifizierungssystem zur Verfügung gestellten Daten gefunden werden', + 'saml_invalid_response_id' => 'Die Anfrage vom externen Authentifizierungssystem wird von einem von dieser Anwendung gestarteten Prozess nicht erkannt. Das Zurückgehen nach einem Login könnte dieses Problem verursachen.', + 'saml_fail_authed' => 'Anmeldung mit :system fehlgeschlagen, System konnte keine erfolgreiche Autorisierung bereitstellen', + 'social_no_action_defined' => 'Es ist keine Aktion definiert', + 'social_login_bad_response' => "Fehler bei der :socialAccount-Anmeldung: \n:error", 'social_account_in_use' => 'Dieses :socialAccount-Konto wird bereits verwendet. Bitte melde dich mit dem :socialAccount-Konto an.', 'social_account_email_in_use' => 'Die E-Mail-Adresse ":email" ist bereits registriert. Wenn Du bereits registriert bist, kannst Du Dein :socialAccount-Konto in Deinen Profil-Einstellungen verknüpfen.', + 'social_account_existing' => 'Dieses :socialAccount-Konto ist bereits mit Ihrem Profil verknüpft.', + 'social_account_already_used_existing' => 'Dieses :socialAccount-Konto wird bereits von einem anderen Benutzer verwendet.', 'social_account_not_used' => 'Dieses :socialAccount-Konto ist bisher keinem Benutzer zugeordnet. Du kannst das in Deinen Profil-Einstellungen tun.', 'social_account_register_instructions' => 'Wenn Du bisher kein Social-Media Konto besitzt, kannst Du ein solches Konto mit der :socialAccount Option anlegen.', + 'social_driver_not_found' => 'Treiber für Social-Media-Konten nicht gefunden', + 'social_driver_not_configured' => 'Ihr :socialAccount-Konto ist nicht korrekt konfiguriert.', + 'invite_token_expired' => 'Dieser Einladungslink ist abgelaufen. Sie können stattdessen versuchen, Ihr Passwort zurückzusetzen.', // System 'path_not_writable' => 'Die Datei kann nicht in den angegebenen Pfad :filePath hochgeladen werden. Stelle sicher, dass dieser Ordner auf dem Server beschreibbar ist.', + 'cannot_get_image_from_url' => 'Bild konnte nicht von der URL :url geladen werden.', 'cannot_create_thumbs' => 'Der Server kann keine Vorschau-Bilder erzeugen. Bitte prüfe, ob die GD PHP-Erweiterung installiert ist.', 'server_upload_limit' => 'Der Server verbietet das Hochladen von Dateien mit dieser Dateigröße. Bitte versuche es mit einer kleineren Datei.', + 'uploaded' => 'Der Server verbietet das Hochladen von Dateien mit dieser Dateigröße. Bitte versuchen Sie es mit einer kleineren Datei.', + 'image_upload_error' => 'Beim Hochladen des Bildes trat ein Fehler auf.', + 'image_upload_type_error' => 'Der Bildtyp der hochgeladenen Datei ist ungültig.', + 'file_upload_timeout' => 'Der Upload der Datei ist abgelaufen.', + + // Attachments + 'attachment_page_mismatch' => 'Die Seite stimmte nach dem Hochladen des Anhangs nicht überein.', + 'attachment_not_found' => 'Anhang konnte nicht gefunden werden.', // Pages 'page_draft_autosave_fail' => 'Fehler beim Speichern des Entwurfs. Stelle sicher, dass Du mit dem Internet verbunden bist, bevor Du den Entwurf dieser Seite speicherst.', 'page_custom_home_deletion' => 'Eine als Startseite gesetzte Seite kann nicht gelöscht werden.', + // Entities + 'entity_not_found' => 'Eintrag nicht gefunden', + 'bookshelf_not_found' => 'Regal nicht gefunden', + 'book_not_found' => 'Buch nicht gefunden', + 'page_not_found' => 'Seite nicht gefunden', + 'chapter_not_found' => 'Kapitel nicht gefunden', + 'selected_book_not_found' => 'Das gewählte Buch wurde nicht gefunden.', + 'selected_book_chapter_not_found' => 'Das gewählte Buch oder Kapitel wurde nicht gefunden.', + 'guests_cannot_save_drafts' => 'Gäste können keine Entwürfe speichern', + // Users 'users_cannot_delete_only_admin' => 'Du kannst den einzigen Administrator nicht löschen.', 'users_cannot_delete_guest' => 'Du kannst den Gast-Benutzer nicht löschen', + // Roles + 'role_cannot_be_edited' => 'Diese Rolle kann nicht bearbeitet werden.', + 'role_system_cannot_be_deleted' => 'Dies ist eine Systemrolle und kann nicht gelöscht werden', + 'role_registration_default_cannot_delete' => 'Diese Rolle kann nicht gelöscht werden, solange sie als Standardrolle für neue Registrierungen gesetzt ist', + 'role_cannot_remove_only_admin' => 'Dieser Benutzer ist der einzige Benutzer, welchem die Administratorrolle zugeordnet ist. Ordnen Sie die Administratorrolle einem anderen Benutzer zu, bevor Sie versuchen, sie hier zu entfernen.', + + // Comments + 'comment_list' => 'Beim Abrufen der Kommentare ist ein Fehler aufgetreten.', + 'cannot_add_comment_to_draft' => 'Du kannst keine Kommentare zu einem Entwurf hinzufügen.', + 'comment_add' => 'Beim Hinzufügen des Kommentars ist ein Fehler aufgetreten.', + 'comment_delete' => 'Beim Löschen des Kommentars ist ein Fehler aufgetreten.', + 'empty_comment' => 'Kann keinen leeren Kommentar hinzufügen', + // Error pages + '404_page_not_found' => 'Seite nicht gefunden', 'sorry_page_not_found' => 'Entschuldigung. Die Seite, die Du angefordert hast, wurde nicht gefunden.', + 'return_home' => 'Zurück zur Startseite', + 'error_occurred' => 'Es ist ein Fehler aufgetreten', + 'app_down' => ':appName befindet sich aktuell im Wartungsmodus.', + 'back_soon' => 'Wir werden so schnell wie möglich wieder online sein.', + + // API errors + 'api_no_authorization_found' => 'Kein Autorisierungs-Token für die Anfrage gefunden', + 'api_bad_authorization_format' => 'Ein Autorisierungs-Token wurde auf die Anfrage gefunden, aber das Format schien falsch zu sein', + 'api_user_token_not_found' => 'Es wurde kein passender API-Token für den angegebenen Autorisierungs-Token gefunden', + 'api_incorrect_token_secret' => 'Das für den angegebenen API-Token angegebene Kennwort ist falsch', + 'api_user_no_api_permission' => 'Der Besitzer des verwendeten API-Token hat keine Berechtigung für API-Aufrufe', + 'api_user_token_expired' => 'Das verwendete Autorisierungs-Token ist abgelaufen', + ]; diff --git a/resources/lang/de_informal/pagination.php b/resources/lang/de_informal/pagination.php index c82c9e0c4..577767137 100644 --- a/resources/lang/de_informal/pagination.php +++ b/resources/lang/de_informal/pagination.php @@ -1,6 +1,12 @@ '« Vorherige', + 'next' => 'Nächste »', + +]; diff --git a/resources/lang/de_informal/passwords.php b/resources/lang/de_informal/passwords.php index c82c9e0c4..74149a7ed 100644 --- a/resources/lang/de_informal/passwords.php +++ b/resources/lang/de_informal/passwords.php @@ -1,6 +1,15 @@ 'Passwörter müssen aus mindestens sechs Zeichen bestehen und mit der eingegebenen Wiederholung übereinstimmen.', + 'user' => "Es wurde kein Benutzer mit dieser E-Mail-Adresse gefunden.", + 'token' => 'Dieser Link zum Zurücksetzen des Passwortes ist ungültig!', + 'sent' => 'Der Link zum Zurücksetzen Ihres Passwortes wurde Ihnen per E-Mail zugesendet.', + 'reset' => 'Ihr Passwort wurde zurückgesetzt!', + +]; diff --git a/resources/lang/de_informal/settings.php b/resources/lang/de_informal/settings.php index c8f5a1b10..fb563ffdf 100644 --- a/resources/lang/de_informal/settings.php +++ b/resources/lang/de_informal/settings.php @@ -1,38 +1,214 @@ 'Einstellungen', + 'settings_save' => 'Einstellungen speichern', + 'settings_save_success' => 'Einstellungen gespeichert', + + // App Settings + 'app_customization' => 'Personalisierung', + 'app_features_security' => 'Funktionen & Sicherheit', + 'app_name' => 'Anwendungsname', + 'app_name_desc' => 'Dieser Name wird im Header und in E-Mails angezeigt.', + 'app_name_header' => 'Anwendungsname im Header anzeigen?', + 'app_public_access' => 'Öffentlicher Zugriff', + 'app_public_access_desc' => 'Wenn Sie diese Option aktivieren, können Besucher, die nicht angemeldet sind, auf Inhalte in Ihrer BookStack-Instanz zugreifen.', + 'app_public_access_desc_guest' => 'Der Zugang für öffentliche Besucher kann über den Benutzer "Guest" gesteuert werden.', + 'app_public_access_toggle' => 'Öffentlichen Zugriff erlauben', + 'app_public_viewing' => 'Öffentliche Ansicht erlauben?', + 'app_secure_images' => 'Erhöhte Sicherheit für hochgeladene Bilder aktivieren?', + 'app_secure_images_toggle' => 'Aktiviere Bild-Upload höherer Sicherheit', + 'app_secure_images_desc' => 'Aus Leistungsgründen sind alle Bilder öffentlich sichtbar. Diese Option fügt zufällige, schwer zu eratene, Zeichenketten zu Bild-URLs hinzu. Stellen sie sicher, dass Verzeichnisindizes deaktiviert sind, um einen einfachen Zugriff zu verhindern.', + 'app_editor' => 'Seiteneditor', 'app_editor_desc' => 'Wähle den Editor aus, der von allen Benutzern genutzt werden soll, um Seiten zu editieren.', - 'app_primary_color_desc' => "Dies sollte ein HEX Wert sein.\nWenn Du nichts eingibst, wird die Anwendung auf die Standardfarbe zurückgesetzt.", + 'app_custom_html' => 'Benutzerdefinierter HTML Inhalt', + 'app_custom_html_desc' => 'Jeder Inhalt, der hier hinzugefügt wird, wird am Ende der Sektion jeder Seite eingefügt. Diese kann praktisch sein, um CSS Styles anzupassen oder Analytics-Code hinzuzufügen.', + 'app_custom_html_disabled_notice' => 'Benutzerdefinierte HTML-Kopfzeileninhalte sind auf dieser Einstellungsseite deaktiviert, um sicherzustellen, dass alle Änderungen rückgängig gemacht werden können.', + 'app_logo' => 'Anwendungslogo', + 'app_logo_desc' => 'Dieses Bild sollte 43px hoch sein. +Größere Bilder werden verkleinert.', + 'app_primary_color' => 'Primäre Anwendungsfarbe', + 'app_primary_color_desc' => 'Dies sollte ein HEX Wert sein. +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_books' => 'Oder wähle die Buch-Übersicht als Startseite. Das wird die Seiten-Auswahl überschreiben.', + 'app_homepage_select' => 'Wählen Sie eine Seite aus', + '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.', - /** - * Maintenance settings - */ - '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.', + // Color settings + 'content_colors' => 'Inhaltsfarben', + 'content_colors_desc' => 'Legt Farben für alle Elemente in der Seitenorganisationshierarchie fest. Die Auswahl von Farben mit einer ähnlichen Helligkeit wie die Standardfarben wird zur Lesbarkeit empfohlen.', + 'bookshelf_color' => 'Regalfarbe', + 'book_color' => 'Buchfarbe', + 'chapter_color' => 'Kapitelfarbe', + 'page_color' => 'Seitenfarbe', + 'page_draft_color' => 'Seitenentwurfsfarbe', + + // Registration Settings + 'reg_settings' => 'Registrierungseinstellungen', + 'reg_enable' => 'Registrierung erlauben?', + 'reg_enable_toggle' => 'Registrierung erlauben', + 'reg_enable_desc' => 'Wenn die Registrierung erlaubt ist, kann sich der Benutzer als Anwendungsbenutzer anmelden. Bei der Registrierung erhält er eine einzige, voreingestellte Benutzerrolle.', + 'reg_default_role' => 'Standard-Benutzerrolle nach Registrierung', + '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' => 'Bestätigung per E-Mail', + 'reg_email_confirmation_toggle' => 'Bestätigung per E-Mail erforderlich', + 'reg_confirm_email_desc' => 'Falls die Einschränkung für Domains genutzt wird, ist die Bestätigung per E-Mail zwingend erforderlich und der untenstehende Wert wird ignoriert.', + 'reg_confirm_restrict_domain' => 'Registrierung auf bestimmte Domains einschränken', + 'reg_confirm_restrict_domain_desc' => 'Fügen sie eine durch Komma getrennte Liste von Domains hinzu, auf die die Registrierung eingeschränkt werden soll. Benutzern wird eine E-Mail gesendet, um ihre E-Mail Adresse zu bestätigen, bevor sie diese Anwendung nutzen können. +Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung ändern.', + 'reg_confirm_restrict_domain_placeholder' => 'Keine Einschränkung gesetzt', + + // Maintenance settings + '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_image_cleanup_ignore_revisions' => 'Bilder in Versionen ignorieren', + '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.', + 'maint_image_cleanup_nothing_found' => 'Keine unbenutzen Bilder gefunden. Nichts zu löschen!', + 'maint_send_test_email' => 'Test Email versenden', + 'maint_send_test_email_desc' => 'Dies sendet eine Test E-Mail an Ihre in Ihrem Profil angegebene E-Mail-Adresse.', + 'maint_send_test_email_run' => 'Sende eine Test E-Mail', + 'maint_send_test_email_success' => 'E-Mail wurde an :address gesendet', + '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 Sie diese E-Mail Benachrichtigung erhalten haben, scheinen Ihre E-Mail-Einstellungen korrekt konfiguriert zu sein.', - /** - * Role settings - */ + // Role Settings + 'roles' => 'Rollen', + 'role_user_roles' => 'Benutzer-Rollen', + 'role_create' => 'Neue Rolle anlegen', + 'role_create_success' => 'Rolle erfolgreich angelegt', + 'role_delete' => 'Rolle löschen', 'role_delete_confirm' => 'Du möchtest die Rolle ":roleName" löschen.', 'role_delete_users_assigned' => 'Diese Rolle ist :userCount Benutzern zugeordnet. Du kannst unten eine neue Rolle auswählen, die Du diesen Benutzern zuordnen möchtest.', + 'role_delete_no_migration' => "Den Benutzern keine andere Rolle zuordnen", 'role_delete_sure' => 'Bist Du sicher, dass Du diese Rolle löschen möchtest?', + 'role_delete_success' => 'Rolle erfolgreich gelöscht', + 'role_edit' => 'Rolle bearbeiten', + 'role_details' => 'Rollendetails', + 'role_name' => 'Rollenname', + 'role_desc' => 'Kurzbeschreibung der Rolle', + 'role_external_auth_id' => 'Externe Authentifizierungs-IDs', + 'role_system' => 'System-Berechtigungen', + 'role_manage_users' => 'Benutzer verwalten', + 'role_manage_roles' => 'Rollen und Rollen-Berechtigungen verwalten', + 'role_manage_entity_permissions' => 'Alle Buch-, Kapitel- und Seiten-Berechtigungen verwalten', + 'role_manage_own_entity_permissions' => 'Nur Berechtigungen eigener Bücher, Kapitel und Seiten verwalten', + 'role_manage_page_templates' => 'Seitenvorlagen verwalten', + 'role_access_api' => 'Systemzugriffs-API', + 'role_manage_settings' => 'Globaleinstellungen verwalten', + 'role_asset' => 'Berechtigungen', + 'role_asset_desc' => 'Diese Berechtigungen gelten für den Standard-Zugriff innerhalb des Systems. Berechtigungen für Bücher, Kapitel und Seiten überschreiben diese Berechtigungenen.', + 'role_asset_admins' => 'Administratoren erhalten automatisch Zugriff auf alle Inhalte, aber diese Optionen können Oberflächenoptionen ein- oder ausblenden.', + 'role_all' => 'Alle', + 'role_own' => 'Eigene', + 'role_controlled_by_asset' => 'Berechtigungen werden vom Uploadziel bestimmt', + 'role_save' => 'Rolle speichern', + 'role_update_success' => 'Rolle erfolgreich gespeichert', + 'role_users' => 'Dieser Rolle zugeordnete Benutzer', + 'role_users_none' => 'Bisher sind dieser Rolle keine Benutzer zugeordnet', - /** - * Users - */ + // Users + 'users' => 'Benutzer', + 'user_profile' => 'Benutzerprofil', + 'users_add_new' => 'Benutzer hinzufügen', + 'users_search' => 'Benutzer suchen', + 'users_details' => 'Benutzerdetails', + 'users_details_desc' => 'Legen Sie für diesen Benutzer einen Anzeigenamen und eine E-Mail-Adresse fest. Die E-Mail-Adresse wird bei der Anmeldung verwendet.', + 'users_details_desc_no_email' => 'Legen Sie für diesen Benutzer einen Anzeigenamen fest, damit andere ihn erkennen können.', + 'users_role' => 'Benutzerrollen', + 'users_role_desc' => 'Wählen Sie aus, welchen Rollen dieser Benutzer zugeordnet werden soll. Wenn ein Benutzer mehreren Rollen zugeordnet ist, werden die Berechtigungen dieser Rollen gestapelt und er erhält alle Fähigkeiten der zugewiesenen Rollen.', + 'users_password' => 'Benutzerpasswort', + 'users_password_desc' => 'Legen Sie ein Passwort fest, mit dem Sie sich anmelden möchten. Diese muss mindestens 5 Zeichen lang sein.', + 'users_send_invite_text' => 'Sie können diesem Benutzer eine Einladungs-E-Mail senden, die es ihm erlaubt, sein eigenes Passwort zu setzen, andernfalls können Sie sein Passwort selbst setzen.', + 'users_send_invite_option' => 'Benutzer-Einladungs-E-Mail senden', + 'users_external_auth_id' => 'Externe Authentifizierungs-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' => 'Fülle die folgenden Felder nur aus, wenn Du Dein Passwort ändern möchtest:', + 'users_system_public' => 'Dieser Benutzer repräsentiert alle unangemeldeten Benutzer, die diese Seite betrachten. Er kann nicht zum Anmelden benutzt werden, sondern wird automatisch zugeordnet.', + 'users_delete' => 'Benutzer löschen', + '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_delete_success' => 'Benutzer erfolgreich gelöscht.', + 'users_edit' => 'Benutzer bearbeiten', + 'users_edit_profile' => 'Profil bearbeiten', + 'users_edit_success' => 'Benutzer erfolgreich aktualisisert', + 'users_avatar' => 'Benutzer-Bild', + 'users_avatar_desc' => 'Das Bild sollte eine Auflösung von 256x256px haben.', + 'users_preferred_language' => 'Bevorzugte Sprache', + 'users_preferred_language_desc' => 'Diese Option ändert die Sprache, die für die Benutzeroberfläche der Anwendung verwendet wird. Dies hat keinen Einfluss auf von Benutzern erstellte Inhalte.', + 'users_social_accounts' => 'Social-Media Konten', 'users_social_accounts_info' => 'Hier kannst Du andere Social-Media-Konten für eine schnellere und einfachere Anmeldung verknüpfen. Wenn Du ein Social-Media Konto löschst, bleibt der Zugriff erhalten. Entferne in diesem Falle die Berechtigung in Deinen Profil-Einstellungen des verknüpften Social-Media-Kontos.', + 'users_social_connect' => 'Social-Media-Konto verknüpfen', + 'users_social_disconnect' => 'Social-Media-Konto lösen', + 'users_social_connected' => ':socialAccount-Konto wurde erfolgreich mit dem Profil verknüpft.', + 'users_social_disconnected' => ':socialAccount-Konto wurde erfolgreich vom Profil gelöst.', + 'users_api_tokens' => 'API-Token', + 'users_api_tokens_none' => 'Für diesen Benutzer wurden keine API-Token erstellt', + 'users_api_tokens_create' => 'Token erstellen', + 'users_api_tokens_expires' => 'Endet', + 'users_api_tokens_docs' => 'API Dokumentation', + + // API Tokens + 'user_api_token_create' => 'Neuen API-Token erstellen', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Geben Sie Ihrem Token einen aussagekräftigen Namen als spätere Erinnerung an seinen Verwendungszweck.', + 'user_api_token_expiry' => 'Ablaufdatum', + 'user_api_token_expiry_desc' => 'Legen Sie ein Datum fest, an dem dieser Token abläuft. Nach diesem Datum funktionieren Anfragen, die mit diesem Token gestellt werden, nicht mehr. Wenn Sie dieses Feld leer lassen, wird ein Ablaufdatum von 100 Jahren in der Zukunft festgelegt.', + 'user_api_token_create_secret_message' => 'Unmittelbar nach der Erstellung dieses Tokens wird eine "Token ID" & ein "Token Kennwort" generiert und angezeigt. Das Kennwort wird nur ein einziges Mal angezeigt. Stellen Sie also sicher, dass Sie den Inhalt an einen sicheren Ort kopieren, bevor Sie fortfahren.', + 'user_api_token_create_success' => 'API-Token erfolgreich erstellt', + 'user_api_token_update_success' => 'API-Token erfolgreich aktualisiert', + 'user_api_token' => 'API-Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'Dies ist ein nicht editierbarer, vom System generierter Identifikator für diesen Token, welcher bei API-Anfragen angegeben werden muss.', + 'user_api_token_secret' => 'Token Kennwort', + 'user_api_token_secret_desc' => 'Dies ist ein systemgeneriertes Kennwort für diesen Token, das bei API-Anfragen zur Verfügung gestellt werden muss. Es wird nur dieses eine Mal angezeigt, deshalb kopieren Sie diesen Wert an einen sicheren und geschützten Ort.', + 'user_api_token_created' => 'Token erstellt :timeAgo', + 'user_api_token_updated' => 'Token aktualisiert :timeAgo', + 'user_api_token_delete' => 'Lösche Token', + 'user_api_token_delete_warning' => 'Dies löscht den API-Token mit dem Namen \':tokenName\' vollständig aus dem System.', + 'user_api_token_delete_confirm' => 'Sind Sie sicher, dass Sie diesen API-Token löschen möchten?', + 'user_api_token_delete_success' => 'API-Token erfolgreich gelöscht', + + //! 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' => 'العربية', + 'da' => 'Dänisch', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// ]; diff --git a/resources/lang/de_informal/validation.php b/resources/lang/de_informal/validation.php index c82c9e0c4..b6105d192 100644 --- a/resources/lang/de_informal/validation.php +++ b/resources/lang/de_informal/validation.php @@ -1,6 +1,114 @@ ':attribute muss akzeptiert werden.', + 'active_url' => ':attribute ist keine valide URL.', + 'after' => ':attribute muss ein Datum nach :date sein.', + 'alpha' => ':attribute kann nur Buchstaben enthalten.', + 'alpha_dash' => ':attribute kann nur Buchstaben, Zahlen und Bindestriche enthalten.', + 'alpha_num' => ':attribute kann nur Buchstaben und Zahlen enthalten.', + 'array' => ':attribute muss ein Array sein.', + 'before' => ':attribute muss ein Datum vor :date sein.', + 'between' => [ + 'numeric' => ':attribute muss zwischen :min und :max liegen.', + 'file' => ':attribute muss zwischen :min und :max Kilobytes groß sein.', + 'string' => ':attribute muss zwischen :min und :max Zeichen lang sein.', + 'array' => ':attribute muss zwischen :min und :max Elemente enthalten.', + ], + 'boolean' => ':attribute Feld muss wahr oder falsch sein.', + 'confirmed' => ':attribute stimmt nicht überein.', + 'date' => ':attribute ist kein valides Datum.', + 'date_format' => ':attribute entspricht nicht dem Format :format.', + 'different' => ':attribute und :other müssen unterschiedlich sein.', + 'digits' => ':attribute muss :digits Stellen haben.', + 'digits_between' => ':attribute muss zwischen :min und :max Stellen haben.', + 'email' => ':attribute muss eine valide E-Mail-Adresse sein.', + 'ends_with' => ':attribute muss mit einem der folgenden Werte: :values enden', + 'filled' => ':attribute ist erforderlich.', + 'gt' => [ + 'numeric' => ':attribute muss größer als :value sein.', + 'file' => ':attribute muss mindestens :value Kilobytes groß sein.', + 'string' => ':attribute muss mehr als :value Zeichen haben.', + 'array' => ':attribute muss mindestens :value Elemente haben.', + ], + 'gte' => [ + 'numeric' => ':attribute muss größer-gleich :value sein.', + 'file' => ':attribute muss mindestens :value Kilobytes groß sein.', + 'string' => ':attribute muss mindestens :value Zeichen enthalten.', + 'array' => ':attribute muss :value Elemente oder mehr haben.', + ], + 'exists' => ':attribute ist ungültig.', + 'image' => ':attribute muss ein Bild sein.', + 'image_extension' => ':attribute muss eine gültige und unterstützte Bild-Dateiendung haben.', + 'in' => ':attribute ist ungültig.', + 'integer' => ':attribute muss eine Zahl sein.', + 'ip' => ':attribute muss eine valide IP-Adresse sein.', + 'ipv4' => ':attribute muss eine gültige IPv4 Adresse sein.', + 'ipv6' => ':attribute muss eine gültige IPv6-Adresse sein.', + 'json' => 'Das Attribut muss eine gültige JSON-Zeichenfolge sein.', + 'lt' => [ + 'numeric' => ':attribute muss kleiner sein :value sein.', + 'file' => ':attribute muss kleiner als :value Kilobytes sein.', + 'string' => ':attribute muss weniger als :value Zeichen haben.', + 'array' => ':attribute muss weniger als :value Elemente haben.', + ], + 'lte' => [ + 'numeric' => ':attribute muss kleiner oder gleich :value sein.', + 'file' => ':attribute muss kleiner oder gleich :value Kilobytes sein.', + 'string' => ':attribute darf höchstens :value Zeichen besitzen.', + 'array' => ':attribute darf höchstens :value Elemente haben.', + ], + 'max' => [ + 'numeric' => ':attribute darf nicht größer als :max sein.', + 'file' => ':attribute darf nicht größer als :max Kilobyte sein.', + 'string' => ':attribute darf nicht länger als :max Zeichen sein.', + 'array' => ':attribute darf nicht mehr als :max Elemente enthalten.', + ], + 'mimes' => ':attribute muss eine Datei vom Typ: :values sein.', + 'min' => [ + 'numeric' => ':attribute muss mindestens :min sein', + 'file' => ':attribute muss mindestens :min Kilobyte groß sein.', + '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.', + 'regex' => ':attribute ist in einem ungültigen Format.', + 'required' => ':attribute ist erforderlich.', + 'required_if' => ':attribute ist erforderlich, wenn :other :value ist.', + 'required_with' => ':attribute ist erforderlich, wenn :values vorhanden ist.', + 'required_with_all' => ':attribute ist erforderlich, wenn :values vorhanden sind.', + 'required_without' => ':attribute ist erforderlich, wenn :values nicht vorhanden ist.', + 'required_without_all' => ':attribute ist erforderlich, wenn :values nicht vorhanden sind.', + 'same' => ':attribute und :other müssen übereinstimmen.', + 'size' => [ + 'numeric' => ':attribute muss :size sein.', + 'file' => ':attribute muss :size Kilobytes groß sein.', + 'string' => ':attribute muss :size Zeichen lang sein.', + 'array' => ':attribute muss :size Elemente enthalten.', + ], + 'string' => ':attribute muss eine Zeichenkette sein.', + 'timezone' => ':attribute muss eine valide zeitzone sein.', + 'unique' => ':attribute wird bereits verwendet.', + 'url' => ':attribute ist kein valides Format.', + 'uploaded' => 'Die Datei konnte nicht hochgeladen werden. Der Server akzeptiert möglicherweise keine Dateien dieser Größe.', + + // Custom validation lines + 'custom' => [ + 'password-confirm' => [ + 'required_with' => 'Passwortbestätigung erforderlich', + ], + ], + + // Custom validation attributes + 'attributes' => [], +]; diff --git a/resources/lang/en/auth.php b/resources/lang/en/auth.php index 37346097f..6961e049b 100644 --- a/resources/lang/en/auth.php +++ b/resources/lang/en/auth.php @@ -21,7 +21,7 @@ return [ 'email' => 'Email', 'password' => 'Password', 'password_confirm' => 'Confirm Password', - 'password_hint' => 'Must be over 5 characters', + '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.', diff --git a/resources/lang/en/common.php b/resources/lang/en/common.php index 1807217a3..c8b4a2b22 100644 --- a/resources/lang/en/common.php +++ b/resources/lang/en/common.php @@ -38,6 +38,7 @@ return [ 'reset' => 'Reset', 'remove' => 'Remove', 'add' => 'Add', + 'fullscreen' => 'Fullscreen', // Sort Options 'sort_options' => 'Sort Options', diff --git a/resources/lang/en/errors.php b/resources/lang/en/errors.php index c3b47744d..4752d8b0c 100644 --- a/resources/lang/en/errors.php +++ b/resources/lang/en/errors.php @@ -13,10 +13,16 @@ return [ '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.', @@ -82,4 +88,12 @@ return [ 'app_down' => ':appName is down right now', 'back_soon' => 'It will be back up soon.', + // 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', + ]; diff --git a/resources/lang/en/passwords.php b/resources/lang/en/passwords.php index 9f7d9e3cb..f41ca7868 100644 --- a/resources/lang/en/passwords.php +++ b/resources/lang/en/passwords.php @@ -6,7 +6,7 @@ */ return [ - 'password' => 'Passwords must be at least six characters and match the confirmation.', + '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' => 'This password reset token is invalid.', 'sent' => 'We have e-mailed your password reset link!', diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index bb542a588..ab274256f 100755 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -33,7 +33,7 @@ return [ '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' => 'This should be a hex value.
Leave empty to reset to the default 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', @@ -41,12 +41,22 @@ return [ '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.', @@ -63,6 +73,13 @@ return [ '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.', // Role Settings 'roles' => 'Roles', @@ -86,6 +103,7 @@ return [ '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', 'role_asset_desc' => 'These permissions control default access to the assets within the system. Permissions on Books, Chapters and Pages will override these permissions.', @@ -113,7 +131,7 @@ return [ '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 LDAP system.', + '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', @@ -134,14 +152,40 @@ return [ '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', - //! Since these labels are already localized this array does not need to be - //! translated in the language-specific files. - //! DELETE BELOW IF COPIED FROM EN + // 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' => 'العربية', + 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', @@ -152,15 +196,16 @@ return [ 'sk' => 'Slovensky', 'cs' => 'Česky', 'sv' => 'Svenska', - 'kr' => '한국어', + 'ko' => '한국어', 'ja' => '日本語', 'pl' => 'Polski', 'it' => 'Italian', 'ru' => 'Русский', 'uk' => 'Українська', 'zh_CN' => '简体中文', - 'zh_TW' => '繁體中文', - 'hu' => 'Magyar' + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', ] //!//////////////////////////////// ]; diff --git a/resources/lang/en/validation.php b/resources/lang/en/validation.php index 210980ac2..76b57a2a3 100644 --- a/resources/lang/en/validation.php +++ b/resources/lang/en/validation.php @@ -12,7 +12,7 @@ return [ '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, and dashes.', + '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.', @@ -30,13 +30,41 @@ return [ '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.', + '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.', + ], + '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.', + ], '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.', + '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.', + ], + '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.', + ], 'max' => [ 'numeric' => 'The :attribute may not be greater than :max.', 'file' => 'The :attribute may not be greater than :max kilobytes.', @@ -52,6 +80,7 @@ return [ ], '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.', diff --git a/resources/lang/es/auth.php b/resources/lang/es/auth.php index f693e7976..3636507fe 100644 --- a/resources/lang/es/auth.php +++ b/resources/lang/es/auth.php @@ -21,7 +21,7 @@ return [ 'email' => 'Correo electrónico', 'password' => 'Contraseña', 'password_confirm' => 'Confirmar Contraseña', - 'password_hint' => 'Debe contener más de 5 caracteres', + 'password_hint' => 'Debe contener más de 7 caracteres', 'forgot_password' => '¿Contraseña Olvidada?', 'remember_me' => 'Recordarme', 'ldap_email_hint' => 'Por favor introduzca un mail para utilizar con esta cuenta.', diff --git a/resources/lang/es/common.php b/resources/lang/es/common.php index 3c9cfa69b..45eff2d5f 100644 --- a/resources/lang/es/common.php +++ b/resources/lang/es/common.php @@ -20,7 +20,7 @@ return [ 'role' => 'Rol', 'cover_image' => 'Imagen de portada', 'cover_image_description' => 'Esta imagen debe ser aproximadamente de 440x250px.', - + // Actions 'actions' => 'Acciones', 'view' => 'Ver', @@ -38,6 +38,7 @@ return [ 'reset' => 'Resetear', 'remove' => 'Remover', 'add' => 'Añadir', + 'fullscreen' => 'Pantalla completa', // Sort Options 'sort_options' => 'Opciones de ordenación', diff --git a/resources/lang/es/entities.php b/resources/lang/es/entities.php index db87efda7..f67a0a3a3 100644 --- a/resources/lang/es/entities.php +++ b/resources/lang/es/entities.php @@ -18,10 +18,10 @@ return [ 'create_now' => 'Crear uno ahora', 'revisions' => 'Revisiones', 'meta_revision' => 'Revisión #:revisionCount', - 'meta_created' => 'Creado el :timeLength', - 'meta_created_name' => 'Creado el :timeLength por :user', - 'meta_updated' => 'Actualizado el :timeLength', - 'meta_updated_name' => 'Actualizado el :timeLength por :user', + 'meta_created' => 'Creado :timeLength', + 'meta_created_name' => 'Creado :timeLength por :user', + 'meta_updated' => 'Actualizado :timeLength', + 'meta_updated_name' => 'Actualizado :timeLength por :user', 'entity_select' => 'Seleccione entidad', 'images' => 'Imágenes', 'my_recent_drafts' => 'Mis borradores recientes', @@ -181,7 +181,7 @@ return [ 'pages_edit_draft' => 'Editar borrador de página', 'pages_editing_draft' => 'Editando borrador', 'pages_editing_page' => 'Editando página', - 'pages_edit_draft_save_at' => 'Borrador guardado el ', + 'pages_edit_draft_save_at' => 'Borrador guardado ', 'pages_edit_delete_draft' => 'Borrar borrador', 'pages_edit_discard_draft' => 'Descartar borrador', 'pages_edit_set_changelog' => 'Ajustar Log de cambios', diff --git a/resources/lang/es/errors.php b/resources/lang/es/errors.php index 77d5520f4..65b20afc7 100644 --- a/resources/lang/es/errors.php +++ b/resources/lang/es/errors.php @@ -5,18 +5,24 @@ return [ // Permissions - 'permission' => 'No tiene permisos para visualizar la página solicitada.', - 'permissionJson' => 'No tiene permisos para ejecutar la acción solicitada.', + 'permission' => 'No tienes permisos para visualizar la página solicitada.', + 'permissionJson' => 'No tienes permisos para ejecutar la acción solicitada.', // Auth 'error_user_exists_different_creds' => 'Un usuario con el correo electrónico :email ya existe pero con credenciales diferentes.', 'email_already_confirmed' => 'El correo electrónico ya ha sido confirmado, intente acceder a la aplicación.', 'email_confirmation_invalid' => 'Este token de confirmación no es válido o ya ha sido usado, intente registrar uno nuevamente.', 'email_confirmation_expired' => 'El token de confirmación ha expirado, un nuevo email de confirmacón ha sido enviado.', + 'email_confirmation_awaiting' => 'La dirección de correo electrónico de la cuenta en uso debe ser confirmada', 'ldap_fail_anonymous' => 'El acceso con LDAP ha fallado usando binding anónimo', 'ldap_fail_authed' => 'El acceso LDAP ha fallado usando el dn & contraseña enviados', 'ldap_extension_not_installed' => 'La extensión LDAP PHP no se encuentra instalada', 'ldap_cannot_connect' => 'No se puede conectar con el servidor ldap, la conexión inicial ha fallado', + 'saml_already_logged_in' => 'Ya estás conectado', + 'saml_user_not_registered' => 'El usuario :name no está registrado y el registro automático está deshabilitado', + 'saml_no_email_address' => 'No se pudo encontrar una dirección de correo electrónico, para este usuario, en los datos proporcionados por el sistema de autenticación externo', + 'saml_invalid_response_id' => 'La solicitud del sistema de autenticación externo no está reconocida por un proceso iniciado por esta aplicación. Navegar hacia atrás después de un inicio de sesión podría causar este problema.', + 'saml_fail_authed' => 'El inicio de sesión con :system falló, el sistema no proporcionó una autorización correcta', 'social_no_action_defined' => 'Acción no definida', 'social_login_bad_response' => "Se ha recibido un error durante el acceso con :socialAccount error: \n:error", 'social_account_in_use' => 'la cuenta :socialAccount ya se encuentra en uso, intente acceder a través de la opción :socialAccount .', @@ -82,4 +88,12 @@ return [ 'app_down' => 'La aplicación :appName se encuentra caída en este momento', 'back_soon' => 'Volverá a estar operativa pronto.', + // API errors + 'api_no_authorization_found' => 'No se encontró ningún token de autorización en la solicitud', + 'api_bad_authorization_format' => 'Se ha encontrado un token de autorización en la solicitud pero el formato era incorrecto', + 'api_user_token_not_found' => 'No se ha encontrado un token API que corresponda con el token de autorización proporcionado', + 'api_incorrect_token_secret' => 'El secreto proporcionado para el token API usado es incorrecto', + 'api_user_no_api_permission' => 'El propietario del token API usado no tiene permiso para hacer llamadas API', + 'api_user_token_expired' => 'El token de autorización usado ha caducado', + ]; diff --git a/resources/lang/es/settings.php b/resources/lang/es/settings.php index f063328f1..ff5c40ee1 100644 --- a/resources/lang/es/settings.php +++ b/resources/lang/es/settings.php @@ -41,12 +41,22 @@ return [ '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.', + // Color settings + 'content_colors' => 'Colores del contenido', + 'content_colors_desc' => 'Establece los colores para todos los elementos en la jerarquía de la organización de la página. Se recomienda elegir colores con un brillo similar al predeterminado para mayor legibilidad.', + 'bookshelf_color' => 'Color del estante', + 'book_color' => 'Color del libro', + 'chapter_color' => 'Color del capítulo', + 'page_color' => 'Color de la página', + 'page_draft_color' => 'Color del borrador de página', + // Registration Settings 'reg_settings' => 'Registro', 'reg_enable' => 'Habilitar Registro', 'reg_enable_toggle' => 'Habilitar registro', 'reg_enable_desc' => 'Cuando se habilita el registro los usuarios podrán registrarse como usuarios de la aplicación. Al registrarse se les asigna un rol único por defecto.', 'reg_default_role' => 'Rol de usuario por defecto después del registro', + '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' => 'Confirmación por Email', 'reg_email_confirmation_toggle' => 'Requerir confirmación por Email', 'reg_confirm_email_desc' => 'Si se emplea la restricción por dominio, entonces se requerirá la confirmación por correo electrónico y esta opción será ignorada.', @@ -63,6 +73,13 @@ return [ 'maint_image_cleanup_warning' => 'Se han encontrado :count imágenes posiblemente no utilizadas . ¿Estás seguro de querer borrar estas imágenes?', 'maint_image_cleanup_success' => '¡Se han encontrado y borrado :count imágenes posiblemente no utilizadas!', 'maint_image_cleanup_nothing_found' => '¡No se han encontrado imágenes sin utilizar, no se han borrado imágenes!', + 'maint_send_test_email' => 'Enviar un correo electrónico de prueba', + 'maint_send_test_email_desc' => 'Esto envía un correo electrónico de prueba a la dirección de correo electrónico especificada en tu perfil.', + 'maint_send_test_email_run' => 'Enviar correo electrónico de prueba', + 'maint_send_test_email_success' => 'Correo electrónico enviado a :address', + 'maint_send_test_email_mail_subject' => 'Probar correo electrónico', + 'maint_send_test_email_mail_greeting' => '¡El envío de correos electrónicos parece funcionar!', + 'maint_send_test_email_mail_text' => '¡Enhorabuena! Al recibir esta notificación de correo electrónico, tu configuración de correo electrónico parece estar ajustada correctamente.', // Role Settings 'roles' => 'Roles', @@ -86,6 +103,7 @@ return [ 'role_manage_entity_permissions' => 'Gestionar todos los permisos de libros, capítulos y páginas', 'role_manage_own_entity_permissions' => 'Gestionar permisos en libros, capítulos y páginas propias', 'role_manage_page_templates' => 'Administrar plantillas', + 'role_access_api' => 'API de sistema de acceso', 'role_manage_settings' => 'Gestionar ajustes de la aplicación', 'role_asset' => 'Permisos de contenido', 'role_asset_desc' => 'Estos permisos controlan el acceso por defecto a los contenidos del sistema. Los permisos de Libros, Capítulos y Páginas sobreescribiran estos permisos.', @@ -102,10 +120,10 @@ return [ 'users' => 'Usuarios', 'user_profile' => 'Perfil de Usuario', 'users_add_new' => 'Agregar Nuevo Usuario', + 'users_search' => 'Buscar usuarios', 'users_details' => 'Detalles de Usuario', 'users_details_desc' => 'Ajusta un nombre público y email para este usuario. El email será empleado para acceder a la aplicación.', 'users_details_desc_no_email' => 'Ajusta un nombre público para este usuario para que pueda ser reconocido por otros.', - 'users_search' => 'Buscar usuarios', 'users_role' => 'Roles de usuario', 'users_role_desc' => 'Selecciona los roles a los que será asignado este usuario. Si se asignan varios roles los permisos se acumularán y recibirá todas las habilidades de los roles asignados.', 'users_password' => 'Contraseña de Usuario', @@ -113,7 +131,7 @@ return [ 'users_send_invite_text' => 'Puede enviar una invitación a este usuario por correo electrónico que le permitirá ajustar su propia contraseña, o puede usted ajustar su contraseña.', 'users_send_invite_option' => 'Enviar un correo electrónico de invitación', 'users_external_auth_id' => 'ID externo de autenticación', - 'users_external_auth_id_desc' => 'Esta es la ID usada para asociar este usuario con LDAP.', + 'users_external_auth_id_desc' => 'Esta es la ID usada para asociar este usuario con el sistema de autenticación externo.', 'users_password_warning' => 'Solo debe rellenar este campo si desea cambiar su contraseña.', 'users_system_public' => 'Este usuario representa cualquier usuario invitado que visita la aplicación. No puede utilizarse para acceder pero es asignado automáticamente.', 'users_delete' => 'Borrar usuario', @@ -134,5 +152,60 @@ return [ 'users_social_disconnect' => 'Desconectar cuenta', 'users_social_connected' => 'La cuenta :socialAccount ha sido añadida éxitosamente a su perfil.', 'users_social_disconnected' => 'La cuenta :socialAccount ha sido desconectada éxitosamente de su perfil.', + 'users_api_tokens' => 'Tokens API', + 'users_api_tokens_none' => 'No se han creado tokens API para este usuario', + 'users_api_tokens_create' => 'Crear token', + 'users_api_tokens_expires' => 'Expira', + 'users_api_tokens_docs' => 'Documentación API', + // API Tokens + 'user_api_token_create' => 'Crear token API', + 'user_api_token_name' => 'Nombre', + 'user_api_token_name_desc' => 'Dale a tu token un nombre legible como un recordatorio futuro de su propósito.', + 'user_api_token_expiry' => 'Fecha de expiración', + 'user_api_token_expiry_desc' => 'Establece una fecha en la que este token expira. Después de esta fecha, las solicitudes realizadas usando este token ya no funcionarán. Dejar este campo en blanco fijará un vencimiento de 100 años en el futuro.', + 'user_api_token_create_secret_message' => 'Inmediatamente después de crear este token se generarán y mostrarán sus correspondientes "Token ID" y "Token Secret". El "Token Secret" sólo se mostrará una vez, así que asegúrese de copiar el valor a un lugar seguro antes de proceder.', + 'user_api_token_create_success' => 'Token API creado correctamente', + 'user_api_token_update_success' => 'Token API actualizado correctamente', + 'user_api_token' => 'Token API', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'Este es un identificador no editable generado por el sistema y único para este token que necesitará ser proporcionado en solicitudes de API.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'Esta es una clave no editable generada por el sistema que necesitará ser proporcionada en solicitudes de API. Solo se monstraré esta vez así que guarde su valor en un lugar seguro.', + 'user_api_token_created' => 'Token creado :timeAgo', + 'user_api_token_updated' => 'Token actualizado :timeAgo', + 'user_api_token_delete' => 'Borrar token', + 'user_api_token_delete_warning' => 'Esto eliminará completamente este token API con el nombre \':tokenName\' del sistema.', + 'user_api_token_delete_confirm' => '¿Está seguro de que desea borrar este API token?', + 'user_api_token_delete_success' => 'Token API borrado correctamente', + + //! 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' => 'العربية', + 'da' => 'Danés', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// ]; diff --git a/resources/lang/es/validation.php b/resources/lang/es/validation.php index 26f713ebd..de6094a71 100644 --- a/resources/lang/es/validation.php +++ b/resources/lang/es/validation.php @@ -30,13 +30,41 @@ return [ 'digits' => ':attribute debe ser de :digits dígitos.', 'digits_between' => ':attribute debe ser un valor entre :min y :max dígios.', 'email' => ':attribute debe ser un correo electrónico válido.', + 'ends_with' => 'El :attribute debe terminar con uno de los siguientes: :values', 'filled' => 'El campo :attribute es requerido.', + 'gt' => [ + 'numeric' => 'El :attribute debe ser mayor que :value.', + 'file' => 'El :attribute debe ser mayor que :value kilobytes.', + 'string' => 'El :attribute debe ser mayor que :value caracteres.', + 'array' => 'El :attribute debe tener más de :value elementos.', + ], + 'gte' => [ + 'numeric' => 'El :attribute debe ser mayor o igual que :value.', + 'file' => 'El :attribute debe ser mayor o igual que :value kilobytes.', + 'string' => 'El :attribute debe ser mayor o igual que :value caracteres.', + 'array' => 'El :attribute debe tener :value o más elementos.', + ], 'exists' => 'El :attribute seleccionado es inválido.', 'image' => 'El :attribute debe ser una imagen.', 'image_extension' => 'El :attribute debe tener una extensión de imagen válida y soportada.', 'in' => 'El selected :attribute es inválio.', 'integer' => 'El :attribute debe ser un entero.', 'ip' => 'El :attribute debe ser una dirección IP válida.', + 'ipv4' => 'El :attribute debe ser una dirección IPv4 válida.', + 'ipv6' => 'El :attribute debe ser una dirección IPv6 válida.', + 'json' => 'El :attribute debe ser una cadena JSON válida.', + 'lt' => [ + 'numeric' => 'El :attribute debe ser menor que :value.', + 'file' => 'El :attribute debe ser menor que :value kilobytes.', + 'string' => 'El :attribute debe ser menor que :value caracteres.', + 'array' => 'El :attribute debe tener menos de :value elementos.', + ], + 'lte' => [ + 'numeric' => 'El :attribute debe ser menor o igual que :value.', + 'file' => 'El :attribute debe ser menor o igual que :value kilobytes.', + 'string' => 'El :attribute debe ser menor o igual que :value caracteres.', + 'array' => 'El :attribute no debe tener más de :value elementos.', + ], 'max' => [ 'numeric' => 'El :attribute no puede ser mayor que :max.', 'file' => 'El :attribute no puede ser mayor que :max kilobytes.', @@ -52,6 +80,7 @@ return [ ], '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.', 'regex' => 'El formato de :attribute es inválido', 'required' => 'El :attribute es requerido.', diff --git a/resources/lang/es_AR/activities.php b/resources/lang/es_AR/activities.php index fd5c8307b..f8f9e8436 100644 --- a/resources/lang/es_AR/activities.php +++ b/resources/lang/es_AR/activities.php @@ -2,9 +2,6 @@ /** * Activity text strings. * Is used for all the text within activity logs & notifications. - * - * Cadenas de texto de Actividades - * Se usa para todos los textos dentro de los registros de actividad y notificaciones. */ return [ diff --git a/resources/lang/es_AR/auth.php b/resources/lang/es_AR/auth.php index e8a62562b..aa54fa71f 100644 --- a/resources/lang/es_AR/auth.php +++ b/resources/lang/es_AR/auth.php @@ -3,16 +3,13 @@ * Authentication Language Lines * The following language lines are used during authentication for various * messages that we need to display to the user. - * - * Líneas de lenguaje para autenticación - * Las siguientes líneas de lenguaje se utilizan para mostrar mensajes al usuario durante la autenticación. */ return [ 'failed' => 'Las credenciales no concuerdan con nuestros registros.', 'throttle' => 'Demasiados intentos fallidos de conexión. Por favor intente nuevamente en :seconds segundos.', - // Login & Register - Ingreso y Registro + // Login & Register 'sign_up' => 'Registrarse', 'log_in' => 'Acceder', 'log_in_with' => 'Acceder con :socialDriver', @@ -24,7 +21,7 @@ return [ 'email' => 'Correo electrónico', 'password' => 'Contraseña', 'password_confirm' => 'Confirmar contraseña', - 'password_hint' => 'Debe contener al menos 5 caracteres', + 'password_hint' => 'Debe contener al menos 7 caracteres', 'forgot_password' => '¿Olvidó la contraseña?', 'remember_me' => 'Recordarme', 'ldap_email_hint' => 'Por favor introduzca un correo electrónico para utilizar con esta cuenta.', @@ -42,19 +39,18 @@ return [ 'register_success' => '¡Gracias por registrarse! Ahora se encuentra registrado y ha accedido a la aplicación.', - // Password Reset - Restablecer Contraseña + // Password Reset 'reset_password' => 'Restablecer la contraseña', 'reset_password_send_instructions' => 'Introduzca su correo electrónico a continuación y se le enviará un correo electrónico con un enlace para la restauración', 'reset_password_send_button' => 'Enviar enlace de restauración', 'reset_password_sent_success' => 'Se envió un enlace para restablecer la contraseña a :email.', 'reset_password_success' => 'Su contraseña se restableció con éxito.', - 'email_reset_subject' => 'Restauración de la contraseña de para la aplicación :appName', 'email_reset_text' => 'Ud. esta recibiendo este correo electrónico debido a que recibimos una solicitud de restauración de la contraseña de su cuenta.', 'email_reset_not_requested' => 'Si ud. no solicitó un cambio de contraseña, no se requiere ninguna acción.', - // Email Confirmation - Confirmación de correo electrónico + // Email Confirmation 'email_confirm_subject' => 'Confirme su correo electrónico en :appName', 'email_confirm_greeting' => '¡Gracias por unirse a :appName!', 'email_confirm_text' => 'Por favor confirme su dirección de correo electrónico presionando en el siguiente botón:', @@ -78,4 +74,4 @@ return [ 'user_invite_page_text' => 'Para finalizar la cuenta y tener acceso debe establcer una contraseña que utilizará para ingresar a :appName en visitas futuras.', 'user_invite_page_confirm_button' => 'Confirmar Contraseña', 'user_invite_success' => 'Contraseña establecida, ahora tiene acceso a :appName!' -]; +]; \ No newline at end of file diff --git a/resources/lang/es_AR/common.php b/resources/lang/es_AR/common.php index 4738897ea..b7201101c 100644 --- a/resources/lang/es_AR/common.php +++ b/resources/lang/es_AR/common.php @@ -1,12 +1,10 @@ 'Cancelar', 'confirm' => 'Confirmar', 'back' => 'Atrás', @@ -15,15 +13,15 @@ return [ 'select' => 'Seleccionar', 'toggle_all' => 'Alternar todo', 'more' => 'Más', - - // Form Labels - Etiquetas de Formularios + + // Form Labels 'name' => 'Nombre', 'description' => 'Descripción', 'role' => 'Rol', 'cover_image' => 'Imagen de cubierta', 'cover_image_description' => 'Esta imagen debe ser de 440x250px aproximadamente.', - - // Actions - Acciones + + // Actions 'actions' => 'Acciones', 'view' => 'Ver', 'view_all' => 'Ver todo', @@ -40,8 +38,9 @@ return [ 'reset' => 'Restablecer', 'remove' => 'Remover', 'add' => 'Agregar', + 'fullscreen' => 'Pantalla completa', - // Sort Options - Opciones de filtro + // Sort Options 'sort_options' => 'Opciones de Orden', 'sort_direction_toggle' => 'Cambiar Dirección de Orden', 'sort_ascending' => 'Orden Ascendente', @@ -50,29 +49,29 @@ return [ 'sort_created_at' => 'Fecha de creación', 'sort_updated_at' => 'Fecha de actualización', - //Misc + // Misc 'deleted_user' => 'Usuario borrado', 'no_activity' => 'Ninguna actividad para mostrar', 'no_items' => 'No hay items disponibles', 'back_to_top' => 'Volver arriba', 'toggle_details' => 'Alternar detalles', - "toggle_thumbnails" => "Alternar miniaturas", + 'toggle_thumbnails' => 'Alternar miniaturas', 'details' => 'Detalles', - "grid_view" => "Vista de grilla", - "list_view" => "Vista de lista", + 'grid_view' => 'Vista de grilla', + 'list_view' => 'Vista de lista', 'default' => 'Por defecto', 'breadcrumb' => 'Miga de Pan', - // Header - Cabecera + // Header 'profile_menu' => 'Menu del Perfil', 'view_profile' => 'Ver Perfil', 'edit_profile' => 'Editar Perfil', - // Layout tabs - Pestañas de visualización + // Layout tabs 'tab_info' => 'Información', 'tab_content' => 'Contenido', - // Email Content - Contenido de correo Electrónico + // 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', ]; diff --git a/resources/lang/es_AR/components.php b/resources/lang/es_AR/components.php index ea61f5f4c..d205afbc1 100644 --- a/resources/lang/es_AR/components.php +++ b/resources/lang/es_AR/components.php @@ -1,9 +1,10 @@ 'Seleccionar Imagen', 'image_all' => 'Todo', 'image_all_title' => 'Ver todas las imágenes', @@ -24,9 +25,7 @@ return [ 'image_delete_success' => 'Imagen borrada exitosamente', 'image_upload_remove' => 'Quitar', - /** - * Code editor - */ + // Code Editor 'code_editor' => 'Editar Código', 'code_language' => 'Lenguaje del Código', 'code_content' => 'Contenido del Código', diff --git a/resources/lang/es_AR/entities.php b/resources/lang/es_AR/entities.php index 8cb840c06..700e873c3 100644 --- a/resources/lang/es_AR/entities.php +++ b/resources/lang/es_AR/entities.php @@ -2,13 +2,10 @@ /** * Text used for 'Entities' (Document Structure Elements) such as * Books, Shelves, Chapters & Pages - * - * Texto utilizado para 'Entities' (Elementos de Estructura de - * los Documentos) como Libros, Estantes, Capítulos y Páginas */ return [ - // Shared - Compartido + // Shared 'recently_created' => 'Creado recientemente', 'recently_created_pages' => 'Páginas creadas recientemente', 'recently_updated_pages' => 'Páginas actualizadas recientemente', @@ -37,13 +34,13 @@ return [ 'export_pdf' => 'Archivo PDF', 'export_text' => 'Archivo de texto plano', - // Permissions and restrictions - Permisos y Restricciones + // Permissions and restrictions 'permissions' => 'Permisos', 'permissions_intro' => 'una vez habilitado, Estos permisos tendrán prioridad por encima de cualquier permiso establecido.', 'permissions_enable' => 'Habilitar permisos custom', 'permissions_save' => 'Guardar permisos', - // Search - Búsqueda + // Search 'search_results' => 'Buscar resultados', 'search_total_results_found' => ':count resultados encontrados|:count total de resultados encontrados', 'search_clear' => 'Limpiar resultados', @@ -68,7 +65,7 @@ return [ 'search_set_date' => 'Esablecer fecha', 'search_update' => 'Actualizar búsqueda', - // Shelves - Estantes + // Shelves 'shelf' => 'Estante', 'shelves' => 'Estantes', 'x_shelves' => ':count Estante|:count Estantes', @@ -100,7 +97,7 @@ return [ 'shelves_copy_permissions_explain' => 'Esta acción aplicará los permisos de este estante a todos los libros contenidos en él. Antes de activarlos, asegúrese que los cambios a los permisos de este estante estén guardados.', 'shelves_copy_permission_success' => 'Se copiaron los permisos del estante a :count libros', - // Books - Libros + // Books 'book' => 'Libro', 'books' => 'Libros', 'x_books' => ':count Libro|:count Libros', @@ -139,7 +136,7 @@ return [ 'books_sort_show_other' => 'Mostrar otros libros', 'books_sort_save' => 'Guardar nuevo orden', - // Chapters - Capítulos + // Chapters 'chapter' => 'Capítulo', 'chapters' => 'Capítulos', 'x_chapters' => ':count Capítulo|:count Capítulos', @@ -162,7 +159,7 @@ return [ 'chapters_permissions_success' => 'Permisos de capítulo actualizados', 'chapters_search_this' => 'Buscar en este capítulo', - // Pages - Páginas + // Pages 'page' => 'Página', 'pages' => 'Páginas', 'x_pages' => ':count Página|:count Páginas', @@ -239,11 +236,11 @@ return [ 'pages_specific' => 'Página Específica', 'pages_is_template' => 'Plantilla de Página', - // Editor sidebar - Barra lateral del editor + // Editor Sidebar 'page_tags' => 'Etiquetas de página', 'chapter_tags' => 'Etiquetas de capítulo', 'book_tags' => 'Etiquetas de libro', - 'shelf_tags' => 'Shelf Tags', + 'shelf_tags' => 'Etiquetas de Estante', 'tag' => 'Etiqueta', 'tags' => 'Etiquetas', 'tag_name' => 'Nombre de etiqueta', @@ -283,7 +280,7 @@ return [ 'templates_append_content' => 'Incorporar al fina del contenido de la página', 'templates_prepend_content' => 'Incorporar al principio del contenido de la página', - // Profile View - Vista de Perfil + // Profile View 'profile_user_for_x' => 'Usuario para :time', 'profile_created_content' => 'Contenido creado', 'profile_not_created_pages' => ':userName no ha creado páginas', @@ -291,8 +288,7 @@ return [ 'profile_not_created_books' => ':userName no ha creado libros', 'profile_not_created_shelves' => ':userName no ha creado estantes', - - // Comments - Comentarios + // Comments 'comment' => 'Comentario', 'comments' => 'Comentarios', 'comment_add' => 'Agregar comentario', @@ -310,9 +306,9 @@ return [ 'comment_delete_confirm' => '¿Está seguro que quiere borrar este comentario?', 'comment_in_reply_to' => 'En respuesta a :commentId', - // Revision - Revisión + // Revision 'revision_delete_confirm' => '¿Está seguro de que quiere eliminar esta revisión?', 'revision_restore_confirm' => '¿Está seguro de que quiere restaurar esta revisión? Se reemplazará el contenido de la página actual.', 'revision_delete_success' => 'Revisión eliminada', 'revision_cannot_delete_latest' => 'No se puede eliminar la última revisión.' -]; +]; \ No newline at end of file diff --git a/resources/lang/es_AR/errors.php b/resources/lang/es_AR/errors.php index f88718545..a3ce98e08 100644 --- a/resources/lang/es_AR/errors.php +++ b/resources/lang/es_AR/errors.php @@ -1,11 +1,9 @@ 'Ud. no tiene permisos para visualizar la página solicitada.', 'permissionJson' => 'Ud. no tiene permisos para ejecutar la acción solicitada.', @@ -15,10 +13,16 @@ return [ 'email_already_confirmed' => 'El email ya ha sido confirmado, Intente loguearse en la aplicación.', 'email_confirmation_invalid' => 'Este token de confirmación no e válido o ya ha sido usado,Intente registrar uno nuevamente.', 'email_confirmation_expired' => 'El token de confirmación ha expirado, Un nuevo email de confirmacón ha sido enviado.', + 'email_confirmation_awaiting' => 'La dirección de correo electrónico de la cuenta en uso debe ser confirmada', 'ldap_fail_anonymous' => 'El acceso con LDAP ha fallado usando binding anónimo', 'ldap_fail_authed' => 'El acceso LDAP usando el dn & password detallados', 'ldap_extension_not_installed' => 'La extensión LDAP PHP no se encuentra instalada', 'ldap_cannot_connect' => 'No se puede conectar con el servidor ldap, la conexión inicial ha fallado', + 'saml_already_logged_in' => 'Ya estás conectado', + 'saml_user_not_registered' => 'El usuario :name no está registrado y el registro automático está deshabilitado', + 'saml_no_email_address' => 'No se pudo encontrar una dirección de correo electrónico, para este usuario, en los datos proporcionados por el sistema de autenticación externo', + 'saml_invalid_response_id' => 'La solicitud del sistema de autenticación externo no está reconocida por un proceso iniciado por esta aplicación. Navegar hacia atrás después de un inicio de sesión podría causar este problema.', + 'saml_fail_authed' => 'El inicio de sesión con :system falló, el sistema no proporcionó una autorización correcta', 'social_no_action_defined' => 'Acción no definida', 'social_login_bad_response' => "SE recibió un Error durante el acceso con :socialAccount : \n:error", 'social_account_in_use' => 'la cuenta :socialAccount ya se encuentra en uso, intente loguearse a través de la opcón :socialAccount .', @@ -36,7 +40,7 @@ return [ 'cannot_get_image_from_url' => 'No se puede obtener la imagen desde :url', 'cannot_create_thumbs' => 'El servidor no puede crear la imagen miniatura. Por favor chequee que tiene la extensión GD instalada.', 'server_upload_limit' => 'El servidor no permite la subida de ficheros de este tamañ. Por favor intente con un fichero de menor tamañ.', - 'uploaded' => 'El servidor no permite subir archivos de este tamaño. Por favor intente un tamaño menor.', 'image_upload_error' => 'Ha ocurrido un error al subir la imagen', + 'uploaded' => 'El servidor no permite subir archivos de este tamaño. Por favor intente un tamaño menor.', 'image_upload_error' => 'Ha ocurrido un error al subir la imagen', 'image_upload_type_error' => 'El tipo de imagen subida es inválido.', 'file_upload_timeout' => 'La carga del archivo ha caducado.', @@ -83,4 +87,13 @@ return [ 'error_occurred' => 'Ha ocurrido un error', 'app_down' => 'La aplicación :appName se encuentra caída en este momento', 'back_soon' => 'Volverá a estar operativa en corto tiempo.', + + // API errors + 'api_no_authorization_found' => 'No se encontró ningún token de autorización en la solicitud', + 'api_bad_authorization_format' => 'Se ha encontrado un token de autorización en la solicitud pero el formato era incorrecto', + 'api_user_token_not_found' => 'No se ha encontrado un token API que corresponda con el token de autorización proporcionado', + 'api_incorrect_token_secret' => 'El secreto proporcionado para el token API usado es incorrecto', + 'api_user_no_api_permission' => 'El propietario del token API usado no tiene permiso para hacer llamadas API', + 'api_user_token_expired' => 'El token de autorización usado ha caducado', + ]; diff --git a/resources/lang/es_AR/pagination.php b/resources/lang/es_AR/pagination.php index 325916dc3..df81d0aa8 100644 --- a/resources/lang/es_AR/pagination.php +++ b/resources/lang/es_AR/pagination.php @@ -1,18 +1,11 @@ '« Anterior', 'next' => 'Siguiente »', diff --git a/resources/lang/es_AR/passwords.php b/resources/lang/es_AR/passwords.php index 62ca0e16e..e38e55ed8 100644 --- a/resources/lang/es_AR/passwords.php +++ b/resources/lang/es_AR/passwords.php @@ -1,18 +1,11 @@ 'La contraseña debe ser como mínimo de seis caracteres y coincidir con la confirmación.', 'user' => "No podemos encontrar un usuario con esta dirección de correo electrónico.", 'token' => 'Este token de restablecimiento de contraseña no es válido.', diff --git a/resources/lang/es_AR/settings.php b/resources/lang/es_AR/settings.php index 11369d94d..465e2ed07 100644 --- a/resources/lang/es_AR/settings.php +++ b/resources/lang/es_AR/settings.php @@ -3,19 +3,15 @@ * Settings text strings * Contains all text strings used in the general settings sections of BookStack * including users and roles. - * - * Cadenas de texto de la configuración - * Contiene todas las cadenas de texto usadas en la sección de configuración general - * de BookStack, incluyendo usuarios y roles. */ return [ - // Common Messages - Mensajes Comunes + // Common Messages 'settings' => 'Ajustes', 'settings_save' => 'Guardar ajustes', 'settings_save_success' => 'Ajustes guardados', - // App Settings - Configuraciones de la aplicación + // App Settings 'app_customization' => 'Personalización', 'app_features_security' => 'Características y Seguridad', 'app_name' => 'Nombre de aplicación', @@ -45,12 +41,22 @@ return [ '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.', - // Registration settings - Configuraciones de registro + // Color settings + 'content_colors' => 'Colores del contenido', + 'content_colors_desc' => 'Establece los colores para todos los elementos en la jerarquía de la organización de la página. Se recomienda elegir colores con un brillo similar al predeterminado para mayor legibilidad.', + 'bookshelf_color' => 'Color del estante', + 'book_color' => 'Color del libro', + 'chapter_color' => 'Color del capítulo', + 'page_color' => 'Color de la página', + 'page_draft_color' => 'Color del borrador de página', + + // Registration Settings 'reg_settings' => 'Ajustes de registro', 'reg_enable' => 'Habilitar Registro', 'reg_enable_toggle' => 'Habilitar registro', 'reg_enable_desc' => 'Cuando se habilita el registro, el usuario podrá crear su usuario en la aplicación. Con el regsitro, se le otorga un rol de usuario único y por defecto.', 'reg_default_role' => 'Rol de usuario por defecto despúes del registro', + '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' => 'Confirmación de correo electrónico', 'reg_email_confirmation_toggle' => 'Requerir confirmación de correo electrónico', 'reg_confirm_email_desc' => 'Si se utiliza la restricción por dominio, entonces se requerirá la confirmación por correo electrónico y se ignorará el valor a continuación.', @@ -58,7 +64,7 @@ return [ 'reg_confirm_restrict_domain_desc' => 'Introduzca una lista separada por comas de los correos electrónicos del dominio a los que les gustaría restringir el registro por dominio. A los usuarios les será enviado un correo elctrónico para confirmar la dirección antes de que se le permita interactuar con la aplicación.
Note que a los usuarios se les permitirá cambiar sus direcciones de correo electrónico luego de un registro éxioso.', 'reg_confirm_restrict_domain_placeholder' => 'Ninguna restricción establecida', - // Maintenance settings - Configuraciones de mantenimiento + // Maintenance settings 'maint' => 'Mantenimiento', 'maint_image_cleanup' => 'Limpiar imágenes', 'maint_image_cleanup_desc' => "Analizar contenido de páginas y revisiones para detectar cuáles imágenes y dibujos están en uso y cuáles son redundantes. Asegúrese de crear un respaldo completo de imágenes y base de datos antes de ejecutar esta tarea.", @@ -67,8 +73,15 @@ return [ 'maint_image_cleanup_warning' => 'Se encontraron :count imágenes pontencialmente sin uso. Está seguro de que quiere eliminarlas?', 'maint_image_cleanup_success' => 'Se encontraron y se eliminaron :count imágenes pontencialmente sin uso!', 'maint_image_cleanup_nothing_found' => 'No se encotraron imágenes sin usar, Nada eliminado!', + 'maint_send_test_email' => 'Enviar un correo electrónico de prueba', + 'maint_send_test_email_desc' => 'Esto envía un correo electrónico de prueba a la dirección de correo electrónico especificada en tu perfil.', + 'maint_send_test_email_run' => 'Enviar correo electrónico de prueba', + 'maint_send_test_email_success' => 'Correo electrónico enviado a :address', + 'maint_send_test_email_mail_subject' => 'Probar correo electrónico', + 'maint_send_test_email_mail_greeting' => '¡El envío de correos electrónicos parece funcionar!', + 'maint_send_test_email_mail_text' => '¡Enhorabuena! Al recibir esta notificación de correo electrónico, tu configuración de correo electrónico parece estar ajustada correctamente.', - // Role settings - Configuraciones de roles + // Role Settings 'roles' => 'Roles', 'role_user_roles' => 'Roles de usuario', 'role_create' => 'Crear nuevo rol', @@ -91,6 +104,7 @@ return [ 'role_manage_own_entity_permissions' => 'Gestionar permisos en libro s propios, capítulos y páginas', 'role_manage_page_templates' => 'Gestionar las plantillas de páginas', + 'role_access_api' => 'API de sistema de acceso', 'role_manage_settings' => 'Gestionar ajustes de activos', 'role_asset' => 'Permisos de activos', 'role_asset_desc' => 'Estos permisos controlan el acceso por defecto a los activos del sistema. Permisos a Libros, Capítulos y Páginas sobreescribiran estos permisos.', @@ -103,7 +117,7 @@ return [ 'role_users' => 'Usuarios en este rol', 'role_users_none' => 'No hay usuarios asignados a este rol', - // Users - Usuarios + // Users 'users' => 'Usuarios', 'user_profile' => 'Perfil de usuario', 'users_add_new' => 'Agregar nuevo usuario', @@ -112,13 +126,13 @@ return [ 'users_details_desc' => 'Asigne un nombre de visualización y una dirección de correo electrónico para este usuario. La dirección de correo electrónico se usará pra ingresar a la aplicación.', 'users_details_desc_no_email' => 'Asigne un nombre de visualización a este usuario para que los demás puedan reconocerlo.', 'users_role' => 'Roles de usuario', - '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_role_desc' => 'Selecciona los roles a los que será asignado este usuario. Si se asignan varios roles los permisos se acumularán y recibirá todas las habilidades de los roles asignados.', + 'users_password' => 'Contraseña de Usuario', 'users_password_desc' => 'Set a password used to log-in to the application. This must be at least 5 characters long.', 'users_send_invite_text' => 'Puede optar por enviar a este usuario un correo electrónico de invitación que les permita establecer su propia contraseña; de lo contrario, puede establecerla contraseña usted mismo.', 'users_send_invite_option' => 'Enviar correo electrónico de invitación al usuario.', 'users_external_auth_id' => 'ID externo de autenticación', - 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your LDAP system.', + 'users_external_auth_id_desc' => 'Esta es la ID usada para asociar este usuario con el sistema de autenticación externo.', 'users_password_warning' => 'Solo rellene a continuación si desea cambiar su password:', 'users_system_public' => 'Este usuario representa cualquier usuario invitado que visita la aplicación. No puede utilizarse para hacer login sino que es asignado automáticamente.', 'users_delete' => 'Borrar usuario', @@ -132,12 +146,67 @@ return [ 'users_avatar' => 'Avatar del usuario', 'users_avatar_desc' => 'Esta imagen debe ser de aproximadamente 256px por lado.', 'users_preferred_language' => 'Lenguaje preferido', - '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_preferred_language_desc' => 'Esta opción cambiará el idioma de la interfaz de usuario en la aplicación. No afectará al contenido creado por los usuarios.', 'users_social_accounts' => 'Cuentas sociales', 'users_social_accounts_info' => 'Aquí puede conectar sus otras cuentas para un acceso rápido y más fácil. Desconectando una cuenta aquí no revoca accesos ya autorizados. Revoque el acceso desde los ajustes de perfil en la cuenta social conectada.', 'users_social_connect' => 'Conectar cuenta', 'users_social_disconnect' => 'Desconectar cuenta', 'users_social_connected' => 'La cuenta :socialAccount ha sido exitosamente añadida a su perfil.', 'users_social_disconnected' => 'La cuenta :socialAccount ha sido desconectada exitosamente de su perfil.', + 'users_api_tokens' => 'Tokens API', + 'users_api_tokens_none' => 'No se han creado tokens API para este usuario', + 'users_api_tokens_create' => 'Crear token', + 'users_api_tokens_expires' => 'Expira', + 'users_api_tokens_docs' => 'Documentación API', + // API Tokens + 'user_api_token_create' => 'Crear token API', + 'user_api_token_name' => 'Nombre', + 'user_api_token_name_desc' => 'Dale a tu token un nombre legible como un recordatorio futuro de su propósito.', + 'user_api_token_expiry' => 'Fecha de expiración', + 'user_api_token_expiry_desc' => 'Establece una fecha en la que este token expira. Después de esta fecha, las solicitudes realizadas usando este token ya no funcionarán. Dejar este campo en blanco fijará un vencimiento de 100 años en el futuro.', + 'user_api_token_create_secret_message' => 'Inmediatamente después de crear este token se generarán y mostrarán sus correspondientes "Token ID" y "Token Secret". El "Token Secret" sólo se mostrará una vez, así que asegúrese de copiar el valor a un lugar seguro antes de proceder.', + 'user_api_token_create_success' => 'Token API creado correctamente', + 'user_api_token_update_success' => 'Token API actualizado correctamente', + 'user_api_token' => 'Token API', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'Este es un identificador no editable generado por el sistema y único para este token que necesitará ser proporcionado en solicitudes de API.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'Esta es una clave no editable generada por el sistema que necesitará ser proporcionada en solicitudes de API. Solo se monstraré esta vez así que guarde su valor en un lugar seguro.', + 'user_api_token_created' => 'Token creado :timeAgo', + 'user_api_token_updated' => 'Token actualizado :timeAgo', + 'user_api_token_delete' => 'Borrar token', + 'user_api_token_delete_warning' => 'Esto eliminará completamente este token API con el nombre \':tokenName\' del sistema.', + 'user_api_token_delete_confirm' => '¿Está seguro de que desea borrar este API token?', + 'user_api_token_delete_success' => 'Token API borrado correctamente', + + //! 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' => 'العربية', + 'da' => 'Danés', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// ]; diff --git a/resources/lang/es_AR/validation.php b/resources/lang/es_AR/validation.php index 556903cb9..cd360c8ea 100644 --- a/resources/lang/es_AR/validation.php +++ b/resources/lang/es_AR/validation.php @@ -4,16 +4,10 @@ * The following language lines contain the default error messages used by * the validator class. Some of these rules have multiple versions such * as the size rules. Feel free to tweak each of these messages here. - * - * Líneas de validación - * Las líneas de lenguaje siguientes contienen los mensajes de error por - * defecto usados por el validador de la clase. Algunas de esta reglas tienen - * varias versiones, como las reglas de tamaño. Siéntase libre de ajustar cada - * uno de los mensajes. */ return [ - // Standard laravel validation lines - Líneas de validación estándar de laravel + // Standard laravel validation lines 'accepted' => 'El :attribute debe ser aceptado.', 'active_url' => 'El :attribute no es una URl válida.', 'after' => 'El :attribute debe ser una fecha posterior :date.', @@ -36,13 +30,41 @@ return [ 'digits' => ':attribute debe ser de :digits dígitos.', 'digits_between' => ':attribute debe ser un valor entre :min y :max dígios.', 'email' => ':attribute debe ser una dirección álida.', + 'ends_with' => 'El :attribute debe terminar con uno de los siguientes: :values', 'filled' => 'El campo :attribute es requerido.', + 'gt' => [ + 'numeric' => 'El :attribute debe ser mayor que :value.', + 'file' => 'El :attribute debe ser mayor que :value kilobytes.', + 'string' => 'El :attribute debe ser mayor que :value caracteres.', + 'array' => 'El :attribute debe tener más de :value objetos.', + ], + 'gte' => [ + 'numeric' => 'El :attribute debe ser mayor o igual a :value.', + 'file' => 'El :attribute debe ser mayor o igual a :value kilobytes.', + 'string' => 'El :attribute debe ser mayor o igual a :value caracteres.', + 'array' => 'El :attribute debe tener :value objetos o más.', + ], 'exists' => 'El :attribute seleccionado es inválido.', 'image' => 'El :attribute debe ser una imagen.', - 'in' => 'El selected :attribute es inválio.', 'image_extension' => 'El :attribute debe tener una extensión de imagen válida y soportada.', + 'in' => 'El selected :attribute es inválio.', 'integer' => 'El :attribute debe ser un entero.', 'ip' => 'El :attribute debe ser una dirección IP álida.', + 'ipv4' => 'El :attribute debe ser una dirección IPv4 válida.', + 'ipv6' => 'El :attribute debe ser una dirección IPv6 válida.', + 'json' => 'El :attribute debe ser una cadena JSON válida.', + 'lt' => [ + 'numeric' => 'El :attribute debe ser menor que :value.', + 'file' => 'El :attribute debe ser menor que :value kilobytes.', + 'string' => 'El :attribute debe ser menor que :value caracteres.', + 'array' => 'El :attribute debe tener menos de :value objetos.', + ], + 'lte' => [ + 'numeric' => 'El :attribute debe ser menor o igual a :value.', + 'file' => 'El :attribute debe ser menor o igual a :value kilobytes.', + 'string' => 'El :attribute debe ser menor o igual a :value caracteres.', + 'array' => 'El :attribute no debe tener más de :value objetos.', + ], 'max' => [ 'numeric' => ':attribute no puede ser mayor que :max.', 'file' => ':attribute no puede ser mayor que :max kilobytes.', @@ -57,7 +79,8 @@ return [ '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álio.', + 'not_in' => ':attribute seleccionado es inválido.', + 'not_regex' => 'El formato de :attribute es inválido.', 'numeric' => ':attribute debe ser numérico.', 'regex' => ':attribute con formato inválido', 'required' => ':attribute es requerido.', @@ -79,14 +102,13 @@ return [ 'url' => 'El atributo :attribute tiene un formato inválido.', 'uploaded' => 'El archivo no se pudo subir. Puede ser que el servidor no acepte archivos de este tamaño.', - // Custom validation lines - Líneas de validación personalizadas + // Custom validation lines 'custom' => [ 'password-confirm' => [ 'required_with' => 'Confirmación de Password requerida', ], ], - // Custom validation attributes - Atributos de validación personalizados + // Custom validation attributes 'attributes' => [], - ]; diff --git a/resources/lang/format.php b/resources/lang/format.php deleted file mode 100755 index 45d0b4842..000000000 --- a/resources/lang/format.php +++ /dev/null @@ -1,330 +0,0 @@ -#!/usr/bin/env php - $line) { - $trimLine = trim($line); - if ($mode === 'header') { - $formatted[$index] = $line; - if (str_replace(' ', '', $trimLine) === 'return[') $mode = 'body'; - } - - if ($mode === 'body') { - $matches = []; - $arrayEndMatch = preg_match('/]\s*,\s*$/', $trimLine); - - if ($skipArray) { - if ($arrayEndMatch) $skipArray = false; - continue; - } - - // Comment to ignore - if (strpos($trimLine, '//!') === 0) { - $formatted[$index] = ""; - continue; - } - - // Comment - if (strpos($trimLine, '//') === 0) { - $formatted[$index] = "\t" . $trimLine; - continue; - } - - // Arrays - $arrayStartMatch = preg_match('/^\'(.*)\'\s+?=>\s+?\[(\],)?\s*?$/', $trimLine, $matches); - - $indent = count($arrayKeys) + 1; - if ($arrayStartMatch === 1) { - if ($fileName === 'settings' && $matches[1] === 'language_select') { - $skipArray = true; - continue; - } - $arrayKeys[] = $matches[1]; - $formatted[$index] = str_repeat(" ", $indent * 4) . str_pad("'{$matches[1]}'", $longestKeyLength) . "=> ["; - if ($arrayEndMatch !== 1) continue; - } - if ($arrayEndMatch === 1) { - unsetArrayByKeys($langContent, $arrayKeys); - array_pop($arrayKeys); - if (isset($formatted[$index])) { - $formatted[$index] .= '],'; - } else { - $formatted[$index] = str_repeat(" ", ($indent-1) * 4) . "],"; - } - continue; - } - - // Translation - $translationMatch = preg_match('/^\'(.*)\'\s+?=>\s+?[\'"](.*)?[\'"].+?$/', $trimLine, $matches); - if ($translationMatch === 1) { - $key = $matches[1]; - $keys = array_merge($arrayKeys, [$key]); - $langVal = getTranslationByKeys($langContent, $keys); - if (empty($langVal)) continue; - - $keyPad = $longestKeyLength; - if (count($arrayKeys) === 0) { - unset($langContent[$key]); - } else { - $keyPad = calculateKeyPadding(getTranslationByKeys($enContent, $arrayKeys)); - } - - $formatted[$index] = formatTranslationLine($key, $langVal, $indent, $keyPad); - continue; - } - } - - } - - // Fill missing lines - $arraySize = max(array_keys($formatted)); - $formatted = array_replace(array_fill(0, $arraySize, ''), $formatted); - - // Add remaining translations - $langContent = array_filter($langContent, function($item) { - return !is_null($item) && !empty($item); - }); - if (count($langContent) > 0) { - $formatted[] = ''; - $formatted[] = "\t// Unmatched"; - } - foreach ($langContent as $key => $value) { - if (is_array($value)) { - $formatted[] = formatTranslationArray($key, $value); - } else { - $formatted[] = formatTranslationLine($key, $value); - } - } - - // Add end line - $formatted[] = '];'; - return implode("\n", $formatted); -} - -/** - * Format a translation line. - * @param string $key - * @param string $value - * @param int $indent - * @param int $keyPad - * @return string - */ -function formatTranslationLine(string $key, string $value, int $indent = 1, int $keyPad = 1) : string { - $start = str_repeat(" ", $indent * 4) . str_pad("'{$key}'", $keyPad, ' '); - if (strpos($value, "\n") !== false) { - $escapedValue = '"' . str_replace("\n", '\n', $value) . '"'; - $escapedValue = '"' . str_replace('"', '\"', $escapedValue) . '"'; - } else { - $escapedValue = "'" . str_replace("'", "\\'", $value) . "'"; - } - return "{$start} => {$escapedValue},"; -} - -/** - * Find the longest key in the array and provide the length - * for all keys to be used when printed. - * @param array $array - * @return int - */ -function calculateKeyPadding(array $array) : int { - $top = 0; - foreach ($array as $key => $value) { - $keyLen = strlen($key); - $top = max($top, $keyLen); - } - return min(35, $top + 2); -} - -/** - * Format an translation array with the given key. - * Simply prints as an old-school php array. - * Used as a last-resort backup to save unused translations. - * @param string $key - * @param array $array - * @return string - */ -function formatTranslationArray(string $key, array $array) : string { - $arrayPHP = var_export($array, true); - return " '{$key}' => {$arrayPHP},"; -} - -/** - * Find a string translation value within a multi-dimensional array - * by traversing the given array of keys. - * @param array $translations - * @param array $keys - * @return string|array - */ -function getTranslationByKeys(array $translations, array $keys) { - $val = $translations; - foreach ($keys as $key) { - $val = $val[$key] ?? ''; - if ($val === '') return ''; - } - return $val; -} - -/** - * Unset an inner item of a multi-dimensional array by - * traversing the given array of keys. - * @param array $input - * @param array $keys - */ -function unsetArrayByKeys(array &$input, array $keys) { - $val = &$input; - $lastIndex = count($keys) - 1; - foreach ($keys as $index => &$key) { - if ($index === $lastIndex && is_array($val)) { - unset($val[$key]); - } - if (!is_array($val)) return; - $val = &$val[$key] ?? []; - } -} - -/** - * Write the given content to a translation file. - * @param string $lang - * @param string $fileName - * @param string $content - */ -function writeLangFile(string $lang, string $fileName, string $content) { - $path = __DIR__ . "/{$lang}/{$fileName}.php"; - if (!file_exists($path)) { - errorOut("Expected translation file '{$path}' does not exist"); - } - file_put_contents($path, $content); -} - -/** - * Load the contents of a language file as an array of text lines. - * @param string $lang - * @param string $fileName - * @return array - */ -function loadLangFileLines(string $lang, string $fileName) : array { - $path = __DIR__ . "/{$lang}/{$fileName}.php"; - if (!file_exists($path)) { - errorOut("Expected translation file '{$path}' does not exist"); - } - $lines = explode("\n", file_get_contents($path)); - return array_map(function($line) { - return trim($line, "\r"); - }, $lines); -} - -/** - * Load the contents of a language file - * @param string $lang - * @param string $fileName - * @return array - */ -function loadLang(string $lang, string $fileName) : array { - $path = __DIR__ . "/{$lang}/{$fileName}.php"; - if (!file_exists($path)) { - errorOut("Expected translation file '{$path}' does not exist"); - } - - $fileData = include($path); - return $fileData; -} - -/** - * Fetch an array containing the names of all translation files without the extension. - * @return array - */ -function getTranslationFileNames() : array { - $dir = __DIR__ . "/en"; - if (!file_exists($dir)) { - errorOut("Expected directory '{$dir}' does not exist"); - } - $files = scandir($dir); - $fileNames = []; - foreach ($files as $file) { - if (substr($file, -4) === '.php') { - $fileNames[] = substr($file, 0, strlen($file) - 4); - } - } - return $fileNames; -} - -/** - * Format a locale to follow the lowercase_UPERCASE standard - * @param string $lang - * @return string - */ -function formatLocale(string $lang) : string { - $langParts = explode('_', strtoupper($lang)); - $langParts[0] = strtolower($langParts[0]); - return implode('_', $langParts); -} - -/** - * Dump a variable then die. - * @param $content - */ -function dd($content) { - print_r($content); - exit(1); -} - -/** - * Log out some information text in blue - * @param $text - */ -function info($text) { - echo "\e[34m" . $text . "\e[0m\n"; -} - -/** - * Log out an error in red and exit. - * @param $text - */ -function errorOut($text) { - echo "\e[31m" . $text . "\e[0m\n"; - exit(1); -} \ No newline at end of file diff --git a/resources/lang/fr/activities.php b/resources/lang/fr/activities.php index ab54bff7c..56db4abff 100644 --- a/resources/lang/fr/activities.php +++ b/resources/lang/fr/activities.php @@ -1,12 +1,10 @@ 'a créé la page', 'page_create_notification' => 'Page créée avec succès', @@ -38,7 +36,7 @@ return [ 'book_sort_notification' => 'Livre réordonné avec succès', // Bookshelves - 'bookshelf_create' => 'a créé l\'étagère', + 'bookshelf_create' => 'a créé l\'étagère', 'bookshelf_create_notification' => 'Étagère créée avec succès', 'bookshelf_update' => 'a modifié l\'étagère', 'bookshelf_update_notification' => 'Étagère modifiée avec succès', @@ -46,5 +44,5 @@ return [ 'bookshelf_delete_notification' => 'Étagère supprimée avec succès', // Other - 'commented_on' => 'a commenté' + 'commented_on' => 'a commenté', ]; diff --git a/resources/lang/fr/auth.php b/resources/lang/fr/auth.php index c9ce6a4d7..99b41c070 100644 --- a/resources/lang/fr/auth.php +++ b/resources/lang/fr/auth.php @@ -1,73 +1,62 @@ 'Ces informations ne correspondent à aucun compte.', - 'throttle' => "Trop d'essais, veuillez réessayer dans :seconds secondes.", - /** - * Login & Register - */ - 'sign_up' => "S'inscrire", + 'failed' => 'Ces informations ne correspondent à aucun compte.', + 'throttle' => 'Trop d\'essais, veuillez réessayer dans :seconds secondes.', + + // Login & Register + 'sign_up' => 'S\'inscrire', 'log_in' => 'Se connecter', 'log_in_with' => 'Se connecter avec :socialDriver', 'sign_up_with' => 'S\'inscrire avec :socialDriver', 'logout' => 'Se déconnecter', 'name' => 'Nom', - 'username' => "Nom d'utilisateur", + 'username' => 'Nom d\'utilisateur', 'email' => 'E-mail', 'password' => 'Mot de passe', 'password_confirm' => 'Confirmez le mot de passe', - 'password_hint' => 'Doit faire plus de 5 caractères', - 'forgot_password' => 'Mot de passe oublié ?', + 'password_hint' => 'Doit faire plus de 7 caractères', + 'forgot_password' => 'Mot de passe oublié ?', 'remember_me' => 'Se souvenir de moi', - 'ldap_email_hint' => "Merci d'entrer une adresse e-mail pour ce compte", + 'ldap_email_hint' => 'Merci d\'entrer une adresse e-mail pour ce compte.', 'create_account' => 'Créer un compte', - 'already_have_account' => 'Vous avez déjà un compte?', - 'dont_have_account' => 'Vous n\'avez pas de compte?', - 'social_login' => 'Social Login', - 'social_registration' => 'Enregistrement Social', - 'social_registration_text' => "S'inscrire et se connecter avec un réseau social", + 'already_have_account' => 'Vous avez déjà un compte ?', + 'dont_have_account' => 'Vous n\'avez pas de compte ?', + 'social_login' => 'Connexion avec un réseau social', + 'social_registration' => 'Inscription avec un réseau social', + 'social_registration_text' => 'S\'inscrire et se connecter avec un réseau social.', - 'register_thanks' => 'Merci pour votre enregistrement', + 'register_thanks' => 'Merci pour votre inscription !', 'register_confirm' => 'Vérifiez vos e-mails et cliquez sur le lien de confirmation pour rejoindre :appName.', - 'registrations_disabled' => "L'inscription est désactivée pour le moment", + 'registrations_disabled' => 'Les inscriptions sont désactivées pour le moment', 'registration_email_domain_invalid' => 'Cette adresse e-mail ne peut pas accéder à l\'application', 'register_success' => 'Merci pour votre inscription. Vous êtes maintenant inscrit(e) et connecté(e)', - /** - * Password Reset - */ - 'reset_password' => 'Reset Password', - 'reset_password_send_instructions' => 'Entrez votre adresse e-mail ci-dessous et un e-mail avec un lien de réinitialisation de mot de passe vous sera envoyé', + // Password Reset + 'reset_password' => 'Réinitialiser le mot de passe', + 'reset_password_send_instructions' => 'Entrez votre adresse e-mail ci-dessous et un e-mail avec un lien de réinitialisation de mot de passe vous sera envoyé.', 'reset_password_send_button' => 'Envoyer un lien de réinitialisation', 'reset_password_sent_success' => 'Un lien de réinitialisation a été envoyé à :email.', 'reset_password_success' => 'Votre mot de passe a été réinitialisé avec succès.', - 'email_reset_subject' => 'Réinitialisez votre mot de passe pour :appName', - 'email_reset_text' => 'Vous recevez cet e-mail parce que nous avons reçu une demande de réinitialisation pour votre compte', + 'email_reset_text' => 'Vous recevez cet e-mail parce que nous avons reçu une demande de réinitialisation pour votre compte.', 'email_reset_not_requested' => 'Si vous n\'avez pas effectué cette demande, vous pouvez ignorer cet e-mail.', - /** - * Email Confirmation - */ + // Email Confirmation 'email_confirm_subject' => 'Confirmez votre adresse e-mail pour :appName', - 'email_confirm_greeting' => 'Merci d\'avoir rejoint :appName !', - 'email_confirm_text' => 'Merci de confirmer en cliquant sur le lien ci-dessous :', + 'email_confirm_greeting' => 'Merci d\'avoir rejoint :appName !', + 'email_confirm_text' => 'Merci de confirmer en cliquant sur le lien ci-dessous :', 'email_confirm_action' => 'Confirmez votre adresse e-mail', 'email_confirm_send_error' => 'La confirmation par e-mail est requise mais le système n\'a pas pu envoyer l\'e-mail. Contactez l\'administrateur système.', - 'email_confirm_success' => 'Votre adresse e-mail a été confirmée !', + 'email_confirm_success' => 'Votre adresse e-mail a été confirmée !', 'email_confirm_resent' => 'L\'e-mail de confirmation a été ré-envoyé. Vérifiez votre boîte de récéption.', 'email_not_confirmed' => 'Adresse e-mail non confirmée', @@ -75,4 +64,14 @@ return [ 'email_not_confirmed_click_link' => 'Merci de cliquer sur le lien dans l\'e-mail qui vous a été envoyé après l\'enregistrement.', 'email_not_confirmed_resend' => 'Si vous ne retrouvez plus l\'e-mail, vous pouvez renvoyer un e-mail de confirmation en utilisant le formulaire ci-dessous.', 'email_not_confirmed_resend_button' => 'Renvoyez l\'e-mail de confirmation', -]; + + // User Invite + 'user_invite_email_subject' => 'Vous avez été invité(e) à rejoindre :appName !', + 'user_invite_email_greeting' => 'Un compte vous a été créé sur :appName.', + 'user_invite_email_text' => 'Cliquez sur le bouton ci-dessous pour renseigner le mot de passe et récupérer l\'accès :', + 'user_invite_email_action' => 'Renseignez le mot de passe de votre compte', + 'user_invite_page_welcome' => 'Bienvenue dans :appName !', + 'user_invite_page_text' => 'Pour finaliser votre compte et recevoir l\'accès, vous devez renseigner le mot de passe qui sera utilisé pour la connexion à :appName les prochaines fois.', + 'user_invite_page_confirm_button' => 'Confirmez le mot de passe', + 'user_invite_success' => 'Mot de passe renseigné, vous avez maintenant accès à :appName !' +]; \ No newline at end of file diff --git a/resources/lang/fr/common.php b/resources/lang/fr/common.php index 1cf6e716f..af31f458a 100644 --- a/resources/lang/fr/common.php +++ b/resources/lang/fr/common.php @@ -1,9 +1,10 @@ 'Annuler', 'confirm' => 'Confirmer', 'back' => 'Retour', @@ -13,18 +14,14 @@ return [ 'toggle_all' => 'Tout sélectionner', 'more' => 'Montrer plus', - /** - * Form Labels - */ + // Form Labels 'name' => 'Nom', 'description' => 'Description', 'role' => 'Rôle', 'cover_image' => 'Image de couverture', - 'cover_image_description' => 'Cette image doit être environ 440x250px.', + 'cover_image_description' => 'Cette image doit faire environ 440x250 px.', - /** - * Actions - */ + // Actions 'actions' => 'Actions', 'view' => 'Voir', 'view_all' => 'Tout afficher', @@ -41,17 +38,18 @@ return [ 'reset' => 'Réinitialiser', 'remove' => 'Enlever', 'add' => 'Ajouter', + 'fullscreen' => 'Fullscreen', - /** - * Sort Options - */ + // Sort Options + 'sort_options' => 'Options de tri', + 'sort_direction_toggle' => 'Inverser la direction du tri', + 'sort_ascending' => 'Tri ascendant', + 'sort_descending' => 'Tri descendant', 'sort_name' => 'Nom', 'sort_created_at' => 'Date de création', 'sort_updated_at' => 'Date de mise à jour', - /** - * Misc - */ + // Misc 'deleted_user' => 'Utilisateur supprimé', 'no_activity' => 'Aucune activité', 'no_items' => 'Aucun élément', @@ -62,16 +60,18 @@ return [ 'grid_view' => 'Vue en grille', 'list_view' => 'Vue en liste', 'default' => 'Défaut', + 'breadcrumb' => 'Fil d\'Ariane', - /** - * Header - */ + // Header + 'profile_menu' => 'Menu du profil', 'view_profile' => 'Voir le profil', 'edit_profile' => 'Modifier le profil', - /** - * 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 :', + // Layout tabs + 'tab_info' => 'Informations', + 'tab_content' => 'Contenu', + + // 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', ]; diff --git a/resources/lang/fr/components.php b/resources/lang/fr/components.php index e314536c7..2f6ff8bf9 100644 --- a/resources/lang/fr/components.php +++ b/resources/lang/fr/components.php @@ -1,9 +1,10 @@ 'Sélectionner une image', 'image_all' => 'Toutes', 'image_all_title' => 'Voir toutes les images', @@ -24,9 +25,7 @@ return [ 'image_delete_success' => 'Image supprimée avec succès', 'image_upload_remove' => 'Supprimer', - /** - * Code editor - */ + // Code Editor 'code_editor' => 'Editer le code', 'code_language' => 'Langage du code', 'code_content' => 'Contenu du code', diff --git a/resources/lang/fr/entities.php b/resources/lang/fr/entities.php index 4ba1a36e3..d52dbfda3 100644 --- a/resources/lang/fr/entities.php +++ b/resources/lang/fr/entities.php @@ -1,9 +1,11 @@ 'Créé récemment', 'recently_created_pages' => 'Pages créées récemment', 'recently_updated_pages' => 'Pages mises à jour récemment', @@ -32,17 +34,13 @@ return [ 'export_pdf' => 'Fichier PDF', 'export_text' => 'Document texte', - /** - * Permissions and restrictions - */ - 'permissions' => 'Permissions', + // Permissions and restrictions + 'permissions' => 'Autorisations', 'permissions_intro' => 'Une fois activées ces permissions prendront la priorité sur tous les sets de permissions préexistants.', 'permissions_enable' => 'Activer les permissions personnalisées', 'permissions_save' => 'Enregistrer les permissions', - /** - * Search - */ + // Search 'search_results' => 'Résultats de recherche', 'search_total_results_found' => ':count résultats trouvés|:count résultats trouvés au total', 'search_clear' => 'Réinitialiser la recherche', @@ -67,9 +65,7 @@ return [ 'search_set_date' => 'Choisir la date', 'search_update' => 'Actualiser la recherche', - /** - * Shelves - */ + // Shelves 'shelf' => 'Étagère', 'shelves' => 'Étagères', 'x_shelves' => ':count Étagère|:count Étagères', @@ -91,8 +87,8 @@ return [ 'shelves_edit' => 'Modifier l\'étagère', 'shelves_delete' => 'Supprimer l\'étagère', 'shelves_delete_named' => 'Supprimer l\'étagère :name', - 'shelves_delete_explain' => "Ceci va supprimer l\'étagère nommée \':bookName\'. Les livres contenus dans cette étagère ne seront pas supprimés.", - 'shelves_delete_confirmation' => 'Êtes-vous sûr(e) de vouloir supprimer cette étagère ?', + 'shelves_delete_explain' => "Ceci va supprimer l\\'étagère nommée \\':bookName\\'. Les livres contenus dans cette étagère ne seront pas supprimés.", + 'shelves_delete_confirmation' => 'Êtes-vous sûr(e) de vouloir supprimer cette étagère ?', 'shelves_permissions' => 'Permissions de l\'étagère', 'shelves_permissions_updated' => 'Permissions de l\'étagère mises à jour', 'shelves_permissions_active' => 'Permissions de l\'étagère activées', @@ -101,9 +97,7 @@ return [ 'shelves_copy_permissions_explain' => 'Ceci va appliquer les permissions actuelles de cette étagère à tous les livres qu\'elle contient. Avant de continuer, assurez-vous que toutes les permissions de cette étagère ont été sauvegardées.', 'shelves_copy_permission_success' => 'Permissions de l\'étagère transférées à :count livres', - /** - * Books - */ + // Books 'book' => 'Livre', 'books' => 'Livres', 'x_books' => ':count livre|:count livres', @@ -118,7 +112,7 @@ return [ 'books_delete' => 'Supprimer un livre', 'books_delete_named' => 'Supprimer le livre :bookName', 'books_delete_explain' => 'Ceci va supprimer le livre nommé \':bookName\', tous les chapitres et pages seront supprimés.', - 'books_delete_confirmation' => 'Êtes-vous sûr(e) de vouloir supprimer ce livre ?', + 'books_delete_confirmation' => 'Êtes-vous sûr(e) de vouloir supprimer ce livre ?', 'books_edit' => 'Modifier le livre', 'books_edit_named' => 'Modifier le livre :bookName', 'books_form_book_name' => 'Nom du livre', @@ -127,7 +121,6 @@ return [ 'books_permissions_updated' => 'Permissions du livre mises à jour', 'books_empty_contents' => 'Aucune page ou chapitre n\'a été ajouté à ce livre.', 'books_empty_create_page' => 'Créer une nouvelle page', - 'books_empty_or' => 'ou', 'books_empty_sort_current_book' => 'Trier les pages du livre', 'books_empty_add_chapter' => 'Ajouter un chapitre', 'books_permissions_active' => 'Permissions personnalisées activées', @@ -143,9 +136,7 @@ return [ 'books_sort_show_other' => 'Afficher d\'autres livres', 'books_sort_save' => 'Enregistrer l\'ordre', - /** - * Chapters - */ + // Chapters 'chapter' => 'Chapitre', 'chapters' => 'Chapitres', 'x_chapters' => ':count chapitre|:count chapitres', @@ -155,7 +146,7 @@ return [ 'chapters_delete' => 'Supprimer le chapitre', 'chapters_delete_named' => 'Supprimer le chapitre :chapterName', 'chapters_delete_explain' => 'Ceci va supprimer le chapitre \':chapterName\', toutes les pages seront déplacées dans le livre parent.', - 'chapters_delete_confirm' => 'Etes-vous sûr(e) de vouloir supprimer ce chapitre ?', + 'chapters_delete_confirm' => 'Etes-vous sûr(e) de vouloir supprimer ce chapitre ?', 'chapters_edit' => 'Modifier le chapitre', 'chapters_edit_named' => 'Modifier le chapitre :chapterName', 'chapters_save' => 'Enregistrer le chapitre', @@ -168,12 +159,10 @@ return [ 'chapters_permissions_success' => 'Permissions du chapitre mises à jour', 'chapters_search_this' => 'Rechercher dans ce chapitre', - /** - * Pages - */ + // Pages 'page' => 'Page', 'pages' => 'Pages', - 'x_pages' => ':count Page|:count Pages', + 'x_pages' => ':count Page|:count pages', 'pages_popular' => 'Pages populaires', 'pages_new' => 'Nouvelle page', 'pages_attachments' => 'Fichiers joints', @@ -184,10 +173,10 @@ return [ 'pages_delete_draft' => 'Supprimer le brouillon', 'pages_delete_success' => 'Page supprimée', 'pages_delete_draft_success' => 'Brouillon supprimé', - 'pages_delete_confirm' => 'Êtes-vous sûr(e) de vouloir supprimer cette page ?', - 'pages_delete_draft_confirm' => 'Êtes-vous sûr(e) de vouloir supprimer ce brouillon ?', + 'pages_delete_confirm' => 'Êtes-vous sûr(e) de vouloir supprimer cette page ?', + 'pages_delete_draft_confirm' => 'Êtes-vous sûr(e) de vouloir supprimer ce brouillon ?', 'pages_editing_named' => 'Modification de la page :pageName', - 'pages_edit_toggle_header' => 'Afficher/cacher l\'en-tête', + 'pages_edit_draft_options' => 'Options du brouillon', 'pages_edit_save_draft' => 'Enregistrer le brouillon', 'pages_edit_draft' => 'Modifier le brouillon', 'pages_editing_draft' => 'Modification du brouillon', @@ -221,6 +210,8 @@ return [ 'pages_revisions_created_by' => 'Créé par', 'pages_revisions_date' => 'Date de révision', 'pages_revisions_number' => '#', + 'pages_revisions_numbered' => 'Révision #:id', + 'pages_revisions_numbered_changes' => 'Modification #:id', 'pages_revisions_changelog' => 'Journal des changements', 'pages_revisions_changes' => 'Changements', 'pages_revisions_current' => 'Version courante', @@ -239,23 +230,24 @@ return [ 'start_b' => ':userName a commencé à éditer cette page', 'time_a' => 'depuis la dernière sauvegarde', 'time_b' => 'dans les :minCount dernières minutes', - 'message' => ':start :time. Attention à ne pas écraser les mises à jour de quelqu\'un d\'autre !', + 'message' => ':start :time. Attention à ne pas écraser les mises à jour de quelqu\'un d\'autre !', ], 'pages_draft_discarded' => 'Brouillon écarté, la page est dans sa version actuelle.', 'pages_specific' => 'Page Spécifique', + 'pages_is_template' => 'Modèle de page', - /** - * Editor sidebar - */ + // Editor Sidebar 'page_tags' => 'Mots-clés de la page', 'chapter_tags' => 'Mots-clés du chapitre', 'book_tags' => 'Mots-clés du livre', 'shelf_tags' => 'Mots-clés de l\'étagère', 'tag' => 'Mot-clé', 'tags' => 'Mots-clés', + 'tag_name' => 'Nom du tag', 'tag_value' => 'Valeur du mot-clé (Optionnel)', 'tags_explain' => "Ajouter des mots-clés pour catégoriser votre contenu.", 'tags_add' => 'Ajouter un autre mot-clé', + 'tags_remove' => 'Supprimer le tag', 'attachments' => 'Fichiers joints', 'attachments_explain' => 'Ajouter des fichiers ou des liens pour les afficher sur votre page. Ils seront affichés dans la barre latérale', 'attachments_explain_instant_save' => 'Ces changements sont enregistrés immédiatement.', @@ -281,10 +273,14 @@ return [ 'attachments_file_uploaded' => 'Fichier ajouté avec succès', 'attachments_file_updated' => 'Fichier mis à jour avec succès', 'attachments_link_attached' => 'Lien attaché à la page avec succès', + 'templates' => 'Modèles', + 'templates_set_as_template' => 'La page est un modèle', + 'templates_explain_set_as_template' => 'Vous pouvez définir cette page comme modèle pour que son contenu soit utilisé lors de la création d\'autres pages. Les autres utilisateurs pourront utiliser ce modèle s\'ils ont les permissions pour cette page.', + 'templates_replace_content' => 'Remplacer le contenu de la page', + 'templates_append_content' => 'Ajouter après le contenu de la page', + 'templates_prepend_content' => 'Ajouter devant le contenu de la page', - /** - * Profile View - */ + // Profile View 'profile_user_for_x' => 'Utilisateur depuis :time', 'profile_created_content' => 'Contenu créé', 'profile_not_created_pages' => ':userName n\'a pas créé de page', @@ -292,30 +288,27 @@ return [ 'profile_not_created_books' => ':userName n\'a pas créé de livre', 'profile_not_created_shelves' => ':userName n\'a pas créé d\'étagère', - /** - * Comments - */ + // Comments 'comment' => 'Commentaire', 'comments' => 'Commentaires', 'comment_add' => 'Ajouter un commentaire', 'comment_placeholder' => 'Entrez vos commentaires ici', - 'comment_count' => '{0} Pas de commentaires|{1} 1 Commentaire|[2,*] :count Commentaires', + 'comment_count' => '{0} Pas de commentaires|{1} Un commentaire|[2,*] :count commentaires', 'comment_save' => 'Enregistrer le commentaire', - 'comment_saving' => 'Enregistrement du commentaire...', - 'comment_deleting' => 'Suppression du commentaire...', + 'comment_saving' => 'Enregistrement du commentaire…', + 'comment_deleting' => 'Suppression du commentaire…', 'comment_new' => 'Nouveau commentaire', 'comment_created' => 'commenté :createDiff', 'comment_updated' => 'Mis à jour :updateDiff par :username', 'comment_deleted_success' => 'Commentaire supprimé', 'comment_created_success' => 'Commentaire ajouté', 'comment_updated_success' => 'Commentaire mis à jour', - 'comment_delete_confirm' => 'Etes-vous sûr de vouloir supprimer ce commentaire ?', + 'comment_delete_confirm' => 'Etes-vous sûr de vouloir supprimer ce commentaire ?', 'comment_in_reply_to' => 'En réponse à :commentId', - /** - * Revision - */ - 'revision_delete_confirm' => 'Êtes-vous sûr de vouloir supprimer cette révision?', + // Revision + 'revision_delete_confirm' => 'Êtes-vous sûr de vouloir supprimer cette révision ?', + 'revision_restore_confirm' => 'Êtes-vous sûr de vouloir restaurer cette révision ? Le contenu courant de la page va être remplacé.', 'revision_delete_success' => 'Révision supprimée', 'revision_cannot_delete_latest' => 'Impossible de supprimer la dernière révision.' -]; +]; \ No newline at end of file diff --git a/resources/lang/fr/errors.php b/resources/lang/fr/errors.php index e758f6e5e..709b208b0 100644 --- a/resources/lang/fr/errors.php +++ b/resources/lang/fr/errors.php @@ -1,11 +1,9 @@ 'Vous n\'avez pas les droits pour accéder à cette page.', 'permissionJson' => 'Vous n\'avez pas les droits pour exécuter cette action.', @@ -15,12 +13,18 @@ return [ 'email_already_confirmed' => 'Cet e-mail a déjà été validé, vous pouvez vous connecter.', 'email_confirmation_invalid' => 'Cette confirmation est invalide. Veuillez essayer de vous inscrire à nouveau.', 'email_confirmation_expired' => 'Le jeton de confirmation est périmé. Un nouvel e-mail vous a été envoyé.', + 'email_confirmation_awaiting' => 'L\'adresse e-mail du compte utilisé doit être confirmée', 'ldap_fail_anonymous' => 'L\'accès LDAP anonyme n\'a pas abouti', 'ldap_fail_authed' => 'L\'accès LDAP n\'a pas abouti avec cet utilisateur et ce mot de passe', 'ldap_extension_not_installed' => 'L\'extension LDAP PHP n\'est pas installée', 'ldap_cannot_connect' => 'Impossible de se connecter au serveur LDAP, la connexion initiale a échoué', + 'saml_already_logged_in' => 'Déjà connecté', + 'saml_user_not_registered' => 'L\'utilisateur :name n\'est pas enregistré et l\'enregistrement automatique est désactivé', + 'saml_no_email_address' => 'Impossible de trouver une adresse e-mail, pour cet utilisateur, dans les données fournies par le système d\'authentification externe', + 'saml_invalid_response_id' => 'La requête du système d\'authentification externe n\'est pas reconnue par un processus démarré par cette application. Naviguer après une connexion peut causer ce problème.', + 'saml_fail_authed' => 'Connexion avec :system échoue, le système n\'a pas fourni l\'autorisation réussie', 'social_no_action_defined' => 'Pas d\'action définie', - 'social_login_bad_response' => "Erreur pendant la tentative de connexion à :socialAccount : \n:error", + 'social_login_bad_response' => "Erreur pendant la tentative de connexion à :socialAccount : \n:error", 'social_account_in_use' => 'Ce compte :socialAccount est déjà utilisé. Essayez de vous connecter via :socialAccount.', 'social_account_email_in_use' => 'L\'email :email est déjà utilisé. Si vous avez déjà un compte :socialAccount, vous pouvez le joindre à votre profil existant.', 'social_account_existing' => 'Ce compte :socialAccount est déjà rattaché à votre profil.', @@ -29,6 +33,7 @@ return [ 'social_account_register_instructions' => 'Si vous n\'avez pas encore de compte, vous pouvez le lier avec l\'option :socialAccount.', 'social_driver_not_found' => 'Pilote de compte social absent', 'social_driver_not_configured' => 'Vos préférences pour le compte :socialAccount sont incorrectes.', + 'invite_token_expired' => 'Le lien de cette invitation a expiré. Vous pouvez essayer de réinitiliser votre mot de passe.', // System 'path_not_writable' => 'Impossible d\'écrire dans :filePath. Assurez-vous d\'avoir les droits d\'écriture sur le serveur', @@ -66,6 +71,14 @@ return [ 'role_cannot_be_edited' => 'Ce rôle ne peut pas être modifié', 'role_system_cannot_be_deleted' => 'Ceci est un rôle du système et ne peut pas être supprimé', 'role_registration_default_cannot_delete' => 'Ce rôle ne peut pas être supprimé tant qu\'il est le rôle par défaut', + 'role_cannot_remove_only_admin' => 'Ceci est le seul compte administrateur. Assignez un nouvel administrateur avant de le supprimer ici.', + + // Comments + 'comment_list' => 'Une erreur s\'est produite lors de la récupération des commentaires.', + 'cannot_add_comment_to_draft' => 'Vous ne pouvez pas ajouter de commentaires à un projet.', + 'comment_add' => 'Une erreur s\'est produite lors de l\'ajout du commentaire.', + 'comment_delete' => 'Une erreur s\'est produite lors de la suppression du commentaire.', + 'empty_comment' => 'Impossible d\'ajouter un commentaire vide.', // Error pages '404_page_not_found' => 'Page non trouvée', @@ -75,10 +88,12 @@ return [ 'app_down' => ':appName n\'est pas en service pour le moment', 'back_soon' => 'Nous serons bientôt de retour.', - // comments - 'comment_list' => 'Une erreur s\'est produite lors de la récupération des commentaires.', - 'cannot_add_comment_to_draft' => 'Vous ne pouvez pas ajouter de commentaires à un projet.', - 'comment_add' => 'Une erreur s\'est produite lors de l\'ajout du commentaire.', - 'comment_delete' => 'Une erreur s\'est produite lors de la suppression du commentaire.', - 'empty_comment' => 'Impossible d\'ajouter un commentaire vide.', + // API errors + 'api_no_authorization_found' => 'Aucun jeton d\'autorisation trouvé pour la demande', + 'api_bad_authorization_format' => 'Un jeton d\'autorisation a été trouvé pour la requête, mais le format semble incorrect', + 'api_user_token_not_found' => 'Aucun jeton API correspondant n\'a été trouvé pour le jeton d\'autorisation fourni', + 'api_incorrect_token_secret' => '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' => 'Le jeton d\'autorisation utilisé a expiré', + ]; diff --git a/resources/lang/fr/pagination.php b/resources/lang/fr/pagination.php index 9f07a5f93..5d8f102fb 100644 --- a/resources/lang/fr/pagination.php +++ b/resources/lang/fr/pagination.php @@ -1,18 +1,11 @@ '« Précédent', 'next' => 'Suivant »', diff --git a/resources/lang/fr/passwords.php b/resources/lang/fr/passwords.php index 484b4b20c..3852f5bf1 100644 --- a/resources/lang/fr/passwords.php +++ b/resources/lang/fr/passwords.php @@ -1,22 +1,15 @@ 'Les mots de passe doivent faire au moins 6 caractères et correspondre à la confirmation.', 'user' => "Nous n'avons pas trouvé d'utilisateur avec cette adresse.", 'token' => 'Le jeton de réinitialisation est invalide.', - 'sent' => 'Nous vous avons envoyé un lien de réinitialisation de mot de passe !', - 'reset' => 'Votre mot de passe a été réinitialisé !', + 'sent' => 'Nous vous avons envoyé un lien de réinitialisation de mot de passe !', + 'reset' => 'Votre mot de passe a été réinitialisé !', ]; diff --git a/resources/lang/fr/settings.php b/resources/lang/fr/settings.php index f978114c5..2fd8980ae 100644 --- a/resources/lang/fr/settings.php +++ b/resources/lang/fr/settings.php @@ -1,38 +1,35 @@ 'Préférences', 'settings_save' => 'Enregistrer les préférences', 'settings_save_success' => 'Préférences enregistrées', - /** - * App settings - */ - + // App Settings 'app_customization' => 'Personnalisation', 'app_features_security' => 'Fonctionnalités et sécurité', 'app_name' => 'Nom de l\'application', 'app_name_desc' => 'Ce nom est affiché dans l\'en-tête et les e-mails.', - 'app_name_header' => 'Afficher le nom dans l\'en-tête ?', + 'app_name_header' => 'Afficher le nom dans l\'en-tête ?', 'app_public_access' => 'Accès public', 'app_public_access_desc' => 'L\'activation de cette option permettra aux visiteurs, qui ne sont pas connectés, d\'accéder au contenu de votre instance BookStack.', 'app_public_access_desc_guest' => 'L\'accès pour les visiteurs publics peut être contrôlé par l\'utilisateur "Guest".', 'app_public_access_toggle' => 'Autoriser l\'accès public', - 'app_public_viewing' => 'Accepter le visionnage public des pages ?', - 'app_secure_images' => 'Activer l\'ajout d\'image sécurisé ?', + 'app_public_viewing' => 'Accepter le visionnage public des pages ?', + 'app_secure_images' => 'Activer l\'ajout d\'image sécurisé ?', 'app_secure_images_toggle' => 'Activer l\'ajout d\'image sécurisé', 'app_secure_images_desc' => 'Pour des questions de performances, toutes les images sont publiques. Cette option ajoute une chaîne aléatoire difficile à deviner dans les URLs des images.', 'app_editor' => 'Editeur des pages', 'app_editor_desc' => 'Sélectionnez l\'éditeur qui sera utilisé pour modifier les pages.', 'app_custom_html' => 'HTML personnalisé dans l\'en-tête', 'app_custom_html_desc' => 'Le contenu inséré ici sera ajouté en bas de la balise de toutes les pages. Vous pouvez l\'utiliser pour ajouter du CSS personnalisé ou un tracker analytique.', + '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' => 'Logo de l\'Application', 'app_logo_desc' => 'Cette image doit faire 43px de hauteur.
Les images plus larges seront réduites.', 'app_primary_color' => 'Couleur principale de l\'application', @@ -43,40 +40,48 @@ return [ '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.', - - /** - * Registration settings - */ + // Color settings + 'content_colors' => 'Couleur du contenu', + 'content_colors_desc' => 'Définit les couleurs pour tous les éléments de la hiérarchie d\'organisation des pages. Choisir les couleurs avec une luminosité similaire aux couleurs par défaut est recommandé pour la lisibilité.', + 'bookshelf_color' => 'Couleur de l\'étagère', + 'book_color' => 'Couleur du livre', + 'chapter_color' => 'Couleur du chapitre', + 'page_color' => 'Couleur de la page', + 'page_draft_color' => 'Couleur du brouillon', + + // Registration Settings 'reg_settings' => 'Préférence pour l\'inscription', 'reg_enable' => 'Activer l\'inscription', 'reg_enable_toggle' => 'Activer l\'inscription', 'reg_enable_desc' => 'Lorsque l\'inscription est activée, l\'utilisateur pourra s\'enregistrer en tant qu\'utilisateur de l\'application. Lors de l\'inscription, ils se voient attribuer un rôle par défaut.', 'reg_default_role' => 'Rôle par défaut lors de l\'inscription', + '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' => 'Confirmation de l\'e-mail', - 'reg_email_confirmation_toggle' => 'Obliger la confirmation par e-mail ?', + 'reg_email_confirmation_toggle' => 'Obliger la confirmation par e-mail ?', 'reg_confirm_email_desc' => 'Si la restriction de domaine est activée, la confirmation sera automatiquement obligatoire et cette valeur sera ignorée.', 'reg_confirm_restrict_domain' => 'Restreindre l\'inscription à un domaine', 'reg_confirm_restrict_domain_desc' => 'Entrez une liste de domaines acceptés lors de l\'inscription, séparés par une virgule. Les utilisateurs recevront un e-mail de confirmation à cette adresse.
Les utilisateurs pourront changer leur adresse après inscription s\'ils le souhaitent.', 'reg_confirm_restrict_domain_placeholder' => 'Aucune restriction en place', - /** - * Maintenance settings - */ - + // Maintenance settings 'maint' => 'Maintenance', 'maint_image_cleanup' => 'Nettoyer les images', 'maint_image_cleanup_desc' => "Scan le contenu des pages et des révisions pour vérifier les images et les dessins en cours d'utilisation et lesquels sont redondant. Veuillez à faire une sauvegarde de la base de données et des images avant de lancer ceci.", 'maint_image_cleanup_ignore_revisions' => 'Ignorer les images dans les révisions', 'maint_image_cleanup_run' => 'Lancer le nettoyage', - 'maint_image_cleanup_warning' => ':count images potentiellement inutilisées trouvées. Etes-vous sûr de vouloir supprimer ces images ?', - 'maint_image_cleanup_success' => ':count images potentiellement inutilisées trouvées et supprimées !', - 'maint_image_cleanup_nothing_found' => 'Aucune image inutilisée trouvée, rien à supprimer !', - - /** - * Role settings - */ + 'maint_image_cleanup_warning' => ':count images potentiellement inutilisées trouvées. Etes-vous sûr de vouloir supprimer ces images ?', + 'maint_image_cleanup_success' => ':count images potentiellement inutilisées trouvées et supprimées !', + 'maint_image_cleanup_nothing_found' => 'Aucune image inutilisée trouvée, rien à supprimer !', + 'maint_send_test_email' => 'Envoyer un email de test', + 'maint_send_test_email_desc' => 'Ceci envoie un e-mail de test à votre adresse e-mail spécifiée dans votre profil.', + 'maint_send_test_email_run' => 'Envoyer un email de test', + 'maint_send_test_email_success' => 'Email envoyé à :address', + 'maint_send_test_email_mail_subject' => 'Email de test', + 'maint_send_test_email_mail_greeting' => 'La livraison d\'email semble fonctionner !', + 'maint_send_test_email_mail_text' => 'Félicitations ! Lorsque vous avez reçu cette notification par courriel, vos paramètres d\'email semblent être configurés correctement.', + // Role Settings 'roles' => 'Rôles', 'role_user_roles' => 'Rôles des utilisateurs', 'role_create' => 'Créer un nouveau rôle', @@ -85,7 +90,7 @@ return [ 'role_delete_confirm' => 'Ceci va supprimer le rôle \':roleName\'.', 'role_delete_users_assigned' => 'Ce rôle a :userCount utilisateurs assignés. Vous pouvez choisir un rôle de remplacement pour ces utilisateurs.', 'role_delete_no_migration' => "Ne pas assigner de nouveau rôle", - 'role_delete_sure' => 'Êtes-vous sûr de vouloir supprimer ce rôle ?', + 'role_delete_sure' => 'Êtes-vous sûr de vouloir supprimer ce rôle ?', 'role_delete_success' => 'Le rôle a été supprimé avec succès', 'role_edit' => 'Modifier le rôle', 'role_details' => 'Détails du rôle', @@ -96,7 +101,9 @@ return [ 'role_manage_users' => 'Gérer les utilisateurs', 'role_manage_roles' => 'Gérer les rôles et permissions', 'role_manage_entity_permissions' => 'Gérer les permissions sur les livres, chapitres et pages', - 'role_manage_own_entity_permissions' => 'Gérer les permissions de ses propres livres, chapitres, et pages', + 'role_manage_own_entity_permissions' => 'Gérer les permissions de ses propres livres, chapitres et pages', + 'role_manage_page_templates' => 'Gérer les modèles de page', + 'role_access_api' => 'Accès à l\'API du système', 'role_manage_settings' => 'Gérer les préférences de l\'application', 'role_asset' => 'Permissions des ressources', 'role_asset_desc' => 'Ces permissions contrôlent l\'accès par défaut des ressources dans le système. Les permissions dans les livres, les chapitres et les pages ignoreront ces permissions', @@ -109,10 +116,7 @@ return [ 'role_users' => 'Utilisateurs ayant ce rôle', 'role_users_none' => 'Aucun utilisateur avec ce rôle actuellement', - /** - * Users - */ - + // Users 'users' => 'Utilisateurs', 'user_profile' => 'Profil d\'utilisateur', 'users_add_new' => 'Ajouter un nouvel utilisateur', @@ -124,20 +128,22 @@ return [ 'users_role_desc' => 'Sélectionnez les rôles auxquels cet utilisateur sera affecté. Si un utilisateur est affecté à plusieurs rôles, les permissions de ces rôles s\'empileront et ils recevront toutes les capacités des rôles affectés.', 'users_password' => 'Mot de passe de l\'utilisateur', 'users_password_desc' => 'Définissez un mot de passe utilisé pour vous connecter à l\'application. Il doit comporter au moins 5 caractères.', + 'users_send_invite_text' => 'Vous pouvez choisir d\'envoyer à cet utilisateur un email d\'invitation qui lui permet de définir son propre mot de passe, sinon vous pouvez définir son mot de passe vous-même.', + 'users_send_invite_option' => 'Envoyer l\'e-mail d\'invitation', 'users_external_auth_id' => 'Identifiant d\'authentification externe', - 'users_external_auth_id_desc' => 'Il s\'agit de l\'identifiant utilisé pour appairer cet utilisateur lors de la communication avec votre système LDAP.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Remplissez ce formulaire uniquement si vous souhaitez changer de mot de passe:', 'users_system_public' => 'Cet utilisateur représente les invités visitant votre instance. Il est assigné automatiquement aux invités.', 'users_delete' => 'Supprimer un utilisateur', 'users_delete_named' => 'Supprimer l\'utilisateur :userName', 'users_delete_warning' => 'Ceci va supprimer \':userName\' du système.', - 'users_delete_confirm' => 'Êtes-vous sûr(e) de vouloir supprimer cet utilisateur ?', + 'users_delete_confirm' => 'Êtes-vous sûr(e) de vouloir supprimer cet utilisateur ?', 'users_delete_success' => 'Utilisateurs supprimés avec succès', 'users_edit' => 'Modifier l\'utilisateur', 'users_edit_profile' => 'Modifier le profil', 'users_edit_success' => 'Utilisateur mis à jour avec succès', 'users_avatar' => 'Avatar de l\'utilisateur', - 'users_avatar_desc' => 'Cette image doit être un carré d\'environ 256px.', + 'users_avatar_desc' => 'Cette image doit être un carré d\'environ 256 px.', 'users_preferred_language' => 'Langue préférée', 'users_preferred_language_desc' => 'Cette option changera la langue utilisée pour l\'interface utilisateur de l\'application. Ceci n\'affectera aucun contenu créé par l\'utilisateur.', 'users_social_accounts' => 'Comptes sociaux', @@ -146,5 +152,60 @@ return [ 'users_social_disconnect' => 'Déconnecter le compte', 'users_social_connected' => 'Votre compte :socialAccount a été ajouté avec succès.', 'users_social_disconnected' => 'Votre compte :socialAccount a été déconnecté avec succès', + 'users_api_tokens' => 'Jetons de l\'API', + 'users_api_tokens_none' => 'Aucun jeton API n\'a été créé pour cet utilisateur', + 'users_api_tokens_create' => 'Créer un jeton', + 'users_api_tokens_expires' => 'Expiré', + 'users_api_tokens_docs' => 'Documentation de l\'API', + // API Tokens + 'user_api_token_create' => 'Créer un nouveau jeton API', + 'user_api_token_name' => 'Nom', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Date d\'expiration', + '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' => 'L\'API token a été créé avec succès', + 'user_api_token_update_success' => 'L\'API token a été mis à jour avec succès', + 'user_api_token' => 'Token API', + 'user_api_token_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' => 'Jeton créé :timeAgo', + 'user_api_token_updated' => 'Jeton mis à jour :timeAgo', + 'user_api_token_delete' => 'Supprimer le 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' => 'Souhaitez-vous vraiment effacer l\'API Token ?', + 'user_api_token_delete_success' => 'L\'API token a été supprimé avec succès', + + //! If editing translations files directly please ignore this in all + //! languages apart from en. Content will be auto-copied from en. + //!//////////////////////////////// + 'language_select' => [ + 'en' => 'English', + 'ar' => 'العربية', + 'da' => 'Danois', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// ]; diff --git a/resources/lang/fr/validation.php b/resources/lang/fr/validation.php index 4be55df4f..f59d5c503 100644 --- a/resources/lang/fr/validation.php +++ b/resources/lang/fr/validation.php @@ -1,18 +1,13 @@ ':attribute doit être accepté.', 'active_url' => ':attribute n\'est pas une URL valide.', 'after' => ':attribute doit être supérieur à :date.', @@ -35,13 +30,41 @@ return [ 'digits' => ':attribute doit être de longueur :digits.', 'digits_between' => ':attribute doit avoir une longueur entre :min et :max.', 'email' => ':attribute doit être une adresse e-mail valide.', + 'ends_with' => ':attribute doit se terminer par une des valeurs suivantes : :values', 'filled' => ':attribute est un champ requis.', + 'gt' => [ + 'numeric' => ':attribute doit être plus grand que :value.', + 'file' => ':attribute doit être plus grand que :value kilobytes.', + 'string' => ':attribute doit être plus grand que :value caractères.', + 'array' => ':attribute doit avoir plus que :value éléments.', + ], + 'gte' => [ + 'numeric' => ':attribute doit être plus grand ou égal à :value.', + 'file' => ':attribute doit être plus grand ou égal à :value kilobytes.', + 'string' => ':attribute doit être plus grand ou égal à :value caractères.', + 'array' => ':attribute doit avoir :value éléments ou plus.', + ], 'exists' => 'L\'attribut :attribute est invalide.', 'image' => ':attribute doit être une image.', 'image_extension' => ':attribute doit avoir une extension d\'image valide et supportée.', 'in' => 'L\'attribut :attribute est invalide.', 'integer' => ':attribute doit être un chiffre entier.', 'ip' => ':attribute doit être une adresse IP valide.', + 'ipv4' => ':attribute doit être une adresse IPv4 valide.', + 'ipv6' => ':attribute doit être une adresse IPv6 valide.', + 'json' => ':attribute doit être une chaine JSON valide.', + 'lt' => [ + 'numeric' => ':attribute doit être plus petit que :value.', + 'file' => ':attribute doit être plus petit que :value kilobytes.', + 'string' => ':attribute doit être plus petit que :value caractères.', + 'array' => ':attribute doit avoir moins de :value éléments.', + ], + 'lte' => [ + 'numeric' => ':attribute doit être plus petit ou égal à :value.', + 'file' => ':attribute doit être plus petit ou égal à :value kilobytes.', + 'string' => ':attribute doit être plus petit ou égal à :value caractères.', + 'array' => ':attribute ne doit pas avoir plus de :value éléments.', + ], 'max' => [ 'numeric' => ':attribute ne doit pas excéder :max.', 'file' => ':attribute ne doit pas excéder :max kilobytes.', @@ -57,6 +80,7 @@ return [ ], '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.', 'regex' => ':attribute a un format invalide.', 'required' => ':attribute est un champ requis.', @@ -78,34 +102,13 @@ return [ 'url' => ':attribute a un format invalide.', 'uploaded' => 'Le fichier n\'a pas pu être envoyé. Le serveur peut ne pas accepter des fichiers de cette taille.', - /* - |-------------------------------------------------------------------------- - | Custom Validation Language Lines - |-------------------------------------------------------------------------- - | - | Here you may specify custom validation messages for attributes using the - | convention "attribute.rule" to name the lines. This makes it quick to - | specify a specific custom language line for a given attribute rule. - | - */ - + // Custom validation lines 'custom' => [ 'password-confirm' => [ 'required_with' => 'La confirmation du mot de passe est requise', ], ], - /* - |-------------------------------------------------------------------------- - | Custom Validation Attributes - |-------------------------------------------------------------------------- - | - | The following language lines are used to swap attribute place-holders - | with something more reader friendly such as E-Mail Address instead - | of "email". This simply helps us make messages a little cleaner. - | - */ - + // Custom validation attributes 'attributes' => [], - ]; diff --git a/resources/lang/hu/auth.php b/resources/lang/hu/auth.php index a1809b0de..dce23545e 100644 --- a/resources/lang/hu/auth.php +++ b/resources/lang/hu/auth.php @@ -21,7 +21,7 @@ return [ 'email' => 'Email', 'password' => 'Jelszó', 'password_confirm' => 'Jelszó megerősítése', - 'password_hint' => 'Öt karakternél hosszabbnak kell lennie', + 'password_hint' => 'Négy karakternél hosszabbnak kell lennie', 'forgot_password' => 'Elfelejtett jelszó?', 'remember_me' => 'Emlékezzen rám', 'ldap_email_hint' => 'A fiókhoz használt email cím megadása.', @@ -64,4 +64,14 @@ return [ 'email_not_confirmed_click_link' => 'Rá kell kattintani a regisztráció után nem sokkal elküldött emailben található hivatkozásra.', 'email_not_confirmed_resend' => 'Ha nem érkezik meg a megerősítő email, a lenti űrlap beküldésével újra lehet küldeni.', 'email_not_confirmed_resend_button' => 'Megerősítő email újraküldése', -]; + + // User Invite + 'user_invite_email_subject' => 'Ez egy meghívó :appName weboldalhoz!', + 'user_invite_email_greeting' => 'Létre lett hozva egy fiók az :appName weboldalon.', + 'user_invite_email_text' => 'Jelszó beállításához és hozzáféréshez a lenti gombra kell kattintani:', + 'user_invite_email_action' => 'Fiók jelszó beállítása', + 'user_invite_page_welcome' => ':appName üdvözöl!', + 'user_invite_page_text' => 'A fiók véglegesítéséhez és a hozzáféréshez be kell állítani egy jelszót ami :appName weboldalon lesz használva a bejelentkezéshez.', + 'user_invite_page_confirm_button' => 'Jelszó megerősítése', + 'user_invite_success' => 'Jelszó beállítva, :appName most már elérhető!' +]; \ No newline at end of file diff --git a/resources/lang/hu/common.php b/resources/lang/hu/common.php index 4e72d5f94..72bc3324b 100644 --- a/resources/lang/hu/common.php +++ b/resources/lang/hu/common.php @@ -38,8 +38,13 @@ return [ 'reset' => 'Visszaállítás', 'remove' => 'Eltávolítás', 'add' => 'Hozzáadás', + 'fullscreen' => 'Teljes képernyő', // Sort Options + 'sort_options' => 'Rendezési beállítások', + 'sort_direction_toggle' => 'Rendezési irány váltása', + 'sort_ascending' => 'Növekvő sorrend', + 'sort_descending' => 'Csökkenő sorrend', 'sort_name' => 'Név', 'sort_created_at' => 'Létrehozás dátuma', 'sort_updated_at' => 'Frissítés dátuma', @@ -55,8 +60,10 @@ return [ 'grid_view' => 'Rács nézet', 'list_view' => 'Lista nézet', 'default' => 'Alapértelmezés szerinti', + 'breadcrumb' => 'Morzsa', // Header + 'profile_menu' => 'Profil menü', 'view_profile' => 'Profil megtekintése', 'edit_profile' => 'Profil szerkesztése', diff --git a/resources/lang/hu/entities.php b/resources/lang/hu/entities.php index 5bd865dd5..6593212f0 100644 --- a/resources/lang/hu/entities.php +++ b/resources/lang/hu/entities.php @@ -162,7 +162,7 @@ return [ // Pages 'page' => 'Oldal', 'pages' => 'Oldalak', - 'x_pages' => ':count oldal|:count oldalak', + 'x_pages' => ':count oldal|:count oldal', 'pages_popular' => 'Népszerű oldalak', 'pages_new' => 'Új oldal', 'pages_attachments' => 'Csatolmányok', @@ -176,7 +176,7 @@ return [ 'pages_delete_confirm' => 'Biztosan törölhető ez az oldal?', 'pages_delete_draft_confirm' => 'Biztosan törölhető ez a vázlatoldal?', 'pages_editing_named' => ':pageName oldal szerkesztése', - 'pages_edit_toggle_header' => 'Fejléc átkapcsolása', + 'pages_edit_draft_options' => 'Vázlatbeállítások', 'pages_edit_save_draft' => 'Vázlat mentése', 'pages_edit_draft' => 'Oldal vázlat szerkesztése', 'pages_editing_draft' => 'Vázlat szerkesztése', @@ -234,6 +234,7 @@ return [ ], 'pages_draft_discarded' => 'Vázlat elvetve, a szerkesztő frissítve lesz az oldal aktuális tartalmával', 'pages_specific' => 'Egy bizonyos oldal', + 'pages_is_template' => 'Oldalsablon', // Editor Sidebar 'page_tags' => 'Oldal címkék', @@ -242,9 +243,11 @@ return [ 'shelf_tags' => 'Polc címkék', 'tag' => 'Címke', 'tags' => 'Címkék', + 'tag_name' => 'Címkenév', 'tag_value' => 'Címke érték (nem kötelező)', 'tags_explain' => "Címkék hozzáadása a tartalom jobb kategorizálásához.\nA mélyebb szervezettség megvalósításához hozzá lehet rendelni egy értéket a címkéhez.", 'tags_add' => 'Másik címke hozzáadása', + 'tags_remove' => 'Címke eltávolítása', 'attachments' => 'Csatolmányok', 'attachments_explain' => 'Az oldalon megjelenő fájlok feltöltése vagy hivatkozások csatolása. Az oldal oldalsávjában fognak megjelenni.', 'attachments_explain_instant_save' => 'Az itt történt módosítások azonnal el lesznek mentve.', @@ -270,6 +273,12 @@ return [ 'attachments_file_uploaded' => 'Fájl sikeresen feltöltve', 'attachments_file_updated' => 'Fájl sikeresen frissítve', 'attachments_link_attached' => 'Hivatkozás sikeresen hozzácsatolva az oldalhoz', + 'templates' => 'Sablonok', + 'templates_set_as_template' => 'Az oldal egy sablon', + 'templates_explain_set_as_template' => 'Ez az oldal sablonnak lett beállítva, így a tartalma felhasználható más oldalak létrehozásakor. Más felhasználók is használhatják ezt a sablont ha megtekintési jogosultságuk van ehhez az oldalhoz.', + 'templates_replace_content' => 'Oldal tartalmának cseréje', + 'templates_append_content' => 'Hozzáfűzés az oldal tartalmához', + 'templates_prepend_content' => 'Hozzáadás az oldal tartalmának elejéhez', // Profile View 'profile_user_for_x' => 'Felhasználó ez óta: :time', diff --git a/resources/lang/hu/errors.php b/resources/lang/hu/errors.php index 679142804..c901e5423 100644 --- a/resources/lang/hu/errors.php +++ b/resources/lang/hu/errors.php @@ -13,10 +13,16 @@ return [ 'email_already_confirmed' => 'Az email cím már meg van erősítve, meg lehet próbálni a bejelentkezést.', 'email_confirmation_invalid' => 'A megerősítő vezérjel nem érvényes vagy használva volt. Meg kell próbálni újraregisztrálni.', 'email_confirmation_expired' => 'A megerősítő vezérjel lejárt. Egy új megerősítő email lett elküldve.', + 'email_confirmation_awaiting' => 'A használatban lévő fiók email címét meg kell erősíteni', 'ldap_fail_anonymous' => 'Nem sikerült az LDAP elérése névtelen csatlakozással', 'ldap_fail_authed' => 'Az LDAP hozzáférés nem sikerült a megadott DN és jelszó beállításokkal', 'ldap_extension_not_installed' => 'LDAP PHP kiterjesztés nincs telepítve', 'ldap_cannot_connect' => 'Nem lehet kapcsolódni az LDAP kiszolgálóhoz, a kezdeti kapcsolatfelvétel nem sikerült', + 'saml_already_logged_in' => 'Már bejelentkezett', + 'saml_user_not_registered' => ':name felhasználó nincs regisztrálva és az automatikus regisztráció le van tiltva', + 'saml_no_email_address' => 'Ehhez a felhasználóhoz nem található email cím a külső hitelesítő rendszer által átadott adatokban', + 'saml_invalid_response_id' => 'A külső hitelesítő rendszerből érkező kérést nem ismerte fel az alkalmazás által indított folyamat. Bejelentkezés után az előző oldalra történő visszalépés okozhatja ezt a hibát.', + 'saml_fail_authed' => 'Bejelentkezés :system használatával sikertelen, a rendszer nem biztosított sikeres hitelesítést', 'social_no_action_defined' => 'Nincs művelet meghatározva', 'social_login_bad_response' => "Hiba történt :socialAccount bejelentkezés közben:\n:error", 'social_account_in_use' => ':socialAccount fiók már használatban van. :socialAccount opción keresztül érdemes megpróbálni a bejelentkezést.', @@ -27,6 +33,7 @@ return [ 'social_account_register_instructions' => ':socialAccount beállítása használatával is lehet fiókot regisztrálni, ha még nem volt fiók létrehozva.', 'social_driver_not_found' => 'Közösségi meghajtó nem található', 'social_driver_not_configured' => ':socialAccount közösségi beállítások nem megfelelőek.', + 'invite_token_expired' => 'Ez a meghívó hivatkozás lejárt. Helyette meg lehet próbálni új jelszót megadni a fiókhoz.', // System 'path_not_writable' => ':filePath elérési út nem tölthető fel. Ellenőrizni kell, hogy az útvonal a kiszolgáló számára írható.', @@ -81,4 +88,12 @@ return [ 'app_down' => ':appName jelenleg nem üzemel', 'back_soon' => 'Hamarosan újra elérhető lesz.', + // API errors + 'api_no_authorization_found' => 'A kérésben nem található hitelesítési vezérjel', + 'api_bad_authorization_format' => 'A kérésben hitelesítési vezérjel található de a formátuma érvénytelennek tűnik', + 'api_user_token_not_found' => 'A megadott hitelesítési vezérjelhez nem található egyező API vezérjel', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'A használt API vezérjel tulajdonosának nincs jogosultsága API hívások végrehajtásához', + 'api_user_token_expired' => 'A használt hitelesítési vezérjel lejárt', + ]; diff --git a/resources/lang/hu/settings.php b/resources/lang/hu/settings.php index efebb4a10..1462fee5d 100644 --- a/resources/lang/hu/settings.php +++ b/resources/lang/hu/settings.php @@ -29,6 +29,7 @@ return [ 'app_editor_desc' => 'Annak kiválasztása, hogy a felhasználók melyik szerkesztőt használhatják az oldalak szerkesztéséhez.', 'app_custom_html' => 'Egyéni HTML fejléc tartalom', 'app_custom_html_desc' => 'Az itt hozzáadott bármilyen tartalom be lesz illesztve minden oldal szekciójának aljára. Ez hasznos a stílusok felülírásához van analitikai kódok hozzáadásához.', + 'app_custom_html_disabled_notice' => 'Az egyéni HTML fejléc tartalom le van tiltva ezen a beállítási oldalon, hogy az esetleg hibásan megadott módosításokat vissza lehessen állítani.', 'app_logo' => 'Alkalmazás logó', 'app_logo_desc' => 'A képnek 43px magasnak kell lennie.
A nagy képek át lesznek méretezve.', 'app_primary_color' => 'Alkalmazás elsődleges színe', @@ -40,12 +41,22 @@ return [ '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.', + // Color settings + 'content_colors' => 'Tartalomszínek', + 'content_colors_desc' => 'Beállítja az elemek színét az oldalszervezési hierarchiában. Az olvashatóság szempontjából javasolt az alapértelmezés szerinti színhez hasonló fényerősséget választani.', + 'bookshelf_color' => 'Polc színe', + 'book_color' => 'Könyv színe', + 'chapter_color' => 'Fejezet színe', + 'page_color' => 'Oldal színe', + 'page_draft_color' => 'Oldalvázlat színe', + // Registration Settings 'reg_settings' => 'Regisztráció', 'reg_enable' => 'Regisztráció engedélyezése', 'reg_enable_toggle' => 'Regisztráció engedélyezése', 'reg_enable_desc' => 'Ha a regisztráció engedélyezett, akkor a felhasználó képes lesz bejelentkezni mint az alkalmazás egy felhasználója. Regisztráció után egy egyszerű, alapértelmezés szerinti felhasználói szerepkör lesz hozzárendelve.', 'reg_default_role' => 'Regisztráció utáni alapértelmezett felhasználói szerepkör', + '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 megerősítés', 'reg_email_confirmation_toggle' => 'Email megerősítés szükséges', 'reg_confirm_email_desc' => 'Ha a tartomány korlátozás be van állítva, akkor email megerősítés szükséges és ez a beállítás figyelmen kívül lesz hagyva.', @@ -62,6 +73,13 @@ return [ 'maint_image_cleanup_warning' => ':count potenciálisan nem használt képet találtam. Biztosan törölhetőek ezek a képek?', 'maint_image_cleanup_success' => ':count potenciálisan nem használt kép megtalálva és törölve!', 'maint_image_cleanup_nothing_found' => 'Nincsenek nem használt képek, semmi sem lett törölve!', + 'maint_send_test_email' => 'Teszt e-mail küldése', + 'maint_send_test_email_desc' => 'Ez elküld egy teszt emailt a profilban megadott email címre.', + 'maint_send_test_email_run' => 'Teszt e-mail küldése', + 'maint_send_test_email_success' => 'Email elküldve :address címre', + 'maint_send_test_email_mail_subject' => 'Teszt e-mail', + 'maint_send_test_email_mail_greeting' => 'Az email kézbesítés működőképesnek tűnik!', + 'maint_send_test_email_mail_text' => 'Gratulálunk! Mivel ez az email figyelmeztetés megérkezett az email beállítások megfelelőek.', // Role Settings 'roles' => 'Szerepkörök', @@ -84,6 +102,8 @@ return [ 'role_manage_roles' => 'Szerepkörök és szerepkör engedélyek kezelése', 'role_manage_entity_permissions' => 'Minden könyv, fejezet és oldalengedély kezelése', 'role_manage_own_entity_permissions' => 'Saját könyv, fejezet és oldalak engedélyeinek kezelése', + 'role_manage_page_templates' => 'Oldalsablonok kezelése', + 'role_access_api' => 'Hozzáférés a rendszer API-hoz', 'role_manage_settings' => 'Alkalmazás beállításainak kezelése', 'role_asset' => 'Eszköz jogosultságok', 'role_asset_desc' => 'Ezek a jogosultság vezérlik a alapértelmezés szerinti hozzáférést a rendszerben található eszközökhöz. A könyvek, fejezetek és oldalak jogosultságai felülírják ezeket a jogosultságokat.', @@ -108,8 +128,10 @@ return [ 'users_role_desc' => 'A felhasználó melyik szerepkörhöz lesz rendelve. Ha a felhasználó több szerepkörhöz van rendelve, akkor ezeknek a szerepköröknek a jogosultságai összeadódnak, és a a felhasználó a hozzárendelt szerepkörök minden képességét megkapja.', 'users_password' => 'Felhasználó jelszava', 'users_password_desc' => 'Az alkalmazásba bejelentkezéshez használható jelszó beállítása. Legalább 5 karakter hosszúnak kell lennie.', + 'users_send_invite_text' => 'Lehetséges egy meghívó emailt küldeni ennek a felhasználónak ami lehetővé teszi, hogy beállíthassa a saját jelszavát. Máskülönben a jelszót az erre jogosult felhasználónak kell beállítania.', + 'users_send_invite_option' => 'Felhasználó meghívó levél küldése', 'users_external_auth_id' => 'Külső hitelesítés azonosítója', - 'users_external_auth_id_desc' => 'Ez az azonosító lesz használva a felhasználó ellenőrzéséhez mikor az LDAP rendszerrel kommunikál.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'A lenti mezőket csak a jelszó módosításához kell kitölteni.', 'users_system_public' => 'Ez a felhasználó bármelyik, a példányt megtekintő felhasználót képviseli. Nem lehet vele bejelentkezni de automatikusan hozzá lesz rendelve.', 'users_delete' => 'Felhasználó törlése', @@ -130,14 +152,40 @@ return [ 'users_social_disconnect' => 'Fiók lecsatlakoztatása', 'users_social_connected' => ':socialAccount fiók sikeresen csatlakoztatva a profilhoz.', 'users_social_disconnected' => ':socialAccount fiók sikeresen lecsatlakoztatva a profilról.', + 'users_api_tokens' => 'API vezérjelek', + 'users_api_tokens_none' => 'Ehhez a felhasználóhoz nincsenek létrehozva API vezérjelek', + 'users_api_tokens_create' => 'Vezérjel létrehozása', + 'users_api_tokens_expires' => 'Lejárat', + 'users_api_tokens_docs' => 'API dokumentáció', - //! Since these labels are already localized this array does not need to be - //! translated in the language-specific files. - //! DELETE BELOW IF COPIED FROM EN + // API Tokens + 'user_api_token_create' => 'API vezérjel létrehozása', + 'user_api_token_name' => 'Név', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Lejárati dátum', + 'user_api_token_expiry_desc' => 'Dátum megadása ameddig a vezérjel érvényes. Ez után a dátum után az ezzel a vezérjellel történő kérések nem fognak működni. Üresen hagyva a lejárati idő 100 évre lesz beállítva.', + '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 vezérjel sikeresen létrehozva', + 'user_api_token_update_success' => 'API vezérjel sikeresen frissítve', + 'user_api_token' => 'API vezérjel', + 'user_api_token_id' => 'Vezérjel azonosító', + 'user_api_token_id_desc' => 'Ez egy nem szerkeszthető, a rendszer által létrehozott azonosító ehhez a vezérjelhez amire API kérésekben lehet szükség.', + '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' => 'Vezérjel létrehozva :timeAgo', + 'user_api_token_updated' => 'Vezérjel frissítve :timeAgo', + 'user_api_token_delete' => 'Vezérjel törlése', + 'user_api_token_delete_warning' => '\':tokenName\' nevű API vezérjel teljesen törölve lesz a rendszerből.', + 'user_api_token_delete_confirm' => 'Biztosan törölhető ez az API vezérjel?', + 'user_api_token_delete_success' => 'API vezérjel sikeresen törölve', + + //! 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' => 'العربية', + 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', @@ -148,14 +196,16 @@ return [ 'sk' => 'Slovensky', 'cs' => 'Česky', 'sv' => 'Svenska', - 'kr' => '한국어', + 'ko' => '한국어', 'ja' => '日本語', 'pl' => 'Polski', 'it' => 'Italian', 'ru' => 'Русский', 'uk' => 'Українська', 'zh_CN' => '简体中文', - 'zh_TW' => '繁體中文' + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', ] //!//////////////////////////////// ]; diff --git a/resources/lang/hu/validation.php b/resources/lang/hu/validation.php index 68a444643..845126cda 100644 --- a/resources/lang/hu/validation.php +++ b/resources/lang/hu/validation.php @@ -30,13 +30,41 @@ return [ 'digits' => ':attribute :digits számból kell álljon.', 'digits_between' => ':attribute hosszának :min és :max számjegy között kell lennie.', 'email' => ':attribute érvényes email cím kell legyen.', + 'ends_with' => ':attribute attribútumnak a következők egyikével kell végződnie: :values', 'filled' => ':attribute mező kötelező.', + 'gt' => [ + 'numeric' => ':attribute nagyobb kell, hogy legyen, mint :value.', + 'file' => ':attribute nagyobb kell, hogy legyen, mint :value kilobájt.', + 'string' => ':attribute nagyobb kell legyen mint :value karakter.', + 'array' => ':attribute több, mint :value elemet kell, hogy tartalmazzon.', + ], + 'gte' => [ + 'numeric' => ':attribute attribútumnak :value értéknél nagyobbnak vagy vele egyenlőnek kell lennie.', + '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.', + ], 'exists' => 'A kiválasztott :attribute érvénytelen.', 'image' => ':attribute kép kell legyen.', 'image_extension' => 'A :attribute kép kiterjesztése érvényes és támogatott kell legyen.', 'in' => 'A kiválasztott :attribute érvénytelen.', 'integer' => ':attribute egész szám kell legyen.', 'ip' => ':attribute érvényes IP cím kell legyen.', + '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.', + '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.', + ], + '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.', + ], 'max' => [ 'numeric' => ':attribute nem lehet nagyobb mint :max.', 'file' => ':attribute nem lehet nagyobb mint :max kilobájt.', @@ -52,6 +80,7 @@ return [ ], '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.', 'regex' => ':attribute formátuma érvénytelen.', 'required' => ':attribute mező kötelező.', diff --git a/resources/lang/it/activities.php b/resources/lang/it/activities.php index 8d7b4bcfe..c66651489 100755 --- a/resources/lang/it/activities.php +++ b/resources/lang/it/activities.php @@ -1,12 +1,10 @@ 'ha creato la pagina', 'page_create_notification' => 'Pagina Creata Correttamente', @@ -25,7 +23,7 @@ return [ 'chapter_update_notification' => 'Capitolo Aggiornato Correttamente', 'chapter_delete' => 'ha eliminato il capitolo', 'chapter_delete_notification' => 'Capitolo Eliminato Correttamente', - 'chapter_move' => 'ha mosso il capitolo', + 'chapter_move' => 'ha spostato il capitolo', // Books 'book_create' => 'ha creato il libro', @@ -37,6 +35,14 @@ return [ 'book_sort' => 'ha ordinato il libro', 'book_sort_notification' => 'Libro Riordinato Correttamente', + // Bookshelves + 'bookshelf_create' => 'ha creato la Libreria', + 'bookshelf_create_notification' => 'Libreria Creata Correttamente', + 'bookshelf_update' => 'ha aggiornato la libreria', + 'bookshelf_update_notification' => 'Libreria Aggiornata Correttamente', + 'bookshelf_delete' => 'ha eliminato la libreria', + 'bookshelf_delete_notification' => 'Libreria Eliminata Correttamente', + // Other 'commented_on' => 'ha commentato in', ]; diff --git a/resources/lang/it/auth.php b/resources/lang/it/auth.php index 68fee41a5..234af2eeb 100755 --- a/resources/lang/it/auth.php +++ b/resources/lang/it/auth.php @@ -1,21 +1,15 @@ 'Credenziali errate.', 'throttle' => 'Troppi tentativi di login. Riprova in :seconds secondi.', - /** - * Login & Register - */ + // Login & Register 'sign_up' => 'Registrati', 'log_in' => 'Login', 'log_in_with' => 'Login con :socialDriver', @@ -27,11 +21,13 @@ return [ 'email' => 'Email', 'password' => 'Password', 'password_confirm' => 'Conferma Password', - 'password_hint' => 'Deve essere più di 5 caratteri', + 'password_hint' => 'Deve essere più di 7 caratteri', 'forgot_password' => 'Password dimenticata?', 'remember_me' => 'Ricordami', 'ldap_email_hint' => 'Inserisci un email per usare quest\'account.', 'create_account' => 'Crea Account', + 'already_have_account' => 'Hai già un account?', + 'dont_have_account' => 'Non hai un account?', 'social_login' => 'Login Social', 'social_registration' => 'Registrazione Social', 'social_registration_text' => 'Registrati usando un altro servizio.', @@ -43,23 +39,18 @@ return [ 'register_success' => 'Grazie per la registrazione! Sei registrato e loggato.', - /** - * Password Reset - */ + // Password Reset 'reset_password' => 'Reimposta Password', 'reset_password_send_instructions' => 'Inserisci il tuo indirizzo sotto e ti verrà inviata una mail contenente un link per resettare la tua password.', 'reset_password_send_button' => 'Invia Link Reset', 'reset_password_sent_success' => 'Un link di reset è stato mandato a :email.', 'reset_password_success' => 'La tua password è stata resettata correttamente.', - 'email_reset_subject' => 'Reimposta la password di :appName', 'email_reset_text' => 'Stai ricevendo questa mail perché abbiamo ricevuto una richiesta di reset della password per il tuo account.', 'email_reset_not_requested' => 'Se non hai richiesto un reset della password, ignora questa mail.', - /** - * Email Confirmation - */ + // Email Confirmation 'email_confirm_subject' => 'Conferma email per :appName', 'email_confirm_greeting' => 'Grazie per esserti registrato a :appName!', 'email_confirm_text' => 'Conferma il tuo indirizzo email cliccando il pulsante sotto:', @@ -73,4 +64,14 @@ return [ 'email_not_confirmed_click_link' => 'Clicca il link nella mail mandata subito dopo la tua registrazione.', 'email_not_confirmed_resend' => 'Se non riesci a trovare la mail puoi rimandarla cliccando il pulsante sotto.', 'email_not_confirmed_resend_button' => 'Reinvia Conferma', + + // User Invite + 'user_invite_email_subject' => 'Sei stato invitato a unirti a :appName!', + 'user_invite_email_greeting' => 'Un account è stato creato per te su :appName.', + 'user_invite_email_text' => 'Clicca sul pulsante qui sotto per impostare una password e ottenere l\'accesso:', + 'user_invite_email_action' => 'Imposta Password', + 'user_invite_page_welcome' => 'Benvenuto in :appName!', + 'user_invite_page_text' => 'Per completare il tuo account e ottenere l\'accesso devi impostare una password che verrà utilizzata per accedere a :appName in futuro.', + 'user_invite_page_confirm_button' => 'Conferma Password', + 'user_invite_success' => 'Password impostata, ora hai accesso a :appName!' ]; \ No newline at end of file diff --git a/resources/lang/it/common.php b/resources/lang/it/common.php index bace09621..d8dbce451 100755 --- a/resources/lang/it/common.php +++ b/resources/lang/it/common.php @@ -1,47 +1,55 @@ 'Annulla', 'confirm' => 'Conferma', 'back' => 'Indietro', 'save' => 'Salva', 'continue' => 'Continua', 'select' => 'Seleziona', - 'more' => 'More', + 'toggle_all' => 'Attiva/disattiva tutto', + 'more' => 'Altro', - /** - * Form Labels - */ + // Form Labels 'name' => 'Nome', 'description' => 'Descrizione', 'role' => 'Ruolo', 'cover_image' => 'Immagine di copertina', 'cover_image_description' => 'Questa immagine dovrebbe essere approssimatamente 440x250px.', - - /** - * Actions - */ + + // Actions 'actions' => 'Azioni', 'view' => 'Visualizza', + 'view_all' => 'Vedi tutto', 'create' => 'Crea', 'update' => 'Aggiorna', 'edit' => 'Modifica', 'sort' => 'Ordina', 'move' => 'Muovi', + 'copy' => 'Copia', 'reply' => 'Rispondi', 'delete' => 'Elimina', 'search' => 'Cerca', 'search_clear' => 'Pulisci Ricerca', - 'reset' => 'Reset', + 'reset' => 'Azzera', 'remove' => 'Rimuovi', 'add' => 'Aggiungi', + 'fullscreen' => 'Schermo intero', - /** - * Misc - */ + // Sort Options + 'sort_options' => 'Opzioni Ordinamento', + 'sort_direction_toggle' => 'Inverti Direzione Ordinamento', + 'sort_ascending' => 'Ordine Ascendente', + 'sort_descending' => 'Ordine Discendente', + 'sort_name' => 'Nome', + 'sort_created_at' => 'Data Creazione', + 'sort_updated_at' => 'Data Aggiornamento', + + // Misc 'deleted_user' => 'Utente Eliminato', 'no_activity' => 'Nessuna attività da mostrare', 'no_items' => 'Nessun elemento disponibile', @@ -51,16 +59,19 @@ return [ 'details' => 'Dettagli', 'grid_view' => 'Visualizzazione Griglia', 'list_view' => 'Visualizzazione Lista', + 'default' => 'Predefinito', + 'breadcrumb' => 'Navigazione', - /** - * Header - */ + // Header + 'profile_menu' => 'Menu del profilo', 'view_profile' => 'Visualizza Profilo', 'edit_profile' => 'Modifica Profilo', - /** - * Email Content - */ + // Layout tabs + 'tab_info' => 'Info', + 'tab_content' => 'Contenuto', + + // 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', -]; \ No newline at end of file +]; diff --git a/resources/lang/it/components.php b/resources/lang/it/components.php index c9ab18a3e..360409646 100755 --- a/resources/lang/it/components.php +++ b/resources/lang/it/components.php @@ -1,16 +1,17 @@ 'Selezione Immagine', 'image_all' => 'Tutte', 'image_all_title' => 'Visualizza tutte le immagini', 'image_book_title' => 'Visualizza immagini caricate in questo libro', 'image_page_title' => 'Visualizza immagini caricate in questa pagina', 'image_search_hint' => 'Cerca immagine per nome', - 'image_uploaded' => 'Uploaded :uploadedDate', + 'image_uploaded' => 'Caricato :uploadedDate', 'image_load_more' => 'Carica Altre', 'image_image_name' => 'Nome Immagine', 'image_delete_used' => 'Questa immagine è usata nelle pagine elencate.', @@ -22,12 +23,11 @@ return [ 'image_upload_success' => 'Immagine caricata correttamente', 'image_update_success' => 'Dettagli immagine aggiornati correttamente', 'image_delete_success' => 'Immagine eliminata correttamente', + 'image_upload_remove' => 'Rimuovi', - /** - * Code editor - */ + // Code Editor 'code_editor' => 'Modifica Codice', 'code_language' => 'Linguaggio Codice', 'code_content' => 'Contenuto Codice', 'code_save' => 'Salva Codice', -]; \ No newline at end of file +]; diff --git a/resources/lang/it/entities.php b/resources/lang/it/entities.php index ad1733b91..9f6acd133 100755 --- a/resources/lang/it/entities.php +++ b/resources/lang/it/entities.php @@ -1,14 +1,17 @@ 'Creati di recente', 'recently_created_pages' => 'Pagine create di recente', 'recently_updated_pages' => 'Pagine aggiornate di recente', 'recently_created_chapters' => 'Capitoli creati di recente', 'recently_created_books' => 'Libri creati di recente', + 'recently_created_shelves' => 'Librerie Create Di Recente', 'recently_update' => 'Aggiornati di recente', 'recently_viewed' => 'Visti di recente', 'recent_activity' => 'Attività Recente', @@ -31,17 +34,13 @@ return [ 'export_pdf' => 'File PDF', 'export_text' => 'File di testo', - /** - * Permissions and restrictions - */ + // Permissions and restrictions 'permissions' => 'Permessi', 'permissions_intro' => 'Una volta abilitati, questi permessi avranno la priorità su tutti gli altri.', 'permissions_enable' => 'Abilita Permessi Custom', 'permissions_save' => 'Salva Permessi', - /** - * Search - */ + // Search 'search_results' => 'Risultati Ricerca', 'search_total_results_found' => ':count risultato trovato|:count risultati trovati', 'search_clear' => 'Pulisci Ricerca', @@ -52,11 +51,13 @@ return [ 'search_content_type' => 'Tipo di Contenuto', 'search_exact_matches' => 'Corrispondenza Esatta', 'search_tags' => 'Ricerche Tag', + 'search_options' => 'Opzioni', 'search_viewed_by_me' => 'Visti', 'search_not_viewed_by_me' => 'Non visti', 'search_permissions_set' => 'Permessi impostati', 'search_created_by_me' => 'Creati da me', 'search_updated_by_me' => 'Aggiornati da me', + 'search_date_options' => 'Opzioni Data', 'search_updated_before' => 'Aggiornati prima del', 'search_updated_after' => 'Aggiornati dopo il', 'search_created_before' => 'Creati prima del', @@ -64,9 +65,39 @@ return [ 'search_set_date' => 'Imposta Data', 'search_update' => 'Aggiorna Ricerca', - /** - * Books - */ + // Shelves + 'shelf' => 'Libreria', + 'shelves' => 'Librerie', + 'x_shelves' => ':count Libreria|:count Librerie', + 'shelves_long' => 'Librerie', + 'shelves_empty' => 'Nessuna libreria è stata creata', + 'shelves_create' => 'Crea Nuova Libreria', + 'shelves_popular' => 'Librerie Popolari', + 'shelves_new' => 'Nuove Librerie', + 'shelves_new_action' => 'Nuova Libreria', + 'shelves_popular_empty' => 'Le librerie più popolari appariranno qui.', + 'shelves_new_empty' => 'Le librerie create più di recente appariranno qui.', + 'shelves_save' => 'Salva Libreria', + 'shelves_books' => 'Libri in questa libreria', + 'shelves_add_books' => 'Aggiungi libri a questa libreria', + 'shelves_drag_books' => 'Trascina i libri qui per aggiungerli a questa libreria', + 'shelves_empty_contents' => 'Questa libreria non ha libri assegnati', + 'shelves_edit_and_assign' => 'Modifica la libreria per assegnare i libri', + 'shelves_edit_named' => 'Modifica Libreria :name', + 'shelves_edit' => 'Modifica Libreria', + 'shelves_delete' => 'Elimina Libreria', + 'shelves_delete_named' => 'Elimina Libreria :name', + 'shelves_delete_explain' => "La libreria ':name' verrà eliminata. I libri contenuti non verranno eliminati.", + 'shelves_delete_confirmation' => 'Sei sicuro di voler eliminare questa libreria?', + 'shelves_permissions' => 'Permessi Libreria', + 'shelves_permissions_updated' => 'Permessi Libreria Aggiornati', + 'shelves_permissions_active' => 'Permessi Attivi Libreria', + 'shelves_copy_permissions_to_books' => 'Copia Permessi ai Libri', + 'shelves_copy_permissions' => 'Copia Permessi', + 'shelves_copy_permissions_explain' => 'Verranno applicati tutti i permessi della libreria ai libri contenuti. Prima di attivarlo, assicurati che ogni permesso di questa libreria sia salvato.', + 'shelves_copy_permission_success' => 'Permessi della libreria copiati in :count libri', + + // Books 'book' => 'Libro', 'books' => 'Libri', 'x_books' => ':count Libro|:count Libri', @@ -74,6 +105,7 @@ return [ 'books_popular' => 'Libri Popolari', 'books_recent' => 'Libri Recenti', 'books_new' => 'Nuovi Libri', + 'books_new_action' => 'Nuovo Libro', 'books_popular_empty' => 'I libri più popolari appariranno qui.', 'books_new_empty' => 'I libri creati più di recente appariranno qui.', 'books_create' => 'Crea Nuovo Libro', @@ -89,7 +121,6 @@ return [ 'books_permissions_updated' => 'Permessi del libro aggiornati', 'books_empty_contents' => 'Non ci sono pagine o capitoli per questo libro.', 'books_empty_create_page' => 'Crea una nuova pagina', - 'books_empty_or' => 'o', 'books_empty_sort_current_book' => 'Ordina il libro corrente', 'books_empty_add_chapter' => 'Aggiungi un capitolo', 'books_permissions_active' => 'Permessi libro attivi', @@ -97,12 +128,15 @@ return [ 'books_navigation' => 'Navigazione Libro', 'books_sort' => 'Ordina il contenuto del libro', 'books_sort_named' => 'Ordina il libro :bookName', + 'books_sort_name' => 'Ordina per Nome', + 'books_sort_created' => 'Ordina per Data di Creazione', + 'books_sort_updated' => 'Ordina per Data di Aggiornamento', + 'books_sort_chapters_first' => 'Capitoli Per Primi', + 'books_sort_chapters_last' => 'Capitoli Per Ultimi', 'books_sort_show_other' => 'Mostra Altri Libri', 'books_sort_save' => 'Salva il nuovo ordine', - /** - * Chapters - */ + // Chapters 'chapter' => 'Capitolo', 'chapters' => 'Capitoli', 'x_chapters' => ':count Capitolo|:count Capitoli', @@ -125,9 +159,7 @@ return [ 'chapters_permissions_success' => 'Permessi Capitolo Aggiornati', 'chapters_search_this' => 'Cerca in questo capitolo', - /** - * Pages - */ + // Pages 'page' => 'Pagina', 'pages' => 'Pagine', 'x_pages' => ':count Pagina|:count Pagine', @@ -144,7 +176,7 @@ return [ 'pages_delete_confirm' => 'Sei sicuro di voler eliminare questa pagina?', 'pages_delete_draft_confirm' => 'Sei sicuro di voler eliminare la bozza di questa pagina?', 'pages_editing_named' => 'Modifica :pageName', - 'pages_edit_toggle_header' => 'Mostra/Nascondi header', + 'pages_edit_draft_options' => 'Opzioni Bozza', 'pages_edit_save_draft' => 'Salva Bozza', 'pages_edit_draft' => 'Modifica Bozza della pagina', 'pages_editing_draft' => 'Modifica Bozza', @@ -166,6 +198,9 @@ return [ 'pages_not_in_chapter' => 'La pagina non è in un capitolo', 'pages_move' => 'Muovi Pagina', 'pages_move_success' => 'Pagina mossa in ":parentName"', + 'pages_copy' => 'Copia Pagina', + 'pages_copy_desination' => 'Copia Destinazione', + 'pages_copy_success' => 'Pagina copiata correttamente', 'pages_permissions' => 'Permessi Pagina', 'pages_permissions_success' => 'Permessi pagina aggiornati', 'pages_revision' => 'Versione', @@ -175,7 +210,9 @@ return [ 'pages_revisions_created_by' => 'Creata Da', 'pages_revisions_date' => 'Data Versione', 'pages_revisions_number' => '#', - 'pages_revisions_changelog' => 'Changelog', + 'pages_revisions_numbered' => 'Revisione #:id', + 'pages_revisions_numbered_changes' => 'Modifiche Revisione #:id', + 'pages_revisions_changelog' => 'Cambiamenti', 'pages_revisions_changes' => 'Cambiamenti', 'pages_revisions_current' => 'Versione Corrente', 'pages_revisions_preview' => 'Anteprima', @@ -195,17 +232,22 @@ return [ 'time_b' => 'negli ultimi :minCount minuti', 'message' => ':start :time. Assicurati di non sovrascrivere le modifiche degli altri!', ], - 'pages_draft_discarded' => "Bozza scartata, l'editor è stato aggiornato con il contenuto corrente della pagina", + 'pages_draft_discarded' => 'Bozza scartata, l\'editor è stato aggiornato con il contenuto corrente della pagina', + 'pages_specific' => 'Pagina Specifica', + 'pages_is_template' => 'Template Pagina', - /** - * Editor sidebar - */ + // Editor Sidebar 'page_tags' => 'Tag Pagina', + 'chapter_tags' => 'Tag Capitolo', + 'book_tags' => 'Tag Libro', + 'shelf_tags' => 'Tag Libreria', 'tag' => 'Tag', - 'tags' => '', + 'tags' => 'Tag', + 'tag_name' => 'Nome Tag', 'tag_value' => 'Valore (Opzionale)', 'tags_explain' => "Aggiungi tag per categorizzare meglio il contenuto. \n Puoi assegnare un valore ai tag per una migliore organizzazione.", 'tags_add' => 'Aggiungi un altro tag', + 'tags_remove' => 'Rimuovi questo tag', 'attachments' => 'Allegati', 'attachments_explain' => 'Carica alcuni file o allega link per visualizzarli nella pagina. Questi sono visibili nella sidebar della pagina.', 'attachments_explain_instant_save' => 'I cambiamenti qui sono salvati istantaneamente.', @@ -213,10 +255,10 @@ return [ 'attachments_upload' => 'Carica File', 'attachments_link' => 'Allega Link', 'attachments_set_link' => 'Imposta Link', - 'attachments_delete_confirm' => "Clicca elimina nuovamente per confermare l'eliminazione di questo allegato.", + 'attachments_delete_confirm' => 'Clicca elimina nuovamente per confermare l\'eliminazione di questo allegato.', 'attachments_dropzone' => 'Rilascia file o clicca qui per allegare un file', 'attachments_no_files' => 'Nessun file è stato caricato', - 'attachments_explain_link' => 'Puoi allegare un link se preferisci non caricare un file. Questo può essere un link a un\'altra pagina o a un file in un cloud.', + 'attachments_explain_link' => 'Puoi allegare un link se preferisci non caricare un file. Questo può essere un link a un\'altra pagina o a un file nel cloud.', 'attachments_link_name' => 'Nome Link', 'attachment_link' => 'Link allegato', 'attachments_link_url' => 'Link al file', @@ -231,19 +273,22 @@ return [ 'attachments_file_uploaded' => 'File caricato correttamente', 'attachments_file_updated' => 'File aggiornato correttamente', 'attachments_link_attached' => 'Link allegato correttamente alla pagina', + 'templates' => 'Template', + 'templates_set_as_template' => 'La pagina è un template', + 'templates_explain_set_as_template' => 'Puoi impostare questa pagina come template in modo che il suo contenuto sia utilizzato quando si creano altre pagine. Gli altri utenti potranno utilizzare questo template se avranno i permessi di visualizzazione per questa pagina.', + 'templates_replace_content' => 'Rimpiazza contenuto della pagina', + 'templates_append_content' => 'Appendi al contenuto della pagina', + 'templates_prepend_content' => 'Prependi al contenuto della pagina', - /** - * Profile View - */ + // Profile View 'profile_user_for_x' => 'Utente da :time', 'profile_created_content' => 'Contenuti Creati', 'profile_not_created_pages' => ':userName non ha creato pagine', 'profile_not_created_chapters' => ':userName non ha creato capitoli', 'profile_not_created_books' => ':userName non ha creato libri', + 'profile_not_created_shelves' => ':userName non ha creato alcuna libreria', - /** - * Comments - */ + // Comments 'comment' => 'Commento', 'comments' => 'Commenti', 'comment_add' => 'Aggiungi Commento', @@ -261,10 +306,9 @@ return [ 'comment_delete_confirm' => 'Sei sicuro di voler elminare questo commento?', 'comment_in_reply_to' => 'In risposta a :commentId', - /** - * Revision - */ + // Revision 'revision_delete_confirm' => 'Sei sicuro di voler eliminare questa revisione?', + 'revision_restore_confirm' => 'Sei sicuro di voler ripristinare questa revisione? Il contenuto della pagina verrà rimpiazzato.', 'revision_delete_success' => 'Revisione cancellata', 'revision_cannot_delete_latest' => 'Impossibile eliminare l\'ultima revisione.' ]; \ No newline at end of file diff --git a/resources/lang/it/errors.php b/resources/lang/it/errors.php index 17be482c7..977f26e19 100755 --- a/resources/lang/it/errors.php +++ b/resources/lang/it/errors.php @@ -1,46 +1,52 @@ 'Non hai il permesso di accedere alla pagina richiesta.', - 'permissionJson' => "Non hai il permesso di eseguire l'azione richiesta.", + 'permissionJson' => 'Non hai il permesso di eseguire l\'azione richiesta.', // Auth 'error_user_exists_different_creds' => 'Un utente con la mail :email esiste già ma con credenziali differenti.', 'email_already_confirmed' => 'La mail è già stata confermata, esegui il login.', 'email_confirmation_invalid' => 'Questo token di conferma non è valido o già stato utilizzato, registrati nuovamente.', 'email_confirmation_expired' => 'Il token di conferma è scaduto, è stata inviata una nuova mail di conferma.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'Accesso LDAP fallito usando bind anonimo', 'ldap_fail_authed' => 'Accesso LDAP fallito usando il dn e la password inseriti', 'ldap_extension_not_installed' => 'L\'estensione PHP LDAP non è installata', 'ldap_cannot_connect' => 'Impossibile connettersi al server ldap, connessione iniziale fallita', + 'saml_already_logged_in' => 'Già loggato', + 'saml_user_not_registered' => 'L\'utente :name non è registrato e la registrazione automatica è disabilitata', + 'saml_no_email_address' => 'Impossibile trovare un indirizzo email per questo utente nei dati forniti dal sistema di autenticazione esterno', + 'saml_invalid_response_id' => 'La richiesta dal sistema di autenticazione esterno non è riconosciuta da un processo iniziato da questa applicazione. Tornare indietro dopo un login potrebbe causare questo problema.', + 'saml_fail_authed' => 'Accesso con :system non riuscito, il sistema non ha fornito l\'autorizzazione corretta', 'social_no_action_defined' => 'Nessuna azione definita', 'social_login_bad_response' => "Ricevuto error durante il login con :socialAccount : \n:error", 'social_account_in_use' => 'Questo account :socialAccount è già utilizzato, prova a loggarti usando l\'opzione :socialAccount.', 'social_account_email_in_use' => 'La mail :email è già in uso. Se hai già un account puoi connettere il tuo account :socialAccount dalle impostazioni del tuo profilo.', 'social_account_existing' => 'Questo account :socialAccount è già connesso al tuo profilo.', - 'social_account_already_used_existing' => 'Questo accoutn :socialAccount è già utilizzato da un altro utente.', + 'social_account_already_used_existing' => 'Questo account :socialAccount è già utilizzato da un altro utente.', 'social_account_not_used' => 'Questo account :socialAccount non è collegato a nessun utente. Collegalo nelle impostazioni del profilo. ', 'social_account_register_instructions' => 'Se non hai ancora un account, puoi registrarti usando l\'opzione :socialAccount.', 'social_driver_not_found' => 'Driver social non trovato', 'social_driver_not_configured' => 'Le impostazioni di :socialAccount non sono configurate correttamente.', + 'invite_token_expired' => 'Il link di invito è scaduto. Puoi provare a resettare la password del tuo account.', // System - 'path_not_writable' => 'La path :filePath non può essere scritta. Controlla che abbia i permessi corretti.', + 'path_not_writable' => 'Il percorso :filePath non è scrivibile. Controlla che abbia i permessi corretti.', 'cannot_get_image_from_url' => 'Impossibile scaricare immagine da :url', 'cannot_create_thumbs' => 'Il server non può creare thumbnail. Controlla che l\'estensione GD sia installata.', 'server_upload_limit' => 'Il server non permette un upload di questa grandezza. Prova con un file più piccolo.', + 'uploaded' => 'Il server non consente upload di questa grandezza. Prova un file più piccolo.', 'image_upload_error' => 'C\'è stato un errore caricando l\'immagine', - 'image_upload_type_error' => 'Il tipo di immagine in upload non è valido', - 'file_upload_timeout' => 'Il caricamento del file è scaduto.', + 'image_upload_type_error' => 'Il tipo di immagine caricata non è valido', + 'file_upload_timeout' => 'Il caricamento del file è andato in timeout.', // Attachments - 'attachment_page_mismatch' => 'Page mismatch during attachment update', + 'attachment_page_mismatch' => 'La pagina non è corrisposta durante l\'aggiornamento dell\'allegato', 'attachment_not_found' => 'Allegato non trovato', // Pages @@ -49,6 +55,7 @@ return [ // Entities 'entity_not_found' => 'Entità non trovata', + 'bookshelf_not_found' => 'Libreria non trovata', 'book_not_found' => 'Libro non trovato', 'page_not_found' => 'Pagina non trovata', 'chapter_not_found' => 'Capitolo non trovato', @@ -57,13 +64,14 @@ return [ 'guests_cannot_save_drafts' => 'Gli ospiti non possono salvare bozze', // Users - 'users_cannot_delete_only_admin' => 'Non puoi eliminare l\'unico adin', + 'users_cannot_delete_only_admin' => 'Non puoi eliminare l\'unico admin', 'users_cannot_delete_guest' => 'Non puoi eliminare l\'utente ospite', // Roles 'role_cannot_be_edited' => 'Questo ruolo non può essere modificato', 'role_system_cannot_be_deleted' => 'Questo ruolo è di sistema e non può essere eliminato', 'role_registration_default_cannot_delete' => 'Questo ruolo non può essere eliminato finchè è impostato come default alla registrazione', + 'role_cannot_remove_only_admin' => 'Questo utente è l\'unico con assegnato il ruolo di amministratore. Assegna il ruolo di amministratore ad un altro utente prima di rimuoverlo qui.', // Comments 'comment_list' => 'C\'è stato un errore scaricando i commenti.', @@ -79,4 +87,13 @@ return [ 'error_occurred' => 'C\'è Stato un errore', 'app_down' => ':appName è offline', 'back_soon' => 'Ritornerà presto.', -]; \ No newline at end of file + + // 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', + +]; diff --git a/resources/lang/it/pagination.php b/resources/lang/it/pagination.php index e3c561423..1fba272fd 100755 --- a/resources/lang/it/pagination.php +++ b/resources/lang/it/pagination.php @@ -1,18 +1,11 @@ '« Precedente', 'next' => 'Successivo »', diff --git a/resources/lang/it/passwords.php b/resources/lang/it/passwords.php index a584aa333..0f95a3e06 100755 --- a/resources/lang/it/passwords.php +++ b/resources/lang/it/passwords.php @@ -1,18 +1,11 @@ 'La password deve avere almeno sei caratteri e corrispondere alla conferma.', 'user' => "Non possiamo trovare un utente per quella mail.", 'token' => 'Questo token per reimpostare la password non è valido.', diff --git a/resources/lang/it/settings.php b/resources/lang/it/settings.php index d14dbfb72..3a1779f95 100755 --- a/resources/lang/it/settings.php +++ b/resources/lang/it/settings.php @@ -1,59 +1,87 @@ 'Impostazioni', 'settings_save' => 'Salva Impostazioni', 'settings_save_success' => 'Impostazioni salvate', - /** - * App settings - */ - - 'app_settings' => 'Impostazioni App', + // App Settings + 'app_customization' => 'Personalizzazione', + 'app_features_security' => 'Funzioni & Sicurezza', 'app_name' => 'Nome applicazione', 'app_name_desc' => 'Questo nome è mostrato nell\'header e in tutte le mail.', 'app_name_header' => 'Mostrare il nome nell\'header', + 'app_public_access' => 'Accesso Pubblico', + 'app_public_access_desc' => 'Abilitando questa opzione, i visitatori, che non sono loggati, potranno accedere ai contenuti nella tua istanza BookStack.', + 'app_public_access_desc_guest' => 'L\'accesso ai visitatori pubblici può essere controllato attraverso l\'utente "Guest".', + 'app_public_access_toggle' => 'Permetti accesso pubblico', 'app_public_viewing' => 'Consentire la visione pubblica?', 'app_secure_images' => 'Abilitare una sicurezza maggiore per le immagini caricate?', + 'app_secure_images_toggle' => 'Abilita sicurezza aggiuntiva negli upload delle immagini', 'app_secure_images_desc' => 'Per una ragione di prestazioni, tutte le immagini sono pubbliche. Questa opzione aaggiunge una stringa, difficile da indovinare, random negli url delle immagini. Assicurati che il listing delle cartelle non sia abilitato per prevenire un accesso semplice.', 'app_editor' => 'Editor pagine', 'app_editor_desc' => 'Seleziona quale editor verrà usato da tutti gli utenti per modificare le pagine.', 'app_custom_html' => 'Contenuto Head HTML Custom', 'app_custom_html_desc' => 'Qualsiasi contenuto aggiunto qui verrà inserito alla fine della sezione di tutte le pagine. Questo è utile per sovrascrivere lo stile o aggiungere il codice per gli analytics.', + 'app_custom_html_disabled_notice' => 'Il contenuto HTML personalizzato è disabilitato su questa pagina impostazioni per garantire che eventuali modifiche possano essere ripristinate.', 'app_logo' => 'Logo applicazione', 'app_logo_desc' => 'Questa immagine dovrebbe essere 43px in altezza.
Immagini più grandi verranno scalate.', 'app_primary_color' => 'Colore primario applicazione', 'app_primary_color_desc' => 'Deve essere un valore hex.
Lascia vuoto per reimpostare il colore di default.', '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_default' => 'Homepage di default scelta', + 'app_homepage_select' => 'Seleziona una pagina', '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. ', - /** - * Registration settings - */ + // Color settings + 'content_colors' => 'Colori del contenuto', + 'content_colors_desc' => 'Imposta i colori per tutti gli elementi nella gerarchia della pagina. È raccomandato scegliere colori con una luminosità simile a quelli di default per una maggiore leggibilità.', + 'bookshelf_color' => 'Colore delle libreria', + 'book_color' => 'Colore del libro', + 'chapter_color' => 'Colore del capitolo', + 'page_color' => 'Colore della Pagina', + 'page_draft_color' => 'Colore della bozza', + // Registration Settings 'reg_settings' => 'Impostazioni Registrazione', - 'reg_allow' => 'Consentire Registrazione?', + 'reg_enable' => 'Abilita Registrazione', + 'reg_enable_toggle' => 'Abilita registrazione', + 'reg_enable_desc' => 'Quando la registrazione è abilitata, l\utente sarà in grado di registrarsi all\'applicazione. Al momento della registrazione gli verrà associato un ruolo utente predefinito.', 'reg_default_role' => 'Ruolo predefinito dopo la registrazione', - 'reg_confirm_email' => 'Richiedere la conferma della mail?', + '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' => 'Conferma Email', + 'reg_email_confirmation_toggle' => 'Richiedi conferma email', 'reg_confirm_email_desc' => 'Se la restrizione per dominio è usata la conferma della mail sarà richiesta e la scelta ignorata.', 'reg_confirm_restrict_domain' => 'Restringi la registrazione al dominio', - 'reg_confirm_restrict_domain_desc' => "Inserisci una lista separata da virgola di domini di email a cui vorresti restringere la registrazione. Agli utenti verrà inviata una mail per confermare il loro indirizzo prima che possano interagire con l'applicazione.
Nota che gli utenti saranno in grado di cambiare il loro indirizzo dopo aver completato la registrazione.", + 'reg_confirm_restrict_domain_desc' => 'Inserisci una lista separata da virgola di domini di email a cui vorresti restringere la registrazione. Agli utenti verrà inviata una mail per confermare il loro indirizzo prima che possano interagire con l\'applicazione.
Nota che gli utenti saranno in grado di cambiare il loro indirizzo dopo aver completato la registrazione.', 'reg_confirm_restrict_domain_placeholder' => 'Nessuna restrizione impostata', - /** - * Role settings - */ + // Maintenance settings + 'maint' => 'Manutenzione', + 'maint_image_cleanup' => 'Pulizia Immagini', + 'maint_image_cleanup_desc' => "Esegue la scansione del contenuto delle pagine e delle revisioni per verificare quali immagini e disegni sono attualmente in uso e quali immagini sono ridondanti. Assicurati di creare backup completo del database e delle immagini prima di eseguire la pulizia.", + 'maint_image_cleanup_ignore_revisions' => 'Ignora le immagini nelle revisioni', + 'maint_image_cleanup_run' => 'Esegui Pulizia', + 'maint_image_cleanup_warning' => ':count immagini potenzialmente inutilizzate sono state trovate. Sei sicuro di voler eliminare queste immagini?', + 'maint_image_cleanup_success' => ':count immagini potenzialmente inutilizzate trovate e eliminate!', + 'maint_image_cleanup_nothing_found' => 'Nessuna immagine non utilizzata trovata, Nulla è stato cancellato!', + 'maint_send_test_email' => 'Invia un Email di Test', + 'maint_send_test_email_desc' => 'Questo invia un\'email di prova al tuo indirizzo email specificato nel tuo profilo.', + 'maint_send_test_email_run' => 'Invia email di test', + 'maint_send_test_email_success' => 'Email inviata a :address', + 'maint_send_test_email_mail_subject' => 'Email di Test', + 'maint_send_test_email_mail_greeting' => 'L\'invio delle email sembra funzionare!', + 'maint_send_test_email_mail_text' => 'Congratulazioni! Siccome hai ricevuto questa notifica email, le tue impostazioni sembrano essere configurate correttamente.', + // Role Settings 'roles' => 'Ruoli', 'role_user_roles' => 'Ruoli Utente', 'role_create' => 'Crea Nuovo Ruolo', @@ -68,36 +96,46 @@ return [ 'role_details' => 'Dettagli Ruolo', 'role_name' => 'Nome Ruolo', 'role_desc' => 'Breve Descrizione del Ruolo', + 'role_external_auth_id' => 'ID Autenticazione Esterna', 'role_system' => 'Permessi di Sistema', 'role_manage_users' => 'Gestire gli utenti', 'role_manage_roles' => 'Gestire ruoli e permessi di essi', 'role_manage_entity_permissions' => 'Gestire tutti i permessi di libri, capitoli e pagine', 'role_manage_own_entity_permissions' => 'Gestire i permessi sui propri libri, capitoli e pagine', + 'role_manage_page_templates' => 'Gestisci template pagine', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Gestire impostazioni app', 'role_asset' => 'Permessi Entità', - 'role_asset_desc' => "Questi permessi controllano l'accesso di default alle entità. I permessi nei Libri, Capitoli e Pagine sovrascriveranno questi.", + 'role_asset_desc' => 'Questi permessi controllano l\'accesso di default alle entità. I permessi nei Libri, Capitoli e Pagine sovrascriveranno questi.', + 'role_asset_admins' => 'Gli amministratori hanno automaticamente accesso a tutti i contenuti ma queste opzioni possono mostrare o nascondere le opzioni della UI.', 'role_all' => 'Tutti', 'role_own' => 'Propri', - 'role_controlled_by_asset' => "Controllato dall'entità in cui sono caricati", + 'role_controlled_by_asset' => 'Controllato dall\'entità in cui sono caricati', 'role_save' => 'Salva Ruolo', 'role_update_success' => 'Ruolo aggiornato correttamente', 'role_users' => 'Utenti in questo ruolo', 'role_users_none' => 'Nessun utente assegnato a questo ruolo', - /** - * Users - */ - + // Users 'users' => 'Utenti', 'user_profile' => 'Profilo Utente', 'users_add_new' => 'Aggiungi Nuovo Utente', 'users_search' => 'Cerca Utenti', + 'users_details' => 'Dettagli Utente', + 'users_details_desc' => 'Imposta un nome e un indirizzo email per questo utente. L\'indirizzo email verrà utilizzato per accedere all\'applicazione.', + 'users_details_desc_no_email' => 'Imposta un nome per questo utente così gli altri possono riconoscerlo.', 'users_role' => 'Ruoli Utente', + 'users_role_desc' => 'Seleziona a quali ruoli verrà assegnato questo utente. Se un utente è assegnato a più ruoli riceverà tutte le abilità dei ruoli assegnati.', + 'users_password' => 'Password Utente', + 'users_password_desc' => 'Imposta una password utilizzata per accedere all\'applicazione. Deve essere lunga almeno 6 caratteri.', + 'users_send_invite_text' => 'Puoi scegliere di inviare a questo utente un\'email di invito che permette loro di impostare la propria password altrimenti puoi impostare la password tu stesso.', + 'users_send_invite_option' => 'Invia email di invito', 'users_external_auth_id' => 'ID Autenticazioni Esterna', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Riempi solo se desideri cambiare la tua password:', 'users_system_public' => 'Questo utente rappresente qualsiasi ospite che visita il sito. Non può essere usato per effettuare il login ma è assegnato automaticamente.', 'users_delete' => 'Elimina Utente', - 'users_delete_named' => "Elimina l'utente :userName", + 'users_delete_named' => 'Elimina l\'utente :userName', 'users_delete_warning' => 'Questo eliminerà completamente l\'utente \':userName\' dal sistema.', 'users_delete_confirm' => 'Sei sicuro di voler eliminare questo utente?', 'users_delete_success' => 'Utenti rimossi correttamente', @@ -105,12 +143,69 @@ return [ 'users_edit_profile' => 'Modifica Profilo', 'users_edit_success' => 'Utente aggiornato correttamente', 'users_avatar' => 'Avatar Utente', - 'users_avatar_desc' => "Quest'immagine dovrebbe essere approssimativamente 256px quadrata.", + 'users_avatar_desc' => 'Quest\'immagine dovrebbe essere approssimativamente 256px quadrata.', 'users_preferred_language' => 'Lingua Preferita', + 'users_preferred_language_desc' => 'Questa opzione cambierà la lingua utilizzata per l\'interfaccia utente dell\'applicazione. Questo non influirà su alcun contenuto creato dall\'utente.', 'users_social_accounts' => 'Account Social', 'users_social_accounts_info' => 'Qui puoi connettere gli altri account per un accesso più veloce e semplice. Disconnettere un account qui non rimuoverà le altre sessioni. Revoca l\'accesso dal tuo profilo negli account social connessi.', 'users_social_connect' => 'Connetti Account', 'users_social_disconnect' => 'Disconnetti Account', 'users_social_connected' => 'L\'account :socialAccount è stato connesso correttamente al tuo profilo.', 'users_social_disconnected' => 'L\'account :socialAccount è stato disconnesso correttamente dal tuo profilo.', + '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' => 'العربية', + 'da' => 'Dansk', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// ]; diff --git a/resources/lang/it/validation.php b/resources/lang/it/validation.php index 832480d4c..3b85303d2 100755 --- a/resources/lang/it/validation.php +++ b/resources/lang/it/validation.php @@ -1,18 +1,13 @@ ':attribute deve essere accettato.', 'active_url' => ':attribute non è uno URL valido.', 'after' => ':attribute deve essere una data dopo il :date.', @@ -35,12 +30,41 @@ return [ 'digits' => 'Il campo :attribute deve essere di :digits numeri.', 'digits_between' => 'Il campo :attribute deve essere tra i numeri :min e :max.', 'email' => 'Il campo :attribute deve essere un indirizzo email valido.', + 'ends_with' => ':attribute deve terminare con uno dei seguenti: :values', 'filled' => 'Il campo :attribute field is required.', + 'gt' => [ + 'numeric' => ':attribute deve essere maggiore di :value.', + 'file' => ':attribute deve essere maggiore di :value kilobytes.', + 'string' => ':attribute deve essere maggiore di :value caratteri.', + 'array' => ':attribute deve avere più di :value elementi.', + ], + 'gte' => [ + 'numeric' => ':attribute deve essere maggiore o uguale a :value.', + 'file' => ':attribute deve essere maggiore o uguale a :value kilobytes.', + 'string' => ':attribute deve essere maggiore o uguale a :value caratteri.', + 'array' => ':attribute deve avere :value elementi o più.', + ], 'exists' => 'Il campo :attribute non è valido.', 'image' => 'Il campo :attribute deve essere un\'immagine.', + 'image_extension' => ':attribute deve avere un\'estensione immagine valida e supportata.', 'in' => 'Il campo :attribute selezionato non è valido.', 'integer' => 'Il campo :attribute deve essere un intero.', 'ip' => 'Il campo :attribute deve essere un indirizzo IP valido.', + 'ipv4' => ':attribute deve essere un indirizzo IPv4 valido.', + 'ipv6' => ':attribute deve essere un indirizzo IPv6 valido.', + 'json' => ':attribute deve essere una stringa JSON valida.', + 'lt' => [ + 'numeric' => ':attribute deve essere inferiore a :value.', + 'file' => ':attribute deve essere inferiore a :value kilobytes.', + 'string' => ':attribute deve essere inferiore a :value caratteri.', + 'array' => ':attribute deve avere meno di :value elementi.', + ], + 'lte' => [ + 'numeric' => ':attribute deve essere minore o uguale :value.', + 'file' => ':attribute deve essere minore o uguale a :value kilobytes.', + 'string' => ':attribute deve essere minore o uguale a :value caratteri.', + 'array' => ':attribute non deve avere più di :value elementi.', + ], 'max' => [ 'numeric' => 'Il campo :attribute non deve essere maggiore di :max.', 'file' => 'Il campo :attribute non deve essere maggiore di :max kilobytes.', @@ -54,7 +78,9 @@ 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.', 'regex' => 'Il formato di :attribute non è valido.', 'required' => 'Il campo :attribute è richiesto.', @@ -74,35 +100,15 @@ return [ 'timezone' => ':attribute deve essere una zona valida.', 'unique' => ':attribute è già preso.', 'url' => 'Il formato :attribute non è valido.', + 'uploaded' => 'Il file non può essere caricato. Il server potrebbe non accettare file di questa dimensione.', - /* - |-------------------------------------------------------------------------- - | Custom Validation Language Lines - |-------------------------------------------------------------------------- - | - | Here you may specify custom validation messages for attributes using the - | convention "attribute.rule" to name the lines. This makes it quick to - | specify a specific custom language line for a given attribute rule. - | - */ - + // Custom validation lines 'custom' => [ 'password-confirm' => [ 'required_with' => 'Conferma della password richiesta', ], ], - /* - |-------------------------------------------------------------------------- - | Custom Validation Attributes - |-------------------------------------------------------------------------- - | - | The following language lines are used to swap attribute place-holders - | with something more reader friendly such as E-Mail Address instead - | of "email". This simply helps us make messages a little cleaner. - | - */ - + // Custom validation attributes 'attributes' => [], - ]; diff --git a/resources/lang/ja/activities.php b/resources/lang/ja/activities.php index b907e0c63..de1ca1ac6 100644 --- a/resources/lang/ja/activities.php +++ b/resources/lang/ja/activities.php @@ -1,12 +1,10 @@ 'がページを作成:', 'page_create_notification' => 'ページを作成しました', @@ -37,4 +35,14 @@ return [ 'book_sort' => 'がブックの並び順を変更:', 'book_sort_notification' => '並び順を変更しました', + // 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', + + // Other + 'commented_on' => 'commented on', ]; diff --git a/resources/lang/ja/auth.php b/resources/lang/ja/auth.php index 4d5aee8b3..d0db7d080 100644 --- a/resources/lang/ja/auth.php +++ b/resources/lang/ja/auth.php @@ -1,21 +1,15 @@ 'この資格情報は登録されていません。', 'throttle' => 'ログイン試行回数が制限を超えました。:seconds秒後に再試行してください。', - /** - * Login & Register - */ + // Login & Register 'sign_up' => '新規登録', 'log_in' => 'ログイン', 'log_in_with' => ':socialDriverでログイン', @@ -27,11 +21,13 @@ return [ 'email' => 'メールアドレス', 'password' => 'パスワード', 'password_confirm' => 'パスワード (確認)', - 'password_hint' => '5文字以上である必要があります', + 'password_hint' => '7文字以上である必要があります', 'forgot_password' => 'パスワードをお忘れですか?', 'remember_me' => 'ログイン情報を保存する', 'ldap_email_hint' => 'このアカウントで使用するEメールアドレスを入力してください。', 'create_account' => 'アカウント作成', + 'already_have_account' => 'Already have an account?', + 'dont_have_account' => 'Don\'t have an account?', 'social_login' => 'SNSログイン', 'social_registration' => 'SNS登録', 'social_registration_text' => '他のサービスで登録 / ログインする', @@ -43,23 +39,18 @@ return [ 'register_success' => '登録が完了し、ログインできるようになりました!', - /** - * Password Reset - */ + // Password Reset 'reset_password' => 'パスワードリセット', 'reset_password_send_instructions' => '以下にEメールアドレスを入力すると、パスワードリセットリンクが記載されたメールが送信されます。', 'reset_password_send_button' => 'リセットリンクを送信', 'reset_password_sent_success' => ':emailへリセットリンクを送信しました。', 'reset_password_success' => 'パスワードがリセットされました。', - 'email_reset_subject' => ':appNameのパスワードをリセット', 'email_reset_text' => 'このメールは、パスワードリセットがリクエストされたため送信されています。', 'email_reset_not_requested' => 'もしパスワードリセットを希望しない場合、操作は不要です。', - /** - * Email Confirmation - */ + // Email Confirmation 'email_confirm_subject' => ':appNameのメールアドレス確認', 'email_confirm_greeting' => ':appNameへ登録してくださりありがとうございます!', 'email_confirm_text' => '以下のボタンを押し、メールアドレスを確認してください:', @@ -73,4 +64,14 @@ return [ 'email_not_confirmed_click_link' => '登録時に受信したメールを確認し、確認リンクをクリックしてください。', 'email_not_confirmed_resend' => 'Eメールが見つからない場合、以下のフォームから再送信してください。', 'email_not_confirmed_resend_button' => '確認メールを再送信', -]; + + // 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!' +]; \ No newline at end of file diff --git a/resources/lang/ja/common.php b/resources/lang/ja/common.php index e7b7b4a57..2a142e55f 100644 --- a/resources/lang/ja/common.php +++ b/resources/lang/ja/common.php @@ -1,64 +1,77 @@ 'キャンセル', 'confirm' => '確認', 'back' => '戻る', 'save' => '保存', 'continue' => '続ける', 'select' => '選択', + 'toggle_all' => 'Toggle All', 'more' => 'その他', - /** - * Form Labels - */ + // Form Labels 'name' => '名称', 'description' => '概要', 'role' => '権限', + 'cover_image' => 'Cover image', 'cover_image_description' => 'この画像は約 300x170px をする必要があります。', - /** - * Actions - */ + + // Actions 'actions' => '実行', 'view' => '表示', - 'reply' => '返信', + 'view_all' => 'View All', 'create' => '作成', 'update' => '更新', 'edit' => '編集', 'sort' => '並び順', 'move' => '移動', + 'copy' => 'Copy', + 'reply' => '返信', 'delete' => '削除', 'search' => '検索', 'search_clear' => '検索をクリア', 'reset' => 'リセット', 'remove' => '削除', 'add' => '追加', + 'fullscreen' => 'Fullscreen', + // 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', - /** - * Misc - */ + // Misc 'deleted_user' => '削除済みユーザ', 'no_activity' => '表示するアクティビティがありません', 'no_items' => 'アイテムはありません', 'back_to_top' => '上に戻る', 'toggle_details' => '概要の表示切替', + 'toggle_thumbnails' => 'Toggle Thumbnails', 'details' => '詳細', 'grid_view' => 'グリッド形式', 'list_view' => 'リスト形式', + 'default' => 'Default', + 'breadcrumb' => 'Breadcrumb', - /** - * Header - */ + // Header + 'profile_menu' => 'Profile Menu', 'view_profile' => 'プロフィール表示', 'edit_profile' => 'プロフィール編集', - /** - * Email Content - */ + // Layout tabs + 'tab_info' => 'Info', + 'tab_content' => 'Content', + + // Email Content 'email_action_help' => '":actionText" をクリックできない場合、以下のURLをコピーしブラウザで開いてください:', 'email_rights' => 'All rights reserved', ]; diff --git a/resources/lang/ja/components.php b/resources/lang/ja/components.php index 53a9cda1b..65e8a7a79 100644 --- a/resources/lang/ja/components.php +++ b/resources/lang/ja/components.php @@ -1,9 +1,10 @@ '画像を選択', 'image_all' => 'すべて', 'image_all_title' => '全ての画像を表示', @@ -22,12 +23,11 @@ return [ 'image_upload_success' => '画像がアップロードされました', 'image_update_success' => '画像が更新されました', 'image_delete_success' => '画像が削除されました', + 'image_upload_remove' => 'Remove', - /** - * Code editor - */ + // Code Editor 'code_editor' => 'プログラムブロック編集', 'code_language' => 'プログラミング言語の選択', 'code_content' => 'プログラム内容', - 'code_save' => 'プログラムを保存' + 'code_save' => 'プログラムを保存', ]; diff --git a/resources/lang/ja/entities.php b/resources/lang/ja/entities.php index f177154f4..4f1a855ff 100644 --- a/resources/lang/ja/entities.php +++ b/resources/lang/ja/entities.php @@ -1,14 +1,17 @@ '最近作成', 'recently_created_pages' => '最近作成されたページ', 'recently_updated_pages' => '最近更新されたページ', 'recently_created_chapters' => '最近作成されたチャプター', 'recently_created_books' => '最近作成されたブック', + 'recently_created_shelves' => 'Recently Created Shelves', 'recently_update' => '最近更新', 'recently_viewed' => '閲覧履歴', 'recent_activity' => 'アクティビティ', @@ -19,7 +22,6 @@ return [ 'meta_created_name' => '作成: :timeLength (:user)', 'meta_updated' => '更新: :timeLength', 'meta_updated_name' => '更新: :timeLength (:user)', - 'x_pages' => ':count ページ', 'entity_select' => 'エンティティ選択', 'images' => '画像', 'my_recent_drafts' => '最近の下書き', @@ -32,17 +34,13 @@ return [ 'export_pdf' => 'PDF', 'export_text' => 'テキストファイル', - /** - * Permissions and restrictions - */ + // Permissions and restrictions 'permissions' => '権限', 'permissions_intro' => 'この設定は各ユーザの役割よりも優先して適用されます。', 'permissions_enable' => 'カスタム権限設定を有効にする', 'permissions_save' => '権限を保存', - /** - * Search - */ + // Search 'search_results' => '検索結果', 'search_total_results_found' => ':count件見つかりました', 'search_clear' => '検索をクリア', @@ -53,11 +51,13 @@ return [ 'search_content_type' => '種類', 'search_exact_matches' => '完全一致', 'search_tags' => 'タグ検索', + 'search_options' => 'Options', 'search_viewed_by_me' => '自分が閲覧したことがある', 'search_not_viewed_by_me' => '自分が閲覧したことがない', 'search_permissions_set' => '権限が設定されている', 'search_created_by_me' => '自分が作成した', 'search_updated_by_me' => '自分が更新した', + 'search_date_options' => 'Date Options', 'search_updated_before' => '以前に更新', 'search_updated_after' => '以降に更新', 'search_created_before' => '以前に作成', @@ -65,17 +65,49 @@ return [ 'search_set_date' => '日付を設定', 'search_update' => 'フィルタを更新', - /** - * Books - */ + // 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', + + // Books 'book' => 'Book', 'books' => 'ブック', + 'x_books' => ':count ブック', 'books_empty' => 'まだブックは作成されていません', 'books_popular' => '人気のブック', - 'x_books' => ':count ブック', 'books_recent' => '最近のブック', 'books_new' => '新しいブック', + 'books_new_action' => 'New Book', 'books_popular_empty' => 'ここに人気のブックが表示されます。', + 'books_new_empty' => 'The most recently created books will appear here.', 'books_create' => '新しいブックを作成', 'books_delete' => 'ブックを削除', 'books_delete_named' => 'ブック「:bookName」を削除', @@ -89,7 +121,6 @@ return [ 'books_permissions_updated' => 'ブックの権限を更新しました', 'books_empty_contents' => 'まだページまたはチャプターが作成されていません。', 'books_empty_create_page' => '新しいページを作成', - 'books_empty_or' => 'または', 'books_empty_sort_current_book' => 'ブックの並び順を変更', 'books_empty_add_chapter' => 'チャプターを追加', 'books_permissions_active' => 'ブックの権限は有効です', @@ -97,16 +128,19 @@ return [ 'books_navigation' => '目次', 'books_sort' => '並び順を変更', 'books_sort_named' => 'ブック「: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' => '他のブックを表示', 'books_sort_save' => '並び順を保存', - /** - * Chapters - */ + // Chapters 'chapter' => 'チャプター', 'chapters' => 'チャプター', - 'chapters_popular' => '人気のチャプター', 'x_chapters' => ':count チャプター', + 'chapters_popular' => '人気のチャプター', 'chapters_new' => 'チャプターを作成', 'chapters_create' => 'チャプターを作成', 'chapters_delete' => 'チャプターを削除', @@ -125,11 +159,10 @@ return [ 'chapters_permissions_success' => 'チャプターの権限を更新しました', 'chapters_search_this' => 'このチャプターを検索', - /** - * Pages - */ + // Pages 'page' => 'ページ', 'pages' => 'ページ', + 'x_pages' => ':count ページ', 'pages_popular' => '人気のページ', 'pages_new' => 'ページを作成', 'pages_attachments' => '添付', @@ -143,7 +176,7 @@ return [ 'pages_delete_confirm' => 'このページを削除してもよろしいですか?', 'pages_delete_draft_confirm' => 'このページの下書きを削除してもよろしいですか?', 'pages_editing_named' => 'ページ :pageName を編集', - 'pages_edit_toggle_header' => 'ヘッダーの表示切替', + 'pages_edit_draft_options' => 'Draft Options', 'pages_edit_save_draft' => '下書きを保存', 'pages_edit_draft' => 'ページの下書きを編集', 'pages_editing_draft' => '下書きを編集中', @@ -161,17 +194,24 @@ return [ 'pages_md_preview' => 'プレビュー', 'pages_md_insert_image' => '画像を挿入', 'pages_md_insert_link' => 'エンティティへのリンクを挿入', + 'pages_md_insert_drawing' => 'Insert Drawing', 'pages_not_in_chapter' => 'チャプターが設定されていません', 'pages_move' => 'ページを移動', 'pages_move_success' => 'ページを ":parentName" へ移動しました', + 'pages_copy' => 'Copy Page', + 'pages_copy_desination' => 'Copy Destination', + 'pages_copy_success' => 'Page successfully copied', 'pages_permissions' => 'ページの権限設定', 'pages_permissions_success' => 'ページの権限を更新しました', + 'pages_revision' => 'Revision', 'pages_revisions' => '編集履歴', 'pages_revisions_named' => ':pageName のリビジョン', 'pages_revision_named' => ':pageName のリビジョン', 'pages_revisions_created_by' => '作成者', 'pages_revisions_date' => '日付', 'pages_revisions_number' => 'リビジョン', + 'pages_revisions_numbered' => 'Revision #:id', + 'pages_revisions_numbered_changes' => 'Revision #:id Changes', 'pages_revisions_changelog' => '説明', 'pages_revisions_changes' => '変更点', 'pages_revisions_current' => '現在のバージョン', @@ -193,16 +233,21 @@ return [ 'message' => ':start :time. 他のユーザによる更新を上書きしないよう注意してください。', ], 'pages_draft_discarded' => '下書きが破棄されました。エディタは現在の内容へ復元されています。', + 'pages_specific' => 'Specific Page', + 'pages_is_template' => 'Page Template', - /** - * Editor sidebar - */ + // Editor Sidebar 'page_tags' => 'タグ', + 'chapter_tags' => 'Chapter Tags', + 'book_tags' => 'Book Tags', + 'shelf_tags' => 'Shelf Tags', 'tag' => 'タグ', - 'tags' => '', + 'tags' => 'Tags', + 'tag_name' => 'Tag Name', 'tag_value' => '内容 (オプション)', 'tags_explain' => "タグを設定すると、コンテンツの管理が容易になります。\nより高度な管理をしたい場合、タグに内容を設定できます。", 'tags_add' => 'タグを追加', + 'tags_remove' => 'Remove this tag', 'attachments' => '添付ファイル', 'attachments_explain' => 'ファイルをアップロードまたはリンクを添付することができます。これらはサイドバーで確認できます。', 'attachments_explain_instant_save' => 'この変更は即座に保存されます。', @@ -228,19 +273,22 @@ return [ 'attachments_file_uploaded' => 'ファイルがアップロードされました', 'attachments_file_updated' => 'ファイルが更新されました', 'attachments_link_attached' => 'リンクがページへ添付されました', + '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 View 'profile_user_for_x' => ':time前に作成', 'profile_created_content' => '作成したコンテンツ', 'profile_not_created_pages' => ':userNameはページを作成していません', 'profile_not_created_chapters' => ':userNameはチャプターを作成していません', 'profile_not_created_books' => ':userNameはブックを作成していません', + 'profile_not_created_shelves' => ':userName has not created any shelves', - /** - * Comments - */ + // Comments 'comment' => 'コメント', 'comments' => 'コメント', 'comment_add' => 'コメント追加', @@ -258,10 +306,9 @@ return [ 'comment_delete_confirm' => '本当にこのコメントを削除しますか?', 'comment_in_reply_to' => ':commentIdへ返信', - /** - * Revision - */ + // Revision 'revision_delete_confirm' => 'このリビジョンを削除しますか?', + 'revision_restore_confirm' => 'Are you sure you want to restore this revision? The current page contents will be replaced.', 'revision_delete_success' => 'リビジョンを削除しました', 'revision_cannot_delete_latest' => '最新のリビジョンを削除できません。' -]; +]; \ No newline at end of file diff --git a/resources/lang/ja/errors.php b/resources/lang/ja/errors.php index 8c13d4474..cd0dd777c 100644 --- a/resources/lang/ja/errors.php +++ b/resources/lang/ja/errors.php @@ -1,11 +1,9 @@ 'リクエストされたページへの権限がありません。', 'permissionJson' => '要求されたアクションを実行する権限がありません。', @@ -15,11 +13,18 @@ return [ 'email_already_confirmed' => 'Eメールは既に確認済みです。ログインしてください。', 'email_confirmation_invalid' => 'この確認トークンは無効か、または既に使用済みです。登録を再試行してください。', 'email_confirmation_expired' => '確認トークンは有効期限切れです。確認メールを再送しました。', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => '匿名バインドを用いたLDAPアクセスに失敗しました', 'ldap_fail_authed' => '識別名, パスワードを用いたLDAPアクセスに失敗しました', 'ldap_extension_not_installed' => 'LDAP PHP extensionがインストールされていません', 'ldap_cannot_connect' => 'LDAPサーバに接続できませんでした', + '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' => 'アクションが定義されていません', + 'social_login_bad_response' => "Error received during :socialAccount login: \n:error", 'social_account_in_use' => ':socialAccountアカウントは既に使用されています。:socialAccountのオプションからログインを試行してください。', 'social_account_email_in_use' => ':emailは既に使用されています。ログイン後、プロフィール設定から:socialAccountアカウントを接続できます。', 'social_account_existing' => 'アカウント:socialAccountは既にあなたのプロフィールに接続されています。', @@ -28,23 +33,29 @@ return [ 'social_account_register_instructions' => 'まだアカウントをお持ちでない場合、:socialAccountオプションから登録できます。', 'social_driver_not_found' => 'Social driverが見つかりません。', 'social_driver_not_configured' => 'あなたの:socialAccount設定は正しく構成されていません。', + 'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.', // System 'path_not_writable' => 'ファイルパス :filePath へアップロードできませんでした。サーバ上での書き込みを許可してください。', 'cannot_get_image_from_url' => ':url から画像を取得できませんでした。', 'cannot_create_thumbs' => 'このサーバはサムネイルを作成できません。GD PHP extensionがインストールされていることを確認してください。', 'server_upload_limit' => 'このサイズの画像をアップロードすることは許可されていません。ファイルサイズを小さくし、再試行してください。', + 'uploaded' => 'The server does not allow uploads of this size. Please try a smaller file size.', 'image_upload_error' => '画像アップロード時にエラーが発生しました。', + 'image_upload_type_error' => 'The image type being uploaded is invalid', 'file_upload_timeout' => 'ファイルのアップロードがタイムアウトしました。', // Attachments 'attachment_page_mismatch' => '添付を更新するページが一致しません', + 'attachment_not_found' => 'Attachment not found', // Pages 'page_draft_autosave_fail' => '下書きの保存に失敗しました。インターネットへ接続してください。', + 'page_custom_home_deletion' => 'Cannot delete a page while it is set as a homepage', // Entities 'entity_not_found' => 'エンティティが見つかりません', + 'bookshelf_not_found' => 'Bookshelf not found', 'book_not_found' => 'ブックが見つかりません', 'page_not_found' => 'ページが見つかりません', 'chapter_not_found' => 'チャプターが見つかりません', @@ -60,6 +71,14 @@ return [ 'role_cannot_be_edited' => 'この役割は編集できません', 'role_system_cannot_be_deleted' => 'この役割はシステムで管理されているため、削除できません', 'role_registration_default_cannot_delete' => 'この役割を登録時のデフォルトに設定することはできません', + '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.', + + // 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.', // Error pages '404_page_not_found' => 'ページが見つかりません', @@ -68,4 +87,13 @@ return [ 'error_occurred' => 'エラーが発生しました', 'app_down' => ':appNameは現在停止しています', 'back_soon' => '回復までしばらくお待ちください。', + + // 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', + ]; diff --git a/resources/lang/ja/pagination.php b/resources/lang/ja/pagination.php index 1ebcef722..725ec6b41 100644 --- a/resources/lang/ja/pagination.php +++ b/resources/lang/ja/pagination.php @@ -1,18 +1,11 @@ '« 前', 'next' => '次 »', diff --git a/resources/lang/ja/passwords.php b/resources/lang/ja/passwords.php index 17c82e299..3531c73c7 100644 --- a/resources/lang/ja/passwords.php +++ b/resources/lang/ja/passwords.php @@ -1,18 +1,11 @@ 'パスワードは6文字以上である必要があります。', 'user' => "このEメールアドレスに一致するユーザが見つかりませんでした。", 'token' => 'このパスワードリセットトークンは無効です。', diff --git a/resources/lang/ja/settings.php b/resources/lang/ja/settings.php index f9c9c5e86..5b1f31a05 100644 --- a/resources/lang/ja/settings.php +++ b/resources/lang/ja/settings.php @@ -1,56 +1,87 @@ '設定', 'settings_save' => '設定を保存', 'settings_save_success' => '設定を保存しました', - /** - * App settings - */ - - 'app_settings' => 'アプリケーション設定', + // App Settings + 'app_customization' => 'Customization', + 'app_features_security' => 'Features & Security', 'app_name' => 'アプリケーション名', 'app_name_desc' => 'この名前はヘッダーやEメール内で表示されます。', 'app_name_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' => 'アプリケーションを公開する', 'app_secure_images' => '画像アップロード時のセキュリティを強化', + 'app_secure_images_toggle' => 'Enable higher security image uploads', 'app_secure_images_desc' => 'パフォーマンスの観点から、全ての画像が公開になっています。このオプションを有効にすると、画像URLの先頭にランダムで推測困難な文字列が追加され、アクセスを困難にします。', 'app_editor' => 'ページエディタ', 'app_editor_desc' => 'ここで選択されたエディタを全ユーザが使用します。', 'app_custom_html' => 'カスタムheadタグ', 'app_custom_html_desc' => 'スタイルシートやアナリティクスコード追加したい場合、ここを編集します。これはの最下部に挿入されます。', + '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' => 'ロゴ', 'app_logo_desc' => '高さ43pxで表示されます。これを上回る場合、自動で縮小されます。', 'app_primary_color' => 'プライマリカラー', 'app_primary_color_desc' => '16進数カラーコードで入力します。空にした場合、デフォルトの色にリセットされます。', + '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' => 'コメントを無効にする', + 'app_disable_comments_toggle' => 'Disable comments', 'app_disable_comments_desc' => 'アプリケーション内のすべてのページのコメントを無効にします。既存のコメントは表示されません。', - /** - * Registration settings - */ + // 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' => '登録設定', - 'reg_allow' => '新規登録を許可', + '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' => '新規登録時のデフォルト役割', - 'reg_confirm_email' => 'Eメール認証を必須にする', + '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' => 'ドメイン制限を有効にしている場合はEメール認証が必須となり、この項目は無視されます。', 'reg_confirm_restrict_domain' => 'ドメイン制限', 'reg_confirm_restrict_domain_desc' => '特定のドメインのみ登録できるようにする場合、以下にカンマ区切りで入力します。設定された場合、Eメール認証が必須になります。
登録後、ユーザは自由にEメールアドレスを変更できます。', 'reg_confirm_restrict_domain_placeholder' => '制限しない', - /** - * Role settings - */ + // 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.', + // Role Settings 'roles' => '役割', 'role_user_roles' => '役割', 'role_create' => '役割を作成', @@ -65,14 +96,18 @@ return [ 'role_details' => '概要', 'role_name' => '役割名', 'role_desc' => '役割の説明', + 'role_external_auth_id' => 'External Authentication IDs', '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_settings' => 'アプリケーション設定の管理', 'role_asset' => 'アセット権限', 'role_asset_desc' => '各アセットに対するデフォルトの権限を設定します。ここで設定した権限が優先されます。', + 'role_asset_admins' => 'Admins are automatically given access to all content but these options may show or hide UI options.', 'role_all' => '全て', 'role_own' => '自身', 'role_controlled_by_asset' => 'このアセットに対し、右記の操作を許可:', @@ -81,16 +116,22 @@ return [ 'role_users' => 'この役割を持つユーザ', 'role_users_none' => 'この役割が付与されたユーザは居ません', - /** - * Users - */ - + // Users 'users' => 'ユーザ', 'user_profile' => 'ユーザプロフィール', 'users_add_new' => 'ユーザを追加', 'users_search' => 'ユーザ検索', + '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' => 'ユーザ役割', + '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' => '外部認証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' => 'パスワードを変更したい場合のみ入力してください', 'users_system_public' => 'このユーザはアプリケーションにアクセスする全てのゲストを表します。ログインはできませんが、自動的に割り当てられます。', 'users_delete' => 'ユーザを削除', @@ -104,11 +145,67 @@ return [ 'users_avatar' => 'アバター', 'users_avatar_desc' => '256pxの正方形である必要があります。', 'users_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' => 'ソーシャルアカウント', 'users_social_accounts_info' => 'アカウントを接続すると、ログインが簡単になります。ここでアカウントの接続を解除すると、そのアカウントを経由したログインを禁止できます。接続解除後、各ソーシャルアカウントの設定にてこのアプリケーションへのアクセス許可を解除してください。', 'users_social_connect' => 'アカウントを接続', 'users_social_disconnect' => 'アカウントを接続解除', 'users_social_connected' => '「:socialAccount」がプロフィールに接続されました。', - 'users_social_disconnected' => '「: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', + // 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' => 'العربية', + 'da' => 'Dansk', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// ]; diff --git a/resources/lang/ja/validation.php b/resources/lang/ja/validation.php index e0fa3cb2c..231bdfa0b 100644 --- a/resources/lang/ja/validation.php +++ b/resources/lang/ja/validation.php @@ -1,18 +1,13 @@ ':attributeに同意する必要があります。', 'active_url' => ':attributeは正しいURLではありません。', 'after' => ':attributeは:date以降である必要があります。', @@ -35,12 +30,41 @@ return [ 'digits' => ':attributeは:digitsデジットである必要があります', 'digits_between' => ':attributeは:min〜:maxである必要があります。', 'email' => ':attributeは正しいEメールアドレスである必要があります。', + 'ends_with' => 'The :attribute must end with one of the following: :values', 'filled' => ':attributeは必須です。', + '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.', + ], + '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.', + ], 'exists' => '選択された:attributeは不正です。', 'image' => ':attributeは画像である必要があります。', + 'image_extension' => 'The :attribute must have a valid & supported image extension.', 'in' => '選択された:attributeは不正です。', 'integer' => ':attributeは数値である必要があります。', 'ip' => ':attributeは正しいIPアドレスである必要があります。', + '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.', + '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.', + ], + '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.', + ], 'max' => [ 'numeric' => ':attributeは:maxを越えることができません。', 'file' => ':attributeは:maxキロバイトを越えることができません。', @@ -54,7 +78,9 @@ 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は数値である必要があります。', 'regex' => ':attributeのフォーマットは不正です。', 'required' => ':attributeは必須です。', @@ -74,35 +100,15 @@ return [ 'timezone' => ':attributeは正しいタイムゾーンである必要があります。', 'unique' => ':attributeは既に使用されています。', 'url' => ':attributeのフォーマットは不正です。', + 'uploaded' => 'The file could not be uploaded. The server may not accept files of this size.', - /* - |-------------------------------------------------------------------------- - | Custom Validation Language Lines - |-------------------------------------------------------------------------- - | - | Here you may specify custom validation messages for attributes using the - | convention "attribute.rule" to name the lines. This makes it quick to - | specify a specific custom language line for a given attribute rule. - | - */ - + // Custom validation lines 'custom' => [ 'password-confirm' => [ 'required_with' => 'パスワードの確認は必須です。', ], ], - /* - |-------------------------------------------------------------------------- - | Custom Validation Attributes - |-------------------------------------------------------------------------- - | - | The following language lines are used to swap attribute place-holders - | with something more reader friendly such as E-Mail Address instead - | of "email". This simply helps us make messages a little cleaner. - | - */ - + // Custom validation attributes 'attributes' => [], - ]; diff --git a/resources/lang/ko/activities.php b/resources/lang/ko/activities.php new file mode 100644 index 000000000..c3fedeb45 --- /dev/null +++ b/resources/lang/ko/activities.php @@ -0,0 +1,48 @@ + '문서 만들기', + 'page_create_notification' => '문서 만듦', + 'page_update' => '문서 수정', + 'page_update_notification' => '문서 수정함', + 'page_delete' => '문서 지우기', + 'page_delete_notification' => '문서 지움', + 'page_restore' => '문서 복원', + 'page_restore_notification' => '문서 복원함', + 'page_move' => '문서 옮기기', + + // Chapters + 'chapter_create' => '챕터 만들기', + 'chapter_create_notification' => '챕터 만듦', + 'chapter_update' => '챕터 바꾸기', + 'chapter_update_notification' => '챕터 바꿈', + 'chapter_delete' => '챕터 지우기', + 'chapter_delete_notification' => '챕터 지움', + 'chapter_move' => '챕터 옮기기', + + // Books + 'book_create' => '책자 만들기', + 'book_create_notification' => '책자 만듦', + 'book_update' => '책자 바꾸기', + 'book_update_notification' => '책자 바꿈', + 'book_delete' => '책자 지우기', + 'book_delete_notification' => '책자 지움', + 'book_sort' => '책자 정렬', + 'book_sort_notification' => '책자 정렬함', + + // Bookshelves + 'bookshelf_create' => '서가 만들기', + 'bookshelf_create_notification' => '서가 만듦', + 'bookshelf_update' => '서가 바꾸기', + 'bookshelf_update_notification' => '서가 바꿈', + 'bookshelf_delete' => '서가 지우기', + 'bookshelf_delete_notification' => '서가 지움', + + // Other + 'commented_on' => '댓글 쓰기', +]; diff --git a/resources/lang/ko/auth.php b/resources/lang/ko/auth.php new file mode 100644 index 000000000..5346c5540 --- /dev/null +++ b/resources/lang/ko/auth.php @@ -0,0 +1,77 @@ + '가입하지 않았거나 비밀번호가 틀립니다.', + 'throttle' => '여러 번 실패했습니다. :seconds초 후에 다시 시도하세요.', + + // Login & Register + 'sign_up' => '가입', + 'log_in' => '로그인', + 'log_in_with' => ':socialDriver로 로그인', + 'sign_up_with' => ':socialDriver로 가입', + 'logout' => '로그아웃', + + 'name' => '이름', + 'username' => '사용자 이름', + 'email' => '메일 주소', + 'password' => '비밀번호', + 'password_confirm' => '비밀번호 확인', + 'password_hint' => '일곱 글자를 넘어야 합니다.', + 'forgot_password' => '비밀번호를 잊었나요?', + 'remember_me' => '로그인 유지', + 'ldap_email_hint' => '이 계정에 대한 메일 주소를 입력하세요.', + 'create_account' => '가입', + 'already_have_account' => '계정이 있나요?', + 'dont_have_account' => '계정이 없나요?', + 'social_login' => '소셜 로그인', + 'social_registration' => '소셜 가입', + 'social_registration_text' => '소셜 계정으로 가입하고 로그인합니다.', + + 'register_thanks' => '가입해 주셔서 감사합니다!', + 'register_confirm' => '메일을 확인한 후 버튼을 눌러 :appName에 접근하세요.', + 'registrations_disabled' => '가입할 수 없습니다.', + 'registration_email_domain_invalid' => '이 메일 주소로는 이 사이트에 접근할 수 없습니다.', + 'register_success' => '가입했습니다! 이제 로그인할 수 있습니다.', + + + // Password Reset + 'reset_password' => '비밀번호 바꾸기', + 'reset_password_send_instructions' => '메일 주소를 입력하세요. 이 주소로 해당 과정을 위한 링크를 보낼 것입니다.', + 'reset_password_send_button' => '메일 보내기', + 'reset_password_sent_success' => ':email로 메일을 보냈습니다.', + 'reset_password_success' => '비밀번호를 바꿨습니다.', + 'email_reset_subject' => ':appName 비밀번호 바꾸기', + 'email_reset_text' => '비밀번호를 바꿉니다.', + 'email_reset_not_requested' => '원하지 않는다면 이 과정은 필요 없습니다.', + + + // Email Confirmation + 'email_confirm_subject' => ':appName 메일 인증', + 'email_confirm_greeting' => ':appName로 가입해 주셔서 감사합니다!', + 'email_confirm_text' => '다음 버튼을 눌러 인증하세요:', + 'email_confirm_action' => '메일 인증', + 'email_confirm_send_error' => '메일을 보낼 수 없었습니다.', + 'email_confirm_success' => '인증했습니다!', + 'email_confirm_resent' => '다시 보냈습니다. 메일함을 확인하세요.', + + 'email_not_confirmed' => '인증하지 않았습니다.', + 'email_not_confirmed_text' => '인증을 완료하지 않았습니다.', + 'email_not_confirmed_click_link' => '메일을 확인하고 인증 링크를 클릭하세요.', + 'email_not_confirmed_resend' => '메일 주소가 없다면 다음을 입력하세요.', + 'email_not_confirmed_resend_button' => '다시 보내기', + + // User Invite + 'user_invite_email_subject' => ':appName에서 권유를 받았습니다.', + 'user_invite_email_greeting' => ':appName에서 가입한 기록이 있습니다.', + 'user_invite_email_text' => '다음 버튼을 눌러 확인하세요:', + 'user_invite_email_action' => '비밀번호 설정', + 'user_invite_page_welcome' => ':appName로 접속했습니다.', + 'user_invite_page_text' => ':appName에 로그인할 때 입력할 비밀번호를 설정하세요.', + 'user_invite_page_confirm_button' => '비밀번호 확인', + 'user_invite_success' => '이제 :appName에 접근할 수 있습니다.' +]; \ No newline at end of file diff --git a/resources/lang/ko/common.php b/resources/lang/ko/common.php new file mode 100644 index 000000000..c2b09080c --- /dev/null +++ b/resources/lang/ko/common.php @@ -0,0 +1,77 @@ + '취소', + 'confirm' => '확인', + 'back' => '뒤로', + 'save' => '저장', + 'continue' => '계속', + 'select' => '선택', + 'toggle_all' => '모두 보기', + 'more' => '더 보기', + + // Form Labels + 'name' => '이름', + 'description' => '설명', + 'role' => '권한', + 'cover_image' => '대표 이미지', + 'cover_image_description' => '이미지 규격은 440x250px 내외입니다.', + + // Actions + 'actions' => '활동', + 'view' => '보기', + 'view_all' => '모두 보기', + 'create' => '만들기', + 'update' => '바꾸기', + 'edit' => '수정', + 'sort' => '정렬', + 'move' => '옮기기', + 'copy' => '복사', + 'reply' => '답글', + 'delete' => '지우기', + 'search' => '검색', + 'search_clear' => '기록 지우기', + 'reset' => '리셋', + 'remove' => '제거', + 'add' => '추가', + 'fullscreen' => '전체화면', + + // Sort Options + 'sort_options' => '정렬 기준', + 'sort_direction_toggle' => '순서 반전', + 'sort_ascending' => '오름차 순서', + 'sort_descending' => '내림차 순서', + 'sort_name' => '제목', + 'sort_created_at' => '만든 날짜', + 'sort_updated_at' => '수정한 날짜', + + // Misc + 'deleted_user' => '삭제한 사용자', + 'no_activity' => '활동 없음', + 'no_items' => '항목 없음', + 'back_to_top' => '맨 위로', + 'toggle_details' => '내용 보기', + 'toggle_thumbnails' => '섬네일 보기', + 'details' => '정보', + 'grid_view' => '격자 보기', + 'list_view' => '목록 보기', + 'default' => '기본 설정', + 'breadcrumb' => '탐색 경로', + + // Header + 'profile_menu' => '프로필', + 'view_profile' => '프로필 보기', + 'edit_profile' => '프로필 바꾸기', + + // Layout tabs + 'tab_info' => '정보', + 'tab_content' => '내용', + + // Email Content + 'email_action_help' => ':actionText를 클릭할 수 없을 때는 웹 브라우저에서 다음 링크로 접속할 수 있습니다.', + 'email_rights' => '모든 권리 소유', +]; diff --git a/resources/lang/ko/components.php b/resources/lang/ko/components.php new file mode 100644 index 000000000..397d0d187 --- /dev/null +++ b/resources/lang/ko/components.php @@ -0,0 +1,33 @@ + '이미지 선택', + 'image_all' => '모든 이미지', + 'image_all_title' => '모든 이미지', + 'image_book_title' => '이 책자에서 쓰고 있는 이미지', + 'image_page_title' => '이 문서에서 쓰고 있는 이미지', + 'image_search_hint' => '이미지 이름 검색', + 'image_uploaded' => '올림 :uploadedDate', + 'image_load_more' => '더 로드하기', + 'image_image_name' => '이미지 이름', + 'image_delete_used' => '이 이미지는 다음 문서들이 쓰고 있습니다.', + 'image_delete_confirm' => '이 이미지를 지울 건가요?', + 'image_select_image' => '이미지 선택', + 'image_dropzone' => '여기에 이미지를 드롭하거나 여기를 클릭하세요. 이미지를 올릴 수 있습니다.', + 'images_deleted' => '이미지 삭제함', + 'image_preview' => '이미지 미리 보기', + 'image_upload_success' => '이미지 올림', + 'image_update_success' => '이미지 정보 수정함', + 'image_delete_success' => '이미지 삭제함', + 'image_upload_remove' => '삭제', + + // Code Editor + 'code_editor' => '코드 수정', + 'code_language' => '언어', + 'code_content' => '내용', + 'code_save' => '저장', +]; diff --git a/resources/lang/ko/entities.php b/resources/lang/ko/entities.php new file mode 100644 index 000000000..a166cda40 --- /dev/null +++ b/resources/lang/ko/entities.php @@ -0,0 +1,314 @@ + '최근에 수정함', + 'recently_created_pages' => '최근에 만든 문서', + 'recently_updated_pages' => '최근에 수정한 문서', + 'recently_created_chapters' => '최근에 만든 챕터', + 'recently_created_books' => '최근에 만든 책자', + 'recently_created_shelves' => '최근에 만든 서가', + 'recently_update' => '최근에 수정함', + 'recently_viewed' => '최근에 읽음', + 'recent_activity' => '최근에 활동함', + 'create_now' => '바로 만들기', + 'revisions' => '수정본', + 'meta_revision' => '판본 #:revisionCount', + 'meta_created' => '만듦 :timeLength', + 'meta_created_name' => '만듦 :timeLength, :user', + 'meta_updated' => '수정함 :timeLength', + 'meta_updated_name' => '수정함 :timeLength, :user', + 'entity_select' => '항목 선택', + 'images' => '이미지', + 'my_recent_drafts' => '쓰다 만 문서', + 'my_recently_viewed' => '내가 읽은 문서', + 'no_pages_viewed' => '문서 없음', + 'no_pages_recently_created' => '문서 없음', + 'no_pages_recently_updated' => '문서 없음', + 'export' => '파일로 받기', + 'export_html' => 'Contained Web(.html) 파일', + 'export_pdf' => 'PDF 파일', + 'export_text' => 'Plain Text(.txt) 파일', + + // Permissions and restrictions + 'permissions' => '권한', + 'permissions_intro' => '한번 허용하면 이 설정은 사용자 권한에 우선합니다.', + 'permissions_enable' => '설정 허용', + 'permissions_save' => '권한 저장', + + // Search + 'search_results' => '검색 결과', + 'search_total_results_found' => ':count개|총 :count개', + 'search_clear' => '기록 지우기', + 'search_no_pages' => '결과 없음', + 'search_for_term' => ':term 검색', + 'search_more' => '더 많은 결과', + 'search_filters' => '고급 검색', + 'search_content_type' => '형식', + 'search_exact_matches' => '정확히 일치', + 'search_tags' => '꼬리표 일치', + 'search_options' => '선택', + 'search_viewed_by_me' => '내가 읽음', + 'search_not_viewed_by_me' => '내가 읽지 않음', + 'search_permissions_set' => '권한 설정함', + 'search_created_by_me' => '내가 만듦', + 'search_updated_by_me' => '내가 수정함', + 'search_date_options' => '날짜', + 'search_updated_before' => '이전에 수정함', + 'search_updated_after' => '이후에 수정함', + 'search_created_before' => '이전에 만듦', + 'search_created_after' => '이후에 만듦', + 'search_set_date' => '날짜 설정', + 'search_update' => '검색', + + // Shelves + 'shelf' => '서가', + 'shelves' => '서가', + 'x_shelves' => '서가 :count개|총 :count개', + 'shelves_long' => '서가', + 'shelves_empty' => '만든 서가가 없습니다.', + 'shelves_create' => '서가 만들기', + 'shelves_popular' => '많이 읽은 서가', + 'shelves_new' => '새로운 서가', + 'shelves_new_action' => '새로운 서가', + 'shelves_popular_empty' => '많이 읽은 서가 목록', + 'shelves_new_empty' => '새로운 서가 목록', + 'shelves_save' => '저장', + 'shelves_books' => '이 서가에 있는 책자들', + 'shelves_add_books' => '이 서가에 책자 추가', + 'shelves_drag_books' => '여기에 책자를 드롭하세요.', + 'shelves_empty_contents' => '이 서가에 책자가 없습니다.', + 'shelves_edit_and_assign' => '서가 바꾸기로 책자를 추가하세요.', + 'shelves_edit_named' => ':name 바꾸기', + 'shelves_edit' => '서가 바꾸기', + 'shelves_delete' => '서가 지우기', + 'shelves_delete_named' => ':name 지우기', + 'shelves_delete_explain' => ":name을 지웁니다. 책자는 지우지 않습니다.", + 'shelves_delete_confirmation' => '이 서가를 지울 건가요?', + 'shelves_permissions' => '서가 권한', + 'shelves_permissions_updated' => '서가 권한 바꿈', + 'shelves_permissions_active' => '서가 권한 허용함', + 'shelves_copy_permissions_to_books' => '권한 맞춤', + 'shelves_copy_permissions' => '실행', + 'shelves_copy_permissions_explain' => '서가의 모든 책자에 이 권한을 적용합니다. 서가의 권한을 저장했는지 확인하세요.', + 'shelves_copy_permission_success' => '책자 :count개 권한 바꿈', + + // Books + 'book' => '서고', + 'books' => '서고', + 'x_books' => '책자 :count개|총 :count개', + 'books_empty' => '만든 책자가 없습니다.', + 'books_popular' => '많이 읽은 책자', + 'books_recent' => '최근에 읽은 책자', + 'books_new' => '새로운 책자', + 'books_new_action' => '새로운 책자', + 'books_popular_empty' => '많이 읽은 책자 목록', + 'books_new_empty' => '새로운 책자 목록', + 'books_create' => '책자 만들기', + 'books_delete' => '책자 지우기', + 'books_delete_named' => ':bookName(을)를 지웁니다.', + 'books_delete_explain' => ':bookName에 있는 모든 챕터와 문서도 지웁니다.', + 'books_delete_confirmation' => '이 책자를 지울 건가요?', + 'books_edit' => '책자 바꾸기', + 'books_edit_named' => ':bookName(을)를 바꿉니다.', + 'books_form_book_name' => '책자 이름', + 'books_save' => '저장', + 'books_permissions' => '책자 권한', + 'books_permissions_updated' => '권한 저장함', + 'books_empty_contents' => '이 책자에 챕터나 문서가 없습니다.', + 'books_empty_create_page' => '문서 만들기', + 'books_empty_sort_current_book' => '읽고 있는 책자 정렬', + 'books_empty_add_chapter' => '챕터 만들기', + 'books_permissions_active' => '책자 권한 허용함', + 'books_search_this' => '이 책자에서 검색', + 'books_navigation' => '목차', + 'books_sort' => '다른 책자들', + 'books_sort_named' => ':bookName 정렬', + 'books_sort_name' => '제목', + 'books_sort_created' => '만든 날짜', + 'books_sort_updated' => '수정한 날짜', + 'books_sort_chapters_first' => '챕터 우선', + 'books_sort_chapters_last' => '문서 우선', + 'books_sort_show_other' => '다른 책자들', + 'books_sort_save' => '적용', + + // Chapters + 'chapter' => '챕터', + 'chapters' => '챕터', + 'x_chapters' => '챕터 :count개|총 :count개', + 'chapters_popular' => '많이 읽은 챕터', + 'chapters_new' => '새로운 챕터', + 'chapters_create' => '챕터 만들기', + 'chapters_delete' => '챕터 지우기', + 'chapters_delete_named' => ':chapterName(을)를 지웁니다.', + 'chapters_delete_explain' => ':chapterName에 있는 모든 문서는 챕터에서 벗어날 뿐 지우지 않습니다.', + 'chapters_delete_confirm' => '이 챕터를 지울 건가요?', + 'chapters_edit' => '챕터 바꾸기', + 'chapters_edit_named' => ':chapterName 바꾸기', + 'chapters_save' => '저장', + 'chapters_move' => '챕터 옮기기', + 'chapters_move_named' => ':chapterName 옮기기', + 'chapter_move_success' => ':bookName(으)로 옮김', + 'chapters_permissions' => '챕터 권한', + 'chapters_empty' => '이 챕터에 문서가 없습니다.', + 'chapters_permissions_active' => '문서 권한 허용함', + 'chapters_permissions_success' => '권한 저장함', + 'chapters_search_this' => '이 챕터에서 검색', + + // Pages + 'page' => '문서', + 'pages' => '문서', + 'x_pages' => '문서 :count개|총 :count개', + 'pages_popular' => '많이 읽은 문서', + 'pages_new' => '새로운 문서', + 'pages_attachments' => '첨부', + 'pages_navigation' => '목차', + 'pages_delete' => '문서 지우기', + 'pages_delete_named' => ':pageName 지우기', + 'pages_delete_draft_named' => ':pageName 지우기', + 'pages_delete_draft' => '쓰다 만 문서 지우기', + 'pages_delete_success' => '문서 지움', + 'pages_delete_draft_success' => '쓰다 만 문서 지움', + 'pages_delete_confirm' => '이 문서를 지울 건가요?', + 'pages_delete_draft_confirm' => '쓰다 만 문서를 지울 건가요?', + 'pages_editing_named' => ':pageName 수정', + 'pages_edit_draft_options' => '쓰다 만 문서 선택', + 'pages_edit_save_draft' => '보관', + 'pages_edit_draft' => '쓰다 만 문서 수정', + 'pages_editing_draft' => '쓰다 만 문서 수정', + 'pages_editing_page' => '문서 수정', + 'pages_edit_draft_save_at' => '보관함: ', + 'pages_edit_delete_draft' => '삭제', + 'pages_edit_discard_draft' => '폐기', + 'pages_edit_set_changelog' => '수정본 설명', + 'pages_edit_enter_changelog_desc' => '수정본 설명', + 'pages_edit_enter_changelog' => '설명', + 'pages_save' => '저장', + 'pages_title' => '문서 제목', + 'pages_name' => '문서 이름', + 'pages_md_editor' => '에디터', + 'pages_md_preview' => '미리 보기', + 'pages_md_insert_image' => '이미지 추가', + 'pages_md_insert_link' => '내부 링크', + 'pages_md_insert_drawing' => '드로잉 추가', + 'pages_not_in_chapter' => '챕터에 있는 문서가 아닙니다.', + 'pages_move' => '문서 옮기기', + 'pages_move_success' => ':parentName(으)로 옮김', + 'pages_copy' => '문서 복제', + 'pages_copy_desination' => '복제할 위치', + 'pages_copy_success' => '복제함', + 'pages_permissions' => '문서 권한', + 'pages_permissions_success' => '문서 권한 바꿈', + 'pages_revision' => '수정본', + 'pages_revisions' => '문서 수정본', + 'pages_revisions_named' => ':pageName 수정본', + 'pages_revision_named' => ':pageName 수정본', + 'pages_revisions_created_by' => '만든 사용자', + 'pages_revisions_date' => '수정한 날짜', + 'pages_revisions_number' => 'No.', + 'pages_revisions_numbered' => '수정본 :id', + 'pages_revisions_numbered_changes' => '수정본 :id에서 바꾼 부분', + 'pages_revisions_changelog' => '설명', + 'pages_revisions_changes' => '바꾼 부분', + 'pages_revisions_current' => '현재 판본', + 'pages_revisions_preview' => '미리 보기', + 'pages_revisions_restore' => '복원', + 'pages_revisions_none' => '수정본이 없습니다.', + 'pages_copy_link' => '주소 복사', + 'pages_edit_content_link' => '수정', + 'pages_permissions_active' => '문서 권한 허용함', + 'pages_initial_revision' => '처음 판본', + 'pages_initial_name' => '제목 없음', + 'pages_editing_draft_notification' => ':timeDiff에 쓰다 만 문서입니다.', + 'pages_draft_edited_notification' => '최근에 수정한 문서이기 때문에 쓰다 만 문서를 폐기하는 편이 좋습니다.', + 'pages_draft_edit_active' => [ + 'start_a' => ':count명이 이 문서를 수정하고 있습니다.', + 'start_b' => ':userName이 이 문서를 수정하고 있습니다.', + 'time_a' => '수정본이 생겼습니다.', + 'time_b' => '(:minCount분 전)', + 'message' => ':start :time. 다른 사용자의 수정본을 덮어쓰지 않도록 주의하세요.', + ], + 'pages_draft_discarded' => '쓰다 만 문서를 지웠습니다. 에디터에 현재 판본이 나타납니다.', + 'pages_specific' => '특정한 문서', + 'pages_is_template' => '템플릿', + + // Editor Sidebar + 'page_tags' => '문서 꼬리표', + 'chapter_tags' => '챕터 꼬리표', + 'book_tags' => '책자 꼬리표', + 'shelf_tags' => '서가 꼬리표', + 'tag' => '꼬리표', + 'tags' => '꼬리표', + 'tag_name' => '꼬리표 이름', + 'tag_value' => '리스트 값 (선택 사항)', + 'tags_explain' => "태그로 문서를 분류하세요.", + 'tags_add' => '태그 추가', + 'tags_remove' => '태그 삭제', + 'attachments' => '첨부 파일', + 'attachments_explain' => '파일이나 링크를 첨부하세요. 정보 탭에 나타납니다.', + 'attachments_explain_instant_save' => '여기에서 바꾼 내용은 바로 적용합니다.', + 'attachments_items' => '첨부한 파일들', + 'attachments_upload' => '파일 올리기', + 'attachments_link' => '링크로 첨부', + 'attachments_set_link' => '링크 설정', + 'attachments_delete_confirm' => '삭제하려면 버튼을 한 번 더 클릭하세요.', + 'attachments_dropzone' => '여기에 파일을 드롭하거나 여기를 클릭하세요.', + 'attachments_no_files' => '올린 파일 없음', + 'attachments_explain_link' => '파일을 올리지 않고 링크로 첨부할 수 있습니다.', + 'attachments_link_name' => '링크 이름', + 'attachment_link' => '파일 주소', + 'attachments_link_url' => '파일로 링크', + 'attachments_link_url_hint' => '파일 주소', + 'attach' => '파일 첨부', + 'attachments_edit_file' => '파일 수정', + 'attachments_edit_file_name' => '파일 이름', + 'attachments_edit_drop_upload' => '여기에 파일을 드롭하거나 여기를 클릭하세요. 파일을 올리거나 덮어쓸 수 있습니다.', + 'attachments_order_updated' => '첨부 순서 바꿈', + 'attachments_updated_success' => '첨부 파일 정보 수정함', + 'attachments_deleted' => '첨부 파일 삭제함', + 'attachments_file_uploaded' => '파일 올림', + 'attachments_file_updated' => '파일 바꿈', + 'attachments_link_attached' => '링크 첨부함', + 'templates' => '템플릿', + 'templates_set_as_template' => '템플릿', + 'templates_explain_set_as_template' => '템플릿은 보기 권한만 있어도 문서에 쓸 수 있습니다.', + 'templates_replace_content' => '문서 대체', + 'templates_append_content' => '문서 앞에 추가', + 'templates_prepend_content' => '문서 뒤에 추가', + + // Profile View + 'profile_user_for_x' => ':time 전에 가입함', + 'profile_created_content' => '활동한 이력', + 'profile_not_created_pages' => ':userName(이)가 만든 문서 없음', + 'profile_not_created_chapters' => ':userName(이)가 만든 챕터 없음', + 'profile_not_created_books' => ':userName(이)가 만든 책자 없음', + 'profile_not_created_shelves' => ':userName(이)가 만든 서가 없음', + + // Comments + 'comment' => '댓글', + 'comments' => '댓글', + 'comment_add' => '댓글 쓰기', + 'comment_placeholder' => '이곳에 댓글을 쓰세요...', + 'comment_count' => '{0} 댓글 없음|{1} 댓글 1개|[2,*] 댓글 :count개', + 'comment_save' => '등록', + 'comment_saving' => '저장하는 중...', + 'comment_deleting' => '삭제하는 중...', + 'comment_new' => '새로운 댓글', + 'comment_created' => '댓글 등록함 :createDiff', + 'comment_updated' => ':username(이)가 댓글 수정함 :updateDiff', + 'comment_deleted_success' => '댓글 지움', + 'comment_created_success' => '댓글 등록함', + 'comment_updated_success' => '댓글 수정함', + 'comment_delete_confirm' => '이 댓글을 지울 건가요?', + 'comment_in_reply_to' => ':commentId(을)를 향한 답글', + + // Revision + 'revision_delete_confirm' => '이 수정본을 지울 건가요?', + 'revision_restore_confirm' => '이 수정본을 되돌릴 건가요? 현재 판본을 바꿉니다.', + 'revision_delete_success' => '수정본 지움', + 'revision_cannot_delete_latest' => '현재 판본은 지울 수 없습니다.' +]; \ No newline at end of file diff --git a/resources/lang/ko/errors.php b/resources/lang/ko/errors.php new file mode 100644 index 000000000..506baf5a6 --- /dev/null +++ b/resources/lang/ko/errors.php @@ -0,0 +1,99 @@ + '권한이 없습니다.', + 'permissionJson' => '권한이 없습니다.', + + // Auth + 'error_user_exists_different_creds' => ':email(을)를 가진 다른 사용자가 있습니다.', + 'email_already_confirmed' => '확인이 끝난 메일 주소입니다. 로그인하세요.', + 'email_confirmation_invalid' => '이 링크는 더 이상 유효하지 않습니다. 다시 가입하세요.', + 'email_confirmation_expired' => '이 링크는 더 이상 유효하지 않습니다. 메일을 다시 보냈습니다.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', + 'ldap_fail_anonymous' => '익명 정보로 LDAP 서버에 접근할 수 없습니다.', + 'ldap_fail_authed' => '이 정보로 LDAP 서버에 접근할 수 없습니다.', + 'ldap_extension_not_installed' => 'PHP에 LDAP 확장 도구를 설치하세요.', + 'ldap_cannot_connect' => 'LDAP 서버에 연결할 수 없습니다.', + 'saml_already_logged_in' => '이미 로그인되어있습니다.', + 'saml_user_not_registered' => '사용자 이름이 등록되지 않았으며 자동 계정 등록이 활성화되지 않았습니다.', + 'saml_no_email_address' => '이 사용자에 대하여 외부 인증시스템에 의해 제공된 데이타 중 이메일 주소를 찾을 수 없습니다.', + 'saml_invalid_response_id' => '이 응용프로그램에 의해 시작된 프로세스에 의하면 외부 인증시스템으로 온 요청이 인식되지 않습니다. 인증 후에 뒤로가기 기능을 사용했을 경우 이런 현상이 발생할 수 있습니다.', + 'saml_fail_authed' => '시스템 로그인에 실패하였습니다. ( 해당 시스템이 인증성공값을 제공하지 않았습니다. )', + 'social_no_action_defined' => '무슨 활동인지 알 수 없습니다.', + 'social_login_bad_response' => ":socialAccount에 로그인할 수 없습니다. : \\n:error", + 'social_account_in_use' => ':socialAccount(을)를 가진 사용자가 있습니다. :socialAccount로 로그인하세요.', + 'social_account_email_in_use' => ':email(을)를 가진 사용자가 있습니다. 쓰고 있는 계정을 :socialAccount에 연결하세요.', + 'social_account_existing' => ':socialAccount(와)과 연결 상태입니다.', + 'social_account_already_used_existing' => ':socialAccount(와)과 연결한 다른 계정이 있습니다.', + 'social_account_not_used' => ':socialAccount(와)과 연결한 계정이 없습니다. 쓰고 있는 계정을 연결하세요.', + 'social_account_register_instructions' => '계정이 없어도 :socialAccount로 가입할 수 있습니다.', + 'social_driver_not_found' => '가입할 수 없습니다.', + 'social_driver_not_configured' => ':socialAccount가 유효하지 않습니다.', + 'invite_token_expired' => '이 링크는 더 이상 유효하지 않습니다. 비밀번호를 바꾸세요.', + + // System + 'path_not_writable' => ':filePath에 쓰는 것을 서버에서 허용하지 않습니다.', + 'cannot_get_image_from_url' => ':url에서 이미지를 불러올 수 없습니다.', + 'cannot_create_thumbs' => '섬네일을 못 만들었습니다. PHP에 GD 확장 도구를 설치하세요.', + 'server_upload_limit' => '파일 크기가 서버에서 허용하는 수치를 넘습니다.', + 'uploaded' => '파일 크기가 서버에서 허용하는 수치를 넘습니다.', + 'image_upload_error' => '이미지를 올리다 문제가 생겼습니다.', + 'image_upload_type_error' => '유효하지 않은 이미지 형식입니다.', + 'file_upload_timeout' => '파일을 올리는 데 걸리는 시간이 서버에서 허용하는 수치를 넘습니다.', + + // Attachments + 'attachment_page_mismatch' => '올리는 위치와 현재 문서가 다릅니다.', + 'attachment_not_found' => '첨부 파일이 없습니다.', + + // Pages + 'page_draft_autosave_fail' => '쓰다 만 문서를 유실했습니다. 인터넷 연결 상태를 확인하세요.', + 'page_custom_home_deletion' => '처음 페이지는 지울 수 없습니다.', + + // Entities + 'entity_not_found' => '항목이 없습니다.', + 'bookshelf_not_found' => '서가가 없습니다.', + 'book_not_found' => '책자가 없습니다.', + 'page_not_found' => '문서가 없습니다.', + 'chapter_not_found' => '챕터가 없습니다.', + 'selected_book_not_found' => '고른 책자가 없습니다.', + 'selected_book_chapter_not_found' => '고른 책자나 챕터가 없습니다.', + 'guests_cannot_save_drafts' => 'Guest는 쓰다 만 문서를 보관할 수 없습니다.', + + // Users + 'users_cannot_delete_only_admin' => 'Admin을 삭제할 수 없습니다.', + 'users_cannot_delete_guest' => 'Guest를 삭제할 수 없습니다.', + + // Roles + 'role_cannot_be_edited' => '권한을 수정할 수 없습니다.', + 'role_system_cannot_be_deleted' => '시스템 권한을 지울 수 없습니다.', + 'role_registration_default_cannot_delete' => '가입한 사용자의 기본 권한을 지울 수 있어야 합니다.', + 'role_cannot_remove_only_admin' => 'Admin을 가진 사용자가 적어도 한 명 있어야 합니다.', + + // Comments + 'comment_list' => '댓글을 가져오다 문제가 생겼습니다.', + 'cannot_add_comment_to_draft' => '쓰다 만 문서에 댓글을 달 수 없습니다.', + 'comment_add' => '댓글을 등록하다 문제가 생겼습니다.', + 'comment_delete' => '댓글을 지우다 문제가 생겼습니다.', + 'empty_comment' => '빈 댓글은 등록할 수 없습니다.', + + // Error pages + '404_page_not_found' => '404 Not Found', + 'sorry_page_not_found' => '문서를 못 찾았습니다.', + 'return_home' => '처음으로 돌아가기', + 'error_occurred' => '문제가 생겼습니다.', + 'app_down' => ':appName에 문제가 있는 것 같습니다', + 'back_soon' => '곧 되돌아갑니다.', + + // 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', + +]; diff --git a/resources/lang/ko/pagination.php b/resources/lang/ko/pagination.php new file mode 100644 index 000000000..9a06aed73 --- /dev/null +++ b/resources/lang/ko/pagination.php @@ -0,0 +1,12 @@ + '« 이전', + 'next' => '다음 »', + +]; diff --git a/resources/lang/ko/passwords.php b/resources/lang/ko/passwords.php new file mode 100644 index 000000000..35a2a5933 --- /dev/null +++ b/resources/lang/ko/passwords.php @@ -0,0 +1,15 @@ + '여덟 글자를 넘어야 합니다.', + 'user' => "메일 주소를 가진 사용자가 없습니다.", + 'token' => '이 링크는 더 이상 유효하지 않습니다.', + 'sent' => '메일을 보냈습니다.', + 'reset' => '비밀번호를 바꿨습니다.', + +]; diff --git a/resources/lang/ko/settings.php b/resources/lang/ko/settings.php new file mode 100755 index 000000000..5523ee4d3 --- /dev/null +++ b/resources/lang/ko/settings.php @@ -0,0 +1,211 @@ + '설정', + 'settings_save' => '적용', + 'settings_save_success' => '설정 적용함', + + // App Settings + 'app_customization' => '맞춤', + 'app_features_security' => '보안', + 'app_name' => '사이트 제목', + 'app_name_desc' => '메일을 보낼 때 이 제목을 씁니다.', + 'app_name_header' => '사이트 헤더 사용', + 'app_public_access' => '사이트 공개', + 'app_public_access_desc' => '계정 없는 사용자가 문서를 볼 수 있습니다.', + 'app_public_access_desc_guest' => '이들의 권한은 사용자 이름이 Guest인 사용자로 관리할 수 있습니다.', + 'app_public_access_toggle' => '사이트 공개', + 'app_public_viewing' => '공개할 건가요?', + 'app_secure_images' => '이미지 주소 보호', + 'app_secure_images_toggle' => '이미지 주소 보호', + 'app_secure_images_desc' => '성능상의 문제로 이미지에 누구나 접근할 수 있기 때문에 이미지 주소를 무작위한 문자로 구성합니다. 폴더 색인을 끄세요.', + 'app_editor' => '에디터', + 'app_editor_desc' => '모든 사용자에게 적용합니다.', + 'app_custom_html' => '헤드 작성', + 'app_custom_html_desc' => '설정 페이지를 제외한 모든 페이지 head 태그 끝머리에 추가합니다.', + 'app_custom_html_disabled_notice' => '문제가 생겨도 설정 페이지에서 되돌릴 수 있어요.', + 'app_logo' => '사이트 로고', + 'app_logo_desc' => '높이를 43px로 구성하세요. 큰 이미지는 축소합니다.', + 'app_primary_color' => '사이트 색채', + 'app_primary_color_desc' => '16진수로 구성하세요. 비웠을 때는 기본 색채로 설정합니다.', + 'app_homepage' => '처음 페이지', + 'app_homepage_desc' => '고른 페이지에 설정한 권한은 무시합니다.', + 'app_homepage_select' => '문서 고르기', + 'app_disable_comments' => '댓글 사용 안 함', + 'app_disable_comments_toggle' => '댓글 사용 안 함', + 'app_disable_comments_desc' => '모든 페이지에서 댓글을 숨깁니다.', + + // Color settings + 'content_colors' => '본문 색상', + 'content_colors_desc' => '페이지에 있는 모든 요소에 대한 색상 지정하세요. 가독성을 위해 기본 색상과 유사한 밝기를 가진 색상으로 추천됩니다.', + 'bookshelf_color' => '책선반 색상', + 'book_color' => '책 색상', + 'chapter_color' => '챕터 색상', + 'page_color' => '페이지 색상', + 'page_draft_color' => '드래프트 페이지 색상', + + // Registration Settings + 'reg_settings' => '가입', + 'reg_enable' => '사이트 가입 허용', + '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_email_confirmation' => '메일 주소 확인', + 'reg_email_confirmation_toggle' => '주소 확인 요구', + 'reg_confirm_email_desc' => '도메인 차단을 쓰고 있으면 메일 주소를 확인해야 하고, 이 설정은 무시합니다.', + 'reg_confirm_restrict_domain' => '도메인 차단', + 'reg_confirm_restrict_domain_desc' => '쉼표로 분리해서 가입을 차단할 메일 주소 도메인을 쓰세요. 이 설정과 관계없이 사용자가 메일을 보내고, 가입한 사용자가 메일 주소를 바꿀 수 있습니다.', + 'reg_confirm_restrict_domain_placeholder' => '없음', + + // Maintenance settings + 'maint' => '데이터', + 'maint_image_cleanup' => '이미지 정리', + 'maint_image_cleanup_desc' => "중복한 이미지를 찾습니다. 실행하기 전에 이미지를 백업하세요.", + 'maint_image_cleanup_ignore_revisions' => '수정본에 있는 이미지 제외', + 'maint_image_cleanup_run' => '실행', + 'maint_image_cleanup_warning' => '이미지 :count개를 지울 건가요?', + 'maint_image_cleanup_success' => '이미지 :count개 삭제함', + 'maint_image_cleanup_nothing_found' => '삭제한 것 없음', + 'maint_send_test_email' => '테스트 메일 보내기', + 'maint_send_test_email_desc' => '프로필에 명시된 이메일주소로 테스트 메일이 전송됩니다.', + 'maint_send_test_email_run' => '테스트 메일 보내기', + 'maint_send_test_email_success' => '보낼 이메일 주소', + 'maint_send_test_email_mail_subject' => '테스트 메일', + 'maint_send_test_email_mail_greeting' => '이메일 전송이 성공하였습니다.', + 'maint_send_test_email_mail_text' => '축하합니다! 이 메일을 받음으로 이메일 설정이 정상적으로 되었음을 확인하였습니다.', + + // Role Settings + 'roles' => '권한', + 'role_user_roles' => '사용자 권한', + 'role_create' => '권한 만들기', + 'role_create_success' => '권한 만듦', + 'role_delete' => '권한 지우기', + 'role_delete_confirm' => ':roleName(을)를 지웁니다.', + 'role_delete_users_assigned' => '이 권한을 가진 사용자 :userCount명에 할당할 권한을 고르세요.', + 'role_delete_no_migration' => "할당하지 않음", + 'role_delete_sure' => '이 권한을 지울 건가요?', + 'role_delete_success' => '권한 지움', + 'role_edit' => '권한 수정', + 'role_details' => '권한 정보', + 'role_name' => '권한 이름', + 'role_desc' => '설명', + 'role_external_auth_id' => 'LDAP 확인', + 'role_system' => '시스템 권한', + 'role_manage_users' => '사용자 관리', + 'role_manage_roles' => '권한 관리', + 'role_manage_entity_permissions' => '문서별 권한 관리', + 'role_manage_own_entity_permissions' => '직접 만든 문서별 권한 관리', + 'role_manage_page_templates' => '템플릿 관리', + 'role_access_api' => 'Access system API', + 'role_manage_settings' => '사이트 설정 관리', + 'role_asset' => '권한 항목', + 'role_asset_desc' => '책자, 챕터, 문서별 권한은 이 설정에 우선합니다.', + 'role_asset_admins' => 'Admin 권한은 어디든 접근할 수 있지만 이 설정은 사용자 인터페이스에서 해당 활동을 표시할지 결정합니다.', + 'role_all' => '모든 항목', + 'role_own' => '직접 만든 항목', + 'role_controlled_by_asset' => '저마다 다름', + 'role_save' => '저장', + 'role_update_success' => '권한 저장함', + 'role_users' => '이 권한을 가진 사용자들', + 'role_users_none' => '그런 사용자가 없습니다.', + + // Users + 'users' => '사용자', + 'user_profile' => '사용자 프로필', + 'users_add_new' => '사용자 만들기', + 'users_search' => '사용자 검색', + 'users_details' => '사용자 정보', + 'users_details_desc' => '메일 주소로 로그인합니다.', + 'users_details_desc_no_email' => '사용자 이름을 바꿉니다.', + 'users_role' => '사용자 권한', + 'users_role_desc' => '고른 권한 모두를 적용합니다.', + 'users_password' => '비밀번호', + 'users_password_desc' => '여섯 글자를 넘어야 합니다.', + 'users_send_invite_text' => '비밀번호 설정을 권유하는 메일을 보내거나 내가 정할 수 있습니다.', + 'users_send_invite_option' => '메일 보내기', + 'users_external_auth_id' => 'LDAP 확인', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', + 'users_password_warning' => '비밀번호를 바꿀 때만 쓰세요.', + 'users_system_public' => '계정 없는 모든 사용자에 할당한 사용자입니다. 이 사용자로 로그인할 수 없어요.', + 'users_delete' => '사용자 삭제', + 'users_delete_named' => ':userName 삭제', + 'users_delete_warning' => ':userName에 관한 데이터를 지웁니다.', + 'users_delete_confirm' => '이 사용자를 지울 건가요?', + 'users_delete_success' => '사용자 삭제함', + 'users_edit' => '사용자 수정', + 'users_edit_profile' => '프로필 바꾸기', + 'users_edit_success' => '프로필 바꿈', + 'users_avatar' => '프로필 이미지', + 'users_avatar_desc' => '이미지 규격은 256x256px 내외입니다.', + 'users_preferred_language' => '언어', + 'users_preferred_language_desc' => '문서 내용에는 아무런 영향을 주지 않습니다.', + 'users_social_accounts' => '소셜 계정', + 'users_social_accounts_info' => '다른 계정으로 간단하게 로그인하세요. 여기에서 계정 연결을 끊는 것과 소셜 계정에서 접근 권한을 취소하는 것은 별개입니다.', + 'users_social_connect' => '계정 연결', + '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', + + // 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' => 'العربية', + 'da' => 'Dansk', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// +]; diff --git a/resources/lang/ko/validation.php b/resources/lang/ko/validation.php new file mode 100644 index 000000000..180faa35f --- /dev/null +++ b/resources/lang/ko/validation.php @@ -0,0 +1,114 @@ + ':attribute(을)를 허용하세요.', + 'active_url' => ':attribute(을)를 유효한 주소로 구성하세요.', + 'after' => ':attribute(을)를 :date 후로 설정하세요.', + 'alpha' => ':attribute(을)를 문자로만 구성하세요.', + 'alpha_dash' => ':attribute(을)를 문자, 숫자, -, _로만 구성하세요.', + 'alpha_num' => ':attribute(을)를 문자, 숫자로만 구성하세요.', + 'array' => ':attribute(을)를 배열로 구성하세요.', + 'before' => ':attribute(을)를 :date 전으로 설정하세요.', + 'between' => [ + 'numeric' => ':attribute(을)를 :min~:max(으)로 구성하세요.', + 'file' => ':attribute(을)를 :min~:max킬로바이트로 구성하세요.', + 'string' => ':attribute(을)를 :min~:max바이트로 구성하세요.', + 'array' => ':attribute(을)를 :min~:max개로 구성하세요.', + ], + 'boolean' => ':attribute(을)를 true나 false로만 구성하세요.', + 'confirmed' => ':attribute(와)과 다릅니다.', + 'date' => ':attribute(을)를 유효한 날짜로 구성하세요.', + 'date_format' => ':attribute(은)는 :format(와)과 다릅니다.', + 'different' => ':attribute(와)과 :other(을)를 다르게 구성하세요.', + 'digits' => ':attribute(을)를 :digits자리로 구성하세요.', + 'digits_between' => ':attribute(을)를 :min~:max자리로 구성하세요.', + 'email' => ':attribute(을)를 유효한 메일 주소로 구성하세요.', + 'ends_with' => ':attribute(을)를 :values(으)로 끝나게 구성하세요.', + 'filled' => ':attribute(을)를 구성하세요.', + 'gt' => [ + 'numeric' => ':attribute(을)를 :value(이)가 넘게 구성하세요.', + 'file' => ':attribute(을)를 :value킬로바이트가 넘게 구성하세요.', + 'string' => ':attribute(을)를 :value바이트가 넘게 구성하세요.', + 'array' => ':attribute(을)를 :value개가 넘게 구성하세요.', + ], + 'gte' => [ + 'numeric' => ':attribute(을)를 적어도 :value(으)로 구성하세요.', + 'file' => ':attribute(을)를 적어도 :value킬로바이트로 구성하세요.', + 'string' => ':attribute(을)를 적어도 :value바이트로 구성하세요.', + 'array' => ':attribute(을)를 적어도 :value개로 구성하세요..', + ], + 'exists' => '고른 :attribute(이)가 유효하지 않습니다.', + 'image' => ':attribute(을)를 이미지로 구성하세요.', + 'image_extension' => ':attribute(을)를 유효한 이미지 확장자로 구성하세요.', + 'in' => '고른 :attribute(이)가 유효하지 않습니다.', + 'integer' => ':attribute(을)를 정수로 구성하세요.', + 'ip' => ':attribute(을)를 유효한 IP 주소로 구성하세요.', + 'ipv4' => ':attribute(을)를 유효한 IPv4 주소로 구성하세요.', + 'ipv6' => ':attribute(을)를 유효한 IPv6 주소로 구성하세요.', + 'json' => ':attribute(을)를 유효한 JSON으로 구성하세요.', + 'lt' => [ + 'numeric' => ':attribute(을)를 :value(이)가 안 되게 구성하세요.', + 'file' => ':attribute(을)를 :value킬로바이트가 안 되게 구성하세요.', + 'string' => ':attribute(을)를 :value바이트가 안 되게 구성하세요.', + 'array' => ':attribute(을)를 :value개가 안 되게 구성하세요.', + ], + 'lte' => [ + 'numeric' => ':attribute(을)를 많아야 :max(으)로 구성하세요.', + 'file' => ':attribute(을)를 많아야 :max킬로바이트로 구성하세요.', + 'string' => ':attribute(을)를 많아야 :max바이트로 구성하세요.', + 'array' => ':attribute(을)를 많아야 :max개로 구성하세요.', + ], + 'max' => [ + 'numeric' => ':attribute(을)를 많아야 :max(으)로 구성하세요.', + 'file' => ':attribute(을)를 많아야 :max킬로바이트로 구성하세요.', + 'string' => ':attribute(을)를 많아야 :max바이트로 구성하세요.', + 'array' => ':attribute(을)를 많아야 :max개로 구성하세요.', + ], + 'mimes' => ':attribute(을)를 :values 형식으로 구성하세요.', + 'min' => [ + 'numeric' => ':attribute(을)를 적어도 :value(으)로 구성하세요.', + 'file' => ':attribute(을)를 적어도 :value킬로바이트로 구성하세요.', + 'string' => ':attribute(을)를 적어도 :value바이트로 구성하세요.', + 'array' => ':attribute(을)를 적어도 :value개로 구성하세요..', + ], + 'no_double_extension' => ':attribute(이)가 단일한 확장자를 가져야 합니다.', + 'not_in' => '고른 :attribute(이)가 유효하지 않습니다.', + 'not_regex' => ':attribute(은)는 유효하지 않은 형식입니다.', + 'numeric' => ':attribute(을)를 숫자로만 구성하세요.', + 'regex' => ':attribute(은)는 유효하지 않은 형식입니다.', + 'required' => ':attribute(을)를 구성하세요.', + 'required_if' => ':other(이)가 :value일 때 :attribute(을)를 구성해야 합니다.', + 'required_with' => ':values(이)가 있을 때 :attribute(을)를 구성해야 합니다.', + 'required_with_all' => ':values(이)가 모두 있을 때 :attribute(을)를 구성해야 합니다.', + 'required_without' => ':values(이)가 없을 때 :attribute(을)를 구성해야 합니다.', + 'required_without_all' => ':values(이)가 모두 없을 때 :attribute(을)를 구성해야 합니다.', + 'same' => ':attribute(와)과 :other(을)를 똑같이 구성하세요.', + 'size' => [ + 'numeric' => ':attribute(을)를 :size(으)로 구성하세요.', + 'file' => ':attribute(을)를 :size킬로바이트로 구성하세요.', + 'string' => ':attribute(을)를 :size바이트로 구성하세요.', + 'array' => ':attribute(을)를 :size개로 구성하세요..', + ], + 'string' => ':attribute(을)를 문자로 구성하세요.', + 'timezone' => ':attribute(을)를 유효한 시간대로 구성하세요.', + 'unique' => ':attribute(은)는 이미 있습니다.', + 'url' => ':attribute(은)는 유효하지 않은 형식입니다.', + 'uploaded' => '파일 크기가 서버에서 허용하는 수치를 넘습니다.', + + // Custom validation lines + 'custom' => [ + 'password-confirm' => [ + 'required_with' => '같은 비밀번호를 다시 입력하세요.', + ], + ], + + // Custom validation attributes + 'attributes' => [], +]; diff --git a/resources/lang/kr/activities.php b/resources/lang/kr/activities.php deleted file mode 100644 index d2c46a007..000000000 --- a/resources/lang/kr/activities.php +++ /dev/null @@ -1,40 +0,0 @@ - '페이지 생성', - 'page_create_notification' => '페이지를 만들었습니다.', - 'page_update' => '페이지 업데이트', - 'page_update_notification' => '페이지를 업데이트하였습니다.', - 'page_delete' => '페이지 삭제', - 'page_delete_notification' => '페이지를 삭제하였습니다.', - 'page_restore' => '페이지 복원', - 'page_restore_notification' => '페이지를 복원하였습니다.', - 'page_move' => '페이지 이동', - - // Chapters - 'chapter_create' => '챕터 만들기', - 'chapter_create_notification' => '챕터를 만들었습니다.', - 'chapter_update' => '챕터 업데이트', - 'chapter_update_notification' => '챕터를 업데이트하였습니다.', - 'chapter_delete' => '챕터 삭제', - 'chapter_delete_notification' => '챔터를 삭제하였습니다.', - 'chapter_move' => '챕터 이동', - - // Books - 'book_create' => '책 만들기', - 'book_create_notification' => '책을 만들었습니다.', - 'book_update' => '책 업데이트', - 'book_update_notification' => '책을 업데이트하였습니다.', - 'book_delete' => '책 삭제', - 'book_delete_notification' => '책을 삭제하였습니다.', - 'book_sort' => '책 정렬', - 'book_sort_notification' => '책을 정렬하였습니다.', - -]; diff --git a/resources/lang/kr/auth.php b/resources/lang/kr/auth.php deleted file mode 100644 index 671ddc654..000000000 --- a/resources/lang/kr/auth.php +++ /dev/null @@ -1,76 +0,0 @@ - '이 자격 증명은 등록되어 있지 않습니다.', - 'throttle' => '로그인 시도 횟수 제한을 초과했습니다. :seconds초 후에 다시 시도하십시오.', - - /** - * Login & Register - */ - 'sign_up' => '신규등록', - 'log_in' => '로그인', - 'log_in_with' => ':socialDriver에 로그인', - 'sign_up_with' => ':socialDriver로 등록', - 'logout' => '로그아웃', - - 'name' => '이름', - 'username' => '사용자이름', - 'email' => '이메일', - 'password' => '비밀번호', - 'password_confirm' => '비밀번호 (확인)', - 'password_hint' => '5자 이상이어야 합니다.', - 'forgot_password' => '비밀번호를 잊으셨습니까?', - 'remember_me' => '자동로그인', - 'ldap_email_hint' => '이 계정에서 사용하는 이메일을 입력해 주세요.', - 'create_account' => '계정 만들기', - 'social_login' => 'SNS로그인', - 'social_registration' => 'SNS등록', - 'social_registration_text' => '다른 서비스를 사용하여 등록하고 로그인.', - - 'register_thanks' => '등록이완료되었습니다!', - 'register_confirm' => '당신의 이메일을 확인하신후 확인 버튼을 눌러 :appName에 액세스하십시오.', - 'registrations_disabled' => '현재 등록이 불가합니다.', - 'registration_email_domain_invalid' => '해당 이메일 도메인으로 액세스 할 수 없습니다.', - 'register_success' => '등록을 완료하고 로그인 할 수 있습니다!', - - - /** - * Password Reset - */ - 'reset_password' => '암호 재설정', - 'reset_password_send_instructions' => '다음에 메일 주소를 입력하면 비밀번호 재설정 링크가 포함 된 이메일이 전송됩니다.', - 'reset_password_send_button' => '재설정 링크 보내기', - 'reset_password_sent_success' => ':email로 재설정 링크를 보냈습니다.', - 'reset_password_success' => '비밀번호가 재설정되었습니다.', - - 'email_reset_subject' => ':appName 암호를 재설정', - 'email_reset_text' => '귀하의 계정에 대한 비밀번호 재설정 요청을 받았기 때문에 본 이메일이 발송되었습니다.', - 'email_reset_not_requested' => '암호 재설정을 요청하지 않은 경우 더 이상의 조치는 필요하지 않습니다.', - - - /** - * Email Confirmation - */ - 'email_confirm_subject' => ':appName의 이메일 주소 확인', - 'email_confirm_greeting' => ':appName에 가입 ​​해 주셔서 감사합니다!', - 'email_confirm_text' => '다음 버튼을 눌러 이메일 주소를 확인하십시오', - 'email_confirm_action' => '이메일 주소를 확인', - 'email_confirm_send_error' => 'E메일 확인이 필요하지만 시스템에서 메일을 보낼 수 없습니다. 관리자에게 문의하여 메일이 제대로 설정되어 있는지 확인하십시오.', - 'email_confirm_success' => '메일 주소가 확인되었습니다.', - 'email_confirm_resent' => '확인 메일을 다시 보냈습니다. 받은 편지함을 확인하십시오.', - - 'email_not_confirmed' => '메일 주소가 확인되지 않습니다', - 'email_not_confirmed_text' => '메일 주소 확인이 완료되지 않습니다.', - 'email_not_confirmed_click_link' => '등록시 받은 이메일을 확인하고 확인 링크를 클릭하십시오.', - 'email_not_confirmed_resend' => '메일이 없으면 아래 양식을 통해 다시 제출하십시오.', - 'email_not_confirmed_resend_button' => '확인 메일을 다시 전송', -]; diff --git a/resources/lang/kr/common.php b/resources/lang/kr/common.php deleted file mode 100644 index e040c6e5a..000000000 --- a/resources/lang/kr/common.php +++ /dev/null @@ -1,68 +0,0 @@ - '취소', - 'confirm' => '확인', - 'back' => '뒤로', - 'save' => '저장', - 'continue' => '계속하기', - 'select' => '선택', - 'more' => '더보기', - - /** - * Form Labels - */ - 'name' => '이름', - 'description' => '설명', - 'role' => '역할', - 'cover_image' => '대표 이미지', - 'cover_image_description' => '이 이미지는 약 440x250px 정도의 크기여야 합니다.', - - /** - * Actions - */ - 'actions' => 'Actions', - 'view' => '뷰', - 'create' => '생성', - 'update' => '업데이트', - 'edit' => '수정', - 'sort' => '정렬', - 'move' => '이동', - 'copy' => '복사', - 'reply' => 'Reply', - 'delete' => '삭제', - 'search' => '검색', - 'search_clear' => '검색기록 삭제', - 'reset' => '초기화', - 'remove' => '제거', - 'add' => '추가', - - /** - * Misc - */ - 'deleted_user' => '삭제된 사용자', - 'no_activity' => '활동내역이 없음', - 'no_items' => '사용가능한 항목이 없음', - 'back_to_top' => '맨위로', - 'toggle_details' => '상세 토글', - 'toggle_thumbnails' => '썸내일 토글', - 'details' => '상세', - 'grid_view' => '그리드 뷰', - 'list_view' => '리스트뷰', - 'default' => '기본설정', - - /** - * Header - */ - 'view_profile' => '프로파일 보기', - 'edit_profile' => '프로파일 수정하기', - - /** - * Email Content - */ - 'email_action_help' => '":actionText"버튼을 클릭하는 데 문제가 있으면 아래 URL을 복사하여 웹 브라우저에 붙여 넣으십시오:', - 'email_rights' => 'All rights reserved', -]; \ No newline at end of file diff --git a/resources/lang/kr/components.php b/resources/lang/kr/components.php deleted file mode 100644 index ffb1f6bea..000000000 --- a/resources/lang/kr/components.php +++ /dev/null @@ -1,34 +0,0 @@ - '이미지 선택', - 'image_all' => '전체', - 'image_all_title' => '모든 이미지 보기', - 'image_book_title' => '이 책에 업로드된 이미지 보기', - 'image_page_title' => '이 페이지에 업로드된 이미지 보기', - 'image_search_hint' => '이미지 이름으로 검색', - 'image_uploaded' => ':uploadedDate에 업로드됨', - 'image_load_more' => '더 불러오기', - 'image_image_name' => '이미지 이름', - 'image_delete_used' => '이 이미지는 다음 페이지에서 이용되고 있습니다.', - 'image_delete_confirm' => '삭제해도 괜찮으시면 다시 삭제 버튼을 눌러주세요.', - 'image_select_image' => '선택', - 'image_dropzone' => '업로드를 위해 이미지를 가져와 놓거나 클릭하세요', - 'images_deleted' => '이미지 삭제', - 'image_preview' => '이미지 미리보기', - 'image_upload_success' => '이미지 업로드가 완료되었습니다.', - 'image_update_success' => '이미지 상세정보가 업데이트 되었습니다.', - 'image_delete_success' => '이미지가 삭제되었습니다.', - 'image_upload_remove' => '제거', - - /** - * Code editor - */ - 'code_editor' => '코드 수정', - 'code_language' => '코드 언어', - 'code_content' => '코드 내용', - 'code_save' => '코드 저장', -]; diff --git a/resources/lang/kr/entities.php b/resources/lang/kr/entities.php deleted file mode 100644 index 394027564..000000000 --- a/resources/lang/kr/entities.php +++ /dev/null @@ -1,311 +0,0 @@ - '최근작성', - 'recently_created_pages' => '최근 작성된 페이지', - 'recently_updated_pages' => '최근 업데이트된 페이지', - 'recently_created_chapters' => '최근 만들어진 챕터', - 'recently_created_books' => '최근 만들어진 책', - 'recently_update' => '최근 작성', - 'recently_viewed' => '검색 기록', - 'recent_activity' => '최근 활동', - 'create_now' => '지금 만들기', - 'revisions' => '변경이력', - 'meta_revision' => '수정 #:revisionCount', - 'meta_created' => '작성: :timeLength', - 'meta_created_name' => '작성: :timeLength by :user', - 'meta_updated' => '업데이트 :timeLength', - 'meta_updated_name' => '업데이트 :timeLength by :user', - 'entity_select' => '엔티티선택', - 'images' => '이미지', - 'my_recent_drafts' => '내 최근 초안', - 'my_recently_viewed' => '검색 기록', - 'no_pages_viewed' => '조회한 페이지가 없습니다.', - 'no_pages_recently_created' => '최근 만들어진 페이지가 없습니다', - 'no_pages_recently_updated' => '최근 업데이트된 페이지가없습니다', - 'export' => '내보내기', - 'export_html' => 'html 내보내기', - 'export_pdf' => 'PDF 파일', - 'export_text' => '일반 텍스트 파일', - - /** - * Permissions and restrictions - */ - 'permissions' => '권한', - 'permissions_intro' => '이 설정은 각 사용자의 역할보다 우선하여 적용됩니다.', - 'permissions_enable' => '커스텀 권한 활성화', - 'permissions_save' => '권한 저장', - - /** - * Search - */ - 'search_results' => '검색 결과', - 'search_total_results_found' => ':count 개의 결과를 찾았습니다.|총 :count 개의 결과를 찾았습니다.', - 'search_clear' => '검색기록 초기화', - 'search_no_pages' => '검색결과가 없습니다.', - 'search_for_term' => ':term 을(를) 검색합니다.', - 'search_more' => '결과 더보기', - 'search_filters' => '검색 필터', - 'search_content_type' => '컨텐츠 타입', - 'search_exact_matches' => '정확히 일치합니다.', - 'search_tags' => '테그 검색', - 'search_options' => '설정', - 'search_viewed_by_me' => '내가본것', - 'search_not_viewed_by_me' => '내가안본것', - 'search_permissions_set' => '권한 설정', - 'search_created_by_me' => '내가 만듦', - 'search_updated_by_me' => '내가 업데이트함', - 'search_date_options' => '날짜 설정', - 'search_updated_before' => '이전에 업데이트함', - 'search_updated_after' => '이후에 업데이트함', - 'search_created_before' => '이전에 생성함', - 'search_created_after' => '이후에 생성함', - 'search_set_date' => '날짜 설정', - 'search_update' => '검색 업데이트', - - /** - * Shelves - */ - 'shelf' => '책꽃이', - 'shelves' => '책꽃이', - 'shelves_long' => '책꽃이', - 'shelves_empty' => '책꽃이가 만들어지지 않았습니다.', - 'shelves_create' => '새책꽃이 만들기', - 'shelves_popular' => '인기있는 책꽃이', - 'shelves_new' => '새로운 책꽃이', - 'shelves_popular_empty' => '인기있는 책꽃이가 여기에 나타납니다.', - 'shelves_new_empty' => '가장 최근에 만들어진 책꽃이가 여기에 나타납니다.', - 'shelves_save' => '책꽃이 저장', - 'shelves_books' => '이 책꽃이에 있는 책', - 'shelves_add_books' => '이 책꽃이에 책을 추가합니다', - 'shelves_drag_books' => '이 책꽃이에 책을 추가하기 위해 끌어놓으세요.', - 'shelves_empty_contents' => '이책꽃이엔 등록된 책이 없습니다.', - 'shelves_edit_and_assign' => '책을 등록하기 위해 책꽃이를 수정', - 'shelves_edit_named' => ':name 책꽃이 수정', - 'shelves_edit' => '책꽃이 수정', - 'shelves_delete' => '책꽃이 삭제', - 'shelves_delete_named' => ':name 책꽃이를 삭제합니다.', - 'shelves_delete_explain' => "':name' 이름의 책꽃이가 삭제됩니다. 포함된 책은 삭제되지 않습니다.", - 'shelves_delete_confirmation' => '이 책꽃이를 삭제하시겠습니까?', - 'shelves_permissions' => '책꽃이 권한', - 'shelves_permissions_updated' => '책꽃이 권한이 업데이트 되었습니다.', - 'shelves_permissions_active' => '책꽃이 권한 활성화', - 'shelves_copy_permissions_to_books' => '책에 권한을 복사합니다.', - 'shelves_copy_permissions' => '권한 복사', - 'shelves_copy_permissions_explain' => '이 책꽂이의 현재 권한 설정이 안에 포함 된 모든 책에 적용됩니다. 활성화하기 전에이 책꽂이의 사용 권한이 변경되었는지 확인하십시오.', - 'shelves_copy_permission_success' => '책꽃이의 권한이 :count 개의 책에 복사되었습니다.', - - /** - * Books - */ - 'book' => '책', - 'books' => '책들', - 'x_books' => ':count 책|:count 책들', - 'books_empty' => '책이 만들어지지 않았습니다.', - 'books_popular' => '인기있는 책', - 'books_recent' => '최근 책', - 'books_new' => '새로운 책', - 'books_popular_empty' => '가장 인기있는 책이 여기에 보입니다.', - 'books_new_empty' => '가장 최근에 만든 책이 여기에 표시됩니다.', - 'books_create' => '새로운 책 만들기', - 'books_delete' => '책 삭제하기', - 'books_delete_named' => ':bookName 책 삭제하기', - 'books_delete_explain' => '\':bookName\' 이름의 책이 삭제됩니다. 모든 페이지와 챕터가 삭제됩니다.', - 'books_delete_confirmation' => '이 책을 삭제 하시겠습니까?', - 'books_edit' => '책 수정', - 'books_edit_named' => ':bookName 책 수정', - 'books_form_book_name' => '책 이름', - 'books_save' => '책 저장', - 'books_permissions' => '책 권한', - 'books_permissions_updated' => '책 권한이 업데이트 되었습니다.', - 'books_empty_contents' => '이 책에 대한 페이지 또는 장이 작성되지 않았습니다.', - 'books_empty_create_page' => '새로운 페이지 만들기', - 'books_empty_or' => '또는', - 'books_empty_sort_current_book' => '현제 책 정렬하기', - 'books_empty_add_chapter' => '챕터 추가하기', - 'books_permissions_active' => '책 권한 활성화', - 'books_search_this' => '이책 찾기', - 'books_navigation' => '책 네비게이션', - 'books_sort' => '책 구성 정렬하기', - 'books_sort_named' => ':bookName 책 정렬하기', - 'books_sort_show_other' => '다른책 보기', - 'books_sort_save' => '새로운 순서 저장', - - /** - * Chapters - */ - 'chapter' => '챕터', - 'chapters' => '챕터', - 'x_chapters' => ':count 개 챕터|:count 챔터들', - 'chapters_popular' => '인기있는 챕터', - 'chapters_new' => '새로운 챕처', - 'chapters_create' => '새로운 챕터 만들기', - 'chapters_delete' => '챕터 삭제', - 'chapters_delete_named' => ':chapterName 챕터 지우기', - 'chapters_delete_explain' => '\':chapterName\' 챕터를 지웁니다. 챕터에서 모든 페이지가 삭제되며 페이지가 상위 책에 추가됩니다.', - 'chapters_delete_confirm' => '정말로 챕터를 지우시겠습니따?', - 'chapters_edit' => '챕터 수정', - 'chapters_edit_named' => ':chapterName 챕터 수정', - 'chapters_save' => '챕터 저장', - 'chapters_move' => '챕터 이동', - 'chapters_move_named' => ':chapterName 챕터 이동', - 'chapter_move_success' => ':bookName 으로 챕터를 이동하였습니다.', - 'chapters_permissions' => '챕터 권한', - 'chapters_empty' => '챕터에 포함된 페이지가 없습니다.', - 'chapters_permissions_active' => '챕터 권한 활동', - 'chapters_permissions_success' => '챕터 권한 수정됨', - 'chapters_search_this' => '이 챕터 찾기', - - /** - * Pages - */ - 'page' => '페이지', - 'pages' => '페이지들', - 'x_pages' => ':count 개의 페이지|:count 개의 페이지들', - 'pages_popular' => '인기있는 페이지', - 'pages_new' => '새로운 페이지', - 'pages_attachments' => '첨부파일', - 'pages_navigation' => '페이지 네비게이션', - 'pages_delete' => '페이지 지우기', - 'pages_delete_named' => ':pageName 페이지 지우기', - 'pages_delete_draft_named' => ':pageName 초안 페이지 지우기', - 'pages_delete_draft' => '초안 페이지 지우기', - 'pages_delete_success' => '페이지 삭제됨', - 'pages_delete_draft_success' => '초안페이지 삭제됨', - 'pages_delete_confirm' => '정말로 이 페이지를 지우시겠습니까?', - 'pages_delete_draft_confirm' => '정말로 초안페이지를 지우시겠습니까?', - 'pages_editing_named' => ':pageName 페이지 수정', - 'pages_edit_toggle_header' => '헤더 숨김/보이기', - 'pages_edit_save_draft' => '초안 저장', - 'pages_edit_draft' => '페이지 초안 수정', - 'pages_editing_draft' => '초안 수정중', - 'pages_editing_page' => '페이지 수정중', - 'pages_edit_draft_save_at' => '초안이 저장됨 ', - 'pages_edit_delete_draft' => '초안 삭제', - 'pages_edit_discard_draft' => '초안 버리기', - 'pages_edit_set_changelog' => '변경내역 남기기', - 'pages_edit_enter_changelog_desc' => '어떤 내용에 대하여 변경하셨나요?', - 'pages_edit_enter_changelog' => '변경내역 입력', - 'pages_save' => '페이지 저장', - 'pages_title' => '페이지 제목', - 'pages_name' => '페이지 이름', - 'pages_md_editor' => '편집자', - 'pages_md_preview' => 'Preview', - 'pages_md_insert_image' => '이미지 삽입', - 'pages_md_insert_link' => '전체링크 입력', - 'pages_md_insert_drawing' => '드로잉 넣기', - 'pages_not_in_chapter' => '페이지가 챕터에 있지않습니다.', - 'pages_move' => '페이지 옮기기', - 'pages_move_success' => '":parentName"로 페이지를 이동하였습니다.', - 'pages_copy' => '페이지 복사', - 'pages_copy_desination' => '경로(desination) 복사', - 'pages_copy_success' => '페이지가 성공적으로 복사되었습니다', - 'pages_permissions' => '페이지 권한', - 'pages_permissions_success' => '페이지 권한이 업데이트 되었습니다.', - 'pages_revision' => '변경이력', - 'pages_revisions' => '페이지 변경이력', - 'pages_revisions_named' => ':pageName페이지의 변경이력내역', - 'pages_revision_named' => ':pageName페이지의 변경이력', - 'pages_revisions_created_by' => 'Created By', - 'pages_revisions_date' => '변경일', - 'pages_revisions_number' => '#', - 'pages_revisions_changelog' => '변경내역', - 'pages_revisions_changes' => '변경사항 보기', - 'pages_revisions_current' => '현재 버전', - 'pages_revisions_preview' => '미리보기', - 'pages_revisions_restore' => '되돌리기', - 'pages_revisions_none' => '이 페이지에는 변경이력이 없습니다.', - 'pages_copy_link' => '링크복사', - 'pages_edit_content_link' => '링크 수정', - 'pages_permissions_active' => '페이지 권한 활성화', - 'pages_initial_revision' => '최초 작성', - 'pages_initial_name' => '새 페이지', - 'pages_editing_draft_notification' => ':timeDiff 전에 저장된 초안을 최근 편집하셨습니다.', - 'pages_draft_edited_notification' => '이 페이지는 그 이후로 업데이트되었습니다. 이 초안을 폐기하는 것이 좋습니다.', - 'pages_draft_edit_active' => [ - 'start_a' => ':count명의 사용자가 이 페이지를 수정중입니다.', - 'start_b' => ':userName가(이) 페이지를 수정중입니다.', - 'time_a' => '페이지가 마지막으로 업데이트 된 이후', - 'time_b' => '지난 :minCount분 동안', - 'message' => ':start :time. 서로의 업데이트를 덮어 쓰지 않도록 주의하십시오!', - ], - 'pages_draft_discarded' => '초안이 삭제되었습니다. 편집기가 현재 페이지 작성자로 업데이트되었습니다.', - 'pages_specific' => '특정 페이지', - - /** - * Editor sidebar - */ - 'page_tags' => '페이지 테그', - 'chapter_tags' => '챕터 테그', - 'book_tags' => '책 테그', - 'shelf_tags' => '책꽃이 테그', - 'tag' => '테그', - 'tags' => '테그들', - 'tag_value' => '테그 값 (선택사항)', - 'tags_explain' => "컨텐츠를 더 잘 분류하기 위해 테그를 추가하세요! \n 보다 상세한 구성을 위해 태그값을 할당 할 수 있습니다.", - 'tags_add' => '다른 테그 추가', - 'attachments' => '첨부', - 'attachments_explain' => '일부 파일을 업로드하거나 페이지에 표시 할 링크를 첨부하십시오. 페이지 사이드 바에 표시됩니다.', - 'attachments_explain_instant_save' => '변경 사항은 즉시 저장됩니다.', - 'attachments_items' => '첨부된 항목', - 'attachments_upload' => '차일 업로드', - 'attachments_link' => '링크 첨부', - 'attachments_set_link' => '링크 설정', - 'attachments_delete_confirm' => '삭제를 다시 클릭하면 첨부파일이 완전히 삭제됩니다.', - 'attachments_dropzone' => '파일 놓기 또는 여기를 클릭하여 파일 첨부', - 'attachments_no_files' => '업로드 된 파일이 없습니다.', - 'attachments_explain_link' => '파일을 업로드하지 않으려는 경우 링크를 첨부 할 수 있습니다. 이 링크는 다른 페이지에 대한 링크이거나 클라우드에있는 파일에 대한 링크 일 수 있습니다.', - 'attachments_link_name' => '링크 이름', - 'attachment_link' => '첨부 링크', - 'attachments_link_url' => '파일로 첨부', - 'attachments_link_url_hint' => 'Url, 사이트 또는 파일', - 'attach' => '첨부', - 'attachments_edit_file' => '파일 수정', - 'attachments_edit_file_name' => '파일이름', - 'attachments_edit_drop_upload' => '파일을 놓거나 여기를 클릭하여 업로드 및 덮어 쓰기', - 'attachments_order_updated' => '첨부 순서 업데이트', - 'attachments_updated_success' => '첨부파일 상세내용 업데이트 성공', - 'attachments_deleted' => '첨부파일 삭제', - 'attachments_file_uploaded' => '파일이 성공적으로 업로드 되었습니다.', - 'attachments_file_updated' => '파일이 성공적으로 업데이트 되었습니다.', - 'attachments_link_attached' => '링크가 성공적으로 페이지에 첨부되었습니다.', - - /** - * Profile View - */ - 'profile_user_for_x' => ':time 전에 작성', - 'profile_created_content' => '생성한 컨텐츠', - 'profile_not_created_pages' => ':userName가 작성한 페이지가 없습니다.', - 'profile_not_created_chapters' => ':userName가 작성한 챕터가 없습니다.', - 'profile_not_created_books' => ':userName가 작성한 책이 없습니다.', - - /** - * Comments - */ - 'comment' => '코멘트', - 'comments' => '코멘트들', - 'comment_add' => '코멘트 추가', - 'comment_placeholder' => '여기에 코멘트를 남기세요', - 'comment_count' => '{0} 코멘트 없음|{1} 1개 코멘트|[2,*] :count개의 코멘트', - 'comment_save' => '코멘트 저장', - 'comment_saving' => '코멘트 저장중...', - 'comment_deleting' => '코멘트 삭제중...', - 'comment_new' => '새로운 코멘트', - 'comment_created' => '코멘트를 작성하였습니다. :createDiff', - 'comment_updated' => ':username이 코멘트를 수정하였습니다 :updateDiff', - 'comment_deleted_success' => '코멘트 삭제성공', - 'comment_created_success' => '코멘트 추가성공', - 'comment_updated_success' => '코멘트 업데이트 성공', - 'comment_delete_confirm' => '정말로 코멘트를 지우시겠습니까?', - 'comment_in_reply_to' => ':commentId 응답', - - /** - * Revision - */ - 'revision_delete_confirm' => '해당 개정판을 지우시겠습니까??', - 'revision_delete_success' => '개정판 삭제성공', - 'revision_cannot_delete_latest' => '최신버전은 지울수 없습니다.' -]; \ No newline at end of file diff --git a/resources/lang/kr/errors.php b/resources/lang/kr/errors.php deleted file mode 100644 index 59dbfda2b..000000000 --- a/resources/lang/kr/errors.php +++ /dev/null @@ -1,84 +0,0 @@ - '요청한 페이지에 권한이 없습니다.', - 'permissionJson' => '요청한 작업을 수행 할 권한이 없습니다.', - - // Auth - 'error_user_exists_different_creds' => '전자 메일 :email을 가진 사용자가 이미 존재하지만 자격 증명이 다릅니다.', - 'email_already_confirmed' => '이메일이 이미 확인되었습니다. 로그인 해주세요.', - 'email_confirmation_invalid' => '이 확인 토큰이 유효하지 않거나 이미 사용되었습니다. 다시 등록하세요.', - 'email_confirmation_expired' => '확인 토큰이 만료되었습니다. 새 확인 이메일이 전송되었습니다.', - 'ldap_fail_anonymous' => '익명 바인드를 이용한 LDAP 액세스에 실패하였습니다.', - 'ldap_fail_authed' => '주어진 dn 및 비밀번호 세부 정보를 사용하여 LDAP 액세스하는 것이 실패했습니다.', - 'ldap_extension_not_installed' => 'LDAP PHP 확장기능이 설치되지 않았습니다.', - 'ldap_cannot_connect' => 'LDAP 서버에 연결할 수 없습니다. 초기 연결에 실패했습니다.', - 'social_no_action_defined' => '동작이 정의되지 않았습니다.', - 'social_login_bad_response' => ":socialAccount 로그인에 실패하였습니다 : \n:error", - 'social_account_in_use' => '이 :socialAccount 계정이 이미 사용 중입니다. :socialAccount 옵션을 통해 로그인하십시오.', - 'social_account_email_in_use' => ' 이메일 :email이 이미 사용 중입니다. 이미 계정이있는 경우 프로필 설정에서 :socialAccount 계정을 연결할 수 있습니다.', - 'social_account_existing' => ':socialAccount가 이미 프로필에 첨부되어 있습니다.', - 'social_account_already_used_existing' => '이 :socialAccount 계정은 이미 다른 사용자가 사용하고 있습니다.', - 'social_account_not_used' => '이 :socialAccount 계정이 모든 사용자에게 연결되어 있지 않습니다. 프로필 설정에 첨부하십시오. ', - 'social_account_register_instructions' => '아직 계정이없는 경우 :socialAccount 옵션을 사용하여 계정을 등록 할 수 있습니다.', - 'social_driver_not_found' => '소셜 드라이버를 찾을 수 없음', - 'social_driver_not_configured' => '귀하의 :socialAccount 소셜 설정이 올바르게 구성되지 않았습니다.', - - // System - 'path_not_writable' => '파일 경로 :filePath에 업로드 할 수 없습니다. 서버에 쓰기 기능이 활성화 되어있는지 확인하세요.', - 'cannot_get_image_from_url' => ':url에서 이미지를 가져올 수 없습니다.', - 'cannot_create_thumbs' => '서버에서 썸네일을 생성할 수 없습니다. GD PHP확장기능이 설치되어있는지 확인하세요.', - 'server_upload_limit' => '해당 크기의 파일을 업로드하는것이 서버에서 제한됩니다. 파일 사이즈를 작게 줄이거나 서버 설정을 변경하세요.', - 'uploaded' => '해당 크기의 파일을 업로드하는것이 서버에서 제한됩니다. 파일 사이즈를 작게 줄이거나 서버 설정을 변경하세요.', - 'image_upload_error' => '이미지를 업로드하는 중에 오류가 발생했습니다.', - 'image_upload_type_error' => '업로드중인 이미지 유형이 잘못되었습니다.', - 'file_upload_timeout' => '파일 업로드가 시간 초과되었습니다.', - - // Attachments - 'attachment_page_mismatch' => '첨부 파일 업데이트 중 페이지 불일치하였습니다.', - 'attachment_not_found' => '첨부 파일을 찾을 수 없습니다.', - - // Pages - 'page_draft_autosave_fail' => '초안을 저장하지 못했습니다. 이 페이지를 저장하기 전에 인터넷에 연결되어 있는지 확인하십시오.', - 'page_custom_home_deletion' => '홈페이지로 설정되어있는 페이지는 삭제할 수 없습니다.', - - // Entities - 'entity_not_found' => '개체(Entity)를 찾을 수 없음.', - 'bookshelf_not_found' => '책꽂이를 찾을 수 없음.', - 'book_not_found' => '책을 찾을 수 없음.', - 'page_not_found' => '페이지를 찾을 수 없음.', - 'chapter_not_found' => '챕터를 찾을 수 없음.', - 'selected_book_not_found' => '선택한 책을 찾을 수 없습니다.', - 'selected_book_chapter_not_found' => '선택한 책 또는 챕터를 찾을 수 없습니다.', - 'guests_cannot_save_drafts' => '게스트는 임시저장을 할 수 없습니다.', - - // Users - 'users_cannot_delete_only_admin' => '어드민 계정은 삭제할 수 없습니다.', - 'users_cannot_delete_guest' => '게스트 사용자는 삭제할 수 없습니다.', - - // Roles - 'role_cannot_be_edited' => '역할을 수정할 수 없습니다.', - 'role_system_cannot_be_deleted' => '이 역할은 시스템 역할입니다. 삭제할 수 없습니다.', - 'role_registration_default_cannot_delete' => '이 역할은 기본 등록 역할로 설정되어있는 동안 삭제할 수 없습니다.', - - // Comments - 'comment_list' => '댓글을 가져 오는 중에 오류가 발생했습니다.', - 'cannot_add_comment_to_draft' => '초안에 주석을 추가 할 수 없습니다.', - 'comment_add' => '댓글을 추가 / 업데이트하는 중에 오류가 발생했습니다.', - 'comment_delete' => '댓글을 삭제하는 중에 오류가 발생했습니다.', - 'empty_comment' => '빈 주석을 추가 할 수 없습니다.', - - // Error pages - '404_page_not_found' => '페이지를 찾을 수 없습니다.', - 'sorry_page_not_found' => '죄송합니다, 찾고 있던 페이지를 찾을 수 없습니다.', - 'return_home' => 'home으로 가기', - 'error_occurred' => '오류가 발생하였습니다.', - 'app_down' => ':appName가 다운되었습니다.', - 'back_soon' => '곧 복구될 예정입니다.', -]; diff --git a/resources/lang/kr/pagination.php b/resources/lang/kr/pagination.php deleted file mode 100644 index d4a9eef40..000000000 --- a/resources/lang/kr/pagination.php +++ /dev/null @@ -1,19 +0,0 @@ - '« 이전', - 'next' => '다음 »', - -]; diff --git a/resources/lang/kr/passwords.php b/resources/lang/kr/passwords.php deleted file mode 100644 index de49b1f8b..000000000 --- a/resources/lang/kr/passwords.php +++ /dev/null @@ -1,22 +0,0 @@ - '비밀번호는 6자 이상이어야 하며 확인과 일치해야 합니다.', - 'user' => "해당 이메일 주소의 사용자가 없습니다.", - 'token' => '해당 비밀번호의 초기화 토큰이 만료되었습니다.', - 'sent' => '페스워드 초기화 링크를 메일로 보냈습니다!', - 'reset' => '비밀번호가 초기화 되었습니다!', - -]; diff --git a/resources/lang/kr/settings.php b/resources/lang/kr/settings.php deleted file mode 100755 index 61b315cab..000000000 --- a/resources/lang/kr/settings.php +++ /dev/null @@ -1,124 +0,0 @@ - '설정', - 'settings_save' => '설정 저장', - 'settings_save_success' => '설정이 저장되었습니다.', - - /** - * App settings - */ - - 'app_settings' => '앱 설정', - 'app_name' => '어플리케이션 이름', - 'app_name_desc' => '해당 이름은 헤더와 모든 이메일에 표시됩니다.', - 'app_name_header' => '헤더에 어플리케이션 이름을 표시하시겠습니까?', - 'app_public_viewing' => '공개 보기를 허용하시겠습니까?', - 'app_secure_images' => '더 높은 보안 이미지 업로드를 사용하시겠습니까?', - 'app_secure_images_desc' => '성능상의 이유로 모든 이미지를 공개합니다. 해당 옵션은 이미지 URL 앞에 추측하기 어려운 임의의 문자열을 추가합니다. 간편한 접근을 방지하기 위해 디렉토리 색인을 비활성화하십시오.', - 'app_editor' => '페이지 에디터', - 'app_editor_desc' => '모든 사용자가 페이지를 편집하는데 사용할 에디터를 선택하십시오.', - 'app_custom_html' => '사용자 정의 HTML 헤드 컨텐츠', - 'app_custom_html_desc' => '여기에 추가된 모든 내용은 모든 페이지의 섹션 아래쪽에 삽입됩니다. 이는 스타일 오버라이딩이나 분석 코드 삽입에 편리합니다.', - 'app_logo' => '어플리케이션 로고', - 'app_logo_desc' => '해당 이미지는 반드시 높이가 43픽셀이어야 합니다.
대용량 이미지는 축소됩니다.', - 'app_primary_color' => '어플리케이션 기본 색상', - 'app_primary_color_desc' => '해당 값은 16진수이어야 합니다.
입력하지 않으면 기본 색상으로 재설정됩니다.', - 'app_homepage' => '어플리케이션 홈페이지', - 'app_homepage_desc' => '기본 화면 대신에 홈페이지에 표시할 화면을 선택하십시오. 선택된 페이지에서는 페이지 권한이 무시됩니다.', - 'app_homepage_select' => '페이지를 선택하십시오', - 'app_disable_comments' => '주석 비활성화', - 'app_disable_comments_desc' => '어플리케이션의 모든 페이지에서 주석을 비활성화합니다. 기존의 주석은 표시되지 않습니다.', - /** - * Registration settings - */ - 'reg_settings' => '등록 설정', - 'reg_allow' => '등록을 허가하시겠습니까?', - 'reg_default_role' => '등록 후 기본 사용자 역할', - 'reg_confirm_email' => '이메일 확인을 요구하시겠습니까?', - 'reg_confirm_email_desc' => '도메인 제한이 사용되면 이메일 확인이 요구되며, 하단의 값은 무시됩니다.', - 'reg_confirm_restrict_domain' => '도메인 등록 제한', - 'reg_confirm_restrict_domain_desc' => '등록을 제한할 이메일 도메인의 목록을 쉼표로 구분하여 입력해주십시오. 사용자는 어플리케이션과의 상호작용을 허가받기 전에 이메일 주소를 확인하는 이메일을 받게 됩니다,
등록이 완료된 후에는 이메일 주소를 변경할 수 있습니다.', - 'reg_confirm_restrict_domain_placeholder' => '제한 없음 설정', - /** - * Maintenance settings - */ - - 'maint' => 'Maintenance', - 'maint_image_cleanup' => '이미지 정리', - 'maint_image_cleanup_desc' => "페이지를 스캔하여 현재 사용중인 이미지와 도면에서 수정된 내용 및 중복된 이미지를 확인합니다. 이를 실행하기 전에 전체 데이터베이스와 이미지의 백업을 작성했는지 확인하십시오.", - 'maint_image_cleanup_ignore_revisions' => '수정본의 이미지를 무시합니다.', - 'maint_image_cleanup_run' => '정리 실행', - 'maint_image_cleanup_warning' => '잠재적으로 사용되지 않는 이미지를 찾았습니다. 해당 이미지들을 삭제하시겠습니까?', - 'maint_image_cleanup_success' => ':잠재적으로 사용되지 않는 이미지들이 삭제되었습니다.', - 'maint_image_cleanup_nothing_found' => '사용되지 않는 이미지를 찾을 수 없습니다. 아무것도 삭제되지 않았습니다.', - /** - * Role settings - */ - 'roles' => '역할', - 'role_user_roles' => '사용자 역할', - 'role_create' => '신규 역할 생성', - 'role_create_success' => '역할이 생성되었습니다.', - 'role_delete' => '역할을 삭제합니다.', - 'role_delete_confirm' => '\':roleName\'(이)라는 이름의 역할이 삭제됩니다.', - 'role_delete_users_assigned' => '해당 역할에 :userCount 명의 사용자가 할당되어 있습니다. 이 역할로부터 사용자를 재할당하고 싶다면 아래에서 새 역할을 선택하십시오.', - 'role_delete_no_migration' => "사용자 재배치 안함", - 'role_delete_sure' => '이 역할을 삭제하시겠습니까?', - 'role_delete_success' => '역할이 삭제되었습니다.', - 'role_edit' => '역할 편집', - 'role_details' => '역할 상세정보', - 'role_name' => '역할명', - 'role_desc' => '역할에 대한 간략한 설명', - 'role_external_auth_id' => '외부 인증 ID', - 'role_system' => '시스템 권한', - 'role_manage_users' => '사용자 관리', - 'role_manage_roles' => '역할 및 역할 권한 관리', - 'role_manage_entity_permissions' => '모든 책, 챕터, 페이지 관리', - 'role_manage_own_entity_permissions' => '보유한 책, 챕터, 페이지에 대한 권한 관리', - 'role_manage_settings' => '어플리케이선 설정 관리', - 'role_asset' => '자산 관리', - 'role_asset_desc' => '해당 권한들은 시스템 내의 Assets 파일에 대한 기본적인 접근을 제어합니다.', - 'role_asset_admins' => '관리자는 모든 컨텐츠에 대한 접근 권한을 자동으로 부여받지만, 해당 옵션들은 UI 옵션을 표시하거나 숨길 수 있습니다.', - 'role_all' => '전체', - 'role_own' => '보유한 것만', - 'role_controlled_by_asset' => '업로드된 Assets 파일에 의해 제어됩니다.', - 'role_save' => '역할 저장', - 'role_update_success' => '역할이 업데이트되었습니다.', - 'role_users' => '해당 역할의 사용자', - 'role_users_none' => '현재 이 역할에 할당된 사용자가 없습니다.', - /** - * Users - */ - 'users' => '사용자', - 'user_profile' => '사용자 프로필', - 'users_add_new' => '사용자 추가', - 'users_search' => '사용자 검색', - 'users_role' => '사용자 역할', - 'users_external_auth_id' => '외부 인증 ID', - 'users_password_warning' => '비밀번호를 변경하시려면 다음을 입력하십시오:', - 'users_system_public' => '이 사용자는 당신의 인스턴스를 방문하는 게스트 사용자를 나타냅니다. 로그인하는 데는 사용할 수 없지만 자동으로 할당됩니다.', - 'users_delete' => '사용자 삭제', - 'users_delete_named' => '사용자 :userName 삭제', - 'users_delete_warning' => '시스템에서 \':userName\'(이)라는 사용자가 완전히 삭제됩니다.', - 'users_delete_confirm' => '이 사용자를 삭제하시겠습니까?', - 'users_delete_success' => '사용자가 삭제되었습니다.', - 'users_edit' => '사용자 편집', - 'users_edit_profile' => '프로필 편집', - 'users_edit_success' => '사용자가 업데이트되었습니다.', - 'users_avatar' => '사용자 아바타', - 'users_avatar_desc' => '해당 이미지는 256픽셀의 정사각형 이미지여야합니다.', - 'users_preferred_language' => '선호하는 언어', - 'users_social_accounts' => '소셜 계정', - 'users_social_accounts_info' => '여기에서 다른 계정을 연결하여 더 빠르고 쉽게 로그인할 수 있습니다. 여기에서 계정 연결을 해제하면 이전에 승인된 접근이 제공되지 않습니다 연결된 소셜 계정의 프로필 설정에서 접근 권한을 취소하십시오.', - 'users_social_connect' => '계정 연결', - 'users_social_disconnect' => '계정 연결 해제', - 'users_social_connected' => ':socialAccount 계정이 당신의 프로필에 연결되었습니다.', - 'users_social_disconnected' => ':socialAccount 계정이 당신의 프로필에서 연결해제되었습니다.', -]; \ No newline at end of file diff --git a/resources/lang/kr/validation.php b/resources/lang/kr/validation.php deleted file mode 100644 index aa2916ae4..000000000 --- a/resources/lang/kr/validation.php +++ /dev/null @@ -1,108 +0,0 @@ - ':attribute가 반드시 허용되어야 합니다.', - 'active_url' => ':attribute가 올바른 URL이 아닙니다.', - 'after' => ':attribute는 :date이후 날짜여야 합니다.', - 'alpha' => ':attribute는 문자만 포함해야 합니다.', - 'alpha_dash' => ':attribute는 문자, 숫자, 대시만 포함해야 합니다.', - 'alpha_num' => ':attribute는 문자와 숫자만 포함됩니다.', - 'array' => ':attribute는 배열이어야 합니다.', - 'before' => ':attribute는 :date이전 날짜여야 합니다.', - 'between' => [ - 'numeric' => ':attribute는 반드시 :min이상 :max이하여야 합니다.', - 'file' => ':attribute는 반드시 :min이상 :max kilobytes이하여야 합니다.', - 'string' => ':attribute는 반드시 :min이상 :max 문자 이하여야 합니다.', - 'array' => ':attribute는 반드시 :min이상 :max이하 항목이어야 합니다.', - ], - 'boolean' => ':attribute 는 true혹은 false값만 가능합니다.', - 'confirmed' => ':attribute 확인이 일치하지 않습니다.', - 'date' => ':attribute 는 잘못된 날짜입니다.', - 'date_format' => ':attribute 이 :format 포멧과 일치하지 않습니다.', - 'different' => ':attribute 와 :other는 반드시 달라야 합니다.', - 'digits' => ':attribute 는 반드시 :digits 숫자(digit)여야 합니다.', - 'digits_between' => ':attribute 는 반드시 :min이상 :max이하 숫자여야 합니다.', - 'email' => ':attribute 는 반드시 이메일 이어야 합니다.', - 'filled' => ':attribute 항목이 꼭 필요합니다.', - 'exists' => '선택된 :attribute 은(는) 사용 불가합니다.', - 'image' => ':attribute 는 반드시 이미지여야 합니다.', - 'in' => '선택된 :attribute 은(는) 사용 불가합니다.', - 'integer' => ':attribute 는 반드시(integer)여야 합니다.', - 'ip' => ':attribute 는 반드시 IP주소 여야 합니다.', - 'max' => [ - 'numeric' => ':attribute :max 보다 크면 안됩니다.', - 'file' => ':attribute :max kilobytes보다 크면 안됩니다.', - 'string' => ':attribute :max 문자보다 길면 안됩니다.', - 'array' => ':attribute :max 를 초과하면 안됩니다.', - ], - 'mimes' => ':attribute 은(는) 반드시 :values 타입이어야 합니다.', - 'min' => [ - 'numeric' => ':attribute 은(는) 최소한 :min 이어야 합니다.', - 'file' => ':attribute 은(는) 최소한 :min kilobytes여야 합니다.', - 'string' => ':attribute 은(는) 최소한 :min 개 문자여야 합니다.', - 'array' => ':attribute 은(는) 적어도 :min 개의 항목이어야 합니다.', - ], - 'not_in' => '선택된 :attribute 는 사용할 수 없습니다', - 'numeric' => ':attribute 반드시 숫자여야 합니다.', - 'regex' => ':attribute 포멧이 잘못되었습니다.', - 'required' => ':attribute 항목은 필수입니다..', - 'required_if' => ':attribute 은(는) :other 가 :value 일때 필수항목입니다.', - 'required_with' => ':attribute 은(는) :values 가 있을때 필수항목입니다.', - 'required_with_all' => ':attribute 은(는) :values 가 있을때 필수항목입니다.', - 'required_without' => ':attribute 은(는) :values 가 없을때 필수항목입니다.', - 'required_without_all' => ':attribute 은(는) :values 가 전혀 없을때 필수항목입니다.', - 'same' => ':attribute 와 :other 은(는) 반드시 일치해야합니다.', - 'size' => [ - 'numeric' => ':attribute 은(는) :size 여야합니다.', - 'file' => ':attribute 은(는) :size kilobytes여야합니다.', - 'string' => ':attribute 은(는) :size 문자여야합니다.', - 'array' => ':attribute 은(는) :size 개 항목을 포함해야 합니다.', - ], - 'string' => ':attribute 문자열이어야 합니다.', - 'timezone' => ':attribute 정상적인 지역(zone)이어야 합니다.', - 'unique' => ':attribute 은(는) 이미 사용중입니다..', - 'url' => ':attribute 포멧이 사용 불가합니다.', - - /* - |-------------------------------------------------------------------------- - | Custom Validation Language Lines - |-------------------------------------------------------------------------- - | - | Here you may specify custom validation messages for attributes using the - | convention "attribute.rule" to name the lines. This makes it quick to - | specify a specific custom language line for a given attribute rule. - | - */ - - 'custom' => [ - 'password-confirm' => [ - 'required_with' => '비밀번호 확인이 필요합니다.', - ], - ], - - /* - |-------------------------------------------------------------------------- - | Custom Validation Attributes - |-------------------------------------------------------------------------- - | - | The following language lines are used to swap attribute place-holders - | with something more reader friendly such as E-Mail Address instead - | of "email". This simply helps us make messages a little cleaner. - | - */ - - 'attributes' => [], - -]; diff --git a/resources/lang/nl/activities.php b/resources/lang/nl/activities.php index 021b6d21e..762728881 100644 --- a/resources/lang/nl/activities.php +++ b/resources/lang/nl/activities.php @@ -1,12 +1,10 @@ 'maakte pagina', 'page_create_notification' => 'Pagina Succesvol Aangemaakt', @@ -36,9 +34,9 @@ return [ 'book_delete_notification' => 'Boek Succesvol Verwijderd', 'book_sort' => 'sorteerde boek', 'book_sort_notification' => 'Boek Succesvol Gesorteerd', - + // Bookshelves - 'bookshelf_create' => 'maakte Boekenplank', + 'bookshelf_create' => 'maakte Boekenplank', 'bookshelf_create_notification' => 'Boekenplank Succesvol Aangemaakt', 'bookshelf_update' => 'veranderde boekenplank', 'bookshelf_update_notification' => 'Boekenplank Succesvol Bijgewerkt', @@ -46,5 +44,5 @@ return [ 'bookshelf_delete_notification' => 'Boekenplank Succesvol Verwijderd', // Other - 'commented_on' => 'reactie op', + 'commented_on' => 'reactie op', ]; diff --git a/resources/lang/nl/auth.php b/resources/lang/nl/auth.php index 31bd330cc..c691bf6b5 100644 --- a/resources/lang/nl/auth.php +++ b/resources/lang/nl/auth.php @@ -1,38 +1,34 @@ 'Deze inloggegevens zijn niet bij ons bekend.', 'throttle' => 'Te veel loginpogingen! Probeer het opnieuw na :seconds seconden.', - /** - * Login & Register - */ + // Login & Register 'sign_up' => 'Registreren', - 'log_in' => 'Log in', + 'log_in' => 'Inloggen', 'log_in_with' => 'Login met :socialDriver', 'sign_up_with' => 'Registreer met :socialDriver', 'logout' => 'Uitloggen', 'name' => 'Naam', 'username' => 'Gebruikersnaam', - 'email' => 'Email', + 'email' => 'E-mail', 'password' => 'Wachtwoord', 'password_confirm' => 'Wachtwoord Bevestigen', - 'password_hint' => 'Minimaal 6 tekens', + 'password_hint' => 'Minimaal 8 tekens', 'forgot_password' => 'Wachtwoord vergeten?', 'remember_me' => 'Mij onthouden', 'ldap_email_hint' => 'Geef een email op waarmee je dit account wilt gebruiken.', 'create_account' => 'Account Aanmaken', - 'social_login' => 'Social Login', + 'already_have_account' => 'Heb je al een account?', + 'dont_have_account' => 'Nog geen account?', + 'social_login' => 'Aanmelden via een sociaal netwerk', 'social_registration' => 'Social Registratie', 'social_registration_text' => 'Registreer en log in met een andere dienst.', @@ -43,23 +39,18 @@ return [ 'register_success' => 'Bedankt voor het inloggen. Je bent ook geregistreerd.', - /** - * Password Reset - */ + // Password Reset 'reset_password' => 'Wachtwoord Herstellen', 'reset_password_send_instructions' => 'Geef je e-mail en we sturen je een link om je wachtwoord te herstellen', 'reset_password_send_button' => 'Link Sturen', 'reset_password_sent_success' => 'Een link om je wachtwoord te herstellen is verstuurd naar :email.', 'reset_password_success' => 'Je wachtwoord is succesvol hersteld.', - 'email_reset_subject' => 'Herstel je wachtwoord van :appName', 'email_reset_text' => 'Je ontvangt deze e-mail zodat je je wachtwoord kunt herstellen.', 'email_reset_not_requested' => 'Als je jouw wachtwoord niet wilt wijzigen, doe dan niets.', - /** - * Email Confirmation - */ + // Email Confirmation 'email_confirm_subject' => 'Bevestig je e-mailadres op :appName', 'email_confirm_greeting' => 'Bedankt voor je aanmelding op :appName!', 'email_confirm_text' => 'Bevestig je registratie door op onderstaande knop te drukken:', @@ -73,4 +64,14 @@ return [ 'email_not_confirmed_click_link' => 'Klik op de link in de e-mail die vlak na je registratie is verstuurd.', 'email_not_confirmed_resend' => 'Als je deze e-mail niet kunt vinden kun je deze met onderstaande formulier opnieuw verzenden.', 'email_not_confirmed_resend_button' => 'Bevestigingsmail Opnieuw Verzenden', -]; + + // User Invite + 'user_invite_email_subject' => 'Je bent uitgenodigd voor :appName!', + 'user_invite_email_greeting' => 'Er is een account voor je aangemaakt op :appName.', + 'user_invite_email_text' => 'Klik op de onderstaande knop om een account wachtwoord in te stellen en toegang te krijgen:', + 'user_invite_email_action' => 'Account wachtwoord instellen', + 'user_invite_page_welcome' => 'Welkom bij :appName!', + 'user_invite_page_text' => 'Om je account af te ronden en toegang te krijgen moet je een wachtwoord instellen dat gebruikt wordt om in te loggen op :appName bij toekomstige bezoeken.', + 'user_invite_page_confirm_button' => 'Bevestig wachtwoord', + 'user_invite_success' => 'Wachtwoord ingesteld, je hebt nu toegang tot :appName!' +]; \ No newline at end of file diff --git a/resources/lang/nl/common.php b/resources/lang/nl/common.php index d44bd514d..01e9969ef 100644 --- a/resources/lang/nl/common.php +++ b/resources/lang/nl/common.php @@ -1,7 +1,9 @@ 'Annuleren', 'confirm' => 'Bevestigen', @@ -11,7 +13,7 @@ return [ 'select' => 'Kies', 'toggle_all' => 'Toggle Alles', 'more' => 'Meer', - + // Form Labels 'name' => 'Naam', 'description' => 'Beschrijving', @@ -24,7 +26,7 @@ return [ 'view' => 'Bekijk', 'view_all' => 'Bekijk Alle', 'create' => 'Aanmaken', - 'update' => 'Update', + 'update' => 'Bijwerken', 'edit' => 'Bewerk', 'sort' => 'Sorteer', 'move' => 'Verplaats', @@ -36,12 +38,17 @@ return [ 'reset' => 'Reset', 'remove' => 'Verwijderen', 'add' => 'Toevoegen', + 'fullscreen' => 'Volledig scherm', // Sort Options + 'sort_options' => 'Sorteeropties', + 'sort_direction_toggle' => 'Sorteer richting', + 'sort_ascending' => 'Sorteer oplopend', + 'sort_descending' => 'Sorteer teruglopend', 'sort_name' => 'Naam', 'sort_created_at' => 'Aanmaakdatum', 'sort_updated_at' => 'Gewijzigd op', - + // Misc 'deleted_user' => 'Verwijderde gebruiker', 'no_activity' => 'Geen activiteiten', @@ -53,20 +60,18 @@ return [ 'grid_view' => 'Grid weergave', 'list_view' => 'Lijst weergave', 'default' => 'Standaard', + 'breadcrumb' => 'Kruimelpad', - /** - * Header - */ + // Header + 'profile_menu' => 'Profiel menu', 'view_profile' => 'Profiel Weergeven', 'edit_profile' => 'Profiel Bewerken', // Layout tabs 'tab_info' => 'Info', 'tab_content' => 'Inhoud', - - /** - * Email Content - */ + + // 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', ]; diff --git a/resources/lang/nl/components.php b/resources/lang/nl/components.php index 576298ef2..4083b57be 100644 --- a/resources/lang/nl/components.php +++ b/resources/lang/nl/components.php @@ -1,16 +1,17 @@ 'Selecteer Afbeelding', + // Image Manager + 'image_select' => 'Afbeelding selecteren', 'image_all' => 'Alles', 'image_all_title' => 'Alle afbeeldingen weergeven', 'image_book_title' => 'Afbeeldingen van dit boek weergeven', 'image_page_title' => 'Afbeeldingen van deze pagina weergeven', 'image_search_hint' => 'Zoek op afbeeldingsnaam', - 'image_uploaded' => 'Uploaded :uploadedDate', + 'image_uploaded' => 'Geüpload :uploadedDate', 'image_load_more' => 'Meer Laden', 'image_image_name' => 'Afbeeldingsnaam', 'image_delete_used' => 'Deze afbeeldingen is op onderstaande pagina\'s in gebruik.', @@ -22,9 +23,9 @@ return [ 'image_upload_success' => 'Afbeelding succesvol geüpload', 'image_update_success' => 'Afbeeldingsdetails succesvol verwijderd', 'image_delete_success' => 'Afbeelding succesvol verwijderd', - /** - * Code editor - */ + 'image_upload_remove' => 'Verwijderen', + + // Code Editor 'code_editor' => 'Code invoegen', 'code_language' => 'Code taal', 'code_content' => 'Code', diff --git a/resources/lang/nl/entities.php b/resources/lang/nl/entities.php index 34142ad7f..bcd069053 100644 --- a/resources/lang/nl/entities.php +++ b/resources/lang/nl/entities.php @@ -1,14 +1,17 @@ 'Recent Aangemaakt', 'recently_created_pages' => 'Recent Aangemaakte Pagina\'s', 'recently_updated_pages' => 'Recent Bijgewerkte Pagina\'s', 'recently_created_chapters' => 'Recent Aangemaakte Hoofdstukken', 'recently_created_books' => 'Recent Aangemaakte Boeken', + 'recently_created_shelves' => 'Recently Created Shelves', 'recently_update' => 'Recent Bijgewerkt', 'recently_viewed' => 'Recent Bekeken', 'recent_activity' => 'Recente Activiteit', @@ -19,7 +22,6 @@ return [ 'meta_created_name' => 'Aangemaakt: :timeLength door :user', 'meta_updated' => ':timeLength Aangepast', 'meta_updated_name' => 'Aangepast: :timeLength door :user', - 'x_pages' => ':count Pagina\'s', 'entity_select' => 'Entiteit Selecteren', 'images' => 'Afbeeldingen', 'my_recent_drafts' => 'Mijn Concepten', @@ -32,17 +34,13 @@ return [ 'export_pdf' => 'PDF File', 'export_text' => 'Plain Text File', - /** - * Permissions and restrictions - */ + // Permissions and restrictions 'permissions' => 'Permissies', 'permissions_intro' => 'Als je dit aanzet, dan gelden rol-permissies niet meer voor deze pagina.', 'permissions_enable' => 'Custom Permissies Aanzetten', 'permissions_save' => 'Permissies Opslaan', - /** - * Search - */ + // Search 'search_results' => 'Zoekresultaten', 'search_total_results_found' => ':count resultaten gevonden|:count resultaten gevonden', 'search_clear' => 'Zoekopdracht wissen', @@ -53,11 +51,13 @@ return [ 'search_content_type' => 'Content Type', 'search_exact_matches' => 'Exacte Matches', 'search_tags' => 'Zoek tags', + 'search_options' => 'Options', 'search_viewed_by_me' => 'Bekeken door mij', 'search_not_viewed_by_me' => 'Niet bekeken door mij', 'search_permissions_set' => 'Permissies gezet', 'search_created_by_me' => 'Door mij gemaakt', 'search_updated_by_me' => 'Door mij geupdate', + 'search_date_options' => 'Date Options', 'search_updated_before' => 'Geupdate voor', 'search_updated_after' => 'Geupdate na', 'search_created_before' => 'Gecreeerd voor', @@ -74,6 +74,7 @@ return [ 'shelves_create' => 'Nieuwe Boekenplank Aanmaken', 'shelves_popular' => 'Populaire Boekenplanken', 'shelves_new' => 'Nieuwe Boekenplanken', + 'shelves_new_action' => 'New Shelf', 'shelves_popular_empty' => 'De meest populaire boekenplanken worden hier weergegeven.', 'shelves_new_empty' => 'De meest recent aangemaakt boekenplanken worden hier weergeven.', 'shelves_save' => 'Boekenplanken Opslaan', @@ -95,7 +96,7 @@ return [ 'shelves_copy_permissions' => 'Kopieer Permissies', 'shelves_copy_permissions_explain' => 'Met deze actie worden de permissies van deze boekenplank gekopieerd naar alle boeken op de plank. Voordat deze actie wordt uitgevoerd, zorg dat de wijzigingen in de permissies van deze boekenplank zijn opgeslagen.', 'shelves_copy_permission_success' => 'Boekenplank permissies gekopieerd naar :count boeken', - + // Books 'book' => 'Boek', 'books' => 'Boeken', @@ -104,7 +105,9 @@ return [ 'books_popular' => 'Populaire Boeken', 'books_recent' => 'Recente Boeken', 'books_new' => 'Nieuwe Boeken', + 'books_new_action' => 'New Book', 'books_popular_empty' => 'De meest populaire boeken worden hier weergegeven.', + 'books_new_empty' => 'The most recently created books will appear here.', 'books_create' => 'Nieuw Boek Aanmaken', 'books_delete' => 'Boek Verwijderen', 'books_delete_named' => 'Verwijder Boek :bookName', @@ -118,7 +121,6 @@ return [ 'books_permissions_updated' => 'Boek Permissies Opgeslagen', 'books_empty_contents' => 'Er zijn nog een hoofdstukken en pagina\'s voor dit boek gemaakt.', 'books_empty_create_page' => 'Pagina Toevoegen', - 'books_empty_or' => 'of', 'books_empty_sort_current_book' => 'Boek sorteren', 'books_empty_add_chapter' => 'Hoofdstuk Toevoegen', 'books_permissions_active' => 'Boek Permissies Actief', @@ -126,12 +128,15 @@ return [ 'books_navigation' => 'Boek Navigatie', 'books_sort' => 'Inhoud van het boek sorteren', 'books_sort_named' => 'Sorteer Boek :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' => 'Bekijk Andere Boeken', 'books_sort_save' => 'Nieuwe Order Opslaan', - /** - * Chapters - */ + // Chapters 'chapter' => 'Hoofdstuk', 'chapters' => 'Hoofdstukken', 'x_chapters' => ':count Hoofdstuk|:count Hoofdstukken', @@ -155,9 +160,7 @@ return [ 'chapters_permissions_success' => 'Hoofdstuk Permissies Bijgewerkt', 'chapters_search_this' => 'Doorzoek dit hoofdstuk', - /** - * Pages - */ + // Pages 'page' => 'Pagina', 'pages' => 'Pagina\'s', 'x_pages' => ':count Pagina|:count Pagina\'s', @@ -174,7 +177,7 @@ return [ 'pages_delete_confirm' => 'Weet je zeker dat je deze pagina wilt verwijderen?', 'pages_delete_draft_confirm' => 'Weet je zeker dat je dit concept wilt verwijderen?', 'pages_editing_named' => 'Pagina :pageName Bewerken', - 'pages_edit_toggle_header' => 'Wissel header', + 'pages_edit_draft_options' => 'Draft Options', 'pages_edit_save_draft' => 'Concept opslaan', 'pages_edit_draft' => 'Paginaconcept Bewerken', 'pages_editing_draft' => 'Concept Bewerken', @@ -192,9 +195,13 @@ return [ 'pages_md_preview' => 'Voorbeeld', 'pages_md_insert_image' => 'Afbeelding Invoegen', 'pages_md_insert_link' => 'Entity Link Invoegen', + 'pages_md_insert_drawing' => 'Insert Drawing', 'pages_not_in_chapter' => 'Deze pagina staat niet in een hoofdstuk', 'pages_move' => 'Pagina Verplaatsten', 'pages_move_success' => 'Pagina verplaatst naar ":parentName"', + 'pages_copy' => 'Copy Page', + 'pages_copy_desination' => 'Copy Destination', + 'pages_copy_success' => 'Page successfully copied', 'pages_permissions' => 'Pagina Permissies', 'pages_permissions_success' => 'Pagina Permissies bijgwerkt', 'pages_revision' => 'Revisie', @@ -204,6 +211,8 @@ return [ 'pages_revisions_created_by' => 'Aangemaakt door', 'pages_revisions_date' => 'Revisiedatum', 'pages_revisions_number' => '#', + 'pages_revisions_numbered' => 'Revision #:id', + 'pages_revisions_numbered_changes' => 'Revision #:id Changes', 'pages_revisions_changelog' => 'Changelog', 'pages_revisions_changes' => 'Wijzigingen', 'pages_revisions_current' => 'Huidige Versie', @@ -225,16 +234,21 @@ return [ 'message' => ':start :time. Take care not to overwrite each other\'s updates!', ], 'pages_draft_discarded' => 'Draft discarded, The editor has been updated with the current page content', + 'pages_specific' => 'Specific Page', + 'pages_is_template' => 'Page Template', - /** - * Editor sidebar - */ + // Editor Sidebar 'page_tags' => 'Pagina Labels', + 'chapter_tags' => 'Chapter Tags', + 'book_tags' => 'Book Tags', + 'shelf_tags' => 'Shelf Tags', 'tag' => 'Label', - 'tags' => '', + 'tags' => 'Tags', + 'tag_name' => 'Tag Name', 'tag_value' => 'Label Waarde (Optioneel)', 'tags_explain' => "Voeg labels toe om de inhoud te categoriseren. \n Je kunt meerdere labels toevoegen.", 'tags_add' => 'Voeg een extra label toe', + 'tags_remove' => 'Remove this tag', 'attachments' => 'Bijlages', 'attachments_explain' => 'Upload bijlages of voeg een link toe. Deze worden zichtbaar in het navigatiepaneel.', 'attachments_explain_instant_save' => 'Wijzigingen worden meteen opgeslagen.', @@ -260,21 +274,25 @@ return [ 'attachments_file_uploaded' => 'Bestand succesvol geüpload', 'attachments_file_updated' => 'Bestand succesvol bijgewerkt', 'attachments_link_attached' => 'Link successfully gekoppeld aan de pagina', + '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 View 'profile_user_for_x' => 'Lid sinds :time', 'profile_created_content' => 'Aangemaakte Inhoud', 'profile_not_created_pages' => ':userName heeft geen pagina\'s gemaakt', 'profile_not_created_chapters' => ':userName heeft geen hoofdstukken gemaakt', 'profile_not_created_books' => ':userName heeft geen boeken gemaakt', + 'profile_not_created_shelves' => ':userName has not created any shelves', - /** - * Comments - */ + // Comments 'comment' => 'Reactie', 'comments' => 'Reacties', + 'comment_add' => 'Add Comment', 'comment_placeholder' => 'Laat hier een reactie achter', 'comment_count' => '{0} Geen reacties|{1} 1 Reactie|[2,*] :count Reacties', 'comment_save' => 'Sla reactie op', @@ -289,10 +307,9 @@ return [ 'comment_delete_confirm' => 'Zeker reactie verwijderen?', 'comment_in_reply_to' => 'Antwoord op :commentId', - /** - * Revision - */ + // Revision 'revision_delete_confirm' => 'Weet u zeker dat u deze revisie wilt verwijderen?', + 'revision_restore_confirm' => 'Are you sure you want to restore this revision? The current page contents will be replaced.', 'revision_delete_success' => 'Revisie verwijderd', 'revision_cannot_delete_latest' => 'Kan de laatste revisie niet verwijderen.' -]; +]; \ No newline at end of file diff --git a/resources/lang/nl/errors.php b/resources/lang/nl/errors.php index 19dbbd8d1..7dd2bdaa5 100644 --- a/resources/lang/nl/errors.php +++ b/resources/lang/nl/errors.php @@ -1,11 +1,9 @@ 'Je hebt onvoldoende rechten om deze pagina te zien.', 'permissionJson' => 'Je hebt onvoldoende rechten voor deze actie.', @@ -15,11 +13,18 @@ return [ 'email_already_confirmed' => 'Het e-mailadres is al bevestigd. Probeer in te loggen.', 'email_confirmation_invalid' => 'Deze bevestigingstoken is ongeldig, Probeer opnieuw te registreren.', 'email_confirmation_expired' => 'De bevestigingstoken is verlopen, Een nieuwe bevestigingsmail is verzonden.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'LDAP toegang kon geen \'anonymous bind\' uitvoeren', 'ldap_fail_authed' => 'LDAP toegang was niet mogelijk met de opgegeven dn & wachtwoord', - 'ldap_extension_not_installed' => 'LDAP PHP extension not installed', + 'ldap_extension_not_installed' => 'LDAP PHP-extensie is niet geïnstalleerd', 'ldap_cannot_connect' => 'Kon niet met de LDAP server verbinden', + 'saml_already_logged_in' => 'Al ingelogd', + 'saml_user_not_registered' => 'De gebruiker: naam is niet geregistreerd en automatische registratie is uitgeschakeld', + 'saml_no_email_address' => 'Kan geen e-mailadres voor deze gebruiker vinden in de gegevens die door het externe verificatiesysteem worden verstrekt', + 'saml_invalid_response_id' => 'Het verzoek van het externe verificatiesysteem is niet herkend door een door deze applicatie gestart proces. Het terug navigeren na een login kan dit probleem veroorzaken.', + 'saml_fail_authed' => 'Inloggen met :system mislukt, het systeem gaf geen succesvolle autorisatie', 'social_no_action_defined' => 'Geen actie gedefineerd', + 'social_login_bad_response' => "Fout ontvangen tijdens :socialAccount login: \n:error", 'social_account_in_use' => 'Dit :socialAccount account is al in gebruik, Probeer in te loggen met de :socialAccount optie.', 'social_account_email_in_use' => 'Het e-mailadres :email is al in gebruik. Als je al een account hebt kun je een :socialAccount account verbinden met je profielinstellingen.', 'social_account_existing' => 'Dit :socialAccount is al gekoppeld aan een profiel.', @@ -28,23 +33,29 @@ return [ 'social_account_register_instructions' => 'Als je nog geen account hebt kun je je registreren met de :socialAccount optie.', 'social_driver_not_found' => 'Social driver niet gevonden', 'social_driver_not_configured' => 'Je :socialAccount instellingen zijn correct geconfigureerd.', + 'invite_token_expired' => 'Deze uitnodigingslink is verlopen. U kunt in plaats daarvan proberen uw wachtwoord opnieuw in te stellen.', // System 'path_not_writable' => 'Bestand :filePath kon niet geupload worden. Zorg dat je schrijfrechten op de server hebt.', 'cannot_get_image_from_url' => 'Kon geen afbeelding genereren van :url', 'cannot_create_thumbs' => 'De server kon geen thumbnails maken. Controleer of je de GD PHP extensie geïnstalleerd hebt.', 'server_upload_limit' => 'Het afbeeldingsformaat is te groot. Probeer een kleinere bestandsgrootte.', + 'uploaded' => 'Server staat geen uploads van deze grootte toe. Probeer een kleinere grootte van het bestand.', 'image_upload_error' => 'Er ging iets fout bij het uploaden van de afbeelding', + 'image_upload_type_error' => 'Het afbeeldingstype dat wordt geüpload is ongeldig', 'file_upload_timeout' => 'Het uploaden van het bestand is verlopen.', // Attachments 'attachment_page_mismatch' => 'Bij het bijwerken van de bijlage bleek de pagina onjuist', + 'attachment_not_found' => 'Bijlage niet gevonden', // Pages 'page_draft_autosave_fail' => 'Kon het concept niet opslaan. Zorg ervoor dat je een werkende internetverbinding hebt.', + 'page_custom_home_deletion' => 'Kan geen pagina verwijderen terwijl deze is ingesteld als een homepage', // Entities 'entity_not_found' => 'Entiteit niet gevonden', + 'bookshelf_not_found' => 'Boekenplank niet gevonden', 'book_not_found' => 'Boek niet gevonden', 'page_not_found' => 'Pagina niet gevonden', 'chapter_not_found' => 'Hoofdstuk niet gevonden', @@ -60,6 +71,7 @@ return [ 'role_cannot_be_edited' => 'Deze rol kan niet bewerkt worden', 'role_system_cannot_be_deleted' => 'Dit is een systeemrol en kan niet verwijderd worden', 'role_registration_default_cannot_delete' => 'Deze rol kan niet verwijerd worden zolang dit de standaardrol na registratie is.', + 'role_cannot_remove_only_admin' => 'Deze gebruiker is de enige gebruiker die is toegewezen aan de beheerdersrol. Wijs de beheerdersrol toe aan een andere gebruiker voordat u probeert deze hier te verwijderen.', // Comments 'comment_list' => 'Er is een fout opgetreden tijdens het ophalen van de reacties.', @@ -67,6 +79,7 @@ return [ 'comment_add' => 'Er is een fout opgetreden tijdens het toevoegen van de reactie.', 'comment_delete' => 'Er is een fout opgetreden tijdens het verwijderen van de reactie.', 'empty_comment' => 'Kan geen lege reactie toevoegen.', + // Error pages '404_page_not_found' => 'Pagina Niet Gevonden', 'sorry_page_not_found' => 'Sorry, de pagina die je zocht is niet beschikbaar.', @@ -74,4 +87,13 @@ return [ 'error_occurred' => 'Er Ging Iets Fout', 'app_down' => ':appName is nu niet beschikbaar', 'back_soon' => 'Komt snel weer online.', -]; \ No newline at end of file + + // 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', + +]; diff --git a/resources/lang/nl/pagination.php b/resources/lang/nl/pagination.php index 9a2a9677a..a5762a5ae 100644 --- a/resources/lang/nl/pagination.php +++ b/resources/lang/nl/pagination.php @@ -1,18 +1,11 @@ '« Vorige', 'next' => 'Volgende »', diff --git a/resources/lang/nl/passwords.php b/resources/lang/nl/passwords.php index f89830804..a1efd480e 100644 --- a/resources/lang/nl/passwords.php +++ b/resources/lang/nl/passwords.php @@ -1,18 +1,11 @@ 'Wachtwoorden moeten overeenkomen en minimaal zes tekens lang zijn.', 'user' => "We kunnen niemand vinden met dat e-mailadres.", 'token' => 'De token om het wachtwoord te herstellen is ongeldig.', diff --git a/resources/lang/nl/settings.php b/resources/lang/nl/settings.php index ba73dc7e9..0c320be63 100644 --- a/resources/lang/nl/settings.php +++ b/resources/lang/nl/settings.php @@ -1,56 +1,87 @@ 'Instellingen', - 'settings_save' => 'Instellingen Opslaan', + 'settings_save' => 'Instellingen opslaan', 'settings_save_success' => 'Instellingen Opgeslagen', - /** - * App settings - */ - - 'app_settings' => 'App Instellingen', + // App Settings + 'app_customization' => 'Aanpassingen', + 'app_features_security' => 'Functies en beveiliging', 'app_name' => 'Applicatienaam', 'app_name_desc' => 'De applicatienaam wordt in e-mails in in de header weergegeven.', 'app_name_header' => 'Applicatienaam in de header weergeven?', + 'app_public_access' => 'Openbare toegang', + 'app_public_access_desc' => 'Door deze optie in te schakelen, krijgen bezoekers die niet zijn ingelogd, toegang tot content in je BookStack.', + 'app_public_access_desc_guest' => 'Toegang voor openbare bezoekers kan worden gecontroleerd via de "Guest" gebruiker.', + 'app_public_access_toggle' => 'Openbare toegang toestaan', 'app_public_viewing' => 'Publieke bewerkingen toestaan?', 'app_secure_images' => 'Beter beveiligide afbeeldingen gebruiken?', + 'app_secure_images_toggle' => 'Hogere beveiliging geuploade afbeeldingen inschakelen', 'app_secure_images_desc' => 'Omwille van de performance zijn alle afbeeldingen publiek toegankelijk. Zorg ervoor dat je de \'directory index\' niet hebt ingeschakeld.', 'app_editor' => 'Pagina Bewerken', 'app_editor_desc' => 'Selecteer welke tekstverwerker je wilt gebruiken.', 'app_custom_html' => 'Speciale HTML toevoegen', 'app_custom_html_desc' => 'Alles wat je hier toevoegd wordt in de sectie van elke pagina meengenomen. Dit kun je bijvoorbeeld voor analytics gebruiken.', + 'app_custom_html_disabled_notice' => 'Aangepaste HTML-hoofd-inhoud is uitgeschakeld op deze instellingenpagina om ervoor te zorgen dat breekbare wijzigingen ongedaan gemaakt kunnen worden.', 'app_logo' => 'Applicatielogo', 'app_logo_desc' => 'De afbeelding moet 43px hoog zijn.
Grotere afbeeldingen worden geschaald.', 'app_primary_color' => 'Applicatie hoofdkleur', 'app_primary_color_desc' => 'Geef een hexadecimale waarde.
Als je niks invult wordt de standaardkleur gebruikt.', + '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_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.', - /** - * Registration settings - */ + // Color settings + 'content_colors' => 'Kleuren inhoud', + 'content_colors_desc' => 'Stelt de kleuren in voor alle elementen in de pagina-organisatieleiding. Het kiezen van kleuren met dezelfde helderheid als de standaard kleuren wordt aanbevolen voor de leesbaarheid.', + 'bookshelf_color' => 'Shelf Color', + 'book_color' => 'Book Color', + 'chapter_color' => 'Chapter Color', + 'page_color' => 'Pagina kleur', + 'page_draft_color' => 'Klad pagina kleur', + // Registration Settings 'reg_settings' => 'Registratieinstellingen', - 'reg_allow' => 'Registratie toestaan?', + 'reg_enable' => 'Registratie inschakelen', + 'reg_enable_toggle' => 'Registratie inschakelen', + 'reg_enable_desc' => 'Wanneer registratie is ingeschakeld, kan de gebruiker zich aanmelden als een gebruiker. Na registratie krijgen ze een enkele, standaard gebruikersrol.', 'reg_default_role' => 'Standaard rol na registratie', - 'reg_confirm_email' => 'E-mailbevesting vereist?', + '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' => 'E-mail bevestiging', + 'reg_email_confirmation_toggle' => 'E-mailbevestiging verplichten', 'reg_confirm_email_desc' => 'Als domeinrestricties aan staan dan is altijd e-maibevestiging nodig. Onderstaande instelling wordt dan genegeerd.', 'reg_confirm_restrict_domain' => 'Beperk registratie tot een maildomein', 'reg_confirm_restrict_domain_desc' => 'Geen een komma-gescheiden lijst van domeinnamen die gebruikt mogen worden bij registratie.
Let op: na registratie kunnen gebruikers hun e-mailadres nog steeds wijzigen.', 'reg_confirm_restrict_domain_placeholder' => 'Geen beperkingen ingesteld', - /** - * Role settings - */ + // Maintenance settings + 'maint' => 'Onderhoud', + 'maint_image_cleanup' => 'Afbeeldingen opschonen', + 'maint_image_cleanup_desc' => "Scant pagina- en revisie inhoud om te controleren welke afbeeldingen en tekeningen momenteel worden gebruikt en welke afbeeldingen overbodig zijn. Zorg ervoor dat je een volledige database en afbeelding backup maakt voordat je dit uitvoert.", + 'maint_image_cleanup_ignore_revisions' => 'Afbeeldingen in revisies negeren', + 'maint_image_cleanup_run' => 'Opschonen uitvoeren', + 'maint_image_cleanup_warning' => ':count potentieel ongebruikte afbeeldingen gevonden. Weet u zeker dat u deze afbeeldingen wilt verwijderen?', + 'maint_image_cleanup_success' => ':count potentieel ongebruikte afbeeldingen gevonden en verwijderd!', + 'maint_image_cleanup_nothing_found' => 'Geen ongebruikte afbeeldingen gevonden, niets verwijderd!', + 'maint_send_test_email' => 'Stuur een test e-mail', + 'maint_send_test_email_desc' => 'Dit verstuurt een test e-mail naar het e-mailadres dat je in je profiel hebt opgegeven.', + 'maint_send_test_email_run' => 'Test e-mail verzenden', + 'maint_send_test_email_success' => 'E-mail verzonden naar :address', + 'maint_send_test_email_mail_subject' => 'Test E-mail', + 'maint_send_test_email_mail_greeting' => 'E-mailbezorging lijkt te werken!', + 'maint_send_test_email_mail_text' => 'Gefeliciteerd! Nu je deze e-mailmelding hebt ontvangen, lijken je e-mailinstellingen correct te zijn geconfigureerd.', + // Role Settings 'roles' => 'Rollen', 'role_user_roles' => 'Gebruikrollen', 'role_create' => 'Nieuwe Rol Maken', @@ -65,14 +96,18 @@ return [ 'role_details' => 'Rol Details', 'role_name' => 'Rolnaam', 'role_desc' => 'Korte beschrijving van de rol', + 'role_external_auth_id' => 'Externe authenticatie ID\'s', 'role_system' => 'Systeem Permissies', 'role_manage_users' => 'Gebruikers beheren', 'role_manage_roles' => 'Rollen en rechten beheren', 'role_manage_entity_permissions' => 'Beheer alle boeken-, hoofdstukken- en paginaresitrcties', 'role_manage_own_entity_permissions' => 'Beheer restricties van je eigen boeken, hoofdstukken en pagina\'s', + 'role_manage_page_templates' => 'Paginasjablonen beheren', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Beheer app instellingen', 'role_asset' => 'Asset Permissies', 'role_asset_desc' => 'Deze permissies bepalen de standaardtoegangsrechten. Permissies op boeken, hoofdstukken en pagina\'s overschrijven deze instelling.', + 'role_asset_admins' => 'Beheerders krijgen automatisch toegang tot alle inhoud, maar deze opties kunnen interface opties tonen of verbergen.', 'role_all' => 'Alles', 'role_own' => 'Eigen', 'role_controlled_by_asset' => 'Gecontroleerd door de asset waar deze is geüpload', @@ -81,19 +116,24 @@ return [ 'role_users' => 'Gebruikers in deze rol', 'role_users_none' => 'Geen enkele gebruiker heeft deze rol', - /** - * Users - */ - + // Users 'users' => 'Gebruikers', 'user_profile' => 'Gebruikersprofiel', 'users_add_new' => 'Gebruiker toevoegen', 'users_search' => 'Gebruiker zoeken', + 'users_details' => 'Gebruiker details', + 'users_details_desc' => 'Stel een weergavenaam en e-mailadres in voor deze gebruiker. Het e-mailadres zal worden gebruikt om in te loggen.', + 'users_details_desc_no_email' => 'Stel een weergavenaam in voor deze gebruiker zodat anderen deze kunnen herkennen.', 'users_role' => 'Gebruikersrollen', - 'users_external_auth_id' => 'External Authentication ID', + 'users_role_desc' => 'Selecteer aan welke rollen deze gebruiker zal worden toegewezen. Als een gebruiker aan meerdere rollen wordt toegewezen worden de machtigingen van deze rollen samengevoegd en krijgen ze alle machtigingen van de toegewezen rollen.', + 'users_password' => 'Wachtwoord gebruiker', + 'users_password_desc' => 'Stel een wachtwoord in dat gebruikt wordt om in te loggen op de applicatie. Dit moet minstens 6 tekens lang zijn.', + 'users_send_invite_text' => 'U kunt ervoor kiezen om deze gebruiker een uitnodigingsmail te sturen waarmee hij zijn eigen wachtwoord kan instellen, anders kunt u zelf zijn wachtwoord instellen.', + 'users_send_invite_option' => 'Stuur gebruiker uitnodigings e-mail', + 'users_external_auth_id' => 'Externe authenticatie 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' => 'Vul onderstaande formulier alleen in als je het wachtwoord wilt aanpassen:', 'users_system_public' => 'De eigenschappen van deze gebruiker worden voor elke gastbezoeker gebruikt. Er kan niet mee ingelogd worden en wordt automatisch toegewezen.', - 'users_books_view_type' => 'Voorkeursuitleg voor het weergeven van boeken', 'users_delete' => 'Verwijder gebruiker', 'users_delete_named' => 'Verwijder gebruiker :userName', 'users_delete_warning' => 'Dit zal de gebruiker \':userName\' volledig uit het systeem verwijderen.', @@ -105,10 +145,67 @@ return [ 'users_avatar' => 'Avatar', 'users_avatar_desc' => 'De afbeelding moet vierkant zijn en ongeveer 256px breed.', 'users_preferred_language' => 'Voorkeurstaal', - 'users_social_accounts' => 'Social Accounts', + 'users_preferred_language_desc' => 'Deze optie wijzigt de taal die gebruikt wordt voor de gebruikersinterface. Dit heeft geen invloed op de door de gebruiker gemaakte inhoud.', + 'users_social_accounts' => 'Sociale accounts', 'users_social_accounts_info' => 'Hier kun je accounts verbinden om makkelijker in te loggen. Via je profiel kun je ook weer rechten intrekken die bij deze social accountsh horen.', 'users_social_connect' => 'Account Verbinden', 'users_social_disconnect' => 'Account Ontkoppelen', 'users_social_connected' => ':socialAccount account is succesvol aan je profiel gekoppeld.', 'users_social_disconnected' => ':socialAccount account is succesvol ontkoppeld van je profiel.', + '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' => 'العربية', + 'da' => 'Dansk', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// ]; diff --git a/resources/lang/nl/validation.php b/resources/lang/nl/validation.php index b75af7485..f85e5786f 100644 --- a/resources/lang/nl/validation.php +++ b/resources/lang/nl/validation.php @@ -1,108 +1,114 @@ '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, and dashes.', - '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.', + // Standard laravel validation lines + 'accepted' => ':attribute moet geaccepteerd worden.', + 'active_url' => ':attribute is geen geldige URL.', + 'after' => ':attribute moet een datum zijn later dan :date.', + 'alpha' => ':attribute mag alleen letters bevatten.', + 'alpha_dash' => ':attribute mag alleen letters, cijfers, streepjes en liggende streepjes bevatten.', + 'alpha_num' => ':attribute mag alleen letters en nummers bevatten.', + 'array' => ':attribute moet een reeks zijn.', + 'before' => ':attribute moet een datum zijn voor :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' => ':attribute moet tussen de :min en :max zijn.', + 'file' => ':attribute moet tussen de :min en :max kilobytes zijn.', + 'string' => ':attribute moet tussen de :min en :max tekens zijn.', + 'array' => ':attribute moet tussen de :min en :max items bevatten.', + ], + 'boolean' => ':attribute moet ja of nee zijn.', + 'confirmed' => ':attribute bevestiging komt niet overeen.', + 'date' => ':attribute is geen geldige datum.', + 'date_format' => ':attribute komt niet overeen met het formaat :format.', + 'different' => ':attribute en :other moeten verschillend zijn.', + 'digits' => ':attribute moet bestaan uit :digits cijfers.', + 'digits_between' => ':attribute moet tussen de :min en :max cijfers zijn.', + 'email' => ':attribute is geen geldig e-mailadres.', + 'ends_with' => ':attribute moet eindigen met een van de volgende: :values', + 'filled' => ':attribute is verplicht.', + 'gt' => [ + 'numeric' => ':attribute moet groter zijn dan :value.', + 'file' => ':attribute moet groter zijn dan :value kilobytes.', + 'string' => ':attribute moet meer dan :value tekens bevatten.', + 'array' => ':attribute moet meer dan :value items bevatten.', + ], + 'gte' => [ + 'numeric' => ':attribute moet groter of gelijk zijn aan :value.', + 'file' => ':attribute moet groter of gelijk zijn aan :value kilobytes.', + 'string' => ':attribute moet :value of meer tekens bevatten.', + 'array' => ':attribute moet :value items of meer bevatten.', + ], + 'exists' => ':attribute is ongeldig.', + 'image' => ':attribute moet een afbeelding zijn.', + 'image_extension' => ':attribute moet een geldige en ondersteunde afbeeldings-extensie hebben.', + 'in' => ':attribute is ongeldig.', + 'integer' => ':attribute moet een getal zijn.', + 'ip' => ':attribute moet een geldig IP-adres zijn.', + 'ipv4' => ':attribute moet een geldig IPv4-adres zijn.', + 'ipv6' => ':attribute moet een geldig IPv6-adres zijn.', + 'json' => ':attribute moet een geldige JSON-string zijn.', + 'lt' => [ + 'numeric' => ':attribute moet kleiner zijn dan :value.', + 'file' => ':attribute moet kleiner zijn dan :value kilobytes.', + 'string' => ':attribute moet minder dan :value tekens bevatten.', + 'array' => ':attribute moet minder dan :value items bevatten.', + ], + 'lte' => [ + 'numeric' => ':attribute moet kleiner of gelijk zijn aan :value.', + 'file' => ':attribute moet kleiner of gelijk zijn aan :value kilobytes.', + 'string' => ':attribute moet :value tekens of minder bevatten.', + 'array' => ':attribute mag niet meer dan :value items bevatten.', ], - '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.', - 'filled' => 'The :attribute field is required.', - 'exists' => 'The selected :attribute is invalid.', - 'image' => 'The :attribute must be an image.', - 'in' => 'The selected :attribute is invalid.', - 'integer' => 'The :attribute must be an integer.', - 'ip' => 'The :attribute must be a valid IP address.', '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' => ':attribute mag niet groter zijn dan :max.', + 'file' => ':attribute mag niet groter zijn dan :max kilobytes.', + 'string' => ':attribute mag niet groter zijn dan :max tekens.', + 'array' => ':attribute mag niet meer dan :max items bevatten.', ], - 'mimes' => 'The :attribute must be a file of type: :values.', + 'mimes' => ':attribute moet een bestand zijn van het 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' => ':attribute moet minstens :min zijn.', + 'file' => ':attribute moet minstens :min kilobytes zijn.', + 'string' => ':attribute moet minstens :min karakters bevatten.', + 'array' => ':attribute moet minstens :min items bevatten.', ], - 'not_in' => 'The selected :attribute 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.', + '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.', + 'regex' => ':attribute formaat is ongeldig.', + 'required' => ':attribute veld is verplicht.', + 'required_if' => ':attribute veld is verplicht als :other gelijk is aan :value.', + 'required_with' => ':attribute veld is verplicht wanneer :values ingesteld is.', + 'required_with_all' => ':attribute veld is verplicht wanneer :values ingesteld is.', + 'required_without' => ':attribute veld is verplicht wanneer :values niet ingesteld is.', + 'required_without_all' => ':attribute veld is verplicht wanneer geen van :values ingesteld zijn.', + 'same' => ':attribute en :other moeten overeenkomen.', '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' => ':attribute moet :size zijn.', + 'file' => ':attribute moet :size kilobytes zijn.', + 'string' => ':attribute moet :size tekens bevatten.', + 'array' => ':attribute moet :size items bevatten.', ], - '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.', - - /* - |-------------------------------------------------------------------------- - | Custom Validation Language Lines - |-------------------------------------------------------------------------- - | - | Here you may specify custom validation messages for attributes using the - | convention "attribute.rule" to name the lines. This makes it quick to - | specify a specific custom language line for a given attribute rule. - | - */ + 'string' => ':attribute moet tekst zijn.', + 'timezone' => ':attribute moet een geldige zone zijn.', + 'unique' => ':attribute is al in gebruik.', + 'url' => ':attribute formaat is ongeldig.', + 'uploaded' => 'Het bestand kon niet worden geüpload. De server accepteert mogelijk geen bestanden van deze grootte.', + // Custom validation lines 'custom' => [ 'password-confirm' => [ - 'required_with' => 'Password confirmation required', + 'required_with' => 'Wachtwoord bevestiging verplicht', ], ], - /* - |-------------------------------------------------------------------------- - | Custom Validation Attributes - |-------------------------------------------------------------------------- - | - | The following language lines are used to swap attribute place-holders - | with something more reader friendly such as E-Mail Address instead - | of "email". This simply helps us make messages a little cleaner. - | - */ - + // Custom validation attributes 'attributes' => [], - ]; diff --git a/resources/lang/pl/activities.php b/resources/lang/pl/activities.php index 7013be566..f641ca232 100644 --- a/resources/lang/pl/activities.php +++ b/resources/lang/pl/activities.php @@ -1,12 +1,10 @@ 'utworzono stronę', 'page_create_notification' => 'Strona utworzona pomyślnie', @@ -28,14 +26,14 @@ return [ 'chapter_move' => 'przeniesiono rozdział', // Books - 'book_create' => 'utworzono podręcznik', - 'book_create_notification' => 'Podręcznik utworzony pomyślnie', - 'book_update' => 'zaktualizowano podręcznik', - 'book_update_notification' => 'Podręcznik zaktualizowany pomyślnie', - 'book_delete' => 'usunięto podręcznik', - 'book_delete_notification' => 'Podręcznik usunięty pomyślnie', - 'book_sort' => 'posortowano podręcznik', - 'book_sort_notification' => 'Podręcznik posortowany pomyślnie', + 'book_create' => 'utworzono książkę', + 'book_create_notification' => 'Książkę utworzony pomyślnie', + 'book_update' => 'zaktualizowano książkę', + 'book_update_notification' => 'Książkę zaktualizowany pomyślnie', + 'book_delete' => 'usunięto książkę', + 'book_delete_notification' => 'Książkę usunięty pomyślnie', + 'book_sort' => 'posortowano książkę', + 'book_sort_notification' => 'Książkę posortowany pomyślnie', // Bookshelves 'bookshelf_create' => 'utworzono półkę', diff --git a/resources/lang/pl/auth.php b/resources/lang/pl/auth.php index 5cec651a9..a85159a1b 100644 --- a/resources/lang/pl/auth.php +++ b/resources/lang/pl/auth.php @@ -1,21 +1,15 @@ 'Wprowadzone poświadczenia są nieprawidłowe.', 'throttle' => 'Zbyt wiele prób logowania. Spróbuj ponownie za :seconds s.', - /** - * Login & Register - */ + // Login & Register 'sign_up' => 'Zarejestruj się', 'log_in' => 'Zaloguj się', 'log_in_with' => 'Zaloguj się za pomocą :socialDriver', @@ -27,11 +21,13 @@ return [ 'email' => 'E-mail', 'password' => 'Hasło', 'password_confirm' => 'Potwierdzenie hasła', - 'password_hint' => 'Musi mieć więcej niż 5 znaków', + 'password_hint' => 'Musi mieć więcej niż 7 znaków', 'forgot_password' => 'Zapomniałem hasła', 'remember_me' => 'Zapamiętaj mnie', 'ldap_email_hint' => 'Wprowadź adres e-mail dla tego konta.', 'create_account' => 'Utwórz konto', + 'already_have_account' => 'Masz już konto?', + 'dont_have_account' => 'Nie masz konta?', 'social_login' => 'Logowanie za pomocą konta społecznościowego', 'social_registration' => 'Rejestracja za pomocą konta społecznościowego', 'social_registration_text' => 'Zarejestruj się za pomocą innej usługi.', @@ -43,23 +39,18 @@ return [ 'register_success' => 'Dziękujemy za rejestrację! Zostałeś zalogowany automatycznie.', - /** - * Password Reset - */ + // Password Reset 'reset_password' => 'Resetowanie hasła', 'reset_password_send_instructions' => 'Wprowadź adres e-mail powiązany z Twoim kontem, by otrzymać link do resetowania hasła.', 'reset_password_send_button' => 'Wyślij link do resetowania hasła', 'reset_password_sent_success' => 'Wysłano link do resetowania hasła na adres :email.', 'reset_password_success' => 'Hasło zostało zresetowane pomyślnie.', - 'email_reset_subject' => 'Resetowanie hasła do :appName', 'email_reset_text' => 'Otrzymujesz tę wiadomość ponieważ ktoś zażądał zresetowania hasła do Twojego konta.', 'email_reset_not_requested' => 'Jeśli to nie Ty złożyłeś żądanie zresetowania hasła, zignoruj tę wiadomość.', - /** - * Email Confirmation - */ + // Email Confirmation 'email_confirm_subject' => 'Potwierdź swój adres e-mail w :appName', 'email_confirm_greeting' => 'Dziękujemy za dołączenie do :appName!', 'email_confirm_text' => 'Prosimy byś potwierdził swoje hasło klikając przycisk poniżej:', @@ -73,4 +64,14 @@ return [ 'email_not_confirmed_click_link' => 'Aby potwierdzić swoje konto kliknij w link wysłany w wiadomości po rejestracji.', 'email_not_confirmed_resend' => 'Jeśli wiadomość do Ciebie nie dotarła możesz wysłać ją ponownie wypełniając formularz poniżej.', 'email_not_confirmed_resend_button' => 'Wyślij ponownie wiadomość z potwierdzeniem', -]; + + // User Invite + 'user_invite_email_subject' => 'Zostałeś zaproszony do :appName!', + 'user_invite_email_greeting' => 'Zostało dla Ciebie utworzone konto w :appName.', + 'user_invite_email_text' => 'Kliknij przycisk poniżej, aby ustawić hasło do konta i uzyskać do niego dostęp:', + 'user_invite_email_action' => 'Ustaw hasło do konta', + 'user_invite_page_welcome' => 'Witaj w :appName!', + 'user_invite_page_text' => 'Aby zakończyć tworzenie konta musisz ustawić hasło, które będzie używane do logowania do :appName w przyszłości.', + 'user_invite_page_confirm_button' => 'Potwierdź hasło', + 'user_invite_success' => 'Hasło zostało ustawione, teraz masz dostęp do :appName!' +]; \ No newline at end of file diff --git a/resources/lang/pl/common.php b/resources/lang/pl/common.php index b97925222..f91a682e5 100644 --- a/resources/lang/pl/common.php +++ b/resources/lang/pl/common.php @@ -1,31 +1,30 @@ 'Anuluj', 'confirm' => 'Zatwierdź', 'back' => 'Wstecz', 'save' => 'Zapisz', 'continue' => 'Kontynuuj', 'select' => 'Wybierz', + 'toggle_all' => 'Przełącz wszystko', 'more' => 'Więcej', - /** - * Form Labels - */ + // Form Labels 'name' => 'Nazwa', 'description' => 'Opis', 'role' => 'Rola', 'cover_image' => 'Zdjęcie z okładki', 'cover_image_description' => 'Ten obraz powinien posiadać wymiary około 440x250px.', - /** - * Actions - */ + // Actions 'actions' => 'Akcje', 'view' => 'Widok', + 'view_all' => 'Zobacz wszystkie', 'create' => 'Utwórz', 'update' => 'Zaktualizuj', 'edit' => 'Edytuj', @@ -39,10 +38,18 @@ return [ 'reset' => 'Resetuj', 'remove' => 'Usuń', 'add' => 'Dodaj', + 'fullscreen' => 'Fullscreen', - /** - * Misc - */ + // Sort Options + 'sort_options' => 'Opcje sortowania', + 'sort_direction_toggle' => 'Przełącz kierunek sortowania', + 'sort_ascending' => 'Sortuj rosnąco', + 'sort_descending' => 'Sortuj malejąco', + 'sort_name' => 'Nazwa', + 'sort_created_at' => 'Data utworzenia', + 'sort_updated_at' => 'Data aktualizacji', + + // Misc 'deleted_user' => 'Użytkownik usunięty', 'no_activity' => 'Brak aktywności do wyświetlenia', 'no_items' => 'Brak elementów do wyświetlenia', @@ -53,16 +60,18 @@ return [ 'grid_view' => 'Widok kafelkowy', 'list_view' => 'Widok listy', 'default' => 'Domyślny', + 'breadcrumb' => 'Breadcrumb', - /** - * Header - */ + // Header + 'profile_menu' => 'Menu profilu', 'view_profile' => 'Zobacz profil', 'edit_profile' => 'Edytuj profil', - /** - * Email Content - */ + // Layout tabs + 'tab_info' => 'Informacje', + 'tab_content' => 'Treść', + + // 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', ]; diff --git a/resources/lang/pl/components.php b/resources/lang/pl/components.php index 8c5429088..b189c8171 100644 --- a/resources/lang/pl/components.php +++ b/resources/lang/pl/components.php @@ -1,13 +1,14 @@ 'Wybór obrazka', 'image_all' => 'Wszystkie', 'image_all_title' => 'Zobacz wszystkie obrazki', - 'image_book_title' => 'Zobacz obrazki zapisane w tym podręczniku', + 'image_book_title' => 'Zobacz obrazki zapisane w tej książce', 'image_page_title' => 'Zobacz obrazki zapisane na tej stronie', 'image_search_hint' => 'Szukaj po nazwie obrazka', 'image_uploaded' => 'Przesłano :uploadedDate', @@ -24,9 +25,7 @@ return [ 'image_delete_success' => 'Obrazek usunięty pomyślnie', 'image_upload_remove' => 'Usuń', - /** - * Code editor - */ + // Code Editor 'code_editor' => 'Edytuj kod', 'code_language' => 'Język kodu', 'code_content' => 'Zawartość kodu', diff --git a/resources/lang/pl/entities.php b/resources/lang/pl/entities.php index 3dad5e2e3..9a1b7f9d2 100644 --- a/resources/lang/pl/entities.php +++ b/resources/lang/pl/entities.php @@ -1,14 +1,17 @@ 'Ostatnio utworzone', 'recently_created_pages' => 'Ostatnio utworzone strony', 'recently_updated_pages' => 'Ostatnio zaktualizowane strony', 'recently_created_chapters' => 'Ostatnio utworzone rozdziały', - 'recently_created_books' => 'Ostatnio utworzone podręczniki', + 'recently_created_books' => 'Ostatnio utworzone książki', + 'recently_created_shelves' => 'Ostatnio utworzone półki', 'recently_update' => 'Ostatnio zaktualizowane', 'recently_viewed' => 'Ostatnio wyświetlane', 'recent_activity' => 'Ostatnia aktywność', @@ -19,7 +22,6 @@ return [ 'meta_created_name' => 'Utworzono :timeLength przez :user', 'meta_updated' => 'Zaktualizowano :timeLength', 'meta_updated_name' => 'Zaktualizowano :timeLength przez :user', - 'x_pages' => ':count stron', 'entity_select' => 'Wybór obiektu', 'images' => 'Obrazki', 'my_recent_drafts' => 'Moje ostatnie wersje robocze', @@ -32,17 +34,13 @@ return [ 'export_pdf' => 'Plik PDF', 'export_text' => 'Plik tekstowy', - /** - * Permissions and restrictions - */ + // Permissions and restrictions 'permissions' => 'Uprawnienia', 'permissions_intro' => 'Jeśli włączone są indywidualne uprawnienia, to te uprawnienia będą miały priorytet względem pozostałych ustawionych uprawnień ról.', 'permissions_enable' => 'Włącz własne uprawnienia', 'permissions_save' => 'Zapisz uprawnienia', - /** - * Search - */ + // Search 'search_results' => 'Wyniki wyszukiwania', 'search_total_results_found' => ':count znalezionych wyników|:count ogółem znalezionych wyników', 'search_clear' => 'Wyczyść wyszukiwanie', @@ -66,78 +64,79 @@ return [ 'search_created_after' => 'Utworzone po', 'search_set_date' => 'Ustaw datę', 'search_update' => 'Zaktualizuj wyszukiwanie', - - /** - * Shelves - */ + + // Shelves 'shelf' => 'Półka', 'shelves' => 'Półki', + 'x_shelves' => ':count Półek|:count Półek', 'shelves_long' => 'Półki', 'shelves_empty' => 'Brak utworzonych półek', 'shelves_create' => 'Utwórz półkę', 'shelves_popular' => 'Popularne półki', 'shelves_new' => 'Nowe półki', + 'shelves_new_action' => 'Nowa półka', 'shelves_popular_empty' => 'Najpopularniejsze półki pojawią się w tym miejscu.', 'shelves_new_empty' => 'Tutaj pojawią się ostatnio utworzone półki.', 'shelves_save' => 'Zapisz półkę', - 'shelves_books' => 'Podręczniki na tej półce', - 'shelves_add_books' => 'Dodaj podręczniki do tej półki', - 'shelves_drag_books' => 'Przeciągnij podręczniki tutaj aby dodać je do półki', - 'shelves_empty_contents' => 'Ta półka nie ma przypisanych żadnych podręczników', - 'shelves_edit_and_assign' => 'Edytuj półkę aby przypisać podręczniki', + 'shelves_books' => 'Książki na tej półce', + 'shelves_add_books' => 'Dodaj książkę do tej półki', + 'shelves_drag_books' => 'Przeciągnij książki tutaj aby dodać je do półki', + 'shelves_empty_contents' => 'Ta półka nie ma przypisanych żadnych książek', + 'shelves_edit_and_assign' => 'Edytuj półkę aby przypisać książki', 'shelves_edit_named' => 'Edytuj półkę :name', 'shelves_edit' => 'Edytuj półkę', 'shelves_delete' => 'Usuń półkę', 'shelves_delete_named' => 'Usuń półkę :name', - 'shelves_delete_explain' => "Ta operacja usunie półkę o nazwie ':name'. Podręczniki z tej półki nie zostaną usunięte.", + 'shelves_delete_explain' => "Ta operacja usunie półkę o nazwie ':name'. Książki z tej półki nie zostaną usunięte.", 'shelves_delete_confirmation' => 'Czy jesteś pewien, że chcesz usunąć tę półkę?', 'shelves_permissions' => 'Uprawnienia półki', 'shelves_permissions_updated' => 'Uprawnienia półki zostały zaktualizowane', 'shelves_permissions_active' => 'Uprawnienia półki są aktywne', - 'shelves_copy_permissions_to_books' => 'Skopiuj uprawnienia do podręczników', + 'shelves_copy_permissions_to_books' => 'Skopiuj uprawnienia do książek', 'shelves_copy_permissions' => 'Skopiuj uprawnienia', - 'shelves_copy_permissions_explain' => 'To spowoduje zastosowanie obecnych ustawień uprawnień dla tej półki do wszystkich podręczników w niej zawartych. Przed aktywacją upewnij się, że wszelkie zmiany w uprawnieniach do tej półki zostały zapisane.', - 'shelves_copy_permission_success' => 'Uprawnienia półki zostały skopiowane do :count podręczników', - - /** - * Books - */ - 'book' => 'Podręcznik', - 'books' => 'Podręczniki', - 'x_books' => ':count Podręcznik|:count Podręczniki', - 'books_empty' => 'Brak utworzonych podręczników', - 'books_popular' => 'Popularne podręczniki', - 'books_recent' => 'Ostatnie podręczniki', - 'books_new' => 'Nowe podręczniki', - 'books_popular_empty' => 'Najpopularniejsze podręczniki pojawią się w tym miejscu.', - 'books_new_empty' => 'Tutaj pojawią się ostatnio utworzone podręczniki.', - 'books_create' => 'Utwórz podręcznik', - 'books_delete' => 'Usuń podręcznik', - 'books_delete_named' => 'Usuń podręcznik :bookName', - 'books_delete_explain' => 'To spowoduje usunięcie podręcznika \':bookName\', Wszystkie strony i rozdziały zostaną usunięte.', - 'books_delete_confirmation' => 'Czy na pewno chcesz usunąc ten podręcznik?', - 'books_edit' => 'Edytuj podręcznik', - 'books_edit_named' => 'Edytuj podręcznik :bookName', - 'books_form_book_name' => 'Nazwa podręcznika', - 'books_save' => 'Zapisz podręcznik', - 'books_permissions' => 'Uprawnienia podręcznika', - 'books_permissions_updated' => 'Zaktualizowano uprawnienia podręcznika', - 'books_empty_contents' => 'Brak stron lub rozdziałów w tym podręczniku.', + 'shelves_copy_permissions_explain' => 'To spowoduje zastosowanie obecnych ustawień uprawnień dla tej półki do wszystkich książek w niej zawartych. Przed aktywacją upewnij się, że wszelkie zmiany w uprawnieniach do tej półki zostały zapisane.', + 'shelves_copy_permission_success' => 'Uprawnienia półki zostały skopiowane do :count książek', + + // Books + 'book' => 'Książka', + 'books' => 'Książki', + 'x_books' => ':count Książka|:count Książki', + 'books_empty' => 'Brak utworzonych książek', + 'books_popular' => 'Popularne książki', + 'books_recent' => 'Ostatnie książki', + 'books_new' => 'Nowe książki', + 'books_new_action' => 'Nowa księga', + 'books_popular_empty' => 'Najpopularniejsze książki pojawią się w tym miejscu.', + 'books_new_empty' => 'Tutaj pojawią się ostatnio utworzone książki.', + 'books_create' => 'Utwórz książkę', + 'books_delete' => 'Usuń książkę', + 'books_delete_named' => 'Usuń książkę :bookName', + 'books_delete_explain' => 'To spowoduje usunięcie książki \':bookName\', Wszystkie strony i rozdziały zostaną usunięte.', + 'books_delete_confirmation' => 'Czy na pewno chcesz usunąc tę książkę?', + 'books_edit' => 'Edytuj książkę', + 'books_edit_named' => 'Edytuj książkę :bookName', + 'books_form_book_name' => 'Nazwa książki', + 'books_save' => 'Zapisz książkę', + 'books_permissions' => 'Uprawnienia książki', + 'books_permissions_updated' => 'Zaktualizowano uprawnienia książki', + 'books_empty_contents' => 'Brak stron lub rozdziałów w tej książce.', 'books_empty_create_page' => 'Utwórz nową stronę', - 'books_empty_or' => 'lub', - 'books_empty_sort_current_book' => 'posortuj bieżący podręcznik', + 'books_empty_sort_current_book' => 'posortuj bieżącą książkę', 'books_empty_add_chapter' => 'Dodaj rozdział', - 'books_permissions_active' => 'Uprawnienia podręcznika są aktywne', - 'books_search_this' => 'Wyszukaj w tym podręczniku', - 'books_navigation' => 'Nawigacja po podręczniku', - 'books_sort' => 'Sortuj zawartość podręcznika', - 'books_sort_named' => 'Sortuj podręcznik :bookName', - 'books_sort_show_other' => 'Pokaż inne podręczniki', + 'books_permissions_active' => 'Uprawnienia książki są aktywne', + 'books_search_this' => 'Wyszukaj w tej książce', + 'books_navigation' => 'Nawigacja po książce', + 'books_sort' => 'Sortuj zawartość książki', + 'books_sort_named' => 'Sortuj książkę :bookName', + 'books_sort_name' => 'Sortuj według nazwy', + 'books_sort_created' => 'Sortuj według daty utworzenia', + 'books_sort_updated' => 'Sortuj według daty modyfikacji', + 'books_sort_chapters_first' => 'Rozdziały na początku', + 'books_sort_chapters_last' => 'Rozdziały na końcu', + 'books_sort_show_other' => 'Pokaż inne książki', 'books_sort_save' => 'Zapisz nową kolejność', - /** - * Chapters - */ + // Chapters 'chapter' => 'Rozdział', 'chapters' => 'Rozdziały', 'x_chapters' => ':count Rozdział|:count Rozdziały', @@ -147,7 +146,7 @@ return [ 'chapters_delete' => 'Usuń rozdział', 'chapters_delete_named' => 'Usuń rozdział :chapterName', 'chapters_delete_explain' => 'To spowoduje usunięcie rozdziału \':chapterName\', Wszystkie strony zostaną usunięte - i dodane bezpośrednio do podręcznika nadrzędnego.', + i dodane bezpośrednio do książki.', 'chapters_delete_confirm' => 'Czy na pewno chcesz usunąć ten rozdział?', 'chapters_edit' => 'Edytuj rozdział', 'chapters_edit_named' => 'Edytuj rozdział :chapterName', @@ -161,11 +160,10 @@ return [ 'chapters_permissions_success' => 'Zaktualizowano uprawnienia rozdziału', 'chapters_search_this' => 'Przeszukaj ten rozdział', - /** - * Pages - */ + // Pages 'page' => 'Strona', 'pages' => 'Strony', + 'x_pages' => ':count stron', 'pages_popular' => 'Popularne strony', 'pages_new' => 'Nowa strona', 'pages_attachments' => 'Załączniki', @@ -179,7 +177,7 @@ return [ 'pages_delete_confirm' => 'Czy na pewno chcesz usunąć tę stronę?', 'pages_delete_draft_confirm' => 'Czy na pewno chcesz usunąć wersje roboczą strony?', 'pages_editing_named' => 'Edytowanie strony :pageName', - 'pages_edit_toggle_header' => 'Włącz/wyłącz nagłówek', + 'pages_edit_draft_options' => 'Ustawienia wersji roboczej', 'pages_edit_save_draft' => 'Zapisano wersje roboczą o ', 'pages_edit_draft' => 'Edytuj wersje roboczą', 'pages_editing_draft' => 'Edytowanie wersji roboczej', @@ -213,6 +211,8 @@ return [ 'pages_revisions_created_by' => 'Utworzona przez', 'pages_revisions_date' => 'Data wersji', 'pages_revisions_number' => '#', + 'pages_revisions_numbered' => 'Wersja #:id', + 'pages_revisions_numbered_changes' => 'Zmiany w wersji #:id', 'pages_revisions_changelog' => 'Dziennik zmian', 'pages_revisions_changes' => 'Zmiany', 'pages_revisions_current' => 'Obecna wersja', @@ -235,19 +235,20 @@ return [ ], 'pages_draft_discarded' => 'Wersja robocza odrzucona, edytor został uzupełniony najnowszą wersją strony', 'pages_specific' => 'Określona strona', + 'pages_is_template' => 'Szablon strony', - /** - * Editor sidebar - */ + // Editor Sidebar 'page_tags' => 'Tagi strony', 'chapter_tags' => 'Tagi rozdziału', - 'book_tags' => 'Tagi podręcznika', + 'book_tags' => 'Tagi książki', 'shelf_tags' => 'Tagi półki', 'tag' => 'Tag', 'tags' => 'Tagi', + 'tag_name' => 'Nazwa tagu', 'tag_value' => 'Wartość tagu (opcjonalnie)', 'tags_explain' => "Dodaj tagi by skategoryzować zawartość. \n W celu dokładniejszej organizacji zawartości możesz dodać wartości do tagów.", 'tags_add' => 'Dodaj kolejny tag', + 'tags_remove' => 'Usuń ten tag', 'attachments' => 'Załączniki', 'attachments_explain' => 'Prześlij kilka plików lub załącz linki. Będą one widoczne na pasku bocznym strony.', 'attachments_explain_instant_save' => 'Zmiany są zapisywane natychmiastowo.', @@ -273,19 +274,22 @@ return [ 'attachments_file_uploaded' => 'Plik załączony pomyślnie', 'attachments_file_updated' => 'Plik zaktualizowany pomyślnie', 'attachments_link_attached' => 'Link pomyślnie dodany do strony', + 'templates' => 'Szablony', + 'templates_set_as_template' => 'Strona jest szablonem', + 'templates_explain_set_as_template' => 'Możesz ustawić tę stronę jako szablon, tak aby jej zawartość była wykorzystywana przy tworzeniu innych stron. Inni użytkownicy będą mogli korzystać z tego szablonu, jeśli mają uprawnienia do przeglądania tej strony.', + 'templates_replace_content' => 'Zmień zawartość strony', + 'templates_append_content' => 'Dodaj do zawartośći strony na końcu', + 'templates_prepend_content' => 'Dodaj do zawartośći strony na początku', - /** - * Profile View - */ + // Profile View 'profile_user_for_x' => 'Użytkownik od :time', 'profile_created_content' => 'Utworzona zawartość', 'profile_not_created_pages' => ':userName nie utworzył żadnych stron', 'profile_not_created_chapters' => ':userName nie utworzył żadnych rozdziałów', - 'profile_not_created_books' => ':userName nie utworzył żadnych podręczników', + 'profile_not_created_books' => ':userName nie utworzył żadnych książek', + 'profile_not_created_shelves' => ':userName nie utworzył żadnych półek', - /** - * Comments - */ + // Comments 'comment' => 'Komentarz', 'comments' => 'Komentarze', 'comment_add' => 'Dodaj komentarz', @@ -303,10 +307,9 @@ return [ 'comment_delete_confirm' => 'Czy na pewno chcesz usunąc ten komentarz?', 'comment_in_reply_to' => 'W odpowiedzi na :commentId', - /** - * Revision - */ + // Revision 'revision_delete_confirm' => 'Czy na pewno chcesz usunąć tę wersję?', + 'revision_restore_confirm' => 'Czu ma pewno chcesz przywrócić tą wersję? Aktualna zawartość strony zostanie nadpisana.', 'revision_delete_success' => 'Usunięto wersję', 'revision_cannot_delete_latest' => 'Nie można usunąć najnowszej wersji.' -]; +]; \ No newline at end of file diff --git a/resources/lang/pl/errors.php b/resources/lang/pl/errors.php index 6377e1262..c31f04efa 100644 --- a/resources/lang/pl/errors.php +++ b/resources/lang/pl/errors.php @@ -1,11 +1,9 @@ 'Nie masz uprawnień do wyświetlenia tej strony.', 'permissionJson' => 'Nie masz uprawnień do wykonania tej akcji.', @@ -15,10 +13,16 @@ return [ 'email_already_confirmed' => 'E-mail został potwierdzony, spróbuj się zalogować.', 'email_confirmation_invalid' => 'Ten token jest nieprawidłowy lub został już wykorzystany. Spróbuj zarejestrować się ponownie.', 'email_confirmation_expired' => 'Ten token potwierdzający wygasł. Wysłaliśmy Ci kolejny.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'Dostęp LDAP przy użyciu anonimowego powiązania nie powiódł się', 'ldap_fail_authed' => 'Dostęp LDAP przy użyciu tego DN i hasła nie powiódł się', 'ldap_extension_not_installed' => 'Rozszerzenie LDAP PHP nie zostało zainstalowane', 'ldap_cannot_connect' => 'Nie można połączyć z serwerem LDAP, połączenie nie zostało ustanowione', + 'saml_already_logged_in' => 'Już zalogowany', + 'saml_user_not_registered' => 'Użytkownik :name nie jest zarejestrowany i automatyczna rejestracja jest wyłączona', + 'saml_no_email_address' => 'Nie można odnaleźć adresu email dla tego użytkownika w danych dostarczonych przez zewnętrzny system uwierzytelniania', + 'saml_invalid_response_id' => 'Żądanie z zewnętrznego systemu uwierzytelniania nie zostało rozpoznane przez proces rozpoczęty przez tę aplikację. Cofnięcie po zalogowaniu mogło spowodować ten problem.', + 'saml_fail_authed' => 'Logowanie przy użyciu :system nie powiodło się, system nie mógł pomyślnie ukończyć uwierzytelniania', 'social_no_action_defined' => 'Brak zdefiniowanej akcji', 'social_login_bad_response' => "Podczas próby logowania :socialAccount wystąpił błąd: \n:error", 'social_account_in_use' => 'To konto :socialAccount jest już w użyciu. Spróbuj zalogować się za pomocą opcji :socialAccount.', @@ -29,6 +33,7 @@ return [ 'social_account_register_instructions' => 'Jeśli nie masz jeszcze konta, możesz zarejestrować je używając opcji :socialAccount.', 'social_driver_not_found' => 'Funkcja społecznościowa nie została odnaleziona', 'social_driver_not_configured' => 'Ustawienia konta :socialAccount nie są poprawne.', + 'invite_token_expired' => 'Zaproszenie wygasło. Możesz spróować zresetować swoje hasło.', // System 'path_not_writable' => 'Zapis do ścieżki :filePath jest niemożliwy. Upewnij się że aplikacja ma prawa do zapisu plików na serwerze.', @@ -51,11 +56,11 @@ return [ // Entities 'entity_not_found' => 'Nie znaleziono obiektu', 'bookshelf_not_found' => 'Nie znaleziono półki', - 'book_not_found' => 'Nie znaleziono podręcznika', + 'book_not_found' => 'Nie znaleziono książki', 'page_not_found' => 'Nie znaleziono strony', 'chapter_not_found' => 'Nie znaleziono rozdziału', - 'selected_book_not_found' => 'Wybrany podręcznik nie został znaleziony', - 'selected_book_chapter_not_found' => 'Wybrany podręcznik lub rozdział nie został znaleziony', + 'selected_book_not_found' => 'Wybrana książka nie została znaleziona', + 'selected_book_chapter_not_found' => 'Wybrana książka lub rozdział nie został znaleziony', 'guests_cannot_save_drafts' => 'Goście nie mogą zapisywać wersji roboczych', // Users @@ -66,14 +71,15 @@ return [ 'role_cannot_be_edited' => 'Ta rola nie może być edytowana', 'role_system_cannot_be_deleted' => 'Ta rola jest rolą systemową i nie może zostać usunięta', 'role_registration_default_cannot_delete' => 'Ta rola nie może zostać usunięta, dopóki jest ustawiona jako domyślna rola użytkownika', - + 'role_cannot_remove_only_admin' => 'Ten użytkownik jest jedynym użytkownikiem przypisanym do roli administratora. Przypisz rolę administratora innemu użytkownikowi przed próbą usunięcia.', + // Comments 'comment_list' => 'Wystąpił błąd podczas pobierania komentarzy.', 'cannot_add_comment_to_draft' => 'Nie możesz dodawać komentarzy do wersji roboczej.', 'comment_add' => 'Wystąpił błąd podczas dodwania / aktualizaowania komentarza.', 'comment_delete' => 'Wystąpił błąd podczas usuwania komentarza.', 'empty_comment' => 'Nie można dodać pustego komentarza.', - + // Error pages '404_page_not_found' => 'Strona nie została znaleziona', 'sorry_page_not_found' => 'Przepraszamy, ale strona której szukasz nie została znaleziona.', @@ -81,4 +87,13 @@ return [ 'error_occurred' => 'Wystąpił błąd', 'app_down' => ':appName jest aktualnie wyłączona', 'back_soon' => 'Niedługo zostanie uruchomiona ponownie.', + + // 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', + ]; diff --git a/resources/lang/pl/pagination.php b/resources/lang/pl/pagination.php index 564694190..c3d80d681 100644 --- a/resources/lang/pl/pagination.php +++ b/resources/lang/pl/pagination.php @@ -1,18 +1,11 @@ '« Poprzednia', 'next' => 'Następna »', diff --git a/resources/lang/pl/passwords.php b/resources/lang/pl/passwords.php index a9103d593..8c9eae227 100644 --- a/resources/lang/pl/passwords.php +++ b/resources/lang/pl/passwords.php @@ -1,18 +1,11 @@ 'Hasło musi zawierać co najmniej 6 znaków i być zgodne z powtórzeniem.', 'user' => "Nie znaleziono użytkownika o takim adresie e-mail.", 'token' => 'Ten token resetowania hasła jest nieprawidłowy.', diff --git a/resources/lang/pl/settings.php b/resources/lang/pl/settings.php index e1c8c7b8d..4edb214da 100644 --- a/resources/lang/pl/settings.php +++ b/resources/lang/pl/settings.php @@ -1,32 +1,35 @@ 'Ustawienia', 'settings_save' => 'Zapisz ustawienia', 'settings_save_success' => 'Ustawienia zapisane', - /** - * App settings - */ - - 'app_settings' => 'Ustawienia aplikacji', + // App Settings + 'app_customization' => 'Dostosowywanie', + 'app_features_security' => 'Funkcje i bezpieczeństwo', 'app_name' => 'Nazwa aplikacji', 'app_name_desc' => 'Ta nazwa jest wyświetlana w nagłówku i e-mailach.', 'app_name_header' => 'Pokazać nazwę aplikacji w nagłówku?', + 'app_public_access' => 'Dostęp publiczny', + 'app_public_access_desc' => 'Włączenie tej opcji umożliwi niezalogowanym odwiedzającym dostęp do treści w Twojej instancji BookStack.', + 'app_public_access_desc_guest' => 'Dostęp dla niezalogowanych odwiedzających jest dostępny poprzez użytkownika "Guest".', + 'app_public_access_toggle' => 'Zezwalaj na dostęp publiczny', 'app_public_viewing' => 'Zezwolić na publiczne przeglądanie?', 'app_secure_images' => 'Włączyć przesyłanie obrazów o wyższym poziomie bezpieczeństwa?', + 'app_secure_images_toggle' => 'Włącz wyższy poziom bezpieczeństwa dla obrazów', 'app_secure_images_desc' => 'Ze względów wydajnościowych wszystkie obrazki są publiczne. Ta opcja dodaje dodatkowy, trudny do odgadnięcia losowy ciąg na początku nazwy obrazka. Upewnij się że indeksowanie katalogów jest zablokowane, aby uniemożliwić łatwy dostęp do obrazków.', 'app_editor' => 'Edytor strony', 'app_editor_desc' => 'Wybierz edytor używany przez użytkowników do edycji zawartości.', 'app_custom_html' => 'Własna zawartość w tagu ', 'app_custom_html_desc' => 'Zawartość dodana tutaj zostanie dołączona na dole sekcji każdej strony. Przydatne przy nadpisywaniu styli lub dodawaniu analityki.', + 'app_custom_html_disabled_notice' => 'Niestandardowa zawartość nagłówka HTML jest wyłączona na tej stronie ustawień aby zapewnić, że wszystkie błedne zmiany (braking change) mogą zostać cofnięte.', 'app_logo' => 'Logo aplikacji', 'app_logo_desc' => 'Ten obrazek powinien mieć nie więcej niż 43px wysokosci.
Większe obrazki zostaną zmniejszone.', 'app_primary_color' => 'Podstawowy kolor aplikacji', @@ -35,25 +38,33 @@ return [ '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_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.', - /** - * Registration settings - */ + // Color settings + 'content_colors' => 'Kolory zawartości', + 'content_colors_desc' => 'Ustawia kolory dla wszystkich elementów w hierarchii organizacji stron. Wybór kolorów o podobnej jasności do domyślnych kolorów jest zalecany dla czytelności.', + 'bookshelf_color' => 'Kolor półki', + 'book_color' => 'Kolor książki', + 'chapter_color' => 'Kolor rozdziału', + 'page_color' => 'Kolor strony', + 'page_draft_color' => 'Kolor szkicu strony', + // Registration Settings 'reg_settings' => 'Ustawienia rejestracji', - 'reg_allow' => 'Zezwolić na rejestrację?', + 'reg_enable' => 'Włącz rejestrację', + 'reg_enable_toggle' => 'Włącz rejestrację', + 'reg_enable_desc' => 'Kiedy rejestracja jest włączona użytkownicy mogą się rejestrować. Po rejestracji otrzymują jedną domyślną rolę użytkownika.', 'reg_default_role' => 'Domyślna rola użytkownika po rejestracji', - 'reg_confirm_email' => 'Wymagać potwierdzenia adresu e-mail?', + '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' => 'Potwierdzenie adresu email', + 'reg_email_confirmation_toggle' => 'Wymagaj potwierdzenia adresu email', 'reg_confirm_email_desc' => 'Jeśli restrykcje domenowe zostały ustawione, potwierdzenie adresu stanie się konieczne, a poniższa wartośc zostanie zignorowana.', 'reg_confirm_restrict_domain' => 'Restrykcje domenowe dot. adresu e-mail', 'reg_confirm_restrict_domain_desc' => 'Wprowadź listę domen adresów e-mail, rozdzieloną przecinkami, którym chciałbyś zezwolić na rejestrację. Wymusi to konieczność potwierdzenia adresu e-mail przez użytkownika przed uzyskaniem dostępu do aplikacji.
Pamiętaj, że użytkownicy będą mogli zmienić adres e-mail po rejestracji.', 'reg_confirm_restrict_domain_placeholder' => 'Brak restrykcji', - /** - * Maintenance settings - */ - + // Maintenance settings 'maint' => 'Konserwacja', 'maint_image_cleanup' => 'Czyszczenie obrazków', 'maint_image_cleanup_desc' => "Skanuje zawartość strony i poprzednie wersje, aby sprawdzić, które obrazy i rysunki są aktualnie używane, a które obrazy są zbędne. Przed uruchomieniem tej opcji należy utworzyć pełną kopię zapasową bazy danych i obrazków.", @@ -62,11 +73,15 @@ return [ 'maint_image_cleanup_warning' => 'Znaleziono :count potencjalnie niepotrzebnych obrazków. Czy na pewno chcesz je usunąć?', 'maint_image_cleanup_success' => ':count potencjalnie nieużywane obrazki zostały znalezione i usunięte!', 'maint_image_cleanup_nothing_found' => 'Nie znaleziono żadnych nieużywanych obrazków. Nic nie zostało usunięte!', + 'maint_send_test_email' => 'Wyślij testową wiadomość e-mail', + 'maint_send_test_email_desc' => 'Ta opcje wyśle wiadomość testową na adres e-mail podany w Twoim profilu', + 'maint_send_test_email_run' => 'Wyślij testową wiadomość e-mail', + 'maint_send_test_email_success' => 'E-mail wysłany na adres :address', + 'maint_send_test_email_mail_subject' => 'E-mail testowy', + 'maint_send_test_email_mail_greeting' => 'Wygląda na to, że wysyłka wiadomości e-mail działa!', + 'maint_send_test_email_mail_text' => 'Gratulacje! Otrzymałeś tego e-maila więc Twoje ustawienia poczty elektronicznej wydają się być prawidłowo skonfigurowane.', - /** - * Role settings - */ - + // Role Settings 'roles' => 'Role', 'role_user_roles' => 'Role użytkowników', 'role_create' => 'Utwórz nową rolę', @@ -85,11 +100,13 @@ return [ 'role_system' => 'Uprawnienia systemowe', 'role_manage_users' => 'Zarządzanie użytkownikami', 'role_manage_roles' => 'Zarządzanie rolami i uprawnieniami ról', - 'role_manage_entity_permissions' => 'Zarządzanie uprawnieniami podręczników, rozdziałów i stron', - 'role_manage_own_entity_permissions' => 'Zarządzanie uprawnieniami własnych podręczników, rozdziałów i stron', + 'role_manage_entity_permissions' => 'Zarządzanie uprawnieniami książek, rozdziałów i stron', + 'role_manage_own_entity_permissions' => 'Zarządzanie uprawnieniami własnych książek, rozdziałów i stron', + 'role_manage_page_templates' => 'Zarządzaj szablonami stron', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Zarządzanie ustawieniami aplikacji', 'role_asset' => 'Zarządzanie zasobami', - 'role_asset_desc' => 'Te ustawienia kontrolują zarządzanie zasobami systemu. Uprawnienia podręczników, rozdziałów i stron nadpisują te ustawienia.', + 'role_asset_desc' => 'Te ustawienia kontrolują zarządzanie zasobami systemu. Uprawnienia książek, rozdziałów i stron nadpisują te ustawienia.', 'role_asset_admins' => 'Administratorzy mają automatycznie dostęp do wszystkich treści, ale te opcję mogą być pokazywać lub ukrywać opcje interfejsu użytkownika.', 'role_all' => 'Wszyscy', 'role_own' => 'Własne', @@ -99,16 +116,22 @@ return [ 'role_users' => 'Użytkownicy w tej roli', 'role_users_none' => 'Brak użytkowników zapisanych do tej roli', - /** - * Users - */ - + // Users 'users' => 'Użytkownicy', 'user_profile' => 'Profil użytkownika', 'users_add_new' => 'Dodaj użytkownika', 'users_search' => 'Wyszukaj użytkownika', + 'users_details' => 'Szczegóły użytkownika', + 'users_details_desc' => 'Ustaw wyświetlaną nazwę i adres e-mail dla tego użytkownika. Adres e-mail zostanie wykorzystany do zalogowania się do aplikacji.', + 'users_details_desc_no_email' => 'Ustaw wyświetlaną nazwę dla tego użytkownika, aby inni mogli go rozpoznać.', 'users_role' => 'Role użytkownika', + 'users_role_desc' => 'Wybierz role, do których ten użytkownik zostanie przypisany. Jeśli użytkownik jest przypisany do wielu ról, uprawnienia z tych ról zostaną nałożone i otrzyma wszystkie uprawnienia przypisanych ról.', + 'users_password' => 'Hasło użytkownika', + 'users_password_desc' => 'Ustaw hasło logowania do aplikacji. Hasło musi mieć przynajmniej 6 znaków.', + 'users_send_invite_text' => 'Możesz wybrać wysłanie do tego użytkownika wiadomości e-mail z zaproszeniem, która pozwala mu ustawić własne hasło, w przeciwnym razie możesz ustawić je samemu.', + 'users_send_invite_option' => 'Wyślij e-mail z zaproszeniem', 'users_external_auth_id' => 'Zewnętrzne identyfikatory autentykacji', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Wypełnij poniżej tylko jeśli chcesz zmienić swoje hasło:', 'users_system_public' => 'Ten użytkownik reprezentuje każdego gościa odwiedzającego tę aplikację. Nie można się na niego zalogować, lecz jest przyznawany automatycznie.', 'users_delete' => 'Usuń użytkownika', @@ -122,10 +145,67 @@ return [ 'users_avatar' => 'Avatar użytkownika', 'users_avatar_desc' => 'Ten obrazek powinien posiadać wymiary 256x256px.', 'users_preferred_language' => 'Preferowany język', + 'users_preferred_language_desc' => 'Opcja ta zmieni język używany w interfejsie użytkownika aplikacji. Nie wpłynie to na zawartość stworzoną przez użytkownika.', 'users_social_accounts' => 'Konta społecznościowe', 'users_social_accounts_info' => 'Tutaj możesz połączyć kilka kont społecznościowych w celu łatwiejszego i szybszego logowania. Odłączenie konta tutaj nie autoryzowało dostępu. Odwołaj dostęp z ustawień profilu na podłączonym koncie społecznościowym.', 'users_social_connect' => 'Podłącz konto', 'users_social_disconnect' => 'Odłącz konto', 'users_social_connected' => ':socialAccount zostało dodane do Twojego profilu.', 'users_social_disconnected' => ':socialAccount zostało odłączone od Twojego profilu.', + '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' => 'العربية', + 'da' => 'Dansk', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// ]; diff --git a/resources/lang/pl/validation.php b/resources/lang/pl/validation.php index 6a7c13e80..249d20ca7 100644 --- a/resources/lang/pl/validation.php +++ b/resources/lang/pl/validation.php @@ -1,18 +1,13 @@ ':attribute musi zostać zaakceptowany.', 'active_url' => ':attribute nie jest prawidłowym adresem URL.', 'after' => ':attribute musi być datą następującą po :date.', @@ -35,12 +30,41 @@ return [ 'digits' => ':attribute musi mieć :digits cyfr.', 'digits_between' => ':attribute musi mieć od :min do :max cyfr.', 'email' => ':attribute musi być prawidłowym adresem e-mail.', + 'ends_with' => ':attribute musi kończyć się jedną z poniższych wartości: :values', 'filled' => ':attribute jest wymagany.', + 'gt' => [ + 'numeric' => ':attribute musi być większy niż :value.', + 'file' => ':attribute musi mieć rozmiar większy niż :value kilobajtów.', + 'string' => ':attribute musi mieć więcej niż :value znaków.', + 'array' => ':attribute musi mieć więcej niż :value elementów.', + ], + 'gte' => [ + 'numeric' => ':attribute musi być większy lub równy :value.', + 'file' => ':attribute musi mieć rozmiar większy niż lub równy :value kilobajtów.', + 'string' => ':attribute musi mieć :value lub więcej znaków.', + 'array' => ':attribute musi mieć :value lub więcej elementów.', + ], 'exists' => 'Wybrana wartość :attribute jest nieprawidłowa.', 'image' => ':attribute musi być obrazkiem.', + 'image_extension' => ':attribute musi mieć prawidłowe i wspierane rozszerzenie', 'in' => 'Wybrana wartość :attribute jest nieprawidłowa.', 'integer' => ':attribute musi być liczbą całkowitą.', 'ip' => ':attribute musi być prawidłowym adresem IP.', + 'ipv4' => ':attribute musi być prawidłowym adresem IPv4.', + 'ipv6' => ':attribute musi być prawidłowym adresem IPv6.', + 'json' => ':attribute musi być prawidłowym ciągiem JSON.', + 'lt' => [ + 'numeric' => ':attribute musi być mniejszy niż :value.', + 'file' => ':attribute musi mieć rozmiar mniejszy niż :value kilobajtów.', + 'string' => ':attribute musi mieć mniej niż :value znaków.', + 'array' => ':attribute musi mieć mniej niż :value elementów.', + ], + 'lte' => [ + 'numeric' => ':attribute musi być mniejszy lub równy :value.', + 'file' => ':attribute musi mieć rozmiar mniejszy lub równy:value kilobajtów.', + 'string' => ':attribute nie może mieć więcej niż :value znaków.', + 'array' => ':attribute nie może mieć więcej niż :value elementów.', + ], 'max' => [ 'numeric' => 'Wartość :attribute nie może być większa niż :max.', 'file' => 'Wielkość :attribute nie może być większa niż :max kilobajtów.', @@ -54,7 +78,9 @@ 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ą.', 'regex' => 'Format :attribute jest nieprawidłowy.', 'required' => 'Pole :attribute jest wymagane.', @@ -74,35 +100,15 @@ return [ 'timezone' => ':attribute musi być prawidłową strefą czasową.', 'unique' => ':attribute zostało już zajęte.', 'url' => 'Format :attribute jest nieprawidłowy.', + 'uploaded' => 'Plik nie może zostać wysłany. Serwer nie akceptuje plików o takim rozmiarze.', - /* - |-------------------------------------------------------------------------- - | Custom Validation Language Lines - |-------------------------------------------------------------------------- - | - | Here you may specify custom validation messages for attributes using the - | convention "attribute.rule" to name the lines. This makes it quick to - | specify a specific custom language line for a given attribute rule. - | - */ - + // Custom validation lines 'custom' => [ 'password-confirm' => [ 'required_with' => 'Potwierdzenie hasła jest wymagane.', ], ], - /* - |-------------------------------------------------------------------------- - | Custom Validation Attributes - |-------------------------------------------------------------------------- - | - | The following language lines are used to swap attribute place-holders - | with something more reader friendly such as E-Mail Address instead - | of "email". This simply helps us make messages a little cleaner. - | - */ - + // Custom validation attributes 'attributes' => [], - ]; diff --git a/resources/lang/pt_BR/activities.php b/resources/lang/pt_BR/activities.php index 91417cc8b..9789fe3be 100644 --- a/resources/lang/pt_BR/activities.php +++ b/resources/lang/pt_BR/activities.php @@ -4,44 +4,44 @@ * Is used for all the text within activity logs & notifications. */ return [ - + // Pages - 'page_create' => 'página criada', + 'page_create' => 'criou a página', 'page_create_notification' => 'Página criada com sucesso', - 'page_update' => 'página atualizada', + 'page_update' => 'atualizou a página', 'page_update_notification' => 'Página atualizada com sucesso', - 'page_delete' => 'página excluída', + 'page_delete' => 'excluiu a página', 'page_delete_notification' => 'Página excluída com sucesso', - 'page_restore' => 'página restaurada', + 'page_restore' => 'restaurou a página', 'page_restore_notification' => 'Página restaurada com sucesso', - 'page_move' => 'página movida', + 'page_move' => 'moveu a página', // Chapters - 'chapter_create' => 'capítulo criado', + 'chapter_create' => 'criou o capítulo', '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_update' => 'atualizou o capítulo', + 'chapter_update_notification' => 'Capítulo atualizado com sucesso', + 'chapter_delete' => 'excluiu o capítulo', 'chapter_delete_notification' => 'Capítulo excluído com sucesso', - 'chapter_move' => 'capitulo movido', + 'chapter_move' => 'moveu o capítulo', // Books - 'book_create' => 'livro criado', + 'book_create' => 'criou o livro', 'book_create_notification' => 'Livro criado com sucesso', - 'book_update' => 'livro atualizado', + 'book_update' => 'atualizou o livro', 'book_update_notification' => 'Livro atualizado com sucesso', - 'book_delete' => 'livro excluído', + 'book_delete' => 'excluiu o livro', 'book_delete_notification' => 'Livro excluído com sucesso', - 'book_sort' => 'livro classificado', - 'book_sort_notification' => 'Livro reclassificado com sucesso', + 'book_sort' => 'ordenou o livro', + 'book_sort_notification' => 'Livro reordenado com sucesso', // Bookshelves - 'bookshelf_create' => 'prateleira de livros criada', - 'bookshelf_create_notification' => 'Prateleira de Livros criada com sucesso', - 'bookshelf_update' => 'prateleira de livros atualizada', - 'bookshelf_update_notification' => 'Prateleira de Livros atualizada com sucesso', - 'bookshelf_delete' => 'prateleira de livros excluída', - 'bookshelf_delete_notification' => 'Prateleira de Livros excluída com sucesso', + 'bookshelf_create' => 'criou a prateleira', + 'bookshelf_create_notification' => 'Prateleira criada com sucesso', + 'bookshelf_update' => 'atualizou a prateleira', + 'bookshelf_update_notification' => 'Prateleira atualizada com sucesso', + 'bookshelf_delete' => 'excluiu a prateleira', + 'bookshelf_delete_notification' => 'Prateleira excluída com sucesso', // Other 'commented_on' => 'comentou em', diff --git a/resources/lang/pt_BR/auth.php b/resources/lang/pt_BR/auth.php index 20dc690af..fd0cf823d 100644 --- a/resources/lang/pt_BR/auth.php +++ b/resources/lang/pt_BR/auth.php @@ -6,14 +6,14 @@ */ return [ - 'failed' => 'As credenciais fornecidas não puderam ser validadas em nossos registros..', + 'failed' => 'As credenciais fornecidas não puderam ser validadas em nossos registros.', 'throttle' => 'Muitas tentativas de login. Por favor, tente novamente em :seconds segundos.', // Login & Register - 'sign_up' => 'Registrar-se', + 'sign_up' => 'Criar Conta', 'log_in' => 'Entrar', 'log_in_with' => 'Entrar com :socialDriver', - 'sign_up_with' => 'Registrar com :socialDriver', + 'sign_up_with' => 'Cadastre-se com :socialDriver', 'logout' => 'Sair', 'name' => 'Nome', @@ -21,47 +21,57 @@ return [ 'email' => 'E-mail', 'password' => 'Senha', 'password_confirm' => 'Confirmar Senha', - 'password_hint' => 'Senha deverá ser maior que 5 caracteres', + 'password_hint' => 'Deve ser maior que 7 caracteres', 'forgot_password' => 'Esqueceu a senha?', 'remember_me' => 'Lembrar de mim', 'ldap_email_hint' => 'Por favor, digite um e-mail para essa conta.', - 'create_account' => 'Criar conta', - 'already_have_account' => 'Você já possui uma conta?', + 'create_account' => 'Criar Conta', + 'already_have_account' => 'Já possui uma conta?', 'dont_have_account' => 'Não possui uma conta?', - 'social_login' => 'Login social', - 'social_registration' => 'Registro social', - 'social_registration_text' => 'Registre e entre usando outro serviço.', + 'social_login' => 'Login Social', + 'social_registration' => 'Cadastro Social', + 'social_registration_text' => 'Cadastre-se e entre utilizando outro serviço.', - 'register_thanks' => 'Obrigado por efetuar o registro!', + 'register_thanks' => 'Obrigado por se cadastrar!', 'register_confirm' => 'Por favor, verifique seu e-mail e clique no botão de confirmação para acessar :appName.', - 'registrations_disabled' => 'Registros estão temporariamente desabilitados', + 'registrations_disabled' => 'Cadastros estão temporariamente desabilitados', 'registration_email_domain_invalid' => 'O domínio de e-mail usado não tem acesso permitido a essa aplicação', - 'register_success' => 'Obrigado por se registrar! Você agora encontra-se registrado e logado..', + 'register_success' => 'Obrigado por se cadastrar! Você agora encontra-se cadastrado(a) e logado(a).', // Password Reset - 'reset_password' => 'Resetar senha', - 'reset_password_send_instructions' => 'Digite seu e-mail abaixo e o sistema enviará uma mensagem com o link de reset de senha.', - 'reset_password_send_button' => 'Enviar o link de reset de senha', - 'reset_password_sent_success' => 'Um link de reset de senha foi enviado para :email.', - 'reset_password_success' => 'Sua senha foi resetada com sucesso.', - 'email_reset_subject' => 'Resetar a senha de :appName', - 'email_reset_text' => 'Você recebeu esse e-mail pois recebemos uma solicitação de reset de senha para sua conta.', - 'email_reset_not_requested' => 'Caso não tenha sido você a solicitar o reset de senha, ignore esse e-mail.', + 'reset_password' => 'Redefinir Senha', + 'reset_password_send_instructions' => 'Insira seu e-mail abaixo e uma mensagem com o link de redefinição de senha lhe será enviada.', + 'reset_password_send_button' => 'Enviar o Link de Redefinição', + 'reset_password_sent_success' => 'Um link de redefinição de senha foi enviado para :email.', + 'reset_password_success' => 'Sua senha foi redefinida com sucesso.', + 'email_reset_subject' => 'Redefina a senha de :appName', + 'email_reset_text' => 'Você recebeu esse 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 esse e-mail.', // Email Confirmation 'email_confirm_subject' => 'Confirme seu e-mail para :appName', - 'email_confirm_greeting' => 'Obrigado por se registrar em :appName!', + 'email_confirm_greeting' => 'Obrigado por se cadastrar em :appName!', 'email_confirm_text' => 'Por favor, confirme seu endereço de e-mail clicando no botão abaixo:', 'email_confirm_action' => 'Confirmar E-mail', - 'email_confirm_send_error' => 'E-mail de confirmação é requerido, mas o sistema não pôde enviar a mensagem. Por favor, entre em contato com o admin para se certificar que o serviço de envio de e-mails está corretamente configurado.', + 'email_confirm_send_error' => 'A confirmação de e-mail é requerida, mas o sistema não pôde enviar a mensagem. Por favor, entre em contato com o administrador para se certificar que o serviço de envio de e-mails está corretamente configurado.', 'email_confirm_success' => 'Seu e-mail foi confirmado!', - 'email_confirm_resent' => 'E-mail de confirmação reenviado. Por favor, cheque sua caixa postal.', + 'email_confirm_resent' => 'E-mail de confirmação reenviado. Por favor, verifique sua caixa de entrada.', - 'email_not_confirmed' => 'Endereço de e-mail não foi confirmado', + 'email_not_confirmed' => 'Endereço de E-mail Não Confirmado', 'email_not_confirmed_text' => 'Seu endereço de e-mail ainda não foi confirmado.', - 'email_not_confirmed_click_link' => 'Por favor, clique no link no e-mail que foi enviado após o registro.', + 'email_not_confirmed_click_link' => 'Por favor, clique no link no e-mail que foi enviado após o cadastro.', 'email_not_confirmed_resend' => 'Caso não encontre o e-mail você poderá reenviar a confirmação usando o formulário abaixo.', - 'email_not_confirmed_resend_button' => 'Reenviar o e-mail de confirmação', + 'email_not_confirmed_resend_button' => 'Reenviar o E-mail de Confirmação', + + // User Invite + 'user_invite_email_subject' => 'Você recebeu um convite para :appName!', + 'user_invite_email_greeting' => 'Uma conta foi criada para você em :appName.', + 'user_invite_email_text' => 'Clique no botão abaixo para definir uma senha de conta e obter acesso:', + 'user_invite_email_action' => 'Defina a Senha da Conta', + 'user_invite_page_welcome' => 'Bem-vindo(a) a :appName!', + 'user_invite_page_text' => 'Para finalizar sua conta e obter acesso, você precisa definir uma senha que será usada para efetuar login em :appName em futuras visitas.', + 'user_invite_page_confirm_button' => 'Confirmar Senha', + 'user_invite_success' => 'Senha definida, você agora tem acesso a :appName!' ]; \ No newline at end of file diff --git a/resources/lang/pt_BR/common.php b/resources/lang/pt_BR/common.php index c6750a954..f32774014 100644 --- a/resources/lang/pt_BR/common.php +++ b/resources/lang/pt_BR/common.php @@ -11,20 +11,20 @@ return [ 'save' => 'Salvar', 'continue' => 'Continuar', 'select' => 'Selecionar', - 'toggle_all' => 'Alternar Tudo', + 'toggle_all' => 'Alternar Todos', 'more' => 'Mais', // Form Labels 'name' => 'Nome', 'description' => 'Descrição', - 'role' => 'Regra', + 'role' => 'Cargo', 'cover_image' => 'Imagem de capa', - 'cover_image_description' => 'Esta imagem deve ser aproximadamente 300x170px.', + 'cover_image_description' => 'Esta imagem deve ser aproximadamente 440x250px.', // Actions 'actions' => 'Ações', 'view' => 'Visualizar', - 'view_all' => 'Ver Tudo', + 'view_all' => 'Visualizar Tudo', 'create' => 'Criar', 'update' => 'Atualizar', 'edit' => 'Editar', @@ -35,11 +35,16 @@ return [ 'delete' => 'Excluir', 'search' => 'Pesquisar', 'search_clear' => 'Limpar Pesquisa', - 'reset' => 'Resetar', + 'reset' => 'Redefinir', 'remove' => 'Remover', 'add' => 'Adicionar', + 'fullscreen' => 'Tela cheia', // Sort Options + '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', @@ -55,16 +60,18 @@ return [ 'grid_view' => 'Visualização em Grade', 'list_view' => 'Visualização em Lista', 'default' => 'Padrão', + 'breadcrumb' => 'Caminho', // Header + 'profile_menu' => 'Menu de Perfil', 'view_profile' => 'Visualizar Perfil', 'edit_profile' => 'Editar Perfil', // Layout tabs - 'tab_info' => 'Info', + 'tab_info' => 'Informações', 'tab_content' => 'Conteúdo', // 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', -]; \ No newline at end of file +]; diff --git a/resources/lang/pt_BR/components.php b/resources/lang/pt_BR/components.php index b9f1c3a38..e45101452 100644 --- a/resources/lang/pt_BR/components.php +++ b/resources/lang/pt_BR/components.php @@ -5,27 +5,27 @@ return [ // Image Manager - 'image_select' => 'Selecionar imagem', - 'image_all' => 'Todos', + 'image_select' => 'Selecionar Imagem', + 'image_all' => 'Todas', 'image_all_title' => 'Visualizar todas as imagens', 'image_book_title' => 'Visualizar imagens relacionadas a esse livro', 'image_page_title' => 'visualizar imagens relacionadas a essa página', 'image_search_hint' => 'Pesquisar imagem por nome', - 'image_uploaded' => 'Carregado :uploadedDate', + 'image_uploaded' => 'Adicionada em :uploadedDate', 'image_load_more' => 'Carregar Mais', 'image_image_name' => 'Nome da Imagem', 'image_delete_used' => 'Essa imagem é usada nas páginas abaixo.', 'image_delete_confirm' => 'Clique em Excluir novamente para confirmar que você deseja mesmo eliminar a imagem.', 'image_select_image' => 'Selecionar Imagem', 'image_dropzone' => 'Arraste imagens ou clique aqui para fazer upload', - 'images_deleted' => 'Imagens excluídas', - 'image_preview' => 'Virtualização de Imagem', + 'images_deleted' => 'Imagens Excluídas', + 'image_preview' => 'Pré-Visualização de Imagem', 'image_upload_success' => 'Upload de imagem efetuado com sucesso', - 'image_update_success' => 'Upload de detalhes da imagem efetuado com sucesso', + 'image_update_success' => 'Detalhes da imagem atualizados com sucesso', 'image_delete_success' => 'Imagem excluída com sucesso', 'image_upload_remove' => 'Remover', - // Code editor + // Code Editor 'code_editor' => 'Editar Código', 'code_language' => 'Linguagem do Código', 'code_content' => 'Código', diff --git a/resources/lang/pt_BR/entities.php b/resources/lang/pt_BR/entities.php index 7ce5ef01e..323ce083f 100644 --- a/resources/lang/pt_BR/entities.php +++ b/resources/lang/pt_BR/entities.php @@ -6,29 +6,29 @@ return [ // Shared - 'recently_created' => 'Recentemente Criado', - 'recently_created_pages' => 'Páginas Recentemente Criadas', - 'recently_updated_pages' => 'Páginas Recentemente Atualizadas', - 'recently_created_chapters' => 'Capítulos Recentemente Criados', - 'recently_created_books' => 'Livros Recentemente Criados', - 'recently_created_shelves' => 'Prateleiras Recentemente Criadas', - 'recently_update' => 'Recentemente Atualizado', - 'recently_viewed' => 'Recentemente Visualizado', + 'recently_created' => 'Criados 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' => 'Prateleiras 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 em :timeLength', - 'meta_created_name' => 'Criado em :timeLength por :user', - 'meta_updated' => 'Atualizado em :timeLength', - 'meta_updated_name' => 'Atualizado em :timeLength por :user', + 'meta_created' => 'Criado :timeLength', + 'meta_created_name' => 'Criado :timeLength por :user', + 'meta_updated' => 'Atualizado :timeLength', + 'meta_updated_name' => 'Atualizado :timeLength por :user', 'entity_select' => 'Seleção de Entidade', 'images' => 'Imagens', - 'my_recent_drafts' => 'Meus rascunhos recentes', - 'my_recently_viewed' => 'Meus itens recentemente visto', + 'my_recent_drafts' => 'Meus Rascunhos Recentes', + 'my_recently_viewed' => 'Visualizados por mim Recentemente', 'no_pages_viewed' => 'Você não visualizou nenhuma página', - 'no_pages_recently_created' => 'Nenhuma página recentemente criada', - 'no_pages_recently_updated' => 'Nenhuma página recentemente atualizada', + 'no_pages_recently_created' => 'Nenhuma página criada recentemente', + 'no_pages_recently_updated' => 'Nenhuma página atualizada recentemente', 'export' => 'Exportar', 'export_html' => 'Arquivo Web Contained', 'export_pdf' => 'Arquivo PDF', @@ -36,7 +36,7 @@ return [ // Permissions and restrictions 'permissions' => 'Permissões', - 'permissions_intro' => 'Uma vez habilitado, as permissões terão prioridade sobre outro conjunto de permissões.', + 'permissions_intro' => 'Uma vez habilitadas, estas permissões terão prioridade sobre outro conjunto de permissões.', 'permissions_enable' => 'Habilitar Permissões Customizadas', 'permissions_save' => 'Salvar Permissões', @@ -50,10 +50,10 @@ return [ 'search_filters' => 'Filtros de Pesquisa', 'search_content_type' => 'Tipo de Conteúdo', 'search_exact_matches' => 'Correspondências Exatas', - 'search_tags' => 'Tags', + 'search_tags' => 'Persquisar Tags', 'search_options' => 'Opções', - 'search_viewed_by_me' => 'Visto por mim', - 'search_not_viewed_by_me' => 'Não visto por mim', + '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', @@ -62,7 +62,7 @@ return [ 'search_updated_after' => 'Atualizado depois de', 'search_created_before' => 'Criado antes de', 'search_created_after' => 'Criado depois de', - 'search_set_date' => 'Definir data', + 'search_set_date' => 'Definir Data', 'search_update' => 'Refazer Pesquisa', // Shelves @@ -82,20 +82,20 @@ return [ 'shelves_add_books' => 'Adicionar livros a esta prateleira', 'shelves_drag_books' => 'Arraste livros aqui para adicioná-los a esta prateleira', 'shelves_empty_contents' => 'Esta prateleira não possui livros atribuídos a ela', - 'shelves_edit_and_assign' => 'Edit shelf to assign books', + 'shelves_edit_and_assign' => 'Editar prateleira para atribuir livros', 'shelves_edit_named' => 'Editar Prateleira de Livros :name', 'shelves_edit' => 'Edit Prateleira de Livros', 'shelves_delete' => 'Excluir Prateleira de Livros', 'shelves_delete_named' => 'Excluir Prateleira de Livros :name', - 'shelves_delete_explain' => "A ação vai excluír a prateleira de livros com o nome ':name'. Livros contidos não serão excluídos", + 'shelves_delete_explain' => "A ação vai excluír a prateleira com o nome ':name'. Livros contidos não serão excluídos.", 'shelves_delete_confirmation' => 'Você tem certeza que quer excluir esta prateleira de livros?', - 'shelves_permissions' => 'Permissões da Prateleira de Livros', - 'shelves_permissions_updated' => 'Permissões da Prateleira de Livros Atualizada', - 'shelves_permissions_active' => 'Permissões da Prateleira de Livros Ativadas', + 'shelves_permissions' => 'Permissões da Prateleira', + 'shelves_permissions_updated' => 'Permissões da Prateleira Atualizadas', + 'shelves_permissions_active' => 'Permissões da Prateleira 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 prateleira de livros a todos os livros contidos nela. Antes de ativar, assegure-se de que quaisquer alterações nas permissões desta prateleira de livros tenham sido salvas.', - 'shelves_copy_permission_success' => 'Permissões da prateleira de livros copiada para :count livros', + 'shelves_copy_permissions_explain' => 'Isto aplicará as configurações de permissões atuais desta prateleira a todos os livros contidos nela. Antes de ativar, assegure-se de que quaisquer alterações nas permissões desta prateleira tenham sido salvas.', + 'shelves_copy_permission_success' => 'Permissões da prateleira copiadas para :count livros', // Books 'book' => 'Livro', @@ -108,23 +108,23 @@ return [ 'books_new_action' => 'Novo Livro', 'books_popular_empty' => 'Os livros mais populares aparecerão aqui.', 'books_new_empty' => 'Os livros criados mais recentemente aparecerão aqui.', - 'books_create' => 'Criar novo Livro', + 'books_create' => 'Criar Novo Livro', 'books_delete' => 'Excluir Livro', 'books_delete_named' => 'Excluir Livro :bookName', - 'books_delete_explain' => 'A ação vai excluír o livro com o nome \':bookName\'. Todas as páginas e capítulos serão removidos.', - 'books_delete_confirmation' => 'Você tem certeza que quer excluír o Livro?', + 'books_delete_explain' => 'A ação vai excluir o livro com o nome \':bookName\'. Todas as páginas e capítulos serão removidos.', + 'books_delete_confirmation' => 'Você tem certeza que quer excluir o Livro?', 'books_edit' => 'Editar Livro', 'books_edit_named' => 'Editar Livro :bookName', 'books_form_book_name' => 'Nome do Livro', 'books_save' => 'Salvar Livro', 'books_permissions' => 'Permissões do Livro', 'books_permissions_updated' => 'Permissões do Livro Atualizadas', - 'books_empty_contents' => 'Nenhuma página ou capítulo criado para esse livro.', + '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 Ativadas', - 'books_search_this' => 'Pesquisar esse livro', + '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', @@ -143,10 +143,10 @@ return [ 'chapters_popular' => 'Capítulos Populares', 'chapters_new' => 'Novo Capítulo', 'chapters_create' => 'Criar Novo Capítulo', - 'chapters_delete' => 'Excluír Capítulo', + 'chapters_delete' => 'Excluir Capítulo', 'chapters_delete_named' => 'Excluir Capítulo :chapterName', - 'chapters_delete_explain' => 'A ação vai excluír o capítulo de nome \':chapterName\'. Todas as páginas do capítulo serão removidas e adicionadas diretamente ao livro pai.', - 'chapters_delete_confirm' => 'Tem certeza que deseja excluír o capítulo?', + 'chapters_delete_explain' => 'A ação vai excluir o capítulo de nome \':chapterName\'. Todas as páginas do capítulo serão removidas e adicionadas diretamente ao livro pai.', + 'chapters_delete_confirm' => 'Tem certeza que deseja excluir o capítulo?', 'chapters_edit' => 'Editar Capítulo', 'chapters_edit_named' => 'Editar Capítulo :chapterName', 'chapters_save' => 'Salvar Capítulo', @@ -155,106 +155,110 @@ return [ 'chapter_move_success' => 'Capítulo movido para :bookName', 'chapters_permissions' => 'Permissões do Capítulo', 'chapters_empty' => 'Nenhuma página existente nesse capítulo.', - 'chapters_permissions_active' => 'Permissões de Capítulo Ativadas', + 'chapters_permissions_active' => 'Permissões de Capítulo Ativas', 'chapters_permissions_success' => 'Permissões de Capítulo Atualizadas', - 'chapters_search_this' => 'Pesquisar este Capítulo', + 'chapters_search_this' => 'Pesquisar neste Capítulo', // Pages 'page' => 'Página', 'pages' => 'Páginas', 'x_pages' => ':count Página|:count Páginas', - 'pages_popular' => 'Páginas Popular', + 'pages_popular' => 'Páginas Populares', 'pages_new' => 'Nova Página', 'pages_attachments' => 'Anexos', - 'pages_navigation' => 'Página de Navegação', - 'pages_delete' => 'Excluír Página', - 'pages_delete_named' => 'Excluír Página :pageName', - 'pages_delete_draft_named' => 'Excluir rascunho de Página de nome :pageName', - 'pages_delete_draft' => 'Excluir rascunho de Página', + 'pages_navigation' => 'Navegação da Página', + 'pages_delete' => 'Excluir Página', + 'pages_delete_named' => 'Excluir Página :pageName', + 'pages_delete_draft_named' => 'Excluir Rascunho de Página de nome :pageName', + 'pages_delete_draft' => 'Excluir Rascunho de Página', 'pages_delete_success' => 'Página excluída', - 'pages_delete_draft_success' => 'Página de rascunho excluída', + 'pages_delete_draft_success' => 'Rascunho de página excluído', 'pages_delete_confirm' => 'Tem certeza que deseja excluir a página?', 'pages_delete_draft_confirm' => 'Tem certeza que deseja excluir o rascunho de página?', 'pages_editing_named' => 'Editando a Página :pageName', + 'pages_edit_draft_options' => 'Opções de Rascunho', 'pages_edit_save_draft' => 'Salvar Rascunho', - 'pages_edit_draft' => 'Editar rascunho de Página', + 'pages_edit_draft' => 'Editar Rascunho de Página', 'pages_editing_draft' => 'Editando Rascunho', 'pages_editing_page' => 'Editando Página', 'pages_edit_draft_save_at' => 'Rascunho salvo em ', - 'pages_edit_delete_draft' => 'Excluir rascunho', - 'pages_edit_discard_draft' => 'Descartar rascunho', - 'pages_edit_set_changelog' => 'Definir Changelog', - 'pages_edit_enter_changelog_desc' => 'Digite uma breve descrição das mudanças efetuadas por você', - 'pages_edit_enter_changelog' => 'Entrar no Changelog', + 'pages_edit_delete_draft' => 'Excluir 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 você', + 'pages_edit_enter_changelog' => 'Insira Alterações', 'pages_save' => 'Salvar Página', - 'pages_title' => 'Título de 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_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' => 'Página não está dentro de um Capítulo', + 'pages_not_in_chapter' => '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 de Página', - 'pages_permissions_success' => 'Permissões de Página atualizadas', + 'pages_permissions' => 'Permissões da Página', + 'pages_permissions_success' => 'Permissões da Página atualizadas', 'pages_revision' => 'Revisão', - 'pages_revisions' => 'Revisões de Página', + '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_revisions_created_by' => 'Criado por', + 'pages_revisions_created_by' => 'Criada por', 'pages_revisions_date' => 'Data da Revisão', 'pages_revisions_number' => '#', 'pages_revisions_numbered' => 'Revisão #:id', - 'pages_revisions_changelog' => 'Changelog', 'pages_revisions_numbered_changes' => 'Alterações da Revisão #:id', - 'pages_revisions_changes' => 'Mudanças', - 'pages_revisions_current' => 'Versão atual', - 'pages_revisions_preview' => 'Preview', + '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' => 'Copia Link', - 'pages_edit_content_link' => 'Editar conteúdo', + '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 editando um rascunho que foi salvo da última vez em :timeDiff.', 'pages_draft_edited_notification' => 'Essa página foi atualizada desde então. É recomendado que você descarte esse rascunho.', 'pages_draft_edit_active' => [ - 'start_a' => ':count usuários que iniciaram edição dessa página', + 'start_a' => ':count usuários iniciaram a edição dessa página', 'start_b' => ':userName iniciou a edição dessa página', 'time_a' => 'desde que a página foi atualizada pela última vez', 'time_b' => 'nos últimos :minCount minutos', 'message' => ':start :time. Tome cuidado para não sobrescrever atualizações de outras pessoas!', ], - 'pages_draft_discarded' => 'Rascunho descartado. O editor foi atualizado com a página atualizada', + '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 + // Editor Sidebar 'page_tags' => 'Tags de Página', 'chapter_tags' => 'Tags de Capítulo', 'book_tags' => 'Tags de Livro', 'shelf_tags' => 'Tags de Prateleira', 'tag' => 'Tag', - 'tags' => '', + 'tags' => 'Tags', + 'tag_name' => 'Nome da Tag', 'tag_value' => 'Valor da Tag (Opcional)', - 'tags_explain' => "Adicione algumas tags para melhor categorizar seu conteúdo. \n Você pode atrelar um valor para uma tag para uma organização mais consistente.", + 'tags_explain' => "Adicione algumas tags para melhor categorizar seu conteúdo. \n Você pode atribuir valores às tags para uma organização mais complexa.", 'tags_add' => 'Adicionar outra tag', + 'tags_remove' => 'Remover essa tag', 'attachments' => 'Anexos', - 'attachments_explain' => 'Faça o Upload de alguns arquivos ou anexo algum link para ser mostrado na sua página. Eles estarão visíveis na barra lateral à direita da página.', + 'attachments_explain' => 'Faça o upload de 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' => 'Mudanças são salvas instantaneamente.', 'attachments_items' => 'Itens Anexados', - 'attachments_upload' => 'Upload de arquivos', + 'attachments_upload' => 'Upload de Arquivos', 'attachments_link' => 'Links Anexados', 'attachments_set_link' => 'Definir Link', 'attachments_delete_confirm' => 'Clique novamente em Excluir para confirmar a exclusão desse anexo.', 'attachments_dropzone' => 'Arraste arquivos para cá ou clique para anexar arquivos', 'attachments_no_files' => 'Nenhum arquivo foi enviado', - 'attachments_explain_link' => 'Você pode anexar um link se preferir não fazer o upload do arquivo. O link poderá ser para uma outra página ou link para um arquivo na nuvem.', + 'attachments_explain_link' => 'Você pode anexar um link se preferir não fazer o upload 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 para o Anexo', 'attachments_link_url' => 'Link para o Arquivo', @@ -262,13 +266,19 @@ return [ 'attach' => 'Anexar', '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-lo', + 'attachments_edit_drop_upload' => 'Arraste arquivos para cá ou clique para anexar arquivos e sobrescreve-los', 'attachments_order_updated' => 'Ordem dos anexos atualizada', 'attachments_updated_success' => 'Detalhes dos anexos atualizados', 'attachments_deleted' => 'Anexo excluído', 'attachments_file_uploaded' => 'Upload 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' => 'Você pode definir esta página como um modelo para que 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' => 'Usuário por :time', @@ -287,13 +297,13 @@ return [ 'comment_save' => 'Salvar comentário', 'comment_saving' => 'Salvando comentário...', 'comment_deleting' => 'Removendo comentário...', - 'comment_new' => 'Novo comentário', + 'comment_new' => 'Novo Comentário', 'comment_created' => 'comentado :createDiff', 'comment_updated' => 'Editado :updateDiff por :username', 'comment_deleted_success' => 'Comentário removido', 'comment_created_success' => 'Comentário adicionado', 'comment_updated_success' => 'Comentário editado', - 'comment_delete_confirm' => 'Você tem certeza de que quer deletar este comentário?', + 'comment_delete_confirm' => 'Você tem certeza de que deseja excluir este comentário?', 'comment_in_reply_to' => 'Em resposta à :commentId', // Revision diff --git a/resources/lang/pt_BR/errors.php b/resources/lang/pt_BR/errors.php index c5b1a9f92..d7aa69bf0 100644 --- a/resources/lang/pt_BR/errors.php +++ b/resources/lang/pt_BR/errors.php @@ -5,37 +5,44 @@ return [ // Permissions - 'permission' => 'Você não tem permissões para acessar a página requerida.', + 'permission' => 'Você não tem permissão para acessar a página requerida.', 'permissionJson' => 'Você não tem permissão para realizar a ação requerida.', // Auth 'error_user_exists_different_creds' => 'Um usuário com o e-mail :email já existe mas com credenciais diferentes.', 'email_already_confirmed' => 'E-mail já foi confirmado. Tente efetuar o login.', - 'email_confirmation_invalid' => 'Esse token de confirmação não é válido ou já foi utilizado. Por favor, tente efetuar o registro novamente.', + 'email_confirmation_invalid' => 'Esse token de confirmação não é válido ou já foi utilizado. Por favor, tente cadastrar-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' => 'As extensões LDAP PHP não estão instaladas', + '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' => 'Login já efetuado', + 'saml_user_not_registered' => 'O usuário :name não está cadastrado e o cadastro automático está desativado', + 'saml_no_email_address' => 'Não foi possível encontrar um endereço de e-mail para este usuário nos dados providos 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. Após o login, navegar para o caminho anterior pode causar um problema.', + 'saml_fail_authed' => 'Login utilizando :system falhou. Sistema não forneceu autorização bem sucedida', 'social_no_action_defined' => 'Nenhuma ação definida', 'social_login_bad_response' => "Erro recebido durante o login :socialAccount: \n:error", - 'social_account_in_use' => 'Essa conta :socialAccount já está em uso. Por favor, tente se logar usando a opção :socialAccount', - 'social_account_email_in_use' => 'O e-mail :email já está e muso. Se você já tem uma conta você poderá se conectar a conta :socialAccount a partir das configurações de seu perfil.', - 'social_account_existing' => 'Essa conta :socialAccount já está atrelada a esse perfil.', - 'social_account_already_used_existing' => 'Essa conta :socialAccount já está sendo usada por outro usuário.', - 'social_account_not_used' => 'Essa conta :socialAccount não está atrelada a nenhum usuário. Por favor, faça o link da conta com suas configurações de perfil. ', - 'social_account_register_instructions' => 'Se você não tem uma conta, você poderá fazer o registro usando a opção :socialAccount', + 'social_account_in_use' => 'Essa 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 você já tem uma conta você poderá se conectar a conta :socialAccount a partir das configurações de seu perfil.', + 'social_account_existing' => 'Essa conta :socialAccount já está vinculada a esse perfil.', + 'social_account_already_used_existing' => 'Essa conta :socialAccount já está sendo utilizada por outro usuário.', + 'social_account_not_used' => 'Essa conta :socialAccount não está vinculada a nenhum usuário. Por favor vincule a conta nas suas configurações de perfil. ', + 'social_account_register_instructions' => 'Se você não tem uma conta, você poderá se cadastrar usando a opção :socialAccount.', 'social_driver_not_found' => 'Social driver não encontrado', 'social_driver_not_configured' => 'Seus parâmetros socials de :socialAccount não estão configurados corretamente.', + 'invite_token_expired' => 'Esse link de convite expirou. Alternativamente, você pode tentar redefinir a senha da sua conta.', // System 'path_not_writable' => 'O caminho de destino (:filePath) de upload de arquivo não possui permissão de escrita. Certifique-se que ele possui direitos de escrita no servidor.', - 'cannot_get_image_from_url' => 'Não foi possivel capturar a imagem a partir de :url', + '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 upload de arquivos com esse tamanho. Por favor, tente fazer o upload de arquivos de menor tamanho.', - 'uploaded' => 'O servidor não permite o upload de arquivos com esse tamanho. Por favor, tente fazer o upload de arquivos de menor tamanho.', + 'uploaded' => 'O servidor não permite o upload de arquivos com esse tamanho. Por favor, tente fazer o upload de arquivos de menor tamanho.', 'image_upload_error' => 'Um erro aconteceu enquanto o servidor tentava efetuar o upload da imagem', - 'image_upload_type_error' => 'O tipo de imagem que está sendo feito upload é inválido', + 'image_upload_type_error' => 'O tipo de imagem que está sendo enviada é inválido', 'file_upload_timeout' => 'O upload do arquivo expirou.', // Attachments @@ -43,8 +50,8 @@ return [ 'attachment_not_found' => 'Anexo não encontrado', // Pages - 'page_draft_autosave_fail' => 'Falhou ao tentar salvar o rascunho. Certifique-se que a conexão de internet está funcional antes de tentar salvar essa página', - 'page_custom_home_deletion' => 'Não pode deletar uma página que está definida como página inicial', + 'page_draft_autosave_fail' => 'Falha ao tentar salvar o rascunho. Certifique-se que a conexão de internet está funcional antes de tentar salvar essa página', + 'page_custom_home_deletion' => 'Não é possível excluir uma página que está definida como página inicial', // Entities 'entity_not_found' => 'Entidade não encontrada', @@ -53,20 +60,20 @@ return [ '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 selecionado ou Capítulo 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 salvar rascunhos', // Users - 'users_cannot_delete_only_admin' => 'Você não pode excluir o conteúdo, apenas o admin.', + 'users_cannot_delete_only_admin' => 'Você não pode excluir o único admin', 'users_cannot_delete_guest' => 'Você não pode excluir o usuário convidado', // Roles - 'role_cannot_be_edited' => 'Esse perfil não pode ser editado', - 'role_system_cannot_be_deleted' => 'Esse perfil é um perfil de sistema e não pode ser excluído', - 'role_registration_default_cannot_delete' => 'Esse perfil não poderá se excluído enquando estiver registrado como o perfil padrão', - 'role_cannot_remove_only_admin' => 'Este usuário é o único usuário atribuído ao perfil de administrador. Atribua o perfil de administrador a outro usuário antes de tentar removê-lo aqui.', + 'role_cannot_be_edited' => 'Esse cargo não pode ser editado', + 'role_system_cannot_be_deleted' => 'Esse cargo é um cargo do sistema e não pode ser excluído', + 'role_registration_default_cannot_delete' => 'Esse cargo não poderá se excluído enquanto estiver registrado como o cargo padrão', + 'role_cannot_remove_only_admin' => 'Este usuário é o único usuário vinculado ao cargo de administrador. Atribua o cargo de administrador a outro usuário antes de tentar removê-lo aqui.', - // comments + // Comments 'comment_list' => 'Ocorreu um erro ao buscar os comentários.', 'cannot_add_comment_to_draft' => 'Você não pode adicionar comentários a um rascunho.', 'comment_add' => 'Ocorreu um erro ao adicionar o comentário.', @@ -74,11 +81,19 @@ return [ 'empty_comment' => 'Não é possível adicionar um comentário vazio.', // Error pages - '404_page_not_found' => 'Página não encontrada', + '404_page_not_found' => 'Página Não Encontrada', 'sorry_page_not_found' => 'Desculpe, a página que você está procurando não pôde ser encontrada.', - 'return_home' => 'Retornar à página principal', - 'error_occurred' => 'Um erro ocorreu', + 'return_home' => 'Retornar à página inicial', + 'error_occurred' => 'Ocorreu um Erro', 'app_down' => ':appName está fora do ar no momento', - 'back_soon' => 'Voltaremos em seguida.', - + 'back_soon' => 'Voltaremos em breve.', + + // API errors + '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', + ]; diff --git a/resources/lang/pt_BR/passwords.php b/resources/lang/pt_BR/passwords.php index 61a49f57a..0d452c361 100644 --- a/resources/lang/pt_BR/passwords.php +++ b/resources/lang/pt_BR/passwords.php @@ -6,10 +6,10 @@ */ return [ - 'password' => 'Senhas devem ter ao menos 6 caraceres e combinar com os atributos mínimos para a senha.', + 'password' => 'Senhas devem ter ao menos oito caracteres e ser iguais à confirmação.', 'user' => "Não pudemos encontrar um usuário com o e-mail fornecido.", - 'token' => 'O token de reset de senha é inválido.', - 'sent' => 'Enviamos para seu e-mail o link de reset de senha!', - 'reset' => 'Sua senha foi resetada com sucesso!', + 'token' => 'O token de redefinição de senha é inválido.', + 'sent' => 'Enviamos o link de redefinição de senha para o seu e-mail!', + 'reset' => 'Sua senha foi redefinida com sucesso!', ]; diff --git a/resources/lang/pt_BR/settings.php b/resources/lang/pt_BR/settings.php index 4bb8f37e0..7c470da2a 100644 --- a/resources/lang/pt_BR/settings.php +++ b/resources/lang/pt_BR/settings.php @@ -9,93 +9,112 @@ return [ // Common Messages 'settings' => 'Configurações', 'settings_save' => 'Salvar Configurações', - 'settings_save_success' => 'Configurações Salvas', + 'settings_save_success' => 'Configurações salvas', // App Settings 'app_customization' => 'Customização', 'app_features_security' => 'Recursos & Segurança', 'app_name' => 'Nome da Aplicação', 'app_name_desc' => 'Esse nome será mostrado no cabeçalho e em e-mails.', - 'app_name_header' => 'Mostrar o nome da Aplicação no cabeçalho?', + 'app_name_header' => 'Mostrar o nome no cabeçalho', 'app_public_access' => 'Acesso Público', 'app_public_access_desc' => 'Habilitar esta opção irá permitir que visitantes, que não estão logados, acessem o conteúdo em sua instância do BookStack.', 'app_public_access_desc_guest' => 'O acesso de visitantes públicos pode ser controlado através do usuário "Convidado".', 'app_public_access_toggle' => 'Permitir acesso público', 'app_public_viewing' => 'Permitir visualização pública?', - 'app_secure_images' => 'Permitir upload de imagens com maior segurança?', - 'app_secure_images_toggle' => 'Habilitar uploads de imagem de maior segurança', - 'app_secure_images_desc' => 'Por questões de performance, todas as imagens são públicas. Essa opção adiciona uma string randômica na frente da imagem. Certifique-se de que os índices do diretórios permitem o acesso fácil.', + 'app_secure_images' => 'Upload de Imagens mais Seguro', + 'app_secure_images_toggle' => 'Habilitar uploads 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 randômica 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 a ser usado pelos usuários para editar páginas.', - 'app_custom_html' => 'Conteúdo para tag HTML HEAD customizado', - 'app_custom_html_desc' => 'Quaisquer conteúdos aqui inseridos serão inseridos no final da seção do HTML de cada página. Essa é 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 head do HTML está desabilitado nesta página de configurações para garantir que quaisquer alterações significativas possam ser revertidas.', + 'app_editor_desc' => 'Selecione qual editor será utilizado pelos usuários ao editar páginas.', + 'app_custom_html' => 'Conteúdo customizado para HTML', + 'app_custom_html_desc' => 'Quaisquer conteúdos aqui adicionados serão inseridos no final da seção de cada página. Essa é uma maneira útil de sobrescrever estilos e adicionar códigos de análise de site.', + 'app_custom_html_disabled_notice' => 'O conteúdo customizado do HTML está desabilitado nesta página de configurações, para garantir que quaisquer alterações danosas possam ser revertidas.', 'app_logo' => 'Logo da Aplicação', - 'app_logo_desc' => 'A imagem deve ter 43px de altura.
Imagens mais largas devem ser reduzidas.', - 'app_primary_color' => 'Cor primária da Aplicação', - 'app_primary_color_desc' => 'Esse valor deverá ser Hexadecimal.
Deixe em branco para que o Bookstack assuma a cor padrão.', - 'app_homepage' => 'Página incial', - 'app_homepage_desc' => 'Selecione a página para ser usada como página inicial em vez da padrão. Permissões da página serão ignoradas.', + '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_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. Os comentários existentes não são exibidos.', + 'app_disable_comments_desc' => 'Desativar comentários em todas as páginas no aplicativo.
Comentários existentes não serão exibidos.', - // Registration settings - 'reg_settings' => 'Registro', - 'reg_enable' => 'Habilitar Registro', - 'reg_enable_toggle' => 'Habilitar registro', - 'reg_enable_desc' => 'Quando o registro é habilitado, o usuário poderá se registrar como usuário do aplicativo. No registro, eles recebem um único perfil padrão.', - 'reg_default_role' => 'Perfil padrão para usuários após o registro', + // Color settings + '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' => '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' => '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' => 'Confirmação de E-mail', - 'reg_email_confirmation_toggle' => 'Requer confirmação de e-mail', - 'reg_confirm_email_desc' => 'Se restrições de domínio são usadas a confirmação por e-mail será requerida e o valor abaixo será ignorado.', - 'reg_confirm_restrict_domain' => 'Restringir registro ao domínio', - 'reg_confirm_restrict_domain_desc' => 'Entre com uma lista de domínios de e-mails separados por vírgula para os quais você deseja restringir os registros. Será enviado um e-mail de confirmação para o usuário validar o e-mail antes de ser permitido interação com a aplicação.
Note que os usuários serão capazes de alterar o e-mail cadastrado após o sucesso na confirmação do registro.', - 'reg_confirm_restrict_domain_placeholder' => 'Nenhuma restrição configurada', + '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 essa 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 cadastro. Um e-mail de confirmação será enviado para o usuário validar seu endereço de e-mail antes de ser permitido a interagir com a aplicação.
Note que os usuários serão capazes de alterar o seus endereços de e-mail após o sucesso na confirmação do cadastro.', + 'reg_confirm_restrict_domain_placeholder' => 'Nenhuma restrição definida', // Maintenance settings 'maint' => 'Manutenção', 'maint_image_cleanup' => 'Limpeza de Imagens', - 'maint_image_cleanup_desc' => "Examina páginas & revisa o conteúdo para verificar quais imagens e desenhos estão atualmente em uso e quais imagens são redundantes. Certifique-se de criar um backup completo do banco de dados e imagens antes de executar isso.", + 'maint_image_cleanup_desc' => "Examina páginas e revisa seus conteúdos para verificar quais imagens e desenhos estão atualmente em uso e quais são redundantes. Certifique-se de criar um backup completo do banco de dados e imagens antes de executar esta ação.", 'maint_image_cleanup_ignore_revisions' => 'Ignorar imagens em revisões', 'maint_image_cleanup_run' => 'Executar Limpeza', 'maint_image_cleanup_warning' => ':count imagens potencialmente não utilizadas foram encontradas. Tem certeza de que deseja excluir estas imagens?', 'maint_image_cleanup_success' => ':count imagens potencialmente não utilizadas foram encontradas e excluídas!', 'maint_image_cleanup_nothing_found' => 'Nenhuma imagem não utilizada foi encontrada, nada foi excluído!', + '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 você recebeu esta notificação, suas opções de e-mail parecem estar configuradas corretamente.', - // Role settings - 'roles' => 'Perfis', - 'role_user_roles' => 'Perfis de Usuário', - 'role_create' => 'Criar novo Perfil', - 'role_create_success' => 'Perfil criado com sucesso', - 'role_delete' => 'Excluir Perfil', - 'role_delete_confirm' => 'A ação vai excluír o Perfil de nome \':roleName\'.', - 'role_delete_users_assigned' => 'Esse Perfil tem :userCount usuários assinalados a ele. Se quiser migrar usuários desse Perfil para outro, selecione um novo Perfil.', + // Role Settings + 'roles' => 'Cargos', + 'role_user_roles' => 'Cargos de Usuário', + 'role_create' => 'Criar novo Cargo', + 'role_create_success' => 'Cargo criado com sucesso', + 'role_delete' => 'Excluir Cargo', + 'role_delete_confirm' => 'A ação vai excluír o cargo de nome \':roleName\'.', + 'role_delete_users_assigned' => 'Esse cargo tem :userCount usuários vinculados a ele. Se quiser migrar usuários desse cargo para outro, selecione um novo cargo.', 'role_delete_no_migration' => "Não migre os usuários", - 'role_delete_sure' => 'Tem certeza que deseja excluir esse Perfil?', - 'role_delete_success' => 'Perfil excluído com sucesso', - 'role_edit' => 'Editar Perfil', - 'role_details' => 'Detalhes do Perfil', - 'role_name' => 'Nome do Perfil', - 'role_desc' => 'Descrição Curta do Perfil', + 'role_delete_sure' => 'Tem certeza que deseja excluir esse 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' => 'Gerenciar Usuários', - 'role_manage_roles' => 'Gerenciar Perfis & Permissões de Perfis', + 'role_manage_users' => 'Gerenciar usuários', + 'role_manage_roles' => 'Gerenciar cargos e permissões de cargos', 'role_manage_entity_permissions' => 'Gerenciar todos os livros, capítulos e permissões de páginas', 'role_manage_own_entity_permissions' => 'Gerenciar permissões de seu próprio livro, capítulo e paginas', - 'role_manage_settings' => 'Gerenciar configurações de app', + 'role_manage_page_templates' => 'Gerenciar modelos de página', + 'role_access_api' => 'Acessar API do sistema', + 'role_manage_settings' => 'Gerenciar configurações da aplicação', 'role_asset' => 'Permissões de Ativos', 'role_asset_desc' => 'Essas permissões controlam o acesso padrão para os ativos dentro do sistema. Permissões em Livros, Capítulos e Páginas serão sobrescritas por essas permissões.', - 'role_asset_admins' => 'Administradores recebem automaticamente acesso a todo o conteúdo, mas essas opções podem mostrar ou ocultar as opções da UI.', + 'role_asset_admins' => 'Administradores recebem automaticamente acesso a todo o conteúdo, mas essas opções podem mostrar ou ocultar as opções da Interface de Usuário.', 'role_all' => 'Todos', 'role_own' => 'Próprio', - 'role_controlled_by_asset' => 'Controlado pelos ativos que você fez upload', - 'role_save' => 'Salvar Perfil', - 'role_update_success' => 'Perfil atualizado com sucesso', - 'role_users' => 'Usuários neste Perfil', - 'role_users_none' => 'Nenhum usuário está atualmente atrelado a esse Perfil', + 'role_controlled_by_asset' => 'Controlado pelos ativos nos quais o upload foi realizado', + 'role_save' => 'Salvar Cargo', + 'role_update_success' => 'Cargo atualizado com sucesso', + 'role_users' => 'Usuários com este cargo', + 'role_users_none' => 'Nenhum usuário está atualmente vinculado a este cargo', // Users 'users' => 'Usuários', @@ -105,61 +124,88 @@ return [ 'users_details' => 'Detalhes do Usuário', 'users_details_desc' => 'Defina um nome de exibição e um endereço de e-mail para este usuário. O endereço de e-mail será usado para fazer login na aplicação.', 'users_details_desc_no_email' => 'Defina um nome de exibição para este usuário para que outros usuários possam reconhecê-lo', - 'users_role' => 'Perfis do Usuário', - 'users_role_desc' => 'Selecione os perfis para os quais este usuário será atribuído. Se um usuário for atribuído a multiplos perfis, as permissões destes perfis serão empilhadas e eles receberão todas as habilidades dos perfis atribuídos.', + 'users_role' => 'Cargos do Usuário', + 'users_role_desc' => 'Selecione os cargos aos quais este usuário será vinculado. Se um usuário for vinculado a múltiplos cargos, suas permissões serão empilhadas e ele receberá todas as habilidades dos cargos atribuídos.', 'users_password' => 'Senha do Usuário', - 'users_password_desc' => 'Defina uma senha usada para fazer login na aplicação. Esta deve ter pelo menos 5 caracteres.', + 'users_password_desc' => 'Defina uma senha usada para fazer login na aplicação. Esta deve ter pelo menos 6 caracteres.', + 'users_send_invite_text' => 'Você pode escolher enviar a este usuário um convite por e-mail que o possibilitará definir sua própria senha, ou defina você uma senha.', + 'users_send_invite_option' => 'Enviar convite por e-mail', 'users_external_auth_id' => 'ID de Autenticação Externa', - 'users_external_auth_id_desc' => 'Este é o ID usado para corresponder a este usuário ao se comunicar com seu sistema LDAP.', - 'users_password_warning' => 'Preencha os dados abaixo caso queira modificar a sua senha:', - 'users_system_public' => 'Esse usuário representa quaisquer convidados que visitam o aplicativo. Ele não pode ser usado para login.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', + 'users_password_warning' => 'Apenas preencha os dados abaixo caso queira modificar a sua senha.', + 'users_system_public' => 'Esse usuário representa quaisquer convidados que visitam o aplicativo. Ele não pode ser usado para login mas é automaticamente atribuído.', 'users_delete' => 'Excluir Usuário', 'users_delete_named' => 'Excluir :userName', 'users_delete_warning' => 'A ação vai excluir completamente o usuário de nome \':userName\' do sistema.', 'users_delete_confirm' => 'Tem certeza que deseja excluir esse usuário?', 'users_delete_success' => 'Usuários excluídos com sucesso', - 'users_edit' => 'Editar usuário', + 'users_edit' => 'Editar Usuário', 'users_edit_profile' => 'Editar Perfil', 'users_edit_success' => 'Usuário atualizado com sucesso', 'users_avatar' => 'Imagem de Usuário', - 'users_avatar_desc' => 'Essa imagem deve ser um quadrado com aproximadamente 256px de altura e largura.', + 'users_avatar_desc' => 'Defina uma imagem para representar este usuário. Essa imagem 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 usado para a interface de usuário da aplicação. Isto não afetará nenhum conteúdo criado pelo usuário.', + 'users_preferred_language_desc' => 'Esta opção irá alterar o idioma utilizado para a interface de usuário da aplicação. Isto não afetará nenhum conteúdo criado por usuários.', 'users_social_accounts' => 'Contas Sociais', 'users_social_accounts_info' => 'Aqui você pode conectar outras contas para acesso mais rápido. Desconectar 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 conectadas', + 'users_social_connect' => 'Contas Conectadas', 'users_social_disconnect' => 'Desconectar Conta', 'users_social_connected' => 'Conta :socialAccount foi conectada com sucesso ao seu perfil.', 'users_social_disconnected' => 'Conta :socialAccount foi desconectada com sucesso de seu perfil.', + 'users_api_tokens' => 'Tokens de API', + 'users_api_tokens_none' => 'Nenhum token de API foi criado para este usuário', + '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' => '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 não funcionarão mais. 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 "Secreto 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 :timeAgo', + 'user_api_token_updated' => 'Token Atualizado :timeAgo', + 'user_api_token_delete' => 'Excluir 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' => 'Você tem certeza que deseja excluir 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. + //!//////////////////////////////// + 'language_select' => [ + 'en' => 'English', + 'ar' => 'العربية', + 'da' => 'Dansk', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// ]; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/lang/pt_BR/validation.php b/resources/lang/pt_BR/validation.php index 3d4b51f03..718fca6b9 100644 --- a/resources/lang/pt_BR/validation.php +++ b/resources/lang/pt_BR/validation.php @@ -8,50 +8,79 @@ return [ // Standard laravel validation lines - 'accepted' => 'O :attribute deve ser aceito.', - 'active_url' => 'O :attribute não é uma URL válida.', - 'after' => 'O :attribute deve ser uma data posterior à data :date.', - 'alpha' => 'O :attribute deve conter apenas letras.', - 'alpha_dash' => 'O :attribute deve conter apenas letras, números e traços.', - 'alpha_num' => 'O :attribute deve conter apenas letras e números.', - 'array' => 'O :attribute deve ser uma array.', - 'before' => 'O :attribute deve ser uma data anterior à data :date.', + 'accepted' => 'O campo :attribute deve ser aceito.', + 'active_url' => 'O campo :attribute não é uma URL válida.', + '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 underlines.', + 'alpha_num' => 'O campo :attribute deve conter apenas letras e números.', + 'array' => 'O campo :attribute deve ser uma array.', + 'before' => 'O campo :attribute deve ser uma data anterior à data :date.', 'between' => [ - 'numeric' => 'O :attribute deve ter tamanho entre :min e :max.', - 'file' => 'O :attribute deve ter entre :min e :max kilobytes.', - 'string' => 'O :attribute deve ter entre :min e :max caracteres.', - 'array' => 'O :attribute deve ter entre :min e :max itens.', + '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' => 'O campo :attribute deve ser verdadeiro ou falso.', - 'confirmed' => 'O campo :attribute de confirmação não é igual.', + 'confirmed' => 'O campo :attribute não é igual à sua confirmação.', 'date' => 'O campo :attribute não está em um 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 e-mail válido.', + 'ends_with' => 'O campo :attribute deve terminar com um dos seguintes: :values', 'filled' => 'O campo :attribute é requerido.', - 'exists' => 'O atributo :attribute selecionado não é válido.', + 'gt' => [ + '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' => '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' => '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 & suportada.', - 'in' => 'The selected :attribute is invalid.', + '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 IP válido.', + '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' => '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' => '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' => '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' => 'O :attribute deve ser do tipo type: :values.', + 'mimes' => 'O campo :attribute deve ser do tipo type: :values.', 'min' => [ - 'numeric' => 'O valor para o campo :attribute não deve ser menor que :min.', - 'file' => 'O valor para o campo :attribute não deve ter tamanho menor que :min kilobytes.', - 'string' => 'O valor para o campo :attribute não deve ter menos que :min caracteres.', - 'array' => 'O valor para o campo :attribute não deve ter menos que :min itens.', + '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' => '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.', 'regex' => 'O formato do campo :attribute é inválido.', 'required' => 'O campo :attribute é requerido.', diff --git a/resources/lang/ru/activities.php b/resources/lang/ru/activities.php index 35eefadc6..7c8efcacb 100644 --- a/resources/lang/ru/activities.php +++ b/resources/lang/ru/activities.php @@ -1,12 +1,10 @@ 'создал страницу', 'page_create_notification' => 'Страница успешно создана', @@ -37,6 +35,14 @@ return [ 'book_sort' => 'отсортировал книгу', 'book_sort_notification' => 'Книга успешно отсортирована', + // Bookshelves + 'bookshelf_create' => 'создал книжную полку', + 'bookshelf_create_notification' => 'Книжная полка успешно создана', + 'bookshelf_update' => 'обновил книжную полку', + 'bookshelf_update_notification' => 'Книжная полка успешно обновлена', + 'bookshelf_delete' => 'удалил книжную полку', + 'bookshelf_delete_notification' => 'Книжная полка успешно удалена', + // Other 'commented_on' => 'прокомментировал', ]; diff --git a/resources/lang/ru/auth.php b/resources/lang/ru/auth.php index 8bd94513c..490707c83 100644 --- a/resources/lang/ru/auth.php +++ b/resources/lang/ru/auth.php @@ -5,7 +5,7 @@ * messages that we need to display to the user. */ return [ - + 'failed' => 'Учетная запись не найдена.', 'throttle' => 'Слишком много попыток входа. Пожалуйста, попробуйте позже через :seconds секунд.', @@ -18,13 +18,13 @@ return [ 'name' => 'Имя', 'username' => 'Логин', - 'email' => 'Email', + 'email' => 'Адрес электронной почты', 'password' => 'Пароль', 'password_confirm' => 'Подтверждение пароля', - 'password_hint' => 'Должен быть больше 5 символов', + 'password_hint' => 'Должен быть больше 7 символов', 'forgot_password' => 'Забыли пароль?', 'remember_me' => 'Запомнить меня', - 'ldap_email_hint' => 'Введите email адрес для данной учетной записи.', + 'ldap_email_hint' => 'Введите адрес электронной почты для этой учетной записи.', 'create_account' => 'Создать аккаунт', 'already_have_account' => 'Уже есть аккаунт?', 'dont_have_account' => 'У вас нет аккаунта?', @@ -39,7 +39,7 @@ return [ 'register_success' => 'Спасибо за регистрацию! Регистрация и вход в систему выполнены.', - //Password Reset + // Password Reset 'reset_password' => 'Сброс пароля', 'reset_password_send_instructions' => 'Введите свой email ниже, и вам будет отправлено письмо со ссылкой для сброса пароля.', 'reset_password_send_button' => 'Отправить ссылку для сброса', @@ -50,21 +50,21 @@ return [ 'email_reset_not_requested' => 'Если вы не запрашивали сброса пароля, то никаких дополнительных действий не требуется.', - //Email Confirmation + // Email Confirmation 'email_confirm_subject' => 'Подтвердите ваш почтовый адрес на :appName', 'email_confirm_greeting' => 'Благодарим за участие :appName!', - 'email_confirm_text' => 'Пожалуйста, подтвердите ваш email адрес кликнув на кнопку ниже:', - 'email_confirm_action' => 'Подтвердить email', + 'email_confirm_text' => 'Пожалуйста, подтвердите свой адрес электронной почты нажав на кнопку ниже:', + 'email_confirm_action' => 'Подтвердить адрес электронной почты', 'email_confirm_send_error' => 'Требуется подтверждение электронной почты, но система не может отправить письмо. Свяжитесь с администратором, чтобы убедиться, что адрес электронной почты настроен правильно.', - 'email_confirm_success' => 'Ваш email был подтвержден!', + 'email_confirm_success' => 'Ваш адрес подтвержден!', 'email_confirm_resent' => 'Письмо с подтверждение выслано снова. Пожалуйста, проверьте ваш почтовый ящик.', - 'email_not_confirmed' => 'email не подтвержден', + 'email_not_confirmed' => 'Адрес электронной почты не подтвержден', 'email_not_confirmed_text' => 'Ваш email адрес все еще не подтвержден.', 'email_not_confirmed_click_link' => 'Пожалуйста, нажмите на ссылку в письме, которое было отправлено при регистрации.', 'email_not_confirmed_resend' => 'Если вы не можете найти электронное письмо, вы можете снова отправить письмо с подтверждением по форме ниже.', 'email_not_confirmed_resend_button' => 'Переотправить письмо с подтверждением', - + // User Invite 'user_invite_email_subject' => 'Вас приглашают присоединиться к :appName!', 'user_invite_email_greeting' => 'Для вас создан аккаунт в :appName.', @@ -74,4 +74,4 @@ return [ 'user_invite_page_text' => 'Завершите настройку аккаунта, установите пароль для дальнейшего входа в :appName.', 'user_invite_page_confirm_button' => 'Подтвердите пароль', 'user_invite_success' => 'Пароль установлен, теперь у вас есть доступ к :appName!' -]; +]; \ No newline at end of file diff --git a/resources/lang/ru/common.php b/resources/lang/ru/common.php index e70b0a3a7..cd6661d57 100644 --- a/resources/lang/ru/common.php +++ b/resources/lang/ru/common.php @@ -4,7 +4,7 @@ */ return [ - //Buttons + // Buttons 'cancel' => 'Отмена', 'confirm' => 'Применить', 'back' => 'Назад', @@ -14,14 +14,14 @@ return [ 'toggle_all' => 'Переключить все', 'more' => 'Еще', - //Form Labels + // Form Labels 'name' => 'Имя', 'description' => 'Описание', 'role' => 'Роль', 'cover_image' => 'Обложка', 'cover_image_description' => 'Изображение должно быть размером около 440x250px.', - - //Actions + + // Actions 'actions' => 'Действия', 'view' => 'Просмотр', 'view_all' => 'Показать все', @@ -38,7 +38,8 @@ return [ 'reset' => 'Сбросить', 'remove' => 'Удалить', 'add' => 'Добавить', - + 'fullscreen' => 'Fullscreen', + // Sort Options 'sort_options' => 'Параметры сортировки', 'sort_direction_toggle' => 'Переключить направления сортировки', @@ -48,7 +49,7 @@ return [ 'sort_created_at' => 'По дате создания', 'sort_updated_at' => 'По дате обновления', - //Misc + // Misc 'deleted_user' => 'Удаленный пользователь', 'no_activity' => 'Нет действий для просмотра', 'no_items' => 'Нет доступных элементов', @@ -61,16 +62,16 @@ return [ 'default' => 'По умолчанию', 'breadcrumb' => 'Навигация', - //Header + // Header 'profile_menu' => 'Меню профиля', 'view_profile' => 'Просмотреть профиль', 'edit_profile' => 'Редактировать профиль', - + // Layout tabs 'tab_info' => 'Информация', 'tab_content' => 'Содержание', - //Email Content + // Email Content 'email_action_help' => 'Если у вас возникли проблемы с нажатием кнопки \':actionText\', то скопируйте и вставьте указанный URL-адрес в свой веб-браузер:', - 'email_rights' => 'Все права зарезервированы', + 'email_rights' => 'Все права защищены', ]; diff --git a/resources/lang/ru/components.php b/resources/lang/ru/components.php index 2fc88d462..e9481f791 100644 --- a/resources/lang/ru/components.php +++ b/resources/lang/ru/components.php @@ -4,7 +4,7 @@ */ return [ - //Image Manager + // Image Manager 'image_select' => 'Выбрать изображение', 'image_all' => 'Все', 'image_all_title' => 'Простмотр всех изображений', @@ -25,7 +25,7 @@ return [ 'image_delete_success' => 'Изображение успешно удалено', 'image_upload_remove' => 'Удалить изображение', - //Code editor + // Code Editor 'code_editor' => 'Изменить код', 'code_language' => 'Язык кода', 'code_content' => 'Содержимое кода', diff --git a/resources/lang/ru/entities.php b/resources/lang/ru/entities.php index 99c5d6d9f..e9fe6ba30 100644 --- a/resources/lang/ru/entities.php +++ b/resources/lang/ru/entities.php @@ -5,7 +5,7 @@ */ return [ - //Shared + // Shared 'recently_created' => 'Недавно созданные', 'recently_created_pages' => 'Недавно созданные страницы', 'recently_updated_pages' => 'Недавно обновленные страницы', @@ -34,13 +34,13 @@ return [ 'export_pdf' => 'PDF файл', 'export_text' => 'Текстовый файл', - //Permissions and restrictions + // Permissions and restrictions 'permissions' => 'Разрешения', 'permissions_intro' => 'После включения эти разрешения будут иметь приоритет над любыми установленными полномочиями.', 'permissions_enable' => 'Включение пользовательских разрешений', 'permissions_save' => 'Сохранить разрешения', - //Search + // Search 'search_results' => 'Результаты поиска', 'search_total_results_found' => ':count результатов найдено|:count всего результатов найдено', 'search_clear' => 'Очистить поиск', @@ -65,7 +65,7 @@ return [ 'search_set_date' => 'Установить дату', 'search_update' => 'Обновить поиск', - //Shelves + // Shelves 'shelf' => 'Полка', 'shelves' => 'Полки', 'x_shelves' => ':count полок|:count полок', @@ -96,8 +96,8 @@ return [ 'shelves_copy_permissions' => 'Копировать доступы', 'shelves_copy_permissions_explain' => 'Это применит текущие настройки доступов этой книжной полки ко всем книгам, содержащимся внутри. Перед активацией убедитесь, что все изменения в доступах этой книжной полки сохранены.', 'shelves_copy_permission_success' => 'Доступы книжной полки скопированы для :count books', - - //Books + + // Books 'book' => 'Книга', 'books' => 'Книги', 'x_books' => ':count книга|:count книг', @@ -136,7 +136,7 @@ return [ 'books_sort_show_other' => 'Показать другие книги', 'books_sort_save' => 'Сохранить новый порядок', - //Chapters + // Chapters 'chapter' => 'Глава', 'chapters' => 'Главы', 'x_chapters' => ':count глава|:count главы', @@ -159,7 +159,7 @@ return [ 'chapters_permissions_success' => 'Разрешения главы обновлены', 'chapters_search_this' => 'Искать в этой главе', - //Pages + // Pages 'page' => 'Страница', 'pages' => 'Страницы', 'x_pages' => ':count страница|:count страниц', @@ -176,12 +176,12 @@ return [ 'pages_delete_confirm' => 'Вы действительно хотите удалить эту страницу?', 'pages_delete_draft_confirm' => 'Вы действительно хотите удалить этот черновик?', 'pages_editing_named' => 'Редактирование страницы :pageName', - 'pages_edit_toggle_header' => 'Переключение заголовка', + 'pages_edit_draft_options' => 'Параметры черновика', 'pages_edit_save_draft' => 'Сохранить черновик', 'pages_edit_draft' => 'Редактировать черновик', 'pages_editing_draft' => 'Редактирование черновика', 'pages_editing_page' => 'Редактирование страницы', - 'pages_edit_draft_save_at' => 'Черновик сохранить в ', + 'pages_edit_draft_save_at' => 'Черновик сохранён в ', 'pages_edit_delete_draft' => 'Удалить черновик', 'pages_edit_discard_draft' => 'отменить черновик', 'pages_edit_set_changelog' => 'Задать список изменений', @@ -236,7 +236,7 @@ return [ 'pages_specific' => 'Конкретная страница', 'pages_is_template' => 'Шаблон страницы', - //Editor sidebar + // Editor Sidebar 'page_tags' => 'Теги страницы', 'chapter_tags' => 'Теги главы', 'book_tags' => 'Теги книги', @@ -245,7 +245,7 @@ return [ 'tags' => 'Теги', 'tag_name' => 'Имя тега', 'tag_value' => 'Значение тега (опционально)', - 'tags_explain' => 'Добавьте теги, чтобы лучше классифицировать ваш контент. \n Вы можете присвоить значение тегу для более глубокой организации.', + 'tags_explain' => "Добавьте теги, чтобы лучше классифицировать ваш контент. \\n Вы можете присвоить значение тегу для более глубокой организации.", 'tags_add' => 'Добавить тег', 'tags_remove' => 'Удалить этот тэг', 'attachments' => 'Вложение', @@ -280,7 +280,7 @@ return [ 'templates_append_content' => 'Добавить к содержанию страницы', 'templates_prepend_content' => 'Добавить в начало содержимого страницы', - //Profile View + // Profile View 'profile_user_for_x' => 'пользователь уже :time', 'profile_created_content' => 'Созданный контент', 'profile_not_created_pages' => ':userName не создавал страниц', @@ -288,7 +288,7 @@ return [ 'profile_not_created_books' => ':userName не создавал ни одной книги', 'profile_not_created_shelves' => ':userName не создал ни одной полки', - //Comments + // Comments 'comment' => 'Комментарий', 'comments' => 'Комментарии', 'comment_add' => 'Комментировать', @@ -306,9 +306,9 @@ return [ 'comment_delete_confirm' => 'Удалить этот комментарий?', 'comment_in_reply_to' => 'В ответ на :commentId', - //Revision + // Revision 'revision_delete_confirm' => 'Удалить эту ревизию?', 'revision_restore_confirm' => 'Восстановить эту ревизию? Текущее содержимое будет заменено.', 'revision_delete_success' => 'Ревизия удалена', 'revision_cannot_delete_latest' => 'Нельзя удалить последнюю версию.' -]; +]; \ No newline at end of file diff --git a/resources/lang/ru/errors.php b/resources/lang/ru/errors.php index 69063e546..2f5f74caa 100644 --- a/resources/lang/ru/errors.php +++ b/resources/lang/ru/errors.php @@ -13,12 +13,18 @@ return [ 'email_already_confirmed' => 'Электронная почта уже подтверждена, попробуйте войти в систему.', 'email_confirmation_invalid' => 'Этот токен подтверждения недействителен или уже используется. Повторите попытку регистрации.', 'email_confirmation_expired' => 'Истек срок действия токена. Отправлено новое письмо с подтверждением.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'Недопустимый доступ LDAP с использованием анонимной привязки', 'ldap_fail_authed' => 'Не удалось получить доступ к LDAP, используя данные dn & password', 'ldap_extension_not_installed' => 'LDAP расширения для PHP не установлено', 'ldap_cannot_connect' => 'Не удается подключиться к серверу ldap, не удалось выполнить начальное соединение', + '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' => 'Действие не определено', - 'social_login_bad_response' => 'При попытке входа с :socialAccount произошла ошибка: \n:error', + 'social_login_bad_response' => "При попытке входа с :socialAccount произошла ошибка: \\n:error", 'social_account_in_use' => 'Этот :socialAccount аккаунт уже исопльзуется, попробуйте войти с параметрами :socialAccount.', 'social_account_email_in_use' => 'Электронный ящик :email уже используется. Если у вас уже есть учетная запись, вы можете подключить свою учетную запись :socialAccount из настроек своего профиля.', 'social_account_existing' => 'Этот :socialAccount уже привязан к вашему профилю.', @@ -81,5 +87,13 @@ return [ 'error_occurred' => 'Произошла ошибка', 'app_down' => ':appName в данный момент не достпуно', 'back_soon' => 'Скоро восстановится.', - + + // 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', + ]; diff --git a/resources/lang/ru/passwords.php b/resources/lang/ru/passwords.php index 760509a6a..5e7717803 100644 --- a/resources/lang/ru/passwords.php +++ b/resources/lang/ru/passwords.php @@ -7,9 +7,9 @@ return [ 'password' => 'Пароль должен содержать не менее шести символов и совпадать с подтверждением.', - 'user' => 'Пользователь с указаным email отсутствует.', + 'user' => "Пользователя с таким адресом не существует.", 'token' => 'Токен сброса пароля недействителен.', - 'sent' => 'Ссылка для сброса пароля отправлена на email!', + 'sent' => 'Ссылка для сброса пароля отправлена на вашу почту!', 'reset' => 'Ваш пароль был сброшен!', ]; diff --git a/resources/lang/ru/settings.php b/resources/lang/ru/settings.php index c182cf22e..ecd80c283 100755 --- a/resources/lang/ru/settings.php +++ b/resources/lang/ru/settings.php @@ -13,7 +13,7 @@ return [ // App Settings 'app_customization' => 'Настройки', - 'app_features_security' => 'Функции & Безопасность', + 'app_features_security' => 'Функционал & Безопасность', 'app_name' => 'Имя приложения', 'app_name_desc' => 'Имя отображается в заголовке email отправленных системой.', 'app_name_header' => 'Отображать имя приложения в заголовке', @@ -41,28 +41,45 @@ return [ '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', + // Registration Settings 'reg_settings' => 'Настройки регистрации', - 'reg_enable' => 'Разрешить регистрацияю', + 'reg_enable' => 'Разрешить регистрацию', 'reg_enable_toggle' => 'Разрешить регистрацию', - 'reg_enable_desc' => 'Если регистрация разрешена, пользователь сможет зарегистрироваться в системе самомтоятельно. При регистрации назначается роль пользователя по умолчанию', + 'reg_enable_desc' => 'Если регистрация разрешена, пользователь сможет зарегистрироваться в системе самостоятельно. При регистрации назначается роль пользователя по умолчанию', 'reg_default_role' => 'Роль пользователя по умолчанию после регистрации', - 'reg_email_confirmation' => 'Подтверждение электонной почты', + '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' => 'Подтверждение электронной почты', 'reg_email_confirmation_toggle' => 'Требовать подтверждение по электронной почте', - 'reg_confirm_email_desc' => 'Если используется ограничение по домену, подтверждение будет обязательно, а этот пункт проигнорирован.', + 'reg_confirm_email_desc' => 'При использовании ограничения по домену - подтверждение обязательно, этот пункт игнорируется.', 'reg_confirm_restrict_domain' => 'Ограничить регистрацию по домену', - 'reg_confirm_restrict_domain_desc' => 'Введите список доменов почты через запятую, для которых разрешена регистрация. Пользователям будет отправлено письмо для подтверждения адреса перед входом в приложение.
Обратите внимание, что пользователи смогут изменить свои адреса уже после регистрации.', + 'reg_confirm_restrict_domain_desc' => 'Введите список доменов почты через запятую, для которых разрешена регистрация. Пользователям будет отправлено письмо для подтверждения адреса перед входом в приложение.
Обратите внимание, что пользователи смогут изменять свой адрес после регистрации.', 'reg_confirm_restrict_domain_placeholder' => 'Без ограничений', // Maintenance settings 'maint' => 'Обслуживание', 'maint_image_cleanup' => 'Очистка изображений', - 'maint_image_cleanup_desc' => 'Сканирует содержимое страниц и предыдущих версий и определяет изображения, которые не используются. Убедитесь, что у вас есть резервная копия базы данных и папки изображений перед запуском этой функции.', + 'maint_image_cleanup_desc' => "Сканирует содержимое страниц и предыдущих версий и определяет изображения, которые не используются. Убедитесь, что у вас есть резервная копия базы данных и папки изображений перед запуском этой функции.", 'maint_image_cleanup_ignore_revisions' => 'Пропускать изображения в версиях', 'maint_image_cleanup_run' => 'Выполнить очистку', 'maint_image_cleanup_warning' => 'Найдено :count возможно бесполезных изображений. Вы уверены, что хотите удалить эти изображения?', 'maint_image_cleanup_success' => ':count возможно бесполезных изображений было найдено и удалено!', 'maint_image_cleanup_nothing_found' => 'Не найдено ни одного бесполезного изображения!', + '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' => 'Поздравляем! Поскольку вы получили это письмо, электронная почта настроена правильно.', // Role Settings 'roles' => 'Роли', @@ -72,7 +89,7 @@ return [ 'role_delete' => 'Удалить роль', 'role_delete_confirm' => 'Это удалит роль с именем \':roleName\'.', 'role_delete_users_assigned' => 'Эта роль назначена :userCount пользователям. Если вы хотите перенести их из этой роли, выберите новую роль ниже.', - 'role_delete_no_migration' => 'Не мигрировать пользователей', + 'role_delete_no_migration' => "Не мигрировать пользователей", 'role_delete_sure' => 'Вы уверены что хотите удалить данную роль?', 'role_delete_success' => 'Роль успешно удалена', 'role_edit' => 'Редактировать роль', @@ -86,6 +103,7 @@ return [ 'role_manage_entity_permissions' => 'Управление правами на все книги, главы и страницы', 'role_manage_own_entity_permissions' => 'Управление разрешениями для собственных книг, разделов и страниц', 'role_manage_page_templates' => 'Управление шаблонами страниц', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Управление настройками приложения', 'role_asset' => 'Разрешение для активации', 'role_asset_desc' => 'Эти разрешения контролируют доступ по умолчанию к параметрам внутри системы. Разрешения на книги, главы и страницы перезапишут эти разрешения.', @@ -104,16 +122,16 @@ return [ 'users_add_new' => 'Добавить пользователя', 'users_search' => 'Поиск пользователей', 'users_details' => 'Данные пользователя', - 'users_details_desc' => 'Задайте имя для этого пользователя, чтобы другие могли его узнать', + 'users_details_desc' => 'Укажите имя и адрес электронной почты для этого пользователя. Адрес электронной почты будет использоваться для входа в приложение.', 'users_details_desc_no_email' => 'Задайте имя для этого пользователя, чтобы другие могли его узнать', 'users_role' => 'Роли пользователя', 'users_role_desc' => 'Назначьте роли пользователю. Если назначено несколько ролей, разрешения будут суммироваться и пользователь получит все права назначенных ролей.', 'users_password' => 'Пароль пользователя', 'users_password_desc' => 'Установите пароль для входа в приложение. Должно быть не менее 6 символов.', 'users_send_invite_text' => 'Вы можете отправить этому пользователю email с приглашением, которое позволит ему установить пароль самостоятельно или задайте пароль сами.', - 'users_send_invite_option' => 'Отправить пользователю email с приглашением.', + 'users_send_invite_option' => 'Отправить пользователю письмо с приглашением', 'users_external_auth_id' => 'Внешний ID аутентификации', - 'users_external_auth_id_desc' => 'Этот ID используется для связи с вашей LDAP системой.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Заполните ниже только если вы хотите сменить свой пароль.', 'users_system_public' => 'Этот пользователь представляет любых гостевых пользователей, которые посещают ваше приложение. Он не может использоваться для входа в систему и назначается автоматически.', 'users_delete' => 'Удалить пользователя', @@ -134,6 +152,60 @@ 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', + // 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' => 'العربية', + 'da' => 'Dansk', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// ]; diff --git a/resources/lang/ru/validation.php b/resources/lang/ru/validation.php index fabb109f9..80cd89fd5 100644 --- a/resources/lang/ru/validation.php +++ b/resources/lang/ru/validation.php @@ -30,13 +30,41 @@ return [ 'digits' => ':attribute должен состоять из :digits цифр.', 'digits_between' => ':attribute должен иметь от :min до :max цифр.', 'email' => ':attribute должен быть корректным email адресом.', + 'ends_with' => 'The :attribute must end with one of the following: :values', 'filled' => ':attribute поле необходимо.', + '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.', + ], + '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.', + ], 'exists' => 'выделенный :attribute некорректен.', 'image' => ':attribute должен быть изображением.', 'image_extension' => ':attribute должен быть исправным и содержать расширение картинки', 'in' => 'выделенный :attribute некорректен.', 'integer' => ':attribute должно быть целое число.', 'ip' => ':attribute должен быть корректным IP адресом.', + '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.', + '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.', + ], + '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.', + ], 'max' => [ 'numeric' => ':attribute не может быть больше чем :max.', 'file' => ':attribute не может быть больше чем :max килобайт.', @@ -52,6 +80,7 @@ return [ ], 'no_double_extension' => ':attribute должен иметь только одно расширение файла.', 'not_in' => 'Выбранный :attribute некорректен.', + 'not_regex' => 'The :attribute format is invalid.', 'numeric' => ':attribute должен быть числом.', 'regex' => ':attribute неправильный формат.', 'required' => ':attribute обязательное поле.', @@ -73,14 +102,13 @@ return [ 'url' => ':attribute имеет неправильный формат.', 'uploaded' => 'Не удалось загрузить файл. Сервер не может принимать файлы такого размера.', - //Custom validation lines + // Custom validation lines 'custom' => [ 'password-confirm' => [ 'required_with' => 'Требуется подтверждение пароля', ], ], - //Custom validation attributes + // Custom validation attributes 'attributes' => [], - ]; diff --git a/resources/lang/sk/activities.php b/resources/lang/sk/activities.php index 1d87d3fa3..444d78e95 100644 --- a/resources/lang/sk/activities.php +++ b/resources/lang/sk/activities.php @@ -1,12 +1,10 @@ 'vytvoril stránku', 'page_create_notification' => 'Stránka úspešne vytvorená', @@ -37,4 +35,14 @@ return [ 'book_sort' => 'zoradil knihu', 'book_sort_notification' => 'Kniha úspešne znovu zoradená', + // 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', + + // Other + 'commented_on' => 'commented on', ]; diff --git a/resources/lang/sk/auth.php b/resources/lang/sk/auth.php index 2fa69ac3e..fcce42bbd 100644 --- a/resources/lang/sk/auth.php +++ b/resources/lang/sk/auth.php @@ -1,21 +1,15 @@ 'Tieto údaje nesedia s našimi záznamami.', 'throttle' => 'Priveľa pokusov o prihlásenie. Skúste znova o :seconds sekúnd.', - /** - * Login & Register - */ + // Login & Register 'sign_up' => 'Registrácia', 'log_in' => 'Prihlásenie', 'log_in_with' => 'Prihlásiť sa cez :socialDriver', @@ -27,11 +21,13 @@ return [ 'email' => 'Email', 'password' => 'Heslo', 'password_confirm' => 'Potvrdiť heslo', - 'password_hint' => 'Musí mať viac ako 5 znakov', + 'password_hint' => 'Musí mať viac ako 7 znakov', 'forgot_password' => 'Zabudli ste heslo?', 'remember_me' => 'Zapamätať si ma', 'ldap_email_hint' => 'Zadajte prosím email, ktorý sa má použiť pre tento účet.', 'create_account' => 'Vytvoriť účet', + 'already_have_account' => 'Already have an account?', + 'dont_have_account' => 'Don\'t have an account?', 'social_login' => 'Sociálne prihlásenie', 'social_registration' => 'Sociálna registrácia', 'social_registration_text' => 'Registrovať sa a prihlásiť sa použitím inej služby.', @@ -43,23 +39,18 @@ return [ 'register_success' => 'Ďakujeme za registráciu! Teraz ste registrovaný a prihlásený.', - /** - * Password Reset - */ + // Password Reset 'reset_password' => 'Reset hesla', 'reset_password_send_instructions' => 'Zadajte svoj email nižšie a bude Vám odoslaný email s odkazom pre reset hesla.', 'reset_password_send_button' => 'Poslať odkaz na reset hesla', 'reset_password_sent_success' => 'Odkaz na reset hesla bol poslaný na :email.', 'reset_password_success' => 'Vaše heslo bolo úspešne resetované.', - 'email_reset_subject' => 'Reset Vášho :appName hesla', 'email_reset_text' => 'Tento email Ste dostali pretože sme dostali požiadavku na reset hesla pre Váš účet.', 'email_reset_not_requested' => 'Ak ste nepožiadali o reset hesla, nemusíte nič robiť.', - /** - * Email Confirmation - */ + // Email Confirmation 'email_confirm_subject' => 'Potvrdiť email na :appName', 'email_confirm_greeting' => 'Ďakujeme za pridanie sa k :appName!', 'email_confirm_text' => 'Prosím potvrďte Vašu emailovú adresu kliknutím na tlačidlo nižšie:', @@ -73,4 +64,14 @@ return [ 'email_not_confirmed_click_link' => 'Prosím, kliknite na odkaz v emaili, ktorý bol poslaný krátko po Vašej registrácii.', 'email_not_confirmed_resend' => 'Ak nemôžete násť email, môžete znova odoslať overovací email odoslaním doleuvedeného formulára.', 'email_not_confirmed_resend_button' => 'Znova odoslať overovací email', -]; + + // 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!' +]; \ No newline at end of file diff --git a/resources/lang/sk/common.php b/resources/lang/sk/common.php index a823fb379..30faa9e77 100644 --- a/resources/lang/sk/common.php +++ b/resources/lang/sk/common.php @@ -1,60 +1,77 @@ 'Zrušiť', 'confirm' => 'Potvrdiť', 'back' => 'Späť', 'save' => 'Uložiť', 'continue' => 'Pokračovať', 'select' => 'Vybrať', + 'toggle_all' => 'Toggle All', + 'more' => 'More', - /** - * Form Labels - */ + // Form Labels 'name' => 'Meno', 'description' => 'Popis', 'role' => 'Rola', 'cover_image' => 'Obal knihy', 'cover_image_description' => 'Tento obrázok by mal byť približne 300 x 170 pixelov.', - /** - * Actions - */ + + // Actions 'actions' => 'Akcie', 'view' => 'Zobraziť', + 'view_all' => 'View All', 'create' => 'Vytvoriť', 'update' => 'Aktualizovať', 'edit' => 'Editovať', 'sort' => 'Zoradiť', 'move' => 'Presunúť', + 'copy' => 'Copy', + 'reply' => 'Reply', 'delete' => 'Zmazať', 'search' => 'Hľadť', 'search_clear' => 'Vyčistiť hľadanie', 'reset' => 'Reset', 'remove' => 'Odstrániť', + 'add' => 'Add', + 'fullscreen' => 'Fullscreen', + // 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', - /** - * Misc - */ + // Misc 'deleted_user' => 'Odstránený používateľ', 'no_activity' => 'Žiadna aktivita na zobrazenie', 'no_items' => 'Žiadne položky nie sú dostupné', 'back_to_top' => 'Späť nahor', 'toggle_details' => 'Prepnúť detaily', 'toggle_thumbnails' => 'Prepnúť náhľady', + 'details' => 'Details', + 'grid_view' => 'Grid View', + 'list_view' => 'List View', + 'default' => 'Default', + 'breadcrumb' => 'Breadcrumb', - /** - * Header - */ + // Header + 'profile_menu' => 'Profile Menu', 'view_profile' => 'Zobraziť profil', 'edit_profile' => 'Upraviť profil', - /** - * Email Content - */ + // Layout tabs + 'tab_info' => 'Info', + 'tab_content' => 'Content', + + // 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é', ]; diff --git a/resources/lang/sk/components.php b/resources/lang/sk/components.php index c20b62c7a..726d83614 100644 --- a/resources/lang/sk/components.php +++ b/resources/lang/sk/components.php @@ -1,9 +1,10 @@ 'Vybrať obrázok', 'image_all' => 'Všetko', 'image_all_title' => 'Zobraziť všetky obrázky', @@ -21,5 +22,12 @@ return [ 'image_preview' => 'Náhľad obrázka', 'image_upload_success' => 'Obrázok úspešne nahraný', 'image_update_success' => 'Detaily obrázka úspešne aktualizované', - 'image_delete_success' => 'Obrázok úspešne zmazaný' + 'image_delete_success' => 'Obrázok úspešne zmazaný', + 'image_upload_remove' => 'Remove', + + // Code Editor + 'code_editor' => 'Edit Code', + 'code_language' => 'Code Language', + 'code_content' => 'Code Content', + 'code_save' => 'Save Code', ]; diff --git a/resources/lang/sk/entities.php b/resources/lang/sk/entities.php index 7fbbaf2e2..2b42ca86c 100644 --- a/resources/lang/sk/entities.php +++ b/resources/lang/sk/entities.php @@ -1,24 +1,27 @@ 'Nedávno vytvorené', 'recently_created_pages' => 'Nedávno vytvorené stránky', 'recently_updated_pages' => 'Nedávno aktualizované stránky', 'recently_created_chapters' => 'Nedávno vytvorené kapitoly', 'recently_created_books' => 'Nedávno vytvorené knihy', + 'recently_created_shelves' => 'Recently Created Shelves', 'recently_update' => 'Nedávno aktualizované', 'recently_viewed' => 'Nedávno zobrazené', 'recent_activity' => 'Nedávna aktivita', 'create_now' => 'Vytvoriť teraz', 'revisions' => 'Revízie', + 'meta_revision' => 'Revision #:revisionCount', 'meta_created' => 'Vytvorené :timeLength', 'meta_created_name' => 'Vytvorené :timeLength používateľom :user', 'meta_updated' => 'Aktualizované :timeLength', 'meta_updated_name' => 'Aktualizované :timeLength používateľom :user', - 'x_pages' => ':count stránok', 'entity_select' => 'Entita vybraná', 'images' => 'Obrázky', 'my_recent_drafts' => 'Moje nedávne koncepty', @@ -31,40 +34,80 @@ return [ 'export_pdf' => 'PDF súbor', 'export_text' => 'Súbor s čistým textom', - /** - * Permissions and restrictions - */ + // Permissions and restrictions 'permissions' => 'Oprávnenia', 'permissions_intro' => 'Ak budú tieto oprávnenia povolené, budú mať prioritu pred oprávneniami roly.', 'permissions_enable' => 'Povoliť vlastné oprávnenia', 'permissions_save' => 'Uložiť oprávnenia', - /** - * Search - */ + // Search 'search_results' => 'Výsledky hľadania', - 'search_results_page' => 'Výsledky hľadania stránky', - 'search_results_chapter' => 'Výsledky hľadania kapitoly', - 'search_results_book' => 'Výsledky hľadania knihy', + 'search_total_results_found' => ':count result found|:count total results found', 'search_clear' => 'Vyčistiť hľadanie', - 'search_view_pages' => 'Zobraziť všetky vyhovujúce stránky', - 'search_view_chapters' => 'Zobraziť všetky vyhovujúce kapitoly', - 'search_view_books' => 'Zobraziť všetky vyhovujúce knihy', 'search_no_pages' => 'Žiadne stránky nevyhovujú tomuto hľadaniu', 'search_for_term' => 'Hľadať :term', - 'search_page_for_term' => 'Hľadať :term medzi stránkami', - 'search_chapter_for_term' => 'Hľadať :term medzi kapitolami', - 'search_book_for_term' => 'Hľadať :term medzi knihami', + 'search_more' => 'More Results', + 'search_filters' => 'Search Filters', + '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', - /** - * Books - */ + // 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', + + // Books 'book' => 'Kniha', 'books' => 'Knihy', + 'x_books' => ':count Book|:count Books', 'books_empty' => 'Žiadne knihy neboli vytvorené', 'books_popular' => 'Populárne knihy', 'books_recent' => 'Nedávne knihy', + 'books_new' => 'New Books', + 'books_new_action' => 'New Book', 'books_popular_empty' => 'Najpopulárnejšie knihy sa objavia tu.', + 'books_new_empty' => 'The most recently created books will appear here.', 'books_create' => 'Vytvoriť novú knihu', 'books_delete' => 'Zmazať knihu', 'books_delete_named' => 'Zmazať knihu :bookName', @@ -78,7 +121,6 @@ return [ 'books_permissions_updated' => 'Oprávnenia knihy aktualizované', 'books_empty_contents' => 'Pre túto knihu neboli vytvorené žiadne stránky alebo kapitoly.', 'books_empty_create_page' => 'Vytvoriť novú stránku', - 'books_empty_or' => 'alebo', 'books_empty_sort_current_book' => 'Zoradiť aktuálnu knihu', 'books_empty_add_chapter' => 'Pridať kapitolu', 'books_permissions_active' => 'Oprávnenia knihy aktívne', @@ -86,14 +128,18 @@ return [ 'books_navigation' => 'Navigácia knihy', 'books_sort' => 'Zoradiť obsah knihy', 'books_sort_named' => 'Zoradiť knihu :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' => 'Zobraziť ostatné knihy', 'books_sort_save' => 'Uložiť nové zoradenie', - /** - * Chapters - */ + // Chapters 'chapter' => 'Kapitola', 'chapters' => 'Kapitoly', + 'x_chapters' => ':count Chapter|:count Chapters', 'chapters_popular' => 'Populárne kapitoly', 'chapters_new' => 'Nová kapitola', 'chapters_create' => 'Vytvoriť novú kapitolu', @@ -112,12 +158,12 @@ return [ 'chapters_empty' => 'V tejto kapitole nie sú teraz žiadne stránky.', 'chapters_permissions_active' => 'Oprávnenia kapitoly aktívne', 'chapters_permissions_success' => 'Oprávnenia kapitoly aktualizované', + 'chapters_search_this' => 'Search this chapter', - /** - * Pages - */ + // Pages 'page' => 'Stránka', 'pages' => 'Stránky', + 'x_pages' => ':count stránok', 'pages_popular' => 'Populárne stránky', 'pages_new' => 'Nová stránka', 'pages_attachments' => 'Prílohy', @@ -131,7 +177,7 @@ return [ 'pages_delete_confirm' => 'Ste si istý, že chcete zmazať túto stránku?', 'pages_delete_draft_confirm' => 'Ste si istý, že chcete zmazať tento koncept stránky?', 'pages_editing_named' => 'Upraviť stránku :pageName', - 'pages_edit_toggle_header' => 'Prepnúť hlavičku', + 'pages_edit_draft_options' => 'Draft Options', 'pages_edit_save_draft' => 'Uložiť koncept', 'pages_edit_draft' => 'Upraviť koncept stránky', 'pages_editing_draft' => 'Upravuje sa koncept', @@ -149,16 +195,24 @@ return [ 'pages_md_preview' => 'Náhľad', 'pages_md_insert_image' => 'Vložiť obrázok', 'pages_md_insert_link' => 'Vložiť odkaz na entitu', + 'pages_md_insert_drawing' => 'Insert Drawing', 'pages_not_in_chapter' => 'Stránka nie je v kapitole', 'pages_move' => 'Presunúť stránku', 'pages_move_success' => 'Stránka presunutá do ":parentName"', + 'pages_copy' => 'Copy Page', + 'pages_copy_desination' => 'Copy Destination', + 'pages_copy_success' => 'Page successfully copied', 'pages_permissions' => 'Oprávnenia stránky', 'pages_permissions_success' => 'Oprávnenia stránky aktualizované', + 'pages_revision' => 'Revision', 'pages_revisions' => 'Revízie stránky', 'pages_revisions_named' => 'Revízie stránky :pageName', 'pages_revision_named' => 'Revízia stránky :pageName', 'pages_revisions_created_by' => 'Vytvoril', 'pages_revisions_date' => 'Dátum revízie', + 'pages_revisions_number' => '#', + 'pages_revisions_numbered' => 'Revision #:id', + 'pages_revisions_numbered_changes' => 'Revision #:id Changes', 'pages_revisions_changelog' => 'Záznam zmien', 'pages_revisions_changes' => 'Zmeny', 'pages_revisions_current' => 'Aktuálna verzia', @@ -180,16 +234,21 @@ return [ 'message' => ':start :time. Dávajte pozor aby ste si navzájom neprepísali zmeny!', ], 'pages_draft_discarded' => 'Koncept ostránený, aktuálny obsah stránky bol nahraný do editora', + 'pages_specific' => 'Specific Page', + 'pages_is_template' => 'Page Template', - /** - * Editor sidebar - */ + // Editor Sidebar 'page_tags' => 'Štítky stránok', + 'chapter_tags' => 'Chapter Tags', + 'book_tags' => 'Book Tags', + 'shelf_tags' => 'Shelf Tags', 'tag' => 'Štítok', 'tags' => 'Štítky', + 'tag_name' => 'Tag Name', 'tag_value' => 'Hodnota štítku (Voliteľné)', 'tags_explain' => "Pridajte pár štítkov pre uľahčenie kategorizácie Vášho obsahu. \n Štítku môžete priradiť hodnotu pre ešte lepšiu organizáciu.", 'tags_add' => 'Pridať ďalší štítok', + 'tags_remove' => 'Remove this tag', 'attachments' => 'Prílohy', 'attachments_explain' => 'Nahrajte nejaké súbory alebo priložte zopár odkazov pre zobrazenie na Vašej stránke. Budú viditeľné v bočnom paneli.', 'attachments_explain_instant_save' => 'Zmeny budú okamžite uložené.', @@ -215,28 +274,42 @@ return [ 'attachments_file_uploaded' => 'Súbor úspešne nahraný', 'attachments_file_updated' => 'Súbor úspešne aktualizovaný', 'attachments_link_attached' => 'Odkaz úspešne pripojený k stránke', + '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 View 'profile_user_for_x' => 'Používateľ už :time', 'profile_created_content' => 'Vytvorený obsah', 'profile_not_created_pages' => ':userName nevytvoril žiadne stránky', 'profile_not_created_chapters' => ':userName nevytvoril žiadne kapitoly', 'profile_not_created_books' => ':userName nevytvoril žiadne knihy', + 'profile_not_created_shelves' => ':userName has not created any shelves', - /** - * Comments - */ + // Comments 'comment' => 'Komentár', 'comments' => 'Komentáre', + 'comment_add' => 'Add Comment', 'comment_placeholder' => 'Tu zadajte svoje pripomienky', + 'comment_count' => '{0} No Comments|{1} 1 Comment|[2,*] :count Comments', 'comment_save' => 'Uložiť komentár', + '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 'revision_delete_confirm' => 'Naozaj chcete túto revíziu odstrániť?', + 'revision_restore_confirm' => 'Are you sure you want to restore this revision? The current page contents will be replaced.', 'revision_delete_success' => 'Revízia bola vymazaná', 'revision_cannot_delete_latest' => 'Nie je možné vymazať poslednú revíziu.' -]; +]; \ No newline at end of file diff --git a/resources/lang/sk/errors.php b/resources/lang/sk/errors.php index 05277014b..ef6474b4d 100644 --- a/resources/lang/sk/errors.php +++ b/resources/lang/sk/errors.php @@ -1,11 +1,9 @@ 'Nemáte oprávnenie pre prístup k požadovanej stránke.', 'permissionJson' => 'Nemáte oprávnenie pre vykonanie požadovaného úkonu.', @@ -15,11 +13,18 @@ return [ 'email_already_confirmed' => 'Email bol už overený, skúste sa prihlásiť.', 'email_confirmation_invalid' => 'Tento potvrdzujúci token nie je platný alebo už bol použitý, skúste sa prosím registrovať znova.', 'email_confirmation_expired' => 'Potvrdzujúci token expiroval, bol odoslaný nový potvrdzujúci email.', + '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' => 'Nebola definovaná žiadna akcia', + 'social_login_bad_response' => "Error received during :socialAccount login: \n:error", 'social_account_in_use' => 'Tento :socialAccount účet sa už používa, skúste sa prihlásiť pomocou možnosti :socialAccount.', 'social_account_email_in_use' => 'Email :email sa už používa. Ak už máte účet, môžete pripojiť svoj :socialAccount účet v nastaveniach profilu.', 'social_account_existing' => 'Tento :socialAccount účet je už spojený s Vaším profilom.', @@ -28,23 +33,29 @@ return [ 'social_account_register_instructions' => 'Ak zatiaľ nemáte účet, môžete sa registrovať pomocou možnosti :socialAccount.', 'social_driver_not_found' => 'Ovládač socialnych sietí nebol nájdený', 'social_driver_not_configured' => 'Nastavenia Vášho :socialAccount účtu nie sú správne.', + 'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.', // System 'path_not_writable' => 'Do cesty :filePath sa nedá nahrávať. Uistite sa, že je zapisovateľná serverom.', 'cannot_get_image_from_url' => 'Nedá sa získať obrázok z :url', 'cannot_create_thumbs' => 'Server nedokáže vytvoriť náhľady. Skontrolujte prosím, či máte nainštalované GD rozšírenie PHP.', 'server_upload_limit' => 'Server nedovoľuje nahrávanie súborov s takouto veľkosťou. Skúste prosím menší súbor.', + 'uploaded' => 'The server does not allow uploads of this size. Please try a smaller file size.', 'image_upload_error' => 'Pri nahrávaní obrázka nastala chyba', + 'image_upload_type_error' => 'The image type being uploaded is invalid', 'file_upload_timeout' => 'Nahrávanie súboru vypršalo.', // Attachments 'attachment_page_mismatch' => 'Page mismatch during attachment update', + 'attachment_not_found' => 'Attachment not found', // Pages 'page_draft_autosave_fail' => 'Koncept nemohol byť uložený. Uistite sa, že máte pripojenie k internetu pre uložením tejto stránky', + 'page_custom_home_deletion' => 'Cannot delete a page while it is set as a homepage', // Entities 'entity_not_found' => 'Entita nenájdená', + 'bookshelf_not_found' => 'Bookshelf not found', 'book_not_found' => 'Kniha nenájdená', 'page_not_found' => 'Stránka nenájdená', 'chapter_not_found' => 'Kapitola nenájdená', @@ -60,6 +71,14 @@ return [ 'role_cannot_be_edited' => 'Táto rola nemôže byť upravovaná', 'role_system_cannot_be_deleted' => 'Táto rola je systémová rola a nemôže byť zmazaná', 'role_registration_default_cannot_delete' => 'Táto rola nemôže byť zmazaná, pretože je nastavená ako prednastavená rola pri registrácii', + '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.', + + // Comments + 'comment_list' => 'Pri načítaní komentárov sa vyskytla chyba', + 'cannot_add_comment_to_draft' => 'Do konceptu nemôžete pridávať komentáre.', + 'comment_add' => 'Počas pridávania komentára sa vyskytla chyba', + 'comment_delete' => 'Pri odstraňovaní komentára došlo k chybe', + 'empty_comment' => 'Nelze pridať prázdny komentár.', // Error pages '404_page_not_found' => 'Stránka nenájdená', @@ -69,10 +88,12 @@ return [ 'app_down' => ':appName je momentálne nedostupná', 'back_soon' => 'Čoskoro bude opäť dostupná.', - // comments - 'comment_list' => 'Pri načítaní komentárov sa vyskytla chyba', - 'cannot_add_comment_to_draft' => 'Do konceptu nemôžete pridávať komentáre.', - 'comment_add' => 'Počas pridávania komentára sa vyskytla chyba', - 'comment_delete' => 'Pri odstraňovaní komentára došlo k chybe', - 'empty_comment' => 'Nelze pridať prázdny komentár.', + // 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', + ]; diff --git a/resources/lang/sk/pagination.php b/resources/lang/sk/pagination.php index 8f844f5f4..7c9333efa 100644 --- a/resources/lang/sk/pagination.php +++ b/resources/lang/sk/pagination.php @@ -1,18 +1,11 @@ '« Predchádzajúca', 'next' => 'Ďalšia »', diff --git a/resources/lang/sk/passwords.php b/resources/lang/sk/passwords.php index ff2eb68fa..de7d24442 100644 --- a/resources/lang/sk/passwords.php +++ b/resources/lang/sk/passwords.php @@ -1,18 +1,11 @@ 'Heslo musí obsahovať aspoň šesť znakov a musí byť rovnaké ako potvrdzujúce.', 'user' => "Nenašli sme používateľa s takou emailovou adresou.", 'token' => 'Tento token pre reset hesla je neplatný.', diff --git a/resources/lang/sk/settings.php b/resources/lang/sk/settings.php index 521af196e..f4e67f2ff 100644 --- a/resources/lang/sk/settings.php +++ b/resources/lang/sk/settings.php @@ -1,56 +1,87 @@ 'Nastavenia', 'settings_save' => 'Uložiť nastavenia', 'settings_save_success' => 'Nastavenia uložené', - /** - * App settings - */ - - 'app_settings' => 'Nastavenia aplikácie', + // App Settings + 'app_customization' => 'Customization', + 'app_features_security' => 'Features & Security', 'app_name' => 'Názov aplikácia', 'app_name_desc' => 'Tento názov sa zobrazuje v hlavičke a v emailoch.', 'app_name_header' => 'Zobraziť názov aplikácie v hlavičke?', + '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' => 'Povoliť verejné zobrazenie?', 'app_secure_images' => 'Povoliť nahrávanie súborov so zvýšeným zabezpečením?', + 'app_secure_images_toggle' => 'Enable higher security image uploads', 'app_secure_images_desc' => 'Kvôli výkonu sú všetky obrázky verejné. Táto možnosť pridá pred URL obrázka náhodný, ťažko uhádnuteľný reťazec. Aby ste zabránili jednoduchému prístupu, uistite sa, že indexy priečinkov nie sú povolené.', 'app_editor' => 'Editor stránky', 'app_editor_desc' => 'Vyberte editor, ktorý bude používaný všetkými používateľmi na editáciu stránok.', 'app_custom_html' => 'Vlastný HTML obsah hlavičky', 'app_custom_html_desc' => 'Všetok text pridaný sem bude vložený naspodok sekcie na každej stránke. Môže sa to zísť pri zmene štýlu alebo pre pridanie analytického kódu.', + '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' => 'Logo aplikácie', 'app_logo_desc' => 'Tento obrázok by mal mať 43px na výšku.
Veľké obrázky budú preškálované na menší rozmer.', 'app_primary_color' => 'Primárna farba pre aplikáciu', 'app_primary_color_desc' => 'Toto by mala byť hodnota v hex tvare.
Nechajte prázdne ak chcete použiť prednastavenú farbu.', + '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' => '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ú.', - /** - * Registration settings - */ + // 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' => 'Nastavenia registrácie', - 'reg_allow' => 'Povoliť registráciu?', + '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' => 'Prednastavená používateľská rola po registrácii', - 'reg_confirm_email' => 'Vyžadovať overenie emailu?', + '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' => 'Ak je použité obmedzenie domény, potom bude vyžadované overenie emailu a hodnota nižšie bude ignorovaná.', 'reg_confirm_restrict_domain' => 'Obmedziť registráciu na doménu', 'reg_confirm_restrict_domain_desc' => 'Zadajte zoznam domén, pre ktoré chcete povoliť registráciu oddelených čiarkou. Používatelia dostanú email kvôli overeniu adresy predtým ako im bude dovolené používať aplikáciu.
Používatelia si budú môcť po úspešnej registrácii zmeniť svoju emailovú adresu.', 'reg_confirm_restrict_domain_placeholder' => 'Nie sú nastavené žiadne obmedzenia', - /** - * Role settings - */ + // 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.', + // Role Settings 'roles' => 'Roly', 'role_user_roles' => 'Používateľské roly', 'role_create' => 'Vytvoriť novú rolu', @@ -65,14 +96,18 @@ return [ 'role_details' => 'Detaily roly', 'role_name' => 'Názov roly', 'role_desc' => 'Krátky popis roly', + 'role_external_auth_id' => 'External Authentication IDs', 'role_system' => 'Systémové oprávnenia', 'role_manage_users' => 'Spravovať používateľov', 'role_manage_roles' => 'Spravovať role a oprávnenia rolí', 'role_manage_entity_permissions' => 'Spravovať všetky oprávnenia kníh, kapitol a stránok', 'role_manage_own_entity_permissions' => 'Spravovať oprávnenia vlastných kníh, kapitol a stránok', + 'role_manage_page_templates' => 'Manage page templates', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Spravovať nastavenia aplikácie', 'role_asset' => 'Oprávnenia majetku', 'role_asset_desc' => 'Tieto oprávnenia regulujú prednastavený prístup k zdroju v systéme. Oprávnenia pre knihy, kapitoly a stránky majú vyššiu prioritu.', + 'role_asset_admins' => 'Admins are automatically given access to all content but these options may show or hide UI options.', 'role_all' => 'Všetko', 'role_own' => 'Vlastné', 'role_controlled_by_asset' => 'Regulované zdrojom, do ktorého sú nahrané', @@ -81,19 +116,24 @@ return [ 'role_users' => 'Používatelia s touto rolou', 'role_users_none' => 'Žiadni používatelia nemajú priradenú túto rolu', - /** - * Users - */ - + // Users 'users' => 'Používatelia', 'user_profile' => 'Profil používateľa', 'users_add_new' => 'Pridať nového používateľa', 'users_search' => 'Hľadať medzi používateľmi', + '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' => 'Používateľské roly', + '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' => 'Externé autentifikačné 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' => 'Pole nižšie vyplňte iba ak chcete zmeniť heslo:', 'users_system_public' => 'Tento účet reprezentuje každého hosťovského používateľa, ktorý navštívi Vašu inštanciu. Nedá sa pomocou neho prihlásiť a je priradený automaticky.', - 'users_books_view_type' => 'Preferované rozloženie pre prezeranie kníh', 'users_delete' => 'Zmazať používateľa', 'users_delete_named' => 'Zmazať používateľa :userName', 'users_delete_warning' => ' Toto úplne odstráni používateľa menom \':userName\' zo systému.', @@ -105,10 +145,67 @@ return [ 'users_avatar' => 'Avatar používateľa', 'users_avatar_desc' => 'Tento obrázok by mal byť štvorec s rozmerom približne 256px.', 'users_preferred_language' => 'Preferovaný jazyk', + '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álne účty', 'users_social_accounts_info' => 'Tu si môžete pripojiť iné účty pre rýchlejšie a jednoduchšie prihlásenie. Disconnecting an account here does not previously authorized access. Revoke access from your profile settings on the connected social account.', 'users_social_connect' => 'Pripojiť účet', 'users_social_disconnect' => 'Odpojiť účet', 'users_social_connected' => ':socialAccount účet bol úspešne pripojený k Vášmu profilu.', 'users_social_disconnected' => ':socialAccount účet bol úspešne odpojený od Vášho profilu.', + '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' => 'العربية', + 'da' => 'Dansk', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// ]; diff --git a/resources/lang/sk/validation.php b/resources/lang/sk/validation.php index b365b409d..8dc26905d 100644 --- a/resources/lang/sk/validation.php +++ b/resources/lang/sk/validation.php @@ -1,18 +1,13 @@ ':attribute musí byť akceptovaný.', 'active_url' => ':attribute nie je platná URL.', 'after' => ':attribute musí byť dátum po :date.', @@ -35,12 +30,41 @@ return [ 'digits' => ':attribute musí mať :digits číslic.', 'digits_between' => ':attribute musí mať medzi :min a :max číslicami.', 'email' => ':attribute musí byť platná emailová adresa.', + 'ends_with' => 'The :attribute must end with one of the following: :values', 'filled' => 'Políčko :attribute je povinné.', + '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.', + ], + '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.', + ], 'exists' => 'Vybraný :attribute nie je platný.', 'image' => ':attribute musí byť obrázok.', + 'image_extension' => 'The :attribute must have a valid & supported image extension.', 'in' => 'Vybraný :attribute je neplatný.', 'integer' => ':attribute musí byť celé číslo.', 'ip' => ':attribute musí byť platná IP adresa.', + '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.', + '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.', + ], + '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.', + ], 'max' => [ 'numeric' => ':attribute nesmie byť väčší ako :max.', 'file' => ':attribute nesmie byť väčší ako :max kilobajtov.', @@ -54,7 +78,9 @@ 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.', 'regex' => ':attribute formát je neplatný.', 'required' => 'Políčko :attribute je povinné.', @@ -74,35 +100,15 @@ return [ 'timezone' => ':attribute musí byť plantá časová zóna.', 'unique' => ':attribute je už použité.', 'url' => ':attribute formát je neplatný.', + 'uploaded' => 'The file could not be uploaded. The server may not accept files of this size.', - /* - |-------------------------------------------------------------------------- - | Custom Validation Language Lines - |-------------------------------------------------------------------------- - | - | Here you may specify custom validation messages for attributes using the - | convention "attribute.rule" to name the lines. This makes it quick to - | specify a specific custom language line for a given attribute rule. - | - */ - + // Custom validation lines 'custom' => [ 'password-confirm' => [ 'required_with' => 'Vyžaduje sa potvrdenie hesla', ], ], - /* - |-------------------------------------------------------------------------- - | Custom Validation Attributes - |-------------------------------------------------------------------------- - | - | The following language lines are used to swap attribute place-holders - | with something more reader friendly such as E-Mail Address instead - | of "email". This simply helps us make messages a little cleaner. - | - */ - + // Custom validation attributes 'attributes' => [], - ]; diff --git a/resources/lang/sv/activities.php b/resources/lang/sv/activities.php index 6730d5f98..1cb8051b9 100644 --- a/resources/lang/sv/activities.php +++ b/resources/lang/sv/activities.php @@ -1,12 +1,10 @@ 'skapade sidan', 'page_create_notification' => 'Sidan har skapats', @@ -37,13 +35,13 @@ return [ 'book_sort' => 'sorterade boken', 'book_sort_notification' => 'Boken har sorterats om', - // Shelves - 'bookshelf_create' => 'skapade hyllan', - 'bookshelf_create_notification' => 'Hyllan har skapats', - 'bookshelf_update' => 'uppdaterade hyllan', - 'bookshelf_update_notification' => 'Hyllan har uppdaterats', - 'bookshelf_delete' => 'tog bort hyllan', - 'bookshelf_delete_notification' => 'Hyllan har tagits bort', + // Bookshelves + 'bookshelf_create' => 'skapade hyllan', + 'bookshelf_create_notification' => 'Hyllan har skapats', + 'bookshelf_update' => 'uppdaterade hyllan', + 'bookshelf_update_notification' => 'Hyllan har uppdaterats', + 'bookshelf_delete' => 'tog bort hyllan', + 'bookshelf_delete_notification' => 'Hyllan har tagits bort', // Other 'commented_on' => 'kommenterade', diff --git a/resources/lang/sv/auth.php b/resources/lang/sv/auth.php index 30e1a1937..96feee117 100644 --- a/resources/lang/sv/auth.php +++ b/resources/lang/sv/auth.php @@ -1,21 +1,15 @@ 'Uppgifterna stämmer inte överrens med våra register.', 'throttle' => 'För många inloggningsförsök. Prova igen om :seconds sekunder.', - /** - * Login & Register - */ + // Login & Register 'sign_up' => 'Skapa konto', 'log_in' => 'Logga in', 'log_in_with' => 'Logga in med :socialDriver', @@ -27,7 +21,7 @@ return [ 'email' => 'E-post', 'password' => 'Lösenord', 'password_confirm' => 'Bekräfta lösenord', - 'password_hint' => 'Måste vara fler än 5 tecken', + 'password_hint' => 'Måste vara fler än 7 tecken', 'forgot_password' => 'Glömt lösenord?', 'remember_me' => 'Kom ihåg mig', 'ldap_email_hint' => 'Vänligen ange en e-postadress att använda till kontot.', @@ -45,23 +39,18 @@ return [ 'register_success' => 'Tack för din registrering! Du är nu registerad och inloggad.', - /** - * Password Reset - */ + // Password Reset 'reset_password' => 'Återställ lösenord', 'reset_password_send_instructions' => 'Ange din e-postadress nedan så skickar vi ett mail med en länk för att återställa ditt lösenord.', 'reset_password_send_button' => 'Skicka återställningslänk', 'reset_password_sent_success' => 'En länk för att återställa lösenordet har skickats till :email.', 'reset_password_success' => 'Ditt lösenord har återställts.', - 'email_reset_subject' => 'Återställ ditt lösenord till :appName', 'email_reset_text' => 'Du får detta mail eftersom vi fått en begäran om att återställa lösenordet till ditt konto.', 'email_reset_not_requested' => 'Om du inte begärt att få ditt lösenord återställt behöver du inte göra någonting', - /** - * Email Confirmation - */ + // Email Confirmation 'email_confirm_subject' => 'Bekräfta din e-post på :appName', 'email_confirm_greeting' => 'Tack för att du gått med i :appName!', 'email_confirm_text' => 'Vänligen bekräfta din e-postadress genom att klicka på knappen nedan:', @@ -75,4 +64,14 @@ return [ 'email_not_confirmed_click_link' => 'Vänligen klicka på länken i det mail du fick strax efter att du registerade dig.', 'email_not_confirmed_resend' => 'Om du inte hittar mailet kan du begära en ny bekräftelse genom att fylla i formuläret nedan.', 'email_not_confirmed_resend_button' => 'Skicka bekräftelse på nytt', -]; + + // 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!' +]; \ No newline at end of file diff --git a/resources/lang/sv/common.php b/resources/lang/sv/common.php index 7f0d425a4..1e49ad03e 100644 --- a/resources/lang/sv/common.php +++ b/resources/lang/sv/common.php @@ -1,9 +1,10 @@ 'Avbryt', 'confirm' => 'Bekräfta', 'back' => 'Bakåt', @@ -13,18 +14,14 @@ return [ 'toggle_all' => 'Ändra alla', 'more' => 'Mer', - /** - * Form Labels - */ + // Form Labels 'name' => 'Namn', 'description' => 'Beskrivning', 'role' => 'Roll', 'cover_image' => 'Omslagsbild', 'cover_image_description' => 'Bilden bör vara cirka 440x250px stor.', - - /** - * Actions - */ + + // Actions 'actions' => 'Åtgärder', 'view' => 'Visa', 'view_all' => 'Visa alla', @@ -41,17 +38,18 @@ return [ 'reset' => 'Återställ', 'remove' => 'Radera', 'add' => 'Lägg till', + 'fullscreen' => 'Fullscreen', - /** - * Sort Options - */ + // Sort Options + 'sort_options' => 'Sort Options', + 'sort_direction_toggle' => 'Sort Direction Toggle', + 'sort_ascending' => 'Sort Ascending', + 'sort_descending' => 'Sort Descending', 'sort_name' => 'Namn', 'sort_created_at' => 'Skapad', 'sort_updated_at' => 'Uppdaterad', - /** - * Misc - */ + // Misc 'deleted_user' => 'Borttagen användare', 'no_activity' => 'Ingen aktivitet att visa', 'no_items' => 'Inga tillgängliga föremål', @@ -62,22 +60,18 @@ return [ 'grid_view' => 'Rutnätsvy', 'list_view' => 'Listvy', 'default' => 'Förvald', + 'breadcrumb' => 'Breadcrumb', - /** - * Header - */ + // Header + 'profile_menu' => 'Profile Menu', 'view_profile' => 'Visa profil', 'edit_profile' => 'Redigera profil', - /** - * Layout tabs - */ + // Layout tabs 'tab_info' => 'Information', 'tab_content' => 'Innehåll', - /** - * Email Content - */ + // 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', ]; diff --git a/resources/lang/sv/components.php b/resources/lang/sv/components.php index 8b1e95ec6..5e4085dec 100644 --- a/resources/lang/sv/components.php +++ b/resources/lang/sv/components.php @@ -1,9 +1,10 @@ 'Val av bild', 'image_all' => 'Alla', 'image_all_title' => 'Visa alla bilder', @@ -24,9 +25,7 @@ return [ 'image_delete_success' => 'Bilden har tagits bort', 'image_upload_remove' => 'Radera', - /** - * Code editor - */ + // Code Editor 'code_editor' => 'Redigera kod', 'code_language' => 'Språk', 'code_content' => 'Kod', diff --git a/resources/lang/sv/entities.php b/resources/lang/sv/entities.php index 806e88e3d..bc4b3a4af 100644 --- a/resources/lang/sv/entities.php +++ b/resources/lang/sv/entities.php @@ -1,9 +1,11 @@ 'Nyligen skapat', 'recently_created_pages' => 'Sidor som skapats nyligen', 'recently_updated_pages' => 'Sidor som uppdaterats nyligen', @@ -32,17 +34,13 @@ return [ 'export_pdf' => 'PDF-fil', 'export_text' => 'Textfil', - /** - * Permissions and restrictions - */ + // Permissions and restrictions 'permissions' => 'Rättigheter', 'permissions_intro' => 'Dessa rättigheter kommer att överskrida eventuella rollbaserade rättigheter.', 'permissions_enable' => 'Aktivera anpassade rättigheter', 'permissions_save' => 'Spara rättigheter', - /** - * Search - */ + // Search 'search_results' => 'Sökresultat', 'search_total_results_found' => ':count resultat|:count resultat', 'search_clear' => 'Rensa sökning', @@ -67,9 +65,39 @@ return [ 'search_set_date' => 'Ange datum', 'search_update' => 'Uppdatera sökning', - /** - * Books - */ + // Shelves + 'shelf' => 'Hylla', + 'shelves' => 'Hyllor', + 'x_shelves' => ':count hylla|:count hyllor', + 'shelves_long' => 'Bokhyllor', + 'shelves_empty' => 'Du har inte skapat någon hylla', + 'shelves_create' => 'Skapa ny hylla', + 'shelves_popular' => 'Populära hyllor', + 'shelves_new' => 'Nya hyllor', + 'shelves_new_action' => 'Ny hylla', + 'shelves_popular_empty' => 'De populäraste hyllorna kommer hamna här', + 'shelves_new_empty' => 'De senast skapade hyllorna kommer hamna här', + 'shelves_save' => 'Spara hylla', + 'shelves_books' => 'Böcker i denna hylla', + 'shelves_add_books' => 'Lägg till böcker till hyllan', + 'shelves_drag_books' => 'Dra böcker hit för att lägga dem på hyllan', + 'shelves_empty_contents' => 'Denna hylla har inga böcker än', + 'shelves_edit_and_assign' => 'Redigera hyllan för att lägga till böcker', + 'shelves_edit_named' => 'Ändra hyllan :name', + 'shelves_edit' => 'Ändra bokhylla', + 'shelves_delete' => 'Radera bokhylla', + 'shelves_delete_named' => 'Radera bokhyllan :name', + 'shelves_delete_explain' => "Detta kommer radera bokhyllan ':name'. Böckerna på hyllan kommer finnas kvar.", + 'shelves_delete_confirmation' => 'Är du säker på att du vill radera hyllan?', + 'shelves_permissions' => 'Bokhyllerättigheter', + 'shelves_permissions_updated' => 'Bokhyllerättigheterna har ändrats', + 'shelves_permissions_active' => 'Bokhyllerättigheterna är aktiva', + 'shelves_copy_permissions_to_books' => 'Kopiera rättigheter till böcker', + 'shelves_copy_permissions' => 'Kopiera rättigheter', + 'shelves_copy_permissions_explain' => 'Detta kommer kopiera hyllans rättigheter till alla böcker på den. Se till att du har sparat alla ändringar innan du går vidare.', + 'shelves_copy_permission_success' => 'Hyllans rättigheter har kopierats till :count böcker', + + // Books 'book' => 'Bok', 'books' => 'Böcker', 'x_books' => ':count bok|:count böcker', @@ -108,9 +136,7 @@ return [ 'books_sort_show_other' => 'Visa andra böcker', 'books_sort_save' => 'Spara ordning', - /** - * Chapters - */ + // Chapters 'chapter' => 'Kapitel', 'chapters' => 'Kapitel', 'x_chapters' => ':count kapitel|:count kapitel', @@ -133,9 +159,7 @@ return [ 'chapters_permissions_success' => 'Rättigheterna för kapitlet har uppdaterats', 'chapters_search_this' => 'Sök i detta kapitel', - /** - * Pages - */ + // Pages 'page' => 'Sida', 'pages' => 'Sidor', 'x_pages' => ':count sida|:count sidor', @@ -152,7 +176,7 @@ return [ 'pages_delete_confirm' => 'Är du säker på att du vill ta bort den här sidan?', 'pages_delete_draft_confirm' => 'Är du säker på att du vill ta bort det här utkastet?', 'pages_editing_named' => 'Redigerar sida :pageName', - 'pages_edit_toggle_header' => 'Växla sidhuvud', + 'pages_edit_draft_options' => 'Draft Options', 'pages_edit_save_draft' => 'Spara utkast', 'pages_edit_draft' => 'Redigera utkast', 'pages_editing_draft' => 'Redigerar utkast', @@ -210,53 +234,20 @@ return [ ], 'pages_draft_discarded' => 'Utkastet har tagits bort. Redigeringsverktyget har uppdaterats med aktuellt innehåll.', 'pages_specific' => 'Specifik sida', + 'pages_is_template' => 'Page Template', - /** - * Shelves - */ - 'shelf' => 'Hylla', - 'shelves' => 'Hyllor', - 'x_shelves' => ':count hylla|:count hyllor', - 'shelves_long' => 'Bokhyllor', - 'shelves_empty' => 'Du har inte skapat någon hylla', - 'shelves_create' => 'Skapa ny hylla', - 'shelves_popular' => 'Populära hyllor', - 'shelves_new' => 'Nya hyllor', - 'shelves_new_action' => 'Ny hylla', - 'shelves_popular_empty' => 'De populäraste hyllorna kommer hamna här', - 'shelves_new_empty' => 'De senast skapade hyllorna kommer hamna här', - 'shelves_save' => 'Spara hylla', - 'shelves_books' => 'Böcker i denna hylla', - 'shelves_add_books' => 'Lägg till böcker till hyllan', - 'shelves_drag_books' => 'Dra böcker hit för att lägga dem på hyllan', - 'shelves_empty_contents' => 'Denna hylla har inga böcker än', - 'shelves_edit_and_assign' => 'Redigera hyllan för att lägga till böcker', - 'shelves_edit_named' => 'Ändra hyllan :name', - 'shelves_edit' => 'Ändra bokhylla', - 'shelves_delete' => 'Radera bokhylla', - 'shelves_delete_named' => 'Radera bokhyllan :name', - 'shelves_delete_explain' => "Detta kommer radera bokhyllan ':name'. Böckerna på hyllan kommer finnas kvar.", - 'shelves_delete_confirmation' => 'Är du säker på att du vill radera hyllan?', - 'shelves_permissions' => 'Bokhyllerättigheter', - 'shelves_permissions_updated' => 'Bokhyllerättigheterna har ändrats', - 'shelves_permissions_active' => 'Bokhyllerättigheterna är aktiva', - 'shelves_copy_permissions_to_books' => 'Kopiera rättigheter till böcker', - 'shelves_copy_permissions' => 'Kopiera rättigheter', - 'shelves_copy_permissions_explain' => 'Detta kommer kopiera hyllans rättigheter till alla böcker på den. Se till att du har sparat alla ändringar innan du går vidare.', - 'shelves_copy_permission_success' => 'Hyllans rättigheter har kopierats till :count böcker', - - /** - * Editor sidebar - */ - 'shelf_tags' => 'Hylltaggar', + // Editor Sidebar 'page_tags' => 'Sidtaggar', 'chapter_tags' => 'Kapiteltaggar', 'book_tags' => 'Boktaggar', + 'shelf_tags' => 'Hylltaggar', 'tag' => 'Tagg', 'tags' => 'Taggar', + 'tag_name' => 'Tag Name', 'tag_value' => 'Taggvärde (Frivilligt)', 'tags_explain' => "Lägg till taggar för att kategorisera ditt innehåll bättre. \n Du kan tilldela ett värde till en tagg för ännu bättre organisering.", 'tags_add' => 'Lägg till ännu en tagg', + 'tags_remove' => 'Remove this tag', 'attachments' => 'Bilagor', 'attachments_explain' => 'Ladda upp filer eller bifoga länkar till ditt innehåll. Dessa visas i sidokolumnen.', 'attachments_explain_instant_save' => 'Ändringar här sparas omgående.', @@ -282,10 +273,14 @@ return [ 'attachments_file_uploaded' => 'Filen har laddats upp', 'attachments_file_updated' => 'Filen har uppdaterats', 'attachments_link_attached' => 'Länken har bifogats till sidan', + '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 View 'profile_user_for_x' => 'Användare i :time', 'profile_created_content' => 'Skapat innehåll', 'profile_not_created_pages' => ':userName har inte skapat några sidor', @@ -293,9 +288,7 @@ return [ 'profile_not_created_books' => ':userName har inte skapat några böcker', 'profile_not_created_shelves' => ':userName har inte skapat några hyllor', - /** - * Comments - */ + // Comments 'comment' => 'Kommentar', 'comments' => 'Kommentarer', 'comment_add' => 'Lägg till kommentar', @@ -313,11 +306,9 @@ return [ 'comment_delete_confirm' => 'Är du säker på att du vill ta bort den här kommentaren?', 'comment_in_reply_to' => 'Som svar på :commentId', - /** - * Revision - */ + // Revision 'revision_delete_confirm' => 'Är du säker på att du vill radera den här versionen?', + 'revision_restore_confirm' => 'Är du säker på att du vill använda denna revision? Det nuvarande innehållet kommer att ersättas.', 'revision_delete_success' => 'Revisionen raderad', - 'revision_cannot_delete_latest' => 'Det går inte att ta bort den senaste versionen.', - 'revision_restore_confirm' => 'Är du säker på att du vill använda denna revision? Det nuvarande innehållet kommer att ersättas.' -]; + 'revision_cannot_delete_latest' => 'Det går inte att ta bort den senaste versionen.' +]; \ No newline at end of file diff --git a/resources/lang/sv/errors.php b/resources/lang/sv/errors.php index 8bc940df0..a00109e3d 100644 --- a/resources/lang/sv/errors.php +++ b/resources/lang/sv/errors.php @@ -1,11 +1,9 @@ 'Du har inte tillgång till den här sidan.', 'permissionJson' => 'Du har inte rätt att utföra den här åtgärden.', @@ -15,10 +13,16 @@ return [ 'email_already_confirmed' => 'E-posten har redan bekräftats, prova att logga in.', 'email_confirmation_invalid' => 'Denna bekräftelsekod är inte giltig eller har redan använts. Vänligen prova att registera dig på nytt', 'email_confirmation_expired' => 'Denna bekräftelsekod har gått ut. Vi har skickat dig en ny.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'LDAP-inloggning misslyckades med anonym bindning', 'ldap_fail_authed' => 'LDAP-inloggning misslyckades med angivna dn- och lösenordsuppgifter', 'ldap_extension_not_installed' => 'LDAP PHP-tillägg inte installerat', 'ldap_cannot_connect' => 'Kan inte ansluta till ldap-servern. Anslutningen misslyckades', + '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' => 'Ingen åtgärd definierad', 'social_login_bad_response' => "Ett fel inträffade vid inloggning genom :socialAccount: \n:error", 'social_account_in_use' => 'Detta konto från :socialAccount används redan. Testa att logga in med :socialAccount istället.', @@ -29,6 +33,7 @@ return [ 'social_account_register_instructions' => 'Om du inte har något konto ännu kan du registerar dig genom att välja :socialAccount.', 'social_driver_not_found' => 'Drivrutinen för den här tjänsten hittades inte', 'social_driver_not_configured' => 'Dina inställningar för :socialAccount är inte korrekta.', + 'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.', // System 'path_not_writable' => 'Kunde inte ladda upp till sökvägen :filePath. Kontrollera att webbservern har skrivåtkomst.', @@ -82,4 +87,13 @@ return [ 'error_occurred' => 'Ett fel inträffade', 'app_down' => ':appName är nere just nu', 'back_soon' => 'Vi är snart tillbaka.', + + // 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', + ]; diff --git a/resources/lang/sv/pagination.php b/resources/lang/sv/pagination.php index aa12db17c..c64ca85dc 100644 --- a/resources/lang/sv/pagination.php +++ b/resources/lang/sv/pagination.php @@ -1,18 +1,11 @@ '« Föregående', 'next' => 'Nästa »', diff --git a/resources/lang/sv/passwords.php b/resources/lang/sv/passwords.php index 1f33f550b..8924edc7a 100644 --- a/resources/lang/sv/passwords.php +++ b/resources/lang/sv/passwords.php @@ -1,18 +1,11 @@ 'Lösenord måste vara minst sex tecken långa och anges likadant två gånger.', 'user' => "Det finns ingen användare med den e-postadressen.", 'token' => 'Återställningskoden är ogiltig.', diff --git a/resources/lang/sv/settings.php b/resources/lang/sv/settings.php index 6c44c13fb..514f8f894 100644 --- a/resources/lang/sv/settings.php +++ b/resources/lang/sv/settings.php @@ -1,19 +1,17 @@ 'Inställningar', 'settings_save' => 'Spara inställningar', 'settings_save_success' => 'Inställningarna har sparats', - /** - * App settings - */ + // App Settings 'app_customization' => 'Sidanpassning', 'app_features_security' => 'Funktioner och säkerhet', 'app_name' => 'Applikationsnamn', @@ -31,6 +29,7 @@ return [ 'app_editor_desc' => 'Välj vilket redigeringsverktyg som ska användas av alla användare för att redigera sidor.', 'app_custom_html' => 'Egen HTML i ', 'app_custom_html_desc' => 'Eventuellt innehåll i det här fältet placeras längst ner i -sektionen på varje sida. Detta är användbart för att skriva över stilmaller eller lägga in spårningskoder.', + 'app_custom_html_disabled_notice' => 'Custom HTML head content is disabled on this settings page to ensure any breaking changes can be reverted.', 'app_logo' => 'Applikationslogotyp', 'app_logo_desc' => 'Bilden bör vara minst 43px hög.
Större bilder skalas ner.', 'app_primary_color' => 'Primärfärg', @@ -42,14 +41,22 @@ return [ 'app_disable_comments_toggle' => 'Inaktivera kommentarer', 'app_disable_comments_desc' => 'Inaktivera kommentarer på alla sidor i applikationen. Befintliga kommentarer visas inte.', - /** - * Registration settings - */ + // 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' => 'Registreringsinställningar', 'reg_enable' => 'Tillåt registrering', 'reg_enable_toggle' => 'Tillåt registrering', 'reg_enable_desc' => 'När registrering tillåts kan användaren logga in som en användare. Vid registreringen ges de en förvald användarroll.', 'reg_default_role' => 'Standardroll efter registrering', + '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' => 'E-postbekräftelse', 'reg_email_confirmation_toggle' => 'Kräv e-postbekräftelse', 'reg_confirm_email_desc' => 'Om registrering begränas till vissa domäner kommer e-postbekräftelse alltid att krävas och den här inställningen kommer att ignoreras.', @@ -57,9 +64,7 @@ return [ 'reg_confirm_restrict_domain_desc' => 'Ange en kommaseparerad lista över e-postdomäner till vilka du vill begränsa registrering. Användare kommer att skickas ett mail för att bekräfta deras e-post innan de får logga in.
Notera att användare kommer att kunna ändra sin e-postadress efter lyckad registrering.', 'reg_confirm_restrict_domain_placeholder' => 'Ingen begränsning satt', - /** - * Maintenance settings - */ + // Maintenance settings 'maint' => 'Underhåll', 'maint_image_cleanup' => 'Rensa bilder', 'maint_image_cleanup_desc' => "Söker igenom innehåll i sidor & revisioner för att se vilka bilder och teckningar som är i bruk och vilka som är överflödiga. Se till att ta en komplett backup av databas och bilder innan du kör detta.", @@ -68,10 +73,15 @@ return [ 'maint_image_cleanup_warning' => 'Hittade :count bilder som potentiellt inte används. Vill du verkligen ta bort dessa bilder?', 'maint_image_cleanup_success' => 'Hittade och raderade :count bilder som potentiellt inte används!', 'maint_image_cleanup_nothing_found' => 'Hittade inga oanvända bilder, så inget har raderats!', + '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.', - /** - * Role settings - */ + // Role Settings 'roles' => 'Roller', 'role_user_roles' => 'Användarroller', 'role_create' => 'Skapa ny roll', @@ -79,7 +89,7 @@ return [ 'role_delete' => 'Ta bort roll', 'role_delete_confirm' => 'Rollen med namn \':roleName\' kommer att tas bort.', 'role_delete_users_assigned' => 'Det finns :userCount användare som tillhör den här rollen. Om du vill migrera användarna från den här rollen, välj en ny roll nedan.', - 'role_delete_no_migration' => 'Migrera inte användare', + 'role_delete_no_migration' => "Migrera inte användare", 'role_delete_sure' => 'Är du säker på att du vill ta bort den här rollen?', 'role_delete_success' => 'Rollen har tagits bort', 'role_edit' => 'Redigera roll', @@ -92,6 +102,8 @@ return [ 'role_manage_roles' => 'Hantera roller & rättigheter', 'role_manage_entity_permissions' => 'Hantera rättigheter för alla böcker, kapitel och sidor', 'role_manage_own_entity_permissions' => 'Hantera rättigheter för egna böcker, kapitel och sidor', + 'role_manage_page_templates' => 'Manage page templates', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Hantera appinställningar', 'role_asset' => 'Tillgång till innehåll', 'role_asset_desc' => 'Det här är standardinställningarna för allt innehåll i systemet. Eventuella anpassade rättigheter på böcker, kapitel och sidor skriver över dessa inställningar.', @@ -104,9 +116,7 @@ return [ 'role_users' => 'Användare med denna roll', 'role_users_none' => 'Inga användare tillhör den här rollen', - /** - * Users - */ + // Users 'users' => 'Användare', 'user_profile' => 'Användarprofil', 'users_add_new' => 'Lägg till användare', @@ -118,8 +128,10 @@ return [ 'users_role_desc' => 'Välj vilka roller den här användaren ska tilldelas. Om en användare har tilldelats flera roller kommer behörigheterna från dessa roller att staplas och de kommer att få alla rättigheter i de tilldelade rollerna.', 'users_password' => 'Användarlösenord', 'users_password_desc' => 'Ange ett lösenord som ska användas för att logga in på sidan. Lösenordet måste vara minst 5 tecken långt.', + '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' => 'Externt ID för autentisering', - 'users_external_auth_id_desc' => 'Detta är det ID som används för att matcha användaren när den kommunicerar med ditt LDAP-system.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Fyll i nedanstående fält endast om du vill byta lösenord:', 'users_system_public' => 'Den här användaren representerar eventuella gäster som använder systemet. Den kan inte användas för att logga in utan tilldeles automatiskt.', 'users_delete' => 'Ta bort användare', @@ -139,5 +151,61 @@ return [ 'users_social_connect' => 'Anslut konto', 'users_social_disconnect' => 'Koppla från konto', 'users_social_connected' => ':socialAccount har kopplats till ditt konto.', - 'users_social_disconnected' => ':socialAccount har kopplats bort från ditt konto.' + 'users_social_disconnected' => ':socialAccount har kopplats bort från ditt konto.', + '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' => 'العربية', + 'da' => 'Dansk', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// ]; diff --git a/resources/lang/sv/validation.php b/resources/lang/sv/validation.php index 368a46c0e..490d1d85b 100644 --- a/resources/lang/sv/validation.php +++ b/resources/lang/sv/validation.php @@ -1,17 +1,13 @@ ':attribute måste godkännas.', 'active_url' => ':attribute är inte en giltig URL.', 'after' => ':attribute måste vara efter :date.', @@ -34,13 +30,41 @@ return [ 'digits' => ':attribute måste vara :digits siffror.', 'digits_between' => ':attribute måste vara mellan :min och :max siffror.', 'email' => ':attribute måste vara en giltig e-postadress.', + 'ends_with' => 'The :attribute must end with one of the following: :values', 'filled' => ':attribute är obligatoriskt.', + '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.', + ], + '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.', + ], 'exists' => 'Valt värde för :attribute är ogiltigt.', 'image' => ':attribute måste vara en bild.', 'image_extension' => ':attribute måste ha ett giltigt filtillägg.', 'in' => 'Vald :attribute är ogiltigt.', 'integer' => ':attribute måste vara en integer.', 'ip' => ':attribute måste vara en giltig IP-adress.', + '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.', + '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.', + ], + '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.', + ], 'max' => [ 'numeric' => ':attribute får inte vara större än :max.', 'file' => ':attribute får inte vara större än :max kilobyte.', @@ -56,6 +80,7 @@ return [ ], 'no_double_extension' => ':attribute får bara ha ett filtillägg.', 'not_in' => 'Vald :attribute är inte giltig', + 'not_regex' => 'The :attribute format is invalid.', 'numeric' => ':attribute måste vara ett nummer.', 'regex' => ':attribute har ett ogiltigt format.', 'required' => ':attribute är obligatoriskt.', @@ -77,32 +102,13 @@ return [ 'url' => 'Formatet på :attribute är ogiltigt.', 'uploaded' => 'Filen kunde inte laddas upp. Servern kanske inte tillåter filer med denna storlek.', - /* - |-------------------------------------------------------------------------- - | Custom Validation Language Lines - |-------------------------------------------------------------------------- - | - | Here you may specify custom validation messages for attributes using the - | convention "attribute.rule" to name the lines. This makes it quick to - | specify a specific custom language line for a given attribute rule. - | - */ + // Custom validation lines 'custom' => [ 'password-confirm' => [ 'required_with' => 'Lösenordet måste bekräftas', ], ], - /* - |-------------------------------------------------------------------------- - | Custom Validation Attributes - |-------------------------------------------------------------------------- - | - | The following language lines are used to swap attribute place-holders - | with something more reader friendly such as E-Mail Address instead - | of "email". This simply helps us make messages a little cleaner. - | - */ + // Custom validation attributes 'attributes' => [], - ]; diff --git a/resources/lang/tr/activities.php b/resources/lang/tr/activities.php new file mode 100644 index 000000000..ccc55e172 --- /dev/null +++ b/resources/lang/tr/activities.php @@ -0,0 +1,48 @@ + 'saya oluşturuldu', + 'page_create_notification' => 'Sayfa Başarıyla Oluşturuldu', + 'page_update' => 'sayfa güncellendi', + 'page_update_notification' => 'Sayfa Başarıyla Güncellendi', + 'page_delete' => 'sayfa silindi', + 'page_delete_notification' => 'Sayfa Başarıyla Silindi', + 'page_restore' => 'sayfa kurtarıldı', + 'page_restore_notification' => 'Sayfa Başarıyla Kurtarıldı', + 'page_move' => 'sayfa taşındı', + + // Chapters + 'chapter_create' => 'bölüm oluşturuldu', + 'chapter_create_notification' => 'Bölüm Başarıyla Oluşturuldu', + 'chapter_update' => 'bölüm güncellendi', + 'chapter_update_notification' => 'Bölüm Başarıyla Güncellendi', + 'chapter_delete' => 'bölüm silindi', + 'chapter_delete_notification' => 'Bölüm Başarıyla Silindi', + 'chapter_move' => 'bölüm taşındı', + + // Books + 'book_create' => 'kitap oluşturuldu', + 'book_create_notification' => 'Kitap Başarıyla Oluşturuldu', + 'book_update' => 'kitap güncellendi', + 'book_update_notification' => 'Kitap Başarıyla Güncellendi', + 'book_delete' => 'kitap silindi', + 'book_delete_notification' => 'Kitap Başarıyla Silindi', + 'book_sort' => 'kitap düzenlendi', + 'book_sort_notification' => 'Kitap Başarıyla Yeniden Sıralandı', + + // Bookshelves + 'bookshelf_create' => 'kitaplık oluşturuldu', + 'bookshelf_create_notification' => 'Kitaplık Başarıyla Oluşturuldu', + 'bookshelf_update' => 'kitaplık güncellendi', + 'bookshelf_update_notification' => 'Kitaplık Başarıyla Güncellendi', + 'bookshelf_delete' => 'kitaplık silindi', + 'bookshelf_delete_notification' => 'Kitaplık Başarıyla Silindi', + + // Other + 'commented_on' => 'yorum yaptı', +]; diff --git a/resources/lang/tr/auth.php b/resources/lang/tr/auth.php new file mode 100644 index 000000000..2999f7cae --- /dev/null +++ b/resources/lang/tr/auth.php @@ -0,0 +1,77 @@ + 'Girilen bilgiler bizdeki kayıtlarla uyuşmuyor.', + 'throttle' => 'Çok fazla giriş yapmaya çalıştınız. Lütfen :seconds saniye içinde tekrar deneyin.', + + // Login & Register + 'sign_up' => 'Kayıt Ol', + 'log_in' => 'Giriş Yap', + 'log_in_with' => ':socialDriver ile giriş yap', + 'sign_up_with' => ':socialDriver ile kayıt ol', + 'logout' => 'Çıkış Yap', + + 'name' => 'İsim', + 'username' => 'Kullanıcı Adı', + 'email' => 'E-Posta', + 'password' => 'Şifre', + 'password_confirm' => 'Şifreyi onayla', + 'password_hint' => 'En az 5 karakter olmalı', + 'forgot_password' => 'Şifrenizi mi unuttunuz?', + 'remember_me' => 'Beni Hatırla', + 'ldap_email_hint' => 'Hesabı kullanmak istediğiniz e-mail adresinizi giriniz.', + 'create_account' => 'Hesap Oluştur', + 'already_have_account' => 'Zaten bir hesabınız var mı?', + 'dont_have_account' => 'Hesabınız yok mu?', + 'social_login' => 'Diğer Servisler ile Giriş Yap', + 'social_registration' => 'Diğer Servisler ile Kayıt Ol', + 'social_registration_text' => 'Diğer servisler ile kayıt ol ve giriş yap.', + + 'register_thanks' => 'Kayıt olduğunuz için teşekkürler!', + 'register_confirm' => 'Lütfen e-posta adresinizi kontrol edin ve gelen doğrulama bağlantısına tıklayınız. :appName.', + 'registrations_disabled' => 'Kayıt olma özelliği geçici olarak kısıtlanmıştır', + 'registration_email_domain_invalid' => 'Bu e-mail sağlayıcısının bu uygulamaya erişim izni yoktur.', + 'register_success' => 'Artık kayıtlı bir kullanıcı olarak giriş yaptınız.', + + + // Password Reset + 'reset_password' => 'Parolayı Sıfırla', + 'reset_password_send_instructions' => 'Aşağıya e-mail adresinizi girdiğinizde parola yenileme bağlantısı mail adresinize gönderilecektir.', + 'reset_password_send_button' => '>Sıfırlama Bağlantısını Gönder', + 'reset_password_sent_success' => 'Sıfırlama bağlantısı :email adresinize gönderildi.', + 'reset_password_success' => 'Parolanız başarıyla sıfırlandı.', + 'email_reset_subject' => ':appName şifrenizi sıfırlayın.', + 'email_reset_text' => ' Parola sıfırlama isteğinde bulunduğunuz için bu maili görüntülüyorsunuz.', + 'email_reset_not_requested' => 'Eğer bu parola sıfırlama isteğinde bulunmadıysanız herhangi bir işlem yapmanıza gerek yoktur.', + + + // Email Confirmation + 'email_confirm_subject' => ':appName için girdiğiniz mail adresiniz onaylayınız', + 'email_confirm_greeting' => ':appName\'e katıldığınız için teşekkürler!', + 'email_confirm_text' => 'Lütfen e-mail adresinizi aşağıda bulunan butona tıklayarak onaylayınız:', + 'email_confirm_action' => 'E-Maili Onayla', + 'email_confirm_send_error' => 'e-mail onayı gerekli fakat sistem mail göndermeyi başaramadı. Yöneticiniz ile görüşüp kurulumlarda bir sorun olmadığını doğrulayın.', + 'email_confirm_success' => 'e-mail adresiniz onaylandı!', + 'email_confirm_resent' => 'Doğrulama maili gönderildi, lütfen gelen kutunuzu kontrol ediniz...', + + 'email_not_confirmed' => 'E-mail Adresi Doğrulanmadı', + 'email_not_confirmed_text' => 'Sağlamış olduğunuz e-mail adresi henüz doğrulanmadı.', + 'email_not_confirmed_click_link' => 'Lütfen kayıt olduktan kısa süre sonra size gönderilen maildeki bağlantıya tıklayın ve mail adresinizi onaylayın.', + 'email_not_confirmed_resend' => 'Eğer gelen maili bulamadıysanız aşağıdaki formu tekrar doldurarak onay mailini kendinize tekrar gönderebilirsiniz.', + 'email_not_confirmed_resend_button' => 'Doğrulama Mailini Yeniden Yolla', + + // User Invite + 'user_invite_email_subject' => ':appName\'e katılma daveti aldınız!', + 'user_invite_email_greeting' => 'Sizin için :appName üzerinde bir hesap oluşturuldu.', + 'user_invite_email_text' => 'Parola belirlemek ve erişebilmek için aşağıdaki butona tıklayın:', + 'user_invite_email_action' => 'Hesap Şifresini Belirleyin', + 'user_invite_page_welcome' => ':appName\'e hoş geldiniz!', + 'user_invite_page_text' => 'Hesap açılışını tamamlamak ve erişim izni alabilmek için daha sonraki girişlerinizde kullanabilmek üzere bir şifre belirlemeniz gerekiyor.', + 'user_invite_page_confirm_button' => 'Parolayı Onayla', + 'user_invite_success' => 'Parolanız belirlendi, artık :appName\'e erişebilirsiniz!' +]; \ No newline at end of file diff --git a/resources/lang/tr/common.php b/resources/lang/tr/common.php new file mode 100644 index 000000000..740757671 --- /dev/null +++ b/resources/lang/tr/common.php @@ -0,0 +1,77 @@ + 'İptal', + 'confirm' => 'Onayla', + 'back' => 'Geri', + 'save' => 'Kaydet', + 'continue' => 'Devam', + 'select' => 'Seç', + 'toggle_all' => 'Hepsini Değiştir', + 'more' => 'Daha Fazla', + + // Form Labels + 'name' => 'İsim', + 'description' => 'Açıklama', + 'role' => 'Rol', + 'cover_image' => 'Kapak resmi', + 'cover_image_description' => 'Bu resim yaklaşık 440x250px boyutlarında olmalıdır.', + + // Actions + 'actions' => 'Aksiyonlar', + 'view' => 'Görüntüle', + 'view_all' => 'Hepsini Görüntüle', + 'create' => 'Oluştur', + 'update' => 'Güncelle', + 'edit' => 'Düzenle', + 'sort' => 'Sırala', + 'move' => 'Taşı', + 'copy' => 'Kopyala', + 'reply' => 'Yanıtla', + 'delete' => 'Sil', + 'search' => 'Ara', + 'search_clear' => 'Aramayı Temizle', + 'reset' => 'Sıfırla', + 'remove' => 'Kaldır', + 'add' => 'Ekle', + 'fullscreen' => 'Tam Ekran', + + // Sort Options + 'sort_options' => 'Sıralama Seçenekleri', + 'sort_direction_toggle' => 'Sıralama Yönünü Değiştir', + 'sort_ascending' => 'Artan Sıralama', + 'sort_descending' => 'Azalan Sıralama', + 'sort_name' => 'İsim', + 'sort_created_at' => 'Oluşturulma Tarihi', + 'sort_updated_at' => 'Güncellenme Tarihi', + + // Misc + 'deleted_user' => 'Silinmiş Kullanıcı', + 'no_activity' => 'Gösterilecek aktivite yok', + 'no_items' => 'Kullanılabilir öge yok', + 'back_to_top' => 'Başa dön', + 'toggle_details' => 'Detayları değiştir', + 'toggle_thumbnails' => 'Küçük resimleri değiştir', + 'details' => 'Detaylar', + 'grid_view' => 'Grid görünümü', + 'list_view' => 'Liste görünümü', + 'default' => 'Varsayılan', + 'breadcrumb' => 'Sayfa İşaretleri Yolu', + + // Header + 'profile_menu' => 'Tercih menüsü', + 'view_profile' => 'Profili Görüntüle', + 'edit_profile' => 'Profili Düzenle', + + // Layout tabs + 'tab_info' => 'Bilgi', + 'tab_content' => 'İçerik', + + // Email Content + 'email_action_help' => 'Eğer ":actionText" butonuna tıklamakta zorluk çekiyorsanız, aşağıda bulunan linki kopyalayıp tarayıcınıza yapıştırabilirsiniz.', + 'email_rights' => 'Bütün hakları saklıdır', +]; diff --git a/resources/lang/tr/components.php b/resources/lang/tr/components.php new file mode 100644 index 000000000..d52f2d006 --- /dev/null +++ b/resources/lang/tr/components.php @@ -0,0 +1,33 @@ + 'Görsel Seç', + 'image_all' => 'Tümü', + 'image_all_title' => 'Tüm görselleri temizle', + 'image_book_title' => 'Bu kitaba ait görselleri görüntüle', + 'image_page_title' => 'Bu sayfaya ait görselleri görüntüle', + 'image_search_hint' => 'Görsel adı ile ara', + 'image_uploaded' => ':uploadedDate tarihinde yüklendi', + 'image_load_more' => 'Daha Fazla ', + 'image_image_name' => 'Görsel Adı', + 'image_delete_used' => 'Bu görsel aşağıda bulunan görsellerde kullanılmış.', + 'image_delete_confirm' => 'Gerçekten bu görseli silmek istiyorsanız sil tuşuna basınız.', + 'image_select_image' => 'Görsel Seç', + 'image_dropzone' => 'Görselleri buraya sürükle veya seçmek için buraya tıkla', + 'images_deleted' => 'Görseller Silindi', + 'image_preview' => 'Görsel Önizleme', + 'image_upload_success' => 'Görsel başarıyla yüklendi', + 'image_update_success' => 'Görsel başarıyla güncellendi', + 'image_delete_success' => 'Görsel başarıyla silindi', + 'image_upload_remove' => 'Kaldır', + + // Code Editor + 'code_editor' => 'Kodu Güncelle', + 'code_language' => 'Kod Dil', + 'code_content' => 'Kod İçeriği', + 'code_save' => 'Kodu Kaydet', +]; diff --git a/resources/lang/tr/entities.php b/resources/lang/tr/entities.php new file mode 100644 index 000000000..1163d09f0 --- /dev/null +++ b/resources/lang/tr/entities.php @@ -0,0 +1,314 @@ + 'Yakın Zamanda Oluşturuldu', + 'recently_created_pages' => 'Yakın Zamanda Oluşturulmuş Sayfalar', + 'recently_updated_pages' => 'Yakın Zamanda Güncellenmiş Sayfalar', + 'recently_created_chapters' => 'Yakın Zamanda Oluşturulmuş Bölümler', + 'recently_created_books' => 'Yakın Zamanda Olşturulmuş Kitaplar', + 'recently_created_shelves' => 'Yakın Zamanda Oluşturulmuş Kitaplıklar', + 'recently_update' => 'Yakın Zamanda Güncellenmiş', + 'recently_viewed' => 'Yakın Zamanda Görüntülenmiş', + 'recent_activity' => 'Son Hareketler', + 'create_now' => 'Hemen bir tane oluştur', + 'revisions' => 'Revizyonlar', + 'meta_revision' => 'Revizyon #:revisionCount', + 'meta_created' => 'Oluşturuldu :timeLength', + 'meta_created_name' => ':user tarafından :timeLength tarihinde oluşturuldu', + 'meta_updated' => 'Güncellendi :timeLength', + 'meta_updated_name' => ':user tarafından :timeLength tarihinde güncellendi', + 'entity_select' => 'Öğe Seçme', + 'images' => 'Görseller', + 'my_recent_drafts' => 'Son Taslaklarım', + 'my_recently_viewed' => 'Son Görüntülemelerim', + 'no_pages_viewed' => 'Herhangi bir sayfa görüntülemediniz', + 'no_pages_recently_created' => 'Yakın zamanda bir sayfa oluşturulmadı', + 'no_pages_recently_updated' => 'Yakın zamanda bir sayfa güncellenmedi', + 'export' => 'Dışa Aktar', + 'export_html' => 'Contained Web Dosyası', + 'export_pdf' => 'PDF Dosyası', + 'export_text' => 'Düz Metin Dosyası', + + // Permissions and restrictions + 'permissions' => 'İzinler', + 'permissions_intro' => 'Etkinleştirildikten sonra bu izinler diğer diğer bütün izinlerden öncelikli olacaktır.', + 'permissions_enable' => 'Özelleştirilmiş Yetkileri Etkinleştir', + 'permissions_save' => 'İzinleri Kaydet', + + // Search + 'search_results' => 'Arama Sonuçları', + 'search_total_results_found' => ':count sonuç bulundu |:count toplam sonuç bulundu', + 'search_clear' => 'Aramaları Temizle', + 'search_no_pages' => 'Bu aramayla herhangi bir sonuç eşleşmedi', + 'search_for_term' => ':term için ara', + 'search_more' => 'Daha Fazla Sonuç', + 'search_filters' => 'Arama Filtreleri', + 'search_content_type' => 'İçerik Türü', + 'search_exact_matches' => 'Tam Eşleşmeler', + 'search_tags' => 'Etiket Aramaları', + 'search_options' => 'Ayarlar', + 'search_viewed_by_me' => 'Benim tarafımdan görüntülendi', + 'search_not_viewed_by_me' => 'Benim tarafımdan görüntülenmedi', + 'search_permissions_set' => 'İzinler ayarlandı', + 'search_created_by_me' => 'Benim tarafımdan oluşturuldu', + 'search_updated_by_me' => 'Benim tarafımdan güncellendi', + 'search_date_options' => 'Tarih Seçenekleri', + 'search_updated_before' => 'Önce güncellendi', + 'search_updated_after' => 'Sonra güncellendi', + 'search_created_before' => 'Önce oluşturuldu', + 'search_created_after' => 'Sonra oluşturuldu', + 'search_set_date' => 'Tarih Ayarla', + 'search_update' => 'Aramayı Güncelle', + + // Shelves + 'shelf' => 'Kitaplık', + 'shelves' => 'Kitaplıklar', + 'x_shelves' => ':count Kitaplık|:count Kitaplıklar', + 'shelves_long' => 'Kitaplıklar', + 'shelves_empty' => 'Hiç kitaplık oluşturulmadı', + 'shelves_create' => 'Yeni Kitaplık Oluştur', + 'shelves_popular' => 'Popüler Kitaplıklar', + 'shelves_new' => 'Yeni Kitaplıklar', + 'shelves_new_action' => 'Yeni Kitaplık', + 'shelves_popular_empty' => 'En popüler kitaplıklar burada görüntülenecek.', + 'shelves_new_empty' => 'En son oluşturulmuş kitaplıklar burada görüntülenecek.', + 'shelves_save' => 'Kitaplığı Kaydet', + 'shelves_books' => 'Bu kitaplıktaki kitaplar', + 'shelves_add_books' => 'Bu kitaplığa kitap ekle', + 'shelves_drag_books' => 'Bu kitaplığa kitap eklemek için kitapları buraya sürükle', + 'shelves_empty_contents' => 'Bu kitaplığa henüz hiç bir kitap atanmamış', + 'shelves_edit_and_assign' => 'Kitaplığa kitap eklemek için güncelle', + 'shelves_edit_named' => ':name Kitaplığını Güncelle', + 'shelves_edit' => 'Kitaplığı Güncelle', + 'shelves_delete' => 'Kitaplığı Sil', + 'shelves_delete_named' => ':name Kitaplığını Sil', + 'shelves_delete_explain' => "Bu işlem :name kitaplığını silecektir. İçerdiği kitaplar silinmeyecektir.", + 'shelves_delete_confirmation' => 'Bu kitaplığı silmek istediğinizden emin misiniz?', + 'shelves_permissions' => 'Kitaplık İzinleri', + 'shelves_permissions_updated' => 'Kitaplık İzinleri Güncellendi', + 'shelves_permissions_active' => 'Kitaplık İzinleri Aktif', + 'shelves_copy_permissions_to_books' => 'İzinleri Kitaplara Kopyala', + 'shelves_copy_permissions' => 'İzinleri Kopyala', + 'shelves_copy_permissions_explain' => 'Bu işlem sonucunda kitaplığınızın izinleri içerdiği kitaplara da aynen uygulanır. Aktifleştirmeden bu kitaplığa ait izinleri kaydettiğinizden emin olun.', + 'shelves_copy_permission_success' => 'Kitaplık izinleri :count adet kitaba kopyalandı', + + // Books + 'book' => 'Kitap', + 'books' => 'Kitaplar', + 'x_books' => ':count Kitap|:count Kitaplar', + 'books_empty' => 'Hiç kitap oluşturulmadı', + 'books_popular' => 'Popüler Kitaplar', + 'books_recent' => 'En Son Kitaplar', + 'books_new' => 'Yeni Kitaplar', + 'books_new_action' => 'Yeni Kitap', + 'books_popular_empty' => 'En popüler kitaplar burada görüntülenecek.', + 'books_new_empty' => 'En yeni kitaplar burada görüntülenecek.', + 'books_create' => 'Yeni Kitap Oluştur', + 'books_delete' => 'Kitabı Sil', + 'books_delete_named' => ':bookName kitabını sil', + 'books_delete_explain' => 'Bu işlem \':bookName\' kitabını silecek. Bütün sayfa ve bölümler silinecektir.', + 'books_delete_confirmation' => 'Bu kitabı silmek istediğinizden emin misiniz?', + 'books_edit' => 'Kitabı Güncelle', + 'books_edit_named' => ':bookName Kitabını Güncelle', + 'books_form_book_name' => 'Kitap Adı', + 'books_save' => 'Kitabı Kaydet', + 'books_permissions' => 'Kitap İzinleri', + 'books_permissions_updated' => 'Kitap İzinleri Güncellendi', + 'books_empty_contents' => 'Bu kitaba ait sayfa veya bölüm oluşturulmadı.', + 'books_empty_create_page' => 'Yeni sayfa oluştur', + 'books_empty_sort_current_book' => 'Mevcut kitabı sırala', + 'books_empty_add_chapter' => 'Yeni bölüm ekle', + 'books_permissions_active' => 'Kitap İzinleri Aktif', + 'books_search_this' => 'Bu kitapta ara', + 'books_navigation' => 'Kitap Navigasyonu', + 'books_sort' => 'Kitap İçeriklerini Sırala', + 'books_sort_named' => ':bookName Kitabını Sırala', + 'books_sort_name' => 'İsme Göre Sırala', + 'books_sort_created' => 'Oluşturulma Tarihine Göre Sırala', + 'books_sort_updated' => 'Güncellenme Tarihine Göre Sırala', + 'books_sort_chapters_first' => 'Önce Bölümler', + 'books_sort_chapters_last' => 'En Son Bölümler', + 'books_sort_show_other' => 'Diğer Kitapları Göster', + 'books_sort_save' => 'Yeni Düzeni Kaydet', + + // Chapters + 'chapter' => 'Bölüm', + 'chapters' => 'Bölümler', + 'x_chapters' => ':count Bölüm|:count Bölümler', + 'chapters_popular' => 'Popüler Bölümler', + 'chapters_new' => 'Yeni Bölüm', + 'chapters_create' => 'Yeni Bölüm Oluştur', + 'chapters_delete' => 'Bölümü Sil', + 'chapters_delete_named' => ':chapterName Bölümünü Sil', + 'chapters_delete_explain' => 'Bu işlem \':chapterName\' kitabını silecek. Bütün sayfalar silinecek ve direkt olarak ana kitab eklenecektir.', + 'chapters_delete_confirm' => 'Bölümü silmek istediğinizden emin misiniz?', + 'chapters_edit' => 'Bölümü Güncelle', + 'chapters_edit_named' => ':chapterName Bölümünü Güncelle', + 'chapters_save' => 'Bölümü Kaydet', + 'chapters_move' => 'Bölümü Taşı', + 'chapters_move_named' => ':chapterName Bölümünü Taşı', + 'chapter_move_success' => 'Bölüm :bookName Kitabına Taşındı', + 'chapters_permissions' => 'Bölüm İzinleri', + 'chapters_empty' => 'Bu bölümde henüz bir sayfa yok.', + 'chapters_permissions_active' => 'Bölüm İzinleri Aktif', + 'chapters_permissions_success' => 'Bölüm İzinleri Güncellendi', + 'chapters_search_this' => 'Bu bölümü ara', + + // Pages + 'page' => 'Sayfa', + 'pages' => 'Sayfalar', + 'x_pages' => ':count Sayfa|:count Sayfalar', + 'pages_popular' => 'Popüler Sayfalar', + 'pages_new' => 'Yeni Sayfa', + 'pages_attachments' => 'Ekler', + 'pages_navigation' => 'Sayfa Navigasyonu', + 'pages_delete' => 'Sayfayı Sil', + 'pages_delete_named' => ':pageName Sayfasını Sil', + 'pages_delete_draft_named' => ':pageName Taslak Sayfasını Sil', + 'pages_delete_draft' => 'Taslak Sayfayı Sil', + 'pages_delete_success' => 'Sayfa silindi', + 'pages_delete_draft_success' => 'Taslak sayfa silindi', + 'pages_delete_confirm' => 'Bu sayfayı silmek istediğinizden emin misiniz?', + 'pages_delete_draft_confirm' => 'Bu taslak sayfayı silmek istediğinizden emin misiniz?', + 'pages_editing_named' => ':pageName Sayfası Düzenleniyor', + 'pages_edit_draft_options' => 'Taslak Seçenekleri', + 'pages_edit_save_draft' => 'Taslağı Kaydet', + 'pages_edit_draft' => 'Taslak Sayfasını Düzenle', + 'pages_editing_draft' => 'Taslak Düzenleniyor', + 'pages_editing_page' => 'Sayfa Düzenleniyor', + 'pages_edit_draft_save_at' => 'Taslak kaydedildi ', + 'pages_edit_delete_draft' => 'Taslağı Sl', + 'pages_edit_discard_draft' => 'Taslağı Yoksay', + 'pages_edit_set_changelog' => 'Değişiklik Logunu Kaydet', + 'pages_edit_enter_changelog_desc' => 'Yaptığınız değişiklikler hakkında kısa bir bilgilendirme ekleyin', + 'pages_edit_enter_changelog' => 'Değişim Günlüğü Ekleyin', + 'pages_save' => 'Sayfayı Kaydet', + 'pages_title' => 'Sayfa Başlığı', + 'pages_name' => 'Sayfa İsmi', + 'pages_md_editor' => 'Editör', + 'pages_md_preview' => 'Önizleme', + 'pages_md_insert_image' => 'Görsel Ekle', + 'pages_md_insert_link' => 'Öge Linki Ekle', + 'pages_md_insert_drawing' => 'Çizim Ekle', + 'pages_not_in_chapter' => 'Sayfa Bu Bölümde Değil', + 'pages_move' => 'Sayfayı Taşı', + 'pages_move_success' => 'Sayfa ":parentName"\'a taşındı', + 'pages_copy' => 'Sayfayı Kopyala', + 'pages_copy_desination' => 'Kopyalanacak Hedef', + 'pages_copy_success' => 'Sayfa başarıyla kopyalandı', + 'pages_permissions' => 'Sayfa İzinleri', + 'pages_permissions_success' => 'Sayfa izinleri güncellendi', + 'pages_revision' => 'Revizyon', + 'pages_revisions' => 'Sayfa Revizyonları', + 'pages_revisions_named' => ':pageName için Sayfa Revizyonları', + 'pages_revision_named' => ':pageName için Sayfa Revizyonu', + 'pages_revisions_created_by' => 'Oluşturan', + 'pages_revisions_date' => 'Revizyon Tarihi', + 'pages_revisions_number' => '#', + 'pages_revisions_numbered' => 'Revizyon #:id', + 'pages_revisions_numbered_changes' => 'Revizyon #:id Değişiklikleri', + 'pages_revisions_changelog' => 'Değişim Günlüğü', + 'pages_revisions_changes' => 'Değişiklikler', + 'pages_revisions_current' => 'Mevcut Versiyon', + 'pages_revisions_preview' => 'Önizleme', + 'pages_revisions_restore' => 'Kurtar', + 'pages_revisions_none' => 'Bu sayfaya ait revizyon yok', + 'pages_copy_link' => 'Linki kopyala', + 'pages_edit_content_link' => 'İçeriği Düzenle', + 'pages_permissions_active' => 'Sayfa İzinleri Aktif', + 'pages_initial_revision' => 'İlk Yayın', + 'pages_initial_name' => 'Yeni Sayfa', + 'pages_editing_draft_notification' => 'Şu anda :timeDiff tarhinde kaydedilmiş olan taslağı düzenlemektesiniz.', + 'pages_draft_edited_notification' => 'Bu sayfa son girişinizden bu yana güncellendi. Değişiklikleri yoksayıp, kaydetmeden çıkmanız önerilir.', + 'pages_draft_edit_active' => [ + 'start_a' => ':count kullanıcı bu sayfayı düzenlemeye başladı', + 'start_b' => ':userName kullanıcısı bu sayfayı düzenlemeye başladı', + 'time_a' => 'sayfa son güncellendiğinden beri', + 'time_b' => 'son :minCount dakikada', + 'message' => ':start :time. Birbirinizin düzenlemelerinin çakışmamasına dikkat edin!', + ], + 'pages_draft_discarded' => 'Taslak yok sayıldı, editör mevcut sayfa içeriği ile güncellendi', + 'pages_specific' => 'Özel Sayfa', + 'pages_is_template' => 'Sayfa Şablonu', + + // Editor Sidebar + 'page_tags' => 'Sayfa Etiketleri', + 'chapter_tags' => 'Bölüm Etiketleri', + 'book_tags' => 'Kitap Etiketleri', + 'shelf_tags' => 'Kitaplık Etiketleri', + 'tag' => 'Etiket', + 'tags' => 'Etiketler', + 'tag_name' => 'Etiket İsmi', + 'tag_value' => 'Etiket İçeriği (Opsiyonel)', + 'tags_explain' => "İçeriğini daha iyi kategorize etmek için bazı etiketler ekle. Etiketlere değer atayarak daha derin bir organizasyon yapısına sahip olabilirsin.", + 'tags_add' => 'Başka etiket ekle', + 'tags_remove' => 'Bu Etiketi Sil', + 'attachments' => 'Ekler', + 'attachments_explain' => 'Sayfanızda göstermek için bazı dosyalar yükleyin veya bazı bağlantılar ekleyin. Bunlar sayfanın sidebarında görülebilir.', + 'attachments_explain_instant_save' => 'Burada yapılan değişiklikler anında kaydedilir.', + 'attachments_items' => 'Eklenmiş Ögeler', + 'attachments_upload' => 'Dosya Yükle', + 'attachments_link' => 'Link Ekle', + 'attachments_set_link' => 'Link Düzenle', + 'attachments_delete_confirm' => 'Eki gerçekten silmek istiyor musunuz?', + 'attachments_dropzone' => 'Dosyaları buraya sürükle veya eklemek için buraya tıkla', + 'attachments_no_files' => 'Hiç bir dosya yüklenmedi', + 'attachments_explain_link' => 'Eğer dosya yüklememeyi tercih ederseniz link ekleyebilirsiniz. Bu başka bir sayfaya veya buluttaki bir dosyanın linki olabilir.', + 'attachments_link_name' => 'Bağlantı Adı', + 'attachment_link' => 'Ek linki', + 'attachments_link_url' => 'Dosya linki', + 'attachments_link_url_hint' => 'Dosyanın veya sitenin url adres', + 'attach' => 'Ekle', + 'attachments_edit_file' => 'Dosyayı Düzenle', + 'attachments_edit_file_name' => 'Dosya Adı', + 'attachments_edit_drop_upload' => 'Dosyaları sürükle veya yüklemek için buraya tıkla', + 'attachments_order_updated' => 'Ek sırası güncellendi', + 'attachments_updated_success' => 'Ek detayları güncellendi', + 'attachments_deleted' => 'Ek silindi', + 'attachments_file_uploaded' => 'Dosya başarıyla yüklendi', + 'attachments_file_updated' => 'Dosya başarıyla güncellendi', + 'attachments_link_attached' => 'Link sayfaya başarıyla eklendi', + 'templates' => 'Şablonlar', + 'templates_set_as_template' => 'Sayfa bir şablondur', + 'templates_explain_set_as_template' => 'Bu sayfayı şablon olarak seçebilirsiniz. Böylece taslağın içeriği diğer sayfaları oluştururken düzenlenebilir. Eğer yetkileri varsa diğer kullanıcılar da bu sayfayı görüntülerken bu şablonu kullanabilirler.', + 'templates_replace_content' => 'Sayfa içeriğini değiştir', + 'templates_append_content' => 'Sayfa içeriğine ekle', + 'templates_prepend_content' => 'Sayfa içeriğinin başına ekle', + + // Profile View + 'profile_user_for_x' => 'Kullanıcı :time', + 'profile_created_content' => 'Oluşturulan İçerik', + 'profile_not_created_pages' => ':userName herhangi bir sayfa oluşturmadı', + 'profile_not_created_chapters' => ':userName herhangi bir bölüm oluşturmadı', + 'profile_not_created_books' => ':userName herhangi bir kitap oluşturmadı', + 'profile_not_created_shelves' => ':userName herhangi bir kitaplık oluşturmadı', + + // Comments + 'comment' => 'Yorum', + 'comments' => 'Yorumlar', + 'comment_add' => 'Yorum Ekle', + 'comment_placeholder' => 'Buraya yorum ekle', + 'comment_count' => '{0} Yorum Yok|{1} 1 Yorum|[2,*] :count Yorun', + 'comment_save' => 'Yorum Kaydet', + 'comment_saving' => 'Yorum kaydediliyor...', + 'comment_deleting' => 'Yorum siliniyor...', + 'comment_new' => 'Yeni Yorum', + 'comment_created' => 'yorum yaptı :createDiff', + 'comment_updated' => ':username tarafından :updateDiff önce güncellendi', + 'comment_deleted_success' => 'Yorum silindi', + 'comment_created_success' => 'Yorum eklendi', + 'comment_updated_success' => 'Yorum güncellendi', + 'comment_delete_confirm' => 'Bu yorumu silmek istediğinizden emin misiniz?', + 'comment_in_reply_to' => ':commentId yorumuna yanıt olarak', + + // Revision + 'revision_delete_confirm' => 'Bu revizyonu silmek istediğinizden emin misiniz?', + 'revision_restore_confirm' => 'Bu revizyonu yeniden yüklemek istediğinizden emin misiniz? Mevcut sayfa içeriği değiştirilecektir.', + 'revision_delete_success' => 'Revizyon silindi', + 'revision_cannot_delete_latest' => 'Son revizyon silinemez.' +]; \ No newline at end of file diff --git a/resources/lang/tr/errors.php b/resources/lang/tr/errors.php new file mode 100644 index 000000000..4e20e3b00 --- /dev/null +++ b/resources/lang/tr/errors.php @@ -0,0 +1,99 @@ + 'Bu sayfaya erişme yetkiniz yok.', + 'permissionJson' => 'Bu işlemi yapmak için yetkiniz yo.', + + // Auth + 'error_user_exists_different_creds' => ':email adresi farklı kullanıcı bilgileri ile zaten kullanımda.', + 'email_already_confirmed' => 'E-mail halihazırda onaylanmış, giriş yapmayı dene.', + 'email_confirmation_invalid' => 'Bu doğrulama tokenı daha önce kullanılmış veya geçerli değil, lütfen tekrar kayıt olmayı deneyin.', + 'email_confirmation_expired' => 'Doğrulama token\'ının süresi geçmiş, yeni bir mail gönderildi.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', + 'ldap_fail_anonymous' => 'Anonim LDAP girişi başarısız oldu', + 'ldap_fail_authed' => 'Verdiğiniz bilgiler ile LDAP girişi başarısız oldu.', + 'ldap_extension_not_installed' => 'LDAP PHP eklentisi yüklenmedi', + 'ldap_cannot_connect' => 'LDAP sunucusuna bağlanılamadı, ilk bağlantı başarısız oldu', + 'saml_already_logged_in' => 'Zaten giriş yapıldı', + 'saml_user_not_registered' => ':name adlı kullanıcı kayıtlı değil ve otomatik kaydolma devre dışı', + 'saml_no_email_address' => 'Bu kullanıcı için, harici bir doğrulama siteminden elde edilen verilerde, bir e-posta adresi bulunamadı', + 'saml_invalid_response_id' => 'Harici doğrulama sistemi tarafından sağlanan bir veri talebi, bu uygulama tarafından başlatılan bir işlem tarafından tanınamadı. Giriş yaptıktan sonra geri dönmek bu soruna yol açabilir.', + 'saml_fail_authed' => ':system kullanarak giriş yapma başarısız, sistem başarılı bir doğrulama sağlamadı', + 'social_no_action_defined' => 'Bir aksiyon tanımlanmadı', + 'social_login_bad_response' => ":socialAccount girişi sırasında hata oluştu: \n:error", + 'social_account_in_use' => 'Bu :socialAccount zaten kullanımda, :socialAccount hesabıyla giriş yapmayı deneyin.', + 'social_account_email_in_use' => ':email adresi zaten kullanımda. Eğer zaten bir hesabınız varsa :socialAccount hesabınızı profil ayarları kısmından bağlayabilirsiniz.', + 'social_account_existing' => 'Bu :socialAccount zaten profilinize eklenmiş.', + 'social_account_already_used_existing' => 'Bu :socialAccount başka bir kullanıcı tarafından kullanılıyor.', + 'social_account_not_used' => 'Bu :socialAccount hesabı hiç bir kullanıcıya bağlı değil. Lütfen profil ayarlarına gidiniz ve bağlayınız. ', + 'social_account_register_instructions' => 'Hala bir hesabınız yoksa :socialAccount ile kayıt olabilirsiniz.', + 'social_driver_not_found' => 'Social driver bulunamadı', + 'social_driver_not_configured' => ':socialAccount ayarlarınız doğru bir şekilde ayarlanmadı.', + 'invite_token_expired' => 'Davetiye linkinin süresi doldu. Bunun yerine parolanızı sıfırlamayı deneyebilirsiniz.', + + // System + 'path_not_writable' => ':filePath dosya yolu yüklenemedi. Sunucuya yazılabilir olduğundan emin olun.', + 'cannot_get_image_from_url' => ':url\'den görsel alınamadı', + 'cannot_create_thumbs' => 'Sunucu küçük resimleri oluşturamadı. Lütfen GD PHP eklentisinin yüklü olduğundan emin olun.', + 'server_upload_limit' => 'Sunucu bu boyutta dosya yüklemenize izin vermiyor. Lütfen daha küçük boyutta dosya yüklemeyi deneyiniz.', + 'uploaded' => 'Sunucu bu boyutta dosya yüklemenize izin vermiyor. Lütfen daha küçük boyutta dosya yüklemeyi deneyiniz.', + 'image_upload_error' => 'Görsel yüklenirken bir hata oluştu', + 'image_upload_type_error' => 'Yüklemeye çalıştığınız dosya türü geçerli değildir', + 'file_upload_timeout' => 'Dosya yüklemesi zaman aşımına uğradı', + + // Attachments + 'attachment_page_mismatch' => 'Ek güncellemesi sırasında sayfa uyuşmazlığı yaşandı', + 'attachment_not_found' => 'Ek bulunamadı', + + // Pages + 'page_draft_autosave_fail' => 'Taslak kaydetme başarısız. Sayfanızı kaydetmeden önce internet bağlantınız olduğundan emin olun', + 'page_custom_home_deletion' => 'Bu sayfa anasayfa olarak ayarlandığı için silinemez', + + // Entities + 'entity_not_found' => 'Eleman bulunamadı', + 'bookshelf_not_found' => 'Kitaplık bulunamadı', + 'book_not_found' => 'Kitap bulunamadı', + 'page_not_found' => 'Sayfa bulunamadı', + 'chapter_not_found' => 'Bölüm bulunamadı', + 'selected_book_not_found' => 'Seçilen kitap bulunamadı', + 'selected_book_chapter_not_found' => 'Seçilen kitap veya bölüm bulunamadı', + 'guests_cannot_save_drafts' => 'Misafirler taslak kaydedemezler', + + // Users + 'users_cannot_delete_only_admin' => 'Tek olan yöneticiyi silemezsiniz', + 'users_cannot_delete_guest' => 'Misafir kullanıyıcıyı silemezsiniz', + + // Roles + 'role_cannot_be_edited' => 'Bu rol düzenlenemez', + 'role_system_cannot_be_deleted' => 'Bu bir yönetici rolüdür ve silinemez', + 'role_registration_default_cannot_delete' => 'Bu rol varsayılan yönetici rolü olarak atandığı için silinemez ', + 'role_cannot_remove_only_admin' => 'Bu kullanıcı yönetici rolü olan tek kullanıcı olduğu için silinemez. Bu kullanıcıyı silmek için önce başka bir kullanıcıya yönetici rolü atayın.', + + // Comments + 'comment_list' => 'Yorumlar yüklenirken bir hata oluştu.', + 'cannot_add_comment_to_draft' => 'Taslaklara yorum ekleyemezsiniz.', + 'comment_add' => 'Yorum eklerken/güncellerken bir hata olıuştu.', + 'comment_delete' => 'Yorum silinirken bir hata oluştu.', + 'empty_comment' => 'Boş bir yorum eklenemez.', + + // Error pages + '404_page_not_found' => 'Sayfa Bulunamadı', + 'sorry_page_not_found' => 'Üzgünüz, aradığınız sayfa bulunamıyor.', + 'return_home' => 'Anasayfaya dön', + 'error_occurred' => 'Bir Hata Oluştu', + 'app_down' => ':appName şu anda inaktif', + 'back_soon' => 'En kısa zamanda aktif hale gelecek.', + + // 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', + +]; diff --git a/resources/lang/tr/pagination.php b/resources/lang/tr/pagination.php new file mode 100644 index 000000000..8550a186b --- /dev/null +++ b/resources/lang/tr/pagination.php @@ -0,0 +1,12 @@ + '« Önceki', + 'next' => 'Sonraki »', + +]; diff --git a/resources/lang/tr/passwords.php b/resources/lang/tr/passwords.php new file mode 100644 index 000000000..42e9ef2c7 --- /dev/null +++ b/resources/lang/tr/passwords.php @@ -0,0 +1,15 @@ + 'Parolanız en az 6 karakterden oluşmalı ve doğrulama parolası ile eşleşmelidir. ', + 'user' => "Bu e-mail adresi ile ilişkilendirilmiş bir kullanıcı bulamadık.", + 'token' => 'Parola yenileme tokeni geçerli değil.', + 'sent' => 'Parola sıfırlanma bağlantısını e-mail adresinize gönderdik!', + 'reset' => 'Parolanız sıfırlandı!', + +]; diff --git a/resources/lang/tr/settings.php b/resources/lang/tr/settings.php new file mode 100755 index 000000000..4e81344bd --- /dev/null +++ b/resources/lang/tr/settings.php @@ -0,0 +1,211 @@ + 'Ayarlar', + 'settings_save' => 'Ayarları Kaydet', + 'settings_save_success' => 'Ayarlar Kaydedildi', + + // App Settings + 'app_customization' => 'Özelleştirme', + 'app_features_security' => 'Özellikler & Güvenlik', + 'app_name' => 'Uygulama Adı', + 'app_name_desc' => 'Bu isim başlıkta ve sistem tarafında gönderilen tüm mesajlarda gösterilecektir.', + 'app_name_header' => 'İsmi başlıkta göster', + 'app_public_access' => 'Açık Erişim', + 'app_public_access_desc' => 'Bu özelliği aktif etmek giriş yapmamış misafir kullanıcıların sizin BookStack uygulamanıza erişmesini sağlar', + 'app_public_access_desc_guest' => 'Kayıtlı olmayan kullanıcılar için erişim yetkisi "Guest" kullanıcısı üzerinden düzenlenebilir.', + 'app_public_access_toggle' => 'Açık erişime izin ver', + 'app_public_viewing' => 'Herkese açık görüntülenmeye izin verilsin mi?', + 'app_secure_images' => 'Daha Yüksek Güvenlikli Görsel Yüklemeleri', + 'app_secure_images_toggle' => 'Daha yüksek güveblikli görsel yüklemelerine izin ver', + 'app_secure_images_desc' => 'Performans sebepleri nedeniyle bütün görseller halka açık. Bu opsiyon rastgele ve tahmin edilmesi zor dizileri görsel linklerinin önüne ekler. Dizin indexlerinin kapalı olduğundan emin olun.', + 'app_editor' => 'Sayfa Editörü', + 'app_editor_desc' => 'Sayfa düzenlemesi yapılırken hangi editörün kullanılacağını seçin.', + 'app_custom_html' => 'Özel HTML Head İçeriği', + 'app_custom_html_desc' => 'Buraya eklenecek olan içerik taginin en sonuna eklenecektir. Bu stilleri override ederken veya analytics eklerken faydalı bir kullanım şeklidir.', + 'app_custom_html_disabled_notice' => 'Yapılan hatalı değişikliklerin geriye alınabilmesi için bu sayfada özel HTML head içeriği kapalı.', + 'app_logo' => 'Uygulama Logosu', + 'app_logo_desc' => 'Bu görsel 43px yüksekliğinde olmalı.
Büyük görseller ölçeklenecektir.', + 'app_primary_color' => 'Uygulamanın Birincil Rengi', + 'app_primary_color_desc' => 'Bu bir hex değeri olmalıdır.
Varsayılan rengi seçmek için boş bırakın.', + 'app_homepage' => 'Uygulama Anasayfası', + 'app_homepage_desc' => 'Anasayfada görünmesi için bir view seçin. Sayfa izinleri seçili sayfalar için yok sayılacaktır.', + 'app_homepage_select' => 'Sayfa seçiniz', + 'app_disable_comments' => 'Yorumları Engelle', + 'app_disable_comments_toggle' => 'Yorumları engelle', + 'app_disable_comments_desc' => 'Yorumları uygulamadaki bütün sayfalar için engelle.
Mevcut yorumlar gösterilmeyecektir.', + + // Color settings + 'content_colors' => 'İçerik Renkleri', + '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' => 'Raf Rengi', + 'book_color' => 'Kitap Rengi', + 'chapter_color' => 'Kısım Rengi', + 'page_color' => 'Sayfa Rengi', + 'page_draft_color' => 'Sayfa Taslağı Rengi', + + // Registration Settings + 'reg_settings' => 'Kayıt', + 'reg_enable' => 'Kaydolmaya İzin Ver', + 'reg_enable_toggle' => 'Kaydolmaya izin ver', + 'reg_enable_desc' => 'Kayıt olmaya izin verdiğinizde kullanıcılar kendilerini uygulamaya kaydedebilecekler. Kayıt olduktan sonra kendilerine varsayılan kullanıcı rolü atanacaktır.', + 'reg_default_role' => 'Kayıt olduktan sonra varsayılan kullanıcı rolü', + '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 Doğrulama', + 'reg_email_confirmation_toggle' => 'E-mail onayı gerektir', + 'reg_confirm_email_desc' => 'Eğer domain kısıtlaması kullanılıyorsa o zaman email doğrulaması gereklidir ve bu seçenek yok sayılacaktır.', + 'reg_confirm_restrict_domain' => 'Domain Kısıtlaması', + 'reg_confirm_restrict_domain_desc' => 'Kısıtlamak istediğiniz email domainlerini vigül ile ayırarak yazınız. Kullanıcılara uygulamaya erişmeden önce adreslerini doğrulamak için bir mail gönderilecektir.
Kullanıcılar başarıyla kaydolduktan sonra email adreslerini değiştiremeyeceklerdir.', + 'reg_confirm_restrict_domain_placeholder' => 'Hiçbir kısıtlama tanımlanmamış', + + // Maintenance settings + 'maint' => 'Bakım', + 'maint_image_cleanup' => 'Görsel Temizliği', + 'maint_image_cleanup_desc' => "Sayfaları ve revizyon içeriklerini tarayarak hangi gösel ve çizimlerin kullanımda olduğunu ve hangilerinin gereksiz olduğunu tespit eder. Bunu başlatmadan veritabanı ve görsellerin tam bir yedeğinin alındığından emin olun.", + 'maint_image_cleanup_ignore_revisions' => 'Revizyonlardaki görselleri yoksay', + 'maint_image_cleanup_run' => 'Temizliği Başlat', + 'maint_image_cleanup_warning' => ':count potansiyel kullanılmayan görsel bulundu. Bu görselleri silmek istediğinizden emin misiniz?', + 'maint_image_cleanup_success' => ':count potanisyel kullanılmayan görsel bulundu ve silindi!', + 'maint_image_cleanup_nothing_found' => 'Kullanılmayan görsel bulunamadı ve birşey silinmedi!', + 'maint_send_test_email' => 'Test E-Postası Gönder', + 'maint_send_test_email_desc' => 'Bu profilinizde girdiğiniz e-posta adresine bir test e-postası gönderir.', + 'maint_send_test_email_run' => 'Test E-Postasını gönder', + 'maint_send_test_email_success' => 'E-Posta :address adresine gönderildi', + 'maint_send_test_email_mail_subject' => 'Test e-postası', + 'maint_send_test_email_mail_greeting' => 'E-Posta gönderimi başarılı!', + 'maint_send_test_email_mail_text' => 'Tebrikler! Eğer bu e-posta bildirimini alıyorsanız, e-posta ayarlarınız doğru bir şekilde ayarlanmış demektir.', + + // Role Settings + 'roles' => 'Roller', + 'role_user_roles' => 'Kullanıcı Rolleri', + 'role_create' => 'Yeni Rol Oluştur', + 'role_create_success' => 'Rol Başarıyla Oluşturuldu', + 'role_delete' => 'Rolü Sil', + 'role_delete_confirm' => 'Bu işlem \':roleName\' rolünü silecektir.', + 'role_delete_users_assigned' => 'Bu role atanmış :userCount adet kullanıcı var. Eğer bu kullanıcıların rollerini değiştirmek istiyorsanız aşağıdan yeni bir rol seçin.', + 'role_delete_no_migration' => "Kullanıcıları taşıma", + 'role_delete_sure' => 'Bu rolü silmek istediğinizden emin misiniz?', + 'role_delete_success' => 'Rol başarıyla silindi', + 'role_edit' => 'Rolü Düzenle', + 'role_details' => 'Rol Detayları', + 'role_name' => 'Rol Adı', + 'role_desc' => 'Rolün Kısa Tanımı', + 'role_external_auth_id' => 'Harici Authentication ID\'leri', + 'role_system' => 'Sistem Yetkileri', + 'role_manage_users' => 'Kullanıcıları yönet', + 'role_manage_roles' => 'Rolleri ve rol izinlerini yönet', + 'role_manage_entity_permissions' => 'Bütün kitap, bölüm ve sayfa izinlerini yönet', + 'role_manage_own_entity_permissions' => 'Sahip olunan kitap, bölüm ve sayfaların izinlerini yönet', + 'role_manage_page_templates' => 'Sayfa şablonlarını yönet', + 'role_access_api' => 'Access system API', + 'role_manage_settings' => 'Uygulama ayarlarını yönet', + 'role_asset' => 'Asset Yetkileri', + 'role_asset_desc' => 'Bu izinleri assetlere sistem içinden varsayılan erişimi kontrol eder. Kitaplar, bölümler ve sayfaların izinleri bu izinleri override eder.', + 'role_asset_admins' => 'Yöneticilere otomatik olarak bütün içeriğe erişim yetkisi verilir fakat bu opsiyonlar UI özelliklerini gösterir veya gizler.', + 'role_all' => 'Hepsi', + 'role_own' => 'Sahip Olunan', + 'role_controlled_by_asset' => 'Yükledikleri asset tarafından kontrol ediliyor', + 'role_save' => 'Rolü Kaydet', + 'role_update_success' => 'Rol başarıyla güncellendi', + 'role_users' => 'Bu roldeki kullanıcılar', + 'role_users_none' => 'Bu role henüz bir kullanıcı atanmadı', + + // Users + 'users' => 'Kullanıcılar', + 'user_profile' => 'Kullanıcı Profili', + 'users_add_new' => 'Yeni Kullanıcı Ekle', + 'users_search' => 'Kullanıcıları Ara', + 'users_details' => 'Kullanıcı Detayları', + 'users_details_desc' => 'Bu kullanıcı için gösterilecek bir isim ve mail adresi belirleyin. Bu e-mail adresi kullanıcı tarafından giriş yaparken kullanılacak.', + 'users_details_desc_no_email' => 'Diğer kullanıcılar tarafından tanınabilmesi için bir isim belirleyin.', + 'users_role' => 'Kullanıcı Rolleri', + 'users_role_desc' => 'Bu kullanıcının hangi rollere atanabileceğini belirleyin. Eğer bir kullanıcıya birden fazla rol atanırsa, kullanıcı bütün rollerin özelliklerini kullanabilir.', + 'users_password' => 'Kullanıcı Parolası', + 'users_password_desc' => 'Kullanıcının giriş yaparken kullanacağı bir parola belirleyin. Parola en az 5 karakter olmalıdır.', + 'users_send_invite_text' => 'Bu kullanıcıya parolasını sıfırlayabilmesi için bir e-posta gönder veya şifresini sen belirle.', + 'users_send_invite_option' => 'Kullanıcıya davet e-postası gönder', + 'users_external_auth_id' => 'Harici Authentication ID\'si', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', + 'users_password_warning' => 'Sadece parolanızı değiştirmek istiyorsanız aşağıyı doldurunuz.', + 'users_system_public' => 'Bu kullanıcı sizin uygulamanızı ziyaret eden bütün misafir kullanıcıları temsil eder. Giriş yapmak için kullanılamaz, otomatik olarak atanır.', + 'users_delete' => 'Kullanıcı Sil', + 'users_delete_named' => ':userName kullanıcısını sil ', + 'users_delete_warning' => 'Bu işlem \':userName\' kullanıcısını sistemden tamamen silecektir.', + 'users_delete_confirm' => 'Bu kullanıcıyı tamamen silmek istediğinize emin misiniz?', + 'users_delete_success' => 'Kullanıcılar başarıyla silindi.', + 'users_edit' => 'Kullanıcıyı Güncelle', + 'users_edit_profile' => 'Profili Düzenle', + 'users_edit_success' => 'Kullanıcı başarıyla güncellendi', + 'users_avatar' => 'Kullanıcı Avatarı', + 'users_avatar_desc' => 'Bu kullanıcıyı temsil eden bir görsel seçin. Yaklaşık 256px kare olmalıdır.', + 'users_preferred_language' => 'Tercih Edilen Dil', + 'users_preferred_language_desc' => 'Bu seçenek kullanıcı arayüzünün dilini değiştirecektir. Herhangi bir kullanıcı içeriğini etkilemeyecektir.', + 'users_social_accounts' => 'Sosyal Hesaplar', + 'users_social_accounts_info' => 'Burada diğer hesaplarınızı ekleyerek daha hızlı ve kolay giriş sağlayabilirsiniz. Bir hesabın bağlantısını kesmek daha önce edilnilen erişiminizi kaldırmaz. Profil ayarlarınızdan bağlı sosyal hesabınızın erişimini kaldırınız.', + 'users_social_connect' => 'Hesap Bağla', + 'users_social_disconnect' => 'Hesabın Bağlantısını Kes', + 'users_social_connected' => ':socialAccount hesabı profilinize başarıyla bağlandı.', + 'users_social_disconnected' => ':socialAccount hesabınızın profilinizle ilişiği başarıyla kesildi.', + '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' => 'العربية', + 'da' => 'Dansk', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// +]; diff --git a/resources/lang/tr/validation.php b/resources/lang/tr/validation.php new file mode 100644 index 000000000..18328ce75 --- /dev/null +++ b/resources/lang/tr/validation.php @@ -0,0 +1,114 @@ + ':attribute kabul edilmelidir.', + 'active_url' => ':attribute geçerli bir URL adresi değildir.', + 'after' => ':attribute :date tarihinden sonra bir tarih olmalıdır.', + 'alpha' => ':attribute sadece harflerden oluşabilir.', + 'alpha_dash' => ':attribute sadece harf, rakam ve tirelerden oluşabilir.', + 'alpha_num' => ':attribute sadece harf ve rakam oluşabilir.', + 'array' => ':attribute array olmalıdır..', + 'before' => ':attribute :date tarihinden önce bir tarih olmalıdır.', + 'between' => [ + 'numeric' => ':attribute, :min ve :max değerleri arasında olmalıdır.', + 'file' => ':attribute, :min ve :max kilobyte boyutları arasında olmalıdır.', + 'string' => ':attribute, :min ve :max karakter arasında olmalıdır.', + 'array' => ':attribute :min ve :max öge arasında olmalıdır.', + ], + 'boolean' => ':attribute true veya false olmalıdır.', + 'confirmed' => ':attribute doğrulaması eşleşmiyor.', + 'date' => ':attribute geçerli bir tarih değil.', + 'date_format' => ':attribute formatı :format\'ına uymuyor.', + 'different' => ':attribute be :other birbirinden farklı olmalıdır.', + 'digits' => ':attribute :digits basamaklı olmalıdır.', + 'digits_between' => ':attribute :min ve :max basamaklı olmalıdır.', + 'email' => ':attribute geçerli bir e-mail adresi olmalıdır.', + 'ends_with' => ':attribute şunlardan biriyle bitmelidir: :values', + 'filled' => ':attribute gerekli bir alandır.', + 'gt' => [ + 'numeric' => ':attribute :max değerinden büyük olmalı.', + 'file' => ':attribute değeri :value kilobayt değerinden büyük olmalıdır.', + 'string' => ':attribute değeri :value karakter değerinden büyük olmalıdır.', + 'array' => ':attribute, :value öğeden daha fazlasına sahip olamaz.', + ], + 'gte' => [ + 'numeric' => ':attribute, :value değerinden büyük veya eşit olmalı.', + 'file' => ':attribute, :value kilobayttan eşit ya da büyük olmalı.', + 'string' => ':attribute, :value kilobayttan eşit ya da büyük olmalı.', + 'array' => ':attribute, :value veya daha fazla maddeye sahip olmalıdır.', + ], + 'exists' => 'Seçilen :attribute geçerli bir alan değildir.', + 'image' => ':attribute bir görsel olmalıdır.', + 'image_extension' => ':attribute geçerli ve desteklenen bir görsel uzantısı değildir.', + 'in' => 'Seçilen :attribute geçerli değildir.', + 'integer' => ':attribute bir integer değeri olmalıdır.', + 'ip' => ':attribute geçerli bir IP adresi olmalıdır.', + 'ipv4' => ': Özniteliği geçerli bir IPv4 adresi olmalıdır.', + 'ipv6' => ':attribute geçerli bir IPv6 adresi olmalıdır.', + 'json' => ':attribute geçerli bir JSON dizini olmalı.', + 'lt' => [ + 'numeric' => ':attribute, :value değerinden küçük olmalıdır.', + 'file' => ':attribute, :value kilobayt boyutundan küçük olmalıdır.', + 'string' => ':attribute, :value karakterden küçük olmalıdır.', + 'array' => ':attribute, :value öğeden az olmalıdır.', + ], + 'lte' => [ + 'numeric' => ':attribute, :value değerinden küçük veya eşit olmalıdır.', + 'file' => ':attribute, :value kilobayttan küçük ya da eşit olmalıdır.', + 'string' => ':attribute, :value kilobayttan küçük ya da eşit olmalıdır.', + 'array' => ':attribute, :value öğeden daha fazlasına sahip olamaz.', + ], + 'max' => [ + 'numeric' => ':attribute, :max değerinden büyük olmamalıdır.', + 'file' => ':attribute, :max kilobyte boyutundan büyük olmamalıdır.', + 'string' => ':attribute, :max karakter boyutundan büyük olmamalıdır.', + 'array' => ':attribute, en fazla :max öge içermelidir.', + ], + 'mimes' => ':attribute :values dosya tipinde olmalıdır.', + 'min' => [ + 'numeric' => ':attribute, :min değerinden az olmamalıdır.', + 'file' => ':attribute, :min kilobyte boyutundan küçük olmamalıdır.', + 'string' => ':attribute, :min karakter boyutundan küçük olmamalıdır.', + '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çerli değildir.', + 'not_regex' => ':attribute formatı geçerli değildir.', + 'numeric' => ':attribute rakam olmalıdır.', + 'regex' => ':attribute formatı geçerli değildir.', + 'required' => 'The :attribute field is required. :attribute alanı gereklidir.', + 'required_if' => ':other alanı :value değerinde ise :attribute alanı gereklidir.', + 'required_with' => 'Eğer :values değeri geçerli ise :attribute alanı gereklidir.', + 'required_with_all' => 'Eğer :values değeri geçerli ise :attribute alanı gereklidir. ', + 'required_without' => 'Eğer :values değeri geçerli değil ise :attribute alanı gereklidir.', + 'required_without_all' => 'Eğer :values değerlerinden hiçbiri geçerli değil ise :attribute alanı gereklidir.', + 'same' => ':attribute ve :other eşleşmelidir.', + 'size' => [ + 'numeric' => ':attribute, :size boyutunda olmalıdır.', + 'file' => ':attribute, :size kilobyte boyutunda olmalıdır.', + 'string' => ':attribute, :size karakter uzunluğunda olmalıdır.', + 'array' => ':attribute, :size sayıda öge içermelidir.', + ], + 'string' => ':attribute string olmalıdır.', + 'timezone' => ':attribute geçerli bir alan olmalıdır.', + 'unique' => ':attribute daha önce alınmış.', + 'url' => ':attribute formatı geçerli değil.', + 'uploaded' => 'Dosya yüklemesi başarısız oldu. Server bu boyutta dosyaları kabul etmiyor olabilir.', + + // Custom validation lines + 'custom' => [ + 'password-confirm' => [ + 'required_with' => 'Parola onayı gereklidir.', + ], + ], + + // Custom validation attributes + 'attributes' => [], +]; diff --git a/resources/lang/uk/activities.php b/resources/lang/uk/activities.php index 585f92269..900ccd2b8 100644 --- a/resources/lang/uk/activities.php +++ b/resources/lang/uk/activities.php @@ -1,7 +1,7 @@ 'Книгу успішно відновлено', // Bookshelves - 'bookshelf_create' => 'створено книжкову полицю', + 'bookshelf_create' => 'створив книжкову полицю', 'bookshelf_create_notification' => 'Книжкову полицю успішно створено', 'bookshelf_update' => 'оновив книжкову полицю', 'bookshelf_update_notification' => 'Книжкову полицю успішно оновлено', diff --git a/resources/lang/uk/auth.php b/resources/lang/uk/auth.php index cd73f92db..b8fcc06ad 100644 --- a/resources/lang/uk/auth.php +++ b/resources/lang/uk/auth.php @@ -1,8 +1,8 @@ 'Реєстрація', 'log_in' => 'Увійти', - 'log_in_with' => 'Увійти з :socialDriver', - 'sign_up_with' => 'Зареєструватись з :socialDriver', + 'log_in_with' => 'Увійти через :socialDriver', + 'sign_up_with' => 'Зареєструватися через :socialDriver', 'logout' => 'Вихід', 'name' => 'Ім\'я', 'username' => 'Логін', - 'email' => 'Email', + 'email' => 'Адреса електронної пошти', 'password' => 'Пароль', 'password_confirm' => 'Підтвердження пароля', - 'password_hint' => 'Має бути більше 5 символів', + 'password_hint' => 'Має бути більше ніж 7 символів', 'forgot_password' => 'Забули пароль?', - 'remember_me' => 'Запам’ятати мене', + 'remember_me' => 'Запам\'ятати мене', 'ldap_email_hint' => 'Введіть email для цього облікового запису.', 'create_account' => 'Створити обліковий запис', 'already_have_account' => 'Вже є обліковий запис?', 'dont_have_account' => 'Немає облікового запису?', 'social_login' => 'Вхід через соціальну мережу', 'social_registration' => 'Реєстрація через соціальну мережу', - 'social_registration_text' => 'Реєстрація і вхід через інший сервіс', + 'social_registration_text' => 'Реєстрація і вхід через інший сервіс.', 'register_thanks' => 'Дякуємо за реєстрацію!', 'register_confirm' => 'Будь ласка, перевірте свою електронну пошту та натисніть кнопку підтвердження, щоб отримати доступ до :appName.', @@ -42,7 +42,7 @@ return [ // Password Reset 'reset_password' => 'Скинути пароль', 'reset_password_send_instructions' => 'Введіть адресу електронної пошти нижче, і вам буде надіслано електронне повідомлення з посиланням на зміну пароля.', - 'reset_password_send_button' => 'Надіслати посилання для скидання', + 'reset_password_send_button' => 'Надіслати посилання для скидання пароля', 'reset_password_sent_success' => 'Посилання для скидання пароля було надіслано на :email.', 'reset_password_success' => 'Ваш пароль успішно скинуто.', 'email_reset_subject' => 'Скинути ваш пароль :appName', @@ -59,9 +59,19 @@ return [ 'email_confirm_success' => 'Ваш електронну адресу підтверджено!', 'email_confirm_resent' => 'Лист з підтвердженням надіслано, перевірте свою пошту.', - 'email_not_confirmed' => 'Адреса Email не підтверджена', + 'email_not_confirmed' => 'Адресу електронної скриньки не підтверджено', 'email_not_confirmed_text' => 'Ваша електронна адреса ще не підтверджена.', 'email_not_confirmed_click_link' => 'Будь-ласка, натисніть на посилання в електронному листі, яке було надіслано після реєстрації.', 'email_not_confirmed_resend' => 'Якщо ви не можете знайти електронний лист, ви можете повторно надіслати підтвердження електронною поштою, на формі нижче.', 'email_not_confirmed_resend_button' => 'Повторне підтвердження електронної пошти', -]; + + // User Invite + 'user_invite_email_subject' => 'Вас запросили приєднатися до :appName!', + 'user_invite_email_greeting' => 'Для вас створено обліковий запис на :appName.', + 'user_invite_email_text' => 'Натисніть кнопку нижче, щоб встановити пароль облікового запису та отримати доступ:', + 'user_invite_email_action' => 'Встановити пароль облікового запису', + 'user_invite_page_welcome' => 'Ласкаво просимо до :appName!', + 'user_invite_page_text' => 'Для завершення процесу створення облікового запису та отримання доступу вам потрібно задати пароль, який буде використовуватися для входу в :appName в майбутньому.', + 'user_invite_page_confirm_button' => 'Підтвердити пароль', + 'user_invite_success' => 'Встановлено пароль, тепер у вас є доступ до :appName!' +]; \ No newline at end of file diff --git a/resources/lang/uk/common.php b/resources/lang/uk/common.php index 552f32e11..214fbcb4e 100644 --- a/resources/lang/uk/common.php +++ b/resources/lang/uk/common.php @@ -1,6 +1,6 @@ 'Скинути', 'remove' => 'Видалити', 'add' => 'Додати', - + 'fullscreen' => 'Fullscreen', + // Sort Options + 'sort_options' => 'Параметри сортування', + 'sort_direction_toggle' => 'Перемикач напрямку сортування', + 'sort_ascending' => 'За зростанням', + 'sort_descending' => 'За спаданням', 'sort_name' => 'Ім\'я', 'sort_created_at' => 'Дата створення', 'sort_updated_at' => 'Дата оновлення', @@ -55,11 +60,13 @@ return [ 'grid_view' => 'Вигляд Сіткою', 'list_view' => 'Вигляд Списком', 'default' => 'За замовчуванням', + 'breadcrumb' => 'Навігація', // Header + 'profile_menu' => 'Меню профілю', 'view_profile' => 'Переглянути профіль', 'edit_profile' => 'Редагувати профіль', - + // Layout tabs 'tab_info' => 'Інфо', 'tab_content' => 'Вміст', diff --git a/resources/lang/uk/components.php b/resources/lang/uk/components.php index 937774ad0..0cd7e8804 100644 --- a/resources/lang/uk/components.php +++ b/resources/lang/uk/components.php @@ -1,6 +1,6 @@ 'Ви впевнені, що хочете видалити цю сторінку?', 'pages_delete_draft_confirm' => 'Ви впевнені, що хочете видалити цю чернетку?', 'pages_editing_named' => 'Редагування сторінки :pageName', - 'pages_edit_toggle_header' => 'Переключити заголовок', + 'pages_edit_draft_options' => 'Параметри чернетки', 'pages_edit_save_draft' => 'Зберегти чернетку', 'pages_edit_draft' => 'Редагувати чернетку сторінки', 'pages_editing_draft' => 'Редагування чернетки', 'pages_editing_page' => 'Редагування сторінки', - 'pages_edit_draft_save_at' => 'Чернетку зберегти в ', + 'pages_edit_draft_save_at' => 'Чернетка збережена о ', 'pages_edit_delete_draft' => 'Видалити чернетку', 'pages_edit_discard_draft' => 'Відхилити чернетку', 'pages_edit_set_changelog' => 'Встановити журнал змін', @@ -234,6 +234,7 @@ return [ ], 'pages_draft_discarded' => 'Чернетка відхилена, редактор оновлено з поточним вмістом сторінки', 'pages_specific' => 'Конкретна сторінка', + 'pages_is_template' => 'Шаблон сторінки', // Editor Sidebar 'page_tags' => 'Теги сторінки', @@ -242,9 +243,11 @@ return [ 'shelf_tags' => 'Теги полиць', 'tag' => 'Тег', 'tags' => 'Теги', + 'tag_name' => 'Назва тегу', 'tag_value' => 'Значення тегу (необов\'язково)', 'tags_explain' => "Додайте кілька тегів, щоб краще класифікувати ваш вміст. \n Ви можете присвоїти значення тегу для більш глибокої організації.", 'tags_add' => 'Додати ще один тег', + 'tags_remove' => 'Видалити цей тег', 'attachments' => 'Вкладення', 'attachments_explain' => 'Завантажте файли, або додайте посилання, які відображатимуться на вашій сторінці. Їх буде видно на бічній панелі сторінки.', 'attachments_explain_instant_save' => 'Зміни тут зберігаються миттєво.', @@ -270,6 +273,12 @@ return [ 'attachments_file_uploaded' => 'Файл успішно завантажений', 'attachments_file_updated' => 'Файл успішно оновлено', 'attachments_link_attached' => 'Посилання успішно додано до сторінки', + 'templates' => 'Шаблони', + 'templates_set_as_template' => 'Сторінка це шаблон', + 'templates_explain_set_as_template' => 'Ви можете встановити цю сторінку як шаблон, щоб її вміст використовувався під час створення інших сторінок. Інші користувачі зможуть користуватися цим шаблоном, якщо вони мають права перегляду для цієї сторінки.', + 'templates_replace_content' => 'Замінити вміст сторінки', + 'templates_append_content' => 'Додати до вмісту сторінки', + 'templates_prepend_content' => 'Додати на початок вмісту сторінки', // Profile View 'profile_user_for_x' => 'Користувач вже :time', @@ -302,4 +311,4 @@ return [ 'revision_restore_confirm' => 'Дійсно відновити цю версію? Вміст поточної сторінки буде замінено.', 'revision_delete_success' => 'Версія видалена', 'revision_cannot_delete_latest' => 'Неможливо видалити останню версію.' -]; +]; \ No newline at end of file diff --git a/resources/lang/uk/errors.php b/resources/lang/uk/errors.php index f41a59faf..a62911673 100644 --- a/resources/lang/uk/errors.php +++ b/resources/lang/uk/errors.php @@ -1,6 +1,6 @@ 'Електронна пошта вже підтверджена, спробуйте увійти.', 'email_confirmation_invalid' => 'Цей токен підтвердження недійсний або вже був використаний, будь ласка, спробуйте знову зареєструватися.', 'email_confirmation_expired' => 'Термін дії токена підтвердження минув, новий електронний лист підтвердження був відправлений.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'LDAP-доступ невдалий, з використання анонімного зв\'язку', 'ldap_fail_authed' => 'LDAP-доступ невдалий, використовуючи задані параметри dn та password', 'ldap_extension_not_installed' => 'Розширення PHP LDAP не встановлено', 'ldap_cannot_connect' => 'Неможливо підключитися до ldap-сервера, Помилка з\'єднання', + 'saml_already_logged_in' => 'Вже увійшли', + 'saml_user_not_registered' => 'Користувач «:name» не зареєстрований, а автоматична реєстрація вимкнена', + 'saml_no_email_address' => 'Не вдалося знайти електронну адресу для цього користувача у даних, наданих зовнішньою системою аутентифікації', + 'saml_invalid_response_id' => 'Запит із зовнішньої системи аутентифікації не розпізнається процесом, розпочатим цим додатком. Повернення назад після входу могла спричинити цю проблему.', + 'saml_fail_authed' => 'Вхід із використанням «:system» не вдався, система не здійснила успішну авторизацію', 'social_no_action_defined' => 'Жодних дій не визначено', 'social_login_bad_response' => "Помилка, отримана під час входу з :socialAccount помилка : \n:error", 'social_account_in_use' => 'Цей :socialAccount обліковий запис вже використовується, спробуйте ввійти з параметрами :socialAccount.', @@ -27,6 +33,7 @@ return [ 'social_account_register_instructions' => 'Якщо у вас ще немає облікового запису, ви можете зареєструвати обліковий запис за допомогою параметра :socialAccount.', 'social_driver_not_found' => 'Драйвер для СоціальноїМережі не знайдено', 'social_driver_not_configured' => 'Ваші соціальні настройки :socialAccount не правильно налаштовані.', + 'invite_token_expired' => 'Термін дії цього запрошення закінчився. Замість цього ви можете спробувати скинути пароль свого облікового запису.', // System 'path_not_writable' => 'Не вдається завантажити шлях до файлу :filePath. Переконайтеся, що він доступний для запису на сервер.', @@ -81,4 +88,12 @@ return [ 'app_down' => ':appName зараз недоступний', 'back_soon' => 'Він повернеться найближчим часом.', + // 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', + ]; diff --git a/resources/lang/uk/pagination.php b/resources/lang/uk/pagination.php index 4f81e6cd1..364a29e11 100644 --- a/resources/lang/uk/pagination.php +++ b/resources/lang/uk/pagination.php @@ -1,8 +1,8 @@ 'Паролі повинні містити принаймні шість символів і відповідати підтвердженню.', + 'password' => 'Пароль повинен містити не менше восьми символів і збігатись з підтвердженням.', 'user' => "Ми не можемо знайти користувача з цією адресою електронної пошти.", 'token' => 'Цей токен для скидання пароля недійсний.', - 'sent' => 'Ми надіслали вам електронний лист із посиланням на скидання пароля!', - 'reset' => 'Ваш пароль був скинутий!', + 'sent' => 'Ми надіслали Вам електронний лист із посиланням для скидання пароля!', + 'reset' => 'Ваш пароль скинуто!', ]; diff --git a/resources/lang/uk/settings.php b/resources/lang/uk/settings.php index 801bf8074..a41dc0d36 100644 --- a/resources/lang/uk/settings.php +++ b/resources/lang/uk/settings.php @@ -1,8 +1,8 @@ 'Виберіть, який редактор буде використовуватися всіма користувачами для редагування сторінок.', 'app_custom_html' => 'Користувацький вміст HTML-заголовку', 'app_custom_html_desc' => 'Будь-який доданий тут вміст буде вставлено в нижню частину розділу кожної сторінки. Це зручно для перевизначення стилів, або додавання коду аналітики.', + 'app_custom_html_disabled_notice' => 'На цій сторінці налаштувань відключений користувацький вміст заголовка HTML, щоб гарантувати, що будь-які невдалі зміни можна буде відновити.', 'app_logo' => 'Логотип програми', 'app_logo_desc' => 'Це зображення має бути висотою 43px.
Великі зображення будуть зменшені.', 'app_primary_color' => 'Основний колір програми', @@ -40,12 +41,22 @@ return [ 'app_disable_comments_toggle' => 'Вимкнути коментарі', 'app_disable_comments_desc' => 'Вимкнути коментарі на всіх сторінках програми. Існуючі коментарі не відображаються.', + // Color settings + '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' => 'Колір полиці', + 'book_color' => 'Колір книги', + 'chapter_color' => 'Chapter Color', + 'page_color' => 'Колір сторінки', + 'page_draft_color' => 'Колір чернетки', + // Registration Settings 'reg_settings' => 'Реєстрація', 'reg_enable' => 'Дозволити реєстрацію', '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_email_confirmation' => 'Підтвердження електронною поштою', 'reg_email_confirmation_toggle' => 'Необхідне підтвердження електронною поштою', 'reg_confirm_email_desc' => 'Якщо використовується обмеження домену, то підтвердження електронною поштою буде потрібно, а нижче значення буде проігноровано.', @@ -62,6 +73,13 @@ return [ 'maint_image_cleanup_warning' => ':count потенційно невикористаних зображень було знайдено. Ви впевнені, що хочете видалити ці зображення?', 'maint_image_cleanup_success' => ':count потенційно невикористані зображення знайдено і видалено!', 'maint_image_cleanup_nothing_found' => 'Не знайдено невикористовуваних зображень, нічого не видалено!', + 'maint_send_test_email' => 'Надіслати тестове повідомлення', + 'maint_send_test_email_desc' => 'Надіслати тестового листа на адресу електронної пошти, що вказана у вашому профілі.', + 'maint_send_test_email_run' => 'Надіслати тестовий лист', + 'maint_send_test_email_success' => 'Лист відправлений на : адреса', + 'maint_send_test_email_mail_subject' => 'Перевірка електронної пошти', + 'maint_send_test_email_mail_greeting' => 'Доставляння електронної пошти працює!', + 'maint_send_test_email_mail_text' => 'Вітаємо! Оскільки ви отримали цього листа, поштова скринька налаштована правильно.', // Role Settings 'roles' => 'Ролі', @@ -84,6 +102,8 @@ return [ 'role_manage_roles' => 'Керування правами ролей та ролями', 'role_manage_entity_permissions' => 'Керування всіма правами на книги, розділи та сторінки', 'role_manage_own_entity_permissions' => 'Керування дозволами на власну книгу, розділ та сторінки', + 'role_manage_page_templates' => 'Управління шаблонами сторінок', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Керування налаштуваннями програми', 'role_asset' => 'Дозволи', 'role_asset_desc' => 'Ці дозволи контролюють стандартні доступи всередині системи. Права на книги, розділи та сторінки перевизначать ці дозволи.', @@ -108,8 +128,10 @@ return [ 'users_role_desc' => 'Виберіть, до яких ролей буде призначено цього користувача. Якщо користувачеві призначено декілька ролей, дозволи з цих ролей будуть складатись і вони отримуватимуть усі можливості призначених ролей.', 'users_password' => 'Пароль користувача', 'users_password_desc' => 'Встановіть пароль для входу. Він повинен містити принаймні 5 символів.', + 'users_send_invite_text' => 'Ви можете надіслати цьому користувачеві лист із запрошенням, що дозволить йому встановити пароль власноруч, або ви можете встановити йому пароль самостійно.', + 'users_send_invite_option' => 'Надіслати листа із запрошенням користувачу', 'users_external_auth_id' => 'Зовнішній ID автентифікації', - 'users_external_auth_id_desc' => 'Цей ID використовується для пошуку збігу цього користувача під час зв\'язку з LDAP.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Тільки якщо ви хочете змінити свій пароль, заповніть поля нижче:', 'users_system_public' => 'Цей користувач представляє будь-яких гостьових користувачів, які відвідують ваш екземпляр. Його не можна використовувати для входу, але він призначається автоматично.', 'users_delete' => 'Видалити користувача', @@ -130,5 +152,60 @@ 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', + // 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' => 'العربية', + 'da' => 'Dansk', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// ]; diff --git a/resources/lang/uk/validation.php b/resources/lang/uk/validation.php index 523126382..47f15fe7f 100644 --- a/resources/lang/uk/validation.php +++ b/resources/lang/uk/validation.php @@ -1,76 +1,105 @@ ':attribute повинен бути прийнятий.', - 'active_url' => ':attribute не є дійсною URL-адресою.', - 'after' => ':attribute повинно бути датою після :date.', - 'alpha' => ':attribute може містити лише літери.', - 'alpha_dash' => ':attribute може містити лише літери, цифри та дефіси.', - 'alpha_num' => ':attribute може містити лише літери та цифри.', - 'array' => ':attribute повинен бути масивом.', - 'before' => ':attribute повинен бути датою до :date.', + 'accepted' => 'Ви повинні прийняти :attribute.', + 'active_url' => 'Поле :attribute не є правильним URL.', + 'after' => 'Поле :attribute має містити дату не раніше :date.', + 'alpha' => 'Поле :attribute має містити лише літери.', + 'alpha_dash' => 'Поле :attribute має містити лише літери, цифри, дефіси та підкреслення.', + 'alpha_num' => 'Поле :attribute має містити лише літери та цифри.', + 'array' => 'Поле :attribute має бути масивом.', + 'before' => 'Поле :attribute має містити дату не пізніше :date.', 'between' => [ - 'numeric' => ':attribute повинен бути між :min та :max.', - 'file' => ':attribute повинен бути між :min та :max кілобайт.', - 'string' => ':attribute повинен бути між :min та :max символів.', - 'array' => ':attribute повинен бути між :min та :max елементів.', + 'numeric' => 'Поле :attribute має бути між :min та :max.', + 'file' => 'Розмір файлу в полі :attribute має бути не менше :min та не більше :max кілобайт.', + 'string' => 'Текст в полі :attribute має бути не менше :min та не більше :max символів.', + 'array' => 'Поле :attribute має містити від :min до :max елементів.', + ], + 'boolean' => 'Поле :attribute повинне містити true чи false.', + 'confirmed' => 'Поле :attribute не збігається з підтвердженням.', + 'date' => 'Поле :attribute не є датою.', + 'date_format' => 'Поле :attribute не відповідає формату :format.', + 'different' => 'Поля :attribute та :other повинні бути різними.', + 'digits' => 'Довжина цифрового поля :attribute повинна дорівнювати :digits.', + 'digits_between' => 'Довжина цифрового поля :attribute повинна бути від :min до :max.', + 'email' => 'Поле :attribute повинне містити коректну електронну адресу.', + 'ends_with' => 'Поле :attribute має закінчуватися одним з наступних значень: :values', + 'filled' => 'Поле :attribute є обов\'язковим для заповнення.', + 'gt' => [ + 'numeric' => 'Поле :attribute має бути більше ніж :value.', + 'file' => 'Поле :attribute має бути більше ніж :value кілобайт.', + 'string' => 'Поле :attribute має бути більше ніж :value символів.', + 'array' => 'Поле :attribute має містити більше ніж :value елементів.', + ], + 'gte' => [ + 'numeric' => 'Поле :attribute має дорівнювати чи бути більше ніж :value.', + 'file' => 'Поле :attribute має дорівнювати чи бути більше ніж :value кілобайт.', + 'string' => 'Поле :attribute має дорівнювати чи бути більше ніж :value символів.', + 'array' => 'Поле :attribute має містити :value чи більше елементів.', + ], + 'exists' => 'Вибране для :attribute значення не коректне.', + 'image' => 'Поле :attribute має містити зображення.', + 'image_extension' => 'Поле :attribute має містити дійсне та підтримуване розширення зображення.', + 'in' => 'Вибране для :attribute значення не коректне.', + 'integer' => 'Поле :attribute має містити ціле число.', + 'ip' => 'Поле :attribute має містити IP адресу.', + 'ipv4' => 'Поле :attribute має містити IPv4 адресу.', + 'ipv6' => 'Поле :attribute має містити IPv6 адресу.', + 'json' => 'Дані поля :attribute мають бути в форматі JSON.', + 'lt' => [ + 'numeric' => 'Поле :attribute має бути менше ніж :value.', + 'file' => 'Поле :attribute має бути менше ніж :value кілобайт.', + 'string' => 'Поле :attribute має бути менше ніж :value символів.', + 'array' => 'Поле :attribute має містити менше ніж :value елементів.', + ], + 'lte' => [ + 'numeric' => 'Поле :attribute має дорівнювати чи бути менше ніж :value.', + 'file' => 'Поле :attribute має дорівнювати чи бути менше ніж :value кілобайт.', + 'string' => 'Поле :attribute має дорівнювати чи бути менше ніж :value символів.', + 'array' => 'Поле :attribute має містити не більше ніж :value елементів.', ], - 'boolean' => ':attribute поле має бути true або false.', - 'confirmed' => ':attribute підтвердження не збігається.', - 'date' => ':attribute не є дійсною датою.', - 'date_format' => ':attribute не відповідає формату :format.', - 'different' => ':attribute та :other повинні бути різними.', - 'digits' => ':attribute повинні бути :digits цифрами.', - 'digits_between' => ':attribute має бути між :min та :max цифр.', - 'email' => ':attribute повинна бути дійсною електронною адресою.', - 'filled' => ':attribute поле обов\'язкове.', - 'exists' => 'Вибраний :attribute недійсний.', - 'image' => ':attribute повинен бути зображенням.', - 'image_extension' => ':attribute повинен мати дійсне та підтримуване розширення зображення.', - 'in' => 'Вибраний :attribute недійсний.', - 'integer' => ':attribute повинен бути цілим числом.', - 'ip' => ':attribute повинна бути дійсною IP-адресою.', 'max' => [ - 'numeric' => ':attribute не може бути більшим за :max.', - 'file' => ':attribute не може бути більшим за :max кілобайт.', - 'string' => ':attribute не може бути більшим за :max символів.', - 'array' => ':attribute не може бути більше ніж :max елементів.', + 'numeric' => 'Поле :attribute має бути не більше :max.', + 'file' => 'Файл в полі :attribute має бути не більше :max кілобайт.', + 'string' => 'Текст в полі :attribute повинен мати довжину не більшу за :max.', + 'array' => 'Поле :attribute повинне містити не більше :max елементів.', ], - 'mimes' => ':attribute повинен бути файлом типу: :values.', + 'mimes' => 'Поле :attribute повинне містити файл одного з типів: :values.', 'min' => [ - 'numeric' => ':attribute повинен бути принаймні :min.', - 'file' => ':attribute повинен бути принаймні :min кілобайт.', - 'string' => ':attribute повинен бути принаймні :min символів.', - 'array' => ':attribute повинен містити принаймні :min елементів.', + 'numeric' => 'Поле :attribute повинне бути не менше :min.', + 'file' => 'Розмір файлу в полі :attribute має бути не меншим :min кілобайт.', + 'string' => 'Текст в полі :attribute повинен містити не менше :min символів.', + 'array' => 'Поле :attribute повинне містити не менше :min елементів.', ], - 'no_double_extension' => ':attribute повинен мати тільки одне розширення файлу.', - 'not_in' => 'Вибраний :attribute недійсний.', - 'numeric' => ':attribute повинен бути числом.', - 'regex' => ':attribute формат недійсний.', - 'required' => ':attribute поле обов\'язкове.', - 'required_if' => ':attribute поле бов\'язкове, коли :other з значенням :value.', - 'required_with' => ':attribute поле бов\'язкове, коли :values встановлено.', - 'required_with_all' => ':attribute поле бов\'язкове, коли :values встановлені.', - 'required_without' => ':attribute поле бов\'язкове, коли :values не встановлені.', - 'required_without_all' => ':attribute поле бов\'язкове, коли жодне з :values не встановлене.', - 'same' => ':attribute та :other мають збігатись.', + 'no_double_extension' => 'Поле :attribute повинне містити тільки одне розширення файлу.', + 'not_in' => 'Вибране для :attribute значення не коректне.', + 'not_regex' => 'Формат поля :attribute не вірний.', + 'numeric' => 'Поле :attribute повинно містити число.', + 'regex' => 'Поле :attribute має хибний формат.', + 'required' => 'Поле :attribute є обов\'язковим для заповнення.', + 'required_if' => 'Поле :attribute є обов\'язковим для заповнення, коли :other є рівним :value.', + 'required_with' => 'Поле :attribute є обов\'язковим для заповнення, коли :values вказано.', + 'required_with_all' => 'Поле :attribute є обов\'язковим для заповнення, коли :values вказано.', + 'required_without' => 'Поле :attribute є обов\'язковим для заповнення, коли :values не вказано.', + 'required_without_all' => 'Поле :attribute є обов\'язковим для заповнення, коли :values не вказано.', + 'same' => 'Поля :attribute та :other мають збігатися.', 'size' => [ - 'numeric' => ':attribute має бути :size.', - 'file' => ':attribute має бути :size кілобайт.', - 'string' => ':attribute має бути :size символів.', - 'array' => ':attribute має містити :size елементів.', + 'numeric' => 'Поле :attribute має бути довжини :size.', + 'file' => 'Файл в полі :attribute має бути розміром :size кілобайт.', + 'string' => 'Текст в полі :attribute повинен містити :size символів.', + 'array' => 'Поле :attribute повинне містити :size елементів.', ], - 'string' => ':attribute повинен бути рядком.', - 'timezone' => ':attribute повинен бути дійсною зоною.', - 'unique' => ':attribute вже є.', - 'url' => ':attribute формат недійсний.', + 'string' => 'Поле :attribute повинне містити текст.', + 'timezone' => 'Поле :attribute повинне містити коректну часову зону.', + 'unique' => 'Вказане значення поля :attribute вже існує.', + 'url' => 'Формат поля :attribute неправильний.', 'uploaded' => 'Не вдалося завантажити файл. Сервер може не приймати файли такого розміру.', // Custom validation lines diff --git a/resources/lang/zh_CN/activities.php b/resources/lang/zh_CN/activities.php index 7198710ef..676a1dd92 100644 --- a/resources/lang/zh_CN/activities.php +++ b/resources/lang/zh_CN/activities.php @@ -1,12 +1,10 @@ '创建了页面', 'page_create_notification' => '页面已创建成功', @@ -36,7 +34,7 @@ return [ 'book_delete_notification' => '图书已删除成功', 'book_sort' => '排序了图书', 'book_sort_notification' => '图书已重新排序成功', - + // Bookshelves 'bookshelf_create' => '创建了书架', 'bookshelf_create_notification' => '书架已成功创建', diff --git a/resources/lang/zh_CN/auth.php b/resources/lang/zh_CN/auth.php index 046f2360b..0eec01508 100644 --- a/resources/lang/zh_CN/auth.php +++ b/resources/lang/zh_CN/auth.php @@ -1,21 +1,15 @@ '用户名或密码错误。', 'throttle' => '您的登录次数过多,请在:seconds秒后重试。', - /** - * Login & Register - */ + // Login & Register 'sign_up' => '注册', 'log_in' => '登录', 'log_in_with' => '以:socialDriver登录', @@ -27,14 +21,16 @@ return [ 'email' => 'Email地址', 'password' => '密码', 'password_confirm' => '确认密码', - 'password_hint' => '必须超过5个字符', + 'password_hint' => '必须超过7个字符', 'forgot_password' => '忘记密码?', 'remember_me' => '记住我', 'ldap_email_hint' => '请输入用于此帐户的电子邮件。', 'create_account' => '创建账户', + 'already_have_account' => '您已经有账号?', + 'dont_have_account' => '您还没注册?', 'social_login' => 'SNS登录', 'social_registration' => 'SNS注册', - 'social_registration_text' => '其他服务注册/登录.', + 'social_registration_text' => '其他服务注册/登录。', 'register_thanks' => '注册完成!', 'register_confirm' => '请点击查收您的Email,并点击确认。', @@ -43,23 +39,18 @@ return [ 'register_success' => '感谢您注册:appName,您现在已经登录。', - /** - * Password Reset - */ + // Password Reset 'reset_password' => '重置密码', 'reset_password_send_instructions' => '在下面输入您的Email地址,您将收到一封带有密码重置链接的邮件。', 'reset_password_send_button' => '发送重置链接', 'reset_password_sent_success' => '密码重置链接已发送到:email。', 'reset_password_success' => '您的密码已成功重置。', - 'email_reset_subject' => '重置您的:appName密码', 'email_reset_text' => '您收到此电子邮件是因为我们收到了您的帐户的密码重置请求。', 'email_reset_not_requested' => '如果您没有要求重置密码,则不需要采取进一步的操作。', - /** - * Email Confirmation - */ + // Email Confirmation 'email_confirm_subject' => '确认您在:appName的Email地址', 'email_confirm_greeting' => '感谢您加入:appName!', 'email_confirm_text' => '请点击下面的按钮确认您的Email地址:', @@ -73,4 +64,14 @@ return [ 'email_not_confirmed_click_link' => '请检查注册时收到的电子邮件,然后点击确认链接。', 'email_not_confirmed_resend' => '如果找不到电子邮件,请通过下面的表单重新发送确认Email。', 'email_not_confirmed_resend_button' => '重新发送确认Email', + + // User Invite + 'user_invite_email_subject' => '您已受邀加入 :appName!', + 'user_invite_email_greeting' => ' :appName 已为您创建了一个帐户。', + 'user_invite_email_text' => '点击下面的按钮以设置帐户密码并获得访问权限:', + 'user_invite_email_action' => '设置帐号密码', + 'user_invite_page_welcome' => '欢迎来到 :appName!', + 'user_invite_page_text' => '要完成您的帐户并获得访问权限,您需要设置一个密码,该密码将在以后访问时用于登录 :appName。', + 'user_invite_page_confirm_button' => '确认密码', + 'user_invite_success' => '已设置密码,您现在可以访问 :appName!' ]; \ No newline at end of file diff --git a/resources/lang/zh_CN/common.php b/resources/lang/zh_CN/common.php index cf914983e..c21e8029d 100644 --- a/resources/lang/zh_CN/common.php +++ b/resources/lang/zh_CN/common.php @@ -1,37 +1,36 @@ '取消', 'confirm' => '确认', 'back' => '返回', 'save' => '保存', 'continue' => '继续', 'select' => '选择', + 'toggle_all' => '切换全部', 'more' => '更多', - /** - * Form Labels - */ + // Form Labels 'name' => '名称', 'description' => '概要', 'role' => '角色', 'cover_image' => '封面图片', 'cover_image_description' => '该图像大小需要为440x250px。', - /** - * Actions - */ + // Actions 'actions' => '操作', 'view' => '浏览', + 'view_all' => '查看全部', 'create' => '创建', 'update' => '更新', 'edit' => '编辑', 'sort' => '排序', 'move' => '移动', - 'copy' => '复制', + 'copy' => '复制', 'reply' => '回复', 'delete' => '删除', 'search' => '搜索', @@ -39,10 +38,18 @@ return [ 'reset' => '重置', 'remove' => '删除', 'add' => '添加', + 'fullscreen' => '全屏', - /** - * Misc - */ + // Sort Options + 'sort_options' => '排序选项', + 'sort_direction_toggle' => '排序方向切换', + 'sort_ascending' => '升序', + 'sort_descending' => '降序', + 'sort_name' => '名称', + 'sort_created_at' => '创建时间', + 'sort_updated_at' => '更新时间', + + // Misc 'deleted_user' => '删除用户', 'no_activity' => '没有活动要显示', 'no_items' => '没有可用的项目', @@ -53,16 +60,18 @@ return [ 'grid_view' => '网格视图', 'list_view' => '列表视图', 'default' => '默认', - - /** - * Header - */ + 'breadcrumb' => '面包屑导航', + + // Header + 'profile_menu' => '个人资料', 'view_profile' => '查看资料', 'edit_profile' => '编辑资料', - /** - * Email Content - */ + // Layout tabs + 'tab_info' => '信息', + 'tab_content' => '内容', + + // Email Content 'email_action_help' => '如果您无法点击“:actionText”按钮,请将下面的网址复制到您的浏览器中打开:', - 'email_rights' => 'All rights reserved', + 'email_rights' => '版权所有', ]; diff --git a/resources/lang/zh_CN/components.php b/resources/lang/zh_CN/components.php index e8cad3c30..54d0fb085 100644 --- a/resources/lang/zh_CN/components.php +++ b/resources/lang/zh_CN/components.php @@ -1,9 +1,10 @@ '选择图片', 'image_all' => '全部', 'image_all_title' => '查看所有图片', @@ -24,9 +25,7 @@ return [ 'image_delete_success' => '图片删除成功', 'image_upload_remove' => '去掉', - /** - * Code editor - */ + // Code Editor 'code_editor' => '编辑代码', 'code_language' => '编程语言', 'code_content' => '代码内容', diff --git a/resources/lang/zh_CN/entities.php b/resources/lang/zh_CN/entities.php index 64a205444..5c614b079 100644 --- a/resources/lang/zh_CN/entities.php +++ b/resources/lang/zh_CN/entities.php @@ -1,14 +1,17 @@ '最近创建', 'recently_created_pages' => '最近创建的页面', - 'recently_updated_pages' => '最新页面', + 'recently_updated_pages' => '最近更新的页面', 'recently_created_chapters' => '最近创建的章节', 'recently_created_books' => '最近创建的图书', + 'recently_created_shelves' => '最近创建的书架', 'recently_update' => '最近更新', 'recently_viewed' => '最近查看', 'recent_activity' => '近期活动', @@ -31,17 +34,13 @@ return [ 'export_pdf' => 'PDF文件', 'export_text' => '纯文本文件', - /** - * Permissions and restrictions - */ + // Permissions and restrictions 'permissions' => '权限', 'permissions_intro' => '本设置优先于每个用户角色本身所具有的权限。', 'permissions_enable' => '启用自定义权限', 'permissions_save' => '保存权限', - /** - * Search - */ + // Search 'search_results' => '搜索结果', 'search_total_results_found' => '共找到了:count个结果', 'search_clear' => '清除搜索', @@ -66,16 +65,16 @@ return [ 'search_set_date' => '设置日期', 'search_update' => '只显示更新操作', - /** - * Shelves - */ + // Shelves 'shelf' => '书架', 'shelves' => '书架', + 'x_shelves' => ':count 书架|:count 书架', 'shelves_long' => '书架', 'shelves_empty' => '当前未创建书架', 'shelves_create' => '创建新书架', 'shelves_popular' => '热门书架', 'shelves_new' => '新书架', + 'shelves_new_action' => '新书架', 'shelves_popular_empty' => '最热门的书架', 'shelves_new_empty' => '最新创建的书架', 'shelves_save' => '保存书架', @@ -98,9 +97,7 @@ return [ 'shelves_copy_permissions_explain' => '这会将此书架的当前权限设置应用于其中包含的所有图书。 在激活之前,请确保已保存对此书架权限的任何更改。', 'shelves_copy_permission_success' => '书架权限复制到图书 :count ', - /** - * Books - */ + // Books 'book' => '图书', 'books' => '图书', 'x_books' => ':count本书', @@ -108,6 +105,7 @@ return [ 'books_popular' => '热门图书', 'books_recent' => '最近的书', 'books_new' => '新书', + 'books_new_action' => '新书', 'books_popular_empty' => '最受欢迎的图书将出现在这里。', 'books_new_empty' => '最近创建的图书将出现在这里。', 'books_create' => '创建图书', @@ -123,7 +121,6 @@ return [ 'books_permissions_updated' => '图书权限已更新', 'books_empty_contents' => '本书目前没有页面或章节。', 'books_empty_create_page' => '创建页面', - 'books_empty_or' => '或', 'books_empty_sort_current_book' => '排序当前图书', 'books_empty_add_chapter' => '添加章节', 'books_permissions_active' => '有效的图书权限', @@ -131,12 +128,15 @@ return [ 'books_navigation' => '图书导航', 'books_sort' => '排序图书内容', 'books_sort_named' => '排序图书「:bookName」', + 'books_sort_name' => '按名称排序', + 'books_sort_created' => '创建时间排序', + 'books_sort_updated' => '按更新时间排序', + 'books_sort_chapters_first' => '章节正序', + 'books_sort_chapters_last' => '章节倒序', 'books_sort_show_other' => '显示其他图书', 'books_sort_save' => '保存新顺序', - /** - * Chapters - */ + // Chapters 'chapter' => '章节', 'chapters' => '章节', 'x_chapters' => ':count个章节', @@ -159,9 +159,7 @@ return [ 'chapters_permissions_success' => '章节权限已更新', 'chapters_search_this' => '从本章节搜索', - /** - * Pages - */ + // Pages 'page' => '页面', 'pages' => '页面', 'x_pages' => ':count个页面', @@ -178,7 +176,7 @@ return [ 'pages_delete_confirm' => '您确定要删除此页面吗?', 'pages_delete_draft_confirm' => '您确定要删除此草稿页面吗?', 'pages_editing_named' => '正在编辑页面“:pageName”', - 'pages_edit_toggle_header' => '显示/隐藏导航栏', + 'pages_edit_draft_options' => '草稿选项', 'pages_edit_save_draft' => '保存草稿', 'pages_edit_draft' => '编辑页面草稿', 'pages_editing_draft' => '正在编辑草稿', @@ -196,11 +194,11 @@ return [ 'pages_md_preview' => '预览', 'pages_md_insert_image' => '插入图片', 'pages_md_insert_link' => '插入实体链接', - 'pages_md_insert_drawing' => '插入图表', + 'pages_md_insert_drawing' => '插入图表', 'pages_not_in_chapter' => '本页面不在某章节中', 'pages_move' => '移动页面', 'pages_move_success' => '页面已移动到「:parentName」', - 'pages_copy' => '复制页面', + 'pages_copy' => '复制页面', 'pages_copy_desination' => '复制目的地', 'pages_copy_success' => '页面复制完成', 'pages_permissions' => '页面权限', @@ -212,6 +210,8 @@ return [ 'pages_revisions_created_by' => '创建者', 'pages_revisions_date' => '修订日期', 'pages_revisions_number' => '#', + 'pages_revisions_numbered' => '修订 #:id', + 'pages_revisions_numbered_changes' => '修改 #:id ', 'pages_revisions_changelog' => '更新说明', 'pages_revisions_changes' => '说明', 'pages_revisions_current' => '当前版本', @@ -233,30 +233,31 @@ return [ 'message' => ':time,:start。注意不要覆盖对方的更新!', ], 'pages_draft_discarded' => '草稿已丢弃,编辑器已更新到当前页面内容。', - 'pages_specific' => '具体页面', + 'pages_specific' => '具体页面', + 'pages_is_template' => '页面模板', - /** - * Editor sidebar - */ + // Editor Sidebar 'page_tags' => '页面标签', - 'chapter_tags' => '章节标签', - 'book_tags' => '图书标签', + 'chapter_tags' => '章节标签', + 'book_tags' => '图书标签', 'shelf_tags' => '书架标签', 'tag' => '标签', 'tags' => '标签', + 'tag_name' => '标签名称', 'tag_value' => '标签值 (Optional)', 'tags_explain' => "添加一些标签以更好地对您的内容进行分类。\n您可以为标签分配一个值,以进行更深入的组织。", 'tags_add' => '添加另一个标签', + 'tags_remove' => '删除此标签', 'attachments' => '附件', 'attachments_explain' => '上传一些文件或附加一些链接显示在您的网页上。这些在页面的侧边栏中可见。', - 'attachments_explain_instant_save' => '这里的更改将立即保存。Changes here are saved instantly.', + 'attachments_explain_instant_save' => '这里的更改将立即保存。', 'attachments_items' => '附加项目', 'attachments_upload' => '上传文件', 'attachments_link' => '附加链接', 'attachments_set_link' => '设置链接', 'attachments_delete_confirm' => '确认您想要删除此附件后,请点击删除。', 'attachments_dropzone' => '删除文件或点击此处添加文件', - 'attachments_no_files' => '尚未上传文件', // No files have been uploaded + 'attachments_no_files' => '尚未上传文件', 'attachments_explain_link' => '如果您不想上传文件,则可以附加链接,这可以是指向其他页面的链接,也可以是指向云端文件的链接。', 'attachments_link_name' => '链接名', 'attachment_link' => '附件链接', @@ -272,22 +273,25 @@ return [ 'attachments_file_uploaded' => '附件上传成功', 'attachments_file_updated' => '附件更新成功', 'attachments_link_attached' => '链接成功附加到页面', + 'templates' => '模板', + 'templates_set_as_template' => '设置为模板', + 'templates_explain_set_as_template' => '您可以将此页面设置为模板,以便在创建其他页面时利用其内容。 如果其他用户对此页面具有查看权限,则将可以使用此模板。', + 'templates_replace_content' => '替换页面内容', + 'templates_append_content' => '附加到页面内容', + 'templates_prepend_content' => '追加到页面内容', - /** - * Profile View - */ + // Profile View 'profile_user_for_x' => '来这里:time了', 'profile_created_content' => '已创建内容', 'profile_not_created_pages' => ':userName尚未创建任何页面', 'profile_not_created_chapters' => ':userName尚未创建任何章节', 'profile_not_created_books' => ':userName尚未创建任何图书', + 'profile_not_created_shelves' => ':userName 尚未创建任何书架', - /** - * Comments - */ + // Comments 'comment' => '评论', 'comments' => '评论', - 'comment_add' => '添加评论', + 'comment_add' => '添加评论', 'comment_placeholder' => '在这里评论', 'comment_count' => '{0} 无评论|[1,*] :count条评论', 'comment_save' => '保存评论', @@ -302,10 +306,9 @@ return [ 'comment_delete_confirm' => '你确定要删除这条评论?', 'comment_in_reply_to' => '回复 :commentId', - /** - * Revision - */ + // Revision 'revision_delete_confirm' => '您确定要删除此修订版吗?', + 'revision_restore_confirm' => '您确定要恢复到此修订版吗?恢复后原有内容将会被替换。', 'revision_delete_success' => '修订删除', 'revision_cannot_delete_latest' => '无法删除最新版本。' -]; +]; \ No newline at end of file diff --git a/resources/lang/zh_CN/errors.php b/resources/lang/zh_CN/errors.php index aa1c648d4..465592b6f 100644 --- a/resources/lang/zh_CN/errors.php +++ b/resources/lang/zh_CN/errors.php @@ -1,11 +1,9 @@ '您无权访问所请求的页面。', 'permissionJson' => '您无权执行所请求的操作。', @@ -15,10 +13,16 @@ return [ 'email_already_confirmed' => 'Email已被确认,请尝试登录。', 'email_confirmation_invalid' => '此确认令牌无效或已被使用,请重新注册。', 'email_confirmation_expired' => '确认令牌已过期,已发送新的确认电子邮件。', + 'email_confirmation_awaiting' => '需要认证账户的电子邮箱地址', 'ldap_fail_anonymous' => '使用匿名绑定的LDAP访问失败。', 'ldap_fail_authed' => '带有标识名称和密码的LDAP访问失败。', 'ldap_extension_not_installed' => '未安装LDAP PHP扩展程序', 'ldap_cannot_connect' => '无法连接到ldap服务器,初始连接失败', + 'saml_already_logged_in' => '您已经登陆了', + 'saml_user_not_registered' => '用户 :name 未注册且自动注册功能已被禁用', + 'saml_no_email_address' => '无法找到有效Email地址,此用户数据由外部身份验证系统托管', + 'saml_invalid_response_id' => '来自外部身份验证系统的请求没有被本应用程序认证,在登录后返回上一页可能会导致此问题。', + 'saml_fail_authed' => '使用 :system 登录失败,登录系统未返回成功登录授权信息。', 'social_no_action_defined' => '没有定义行为', 'social_login_bad_response' => "在 :socialAccount 登录时遇到错误:\n:error", 'social_account_in_use' => ':socialAccount 账户已被使用,请尝试通过 :socialAccount 选项登录。', @@ -29,20 +33,21 @@ return [ 'social_account_register_instructions' => '如果您还没有帐户,您可以使用 :socialAccount 选项注册账户。', 'social_driver_not_found' => '未找到社交驱动程序', 'social_driver_not_configured' => '您的:socialAccount社交设置不正确。', + 'invite_token_expired' => '此邀请链接已过期。 您可以尝试重置您的帐户密码。', // System 'path_not_writable' => '无法上传到文件路径“:filePath”,请确保它可写入服务器。', 'cannot_get_image_from_url' => '无法从 :url 中获取图片', 'cannot_create_thumbs' => '服务器无法创建缩略图,请检查您是否安装了GD PHP扩展。', 'server_upload_limit' => '服务器不允许上传此大小的文件。 请尝试较小的文件。', - 'uploaded' => 'The server does not allow uploads of this size. Please try a smaller file size.', + 'uploaded' => '服务器不允许上传此大小的文件。 请尝试较小的文件。', 'image_upload_error' => '上传图片时发生错误', 'image_upload_type_error' => '上传的图像类型无效', 'file_upload_timeout' => '文件上传已超时。', // Attachments 'attachment_page_mismatch' => '附件更新期间的页面不匹配', - 'attachment_not_found' => '找不到附件', + 'attachment_not_found' => '找不到附件', // Pages 'page_draft_autosave_fail' => '无法保存草稿,确保您在保存页面之前已经连接到互联网', @@ -50,7 +55,7 @@ return [ // Entities 'entity_not_found' => '未找到实体', - 'bookshelf_not_found' => '未找到书架', + 'bookshelf_not_found' => '未找到书架', 'book_not_found' => '未找到图书', 'page_not_found' => '未找到页面', 'chapter_not_found' => '未找到章节', @@ -66,6 +71,7 @@ return [ 'role_cannot_be_edited' => '无法编辑该角色', 'role_system_cannot_be_deleted' => '无法删除系统角色', 'role_registration_default_cannot_delete' => '无法删除设置为默认注册的角色', + 'role_cannot_remove_only_admin' => '该用户是分配给管理员角色的唯一用户。 在尝试在此处删除管理员角色之前,请将其分配给其他用户。', // Comments 'comment_list' => '提取评论时出现错误。', @@ -81,4 +87,13 @@ return [ 'error_occurred' => '出现错误', 'app_down' => ':appName现在正在关闭', 'back_soon' => '请耐心等待网站的恢复。', + + // API errors + 'api_no_authorization_found' => '未在请求中找到授权令牌', + 'api_bad_authorization_format' => '已在请求中找到授权令牌,但格式貌似不正确', + 'api_user_token_not_found' => '未能找到所匹配的API提供的授权令牌', + 'api_incorrect_token_secret' => '给已给出的API所提供的密钥不正确', + 'api_user_no_api_permission' => '使用过的 API 令牌的所有者没有进行API 调用的权限', + 'api_user_token_expired' => '所使用的身份令牌已过期', + ]; diff --git a/resources/lang/zh_CN/pagination.php b/resources/lang/zh_CN/pagination.php index f1fc4b5ae..845ae07a5 100644 --- a/resources/lang/zh_CN/pagination.php +++ b/resources/lang/zh_CN/pagination.php @@ -1,18 +1,11 @@ '« 上一页', 'next' => '下一页 »', diff --git a/resources/lang/zh_CN/passwords.php b/resources/lang/zh_CN/passwords.php index d4ba50c49..afdad8423 100644 --- a/resources/lang/zh_CN/passwords.php +++ b/resources/lang/zh_CN/passwords.php @@ -1,18 +1,11 @@ '密码必须至少包含六个字符并与确认相符。', 'user' => "使用该Email地址的用户不存在。", 'token' => '此密码重置令牌无效。', diff --git a/resources/lang/zh_CN/settings.php b/resources/lang/zh_CN/settings.php index 2a5fcba6c..0b936c8c0 100755 --- a/resources/lang/zh_CN/settings.php +++ b/resources/lang/zh_CN/settings.php @@ -1,59 +1,70 @@ '设置', 'settings_save' => '保存设置', 'settings_save_success' => '设置已保存', - /** - * App settings - */ - - 'app_settings' => 'App设置', - 'app_name' => 'App名', + // App Settings + 'app_customization' => '定制', + 'app_features_security' => '功能与安全', + 'app_name' => '站点名称', 'app_name_desc' => '此名称将在网页头部和Email中显示。', 'app_name_header' => '在网页头部显示应用名?', + 'app_public_access' => '访问权限', + 'app_public_access_desc' => '启用此选项将允许未登录的用户访问站点内容。', + 'app_public_access_desc_guest' => '可以通过“访客”用户来控制公共访问者的访问。', + 'app_public_access_toggle' => '允许公众访问', 'app_public_viewing' => '允许公众查看?', 'app_secure_images' => '启用更高安全性的图片上传?', + 'app_secure_images_toggle' => '启用更高安全性的图片上传', 'app_secure_images_desc' => '出于性能原因,所有图像都是公开的。这个选项会在图像的网址前添加一个随机的,难以猜测的字符串,从而使直接访问变得困难。', 'app_editor' => '页面编辑器', 'app_editor_desc' => '选择所有用户将使用哪个编辑器来编辑页面。', 'app_custom_html' => '自定义HTML头部内容', 'app_custom_html_desc' => '此处添加的任何内容都将插入到每个页面的部分的底部,这对于覆盖样式或添加分析代码很方便。', - 'app_logo' => 'App Logo', + 'app_custom_html_disabled_notice' => '在此设置页面上禁用了自定义HTML标题内容,以确保可以恢复所有重大更改。', + 'app_logo' => '站点Logo', 'app_logo_desc' => '这个图片的高度应该为43px。
大图片将会被缩小。', - 'app_primary_color' => 'App主色', + 'app_primary_color' => '站点主色', 'app_primary_color_desc' => '这应该是一个十六进制值。
保留为空以重置为默认颜色。', - 'app_homepage' => 'App主页', + 'app_homepage' => '站点主页', 'app_homepage_desc' => '选择要在主页上显示的页面来替换默认的视图,选定页面的访问权限将被忽略。', - 'app_homepage_default' => '默认主页视图选择', + 'app_homepage_select' => '选择一个页面', 'app_disable_comments' => '禁用评论', - 'app_disable_comments_desc' => '在App的所有页面上禁用评论,现有评论也不会显示出来。', + 'app_disable_comments_toggle' => '禁用评论', + 'app_disable_comments_desc' => '在站点的所有页面上禁用评论,现有评论也不会显示出来。', - /** - * Registration settings - */ + // Color settings + 'content_colors' => '内容颜色', + 'content_colors_desc' => '设置页面组织层次中所有元素的颜色。建议选择与默认颜色相似的亮度的颜色。', + 'bookshelf_color' => '书架颜色', + 'book_color' => '图书颜色', + 'chapter_color' => '章节颜色', + 'page_color' => '页面颜色', + 'page_draft_color' => '页面草稿颜色', + // Registration Settings 'reg_settings' => '注册设置', - 'reg_allow' => '允许注册?', + 'reg_enable' => '启用注册', + 'reg_enable_toggle' => '启用注册', + 'reg_enable_desc' => '启用注册后,用户将可以自己注册为站点用户。 注册后,他们将获得一个默认的单一用户角色。', 'reg_default_role' => '注册后的默认用户角色', - 'reg_confirm_email' => '需要Email验证?', + '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' => '邮箱确认n', + 'reg_email_confirmation_toggle' => '需要电子邮件确认', 'reg_confirm_email_desc' => '如果使用域名限制,则需要Email验证,并且该值将被忽略。', 'reg_confirm_restrict_domain' => '域名限制', 'reg_confirm_restrict_domain_desc' => '输入您想要限制注册的Email域名列表,用逗号隔开。在被允许与应用程序交互之前,用户将被发送一封Email来确认他们的地址。
注意用户在注册成功后可以修改他们的Email地址。', 'reg_confirm_restrict_domain_placeholder' => '尚未设置限制', - /** - * Maintenance settings - */ - + // Maintenance settings 'maint' => '维护', 'maint_image_cleanup' => '清理图像', 'maint_image_cleanup_desc' => "扫描页面和修订内容以检查哪些图像是正在使用的以及哪些图像是多余的。确保在运行前创建完整的数据库和映像备份。", @@ -62,11 +73,15 @@ return [ 'maint_image_cleanup_warning' => '发现了 :count 张可能未使用的图像。您确定要删除这些图像吗?', 'maint_image_cleanup_success' => '找到并删除了 :count 张可能未使用的图像!', 'maint_image_cleanup_nothing_found' => '找不到未使用的图像,没有删除!', + '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' => '恭喜!您收到了此邮件通知,你的电子邮件设置看起来配置正确。', - /** - * Role settings - */ - + // Role Settings 'roles' => '角色', 'role_user_roles' => '用户角色', 'role_create' => '创建角色', @@ -81,16 +96,18 @@ return [ 'role_details' => '角色详细信息', 'role_name' => '角色名', 'role_desc' => '角色简述', - 'role_external_auth_id' => '外部身份认证ID', + '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' => '管理页面模板', + 'role_access_api' => '访问系统 API', 'role_manage_settings' => '管理App设置', 'role_asset' => '资源许可', 'role_asset_desc' => '对系统内资源的默认访问许可将由这些权限控制。单独设置在书籍,章节和页面上的权限将覆盖这里的权限设定。', - 'role_asset_admins' => '管理员可自动获得对所有内容的访问权限,但这些选项可能会显示或隐藏UI选项。', + 'role_asset_admins' => '管理员可自动获得对所有内容的访问权限,但这些选项可能会显示或隐藏UI选项。', 'role_all' => '全部的', 'role_own' => '拥有的', 'role_controlled_by_asset' => '由其所在的资源来控制', @@ -99,16 +116,22 @@ return [ 'role_users' => '此角色的用户', 'role_users_none' => '目前没有用户被分配到这个角色', - /** - * Users - */ - + // Users 'users' => '用户', 'user_profile' => '用户资料', 'users_add_new' => '添加用户', 'users_search' => '搜索用户', + 'users_details' => '用户详细资料', + 'users_details_desc' => '设置该用户的显示名称和电子邮件地址。 该电子邮件地址将用于登录本站。', + 'users_details_desc_no_email' => '设置此用户的昵称,以便其他人识别。', 'users_role' => '用户角色', + 'users_role_desc' => '选择将分配给该用户的角色。 如果将一个用户分配给多个角色,则这些角色的权限将堆叠在一起,并且他们将获得分配的角色的所有功能。', + 'users_password' => '用户密码', + 'users_password_desc' => '设置用于登录应用程序的密码。 该长度必须至少为6个字符。', + 'users_send_invite_text' => '您可以向该用户发送邀请电子邮件,允许他们设置自己的密码,否则,您可以自己设置他们的密码。', + 'users_send_invite_option' => '发送邀请用户电子邮件', 'users_external_auth_id' => '外部身份认证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' => '如果您想更改密码,请填写以下内容:', 'users_system_public' => '此用户代表访问您的App的任何访客。它不能用于登录,而是自动分配。', 'users_delete' => '删除用户', @@ -122,10 +145,67 @@ return [ 'users_avatar' => '用户头像', 'users_avatar_desc' => '当前图片应该为约256px的正方形。', 'users_preferred_language' => '语言', + 'users_preferred_language_desc' => '此选项将更改用于应用程序用户界面的语言。 这不会影响任何用户创建的内容。', 'users_social_accounts' => '社交账户', 'users_social_accounts_info' => '在这里,您可以绑定您的其他帐户,以便更快更轻松地登录。如果您选择解除绑定,之后将不能通过此社交账户登录,请设置社交账户来取消本App的访问权限。', 'users_social_connect' => '绑定账户', 'users_social_disconnect' => '解除绑定账户', 'users_social_connected' => ':socialAccount 账户已经成功绑定到您的资料。', 'users_social_disconnected' => ':socialAccount 账户已经成功解除绑定。', + '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' => '创建 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令牌', + '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. + //!//////////////////////////////// + 'language_select' => [ + 'en' => 'English', + 'ar' => 'العربية', + 'da' => '丹麦', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// ]; diff --git a/resources/lang/zh_CN/validation.php b/resources/lang/zh_CN/validation.php index ae1ffd619..e0bc55523 100644 --- a/resources/lang/zh_CN/validation.php +++ b/resources/lang/zh_CN/validation.php @@ -1,18 +1,13 @@ ':attribute 需要被同意。', 'active_url' => ':attribute 并不是一个有效的网址', 'after' => ':attribute 必须是在 :date 后的日期。', @@ -35,12 +30,41 @@ return [ 'digits' => ':attribute 必须为:digits位数。', 'digits_between' => ':attribute 必须为:min到:max位数。', 'email' => ':attribute 必须是有效的电子邮件地址。', + 'ends_with' => ' :attribute 必须以 :values 后缀结尾', 'filled' => ':attribute 字段是必需的。', + 'gt' => [ + 'numeric' => ':attribute必须大于 :value.', + 'file' => ':attribute 必须大于 :value k', + 'string' => ':attribute 必须大于 :value 字符。', + 'array' => ':attribute 必须包含多个 :value 项目。', + ], + 'gte' => [ + 'numeric' => ':attribute 必须大于或等于 :value.', + 'file' => ':attribute 必须大于或等于 :value k。', + 'string' => ':attribute 必须大于或等于 :value 字符。', + 'array' => ':attribute 必须具有 :value 项或更多', + ], 'exists' => '选中的 :attribute 无效。', 'image' => ':attribute 必须是一个图片。', + 'image_extension' => ':attribute 必须具有有效且受支持的图像扩展名。', 'in' => '选中的 :attribute 无效。', 'integer' => ':attribute 必须是一个整数。', 'ip' => ':attribute 必须是一个有效的IP地址。', + 'ipv4' => ':attribute 必须是有效的IPv4地址。', + 'ipv6' => ':attribute必须是有效的IPv6地址。', + 'json' => ':attribute 必须是JSON类型.', + 'lt' => [ + 'numeric' => ':attribute 必须小于 :value.', + 'file' => ':attribute 必须小于 :value k。', + 'string' => ':attribute 必须小于 :value 字符。', + 'array' => ':attribute 必须小于 :value 项.', + ], + 'lte' => [ + 'numeric' => ':attribute 必须小于或等于 :value.', + 'file' => ':attribute 必须小于或等于 :value k。', + 'string' => ':attribute 必须小于或等于 :value 字符。', + 'array' => ':attribute 不得超过 :value 项。', + ], 'max' => [ 'numeric' => ':attribute 不能超过:max。', 'file' => ':attribute 不能超过:max KB。', @@ -54,7 +78,9 @@ return [ 'string' => ':attribute 至少为:min个字符。', 'array' => ':attribute 至少有:min项。', ], + 'no_double_extension' => ':attribute 必须具有一个扩展名。', 'not_in' => '选中的 :attribute 无效。', + 'not_regex' => ':attribute 格式错误。', 'numeric' => ':attribute 必须是一个数。', 'regex' => ':attribute 格式无效。', 'required' => ':attribute 字段是必需的。', @@ -74,35 +100,15 @@ return [ 'timezone' => ':attribute 必须是有效的区域。', 'unique' => ':attribute 已经被使用。', 'url' => ':attribute 格式无效。', + 'uploaded' => '无法上传文件。 服务器可能不接受此大小的文件。', - /* - |-------------------------------------------------------------------------- - | Custom Validation Language Lines - |-------------------------------------------------------------------------- - | - | Here you may specify custom validation messages for attributes using the - | convention "attribute.rule" to name the lines. This makes it quick to - | specify a specific custom language line for a given attribute rule. - | - */ - + // Custom validation lines 'custom' => [ 'password-confirm' => [ 'required_with' => '需要确认密码', ], ], - /* - |-------------------------------------------------------------------------- - | Custom Validation Attributes - |-------------------------------------------------------------------------- - | - | The following language lines are used to swap attribute place-holders - | with something more reader friendly such as E-Mail Address instead - | of "email". This simply helps us make messages a little cleaner. - | - */ - + // Custom validation attributes 'attributes' => [], - ]; diff --git a/resources/lang/zh_TW/activities.php b/resources/lang/zh_TW/activities.php index eb23e35a1..5cf2bd3cf 100644 --- a/resources/lang/zh_TW/activities.php +++ b/resources/lang/zh_TW/activities.php @@ -1,12 +1,10 @@ '建立了頁面', 'page_create_notification' => '頁面已建立成功', diff --git a/resources/lang/zh_TW/auth.php b/resources/lang/zh_TW/auth.php index f44ac8af0..6b1f75f75 100644 --- a/resources/lang/zh_TW/auth.php +++ b/resources/lang/zh_TW/auth.php @@ -1,21 +1,15 @@ '使用者名稱或密碼錯誤。', - 'throttle' => '您的登入次數過多,請在:seconds秒後重試。', - /** - * Login & Register - */ + 'failed' => '使用者名稱或密碼錯誤。', + 'throttle' => '您的登入次數過多,請在:秒後重試。', + + // Login & Register 'sign_up' => '註冊', 'log_in' => '登入', 'log_in_with' => '以:socialDriver登入', @@ -27,11 +21,13 @@ return [ 'email' => 'Email位址', 'password' => '密碼', 'password_confirm' => '確認密碼', - 'password_hint' => '必須超過5個字元', + 'password_hint' => '必須超過7個字元', 'forgot_password' => '忘記密碼?', - 'remember_me' => '記住我', + 'remember_me' => '記住該賬戶密碼', 'ldap_email_hint' => '請輸入用於此帳號的電子郵件。', 'create_account' => '建立帳號', + 'already_have_account' => '已經擁有賬戶?', + 'dont_have_account' => '沒有賬戶?', 'social_login' => 'SNS登入', 'social_registration' => 'SNS註冊', 'social_registration_text' => '其他服務註冊/登入.', @@ -43,23 +39,18 @@ return [ 'register_success' => '感謝您註冊:appName,您現在已經登入。', - /** - * Password Reset - */ + // Password Reset 'reset_password' => '重置密碼', 'reset_password_send_instructions' => '在下方輸入您的Email位址,您將收到一封帶有密碼重置連結的郵件。', 'reset_password_send_button' => '發送重置連結', 'reset_password_sent_success' => '密碼重置連結已發送到:email。', 'reset_password_success' => '您的密碼已成功重置。', - 'email_reset_subject' => '重置您的:appName密碼', 'email_reset_text' => '您收到此電子郵件是因為我們收到了您的帳號的密碼重置請求。', 'email_reset_not_requested' => '如果您沒有要求重置密碼,則不需要採取進一步的操作。', - /** - * Email Confirmation - */ + // Email Confirmation 'email_confirm_subject' => '確認您在:appName的Email位址', 'email_confirm_greeting' => '感謝您加入:appName!', 'email_confirm_text' => '請點選下面的按鈕確認您的Email位址:', @@ -73,4 +64,14 @@ return [ 'email_not_confirmed_click_link' => '請檢查註冊時收到的電子郵件,然後點選確認連結。', 'email_not_confirmed_resend' => '如果找不到電子郵件,請透過下面的表單重新發送確認Email。', 'email_not_confirmed_resend_button' => '重新發送確認Email', + + // User Invite + 'user_invite_email_subject' => '您被邀請加入:bookstack!', + 'user_invite_email_greeting' => '我們為您在bookstack上創建了一個新賬戶。', + 'user_invite_email_text' => '請點擊下面的按鈕設置賬戶密碼并獲取訪問權限:', + 'user_invite_email_action' => '請設置賬戶密碼', + 'user_invite_page_welcome' => '歡迎使用:bookstack', + 'user_invite_page_text' => '要完善您的賬戶并獲取訪問權限,您需要設置一個密碼,該密碼將在以後訪問時用於登陸:bookstack', + 'user_invite_page_confirm_button' => '請確定密碼', + 'user_invite_success' => '密碼已設置,您現在可以進入:bookstack了啦' ]; \ No newline at end of file diff --git a/resources/lang/zh_TW/common.php b/resources/lang/zh_TW/common.php index 4eacf4bf0..d82945ac0 100644 --- a/resources/lang/zh_TW/common.php +++ b/resources/lang/zh_TW/common.php @@ -1,31 +1,30 @@ '取消', 'confirm' => '確認', 'back' => '返回', 'save' => '儲存', 'continue' => '繼續', 'select' => '選擇', + 'toggle_all' => '轉換全部', 'more' => '更多', - /** - * Form Labels - */ + // Form Labels 'name' => '名稱', 'description' => '摘要', 'role' => '角色', 'cover_image' => '封面圖片', 'cover_image_description' => '所使用圖片大小必須是440x250px。', - - /** - * Actions - */ + + // Actions 'actions' => '動作', 'view' => '檢視', + 'view_all' => '驗視全部', 'create' => '建立', 'update' => '更新', 'edit' => '編輯', @@ -39,10 +38,18 @@ return [ 'reset' => '重置', 'remove' => '刪除', 'add' => '新增', + 'fullscreen' => '全屏顯示', - /** - * Misc - */ + // Sort Options + 'sort_options' => '選項分類', + 'sort_direction_toggle' => '順序方向切換', + 'sort_ascending' => '升序', + 'sort_descending' => '降序', + 'sort_name' => '名稱', + 'sort_created_at' => '創建日期', + 'sort_updated_at' => '更新日期', + + // Misc 'deleted_user' => '刪除使用者', 'no_activity' => '無活動', 'no_items' => '無項目', @@ -53,16 +60,18 @@ return [ 'grid_view' => '縮圖檢視', 'list_view' => '清單撿視', 'default' => '預設', + 'breadcrumb' => '導覽路徑', - /** - * Header - */ + // Header + 'profile_menu' => '個人資料菜單', 'view_profile' => '檢視資料', 'edit_profile' => '編輯資料', - /** - * Email Content - */ + // Layout tabs + 'tab_info' => '訊息', + 'tab_content' => '內容', + + // Email Content 'email_action_help' => '如果您無法點選“:actionText”按鈕,請將下面的網址複製到您的瀏覽器中打開:', - 'email_rights' => 'All rights reserved', + 'email_rights' => '版權所有', ]; diff --git a/resources/lang/zh_TW/components.php b/resources/lang/zh_TW/components.php index 8d9020329..bcadecbb6 100644 --- a/resources/lang/zh_TW/components.php +++ b/resources/lang/zh_TW/components.php @@ -1,9 +1,10 @@ '選擇圖片', 'image_all' => '全部', 'image_all_title' => '檢視所有圖片', @@ -24,9 +25,7 @@ return [ 'image_delete_success' => '圖片刪除成功', 'image_upload_remove' => '移除', - /** - * Code editor - */ + // Code Editor 'code_editor' => '編輯程式碼', 'code_language' => '程式語言', 'code_content' => '程式碼內容', diff --git a/resources/lang/zh_TW/entities.php b/resources/lang/zh_TW/entities.php index 90299a333..d3280217c 100644 --- a/resources/lang/zh_TW/entities.php +++ b/resources/lang/zh_TW/entities.php @@ -1,14 +1,17 @@ '最近建立', 'recently_created_pages' => '最近建立的頁面', 'recently_updated_pages' => '最新頁面', 'recently_created_chapters' => '最近建立的章節', 'recently_created_books' => '最近建立的書本', + 'recently_created_shelves' => '最近建立的章節', 'recently_update' => '最近更新', 'recently_viewed' => '最近看過', 'recent_activity' => '近期活動', @@ -31,17 +34,13 @@ return [ 'export_pdf' => 'PDF檔案', 'export_text' => '純文字檔案', - /** - * Permissions and restrictions - */ + // Permissions and restrictions 'permissions' => '權限', 'permissions_intro' => '本設定優先權高於每個使用者角色本身所具有的權限。', 'permissions_enable' => '啟用自訂權限', 'permissions_save' => '儲存權限', - /** - * Search - */ + // Search 'search_results' => '搜尋結果', 'search_total_results_found' => '共找到了:count個結果', 'search_clear' => '清除搜尋', @@ -66,16 +65,16 @@ return [ 'search_set_date' => '設定日期', 'search_update' => '更新搜尋結果', - /** - * Shelves - */ + // Shelves 'shelf' => '書架', 'shelves' => '書架', + 'x_shelves' => ':架|:章節', 'shelves_long' => '書架', 'shelves_empty' => '不存在已建立的書架', 'shelves_create' => '建立書架', 'shelves_popular' => '熱門書架', 'shelves_new' => '新書架', + 'shelves_new_action' => '建立新的書架', 'shelves_popular_empty' => '最受歡迎的書架將出現在這裡。', 'shelves_new_empty' => '最近建立的書架將出現在這裡。', 'shelves_save' => '儲存書架', @@ -98,9 +97,7 @@ return [ 'shelves_copy_permissions_explain' => '這會將此書架目前的權限設定套用到所有包含的書本上。在生效之前,請確認您已儲存任何對此書架權限的變更。', 'shelves_copy_permission_success' => '已將書架的權限複製到:count本書上', - /** - * Books - */ + // Books 'book' => '書本', 'books' => '書本', 'x_books' => ':count本書', @@ -108,6 +105,7 @@ return [ 'books_popular' => '熱門書本', 'books_recent' => '最近的書', 'books_new' => '新書', + 'books_new_action' => '新增一本書', 'books_popular_empty' => '最受歡迎的書本將出現在這裡。', 'books_new_empty' => '最近建立的書本將出現在這裡。', 'books_create' => '建立書本', @@ -123,7 +121,6 @@ return [ 'books_permissions_updated' => '書本權限已更新', 'books_empty_contents' => '本書目前沒有頁面或章節。', 'books_empty_create_page' => '建立頁面', - 'books_empty_or' => '或', 'books_empty_sort_current_book' => '排序目前書本', 'books_empty_add_chapter' => '加入章節', 'books_permissions_active' => '已啟用此書本的自訂權限', @@ -131,12 +128,15 @@ return [ 'books_navigation' => '書本導覽', 'books_sort' => '排序書本內容', 'books_sort_named' => '排序書本「:bookName」', + 'books_sort_name' => '按名稱排序', + 'books_sort_created' => '按創建時間排序', + 'books_sort_updated' => '按更新時間排序', + 'books_sort_chapters_first' => '第一章', + 'books_sort_chapters_last' => '最後一章', 'books_sort_show_other' => '顯示其他書本', 'books_sort_save' => '儲存新順序', - /** - * Chapters - */ + // Chapters 'chapter' => '章節', 'chapters' => '章節', 'x_chapters' => ':count個章節', @@ -159,9 +159,7 @@ return [ 'chapters_permissions_success' => '章節權限已更新', 'chapters_search_this' => '從本章節搜尋', - /** - * Pages - */ + // Pages 'page' => '頁面', 'pages' => '頁面', 'x_pages' => ':count個頁面', @@ -178,7 +176,7 @@ return [ 'pages_delete_confirm' => '您確定要刪除此頁面嗎?', 'pages_delete_draft_confirm' => '您確定要刪除此草稿頁面嗎?', 'pages_editing_named' => '正在編輯頁面“:pageName”', - 'pages_edit_toggle_header' => '顯示/隱藏導覽欄', + 'pages_edit_draft_options' => '草稿選項', 'pages_edit_save_draft' => '儲存草稿', 'pages_edit_draft' => '編輯頁面草稿', 'pages_editing_draft' => '正在編輯草稿', @@ -212,6 +210,8 @@ return [ 'pages_revisions_created_by' => '建立者', 'pages_revisions_date' => '修訂日期', 'pages_revisions_number' => '#', + 'pages_revisions_numbered' => '修訂編號:id', + 'pages_revisions_numbered_changes' => '修訂編號:id 更改', 'pages_revisions_changelog' => '更新說明', 'pages_revisions_changes' => '說明', 'pages_revisions_current' => '目前版本', @@ -234,19 +234,20 @@ return [ ], 'pages_draft_discarded' => '草稿已丟棄,編輯器已更新到目前頁面內容。', 'pages_specific' => '指定頁面', + 'pages_is_template' => '頁面模板', - /** - * Editor sidebar - */ + // Editor Sidebar 'page_tags' => '頁面標籤', 'chapter_tags' => '章節標籤', 'book_tags' => '書本標籤', 'shelf_tags' => '書架標籤', 'tag' => '標籤', - 'tags' => '', + 'tags' => '標籤', + 'tag_name' => '標籤名稱', 'tag_value' => '標籤值 (非必要)', 'tags_explain' => "加入一些標籤以更好地對您的內容進行分類。\n您可以為標籤分配一個值,以進行更深入的組織。", 'tags_add' => '加入另一個標籤', + 'tags_remove' => '移除此標籤', 'attachments' => '附件', 'attachments_explain' => '上傳一些檔案或附加連結顯示在您的網頁上。將顯示在在頁面的側邊欄。', 'attachments_explain_instant_save' => '這裡的更改將立即儲存。Changes here are saved instantly.', @@ -256,7 +257,7 @@ return [ 'attachments_set_link' => '設定連結', 'attachments_delete_confirm' => '確認您想要刪除此附件後,請點選刪除。', 'attachments_dropzone' => '刪除檔案或點選此處加入檔案', - 'attachments_no_files' => '尚未上傳檔案', // No files have been uploaded + 'attachments_no_files' => '尚未上傳檔案', 'attachments_explain_link' => '如果您不想上傳檔案,則可以附加連結,這可以是指向其他頁面的連結,也可以是指向雲端檔案的連結。', 'attachments_link_name' => '連結名稱', 'attachment_link' => '附件連結', @@ -272,19 +273,22 @@ return [ 'attachments_file_uploaded' => '附件上傳成功', 'attachments_file_updated' => '附件更新成功', 'attachments_link_attached' => '連結成功附加到頁面', + 'templates' => '樣本', + 'templates_set_as_template' => '頁面是模板', + 'templates_explain_set_as_template' => '您可以將此頁面設置為模板,以便在創建其他頁面時利用其內容。 如果其他用戶對此頁面擁有查看權限,則將可以使用此模板。', + 'templates_replace_content' => '替換頁面內容', + 'templates_append_content' => '附加到頁面內容', + 'templates_prepend_content' => '前置頁面內容', - /** - * Profile View - */ + // Profile View 'profile_user_for_x' => '來這裡:time了', 'profile_created_content' => '已建立內容', 'profile_not_created_pages' => ':userName尚未建立任何頁面', 'profile_not_created_chapters' => ':userName尚未建立任何章節', 'profile_not_created_books' => ':userName尚未建立任何書本', + 'profile_not_created_shelves' => ':用戶名 沒有創建任何書架', - /** - * Comments - */ + // Comments 'comment' => '評論', 'comments' => '評論', 'comment_add' => '新增評論', @@ -302,10 +306,9 @@ return [ 'comment_delete_confirm' => '你確定要刪除這條評論?', 'comment_in_reply_to' => '回覆 :commentId', - /** - * Revision - */ + // Revision 'revision_delete_confirm' => '您確定要刪除此修訂版嗎?', + 'revision_restore_confirm' => '您確定要還原此修訂版嗎? 當前頁面內容將被替換。', 'revision_delete_success' => '修訂刪除', 'revision_cannot_delete_latest' => '無法刪除最新版本。' -]; +]; \ No newline at end of file diff --git a/resources/lang/zh_TW/errors.php b/resources/lang/zh_TW/errors.php index 2e8050cde..e71575e59 100644 --- a/resources/lang/zh_TW/errors.php +++ b/resources/lang/zh_TW/errors.php @@ -1,11 +1,9 @@ '您沒有權限進入所請求的頁面。', 'permissionJson' => '您沒有權限執行所請求的操作。', @@ -15,10 +13,16 @@ return [ 'email_already_confirmed' => 'Email已被確認,請嘗試登錄。', 'email_confirmation_invalid' => '此確認 Session 無效或已被使用,請重新註冊。', 'email_confirmation_expired' => '確認 Session 已過期,已發送新的確認電子郵件。', + 'email_confirmation_awaiting' => '用於此賬戶的電子郵箱需要認證', 'ldap_fail_anonymous' => '使用匿名綁定的LDAP進入失敗。', 'ldap_fail_authed' => '帶有標識名稱和密碼的LDAP進入失敗。', 'ldap_extension_not_installed' => '未安裝LDAP PHP外掛程式', 'ldap_cannot_connect' => '無法連接到ldap伺服器,第一次連接失敗', + 'saml_already_logged_in' => '已登陸', + 'saml_user_not_registered' => '用戶:name未註冊,自動註冊不可用', + 'saml_no_email_address' => '在外部認證系統提供的數據中找不到該用戶的電子郵件地址', + 'saml_invalid_response_id' => '該應用程序啟動的進程無法識別來自外部身份驗證系統的請求。 登錄後返回可能會導致此問題。', + 'saml_fail_authed' => '使用:system登錄失敗,系統未提供成功的授權', 'social_no_action_defined' => '沒有定義行為', 'social_login_bad_response' => "在 :socialAccount 登錄時遇到錯誤:\n:error", 'social_account_in_use' => ':socialAccount 帳號已被使用,請嘗試透過 :socialAccount 選項登錄。', @@ -29,13 +33,14 @@ return [ 'social_account_register_instructions' => '如果您還沒有帳號,您可以使用 :socialAccount 選項註冊帳號。', 'social_driver_not_found' => '未找到社交驅動程式', 'social_driver_not_configured' => '您的:socialAccount社交設定不正確。', + 'invite_token_expired' => '此邀請鏈接已過期,您可以嘗試重置您的賬戶密碼。', // System 'path_not_writable' => '無法上傳到檔案路徑“:filePath”,請確保它可寫入伺服器。', 'cannot_get_image_from_url' => '無法從 :url 中獲取圖片', 'cannot_create_thumbs' => '伺服器無法建立縮圖,請檢查您是否安裝了GD PHP外掛。', 'server_upload_limit' => '上傳的檔案大小超過伺服器允許上限。請嘗試較小的檔案。', - 'uploaded' => '上傳的檔案大小超過伺服器允許上限。請嘗試較小的檔案。', + 'uploaded' => '上傳的檔案大小超過伺服器允許上限。請嘗試較小的檔案。', 'image_upload_error' => '上傳圖片時發生錯誤', 'image_upload_type_error' => '上傳圖片類型錯誤', 'file_upload_timeout' => '文件上傳已超時。', @@ -66,6 +71,7 @@ return [ 'role_cannot_be_edited' => '無法編輯這個角色', 'role_system_cannot_be_deleted' => '無法刪除系統角色', 'role_registration_default_cannot_delete' => '無法刪除設定為預設註冊的角色', + 'role_cannot_remove_only_admin' => '該用戶是分配作為管理員職務的唯一用戶。 在嘗試在此處刪除管理員職務之前,請將其分配給其他用戶。', // Comments 'comment_list' => '讀取評論時發生錯誤。', @@ -81,4 +87,13 @@ return [ 'error_occurred' => '發生錯誤', 'app_down' => ':appName現在正在關閉', 'back_soon' => '請耐心等待網站的恢複。', + + // API errors + 'api_no_authorization_found' => '在請求上找不到授權令牌', + 'api_bad_authorization_format' => '在請求中找到授權令牌,但格式似乎不正確', + 'api_user_token_not_found' => '找不到提供的授權令牌的匹配API令牌', + 'api_incorrect_token_secret' => '給定使用的API令牌提供的密鑰不正確', + 'api_user_no_api_permission' => '使用的API令牌的擁有者者無權進行API調用', + 'api_user_token_expired' => '授權令牌已過期', + ]; diff --git a/resources/lang/zh_TW/pagination.php b/resources/lang/zh_TW/pagination.php index fc2f4a059..6e296de8f 100644 --- a/resources/lang/zh_TW/pagination.php +++ b/resources/lang/zh_TW/pagination.php @@ -1,18 +1,11 @@ '« 上一頁', 'next' => '下一頁 »', diff --git a/resources/lang/zh_TW/passwords.php b/resources/lang/zh_TW/passwords.php index aa93eec1e..d1f0aeb08 100644 --- a/resources/lang/zh_TW/passwords.php +++ b/resources/lang/zh_TW/passwords.php @@ -1,18 +1,11 @@ '密碼必須至少包含六個字元並與確認相符。', 'user' => "使用該Email位址的使用者不存在。", 'token' => '此密碼重置 Session 無效。', diff --git a/resources/lang/zh_TW/settings.php b/resources/lang/zh_TW/settings.php index 335f5a098..061e7ad58 100644 --- a/resources/lang/zh_TW/settings.php +++ b/resources/lang/zh_TW/settings.php @@ -1,32 +1,35 @@ '設定', 'settings_save' => '儲存設定', 'settings_save_success' => '設定已儲存', - /** - * App settings - */ - - 'app_settings' => 'App設定', + // App Settings + 'app_customization' => '自定義', + 'app_features_security' => '功能與安全', 'app_name' => 'App名', 'app_name_desc' => '此名稱將在網頁頂端和Email中顯示。', 'app_name_header' => '在網頁頂端顯示應用名稱?', + 'app_public_access' => '公共訪問', + 'app_public_access_desc' => '啟用此選項將允許未登錄的訪問者訪問BookStack實例中的內容。', + 'app_public_access_desc_guest' => '可以通過“訪客”控制公共訪問者的訪問。', + 'app_public_access_toggle' => '允許公開訪問', 'app_public_viewing' => '開放公開閱覽?', 'app_secure_images' => '啟用更高安全性的圖片上傳?', + 'app_secure_images_toggle' => '啟用更高安全性的圖片上傳', 'app_secure_images_desc' => '出於效能考量,所有圖片都是公開的。這個選項會在圖片的網址前加入一個隨機並難以猜測的字元串,從而使直接進入變得困難。', 'app_editor' => '頁面編輯器', 'app_editor_desc' => '選擇所有使用者將使用哪個編輯器來編輯頁面。', 'app_custom_html' => '自訂HTML頂端內容', 'app_custom_html_desc' => '此處加入的任何內容都將插入到每個頁面的部分的底部,這對於覆蓋樣式或加入分析程式碼很方便。', + 'app_custom_html_disabled_notice' => '在此設置頁面上禁用了自定義HTML標題內容,以確保可以恢復所有重大更改。', 'app_logo' => 'App Logo', 'app_logo_desc' => '這個圖片的高度應該為43px。
大圖片將會被縮小。', 'app_primary_color' => 'App主要配色', @@ -35,25 +38,33 @@ return [ 'app_homepage_desc' => '選擇要做為首頁的頁面,這將會替換預設首頁,而且這個頁面的權限設定將被忽略。', 'app_homepage_select' => '預設首頁選擇', 'app_disable_comments' => '關閉評論', + 'app_disable_comments_toggle' => '禁用評論', 'app_disable_comments_desc' => '在App的所有頁面上關閉評論,已經存在的評論也不會顯示。', - /** - * Registration settings - */ + // Color settings + 'content_colors' => '內容顏色', + 'content_colors_desc' => '為頁面組織層次結構中的所有元素設置顏色。 為了提高可讀性,建議選擇亮度與默認顏色相似的顏色。', + 'bookshelf_color' => '书架顏色', + 'book_color' => '书本颜色', + 'chapter_color' => '章节颜色', + 'page_color' => '页面颜色', + 'page_draft_color' => '頁面草稿顏色', + // Registration Settings 'reg_settings' => '註冊設定', - 'reg_allow' => '開放註冊?', + 'reg_enable' => '啟用註冊', + 'reg_enable_toggle' => '啟用註冊', + 'reg_enable_desc' => '啟用註冊後,用戶將可以自己註冊為應用程序用戶,註冊後,他們將獲得一個默認的單一用戶角色。', 'reg_default_role' => '註冊後的預設使用者角色', - 'reg_confirm_email' => '需要Email驗證?', + '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' => '电子邮箱认证', + 'reg_email_confirmation_toggle' => '需要電子郵件確認', 'reg_confirm_email_desc' => '如果使用網域名稱限制,則需要Email驗證,並且本設定將被忽略。', 'reg_confirm_restrict_domain' => '網域名稱限制', 'reg_confirm_restrict_domain_desc' => '輸入您想要限制註冊的Email域域名稱列表,用逗號隔開。在被允許與本系統連結之前,使用者會收到一封Email來確認他們的位址。
注意,使用者在註冊成功後可以修改他們的Email位址。', 'reg_confirm_restrict_domain_placeholder' => '尚未設定限制的網域', - /** - * Maintenance settings - */ - + // Maintenance settings 'maint' => '維護', 'maint_image_cleanup' => '清理圖像', 'maint_image_cleanup_desc' => "掃描頁面和修訂內容以檢查哪些圖像是正在使用的以及哪些圖像是多余的。確保在運行前創建完整的數據庫和映像備份。", @@ -62,11 +73,15 @@ return [ 'maint_image_cleanup_warning' => '發現了 :count 張可能未使用的圖像。您確定要刪除這些圖像嗎?', 'maint_image_cleanup_success' => '找到並刪除了 :count 張可能未使用的圖像!', 'maint_image_cleanup_nothing_found' => '找不到未使用的圖像,沒有刪除!', + 'maint_send_test_email' => '發送測試電子郵件', + 'maint_send_test_email_desc' => '這會將測試電子郵件發送到您的個人資料中指定的電子郵件地址。', + 'maint_send_test_email_run' => '發送測試郵件', + 'maint_send_test_email_success' => '郵件發送到:地址', + 'maint_send_test_email_mail_subject' => '測試郵件', + 'maint_send_test_email_mail_greeting' => '電子郵件傳遞似乎有效!', + 'maint_send_test_email_mail_text' => '恭喜你! 收到此電子郵件通知時,您的電子郵件設置已經認證成功。', - /** - * Role settings - */ - + // Role Settings 'roles' => '角色', 'role_user_roles' => '使用者角色', 'role_create' => '建立角色', @@ -87,6 +102,8 @@ return [ 'role_manage_roles' => '管理角色與角色權限', 'role_manage_entity_permissions' => '管理所有圖書,章節和頁面的權限', 'role_manage_own_entity_permissions' => '管理自己的圖書,章節和頁面的權限', + 'role_manage_page_templates' => '管理頁面模板', + 'role_access_api' => '存取系統API', 'role_manage_settings' => '管理App設定', 'role_asset' => '資源項目', 'role_asset_desc' => '對系統內資源的預設權限將由這裡的權限控制。若有單獨設定在書本、章節和頁面上的權限,將會覆蓋這裡的權限設定。', @@ -99,16 +116,22 @@ return [ 'role_users' => '此角色的使用者', 'role_users_none' => '目前沒有使用者被分配到這個角色', - /** - * Users - */ - + // Users 'users' => '使用者', 'user_profile' => '使用者資料', 'users_add_new' => '加入使用者', 'users_search' => '搜尋使用者', + 'users_details' => '用戶詳情', + 'users_details_desc' => '請設置用戶的顯示名稱和電子郵件地址, 該電子郵件地址將用於登錄該應用。', + 'users_details_desc_no_email' => '設置一個用戶的顯示名稱,以便其他人可以認出你。', 'users_role' => '使用者角色', + 'users_role_desc' => '選擇一個將分配給該用戶的角色。 如果將一個用戶分配給多個角色,則這些角色的權限將堆疊在一起,並且他們將獲得分配的角色的所有功能。', + 'users_password' => '用戶密碼', + 'users_password_desc' => '設置用於登錄賬戶的密碼, 密碼長度必須至少為6個字符。', + 'users_send_invite_text' => '您可以選擇向該用戶發送邀請電子郵件,允許他們設置自己的密碼,或者您可以自己設置他們的密碼。', + 'users_send_invite_option' => '向用戶發送邀請電子郵件', 'users_external_auth_id' => '外部身份驗證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' => '如果您想更改密碼,請填寫以下內容:', 'users_system_public' => '此使用者代表進入您的App的任何訪客。它不能用於登入,而是自動分配。', 'users_delete' => '刪除使用者', @@ -122,10 +145,67 @@ return [ 'users_avatar' => '使用者大頭照', 'users_avatar_desc' => '目前圖片應該為約256px的正方形。', 'users_preferred_language' => '語言', + 'users_preferred_language_desc' => '此選項將更改用於應用用戶界面的語言,但 這不會影響任何用戶創建的內容。', 'users_social_accounts' => '社群網站帳號', 'users_social_accounts_info' => '在這里,您可以連結您的其他帳號,以便方便地登入。如果您選擇解除連結,之後將不能透過此社群網站帳號登入,請設定社群網站帳號來取消本系統p的進入權限。', 'users_social_connect' => '連結帳號', 'users_social_disconnect' => '解除連結帳號', 'users_social_connected' => ':socialAccount 帳號已經成功連結到您的資料。', 'users_social_disconnected' => ':socialAccount 帳號已經成功解除連結。', + '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' => '創建 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' => '令牌已創建:time Ago', + 'user_api_token_updated' => '令牌已更新:timeAgo', + 'user_api_token_delete' => '刪除令牌', + 'user_api_token_delete_warning' => '這將從系統中完全刪除名稱為\':tokenName\'的API令牌。', + '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. + //!//////////////////////////////// + 'language_select' => [ + 'en' => 'English', + 'ar' => 'العربية', + 'da' => '丹麥', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// ]; diff --git a/resources/lang/zh_TW/validation.php b/resources/lang/zh_TW/validation.php index 5b708064d..046e24451 100644 --- a/resources/lang/zh_TW/validation.php +++ b/resources/lang/zh_TW/validation.php @@ -1,18 +1,13 @@ ':attribute 需要被同意。', 'active_url' => ':attribute 並不是一個有效的網址', 'after' => ':attribute 必須是在 :date 後的日期。', @@ -35,12 +30,41 @@ return [ 'digits' => ':attribute 必須為:digits位數。', 'digits_between' => ':attribute 必須為:min到:max位數。', 'email' => ':attribute 必須是有效的電子郵件位址。', + 'ends_with' => ':attribute必須以下列之一結尾::values', 'filled' => ':attribute 字段是必需的。', + 'gt' => [ + 'numeric' => ':attribute必須大於:value。', + 'file' => ':attribute必須大於:value千字節。', + 'string' => ':attribute必須大於:value字符。', + 'array' => ':attribute必須包含比:value多的項目。', + ], + 'gte' => [ + 'numeric' => 'The :attribute必須大於或等於:value.', + 'file' => 'The :attribute必須大於或等於:value千字節。', + 'string' => 'The :attribute必須大於或等於:value字符。', + 'array' => 'The :attribute必須具有:value項或更多。', + ], 'exists' => '選中的 :attribute 無效。', 'image' => ':attribute 必須是一個圖片。', + 'image_extension' => 'The :attribute必須具有有效且受支持的圖像擴展名.', 'in' => '選中的 :attribute 無效。', 'integer' => ':attribute 必須是一個整數。', 'ip' => ':attribute 必須是一個有效的IP位址。', + 'ipv4' => 'The :attribute必須是有效的IPv4地址。', + 'ipv6' => 'The :attribute必須是有效的IPv6地址。', + 'json' => 'The :attribute必須是有效的JSON字符串。', + 'lt' => [ + 'numeric' => 'The :attribute必須小於:value。', + 'file' => 'The :attribute必須小於:value千字節。', + 'string' => 'The :attribute必須小於:value字符。', + 'array' => 'The :attribute必須少於:value個項目。', + ], + 'lte' => [ + 'numeric' => 'The :attribute必須小於或等於:value。', + 'file' => 'The :attribute必須小於或等於:value千字節。', + 'string' => 'The :attribute必須小於或等於:value字符。', + 'array' => 'The :attribute不得超過:value個項目。', + ], 'max' => [ 'numeric' => ':attribute 不能超過:max。', 'file' => ':attribute 不能超過:max KB。', @@ -54,7 +78,9 @@ return [ 'string' => ':attribute 至少為:min個字元。', 'array' => ':attribute 至少有:min項。', ], + 'no_double_extension' => 'The :attribute必須僅具有一個文件擴展名。', 'not_in' => '選中的 :attribute 無效。', + 'not_regex' => 'The :attribute格式無效。', 'numeric' => ':attribute 必須是一個數。', 'regex' => ':attribute 格式無效。', 'required' => ':attribute 字段是必需的。', @@ -74,35 +100,15 @@ return [ 'timezone' => ':attribute 必須是有效的區域。', 'unique' => ':attribute 已經被使用。', 'url' => ':attribute 格式無效。', + 'uploaded' => '無法上傳文件, 服務器可能不接受此大小的文件。', - /* - |-------------------------------------------------------------------------- - | Custom Validation Language Lines - |-------------------------------------------------------------------------- - | - | Here you may specify custom validation messages for attributes using the - | convention "attribute.rule" to name the lines. This makes it quick to - | specify a specific custom language line for a given attribute rule. - | - */ - + // Custom validation lines 'custom' => [ 'password-confirm' => [ 'required_with' => '需要確認密碼', ], ], - /* - |-------------------------------------------------------------------------- - | Custom Validation Attributes - |-------------------------------------------------------------------------- - | - | The following language lines are used to swap attribute place-holders - | with something more reader friendly such as E-Mail Address instead - | of "email". This simply helps us make messages a little cleaner. - | - */ - + // Custom validation attributes 'attributes' => [], - ]; diff --git a/resources/assets/sass/_animations.scss b/resources/sass/_animations.scss similarity index 100% rename from resources/assets/sass/_animations.scss rename to resources/sass/_animations.scss diff --git a/resources/assets/sass/_blocks.scss b/resources/sass/_blocks.scss similarity index 91% rename from resources/assets/sass/_blocks.scss rename to resources/sass/_blocks.scss index 2cb17a18d..ff344158f 100644 --- a/resources/assets/sass/_blocks.scss +++ b/resources/sass/_blocks.scss @@ -236,4 +236,31 @@ .tag-list div:last-child .tag-item { margin-bottom: 0; +} + +/** + * API Docs + */ +.api-method { + font-size: 0.75rem; + background-color: #888; + padding: $-xs; + line-height: 1.3; + opacity: 0.7; + vertical-align: top; + border-radius: 3px; + color: #FFF; + display: inline-block; + min-width: 60px; + text-align: center; + font-weight: bold; + &[data-method="GET"] { background-color: #077b70 } + &[data-method="POST"] { background-color: #cf4d03 } + &[data-method="PUT"] { background-color: #0288D1 } + &[data-method="DELETE"] { background-color: #ab0f0e } +} + +.sticky-sidebar { + position: sticky; + top: $-m; } \ No newline at end of file diff --git a/resources/assets/sass/_buttons.scss b/resources/sass/_buttons.scss similarity index 100% rename from resources/assets/sass/_buttons.scss rename to resources/sass/_buttons.scss diff --git a/resources/assets/sass/_codemirror.scss b/resources/sass/_codemirror.scss similarity index 80% rename from resources/assets/sass/_codemirror.scss rename to resources/sass/_codemirror.scss index e3f7028eb..dc1aef9bb 100644 --- a/resources/assets/sass/_codemirror.scss +++ b/resources/sass/_codemirror.scss @@ -341,46 +341,55 @@ div.CodeMirror-dragcursors { /* Help users use markselection to safely style text background */ span.CodeMirror-selectedtext { background: none; } +/** + * Codemirror Default theme + */ -/* +.cm-s-default .cm-header {color: blue;} +.cm-s-default .cm-quote {color: #090;} +.cm-negative {color: #d44;} +.cm-positive {color: #292;} +.cm-header, .cm-strong {font-weight: bold;} +.cm-em {font-style: italic;} +.cm-link {text-decoration: underline;} +.cm-strikethrough {text-decoration: line-through;} - Name: Base16 Default Light - Author: Chris Kempson (http://chriskempson.com) +.cm-s-default .cm-keyword {color: #708;} +.cm-s-default .cm-atom {color: #219;} +.cm-s-default .cm-number {color: #164;} +.cm-s-default .cm-def {color: #00f;} +.cm-s-default .cm-variable, +.cm-s-default .cm-punctuation, +.cm-s-default .cm-property, +.cm-s-default .cm-operator {} +.cm-s-default .cm-variable-2 {color: #05a;} +.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;} +.cm-s-default .cm-comment {color: #a50;} +.cm-s-default .cm-string {color: #a11;} +.cm-s-default .cm-string-2 {color: #f50;} +.cm-s-default .cm-meta {color: #555;} +.cm-s-default .cm-qualifier {color: #555;} +.cm-s-default .cm-builtin {color: #30a;} +.cm-s-default .cm-bracket {color: #997;} +.cm-s-default .cm-tag {color: #170;} +.cm-s-default .cm-attribute {color: #00c;} +.cm-s-default .cm-hr {color: #999;} +.cm-s-default .cm-link {color: #00c;} - CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) - Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) +.cm-s-default .cm-error {color: #f00;} +.cm-invalidchar {color: #f00;} -*/ +.CodeMirror-composing { border-bottom: 2px solid; } -.cm-s-base16-light.CodeMirror { background: #f8f8f8; color: #444444; } -.cm-s-base16-light div.CodeMirror-selected { background: #e0e0e0; } -.cm-s-base16-light .CodeMirror-line::selection, .cm-s-base16-light .CodeMirror-line > span::selection, .cm-s-base16-light .CodeMirror-line > span > span::selection { background: #e0e0e0; } -.cm-s-base16-light .CodeMirror-line::-moz-selection, .cm-s-base16-light .CodeMirror-line > span::-moz-selection, .cm-s-base16-light .CodeMirror-line > span > span::-moz-selection { background: #e0e0e0; } -.cm-s-base16-light .CodeMirror-gutters { background: #f5f5f5; border-right: 0px; } -.cm-s-base16-light .CodeMirror-guttermarker { color: #ac4142; } -.cm-s-base16-light .CodeMirror-guttermarker-subtle { color: #b0b0b0; } -.cm-s-base16-light .CodeMirror-linenumber { color: #b0b0b0; } -.cm-s-base16-light .CodeMirror-cursor { border-left: 1px solid #505050; } +/* Default styles for common addons */ -.cm-s-base16-light span.cm-comment { color: #8f5536; } -.cm-s-base16-light span.cm-atom { color: #aa759f; } -.cm-s-base16-light span.cm-number { color: #aa759f; } +div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;} +div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} +.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } +.CodeMirror-activeline-background {background: #e8f2ff;} -.cm-s-base16-light span.cm-property, .cm-s-base16-light span.cm-attribute { color: #678c30; } -.cm-s-base16-light span.cm-keyword { color: #ac4142; } -.cm-s-base16-light span.cm-string { color: #e09c3c; } +/* STOP */ -.cm-s-base16-light span.cm-builtin { color: #4c7f9e; } -.cm-s-base16-light span.cm-variable { color: #90a959; } -.cm-s-base16-light span.cm-variable-2 { color: #6a9fb5; } -.cm-s-base16-light span.cm-def { color: #d28445; } -.cm-s-base16-light span.cm-bracket { color: #202020; } -.cm-s-base16-light span.cm-tag { color: #ac4142; } -.cm-s-base16-light span.cm-link { color: #aa759f; } -.cm-s-base16-light span.cm-error { background: #ac4142; color: #505050; } - -.cm-s-base16-light .CodeMirror-activeline-background { background: #DDDCDC; } -.cm-s-base16-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; } /** * Custom BookStack overrides @@ -394,7 +403,8 @@ span.CodeMirror-selectedtext { background: none; } margin-bottom: $-l; border: 1px solid #DDD;; } -.cm-s-base16-light .CodeMirror-gutters { background: #f5f5f5; border-right: 1px solid #DDD; } + +.cm-s-mdn-like .CodeMirror-gutters { background: #f8f8f8; border-left: 0; color: #333; } .code-fill .CodeMirror { position: absolute; @@ -403,6 +413,7 @@ span.CodeMirror-selectedtext { background: none; } left: 0; width: 100%; height: 100%; + margin-bottom: 0; } /** diff --git a/resources/assets/sass/_colors.scss b/resources/sass/_colors.scss similarity index 95% rename from resources/assets/sass/_colors.scss rename to resources/sass/_colors.scss index 8623d374a..77f51b324 100644 --- a/resources/assets/sass/_colors.scss +++ b/resources/sass/_colors.scss @@ -40,6 +40,11 @@ fill: #575757 !important; } +.text-dark { + color: #222 !important; + fill: #222 !important; +} + /* * Entity text colors */ diff --git a/resources/assets/sass/_components.scss b/resources/sass/_components.scss similarity index 98% rename from resources/assets/sass/_components.scss rename to resources/sass/_components.scss index 0172956a7..6ef53b719 100644 --- a/resources/assets/sass/_components.scss +++ b/resources/sass/_components.scss @@ -15,7 +15,7 @@ transition: transform ease-in-out 280ms; transform: translateX(580px); display: grid; - grid-template-columns: 42px 1fr; + grid-template-columns: 42px 1fr 12px; color: #444; font-weight: 700; span, svg { @@ -29,6 +29,13 @@ padding-right: $-s; fill: currentColor; } + .dismiss { + margin-top: -8px; + svg { + height: 1.0rem; + color: #444; + } + } span { vertical-align: middle; line-height: 1.3; @@ -94,9 +101,10 @@ .popup-body { background-color: #FFF; max-height: 90%; - width: 1200px; + max-width: 1200px; + width: 90%; height: auto; - margin: 2% 5%; + margin: 2% auto; border-radius: 4px; box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.3); overflow: hidden; @@ -602,7 +610,7 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group { } #code-editor .lang-options { - max-width: 400px; + max-width: 480px; margin-bottom: $-s; a { margin-right: $-xs; diff --git a/resources/assets/sass/_forms.scss b/resources/sass/_forms.scss similarity index 94% rename from resources/assets/sass/_forms.scss rename to resources/sass/_forms.scss index 64308b29e..da0f7ef4c 100644 --- a/resources/assets/sass/_forms.scss +++ b/resources/sass/_forms.scss @@ -19,6 +19,9 @@ &.disabled, &[disabled] { background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAMUlEQVQIW2NkwAGuXbv2nxGbHEhCS0uLEUMSJgHShCKJLIEiiS4Bl8QmAZbEJQGSBAC62BuJ+tt7zgAAAABJRU5ErkJggg==); } + &[readonly] { + background-color: #f8f8f8; + } &:focus { border-color: var(--color-primary); outline: 1px solid var(--color-primary); @@ -62,6 +65,13 @@ width: 50%; max-width: 50%; } + &.fullscreen { + position: fixed; + top: 0; + left: 0; + height: 100%; + z-index: 2; + } } @include smaller-than($m) { @@ -71,6 +81,7 @@ #markdown-editor .markdown-editor-wrap { width: 100%; max-width: 100%; + flex-grow: 1; } #markdown-editor .editor-toolbar { padding: 0; @@ -83,12 +94,15 @@ border-bottom: 1px solid #DDD; display: block; } - .markdown-editor-wrap:not(.active) .editor-toolbar + div, .markdown-editor-wrap:not(.active) .editor-toolbar .buttons { + .markdown-editor-wrap:not(.active) .editor-toolbar + div, + .markdown-editor-wrap:not(.active) .editor-toolbar .buttons, + .markdown-editor-wrap:not(.active) .markdown-display { display: none; } #markdown-editor .markdown-editor-wrap:not(.active) { flex-grow: 0; flex: none; + min-height: 0; } } @@ -172,6 +186,11 @@ input[type=date] { input[type=color] { height: 60px; + &.small { + height: 42px; + width: 60px; + padding: 2px; + } } .toggle-switch { diff --git a/resources/assets/sass/_header.scss b/resources/sass/_header.scss similarity index 100% rename from resources/assets/sass/_header.scss rename to resources/sass/_header.scss diff --git a/resources/assets/sass/_html.scss b/resources/sass/_html.scss similarity index 83% rename from resources/assets/sass/_html.scss rename to resources/sass/_html.scss index de48c8ed1..e4a8c14bb 100644 --- a/resources/assets/sass/_html.scss +++ b/resources/sass/_html.scss @@ -1,6 +1,7 @@ * { box-sizing: border-box; - outline-color: #444444; + outline-color: var(--color-primary); + outline-width: 1px; } *:focus { diff --git a/resources/assets/sass/_layout.scss b/resources/sass/_layout.scss similarity index 99% rename from resources/assets/sass/_layout.scss rename to resources/sass/_layout.scss index 1a7ff2cab..a280e4ed1 100644 --- a/resources/assets/sass/_layout.scss +++ b/resources/sass/_layout.scss @@ -116,7 +116,6 @@ body.flexbox { min-height: 0; max-width: 100%; position: relative; - overflow-y: hidden; } .flex { diff --git a/resources/assets/sass/_lists.scss b/resources/sass/_lists.scss similarity index 100% rename from resources/assets/sass/_lists.scss rename to resources/sass/_lists.scss diff --git a/resources/assets/sass/_mixins.scss b/resources/sass/_mixins.scss similarity index 100% rename from resources/assets/sass/_mixins.scss rename to resources/sass/_mixins.scss diff --git a/resources/assets/sass/_pages.scss b/resources/sass/_pages.scss similarity index 97% rename from resources/assets/sass/_pages.scss rename to resources/sass/_pages.scss index 709b1a7ef..9281a2194 100755 --- a/resources/assets/sass/_pages.scss +++ b/resources/sass/_pages.scss @@ -20,10 +20,17 @@ } } -body.mce-fullscreen .page-editor .edit-area { +body.mce-fullscreen .page-editor .edit-area, +body.markdown-fullscreen .page-editor .edit-area { z-index: 12; } +body.mce-fullscreen, body.markdown-fullscreen { + .page-editor, .flex-fill { + overflow: visible; + } +} + @include smaller-than($s) { .page-edit-toolbar { overflow-x: scroll; diff --git a/resources/assets/sass/_reset.scss b/resources/sass/_reset.scss similarity index 100% rename from resources/assets/sass/_reset.scss rename to resources/sass/_reset.scss diff --git a/resources/assets/sass/_spacing.scss b/resources/sass/_spacing.scss similarity index 100% rename from resources/assets/sass/_spacing.scss rename to resources/sass/_spacing.scss diff --git a/resources/assets/sass/_tables.scss b/resources/sass/_tables.scss similarity index 100% rename from resources/assets/sass/_tables.scss rename to resources/sass/_tables.scss diff --git a/resources/assets/sass/_text.scss b/resources/sass/_text.scss similarity index 97% rename from resources/assets/sass/_text.scss rename to resources/sass/_text.scss index 315f08c34..77e0773eb 100644 --- a/resources/assets/sass/_text.scss +++ b/resources/sass/_text.scss @@ -213,6 +213,18 @@ blockquote { } } +.text-mono { + font-family: $mono; +} + +.text-uppercase { + text-transform: uppercase; +} + +.text-capitals { + text-transform: capitalize; +} + .code-base { background-color: #F8F8F8; font-size: 0.80em; @@ -224,7 +236,7 @@ code { @extend .code-base; display: inline; padding: 1px 3px; - white-space:pre; + white-space:pre-wrap; line-height: 1.2em; margin-bottom: 1.2em; } @@ -369,4 +381,3 @@ span.sep { margin-right: $-xs; pointer-events: none; } - diff --git a/resources/assets/sass/_tinymce.scss b/resources/sass/_tinymce.scss similarity index 100% rename from resources/assets/sass/_tinymce.scss rename to resources/sass/_tinymce.scss diff --git a/resources/assets/sass/_variables.scss b/resources/sass/_variables.scss similarity index 100% rename from resources/assets/sass/_variables.scss rename to resources/sass/_variables.scss diff --git a/resources/assets/sass/export-styles.scss b/resources/sass/export-styles.scss similarity index 100% rename from resources/assets/sass/export-styles.scss rename to resources/sass/export-styles.scss diff --git a/resources/assets/sass/print-styles.scss b/resources/sass/print-styles.scss similarity index 100% rename from resources/assets/sass/print-styles.scss rename to resources/sass/print-styles.scss diff --git a/resources/assets/sass/styles.scss b/resources/sass/styles.scss similarity index 100% rename from resources/assets/sass/styles.scss rename to resources/sass/styles.scss diff --git a/resources/views/api-docs/index.blade.php b/resources/views/api-docs/index.blade.php new file mode 100644 index 000000000..ab4db89e8 --- /dev/null +++ b/resources/views/api-docs/index.blade.php @@ -0,0 +1,240 @@ +@extends('simple-layout') + +@section('body') + +
+ +
+
+ + +
+ +
+ +
+

Getting Started

+ +
Authentication
+

+ To access the API a user has to have the "Access System API" permission enabled on one of their assigned roles. + Permissions to content accessed via the API is limited by the roles & permissions assigned to the user that's used to access the API. +

+

Authentication to use the API is primarily done using API Tokens. Once the "Access System API" permission has been assigned to a user, a "API Tokens" section should be visible when editing their user profile. Choose "Create Token" and enter an appropriate name and expiry date, relevant for your API usage then press "Save". A "Token ID" and "Token Secret" will be immediately displayed. These values should be used as a header in API HTTP requests in the following format:

+
Authorization: Token <token_id>:<token_secret>
+

Here's an example of an authorized cURL request to list books in the system:

+
curl --request GET \
+  --url https://example.com/api/books \
+  --header 'Authorization: Token C6mdvEQTGnebsmVn3sFNeeuelGEBjyQp:NOvD3VlzuSVuBPNaf1xWHmy7nIRlaj22'
+

If already logged into the system within the browser, via a user account with permission to access the API, the system will also accept an existing session meaning you can browse API endpoints directly in the browser or use the browser devtools to play with the API.

+ +
+ +
Request Format
+

The API is primarily design to be interfaced using JSON so the majority of API endpoints, that accept data, will read JSON request data although application/x-www-form-urlencoded request data is also accepted. Endpoints that receive file data will need data sent in a multipart/form-data format although this will be highlighted in the documentation for such endpoints.

+

For endpoints in this documentation that accept data, a "Body Parameters" table will be available showing the parameters that will accepted in the request. Any rules for the values of such parameters, such as the data-type or if they're required, will be shown alongside the parameter name.

+ +
+ +
Listing Endpoints
+

Some endpoints will return a list of data models. These endpoints will return an array of the model data under a data property along with a numeric total property to indicate the total number of records found for the query within the system. Here's an example of a listing response:

+
{
+  "data": [
+    {
+      "id": 1,
+      "name": "BookStack User Guide",
+      "slug": "bookstack-user-guide",
+      "description": "This is a general guide on using BookStack on a day-to-day basis.",
+      "created_at": "2019-05-05 21:48:46",
+      "updated_at": "2019-12-11 20:57:31",
+      "created_by": 1,
+      "updated_by": 1,
+      "image_id": 3
+    }
+  ],
+  "total": 16
+}
+

+ There are a number of standard URL parameters that can be supplied to manipulate and page through the results returned from a listing endpoint: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDetailsExamples
count + Specify how many records will be returned in the response.
+ (Default: {{ config('api.default_item_count') }}, Max: {{ config('api.max_item_count') }}) +
Limit the count to 50
?count=50
offset + Specify how many records to skip over in the response.
+ (Default: 0) +
Skip over the first 100 records
?offset=100
sort + Specify what field is used to sort the data and the direction of the sort (Ascending or Descending).
+ Value is the name of a field, A + or - prefix dictates ordering.
+ Direction defaults to ascending.
+ Can use most fields shown in the response. +
+ Sort by name ascending
?sort=+name

+ Sort by "Created At" date descending
?sort=-created_at +
filter[<field>] + Specify a filter to be applied to the query. Can use most fields shown in the response.
+ By default a filter will apply a "where equals" query but the below operations are available using the format filter[<field>:<operation>]
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
eqWhere <field> equals the filter value.
neWhere <field> does not equal the filter value.
gtWhere <field> is greater than the filter value.
ltWhere <field> is less than the filter value.
gteWhere <field> is greater than or equal to the filter value.
lteWhere <field> is less than or equal to the filter value.
like + Where <field> is "like" the filter value.
+ % symbols can be used as wildcards. +
+
+ Filter where id is 5:
?filter[id]=5

+ Filter where id is not 5:
?filter[id:ne]=5

+ Filter where name contains "cat":
?filter[name:like]=%cat%

+ Filter where created after 2020-01-01:
?filter[created_at:gt]=2020-01-01 +
+ +
+ +
Error Handling
+

+ Successful responses will return a 200 or 204 HTTP response code. Errors will return a 4xx or a 5xx HTTP response code depending on the type of error. Errors follow a standard format as shown below. The message provided may be translated depending on the configured language of the system in addition to the API users' language preference. The code provided in the JSON response will match the HTTP response code. +

+ +
{
+	"error": {
+		"code": 401,
+		"message": "No authorization token found on the request"
+	}
+}
+
+ +
+ + @foreach($docs as $model => $endpoints) +
+

{{ $model }}

+ + @foreach($endpoints as $endpoint) +
{{ $endpoint['controller_method'] }}
+
+ {{ $endpoint['method'] }} + {{ url($endpoint['uri']) }} +
+

{{ $endpoint['description'] ?? '' }}

+ @if($endpoint['body_params'] ?? false) +
+ Body Parameters + + + + + + @foreach($endpoint['body_params'] as $paramName => $rules) + + + + + @endforeach +
Param NameValue Rules
{{ $paramName }} + @foreach($rules as $rule) + {{ $rule }} + @endforeach +
+
+ @endif + @if($endpoint['example_request'] ?? false) +
+ Example Request +
{{ $endpoint['example_request'] }}
+
+ @endif + @if($endpoint['example_response'] ?? false) +
+ Example Response +
{{ $endpoint['example_response'] }}
+
+ @endif + @if(!$loop->last) +
+ @endif + @endforeach +
+ @endforeach +
+ +
+ + +
+@stop \ No newline at end of file diff --git a/resources/views/auth/forms/login/ldap.blade.php b/resources/views/auth/forms/login/ldap.blade.php index f7903e18c..92eba80e8 100644 --- a/resources/views/auth/forms/login/ldap.blade.php +++ b/resources/views/auth/forms/login/ldap.blade.php @@ -1,19 +1,28 @@ -
- - @include('form.text', ['name' => 'username', 'tabindex' => 1]) -
+
+ {!! csrf_field() !!} -@if(session('request-email', false) === true) -
- - @include('form.text', ['name' => 'email', 'tabindex' => 1]) - - {{ trans('auth.ldap_email_hint') }} - +
+
+ + @include('form.text', ['name' => 'username', 'autofocus' => true]) +
+ + @if(session('request-email', false) === true) +
+ + @include('form.text', ['name' => 'email']) + {{ trans('auth.ldap_email_hint') }} +
+ @endif + +
+ + @include('form.password', ['name' => 'password']) +
+ +
+ +
-@endif -
- - @include('form.password', ['name' => 'password', 'tabindex' => 1]) -
\ No newline at end of file + \ No newline at end of file diff --git a/resources/views/auth/forms/login/saml2.blade.php b/resources/views/auth/forms/login/saml2.blade.php new file mode 100644 index 000000000..aa1913e31 --- /dev/null +++ b/resources/views/auth/forms/login/saml2.blade.php @@ -0,0 +1,11 @@ +
+ {!! csrf_field() !!} + +
+ +
+ +
\ No newline at end of file diff --git a/resources/views/auth/forms/login/standard.blade.php b/resources/views/auth/forms/login/standard.blade.php index dc6081637..87603e2cb 100644 --- a/resources/views/auth/forms/login/standard.blade.php +++ b/resources/views/auth/forms/login/standard.blade.php @@ -1,12 +1,36 @@ -
- - @include('form.text', ['name' => 'email', 'tabindex' => 1]) -
+
+ {!! csrf_field() !!} + +
+
+ + @include('form.text', ['name' => 'email', 'autofocus' => true]) +
+ +
+ + @include('form.password', ['name' => 'password']) + +
+
+ +
+
+ @include('components.custom-checkbox', [ + 'name' => 'remember', + 'checked' => false, + 'value' => 'on', + 'label' => trans('auth.remember_me'), + ]) +
+ +
+ +
+
+ +
+ -
- - @include('form.password', ['name' => 'password', 'tabindex' => 1]) - - {{ trans('auth.forgot_password') }} - -
diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index 438339e92..0a21a0f62 100644 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -7,32 +7,9 @@
 
-

{{ title_case(trans('auth.log_in')) }}

+

{{ Str::title(trans('auth.log_in')) }}

-
- {!! csrf_field() !!} - -
- @include('auth.forms.login.' . $authMethod) -
- -
-
- @include('components.custom-checkbox', [ - 'name' => 'remember', - 'checked' => false, - 'value' => 'on', - 'tabindex' => 1, - 'label' => trans('auth.remember_me'), - ]) -
- -
- -
-
- -
+ @include('auth.forms.login.' . $authMethod) @if(count($socialDrivers) > 0)
@@ -46,7 +23,7 @@ @endforeach @endif - @if(setting('registration-enabled', false)) + @if(setting('registration-enabled') && config('auth.method') === 'standard')
-@stop \ No newline at end of file +@stop diff --git a/resources/views/auth/register.blade.php b/resources/views/auth/register.blade.php index 60ceba93c..1625ebc4c 100644 --- a/resources/views/auth/register.blade.php +++ b/resources/views/auth/register.blade.php @@ -6,7 +6,7 @@
 
-

{{ title_case(trans('auth.sign_up')) }}

+

{{ Str::title(trans('auth.sign_up')) }}

{!! csrf_field() !!} @@ -49,6 +49,7 @@
@endforeach @endif +
@stop diff --git a/resources/views/books/create.blade.php b/resources/views/books/create.blade.php index 6de81cd46..db3e90e51 100644 --- a/resources/views/books/create.blade.php +++ b/resources/views/books/create.blade.php @@ -28,7 +28,7 @@

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

- @include('books.form') + @include('books.form', ['returnLocation' => isset($bookshelf) ? $bookshelf->getUrl() : url('/books')])
diff --git a/resources/views/books/edit.blade.php b/resources/views/books/edit.blade.php index 400fd6e81..ac11b58e2 100644 --- a/resources/views/books/edit.blade.php +++ b/resources/views/books/edit.blade.php @@ -18,7 +18,7 @@

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

- @include('books.form', ['model' => $book]) + @include('books.form', ['model' => $book, 'returnLocation' => $book->getUrl()])
diff --git a/resources/views/books/export.blade.php b/resources/views/books/export.blade.php index 4a7c45e0b..1cf91046d 100644 --- a/resources/views/books/export.blade.php +++ b/resources/views/books/export.blade.php @@ -58,7 +58,7 @@

{{ $bookChild->name }}

@if($bookChild->isA('chapter')) -

{{ $bookChild->text }}

+

{{ $bookChild->description }}

@if(count($bookChild->pages) > 0) @foreach($bookChild->pages as $page) diff --git a/resources/views/books/form.blade.php b/resources/views/books/form.blade.php index 8960b4135..a3235036e 100644 --- a/resources/views/books/form.blade.php +++ b/resources/views/books/form.blade.php @@ -31,11 +31,11 @@
- @include('components.tag-manager', ['entity' => isset($book)?$book:null, 'entityType' => 'chapter']) + @include('components.tag-manager', ['entity' => $book ?? null, 'entityType' => 'chapter'])
- {{ trans('common.cancel') }} + {{ trans('common.cancel') }}
\ No newline at end of file diff --git a/resources/views/books/list.blade.php b/resources/views/books/list.blade.php index 871d931f1..42a2757f9 100644 --- a/resources/views/books/list.blade.php +++ b/resources/views/books/list.blade.php @@ -4,7 +4,11 @@

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

- @include('partials.sort', ['options' => $sortOptions, 'order' => $order, 'sort' => $sort, 'type' => 'books']) + @include('partials.sort', ['options' => [ + 'name' => trans('common.sort_name'), + 'created_at' => trans('common.sort_created_at'), + 'updated_at' => trans('common.sort_updated_at'), + ], 'order' => $order, 'sort' => $sort, 'type' => 'books'])
diff --git a/resources/views/common/header.blade.php b/resources/views/common/header.blade.php index 192996950..7c837ec29 100644 --- a/resources/views/common/header.blade.php +++ b/resources/views/common/header.blade.php @@ -42,7 +42,7 @@ @endif @if(!signedInUser()) - @if(setting('registration-enabled', false)) + @if(setting('registration-enabled') && config('auth.method') === 'standard') @icon('new-user') {{ trans('auth.sign_up') }} @endif @icon('login') {{ trans('auth.log_in') }} @@ -64,7 +64,11 @@ id}") }}">@icon('edit'){{ trans('common.edit_profile') }}
  • - @icon('logout'){{ trans('auth.logout') }} + @if(config('auth.method') === 'saml2') + @icon('logout'){{ trans('auth.logout') }} + @else + @icon('logout'){{ trans('auth.logout') }} + @endif
  • diff --git a/resources/views/components/code-editor.blade.php b/resources/views/components/code-editor.blade.php index 31a583182..70ffc350f 100644 --- a/resources/views/components/code-editor.blade.php +++ b/resources/views/components/code-editor.blade.php @@ -18,14 +18,16 @@ C# Go HTML + INI Java JavaScript JSON Lua - PHP - Powershell MarkDown Nginx + Pascal + PHP + Powershell Python Ruby Shell/Bash diff --git a/resources/views/components/custom-checkbox.blade.php b/resources/views/components/custom-checkbox.blade.php index 6ba2f457f..2bf4e2232 100644 --- a/resources/views/components/custom-checkbox.blade.php +++ b/resources/views/components/custom-checkbox.blade.php @@ -3,12 +3,10 @@ $name $value $checked $label -$tabindex --}}