diff --git a/.github/translators.txt b/.github/translators.txt index ca8f0e218..098751fcd 100644 --- a/.github/translators.txt +++ b/.github/translators.txt @@ -95,3 +95,6 @@ Biepa :: German Informal; German syecu :: Chinese Simplified Lap1t0r :: French Thinkverse (thinkverse) :: Swedish +alef (toishoki) :: Turkish +Robbert Feunekes (Muukuro) :: Dutch +seohyeon.joo :: Korean diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index fa2437f37..7646f0687 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: [7.2, 7.3] + php: [7.2, 7.4] steps: - uses: actions/checkout@v1 diff --git a/app/Api/ListingResponseBuilder.php b/app/Api/ListingResponseBuilder.php index 2fa5644c3..df4cb8bf1 100644 --- a/app/Api/ListingResponseBuilder.php +++ b/app/Api/ListingResponseBuilder.php @@ -36,8 +36,10 @@ class ListingResponseBuilder */ public function toResponse() { - $data = $this->fetchData(); - $total = $this->query->count(); + $filteredQuery = $this->filterQuery($this->query); + + $total = $filteredQuery->count(); + $data = $this->fetchData($filteredQuery); return response()->json([ 'data' => $data, @@ -48,23 +50,22 @@ class ListingResponseBuilder /** * Fetch the data to return in the response. */ - protected function fetchData(): Collection + protected function fetchData(Builder $query): Collection { - $this->applyCountAndOffset($this->query); - $this->applySorting($this->query); - $this->applyFiltering($this->query); - - return $this->query->get($this->fields); + $query = $this->countAndOffsetQuery($query); + $query = $this->sortQuery($query); + return $query->get($this->fields); } /** * Apply any filtering operations found in the request. */ - protected function applyFiltering(Builder $query) + protected function filterQuery(Builder $query): Builder { + $query = clone $query; $requestFilters = $this->request->get('filter', []); if (!is_array($requestFilters)) { - return; + return $query; } $queryFilters = collect($requestFilters)->map(function ($value, $key) { @@ -73,7 +74,7 @@ class ListingResponseBuilder return !is_null($value); })->values()->toArray(); - $query->where($queryFilters); + return $query->where($queryFilters); } /** @@ -101,8 +102,9 @@ class ListingResponseBuilder * Apply sorting operations to the query from given parameters * otherwise falling back to the first given field, ascending. */ - protected function applySorting(Builder $query) + protected function sortQuery(Builder $query): Builder { + $query = clone $query; $defaultSortName = $this->fields[0]; $direction = 'asc'; @@ -116,20 +118,21 @@ class ListingResponseBuilder $sortName = $defaultSortName; } - $query->orderBy($sortName, $direction); + return $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) + protected function countAndOffsetQuery(Builder $query): Builder { + $query = clone $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); + return $query->skip($offset)->take($count); } } diff --git a/app/Auth/Access/Guards/LdapSessionGuard.php b/app/Auth/Access/Guards/LdapSessionGuard.php index 84f54ad29..652141c0c 100644 --- a/app/Auth/Access/Guards/LdapSessionGuard.php +++ b/app/Auth/Access/Guards/LdapSessionGuard.php @@ -60,10 +60,8 @@ class LdapSessionGuard extends ExternalBaseSessionGuard * @param array $credentials * @param bool $remember * @return bool - * @throws LoginAttemptEmailNeededException * @throws LoginAttemptException * @throws LdapException - * @throws UserRegistrationException */ public function attempt(array $credentials = [], $remember = false) { @@ -82,7 +80,11 @@ class LdapSessionGuard extends ExternalBaseSessionGuard } if (is_null($user)) { - $user = $this->createNewFromLdapAndCreds($userDetails, $credentials); + try { + $user = $this->createNewFromLdapAndCreds($userDetails, $credentials); + } catch (UserRegistrationException $exception) { + throw new LoginAttemptException($exception->message); + } } // Sync LDAP groups if required diff --git a/app/Config/app.php b/app/Config/app.php index cf34fd694..a9956edd8 100755 --- a/app/Config/app.php +++ b/app/Config/app.php @@ -52,7 +52,7 @@ return [ 'locale' => env('APP_LANG', 'en'), // Locales available - 'locales' => ['en', 'ar', 'cs', 'da', 'de', 'de_informal', 'es', 'es_AR', 'fa', 'fr', 'he', 'hu', 'it', 'ja', 'ko', 'nl', 'pt', 'pt_BR', 'sk', 'sl', 'sv', 'pl', 'ru', 'tr', 'uk', 'vi', 'zh_CN', 'zh_TW',], + 'locales' => ['en', 'ar', 'cs', 'da', 'de', 'de_informal', 'es', 'es_AR', 'fa', 'fr', 'he', 'hu', 'it', 'ja', 'ko', 'nl', 'pt', 'pt_BR', 'sk', 'sl', 'sv', 'pl', 'ru', 'th', 'tr', 'uk', 'vi', 'zh_CN', 'zh_TW',], // Application Fallback Locale 'fallback_locale' => 'en', diff --git a/app/Config/snappy.php b/app/Config/snappy.php index 60c26ffd5..f347eda23 100644 --- a/app/Config/snappy.php +++ b/app/Config/snappy.php @@ -13,7 +13,9 @@ return [ 'enabled' => true, 'binary' => file_exists(base_path('wkhtmltopdf')) ? base_path('wkhtmltopdf') : env('WKHTMLTOPDF', false), 'timeout' => false, - 'options' => [], + 'options' => [ + 'outline' => true + ], 'env' => [], ], 'image' => [ diff --git a/app/Exceptions/NotifyException.php b/app/Exceptions/NotifyException.php index 78ffde05c..4f8105960 100644 --- a/app/Exceptions/NotifyException.php +++ b/app/Exceptions/NotifyException.php @@ -8,8 +8,6 @@ class NotifyException extends \Exception /** * NotifyException constructor. - * @param string $message - * @param string $redirectLocation */ public function __construct(string $message, string $redirectLocation = "/") { diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 4660c16d5..fb2573b5c 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -125,6 +125,26 @@ class LoginController extends Controller return $this->sendFailedLoginResponse($request); } + /** + * The user has been authenticated. + * + * @param \Illuminate\Http\Request $request + * @param mixed $user + * @return mixed + */ + protected function authenticated(Request $request, $user) + { + // Authenticate on all session guards if a likely admin + if ($user->can('users-manage') && $user->can('user-roles-manage')) { + $guards = ['standard', 'ldap', 'saml2']; + foreach ($guards as $guard) { + auth($guard)->login($user); + } + } + + return redirect()->intended($this->redirectPath()); + } + /** * Validate the user login request. * diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 775e2a984..97ec31dcc 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -76,7 +76,7 @@ class UserController extends Controller if ($authMethod === 'standard' && !$sendInvite) { $validationRules['password'] = 'required|min:6'; $validationRules['password-confirm'] = 'required|same:password'; - } elseif ($authMethod === 'ldap') { + } elseif ($authMethod === 'ldap' || $authMethod === 'saml2') { $validationRules['external_auth_id'] = 'required'; } $this->validate($request, $validationRules); @@ -85,7 +85,7 @@ class UserController extends Controller if ($authMethod === 'standard') { $user->password = bcrypt($request->get('password', Str::random(32))); - } elseif ($authMethod === 'ldap') { + } elseif ($authMethod === 'ldap' || $authMethod === 'saml2') { $user->external_auth_id = $request->get('external_auth_id'); } diff --git a/resources/js/components/book-sort.js b/resources/js/components/book-sort.js index da2b28d8e..b0d64ad17 100644 --- a/resources/js/components/book-sort.js +++ b/resources/js/components/book-sort.js @@ -1,4 +1,4 @@ -import Sortable from "sortablejs"; +import {Sortable, MultiDrag} from "sortablejs"; // Auto sort control const sortOperations = { @@ -43,6 +43,7 @@ class BookSort { this.input = elem.querySelector('[book-sort-input]'); const initialSortBox = elem.querySelector('.sort-box'); + Sortable.mount(new MultiDrag()); this.setupBookSortable(initialSortBox); this.setupSortPresets(); @@ -134,6 +135,9 @@ class BookSort { onSort: this.updateMapInput.bind(this), dragClass: 'bg-white', ghostClass: 'primary-background-light', + multiDrag: true, + multiDragKey: 'CTRL', + selectedClass: 'sortable-selected', }); } } diff --git a/resources/js/components/markdown-editor.js b/resources/js/components/markdown-editor.js index 4dc240d48..cc9a7b859 100644 --- a/resources/js/components/markdown-editor.js +++ b/resources/js/components/markdown-editor.js @@ -557,6 +557,11 @@ class MarkdownEditor { const prependLineCount = markdown.split('\n').length; this.cm.setCursor(cursorPos.line + prependLineCount, cursorPos.ch); }); + + // Focus on editor + window.$events.listen('editor::focus', () => { + this.cm.focus(); + }); } } diff --git a/resources/js/components/wysiwyg-editor.js b/resources/js/components/wysiwyg-editor.js index b8ce901ca..1c8c71099 100644 --- a/resources/js/components/wysiwyg-editor.js +++ b/resources/js/components/wysiwyg-editor.js @@ -98,21 +98,15 @@ function registerEditorShortcuts(editor) { // Loop through callout styles editor.shortcuts.add('meta+9', '', function() { - let selectedNode = editor.selection.getNode(); - let formats = ['info', 'success', 'warning', 'danger']; + const selectedNode = editor.selection.getNode(); + const callout = selectedNode ? selectedNode.closest('.callout') : null; - if (!selectedNode || selectedNode.className.indexOf('callout') === -1) { - editor.formatter.apply('calloutinfo'); - return; - } + const formats = ['info', 'success', 'warning', 'danger']; + const currentFormatIndex = formats.findIndex(format => callout && callout.classList.contains(format)); + const newFormatIndex = (currentFormatIndex + 1) % formats.length; + const newFormat = formats[newFormatIndex]; - for (let i = 0; i < formats.length; i++) { - if (selectedNode.className.indexOf(formats[i]) === -1) continue; - let newFormat = (i === formats.length -1) ? formats[0] : formats[i+1]; - editor.formatter.apply('callout' + newFormat); - return; - } - editor.formatter.apply('p'); + editor.formatter.apply('callout' + newFormat); }); } @@ -408,6 +402,10 @@ function listenForBookStackEditorEvents(editor) { editor.setContent(content); }); + // Focus on the editor + window.$events.listen('editor::focus', () => { + editor.focus(); + }); } class WysiwygEditor { diff --git a/resources/js/vues/page-editor.js b/resources/js/vues/page-editor.js index fbf2857a4..a79ad2049 100644 --- a/resources/js/vues/page-editor.js +++ b/resources/js/vues/page-editor.js @@ -19,6 +19,8 @@ function mounted() { this.pageId= Number(elem.getAttribute('page-id')); this.isNewDraft = Number(elem.getAttribute('page-new-draft')) === 1; this.isUpdateDraft = Number(elem.getAttribute('page-update-draft')) === 1; + this.titleElem = elem.querySelector('input[name=name]'); + this.hasDefaultTitle = this.titleElem.closest('[is-default-value]') !== null; if (this.pageId !== 0 && this.draftsEnabled) { window.setTimeout(() => { @@ -43,6 +45,8 @@ function mounted() { window.$events.listen('editor-markdown-change', markdown => { this.editorMarkdown = markdown; }); + + this.setInitialFocus(); } let data = { @@ -58,18 +62,31 @@ let data = { editorHTML: '', editorMarkdown: '', + + hasDefaultTitle: false, + titleElem: null, }; let methods = { + setInitialFocus() { + if (this.hasDefaultTitle) { + this.titleElem.select(); + } else { + window.setTimeout(() => { + this.$events.emit('editor::focus', ''); + }, 500); + } + }, + startAutoSave() { - currentContent.title = document.getElementById('name').value.trim(); + currentContent.title = this.titleElem.value.trim(); currentContent.html = this.editorHTML; autoSave = window.setInterval(() => { // Return if manually saved recently to prevent bombarding the server if (Date.now() - lastSave < (1000 * autoSaveFrequency)/2) return; - const newTitle = document.getElementById('name').value.trim(); + const newTitle = this.titleElem.value.trim(); const newHtml = this.editorHTML; if (newTitle !== currentContent.title || newHtml !== currentContent.html) { @@ -85,7 +102,7 @@ let methods = { if (!this.draftsEnabled) return; const data = { - name: document.getElementById('name').value.trim(), + name: this.titleElem.value.trim(), html: this.editorHTML }; @@ -126,7 +143,7 @@ let methods = { window.$events.emit('editor-html-update', response.data.html); window.$events.emit('editor-markdown-update', response.data.markdown || response.data.html); - document.getElementById('name').value = response.data.name; + this.titleElem.value = response.data.name; window.setTimeout(() => { this.startAutoSave(); }, 1000); diff --git a/resources/lang/es/common.php b/resources/lang/es/common.php index b61b170b1..4f4f7f600 100644 --- a/resources/lang/es/common.php +++ b/resources/lang/es/common.php @@ -66,8 +66,8 @@ return [ 'profile_menu' => 'Menú de Perfil', 'view_profile' => 'Ver Perfil', 'edit_profile' => 'Editar Perfil', - 'dark_mode' => 'Dark Mode', - 'light_mode' => 'Light Mode', + 'dark_mode' => 'Modo Oscuro', + 'light_mode' => 'Modo Claro', // Layout tabs 'tab_info' => 'Información', diff --git a/resources/lang/es_AR/common.php b/resources/lang/es_AR/common.php index 5f98271ac..0051e9c22 100644 --- a/resources/lang/es_AR/common.php +++ b/resources/lang/es_AR/common.php @@ -66,8 +66,8 @@ return [ 'profile_menu' => 'Menu del Perfil', 'view_profile' => 'Ver Perfil', 'edit_profile' => 'Editar Perfil', - 'dark_mode' => 'Dark Mode', - 'light_mode' => 'Light Mode', + 'dark_mode' => 'Modo Oscuro', + 'light_mode' => 'Modo Claro', // Layout tabs 'tab_info' => 'Información', diff --git a/resources/lang/fr/common.php b/resources/lang/fr/common.php index 4294c3d27..81dde84c4 100644 --- a/resources/lang/fr/common.php +++ b/resources/lang/fr/common.php @@ -66,8 +66,8 @@ return [ 'profile_menu' => 'Menu du profil', 'view_profile' => 'Voir le profil', 'edit_profile' => 'Modifier le profil', - 'dark_mode' => 'Dark Mode', - 'light_mode' => 'Light Mode', + 'dark_mode' => 'Mode sombre', + 'light_mode' => 'Mode clair', // Layout tabs 'tab_info' => 'Informations', diff --git a/resources/lang/ko/common.php b/resources/lang/ko/common.php index 56fc323f9..67cc87bd2 100644 --- a/resources/lang/ko/common.php +++ b/resources/lang/ko/common.php @@ -66,8 +66,8 @@ return [ 'profile_menu' => '프로필', 'view_profile' => '프로필 보기', 'edit_profile' => '프로필 바꾸기', - 'dark_mode' => 'Dark Mode', - 'light_mode' => 'Light Mode', + 'dark_mode' => '다크 모드', + 'light_mode' => '라이트 모드', // Layout tabs 'tab_info' => '정보', diff --git a/resources/lang/ko/settings.php b/resources/lang/ko/settings.php index 4bf653f6c..e7cec851a 100755 --- a/resources/lang/ko/settings.php +++ b/resources/lang/ko/settings.php @@ -103,7 +103,7 @@ return [ 'role_manage_entity_permissions' => '문서별 권한 관리', 'role_manage_own_entity_permissions' => '직접 만든 문서별 권한 관리', 'role_manage_page_templates' => '템플릿 관리', - 'role_access_api' => 'Access system API', + 'role_access_api' => '시스템 접근 API', 'role_manage_settings' => '사이트 설정 관리', 'role_asset' => '권한 항목', 'role_asset_desc' => '책자, 챕터, 문서별 권한은 이 설정에 우선합니다.', @@ -152,29 +152,29 @@ return [ 'users_social_disconnect' => '계정 연결 끊기', 'users_social_connected' => ':socialAccount(와)과 연결했습니다.', 'users_social_disconnected' => ':socialAccount(와)과의 연결을 끊었습니다.', - 'users_api_tokens' => 'API Tokens', + 'users_api_tokens' => 'API 토큰', 'users_api_tokens_none' => 'No API tokens have been created for this user', - 'users_api_tokens_create' => 'Create Token', - 'users_api_tokens_expires' => 'Expires', - 'users_api_tokens_docs' => 'API Documentation', + 'users_api_tokens_create' => '토큰 만들기', + 'users_api_tokens_expires' => '만료', + 'users_api_tokens_docs' => 'API 설명서', // API Tokens - 'user_api_token_create' => 'Create API Token', - 'user_api_token_name' => 'Name', + 'user_api_token_create' => 'API 토큰 만들기', + 'user_api_token_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' => '만료일', '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' => 'API 토큰', + 'user_api_token_id' => '토큰 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' => '토큰 삭제', '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', diff --git a/resources/lang/nl/auth.php b/resources/lang/nl/auth.php index 03211e1b9..ce0be87ed 100644 --- a/resources/lang/nl/auth.php +++ b/resources/lang/nl/auth.php @@ -43,7 +43,7 @@ return [ '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' => 'A password reset link will be sent to :email if that email address is found in the system.', + 'reset_password_sent' => 'Een link om het wachtwoord te resetten zal verstuurd worden naar :email als dat e-mailadres in het systeem gevonden is.', '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.', diff --git a/resources/lang/nl/common.php b/resources/lang/nl/common.php index 2351ab2db..f228fa6c4 100644 --- a/resources/lang/nl/common.php +++ b/resources/lang/nl/common.php @@ -35,7 +35,7 @@ return [ 'delete' => 'Verwijder', 'search' => 'Zoek', 'search_clear' => 'Zoekopdracht wissen', - 'reset' => 'Reset', + 'reset' => 'Resetten', 'remove' => 'Verwijderen', 'add' => 'Toevoegen', 'fullscreen' => 'Volledig scherm', @@ -66,8 +66,8 @@ return [ 'profile_menu' => 'Profiel menu', 'view_profile' => 'Profiel Weergeven', 'edit_profile' => 'Profiel Bewerken', - 'dark_mode' => 'Dark Mode', - 'light_mode' => 'Light Mode', + 'dark_mode' => 'Donkere Modus', + 'light_mode' => 'Lichte Modus', // Layout tabs 'tab_info' => 'Info', diff --git a/resources/lang/nl/entities.php b/resources/lang/nl/entities.php index bcd069053..a88be7711 100644 --- a/resources/lang/nl/entities.php +++ b/resources/lang/nl/entities.php @@ -11,7 +11,7 @@ return [ '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_created_shelves' => 'Recent Aangemaakte Boekenplanken', 'recently_update' => 'Recent Bijgewerkt', 'recently_viewed' => 'Recent Bekeken', 'recent_activity' => 'Recente Activiteit', diff --git a/resources/lang/th/activities.php b/resources/lang/th/activities.php new file mode 100644 index 000000000..4cac54b2a --- /dev/null +++ b/resources/lang/th/activities.php @@ -0,0 +1,48 @@ + 'created page', + 'page_create_notification' => 'Page Successfully Created', + 'page_update' => 'updated page', + 'page_update_notification' => 'Page Successfully Updated', + 'page_delete' => 'deleted page', + 'page_delete_notification' => 'Page Successfully Deleted', + 'page_restore' => 'restored page', + 'page_restore_notification' => 'Page Successfully Restored', + 'page_move' => 'moved page', + + // Chapters + 'chapter_create' => 'created chapter', + 'chapter_create_notification' => 'Chapter Successfully Created', + 'chapter_update' => 'updated chapter', + 'chapter_update_notification' => 'Chapter Successfully Updated', + 'chapter_delete' => 'deleted chapter', + 'chapter_delete_notification' => 'Chapter Successfully Deleted', + 'chapter_move' => 'moved chapter', + + // Books + 'book_create' => 'created book', + 'book_create_notification' => 'Book Successfully Created', + 'book_update' => 'updated book', + 'book_update_notification' => 'Book Successfully Updated', + 'book_delete' => 'deleted book', + 'book_delete_notification' => 'Book Successfully Deleted', + 'book_sort' => 'sorted book', + 'book_sort_notification' => 'Book Successfully Re-sorted', + + // 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/th/auth.php b/resources/lang/th/auth.php new file mode 100644 index 000000000..d64fce93a --- /dev/null +++ b/resources/lang/th/auth.php @@ -0,0 +1,77 @@ + 'These credentials do not match our records.', + 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', + + // Login & Register + 'sign_up' => 'Sign up', + 'log_in' => 'Log in', + 'log_in_with' => 'Login with :socialDriver', + 'sign_up_with' => 'Sign up with :socialDriver', + 'logout' => 'Logout', + + 'name' => 'Name', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'password_confirm' => 'Confirm Password', + 'password_hint' => 'Must be over 7 characters', + 'forgot_password' => 'Forgot Password?', + 'remember_me' => 'Remember Me', + 'ldap_email_hint' => 'Please enter an email to use for this account.', + 'create_account' => 'Create Account', + 'already_have_account' => 'Already have an account?', + 'dont_have_account' => 'Don\'t have an account?', + 'social_login' => 'Social Login', + 'social_registration' => 'Social Registration', + 'social_registration_text' => 'Register and sign in using another service.', + + 'register_thanks' => 'Thanks for registering!', + 'register_confirm' => 'Please check your email and click the confirmation button to access :appName.', + 'registrations_disabled' => 'Registrations are currently disabled', + 'registration_email_domain_invalid' => 'That email domain does not have access to this application', + 'register_success' => 'Thanks for signing up! You are now registered and signed in.', + + + // Password Reset + 'reset_password' => 'Reset Password', + 'reset_password_send_instructions' => 'Enter your email below and you will be sent an email with a password reset link.', + 'reset_password_send_button' => 'Send Reset Link', + 'reset_password_sent' => 'A password reset link will be sent to :email if that email address is found in the system.', + 'reset_password_success' => 'Your password has been successfully reset.', + 'email_reset_subject' => 'Reset your :appName password', + 'email_reset_text' => 'You are receiving this email because we received a password reset request for your account.', + 'email_reset_not_requested' => 'If you did not request a password reset, no further action is required.', + + + // 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/th/common.php b/resources/lang/th/common.php new file mode 100644 index 000000000..68c58b92b --- /dev/null +++ b/resources/lang/th/common.php @@ -0,0 +1,79 @@ + 'Cancel', + 'confirm' => 'Confirm', + 'back' => 'Back', + 'save' => 'Save', + 'continue' => 'Continue', + 'select' => 'Select', + 'toggle_all' => 'Toggle All', + 'more' => 'More', + + // Form Labels + 'name' => 'Name', + 'description' => 'Description', + 'role' => 'Role', + 'cover_image' => 'Cover image', + 'cover_image_description' => 'This image should be approx 440x250px.', + + // Actions + 'actions' => 'Actions', + 'view' => 'View', + 'view_all' => 'View All', + 'create' => 'Create', + 'update' => 'Update', + 'edit' => 'Edit', + 'sort' => 'Sort', + 'move' => 'Move', + 'copy' => 'Copy', + 'reply' => 'Reply', + 'delete' => 'Delete', + 'search' => 'Search', + 'search_clear' => 'Clear Search', + 'reset' => 'Reset', + 'remove' => 'Remove', + '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 + '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', + 'dark_mode' => 'Dark Mode', + 'light_mode' => 'Light Mode', + + // 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/th/components.php b/resources/lang/th/components.php new file mode 100644 index 000000000..d8e8981fb --- /dev/null +++ b/resources/lang/th/components.php @@ -0,0 +1,33 @@ + 'Image Select', + 'image_all' => 'All', + 'image_all_title' => 'View all images', + 'image_book_title' => 'View images uploaded to this book', + 'image_page_title' => 'View images uploaded to this page', + 'image_search_hint' => 'Search by image name', + 'image_uploaded' => 'Uploaded :uploadedDate', + 'image_load_more' => 'Load More', + 'image_image_name' => 'Image Name', + 'image_delete_used' => 'This image is used in the pages below.', + 'image_delete_confirm' => 'Click delete again to confirm you want to delete this image.', + 'image_select_image' => 'Select Image', + 'image_dropzone' => 'Drop images or click here to upload', + 'images_deleted' => 'Images Deleted', + 'image_preview' => 'Image Preview', + 'image_upload_success' => 'Image uploaded successfully', + 'image_update_success' => 'Image details successfully updated', + 'image_delete_success' => 'Image successfully deleted', + 'image_upload_remove' => 'Remove', + + // Code Editor + 'code_editor' => 'Edit Code', + 'code_language' => 'Code Language', + 'code_content' => 'Code Content', + 'code_save' => 'Save Code', +]; diff --git a/resources/lang/th/entities.php b/resources/lang/th/entities.php new file mode 100644 index 000000000..6bbc723b0 --- /dev/null +++ b/resources/lang/th/entities.php @@ -0,0 +1,314 @@ + 'Recently Created', + 'recently_created_pages' => 'Recently Created Pages', + 'recently_updated_pages' => 'Recently Updated Pages', + 'recently_created_chapters' => 'Recently Created Chapters', + 'recently_created_books' => 'Recently Created Books', + 'recently_created_shelves' => 'Recently Created Shelves', + 'recently_update' => 'Recently Updated', + 'recently_viewed' => 'Recently Viewed', + 'recent_activity' => 'Recent Activity', + 'create_now' => 'Create one now', + 'revisions' => 'Revisions', + 'meta_revision' => 'Revision #:revisionCount', + 'meta_created' => 'Created :timeLength', + 'meta_created_name' => 'Created :timeLength by :user', + 'meta_updated' => 'Updated :timeLength', + 'meta_updated_name' => 'Updated :timeLength by :user', + 'entity_select' => 'Entity Select', + 'images' => 'Images', + 'my_recent_drafts' => 'My Recent Drafts', + 'my_recently_viewed' => 'My Recently Viewed', + 'no_pages_viewed' => 'You have not viewed any pages', + 'no_pages_recently_created' => 'No pages have been recently created', + 'no_pages_recently_updated' => 'No pages have been recently updated', + 'export' => 'Export', + 'export_html' => 'Contained Web File', + 'export_pdf' => 'PDF File', + 'export_text' => 'Plain Text File', + + // Permissions and restrictions + 'permissions' => 'Permissions', + 'permissions_intro' => 'Once enabled, These permissions will take priority over any set role permissions.', + 'permissions_enable' => 'Enable Custom Permissions', + 'permissions_save' => 'Save Permissions', + + // Search + 'search_results' => 'Search Results', + 'search_total_results_found' => ':count result found|:count total results found', + 'search_clear' => 'Clear Search', + 'search_no_pages' => 'No pages matched this search', + 'search_for_term' => 'Search for :term', + 'search_more' => 'More Results', + 'search_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', + + // 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' => 'Books', + 'x_books' => ':count Book|:count Books', + 'books_empty' => 'No books have been created', + 'books_popular' => 'Popular Books', + 'books_recent' => 'Recent Books', + 'books_new' => 'New Books', + 'books_new_action' => 'New Book', + 'books_popular_empty' => 'The most popular books will appear here.', + 'books_new_empty' => 'The most recently created books will appear here.', + 'books_create' => 'Create New Book', + 'books_delete' => 'Delete Book', + 'books_delete_named' => 'Delete Book :bookName', + 'books_delete_explain' => 'This will delete the book with the name \':bookName\'. All pages and chapters will be removed.', + 'books_delete_confirmation' => 'Are you sure you want to delete this book?', + 'books_edit' => 'Edit Book', + 'books_edit_named' => 'Edit Book :bookName', + 'books_form_book_name' => 'Book Name', + 'books_save' => 'Save Book', + 'books_permissions' => 'Book Permissions', + 'books_permissions_updated' => 'Book Permissions Updated', + 'books_empty_contents' => 'No pages or chapters have been created for this book.', + 'books_empty_create_page' => 'Create a new page', + 'books_empty_sort_current_book' => 'Sort the current book', + 'books_empty_add_chapter' => 'Add a chapter', + 'books_permissions_active' => 'Book Permissions Active', + 'books_search_this' => 'Search this book', + 'books_navigation' => 'Book Navigation', + 'books_sort' => 'Sort Book Contents', + 'books_sort_named' => 'Sort Book :bookName', + 'books_sort_name' => 'Sort by Name', + 'books_sort_created' => 'Sort by Created Date', + 'books_sort_updated' => 'Sort by Updated Date', + 'books_sort_chapters_first' => 'Chapters First', + 'books_sort_chapters_last' => 'Chapters Last', + 'books_sort_show_other' => 'Show Other Books', + 'books_sort_save' => 'Save New Order', + + // Chapters + 'chapter' => 'Chapter', + 'chapters' => 'Chapters', + 'x_chapters' => ':count Chapter|:count Chapters', + 'chapters_popular' => 'Popular Chapters', + 'chapters_new' => 'New Chapter', + 'chapters_create' => 'Create New Chapter', + 'chapters_delete' => 'Delete Chapter', + 'chapters_delete_named' => 'Delete Chapter :chapterName', + 'chapters_delete_explain' => 'This will delete the chapter with the name \':chapterName\'. All pages will be removed and added directly to the parent book.', + 'chapters_delete_confirm' => 'Are you sure you want to delete this chapter?', + 'chapters_edit' => 'Edit Chapter', + 'chapters_edit_named' => 'Edit Chapter :chapterName', + 'chapters_save' => 'Save Chapter', + 'chapters_move' => 'Move Chapter', + 'chapters_move_named' => 'Move Chapter :chapterName', + 'chapter_move_success' => 'Chapter moved to :bookName', + 'chapters_permissions' => 'Chapter Permissions', + 'chapters_empty' => 'No pages are currently in this chapter.', + 'chapters_permissions_active' => 'Chapter Permissions Active', + 'chapters_permissions_success' => 'Chapter Permissions Updated', + 'chapters_search_this' => 'Search this chapter', + + // Pages + 'page' => 'Page', + 'pages' => 'Pages', + 'x_pages' => ':count Page|:count Pages', + 'pages_popular' => 'Popular Pages', + 'pages_new' => 'New Page', + 'pages_attachments' => 'Attachments', + 'pages_navigation' => 'Page Navigation', + 'pages_delete' => 'Delete Page', + 'pages_delete_named' => 'Delete Page :pageName', + 'pages_delete_draft_named' => 'Delete Draft Page :pageName', + 'pages_delete_draft' => 'Delete Draft Page', + 'pages_delete_success' => 'Page deleted', + 'pages_delete_draft_success' => 'Draft page deleted', + 'pages_delete_confirm' => 'Are you sure you want to delete this page?', + 'pages_delete_draft_confirm' => 'Are you sure you want to delete this draft page?', + 'pages_editing_named' => 'Editing Page :pageName', + 'pages_edit_draft_options' => 'Draft Options', + 'pages_edit_save_draft' => 'Save Draft', + 'pages_edit_draft' => 'Edit Page Draft', + 'pages_editing_draft' => 'Editing Draft', + 'pages_editing_page' => 'Editing Page', + 'pages_edit_draft_save_at' => 'Draft saved at ', + 'pages_edit_delete_draft' => 'Delete Draft', + 'pages_edit_discard_draft' => 'Discard Draft', + 'pages_edit_set_changelog' => 'Set Changelog', + 'pages_edit_enter_changelog_desc' => 'Enter a brief description of the changes you\'ve made', + 'pages_edit_enter_changelog' => 'Enter Changelog', + 'pages_save' => 'Save Page', + 'pages_title' => 'Page Title', + 'pages_name' => 'Page Name', + 'pages_md_editor' => 'Editor', + 'pages_md_preview' => 'Preview', + 'pages_md_insert_image' => 'Insert Image', + 'pages_md_insert_link' => 'Insert Entity Link', + 'pages_md_insert_drawing' => 'Insert Drawing', + 'pages_not_in_chapter' => 'Page is not in a chapter', + 'pages_move' => 'Move Page', + 'pages_move_success' => 'Page moved to ":parentName"', + 'pages_copy' => 'Copy Page', + 'pages_copy_desination' => 'Copy Destination', + 'pages_copy_success' => 'Page successfully copied', + 'pages_permissions' => 'Page Permissions', + 'pages_permissions_success' => 'Page permissions updated', + 'pages_revision' => 'Revision', + 'pages_revisions' => 'Page Revisions', + 'pages_revisions_named' => 'Page Revisions for :pageName', + 'pages_revision_named' => 'Page Revision for :pageName', + 'pages_revisions_created_by' => 'Created By', + 'pages_revisions_date' => 'Revision Date', + 'pages_revisions_number' => '#', + 'pages_revisions_numbered' => 'Revision #:id', + 'pages_revisions_numbered_changes' => 'Revision #:id Changes', + 'pages_revisions_changelog' => 'Changelog', + 'pages_revisions_changes' => 'Changes', + 'pages_revisions_current' => 'Current Version', + 'pages_revisions_preview' => 'Preview', + 'pages_revisions_restore' => 'Restore', + 'pages_revisions_none' => 'This page has no revisions', + 'pages_copy_link' => 'Copy Link', + 'pages_edit_content_link' => 'Edit Content', + 'pages_permissions_active' => 'Page Permissions Active', + 'pages_initial_revision' => 'Initial publish', + 'pages_initial_name' => 'New Page', + 'pages_editing_draft_notification' => 'You are currently editing a draft that was last saved :timeDiff.', + 'pages_draft_edited_notification' => 'This page has been updated by since that time. It is recommended that you discard this draft.', + 'pages_draft_edit_active' => [ + 'start_a' => ':count users have started editing this page', + 'start_b' => ':userName has started editing this page', + 'time_a' => 'since the page was last updated', + 'time_b' => 'in the last :minCount minutes', + 'message' => ':start :time. Take care not to overwrite each other\'s updates!', + ], + '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 + 'page_tags' => 'Page Tags', + 'chapter_tags' => 'Chapter Tags', + 'book_tags' => 'Book Tags', + 'shelf_tags' => 'Shelf Tags', + 'tag' => 'Tag', + 'tags' => 'Tags', + 'tag_name' => 'Tag Name', + 'tag_value' => 'Tag Value (Optional)', + 'tags_explain' => "Add some tags to better categorise your content. \n You can assign a value to a tag for more in-depth organisation.", + 'tags_add' => 'Add another tag', + 'tags_remove' => 'Remove this tag', + 'attachments' => 'Attachments', + 'attachments_explain' => 'Upload some files or attach some links to display on your page. These are visible in the page sidebar.', + 'attachments_explain_instant_save' => 'Changes here are saved instantly.', + 'attachments_items' => 'Attached Items', + 'attachments_upload' => 'Upload File', + 'attachments_link' => 'Attach Link', + 'attachments_set_link' => 'Set Link', + 'attachments_delete_confirm' => 'Click delete again to confirm you want to delete this attachment.', + 'attachments_dropzone' => 'Drop files or click here to attach a file', + 'attachments_no_files' => 'No files have been uploaded', + 'attachments_explain_link' => 'You can attach a link if you\'d prefer not to upload a file. This can be a link to another page or a link to a file in the cloud.', + 'attachments_link_name' => 'Link Name', + 'attachment_link' => 'Attachment link', + 'attachments_link_url' => 'Link to file', + 'attachments_link_url_hint' => 'Url of site or file', + 'attach' => 'Attach', + 'attachments_edit_file' => 'Edit File', + 'attachments_edit_file_name' => 'File Name', + 'attachments_edit_drop_upload' => 'Drop files or click here to upload and overwrite', + 'attachments_order_updated' => 'Attachment order updated', + 'attachments_updated_success' => 'Attachment details updated', + 'attachments_deleted' => 'Attachment deleted', + 'attachments_file_uploaded' => 'File successfully uploaded', + 'attachments_file_updated' => 'File successfully updated', + 'attachments_link_attached' => 'Link successfully attached to page', + 'templates' => 'Templates', + 'templates_set_as_template' => 'Page is a template', + 'templates_explain_set_as_template' => 'You can set this page as a template so its contents be utilized when creating other pages. Other users will be able to use this template if they have view permissions for this page.', + 'templates_replace_content' => 'Replace page content', + 'templates_append_content' => 'Append to page content', + 'templates_prepend_content' => 'Prepend to page content', + + // Profile View + 'profile_user_for_x' => 'User for :time', + 'profile_created_content' => 'Created Content', + 'profile_not_created_pages' => ':userName has not created any pages', + 'profile_not_created_chapters' => ':userName has not created any chapters', + 'profile_not_created_books' => ':userName has not created any books', + 'profile_not_created_shelves' => ':userName has not created any shelves', + + // Comments + 'comment' => 'Comment', + 'comments' => 'Comments', + 'comment_add' => 'Add Comment', + 'comment_placeholder' => 'Leave a comment here', + 'comment_count' => '{0} No Comments|{1} 1 Comment|[2,*] :count Comments', + 'comment_save' => 'Save Comment', + 'comment_saving' => 'Saving comment...', + 'comment_deleting' => 'Deleting comment...', + 'comment_new' => 'New Comment', + 'comment_created' => 'commented :createDiff', + 'comment_updated' => 'Updated :updateDiff by :username', + 'comment_deleted_success' => 'Comment deleted', + 'comment_created_success' => 'Comment added', + 'comment_updated_success' => 'Comment updated', + 'comment_delete_confirm' => 'Are you sure you want to delete this comment?', + 'comment_in_reply_to' => 'In reply to :commentId', + + // Revision + 'revision_delete_confirm' => 'Are you sure you want to delete this revision?', + 'revision_restore_confirm' => 'Are you sure you want to restore this revision? The current page contents will be replaced.', + 'revision_delete_success' => 'Revision deleted', + 'revision_cannot_delete_latest' => 'Cannot delete the latest revision.' +]; \ No newline at end of file diff --git a/resources/lang/th/errors.php b/resources/lang/th/errors.php new file mode 100644 index 000000000..06a5285f5 --- /dev/null +++ b/resources/lang/th/errors.php @@ -0,0 +1,103 @@ + 'You do not have permission to access the requested page.', + 'permissionJson' => 'You do not have permission to perform the requested action.', + + // Auth + 'error_user_exists_different_creds' => 'A user with the email :email already exists but with different credentials.', + 'email_already_confirmed' => 'Email has already been confirmed, Try logging in.', + 'email_confirmation_invalid' => 'This confirmation token is not valid or has already been used, Please try registering again.', + 'email_confirmation_expired' => 'The confirmation token has expired, A new confirmation email has been sent.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', + 'ldap_fail_anonymous' => 'LDAP access failed using anonymous bind', + 'ldap_fail_authed' => 'LDAP access failed using given dn & password details', + 'ldap_extension_not_installed' => 'LDAP PHP extension not installed', + 'ldap_cannot_connect' => 'Cannot connect to ldap server, Initial connection failed', + 'saml_already_logged_in' => 'Already logged in', + 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', + 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', + 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', + 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', + 'social_no_action_defined' => 'No action defined', + 'social_login_bad_response' => "Error received during :socialAccount login: \n:error", + 'social_account_in_use' => 'This :socialAccount account is already in use, Try logging in via the :socialAccount option.', + 'social_account_email_in_use' => 'The email :email is already in use. If you already have an account you can connect your :socialAccount account from your profile settings.', + 'social_account_existing' => 'This :socialAccount is already attached to your profile.', + 'social_account_already_used_existing' => 'This :socialAccount account is already used by another user.', + 'social_account_not_used' => 'This :socialAccount account is not linked to any users. Please attach it in your profile settings. ', + 'social_account_register_instructions' => 'If you do not yet have an account, You can register an account using the :socialAccount option.', + 'social_driver_not_found' => 'Social driver not found', + 'social_driver_not_configured' => 'Your :socialAccount social settings are not configured correctly.', + 'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.', + + // 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.', + 'sorry_page_not_found_permission_warning' => 'If you expected this page to exist, you might not have permission to view it.', + 'return_home' => 'Return to home', + 'error_occurred' => 'An Error Occurred', + 'app_down' => ':appName is down right now', + 'back_soon' => 'It will be back up soon.', + + // 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', + + // Settings & Maintenance + 'maintenance_test_email_failure' => 'Error thrown when sending a test email:', + +]; diff --git a/resources/lang/th/pagination.php b/resources/lang/th/pagination.php new file mode 100644 index 000000000..85bd12fc3 --- /dev/null +++ b/resources/lang/th/pagination.php @@ -0,0 +1,12 @@ + '« Previous', + 'next' => 'Next »', + +]; diff --git a/resources/lang/th/passwords.php b/resources/lang/th/passwords.php new file mode 100644 index 000000000..b408f3c2f --- /dev/null +++ b/resources/lang/th/passwords.php @@ -0,0 +1,15 @@ + 'Passwords must be at least eight characters and match the confirmation.', + 'user' => "We can't find a user with that e-mail address.", + 'token' => 'The password reset token is invalid for this email address.', + 'sent' => 'We have e-mailed your password reset link!', + 'reset' => 'Your password has been reset!', + +]; diff --git a/resources/lang/th/settings.php b/resources/lang/th/settings.php new file mode 100644 index 000000000..f1345c743 --- /dev/null +++ b/resources/lang/th/settings.php @@ -0,0 +1,214 @@ + 'Settings', + 'settings_save' => 'Save Settings', + 'settings_save_success' => 'Settings saved', + + // App Settings + 'app_customization' => 'Customization', + 'app_features_security' => 'Features & Security', + 'app_name' => 'Application Name', + 'app_name_desc' => 'This name is shown in the header and in any system-sent emails.', + 'app_name_header' => 'Show name in header', + 'app_public_access' => 'Public Access', + 'app_public_access_desc' => 'Enabling this option will allow visitors, that are not logged-in, to access content in your BookStack instance.', + 'app_public_access_desc_guest' => 'Access for public visitors can be controlled through the "Guest" user.', + 'app_public_access_toggle' => 'Allow public access', + 'app_public_viewing' => 'Allow public viewing?', + 'app_secure_images' => 'Higher Security Image Uploads', + 'app_secure_images_toggle' => 'Enable higher security image uploads', + 'app_secure_images_desc' => 'For performance reasons, all images are public. This option adds a random, hard-to-guess string in front of image urls. Ensure directory indexes are not enabled to prevent easy access.', + 'app_editor' => 'Page Editor', + 'app_editor_desc' => 'Select which editor will be used by all users to edit pages.', + 'app_custom_html' => 'Custom HTML Head Content', + 'app_custom_html_desc' => 'Any content added here will be inserted into the bottom of the
section of every page. This is handy for overriding styles or adding analytics code.', + 'app_custom_html_disabled_notice' => 'Custom HTML head content is disabled on this settings page to ensure any breaking changes can be reverted.', + 'app_logo' => 'Application Logo', + 'app_logo_desc' => 'This image should be 43px in height.