Initial commit: Pireon Admin — headless admin panel and public API

Laravel 13 + Filament 5 admin panel and REST API for a non-profit developer
collective, backed by the Pireon OAuth identity server. The public site is a
separate, server-rendered application consuming /api/public/v1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-19 17:55:27 +02:00
commit 3897113313
534 changed files with 64050 additions and 0 deletions

119
lang/en/actions.php Normal file
View File

@@ -0,0 +1,119 @@
<?php
declare(strict_types=1);
return [
'accept' => 'Accept',
'action' => 'Action',
'actions' => 'Actions',
'add' => 'Add',
'admin' => 'Admin',
'agree' => 'Agree',
'archive' => 'Archive',
'assign' => 'Assign',
'associate' => 'Associate',
'attach' => 'Attach',
'browse' => 'Browse',
'cancel' => 'Cancel',
'choose' => 'Choose',
'choose_file' => 'Choose File',
'choose_image' => 'Choose Image',
'click_to_copy' => 'Click to copy',
'close' => 'Close',
'collapse' => 'Collapse',
'collapse_all' => 'Collapse All',
'comment' => 'Comment',
'confirm' => 'Confirm',
'connect' => 'Connect',
'create' => 'Create',
'delete' => 'Delete',
'detach' => 'Detach',
'details' => 'Details',
'disable' => 'Disable',
'discard' => 'Discard',
'done' => 'Done',
'down' => 'Down',
'duplicate' => 'Duplicate',
'edit' => 'Edit',
'enable' => 'Enable',
'expand' => 'Expand',
'expand_all' => 'Expand All',
'explanation' => 'Explanation',
'export' => 'Export',
'file' => 'File',
'files' => 'Files',
'go_home' => 'Go Home',
'hide' => 'Hide',
'home' => 'Home',
'image' => 'Image',
'impersonate' => 'Impersonate',
'impersonation' => 'Impersonation',
'import' => 'Import',
'introduction' => 'Introduction',
'like' => 'Like',
'load' => 'Load',
'localize' => 'Localize',
'log_in' => 'Log In',
'log_out' => 'Log Out',
'named' => [
'add' => 'Add :name',
'choose' => 'Choose :name',
'create' => 'Create :name',
'delete' => 'Delete :name',
'duplicate' => 'Duplicate :name',
'edit' => 'Edit :name',
'export' => 'Export :name',
'hide' => 'Hide :name',
'import' => 'Import :name',
'new' => 'New :name',
'restore' => 'Restore :name',
'save' => 'Save :name',
'search' => 'Search :name',
'show' => 'Show :name',
'update' => 'Update :name',
'view' => 'View :name',
],
'new' => 'New',
'no' => 'No',
'open' => 'Open',
'open_website' => 'Open on the website',
'preview' => 'Preview',
'price' => 'Price',
'record' => 'Record',
'restore' => 'Restore',
'save' => 'Save',
'save_and_close' => 'Save & Close',
'save_and_return' => 'Save & Return',
'search' => 'Search',
'select' => 'Select',
'select_all' => 'Select All',
'send' => 'Send',
'settings' => 'Settings',
'show' => 'Show',
'show_all' => 'Show All',
'sign_in' => 'Sign In',
'solve' => 'Solve',
'start' => 'Start',
'stop' => 'Stop',
'submit' => 'Submit',
'subscribe' => 'Subscribe',
'switch' => 'Switch',
'switch_to_role' => 'Switch To Role',
'tag' => 'Tag',
'tags' => 'Tags',
'target_link' => [
'blank' => 'Open in a new window',
'parent' => 'Open in a parent frame',
'self' => 'Open in a current window',
'top' => 'Open in the topmost frame',
],
'translate' => 'Translate',
'translate_it' => 'Translate It',
'unpack' => 'Unpack',
'unsubscribe' => 'Unsubscribe',
'up' => 'Up',
'update' => 'Update',
'user' => 'User',
'view' => 'View',
'yes' => 'Yes',
];

9
lang/en/auth.php Normal file
View File

@@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
return [
'failed' => 'These credentials do not match our records.',
'password' => 'The provided password is incorrect.',
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
];

28
lang/en/console.php Normal file
View File

@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
return [
'prune' => [
'dry_run' => 'Dry run: nothing is deleted.',
'revisions' => 'Old history entries',
'trash' => 'Records erased for good',
'media' => 'Images nothing points at',
'missing_urls' => 'One-off 404s nobody asked for again',
'views' => 'Old reading figures',
],
'types' => [
'no_spec' => 'No specification published at public/openapi.yaml.',
'current' => 'The types are up to date.',
'stale' => 'The types no longer match the specification. Run: php artisan api:types',
'written' => ':count schemas written to :path',
],
'schedule' => [
'closed' => 'closed (its date passed)',
'pending' => 'Waiting for their publication date',
'off_site' => 'Off the site because they expired',
'summary' => '{0}No calls needed closing.|{1}Closed 1 expired call.|[2,*]Closed :count expired calls.',
],
];

7
lang/en/docs.php Normal file
View File

@@ -0,0 +1,7 @@
<?php
declare(strict_types=1);
return [
'title' => 'API documentation',
];

68
lang/en/enums.php Normal file
View File

@@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
return [
'page_status' => [
'draft' => 'Draft',
'review' => 'In review',
'published' => 'Published',
'archived' => 'Archived',
],
'project_status' => [
'idea' => 'Idea',
'active' => 'Active',
'paused' => 'Paused',
'completed' => 'Completed',
'archived' => 'Archived',
],
'missing_url_status' => [
'pending' => 'Undecided',
'resolved' => 'Resolved',
'ignored' => 'Ignored',
],
'review_event' => [
'requested' => 'Review asked for',
'returned' => 'Sent back',
'published' => 'Published',
'commented' => 'Comment',
],
'call_status' => [
'open' => 'Open',
'filled' => 'Filled',
'closed' => 'Closed',
],
'application_status' => [
'new' => 'Unanswered',
'contacted' => 'Contacted',
'accepted' => 'Accepted',
'declined' => 'Declined',
'spam' => 'Spam',
],
'application_kind' => [
'contribute' => 'Offering help',
'request' => 'Asking for help',
],
'radar_ring' => [
'adopt' => 'Adopt',
'trial' => 'Trial',
'assess' => 'Assess',
'hold' => 'Hold',
],
'technology_category' => [
'language' => 'Language',
'framework' => 'Framework',
'datastore' => 'Datastore',
'infrastructure' => 'Infrastructure',
'tool' => 'Tool',
'practice' => 'Practice',
],
];

149
lang/en/health.php Normal file
View File

@@ -0,0 +1,149 @@
<?php
declare(strict_types=1);
return [
'title' => 'Site health',
'subheading' => 'What is wrong with the public site and cannot be seen from here.',
'all_clear' => 'All clear. Nothing to fix.',
'problem_summary' => '{1}1 thing to look at|[2,*]:count things to look at',
'problem_hint' => 'The site lives elsewhere, so these faults do not show up while editing — they show up while visiting.',
'passing' => '{1}1 check passing|[2,*]:count checks passing',
'and_more' => 'and :count more',
'refreshed' => 'Checks refreshed',
'severity' => [
'ok' => 'Fine',
'warning' => 'Warning',
'error' => 'Fault',
],
'actions' => [
'refresh' => 'Check again',
'go_fix' => 'Go and fix it',
],
'bits' => [
'description' => 'no meta description',
'cover' => 'no cover',
'gallery_image' => 'Gallery image with no description',
'itself' => 'itself',
],
'checks' => [
'missing-slugs' => [
'title' => 'Missing slugs',
'ok' => 'Everything translated has its slug.',
'problem' => '{1}1 record is translated into a language but has no slug in it, so its URL in that language either does not exist or 404s.|[2,*]:count records are translated into a language without a slug in it, so those URLs either do not exist or 404.',
],
'duplicate-slugs' => [
'title' => 'Duplicate slugs',
'ok' => 'Every URL resolves to a single record.',
'problem' => '{1}1 slug is repeated within the same language: the API resolves that URL to whichever record it reaches first.|[2,*]:count slugs are repeated within the same language: the API resolves those URLs to whichever record it reaches first.',
],
'broken-images' => [
'title' => 'Broken images',
'ok' => 'Every image file is where it should be.',
'problem' => '{1}1 image the site is publishing no longer exists on disk, or could not be read.|[2,*]:count images the site is publishing no longer exist on disk, or could not be read.',
],
'missing-translations' => [
'title' => 'Untranslated content',
'ok' => 'Everything published exists in all three languages.',
'problem' => '{1}1 published record is missing a translation, so that language of the site goes without it.|[2,*]:count published records are missing a translation, so those languages of the site go without them.',
],
'images-without-alt' => [
'title' => 'Images with no description',
'ok' => 'Every published image has alt text.',
'problem' => '{1}1 published image has no alt text: anyone who cannot see it does not know it is there.|[2,*]:count published images have no alt text: anyone who cannot see them does not know they are there.',
],
'incomplete-seo' => [
'title' => 'Incomplete entries',
'ok' => 'Everything published has a description and a cover.',
'problem' => '{1}1 published record has nothing to show in a search result or when the link is pasted into a chat.|[2,*]:count published records have nothing to show in a search result or when the link is pasted into a chat.',
],
'expired-calls' => [
'title' => 'Expired calls',
'ok' => 'No open call is past its closing date.',
'problem' => '{1}1 call is still marked open with its closing date past. It has already dropped off the site, but it pads the panel\'s counter.|[2,*]:count calls are still marked open with their closing date past. They have already dropped off the site, but they pad the panel\'s counter.',
],
'unanswered-submissions' => [
'title' => 'People waiting for an answer',
'ok' => 'Nobody has been waiting more than a week.',
'problem' => '{1}1 person wrote in over a week ago and still has no answer.|[2,*]:count people wrote in over a week ago and still have no answer.',
],
'stalled-media' => [
'title' => 'Unprocessed images',
'ok' => 'No image is waiting to be processed.',
'problem' => '{1}1 image has been waiting over an hour: most likely neither a queue worker nor the scheduler is running.|[2,*]:count images have been waiting over an hour: most likely neither a queue worker nor the scheduler is running.',
],
'services-without-work' => [
'title' => 'Services with nothing behind them',
'ok' => 'Every published service shows real work.',
'problem' => '{1}1 published service links no published project: that is a promise, not an offer.|[2,*]:count published services link no published project: those are promises, not offers.',
],
'clients-without-logo' => [
'title' => 'Clients with no logo',
'ok' => 'Every client on the wall has a logo.',
'problem' => '{1}1 client appears on the wall of logos without one: a hole that looks like a mistake.|[2,*]:count clients appear on the wall of logos without one: holes that look like mistakes.',
],
'testimonials-missing-original' => [
'title' => 'Quotes without the original',
'ok' => 'Every quote carries the words that were actually said.',
'problem' => '{1}1 testimonial has no quote in the language it was given in: the site is publishing a translation of something nobody can check.|[2,*]:count testimonials have no quote in the language they were given in: the site is publishing translations of things nobody can check.',
],
'talks-without-speaker' => [
'title' => 'Talks with no speaker',
'ok' => 'Every talk credits somebody.',
'problem' => '{1}1 talk does not say who gave it, so it appears on nobody\'s profile.|[2,*]:count talks do not say who gave them, so they appear on nobody\'s profile.',
],
'broken-redirects' => [
'title' => 'Broken redirects',
'ok' => 'No redirect loops or chains into another.',
'problem' => '{1}1 redirect points at itself or at another redirect: the browser loops, or pays an extra hop.|[2,*]:count redirects point at themselves or at another redirect: the browser loops, or pays extra hops.',
],
'redirects-to-nowhere' => [
'title' => 'Redirects to nowhere',
'ok' => 'Every redirect lands on a page that exists.',
'problem' => '{1}1 redirect lands on an address that no longer answers: worse than the 404 it was meant to prevent.|[2,*]:count redirects land on addresses that no longer answer: worse than the 404s they were meant to prevent.',
],
'missing-urls' => [
'title' => 'Addresses nobody can reach',
'ok' => 'No broken address is waiting for a redirect.',
'problem' => '{1}1 address returns 404 and has been asked for more than once: every visitor arriving that way is lost.|[2,*]:count addresses return 404 and have been asked for more than once: every visitor arriving that way is lost.',
],
'stale-reviews' => [
'title' => 'Reviews nobody answered',
'ok' => 'Nobody is waiting for a review.',
'problem' => '{1}1 thing has been waiting for review for over a week: whoever wrote it thinks something is happening.|[2,*]:count things have been waiting for review for over a week: whoever wrote them thinks something is happening.',
],
'stale-translations' => [
'title' => 'Translations left behind',
'ok' => 'No translation has fallen behind its original.',
'problem' => '{1}1 translated record says something its original stopped saying: the translation exists, so nothing else flags it.|[2,*]:count translated records say something their originals stopped saying: the translations exist, so nothing else flags them.',
],
'stale-repositories' => [
'title' => 'Repositories that will not sync',
'ok' => 'Every repository is syncing.',
'problem' => '{1}1 repository has failed several attempts. The site keeps showing its last figures, which are no longer true.|[2,*]:count repositories have failed several attempts. The site keeps showing their last figures, which are no longer true.',
],
],
];

84
lang/en/http-statuses.php Normal file
View File

@@ -0,0 +1,84 @@
<?php
declare(strict_types=1);
return [
'0' => 'Unknown Error',
'100' => 'Continue',
'101' => 'Switching Protocols',
'102' => 'Processing',
'200' => 'OK',
'201' => 'Created',
'202' => 'Accepted',
'203' => 'Non-Authoritative Information',
'204' => 'No Content',
'205' => 'Reset Content',
'206' => 'Partial Content',
'207' => 'Multi-Status',
'208' => 'Already Reported',
'226' => 'IM Used',
'300' => 'Multiple Choices',
'301' => 'Moved Permanently',
'302' => 'Found',
'303' => 'See Other',
'304' => 'Not Modified',
'305' => 'Use Proxy',
'307' => 'Temporary Redirect',
'308' => 'Permanent Redirect',
'400' => 'Bad Request',
'401' => 'Unauthorized',
'402' => 'Payment Required',
'403' => 'Forbidden',
'404' => 'Not Found',
'405' => 'Method Not Allowed',
'406' => 'Not Acceptable',
'407' => 'Proxy Authentication Required',
'408' => 'Request Timeout',
'409' => 'Conflict',
'410' => 'Gone',
'411' => 'Length Required',
'412' => 'Precondition Failed',
'413' => 'Payload Too Large',
'414' => 'URI Too Long',
'415' => 'Unsupported Media Type',
'416' => 'Range Not Satisfiable',
'417' => 'Expectation Failed',
'418' => 'I\'m a teapot',
'419' => 'Session Has Expired',
'421' => 'Misdirected Request',
'422' => 'Unprocessable Entity',
'423' => 'Locked',
'424' => 'Failed Dependency',
'425' => 'Too Early',
'426' => 'Upgrade Required',
'428' => 'Precondition Required',
'429' => 'Too Many Requests',
'431' => 'Request Header Fields Too Large',
'444' => 'Connection Closed Without Response',
'449' => 'Retry With',
'451' => 'Unavailable For Legal Reasons',
'499' => 'Client Closed Request',
'500' => 'Internal Server Error',
'501' => 'Not Implemented',
'502' => 'Bad Gateway',
'503' => 'Maintenance Mode',
'504' => 'Gateway Timeout',
'505' => 'HTTP Version Not Supported',
'506' => 'Variant Also Negotiates',
'507' => 'Insufficient Storage',
'508' => 'Loop Detected',
'509' => 'Bandwidth Limit Exceeded',
'510' => 'Not Extended',
'511' => 'Network Authentication Required',
'520' => 'Unknown Error',
'521' => 'Web Server is Down',
'522' => 'Connection Timed Out',
'523' => 'Origin Is Unreachable',
'524' => 'A Timeout Occurred',
'525' => 'SSL Handshake Failed',
'526' => 'Invalid SSL Certificate',
'527' => 'Railgun Error',
'598' => 'Network Read Timeout Error',
'599' => 'Network Connect Timeout Error',
'unknownError' => 'Unknown Error',
];

34
lang/en/maintenance.php Normal file
View File

@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
return [
'title' => 'Maintenance mode',
'subheading' => 'Affects the public site only. The panel and the admin API keep working.',
'badge' => 'Site down',
'status_up' => 'The public site is up.',
'status_down' => 'The public site is in maintenance.',
'since' => 'Since :time',
'lifts_at' => 'lifts at :time',
'panel_unaffected' => 'You can keep editing: the panel is unaffected.',
'notice' => 'Notice for visitors',
'notice_hint' => 'Returned by the public API in the 503 so the frontend can render it. Left empty, the default text is used.',
'default_message' => 'We are making changes to the site. Back shortly.',
'until' => 'Lifts automatically',
'until_hint' => 'Optional. Stops a forgotten maintenance from leaving the site down indefinitely.',
'enable' => 'Enable maintenance',
'enable_confirm' => 'Visitors will stop seeing the site and get the notice instead. The panel stays available.',
'disable' => 'Lift maintenance',
'save_message' => 'Save notice',
'enabled_notice' => 'The public site is now in maintenance',
'disabled_notice' => 'The public site is up again',
'message_saved' => 'Notice saved',
'bypass_hint' => 'The team can still see the real site using the preview token or from a trusted IP (SITE_TRUSTED_IPS).',
'no_permission' => 'You do not have permission to enable or lift maintenance.',
];

8
lang/en/pagination.php Normal file
View File

@@ -0,0 +1,8 @@
<?php
declare(strict_types=1);
return [
'next' => 'Next &raquo;',
'previous' => '&laquo; Previous',
];

842
lang/en/panel.php Normal file
View File

@@ -0,0 +1,842 @@
<?php
declare(strict_types=1);
return [
'untitled' => 'Untitled',
'duplicates' => [
'title' => 'Similar title',
'body' => 'Something very similar already exists: :titles',
'open' => 'Open existing record',
],
'sessions' => [
'title' => 'Sessions',
'this_one' => 'This session',
'unknown_device' => 'Unknown device',
'fields' => [
'ip_address' => 'IP address',
'device' => 'Device',
'last_activity' => 'Last activity',
],
'actions' => [
'revoke' => 'Sign out',
],
'revoked' => 'Session ended. That connection stops being valid on its next request.',
'empty' => [
'heading' => 'No open sessions',
'description' => 'Nobody has signed in with this account, or it has been idle for a while.',
],
],
'environment' => [
'production' => 'Production — this is real',
'other' => ':name environment',
],
'concurrency' => [
'title' => 'Not saved',
'body' => 'Somebody else changed this while you were editing it. Reload the page to see the current version — saving now would overwrite that change.',
'body_with_author' => ':name changed this while you were editing it. Reload the page to see their version — saving now would overwrite that change.',
],
'presence' => [
'title' => 'Somebody else has this open',
'body' => 'Also editing this right now: :names.',
],
'groups' => [
'collective' => 'Collective',
'content' => 'Content',
'administration' => 'Administration',
],
'language' => [
'label' => 'Language',
'switch' => 'Change language',
],
'pages' => [
'label' => 'Page',
'plural' => 'Pages',
'sections' => [
'content' => 'Content',
'content_hint' => 'Each tab is a language. The primary language is required; the others fall back to it when left empty.',
'publishing' => 'Publishing',
'seo' => 'SEO',
'seo_hint' => 'Metadata for search engines and social networks.',
],
'fields' => [
'title' => 'Title',
'slug' => 'Slug',
'excerpt' => 'Excerpt',
'body' => 'Body',
'meta_title' => 'Meta title',
'meta_description' => 'Meta description',
'category' => 'Category',
'author' => 'Author',
'status' => 'Status',
'featured_image' => 'Featured image',
'featured_image_alt' => 'Alt text',
'featured_image_alt_hint' => 'What the image shows, for someone who cannot see it. Leave empty if it is purely decorative.',
'is_featured' => 'Featured',
'published_at' => 'Published at',
'published_at_hint' => 'With a future date the page stays off the site until it arrives.',
'unpublish_at' => 'Take down on',
'unpublish_at_hint' => 'Optional. When it arrives the page drops off the site by itself. For notices with an expiry.',
'translations' => 'Translations',
],
'filters' => [
'translated_in' => 'Translated into',
'missing_translation' => 'Missing translation for',
],
'actions' => [
'publish' => 'Publish',
'unpublish' => 'Unpublish',
],
],
'categories' => [
'label' => 'Category',
'plural' => 'Categories',
'fields' => [
'name' => 'Name',
'slug' => 'Slug',
'description' => 'Description',
'color' => 'Colour',
'position' => 'Order',
'is_visible' => 'Visible',
'pages_count' => 'Pages',
],
],
'users' => [
'label' => 'User',
'plural' => 'Users',
'sections' => [
'identity' => 'Identity',
'identity_hint' => 'Managed by the OAuth server. Refreshed automatically on every sign-in.',
'access' => 'Access and permissions',
'access_hint' => 'Managed by this application.',
],
'fields' => [
'name' => 'Name',
'email' => 'Email',
'oauth_id' => 'OAuth server ID',
'roles' => 'Roles',
'locale' => 'Preferred language',
'is_active' => 'Active',
'last_login_at' => 'Last sign-in',
'remote_roles' => 'Remote roles',
'never' => 'Never',
],
'actions' => [
'activate' => 'Activate',
'deactivate' => 'Deactivate',
],
],
'roles' => [
'label' => 'Role',
'plural' => 'Roles',
'fields' => [
'name' => 'Name',
'permissions' => 'Permissions',
'users_count' => 'Users',
],
'protected' => 'Protected role: it cannot be deleted.',
'select_all' => 'Select all',
],
'permissions' => [
'groups' => [
'general' => 'General',
'projects' => 'Projects',
'members' => 'Members',
'services' => 'Services',
'clients' => 'Clients',
'testimonials' => 'Testimonials',
'talks' => 'Talks',
'technologies' => 'Technologies',
'calls' => 'Calls for help',
'applications' => 'Inbox',
'repositories' => 'Repositories',
'media' => 'Media',
'redirects' => 'Redirects',
'pages' => 'Pages',
'categories' => 'Categories',
'users' => 'Users',
'roles' => 'Roles',
'settings' => 'Settings',
],
'abilities' => [
'sync' => 'Sync',
'maintenance' => 'Toggle maintenance mode',
'panel_access' => 'Access the panel',
'view_any' => 'List',
'view' => 'View details',
'create' => 'Create',
'update' => 'Edit',
'delete' => 'Delete',
'restore' => 'Restore',
'force_delete' => 'Delete permanently',
'publish' => 'Publish',
],
],
'actions' => [
'duplicate' => 'Duplicate',
'duplicate_heading' => 'Duplicate this record',
'duplicated' => 'Duplicated. Give it a slug and a date before publishing it.',
],
'preview' => [
'label' => 'Preview',
'heading' => 'Preview links',
'hint' => 'Shareable, and they expire in :hours hours. Each one only works for this record.',
'open' => 'Open',
],
'trash' => [
'title' => 'Trash',
'subheading' => 'Everything deleted, together, with the undo button next to it.',
'empty' => 'The trash is empty.',
'deleted_at' => 'Deleted :when',
'restore' => 'Restore',
'erase' => 'Erase',
'erase_confirm' => 'This cannot be undone. Are you sure?',
'restored' => 'Restored',
'erased' => 'Erased for good',
],
'today' => [
'all_clear' => 'Nothing is waiting',
'all_clear_hint' => 'Nobody unanswered, nothing half-finished.',
],
'widgets' => [
'stats' => [
'pages' => 'Pages',
'published' => 'Published',
'users' => 'Active users',
'missing_translations' => 'Untranslated',
'missing_translations_hint' => 'Pages missing at least one language',
'projects' => 'Projects',
'projects_description' => 'Published projects',
'active_projects' => 'Active projects',
'active_projects_description' => 'Seeking contributors',
'members' => 'Members',
'members_description' => 'Active collective members',
'open_calls' => 'Open calls',
'open_calls_description' => 'Seeking participants',
'good_first_issues' => 'Good first issues',
'good_first_issues_description' => 'Available to claim',
'help_wanted' => 'Help wanted',
'help_wanted_description' => 'Open issues',
],
'growth_chart' => 'Growth over time',
'growth' => [
'projects' => 'Projects',
'members' => 'Members',
'issues' => 'Good first issues',
],
'languages_chart' => 'Languages distribution',
'languages' => [
'repositories' => 'Repositories',
],
],
'projects' => [
'label' => 'Project',
'plural' => 'Projects',
'sections' => [
'content' => 'Content',
'writeup' => 'Decisions and postmortem',
'writeup_hint' => 'What a consultancy cannot publish and you can. This is the content other developers actually read.',
'details' => 'Details',
],
'fields' => [
'title' => 'Title',
'slug' => 'Slug',
'tagline' => 'Tagline',
'description' => 'Description',
'decisions' => 'Technical decisions',
'decisions_hint' => 'Why you chose what you chose, and what you ruled out.',
'postmortem' => 'Postmortem',
'postmortem_hint' => 'What went wrong and what you learned. It does not have to be a success story.',
'status' => 'Status',
'published_at' => 'Published at',
'unpublish_at' => 'Take down on',
'unpublish_at_hint' => 'Optional. When it arrives the project drops off the site by itself.',
'published_at_hint' => 'Empty = not visible on the public site.',
'technologies' => 'Technologies',
'lead' => 'Lead',
'members' => 'Contributors',
'client' => 'Who for',
'client_hint' => 'The NGO, association or organisation it was built for. If it is not on the list, you can create it right here.',
'services' => 'Services',
'demo_url' => 'Demo',
'cover_image' => 'Cover image',
'cover_image_alt' => 'Alt text',
'cover_image_alt_hint' => 'What the cover shows, for someone who cannot see it. Leave empty if it is purely decorative.',
'started_at' => 'Started',
'ended_at' => 'Ended',
'is_featured' => 'Featured',
'needs_help' => 'Looking for help',
'needs_help_hint' => 'Surfaces it in the contribute section of the site.',
],
'filters' => ['unpublished' => 'Unpublished'],
'actions' => ['publish' => 'Publish'],
],
'members' => [
'label' => 'Member',
'plural' => 'Members',
'sections' => [
'profile' => 'Public profile',
'profile_hint' => 'This is each person\'s shop window — the currency volunteer work is paid in.',
'membership' => 'Membership',
],
'fields' => [
'name' => 'Name',
'slug' => 'Slug',
'headline' => 'Headline',
'bio' => 'Bio',
'avatar' => 'Photo',
'avatar_hint' => 'The alt text is the person\'s name, so there is nothing to write.',
'github_username' => 'GitHub username',
'user' => 'Panel account',
'user_hint' => 'Optional. Most members never need admin access.',
'technologies' => 'Technologies',
'projects' => 'Projects',
'is_public' => 'Visible on the site',
'is_founder' => 'Founder',
'position' => 'Order',
'joined_at' => 'Joined',
'left_at' => 'Left',
'left_at_hint' => 'Removes them from the current roster but keeps their history.',
],
'filters' => ['current' => 'Current only'],
],
'technologies' => [
'label' => 'Technology',
'plural' => 'Technologies',
'off_radar' => 'Off the radar',
'sections' => ['prose' => 'Description and radar note'],
'fields' => [
'name' => 'Name',
'slug' => 'Slug',
'category' => 'Category',
'radar_ring' => 'Radar ring',
'radar_ring_hint' => 'Empty = usable as a tag but kept off the public radar.',
'radar_note' => 'Radar note',
'radar_note_hint' => 'Why it sits in that ring. This is the part people read.',
'description' => 'Description',
'color' => 'Colour',
'logo' => 'Logo',
'logo_hint' => 'Preferably SVG, or PNG with a transparent background. It shows on the radar and on the cards.',
'website' => 'Website',
'position' => 'Order',
'projects' => 'Projects',
'members' => 'Members',
],
],
'calls' => [
'label' => 'Call for help',
'plural' => 'Calls for help',
'no_project' => 'General',
'sections' => [
'commitment' => 'Commitment',
'commitment_hint' => 'Time is the scarce resource here, not money. Being specific is what makes someone decide.',
],
'fields' => [
'title' => 'Title',
'slug' => 'Slug',
'description' => 'Description',
'what_you_get' => 'What you get',
'what_you_get_hint' => 'Learning, portfolio, references, mentoring. Saying it openly helps.',
'status' => 'Status',
'project' => 'Project',
'project_hint' => 'Empty = a general call from the collective.',
'technologies' => 'Technologies',
'hours_per_week' => 'Hours per week',
'duration_weeks' => 'Weeks',
'seniority' => 'Level',
'commitment' => 'Commitment',
'opens_at' => 'Opens',
'closes_at' => 'Closes',
],
'seniority' => ['any' => 'Any', 'junior' => 'Junior', 'mid' => 'Mid', 'senior' => 'Senior'],
'commitment_summary' => '{0}:hoursh/week|{1}:hoursh/week · :weeks week|[2,*]:hoursh/week · :weeks weeks',
],
'applications' => [
'label' => 'Submission',
'plural' => 'Inbox',
'general_enquiry' => 'General message',
'badge_tooltip' => 'People waiting for an answer',
'saved' => 'Notes saved',
'reply_subject' => 'Re: :subject',
'sections' => [
'message' => 'What they wrote',
'internal' => 'Internal follow-up',
'internal_hint' => 'Only you see this. The sender never does.',
],
'fields' => [
'name' => 'Name',
'email' => 'E-mail',
'organisation' => 'Organisation',
'kind' => 'Kind',
'subject' => 'About',
'call' => 'Call',
'hours_per_week' => 'Hours/week',
'hours_asked' => 'The call asked for :hours h/week',
'message' => 'Message',
'links' => 'Links',
'link_name' => 'Name',
'link_url' => 'URL',
'status' => 'Status',
'received_at' => 'Received',
'handled_by' => 'Handled by',
'handled_at' => 'Handled on',
'locale' => 'Wrote in',
'notes' => 'Notes',
'notes_empty' => 'No notes',
'notes_hint' => 'For the rest of the team: what was discussed, where it was left.',
],
'actions' => [
'group' => 'Mark as',
'open' => 'Open submission',
'reply' => 'Reply',
'notes' => 'Notes',
'contacted' => 'Contacted',
'accepted' => 'Accepted',
'declined' => 'Declined',
'spam' => 'Spam',
],
'tabs' => [
'pending' => 'Unanswered',
'contribute' => 'Offering help',
'request' => 'Asking for help',
'all' => 'All',
'spam' => 'Spam',
],
'empty' => [
'heading' => 'Nothing to answer',
'description' => 'Whatever people send from the public site arrives here.',
'call_heading' => 'Nobody has written yet',
],
'notification' => [
'contribute' => ':name wants to help out',
'request' => ':name is asking for help with a project',
],
'mail' => [
'greeting' => 'Somebody is waiting for an answer.',
'from' => 'From :name (:email)',
],
],
'publishing' => [
'published_count' => '{0}Nothing to publish: already live.|{1}Published 1 record.|[2,*]Published :count records.',
'scheduled' => 'Scheduled',
'expired' => 'Expired',
'expired_at' => 'Expired on :time',
'expires_in' => 'Expires :time',
'live' => 'Live',
'unpublished' => 'Unpublished',
],
'gallery' => [
'title' => 'Gallery',
'missing_alt' => 'Not described',
'pending' => 'Processing',
'fields' => [
'image' => 'Image',
'alt' => 'Alt text',
'alt_hint' => 'What it shows, for someone who cannot see it.',
'caption' => 'Caption',
'caption_hint' => 'Shown to everyone. "Before" and "after" go here.',
'size' => 'Size',
],
'actions' => [
'add' => 'Add image',
],
'empty' => [
'heading' => 'No images yet',
'description' => 'Screenshots, before and after, whatever makes the project understandable. Drag to reorder.',
],
],
'services' => [
'label' => 'Service',
'plural' => 'Services',
'no_projects' => 'Nothing behind it: that is a promise, not an offer.',
'sections' => [
'evidence' => 'What backs it',
'evidence_hint' => 'A service that cannot point at real work is a promise. Link the projects that prove it.',
'seo' => 'SEO',
],
'fields' => [
'title' => 'Title',
'slug' => 'Slug',
'tagline' => 'One-line summary',
'tagline_hint' => 'One line. It is what the card on the landing page shows.',
'description' => 'Description',
'projects' => 'Projects',
'technologies' => 'Technologies',
'icon' => 'Icon',
'icon_hint' => 'A Heroicons name, for example heroicon-o-code-bracket.',
'position' => 'Order',
'is_published' => 'Published',
'is_featured' => 'Featured',
'is_featured_hint' => 'So the landing page can pick a few.',
'published_at' => 'Publish on',
'published_at_hint' => 'With a future date it stays off the site until it arrives.',
'unpublish_at' => 'Take down on',
'unpublish_at_hint' => 'Optional. When it arrives it drops off the site by itself.',
'meta_title' => 'Meta title',
'meta_description' => 'Meta description',
'translations' => 'Translations',
],
'actions' => [
'publish' => 'Publish',
],
],
'clients' => [
'label' => 'Client',
'plural' => 'Clients',
'fields' => [
'name' => 'Name',
'slug' => 'Slug',
'sector' => 'Sector',
'logo' => 'Logo',
'logo_hint' => 'Preferably SVG, or PNG with a transparent background.',
'url' => 'Website',
'projects' => 'Projects',
'is_public' => 'May be shown',
'is_public_hint' => 'Uncheck it if the organisation would rather not appear on the site.',
'position' => 'Order',
],
'filters' => [
'without_logo' => 'Without a logo',
],
],
'testimonials' => [
'label' => 'Testimonial',
'plural' => 'Testimonials',
'sections' => [
'quote' => 'The quote',
'quote_hint' => 'Write what they actually said, in the language they said it in. The other tabs are your translations, and the site will say so.',
'author' => 'Who said it',
'about' => 'What it is about',
'about_hint' => 'Attach it to a client, a project or a service, so the site asks for the right ones per page instead of keeping a loose list.',
],
'fields' => [
'quote' => 'Quote',
'original_locale' => 'Original language',
'original_locale_hint' => 'The language it was said in. Translating a quote puts words in somebody\'s mouth, so the site says as much.',
'author_name' => 'Name',
'author_role' => 'Role',
'avatar' => 'Photo',
'client' => 'Client',
'project' => 'Project',
'service' => 'Service',
'is_public' => 'Visible',
'position' => 'Order',
'given_at' => 'Date',
],
],
'talks' => [
'label' => 'Talk',
'plural' => 'Talks',
'fields' => [
'title' => 'Title',
'title_hint' => 'Not translated: it is the name of a talk given once, in one language.',
'language' => 'Language',
'summary' => 'Summary',
'event' => 'Event',
'city' => 'City',
'held_at' => 'Date',
'video_url' => 'Video',
'slides_url' => 'Slides',
'member' => 'Speaker',
'member_hint' => 'It will show on their profile too, without writing it twice.',
'project' => 'Project',
'is_public' => 'Visible',
],
],
'repositories' => [
'label' => 'Repository',
'plural' => 'Repositories',
'never_synced' => 'Never',
'fields' => [
'provider' => 'Provider',
'full_name' => 'Repository',
'full_name_hint' => 'Format "owner/repo". Everything else is fetched automatically.',
'project' => 'Project',
'is_primary' => 'Primary',
'is_primary_hint' => 'The one representing the project when there are several.',
'show_publicly' => 'Visible on the site',
'language' => 'Language',
'contributors' => 'Contributors',
'good_first_issues' => 'Good first issues',
'pushed_at' => 'Last push',
'last_synced_at' => 'Synced',
],
'filters' => ['failing' => 'Failing', 'dormant' => 'Dormant'],
'actions' => ['sync' => 'Sync', 'sync_selected' => 'Sync selected'],
'notifications' => [
'synced' => 'Repository synced',
'synced_body' => ':stars★ · :issues good first issues',
'sync_failed' => 'Sync failed',
'queued' => ':count repositories queued',
],
],
'revisions' => [
'title' => 'History',
'system' => 'The system',
'before' => 'Before',
'after' => 'After',
'no_changes' => 'This entry records no field changes.',
'restored' => 'Values restored',
'restore_confirm' => 'The fields go back to what they said at that moment. Restoring is recorded too, so it can always be undone.',
'diff_heading' => 'Change by :author · :when',
'fields' => [
'event' => 'What happened',
'author' => 'Who',
'fields' => 'Fields',
'when' => 'When',
],
'events' => [
'created' => 'Created',
'updated' => 'Edited',
'published' => 'Published',
'unpublished' => 'Unpublished',
'deleted' => 'Deleted',
'restored' => 'Recovered',
'erased' => 'Erased for good',
],
'actions' => [
'diff' => 'See the change',
'restore' => 'Restore these values',
],
],
'media' => [
'label' => 'File',
'plural' => 'Media',
'subheading' => ':count files · :size MB on disk, derived versions included.',
'pending' => 'Not processed',
'in_use' => 'In use',
'orphan' => 'Unused',
'fields' => [
'file' => 'File',
'size' => 'Dimensions',
'versions' => 'Versions',
'weight' => 'Weight',
'used' => 'Use',
'error' => 'Error',
],
'filters' => [
'pending' => 'Not processed',
'failed' => 'Failed',
'orphans' => 'Nothing points at them',
'missing' => 'No file on disk',
],
'actions' => [
'open' => 'Open',
'reprocess' => 'Reprocess',
'reprocess_all' => 'Reprocess everything',
'reprocess_all_hint' => 'Regenerates dimensions, versions and placeholders for every image. This is what to do after changing the widths or adding a format.',
'reprocess_queued' => 'Queued. It runs as soon as the queue does.',
],
'empty' => [
'heading' => 'No files yet',
'description' => 'They appear here by themselves as images are uploaded on projects, pages, members or the showcase.',
],
],
'redirects' => [
'label' => 'Redirect',
'plural' => 'Redirects',
'hint' => 'Paths as the site sees them, leading slash included. Renaming a slug writes one by itself.',
'every_locale' => 'Every language',
'automatic' => 'Automatic',
'manual' => 'By hand',
'fields' => [
'from' => 'From',
'from_hint' => 'The address that stopped working.',
'to' => 'To',
'status' => 'Kind',
'status_hint' => 'Permanent is the usual one: it tells Google to update the link.',
'locale' => 'Language',
'locale_hint' => 'Leave empty to apply in all three.',
'is_enabled' => 'Enabled',
'hits' => 'Uses',
'origin' => 'Origin',
],
'statuses' => [
'301' => 'Permanent (301)',
'302' => 'Temporary (302)',
],
'filters' => [
'unused' => 'Never used yet',
],
'empty' => [
'heading' => 'No redirects yet',
'description' => 'They are written automatically when a published slug changes. Add the ones from links older than this site by hand.',
],
],
'translations' => [
'filters' => [
'stale' => 'Translation left behind',
],
],
'views' => [
'column' => 'Reads',
'column_hint' => 'Reads over the last 30 days, every language together. Empty until the frontend reports them.',
'in_days' => 'in :days days',
'filters' => [
'unread' => 'Published and unread',
],
],
'reviews' => [
'title' => 'Review',
'column' => 'Review',
'waiting' => 'Waiting',
'waiting_for_you' => 'Waiting for your review',
'waiting_for_you_hint' => 'Somebody finished something and cannot publish it.',
'anyone' => 'Anybody who can publish',
'requested' => 'Review requested. The people who can publish it have been told.',
'requested_count' => '{0}Nothing to ask for: already in review or published.|{1}Requested review on 1 record.|[2,*]Requested review on :count records.',
'returned' => 'Sent back to whoever wrote it, with your reason.',
'fields' => [
'reviewer' => 'Ask',
'reviewer_hint' => 'Leave empty and everyone who can publish this will see it.',
'note' => 'Note',
'note_hint' => 'Optional. What the reviewer needs to know before looking.',
'reason' => 'What needs changing',
'reason_hint' => 'Required: handing work back without saying why is what stops people using review at all.',
'event' => 'What happened',
'who' => 'Who',
'when' => 'When',
],
'filters' => [
'mine' => 'Waiting for my review',
],
'actions' => [
'request' => 'Ask for review',
'request_bulk' => 'Ask for review (selection)',
'request_heading' => 'Say this is ready',
'request_hint' => 'You cannot publish it yourself, so this tells the people who can.',
'return' => 'Send back',
'return_heading' => 'Send it back to whoever wrote it',
'comment' => 'Comment',
'open' => 'Open',
],
'notification' => [
'title' => ':name is asking you to review something',
'returned' => ':name has sent something back to you',
],
'empty' => [
'heading' => 'Nothing said yet',
'description' => 'What was asked, what was sent back and why. The part the change history cannot hold.',
],
],
'missing_urls' => [
'label' => 'Missing URL',
'plural' => 'Missing URLs',
'linked_from_us' => 'Linked from our own site',
'no_referrer' => 'No referrer',
'fields' => [
'path' => 'Address',
'hits' => 'Requests',
'locale' => 'Language',
'status' => 'Status',
'referrer' => 'Came from',
'last_seen' => 'Last seen',
],
'filters' => [
'internal' => 'Linked from our site',
'repeated' => 'More than one request',
],
'actions' => [
'redirect' => 'Create redirect',
'redirect_heading' => 'Send this address somewhere',
'redirect_hint' => 'The failing address is already filled in. All that is missing is where it should lead.',
'redirected' => 'Redirect created. This address stops returning 404.',
'locale_hint' => 'Taken from the language it was requested in. Empty to apply in all.',
'ignore' => 'Ignore',
'unignore' => 'Stop ignoring',
],
'empty' => [
'heading' => 'Nobody has hit a 404',
'description' => 'Addresses the site could not resolve show up here, ready to be redirected. The frontend reports them, so SITE_INGEST_TOKEN has to be set.',
],
],
'settings' => [
'label' => 'Setting',
'plural' => 'Settings',
'sections' => [
'general' => 'General',
],
'fields' => [
'key' => 'Key',
'value' => 'Value',
'value_hint' => 'The value exactly as it is, in JSON. Invalid JSON is refused.',
],
'actions' => [
'add_setting' => 'Add setting',
'delete_setting' => 'Delete setting',
],
],
'issues' => [
'label' => 'Issue',
'plural' => 'Issues',
'sections' => [
'details' => 'Details',
'classification' => 'Classification',
'metadata' => 'Metadata',
],
'fields' => [
'number' => 'Number',
'title' => 'Title',
'repository' => 'Repository',
'author' => 'Author',
'assignee' => 'Assignee',
'assignee_hint' => 'GitHub username or empty to mark as unclaimed',
'url' => 'URL',
'is_good_first_issue' => 'Good first issue',
'is_good_first_issue_hint' => 'Recommended for newcomers to the project',
'is_help_wanted' => 'Help wanted',
'is_help_wanted_hint' => 'Open to community contributions',
'comments' => 'Comments',
'issue_created_at' => 'Created',
'issue_updated_at' => 'Updated',
'labels' => 'Labels',
'unassigned' => 'Unassigned',
],
'filters' => [
'repository' => 'Repository',
'good_first_issue' => 'Good first issues',
'help_wanted' => 'Help wanted',
'unclaimed' => 'Unclaimed',
'claimed' => 'Claimed',
],
],
];

11
lang/en/passwords.php Normal file
View File

@@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
return [
'reset' => 'Your password has been reset.',
'sent' => 'We have emailed your password reset link.',
'throttled' => 'Please wait before retrying.',
'token' => 'This password reset token is invalid.',
'user' => 'We can\'t find a user with that email address.',
];

27
lang/en/pireon.php Normal file
View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
return [
'sign_in' => 'Sign in',
'sign_in_intro' => 'Sign in with your e-mail and password.',
'signing_in' => 'Checking your credentials…',
'password_grant_disabled' => 'Password sign-in is switched off on this installation. Please tell an administrator.',
'server_unavailable' => 'The identity server is not responding. This is not about your credentials; please tell an administrator.',
'sign_out' => 'Sign out',
'denied' => 'Sign-in was not completed: :reason',
'inactive' => 'Your account is deactivated. Please contact an administrator.',
'pending_approval' => 'Your registration is still awaiting approval by an administrator.',
'no_permission' => 'Your account is not allowed into this panel. Ask an administrator to assign you a role.',
'cannot_grant_super_admin' => 'Only a super admin may grant the super admin role.',
'not_configured_title' => 'The OAuth client is not configured',
'not_configured_body' => 'Register this application at :server, then fill in PIREON_CLIENT_ID and PIREON_CLIENT_SECRET in your .env file.',
'account' => [
'remote_roles' => 'Roles on the identity server',
'remote_roles_hint' => 'Informational only: permissions for this application are managed here, not on the OAuth server.',
'managed_remotely' => 'This field is managed at :server and refreshed on every sign-in.',
],
];

31
lang/en/rules.php Normal file
View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
return [
'translatable' => [
'type' => 'The :attribute field must be a string or a translations object (locale => text).',
'unsupported_locale' => 'The locale ":locale" is not supported for :attribute. Available locales: :supported.',
'max' => 'The ":locale" translation of :attribute may not be longer than :max characters.',
'default_required' => 'The :attribute is missing a translation for the primary locale (":locale").',
],
'slug' => [
'unique' => 'The slug ":slug" is already in use for the ":locale" locale.',
],
'applications' => [
'attributes' => [
'name' => 'name',
'email' => 'e-mail',
'message' => 'message',
'organisation' => 'organisation',
'hours_per_week' => 'hours per week',
'consent' => 'consent',
],
],
'pages' => [
'cannot_publish' => 'You do not have permission to publish pages.',
],
];

20
lang/en/site.php Normal file
View File

@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
/*
* Texts the public API returns to the public frontend, in the language the
* visitor is browsing in. They are rendered by the frontend as-is.
*/
return [
'telemetry' => [
'disabled' => 'Not-found reporting is disabled on this server.',
'forbidden' => 'Invalid ingest token.',
],
'applications' => [
'received' => 'We got your message. We will get back to you as soon as we can.',
'closed' => 'We are not accepting messages right now. Please try again later.',
],
];

290
lang/en/validation.php Normal file
View File

@@ -0,0 +1,290 @@
<?php
declare(strict_types=1);
return [
'accepted' => 'The :attribute field must be accepted.',
'accepted_if' => 'The :attribute field must be accepted when :other is :value.',
'active_url' => 'The :attribute field must be a valid URL.',
'after' => 'The :attribute field must be a date after :date.',
'after_or_equal' => 'The :attribute field must be a date after or equal to :date.',
'alpha' => 'The :attribute field must only contain letters.',
'alpha_dash' => 'The :attribute field must only contain letters, numbers, dashes, and underscores.',
'alpha_num' => 'The :attribute field must only contain letters and numbers.',
'any_of' => 'The :attribute field is invalid.',
'array' => 'The :attribute field must be an array.',
'array_keys' => 'The :attribute field must only contain the following keys: :values.',
'ascii' => 'The :attribute field must only contain single-byte alphanumeric characters and symbols.',
'base64' => 'The :attribute field must be a valid Base64 string.',
'before' => 'The :attribute field must be a date before :date.',
'before_or_equal' => 'The :attribute field must be a date before or equal to :date.',
'between' => [
'array' => 'The :attribute field must have between :min and :max items.',
'file' => 'The :attribute field must be between :min and :max kilobytes.',
'numeric' => 'The :attribute field must be between :min and :max.',
'string' => 'The :attribute field must be between :min and :max characters.',
],
'boolean' => 'The :attribute field must be true or false.',
'can' => 'The :attribute field contains an unauthorized value.',
'confirmed' => 'The :attribute field confirmation does not match.',
'contains' => 'The :attribute field is missing a required value.',
'current_password' => 'The password is incorrect.',
'date' => 'The :attribute field must be a valid date.',
'date_equals' => 'The :attribute field must be a date equal to :date.',
'date_format' => 'The :attribute field must match the format :format.',
'decimal' => 'The :attribute field must have :decimal decimal places.',
'declined' => 'The :attribute field must be declined.',
'declined_if' => 'The :attribute field must be declined when :other is :value.',
'different' => 'The :attribute field and :other must be different.',
'digits' => 'The :attribute field must be :digits digits.',
'digits_between' => 'The :attribute field must be between :min and :max digits.',
'dimensions' => 'The :attribute field has invalid image dimensions.',
'distinct' => 'The :attribute field has a duplicate value.',
'doesnt_contain' => 'The :attribute field must not contain any of the following: :values.',
'doesnt_end_with' => 'The :attribute field must not end with one of the following: :values.',
'doesnt_start_with' => 'The :attribute field must not start with one of the following: :values.',
'email' => 'The :attribute field must be a valid email address.',
'encoding' => 'The :attribute field must be encoded in :encoding.',
'ends_with' => 'The :attribute field must end with one of the following: :values.',
'enum' => 'The selected :attribute is invalid.',
'exists' => 'The selected :attribute is invalid.',
'extensions' => 'The :attribute field must have one of the following extensions: :values.',
'file' => 'The :attribute field must be a file.',
'filled' => 'The :attribute field must have a value.',
'gt' => [
'array' => 'The :attribute field must have more than :value items.',
'file' => 'The :attribute field must be greater than :value kilobytes.',
'numeric' => 'The :attribute field must be greater than :value.',
'string' => 'The :attribute field must be greater than :value characters.',
],
'gte' => [
'array' => 'The :attribute field must have :value items or more.',
'file' => 'The :attribute field must be greater than or equal to :value kilobytes.',
'numeric' => 'The :attribute field must be greater than or equal to :value.',
'string' => 'The :attribute field must be greater than or equal to :value characters.',
],
'hex_color' => 'The :attribute field must be a valid hexadecimal color.',
'image' => 'The :attribute field must be an image.',
'in' => 'The selected :attribute is invalid.',
'in_array' => 'The :attribute field must exist in :other.',
'in_array_keys' => 'The :attribute field must contain at least one of the following keys: :values.',
'integer' => 'The :attribute field must be an integer.',
'ip' => 'The :attribute field must be a valid IP address.',
'ipv4' => 'The :attribute field must be a valid IPv4 address.',
'ipv6' => 'The :attribute field must be a valid IPv6 address.',
'json' => 'The :attribute field must be a valid JSON string.',
'list' => 'The :attribute field must be a list.',
'lowercase' => 'The :attribute field must be lowercase.',
'lt' => [
'array' => 'The :attribute field must have less than :value items.',
'file' => 'The :attribute field must be less than :value kilobytes.',
'numeric' => 'The :attribute field must be less than :value.',
'string' => 'The :attribute field must be less than :value characters.',
],
'lte' => [
'array' => 'The :attribute field must not have more than :value items.',
'file' => 'The :attribute field must be less than or equal to :value kilobytes.',
'numeric' => 'The :attribute field must be less than or equal to :value.',
'string' => 'The :attribute field must be less than or equal to :value characters.',
],
'mac_address' => 'The :attribute field must be a valid MAC address.',
'max' => [
'array' => 'The :attribute field must not have more than :max items.',
'file' => 'The :attribute field must not be greater than :max kilobytes.',
'numeric' => 'The :attribute field must not be greater than :max.',
'string' => 'The :attribute field must not be greater than :max characters.',
],
'max_digits' => 'The :attribute field must not have more than :max digits.',
'mimes' => 'The :attribute field must be a file of type: :values.',
'mimetypes' => 'The :attribute field must be a file of type: :values.',
'min' => [
'array' => 'The :attribute field must have at least :min items.',
'file' => 'The :attribute field must be at least :min kilobytes.',
'numeric' => 'The :attribute field must be at least :min.',
'string' => 'The :attribute field must be at least :min characters.',
],
'min_digits' => 'The :attribute field must have at least :min digits.',
'missing' => 'The :attribute field must be missing.',
'missing_if' => 'The :attribute field must be missing when :other is :value.',
'missing_unless' => 'The :attribute field must be missing unless :other is :value.',
'missing_with' => 'The :attribute field must be missing when :values is present.',
'missing_with_all' => 'The :attribute field must be missing when :values are present.',
'multiple_of' => 'The :attribute field must be a multiple of :value.',
'not_in' => 'The selected :attribute is invalid.',
'not_regex' => 'The :attribute field format is invalid.',
'numeric' => 'The :attribute field must be a number.',
'password' => [
'letters' => 'The :attribute field must contain at least one letter.',
'mixed' => 'The :attribute field must contain at least one uppercase and one lowercase letter.',
'numbers' => 'The :attribute field must contain at least one number.',
'symbols' => 'The :attribute field must contain at least one symbol.',
'uncompromised' => 'The given :attribute has appeared in a data leak. Please choose a different :attribute.',
],
'present' => 'The :attribute field must be present.',
'present_if' => 'The :attribute field must be present when :other is :value.',
'present_unless' => 'The :attribute field must be present unless :other is :value.',
'present_with' => 'The :attribute field must be present when :values is present.',
'present_with_all' => 'The :attribute field must be present when :values are present.',
'prohibited' => 'The :attribute field is prohibited.',
'prohibited_if' => 'The :attribute field is prohibited when :other is :value.',
'prohibited_if_accepted' => 'The :attribute field is prohibited when :other is accepted.',
'prohibited_if_declined' => 'The :attribute field is prohibited when :other is declined.',
'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.',
'prohibits' => 'The :attribute field prohibits :other from being present.',
'regex' => 'The :attribute field format is invalid.',
'required' => 'The :attribute field is required.',
'required_array_keys' => 'The :attribute field must contain entries for: :values.',
'required_if' => 'The :attribute field is required when :other is :value.',
'required_if_accepted' => 'The :attribute field is required when :other is accepted.',
'required_if_declined' => 'The :attribute field is required when :other is declined.',
'required_unless' => 'The :attribute field is required unless :other is in :values.',
'required_with' => 'The :attribute field is required when :values is present.',
'required_with_all' => 'The :attribute field is required when :values are 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 field must match :other.',
'size' => [
'array' => 'The :attribute field must contain :size items.',
'file' => 'The :attribute field must be :size kilobytes.',
'numeric' => 'The :attribute field must be :size.',
'string' => 'The :attribute field must be :size characters.',
],
'starts_with' => 'The :attribute field must start with one of the following: :values.',
'string' => 'The :attribute field must be a string.',
'timezone' => 'The :attribute field must be a valid timezone.',
'ulid' => 'The :attribute field must be a valid ULID.',
'unique' => 'The :attribute has already been taken.',
'uploaded' => 'The :attribute failed to upload.',
'uppercase' => 'The :attribute field must be uppercase.',
'url' => 'The :attribute field must be a valid URL.',
'uuid' => 'The :attribute field must be a valid UUID.',
'attributes' => [
'address' => 'address',
'affiliate_url' => 'affiliate URL',
'age' => 'age',
'amount' => 'amount',
'announcement' => 'announcement',
'area' => 'area',
'audience_prize' => 'audience prize',
'audience_winner' => 'audience winner',
'available' => 'available',
'birthday' => 'birthday',
'body' => 'body',
'city' => 'city',
'color' => 'color',
'company' => 'company',
'compilation' => 'compilation',
'concept' => 'concept',
'conditions' => 'conditions',
'content' => 'content',
'contest' => 'contest',
'country' => 'country',
'cover' => 'cover',
'created_at' => 'created at',
'creator' => 'creator',
'currency' => 'currency',
'current_password' => 'current password',
'customer' => 'customer',
'date' => 'date',
'date_of_birth' => 'date of birth',
'dates' => 'dates',
'day' => 'day',
'deleted_at' => 'deleted at',
'description' => 'description',
'display_type' => 'display type',
'district' => 'district',
'duration' => 'duration',
'email' => 'email',
'excerpt' => 'excerpt',
'filter' => 'filter',
'finished_at' => 'finished at',
'first_name' => 'first name',
'gender' => 'gender',
'grand_prize' => 'grand prize',
'group' => 'group',
'hour' => 'hour',
'image' => 'image',
'image_desktop' => 'desktop image',
'image_main' => 'main image',
'image_mobile' => 'mobile image',
'images' => 'images',
'is_audience_winner' => 'is audience winner',
'is_hidden' => 'is hidden',
'is_subscribed' => 'is subscribed',
'is_visible' => 'is visible',
'is_winner' => 'is winner',
'items' => 'items',
'key' => 'key',
'last_name' => 'last name',
'lesson' => 'lesson',
'line_address_1' => 'line address 1',
'line_address_2' => 'line address 2',
'login' => 'login',
'message' => 'message',
'middle_name' => 'middle name',
'minute' => 'minute',
'mobile' => 'mobile',
'month' => 'month',
'name' => 'name',
'national_code' => 'national code',
'number' => 'number',
'password' => 'password',
'password_confirmation' => 'password confirmation',
'phone' => 'phone',
'photo' => 'photo',
'portfolio' => 'portfolio',
'postal_code' => 'postal code',
'preview' => 'preview',
'price' => 'price',
'product_id' => 'product ID',
'product_uid' => 'product UID',
'product_uuid' => 'product UUID',
'promo_code' => 'promo code',
'province' => 'province',
'quantity' => 'quantity',
'reason' => 'reason',
'recaptcha_response_field' => 'recaptcha response field',
'referee' => 'referee',
'referees' => 'referees',
'region' => 'region',
'reject_reason' => 'reject reason',
'remember' => 'remember',
'restored_at' => 'restored at',
'result_text_under_image' => 'result text under image',
'role' => 'role',
'rule' => 'rule',
'rules' => 'rules',
'second' => 'second',
'sex' => 'sex',
'shipment' => 'shipment',
'short_text' => 'short text',
'size' => 'size',
'skills' => 'skills',
'slug' => 'slug',
'specialization' => 'specialization',
'started_at' => 'started at',
'state' => 'state',
'status' => 'status',
'street' => 'street',
'student' => 'student',
'subject' => 'subject',
'tag' => 'tag',
'tags' => 'tags',
'teacher' => 'teacher',
'terms' => 'terms',
'test_description' => 'test description',
'test_locale' => 'test locale',
'test_name' => 'test name',
'text' => 'text',
'time' => 'time',
'title' => 'title',
'type' => 'type',
'updated_at' => 'updated at',
'user' => 'user',
'username' => 'username',
'value' => 'value',
'winner' => 'winner',
'work' => 'work',
'year' => 'year',
],
];