diff --git a/app/Http/Controllers/AttachmentController.php b/app/Http/Controllers/AttachmentController.php index 62be0b852..b5e7db41e 100644 --- a/app/Http/Controllers/AttachmentController.php +++ b/app/Http/Controllers/AttachmentController.php @@ -77,7 +77,7 @@ class AttachmentController extends Controller $this->checkOwnablePermission('attachment-create', $attachment); if (intval($pageId) !== intval($attachment->uploaded_to)) { - return $this->jsonError('Page mismatch during attached file update'); + return $this->jsonError(trans('errors.attachment_page_mismatch')); } $uploadedFile = $request->file('file'); @@ -113,11 +113,11 @@ class AttachmentController extends Controller $this->checkOwnablePermission('attachment-create', $attachment); if (intval($pageId) !== intval($attachment->uploaded_to)) { - return $this->jsonError('Page mismatch during attachment update'); + return $this->jsonError(trans('errors.attachment_page_mismatch')); } $attachment = $this->attachmentService->updateFile($attachment, $request->all()); - return $attachment; + return response()->json($attachment); } /** @@ -175,7 +175,7 @@ class AttachmentController extends Controller $attachments = $request->get('files'); $this->attachmentService->updateFileOrderWithinPage($attachments, $pageId); - return response()->json(['message' => 'Attachment order updated']); + return response()->json(['message' => trans('entities.attachments_order_updated')]); } /** @@ -210,6 +210,6 @@ class AttachmentController extends Controller $attachment = $this->attachment->findOrFail($attachmentId); $this->checkOwnablePermission('attachment-delete', $attachment); $this->attachmentService->deleteFile($attachment); - return response()->json(['message' => 'Attachment deleted']); + return response()->json(['message' => trans('entities.attachments_deleted')]); } } diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php index 45e40e6fe..d1fbddc50 100644 --- a/app/Http/Controllers/Auth/ForgotPasswordController.php +++ b/app/Http/Controllers/Auth/ForgotPasswordController.php @@ -52,7 +52,7 @@ class ForgotPasswordController extends Controller ); if ($response === Password::RESET_LINK_SENT) { - $message = 'A password reset link has been sent to ' . $request->get('email') . '.'; + $message = trans('auth.reset_password_sent_success', ['email' => $request->get('email')]); session()->flash('success', $message); return back()->with('status', trans($response)); } diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index c9d6a5496..e7eeb9bc1 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -87,7 +87,7 @@ class LoginController extends Controller // Check for users with same email already $alreadyUser = $user->newQuery()->where('email', '=', $user->email)->count() > 0; if ($alreadyUser) { - throw new AuthException('A user with the email ' . $user->email . ' already exists but with different credentials.'); + throw new AuthException(trans('errors.error_user_exists_different_creds', ['email' => $user->email])); } $user->save(); diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index d9bb500b4..8b0ef309a 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -3,6 +3,7 @@ namespace BookStack\Http\Controllers\Auth; use BookStack\Exceptions\ConfirmationEmailException; +use BookStack\Exceptions\SocialSignInException; use BookStack\Exceptions\UserRegistrationException; use BookStack\Repos\UserRepo; use BookStack\Services\EmailConfirmationService; @@ -82,7 +83,7 @@ class RegisterController extends Controller protected function checkRegistrationAllowed() { if (!setting('registration-enabled')) { - throw new UserRegistrationException('Registrations are currently disabled.', '/login'); + throw new UserRegistrationException(trans('auth.registrations_disabled'), '/login'); } } @@ -147,7 +148,7 @@ class RegisterController extends Controller $restrictedEmailDomains = explode(',', str_replace(' ', '', setting('registration-restrict'))); $userEmailDomain = $domain = substr(strrchr($userData['email'], "@"), 1); if (!in_array($userEmailDomain, $restrictedEmailDomains)) { - throw new UserRegistrationException('That email domain does not have access to this application', '/register'); + throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), '/register'); } } @@ -169,7 +170,7 @@ class RegisterController extends Controller } auth()->login($newUser); - session()->flash('success', 'Thanks for signing up! You are now registered and signed in.'); + session()->flash('success', trans('auth.register_success')); return redirect($this->redirectPath()); } @@ -262,7 +263,7 @@ class RegisterController extends Controller return $this->socialRegisterCallback($socialDriver); } } else { - throw new SocialSignInException('No action defined', '/login'); + throw new SocialSignInException(trans('errors.social_no_action_defined'), '/login'); } return redirect()->back(); } diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php index bd64793f9..eb678503d 100644 --- a/app/Http/Controllers/Auth/ResetPasswordController.php +++ b/app/Http/Controllers/Auth/ResetPasswordController.php @@ -41,7 +41,7 @@ class ResetPasswordController extends Controller */ protected function sendResetResponse($response) { - $message = 'Your password has been successfully reset.'; + $message = trans('auth.reset_password_success'); session()->flash('success', $message); return redirect($this->redirectPath()) ->with('status', trans($response)); diff --git a/app/Http/Controllers/BookController.php b/app/Http/Controllers/BookController.php index 8ada59433..80a6c24b3 100644 --- a/app/Http/Controllers/BookController.php +++ b/app/Http/Controllers/BookController.php @@ -7,6 +7,7 @@ use BookStack\Http\Requests; use BookStack\Repos\BookRepo; use BookStack\Repos\ChapterRepo; use BookStack\Repos\PageRepo; +use Illuminate\Http\Response; use Views; class BookController extends Controller @@ -53,7 +54,7 @@ class BookController extends Controller public function create() { $this->checkPermission('book-create-all'); - $this->setPageTitle('Create New Book'); + $this->setPageTitle(trans('entities.books_create')); return view('books/create'); } @@ -99,7 +100,7 @@ class BookController extends Controller { $book = $this->bookRepo->getBySlug($slug); $this->checkOwnablePermission('book-update', $book); - $this->setPageTitle('Edit Book ' . $book->getShortName()); + $this->setPageTitle(trans('entities.books_edit_named',['bookName'=>$book->getShortName()])); return view('books/edit', ['book' => $book, 'current' => $book]); } @@ -131,7 +132,7 @@ class BookController extends Controller { $book = $this->bookRepo->getBySlug($bookSlug); $this->checkOwnablePermission('book-delete', $book); - $this->setPageTitle('Delete Book ' . $book->getShortName()); + $this->setPageTitle(trans('entities.books_delete_named', ['bookName'=>$book->getShortName()])); return view('books/delete', ['book' => $book, 'current' => $book]); } @@ -146,7 +147,7 @@ class BookController extends Controller $this->checkOwnablePermission('book-update', $book); $bookChildren = $this->bookRepo->getChildren($book, true); $books = $this->bookRepo->getAll(false); - $this->setPageTitle('Sort Book ' . $book->getShortName()); + $this->setPageTitle(trans('entities.books_sort_named', ['bookName'=>$book->getShortName()])); return view('books/sort', ['book' => $book, 'current' => $book, 'books' => $books, 'bookChildren' => $bookChildren]); } @@ -264,7 +265,7 @@ class BookController extends Controller $book = $this->bookRepo->getBySlug($bookSlug); $this->checkOwnablePermission('restrictions-manage', $book); $this->bookRepo->updateEntityPermissionsFromRequest($request, $book); - session()->flash('success', 'Book Restrictions Updated'); + session()->flash('success', trans('entities.books_permissions_updated')); return redirect($book->getUrl()); } } diff --git a/app/Http/Controllers/ChapterController.php b/app/Http/Controllers/ChapterController.php index a3fb600fd..849835185 100644 --- a/app/Http/Controllers/ChapterController.php +++ b/app/Http/Controllers/ChapterController.php @@ -3,9 +3,9 @@ use Activity; use BookStack\Repos\UserRepo; use Illuminate\Http\Request; -use BookStack\Http\Requests; use BookStack\Repos\BookRepo; use BookStack\Repos\ChapterRepo; +use Illuminate\Http\Response; use Views; class ChapterController extends Controller @@ -38,7 +38,7 @@ class ChapterController extends Controller { $book = $this->bookRepo->getBySlug($bookSlug); $this->checkOwnablePermission('chapter-create', $book); - $this->setPageTitle('Create New Chapter'); + $this->setPageTitle(trans('entities.chapters_create')); return view('chapters/create', ['book' => $book, 'current' => $book]); } @@ -99,7 +99,7 @@ class ChapterController extends Controller $book = $this->bookRepo->getBySlug($bookSlug); $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); $this->checkOwnablePermission('chapter-update', $chapter); - $this->setPageTitle('Edit Chapter' . $chapter->getShortName()); + $this->setPageTitle(trans('entities.chapters_edit_named', ['chapterName' => $chapter->getShortName()])); return view('chapters/edit', ['book' => $book, 'chapter' => $chapter, 'current' => $chapter]); } @@ -136,7 +136,7 @@ class ChapterController extends Controller $book = $this->bookRepo->getBySlug($bookSlug); $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); $this->checkOwnablePermission('chapter-delete', $chapter); - $this->setPageTitle('Delete Chapter' . $chapter->getShortName()); + $this->setPageTitle(trans('entities.chapters_delete_named', ['chapterName' => $chapter->getShortName()])); return view('chapters/delete', ['book' => $book, 'chapter' => $chapter, 'current' => $chapter]); } @@ -166,6 +166,7 @@ class ChapterController extends Controller public function showMove($bookSlug, $chapterSlug) { $book = $this->bookRepo->getBySlug($bookSlug); $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); + $this->setPageTitle(trans('entities.chapters_move_named', ['chapterName' => $chapter->getShortName()])); $this->checkOwnablePermission('chapter-update', $chapter); return view('chapters/move', [ 'chapter' => $chapter, @@ -202,13 +203,13 @@ class ChapterController extends Controller } if ($parent === false || $parent === null) { - session()->flash('The selected Book was not found'); + session()->flash('error', trans('errors.selected_book_not_found')); return redirect()->back(); } $this->chapterRepo->changeBook($parent->id, $chapter, true); Activity::add($chapter, 'chapter_move', $chapter->book->id); - session()->flash('success', sprintf('Chapter moved to "%s"', $parent->name)); + session()->flash('success', trans('entities.chapter_move_success', ['bookName' => $parent->name])); return redirect($chapter->getUrl()); } @@ -244,7 +245,7 @@ class ChapterController extends Controller $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); $this->checkOwnablePermission('restrictions-manage', $chapter); $this->chapterRepo->updateEntityPermissionsFromRequest($request, $chapter); - session()->flash('success', 'Chapter Restrictions Updated'); + session()->flash('success', trans('entities.chapters_permissions_success')); return redirect($chapter->getUrl()); } } diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index 2fc64b236..e325b9322 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -43,4 +43,39 @@ class HomeController extends Controller ]); } + /** + * Get a js representation of the current translations + * @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response + */ + public function getTranslations() { + $locale = trans()->getLocale(); + $cacheKey = 'GLOBAL_TRANSLATIONS_' . $locale; + if (cache()->has($cacheKey) && config('app.env') !== 'development') { + $resp = cache($cacheKey); + } else { + $translations = [ + // Get only translations which might be used in JS + 'common' => trans('common'), + 'components' => trans('components'), + 'entities' => trans('entities'), + 'errors' => trans('errors') + ]; + if ($locale !== 'en') { + $enTrans = [ + 'common' => trans('common', [], null, 'en'), + 'components' => trans('components', [], null, 'en'), + 'entities' => trans('entities', [], null, 'en'), + 'errors' => trans('errors', [], null, 'en') + ]; + $translations = array_replace_recursive($enTrans, $translations); + } + $resp = 'window.translations = ' . json_encode($translations); + cache()->put($cacheKey, $resp, 120); + } + + return response($resp, 200, [ + 'Content-Type' => 'application/javascript' + ]); + } + } diff --git a/app/Http/Controllers/ImageController.php b/app/Http/Controllers/ImageController.php index 621c23e85..f073bea0a 100644 --- a/app/Http/Controllers/ImageController.php +++ b/app/Http/Controllers/ImageController.php @@ -73,6 +73,7 @@ class ImageController extends Controller * @param $filter * @param int $page * @param Request $request + * @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response */ public function getGalleryFiltered($filter, $page = 0, Request $request) { @@ -169,7 +170,7 @@ class ImageController extends Controller } $this->imageRepo->destroyImage($image); - return response()->json('Image Deleted'); + return response()->json(trans('components.images_deleted')); } diff --git a/app/Http/Controllers/PageController.php b/app/Http/Controllers/PageController.php index c2d8e257c..e40d7668a 100644 --- a/app/Http/Controllers/PageController.php +++ b/app/Http/Controllers/PageController.php @@ -10,6 +10,7 @@ use BookStack\Http\Requests; use BookStack\Repos\BookRepo; use BookStack\Repos\ChapterRepo; use BookStack\Repos\PageRepo; +use Illuminate\Http\Response; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Views; use GatherContent\Htmldiff\Htmldiff; @@ -62,7 +63,7 @@ class PageController extends Controller } // Otherwise show edit view - $this->setPageTitle('Create New Page'); + $this->setPageTitle(trans('entities.pages_new')); return view('pages/guest-create', ['parent' => $parent]); } @@ -104,7 +105,7 @@ class PageController extends Controller $book = $this->bookRepo->getBySlug($bookSlug); $draft = $this->pageRepo->getById($pageId, true); $this->checkOwnablePermission('page-create', $book); - $this->setPageTitle('Edit Page Draft'); + $this->setPageTitle(trans('entities.pages_edit_draft')); $draftsEnabled = $this->signedIn; return view('pages/edit', [ @@ -119,6 +120,7 @@ class PageController extends Controller * Store a new page by changing a draft into a page. * @param Request $request * @param string $bookSlug + * @param int $pageId * @return Response */ public function store(Request $request, $bookSlug, $pageId) @@ -201,7 +203,7 @@ class PageController extends Controller $book = $this->bookRepo->getBySlug($bookSlug); $page = $this->pageRepo->getBySlug($pageSlug, $book->id); $this->checkOwnablePermission('page-update', $page); - $this->setPageTitle('Editing Page ' . $page->getShortName()); + $this->setPageTitle(trans('entities.pages_editing_named', ['pageName'=>$page->getShortName()])); $page->isDraft = false; // Check for active editing @@ -265,7 +267,7 @@ class PageController extends Controller if (!$this->signedIn) { return response()->json([ 'status' => 'error', - 'message' => 'Guests cannot save drafts', + 'message' => trans('errors.guests_cannot_save_drafts'), ], 500); } @@ -279,7 +281,7 @@ class PageController extends Controller $utcUpdateTimestamp = $updateTime + Carbon::createFromTimestamp(0)->offset; return response()->json([ 'status' => 'success', - 'message' => 'Draft saved at ', + 'message' => trans('entities.pages_edit_draft_save_at'), 'timestamp' => $utcUpdateTimestamp ]); } @@ -307,7 +309,7 @@ class PageController extends Controller $book = $this->bookRepo->getBySlug($bookSlug); $page = $this->pageRepo->getBySlug($pageSlug, $book->id); $this->checkOwnablePermission('page-delete', $page); - $this->setPageTitle('Delete Page ' . $page->getShortName()); + $this->setPageTitle(trans('entities.pages_delete_named', ['pageName'=>$page->getShortName()])); return view('pages/delete', ['book' => $book, 'page' => $page, 'current' => $page]); } @@ -324,7 +326,7 @@ class PageController extends Controller $book = $this->bookRepo->getBySlug($bookSlug); $page = $this->pageRepo->getById($pageId, true); $this->checkOwnablePermission('page-update', $page); - $this->setPageTitle('Delete Draft Page ' . $page->getShortName()); + $this->setPageTitle(trans('entities.pages_delete_draft_named', ['pageName'=>$page->getShortName()])); return view('pages/delete', ['book' => $book, 'page' => $page, 'current' => $page]); } @@ -341,7 +343,7 @@ class PageController extends Controller $page = $this->pageRepo->getBySlug($pageSlug, $book->id); $this->checkOwnablePermission('page-delete', $page); Activity::addMessage('page_delete', $book->id, $page->name); - session()->flash('success', 'Page deleted'); + session()->flash('success', trans('entities.pages_delete_success')); $this->pageRepo->destroy($page); return redirect($book->getUrl()); } @@ -358,7 +360,7 @@ class PageController extends Controller $book = $this->bookRepo->getBySlug($bookSlug); $page = $this->pageRepo->getById($pageId, true); $this->checkOwnablePermission('page-update', $page); - session()->flash('success', 'Draft deleted'); + session()->flash('success', trans('entities.pages_delete_draft_success')); $this->pageRepo->destroy($page); return redirect($book->getUrl()); } @@ -373,7 +375,7 @@ class PageController extends Controller { $book = $this->bookRepo->getBySlug($bookSlug); $page = $this->pageRepo->getBySlug($pageSlug, $book->id); - $this->setPageTitle('Revisions For ' . $page->getShortName()); + $this->setPageTitle(trans('entities.pages_revisions_named', ['pageName'=>$page->getShortName()])); return view('pages/revisions', ['page' => $page, 'book' => $book, 'current' => $page]); } @@ -391,7 +393,7 @@ class PageController extends Controller $revision = $this->pageRepo->getRevisionById($revisionId); $page->fill($revision->toArray()); - $this->setPageTitle('Page Revision For ' . $page->getShortName()); + $this->setPageTitle(trans('entities.pages_revision_named', ['pageName'=>$page->getShortName()])); return view('pages/revision', [ 'page' => $page, @@ -417,7 +419,7 @@ class PageController extends Controller $diff = (new Htmldiff)->diff($prevContent, $revision->html); $page->fill($revision->toArray()); - $this->setPageTitle('Page Revision For ' . $page->getShortName()); + $this->setPageTitle(trans('entities.pages_revision_named', ['pageName'=>$page->getShortName()])); return view('pages/revision', [ 'page' => $page, @@ -503,7 +505,7 @@ class PageController extends Controller { $pages = $this->pageRepo->getRecentlyCreatedPaginated(20)->setPath(baseUrl('/pages/recently-created')); return view('pages/detailed-listing', [ - 'title' => 'Recently Created Pages', + 'title' => trans('entities.recently_created_pages'), 'pages' => $pages ]); } @@ -516,7 +518,7 @@ class PageController extends Controller { $pages = $this->pageRepo->getRecentlyUpdatedPaginated(20)->setPath(baseUrl('/pages/recently-updated')); return view('pages/detailed-listing', [ - 'title' => 'Recently Updated Pages', + 'title' => trans('entities.recently_updated_pages'), 'pages' => $pages ]); } @@ -589,13 +591,13 @@ class PageController extends Controller } if ($parent === false || $parent === null) { - session()->flash('The selected Book or Chapter was not found'); + session()->flash(trans('entities.selected_book_chapter_not_found')); return redirect()->back(); } $this->pageRepo->changePageParent($page, $parent); Activity::add($page, 'page_move', $page->book->id); - session()->flash('success', sprintf('Page moved to "%s"', $parent->name)); + session()->flash('success', trans('entities.pages_move_success', ['parentName' => $parent->name])); return redirect($page->getUrl()); } @@ -613,7 +615,7 @@ class PageController extends Controller $page = $this->pageRepo->getBySlug($pageSlug, $book->id); $this->checkOwnablePermission('restrictions-manage', $page); $this->pageRepo->updateEntityPermissionsFromRequest($request, $page); - session()->flash('success', 'Page Permissions Updated'); + session()->flash('success', trans('entities.pages_permissions_success')); return redirect($page->getUrl()); } diff --git a/app/Http/Controllers/PermissionController.php b/app/Http/Controllers/PermissionController.php index ed430c0b7..cd064e7e8 100644 --- a/app/Http/Controllers/PermissionController.php +++ b/app/Http/Controllers/PermissionController.php @@ -2,9 +2,7 @@ use BookStack\Exceptions\PermissionsException; use BookStack\Repos\PermissionsRepo; -use BookStack\Services\PermissionService; use Illuminate\Http\Request; -use BookStack\Http\Requests; class PermissionController extends Controller { @@ -55,7 +53,7 @@ class PermissionController extends Controller ]); $this->permissionsRepo->saveNewRole($request->all()); - session()->flash('success', 'Role successfully created'); + session()->flash('success', trans('settings.role_create_success')); return redirect('/settings/roles'); } @@ -69,7 +67,7 @@ class PermissionController extends Controller { $this->checkPermission('user-roles-manage'); $role = $this->permissionsRepo->getRoleById($id); - if ($role->hidden) throw new PermissionsException('This role cannot be edited'); + if ($role->hidden) throw new PermissionsException(trans('errors.role_cannot_be_edited')); return view('settings/roles/edit', ['role' => $role]); } @@ -88,7 +86,7 @@ class PermissionController extends Controller ]); $this->permissionsRepo->updateRole($id, $request->all()); - session()->flash('success', 'Role successfully updated'); + session()->flash('success', trans('settings.role_update_success')); return redirect('/settings/roles'); } @@ -103,7 +101,7 @@ class PermissionController extends Controller $this->checkPermission('user-roles-manage'); $role = $this->permissionsRepo->getRoleById($id); $roles = $this->permissionsRepo->getAllRolesExcept($role); - $blankRole = $role->newInstance(['display_name' => 'Don\'t migrate users']); + $blankRole = $role->newInstance(['display_name' => trans('settings.role_delete_no_migration')]); $roles->prepend($blankRole); return view('settings/roles/delete', ['role' => $role, 'roles' => $roles]); } @@ -126,7 +124,7 @@ class PermissionController extends Controller return redirect()->back(); } - session()->flash('success', 'Role successfully deleted'); + session()->flash('success', trans('settings.role_delete_success')); return redirect('/settings/roles'); } } diff --git a/app/Http/Controllers/SearchController.php b/app/Http/Controllers/SearchController.php index 58ad737c4..bb70b0f88 100644 --- a/app/Http/Controllers/SearchController.php +++ b/app/Http/Controllers/SearchController.php @@ -1,11 +1,7 @@ -pageRepo->getBySearch($searchTerm, [], 20, $paginationAppends); $books = $this->bookRepo->getBySearch($searchTerm, 10, $paginationAppends); $chapters = $this->chapterRepo->getBySearch($searchTerm, [], 10, $paginationAppends); - $this->setPageTitle('Search For ' . $searchTerm); + $this->setPageTitle(trans('entities.search_for_term', ['term' => $searchTerm])); return view('search/all', [ 'pages' => $pages, 'books' => $books, @@ -70,10 +66,10 @@ class SearchController extends Controller $searchTerm = $request->get('term'); $paginationAppends = $request->only('term'); $pages = $this->pageRepo->getBySearch($searchTerm, [], 20, $paginationAppends); - $this->setPageTitle('Page Search For ' . $searchTerm); + $this->setPageTitle(trans('entities.search_page_for_term', ['term' => $searchTerm])); return view('search/entity-search-list', [ 'entities' => $pages, - 'title' => 'Page Search Results', + 'title' => trans('entities.search_results_page'), 'searchTerm' => $searchTerm ]); } @@ -90,10 +86,10 @@ class SearchController extends Controller $searchTerm = $request->get('term'); $paginationAppends = $request->only('term'); $chapters = $this->chapterRepo->getBySearch($searchTerm, [], 20, $paginationAppends); - $this->setPageTitle('Chapter Search For ' . $searchTerm); + $this->setPageTitle(trans('entities.search_chapter_for_term', ['term' => $searchTerm])); return view('search/entity-search-list', [ 'entities' => $chapters, - 'title' => 'Chapter Search Results', + 'title' => trans('entities.search_results_chapter'), 'searchTerm' => $searchTerm ]); } @@ -110,10 +106,10 @@ class SearchController extends Controller $searchTerm = $request->get('term'); $paginationAppends = $request->only('term'); $books = $this->bookRepo->getBySearch($searchTerm, 20, $paginationAppends); - $this->setPageTitle('Book Search For ' . $searchTerm); + $this->setPageTitle(trans('entities.search_book_for_term', ['term' => $searchTerm])); return view('search/entity-search-list', [ 'entities' => $books, - 'title' => 'Book Search Results', + 'title' => trans('entities.search_results_book'), 'searchTerm' => $searchTerm ]); } diff --git a/app/Http/Controllers/SettingController.php b/app/Http/Controllers/SettingController.php index 65135eda3..70a12631a 100644 --- a/app/Http/Controllers/SettingController.php +++ b/app/Http/Controllers/SettingController.php @@ -1,8 +1,7 @@ flash('success', 'Settings Saved'); + session()->flash('success', trans('settings.settings_save_success')); return redirect('/settings'); } diff --git a/app/Http/Controllers/TagController.php b/app/Http/Controllers/TagController.php index c8a356541..24bdcdb1c 100644 --- a/app/Http/Controllers/TagController.php +++ b/app/Http/Controllers/TagController.php @@ -2,7 +2,6 @@ use BookStack\Repos\TagRepo; use Illuminate\Http\Request; -use BookStack\Http\Requests; class TagController extends Controller { @@ -16,12 +15,14 @@ class TagController extends Controller public function __construct(TagRepo $tagRepo) { $this->tagRepo = $tagRepo; + parent::__construct(); } /** * Get all the Tags for a particular entity * @param $entityType * @param $entityId + * @return \Illuminate\Http\JsonResponse */ public function getForEntity($entityType, $entityId) { @@ -29,29 +30,10 @@ class TagController extends Controller return response()->json($tags); } - /** - * Update the tags for a particular entity. - * @param $entityType - * @param $entityId - * @param Request $request - * @return mixed - */ - public function updateForEntity($entityType, $entityId, Request $request) - { - $entity = $this->tagRepo->getEntity($entityType, $entityId, 'update'); - if ($entity === null) return $this->jsonError("Entity not found", 404); - - $inputTags = $request->input('tags'); - $tags = $this->tagRepo->saveTagsToEntity($entity, $inputTags); - return response()->json([ - 'tags' => $tags, - 'message' => 'Tags successfully updated' - ]); - } - /** * Get tag name suggestions from a given search term. * @param Request $request + * @return \Illuminate\Http\JsonResponse */ public function getNameSuggestions(Request $request) { @@ -63,6 +45,7 @@ class TagController extends Controller /** * Get tag value suggestions from a given search term. * @param Request $request + * @return \Illuminate\Http\JsonResponse */ public function getValueSuggestions(Request $request) { diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 18ef1a671..b5184c40a 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -44,7 +44,7 @@ class UserController extends Controller 'sort' => $request->has('sort') ? $request->get('sort') : 'name', ]; $users = $this->userRepo->getAllUsersPaginatedAndSorted(20, $listDetails); - $this->setPageTitle('Users'); + $this->setPageTitle(trans('settings.users')); $users->appends($listDetails); return view('users/index', ['users' => $users, 'listDetails' => $listDetails]); } @@ -83,7 +83,6 @@ class UserController extends Controller } $this->validate($request, $validationRules); - $user = $this->user->fill($request->all()); if ($authMethod === 'standard') { @@ -131,7 +130,7 @@ class UserController extends Controller $authMethod = ($user->system_name) ? 'system' : config('auth.method'); $activeSocialDrivers = $socialAuthService->getActiveDrivers(); - $this->setPageTitle('User Profile'); + $this->setPageTitle(trans('settings.user_profile')); $roles = $this->userRepo->getAllRoles(); return view('users/edit', ['user' => $user, 'activeSocialDrivers' => $activeSocialDrivers, 'authMethod' => $authMethod, 'roles' => $roles]); } @@ -154,8 +153,6 @@ class UserController extends Controller 'email' => 'min:2|email|unique:users,email,' . $id, 'password' => 'min:5|required_with:password_confirm', 'password-confirm' => 'same:password|required_with:password' - ], [ - 'password-confirm.required_with' => 'Password confirmation required' ]); $user = $this->user->findOrFail($id); @@ -179,7 +176,7 @@ class UserController extends Controller } $user->save(); - session()->flash('success', 'User successfully updated'); + session()->flash('success', trans('settings.users_edit_success')); $redirectUrl = userCan('users-manage') ? '/settings/users' : '/settings/users/' . $user->id; return redirect($redirectUrl); @@ -197,7 +194,7 @@ class UserController extends Controller }); $user = $this->user->findOrFail($id); - $this->setPageTitle('Delete User ' . $user->name); + $this->setPageTitle(trans('settings.users_delete_named', ['userName' => $user->name])); return view('users/delete', ['user' => $user]); } @@ -216,17 +213,17 @@ class UserController extends Controller $user = $this->userRepo->getById($id); if ($this->userRepo->isOnlyAdmin($user)) { - session()->flash('error', 'You cannot delete the only admin'); + session()->flash('error', trans('errors.users_cannot_delete_only_admin')); return redirect($user->getEditUrl()); } if ($user->system_name === 'public') { - session()->flash('error', 'You cannot delete the guest user'); + session()->flash('error', trans('errors.users_cannot_delete_guest')); return redirect($user->getEditUrl()); } $this->userRepo->destroy($user); - session()->flash('success', 'User successfully removed'); + session()->flash('success', trans('settings.users_delete_success')); return redirect('/settings/users'); } diff --git a/app/Notifications/ResetPassword.php b/app/Notifications/ResetPassword.php index 646030a10..affd8f076 100644 --- a/app/Notifications/ResetPassword.php +++ b/app/Notifications/ResetPassword.php @@ -43,8 +43,9 @@ class ResetPassword extends Notification public function toMail() { return (new MailMessage) - ->line('You are receiving this email because we received a password reset request for your account.') - ->action('Reset Password', baseUrl('password/reset/' . $this->token)) - ->line('If you did not request a password reset, no further action is required.'); + ->subject(trans('auth.email_reset_subject', ['appName' => setting('app-name')])) + ->line(trans('auth.email_reset_text')) + ->action(trans('auth.reset_password'), baseUrl('password/reset/' . $this->token)) + ->line(trans('auth.email_reset_not_requested')); } } diff --git a/app/Repos/BookRepo.php b/app/Repos/BookRepo.php index 7bb91f472..b14cf0dab 100644 --- a/app/Repos/BookRepo.php +++ b/app/Repos/BookRepo.php @@ -109,7 +109,7 @@ class BookRepo extends EntityRepo public function getBySlug($slug) { $book = $this->bookQuery()->where('slug', '=', $slug)->first(); - if ($book === null) throw new NotFoundException('Book not found'); + if ($book === null) throw new NotFoundException(trans('errors.book_not_found')); return $book; } diff --git a/app/Repos/ChapterRepo.php b/app/Repos/ChapterRepo.php index 4c13b9aaf..4106f93ee 100644 --- a/app/Repos/ChapterRepo.php +++ b/app/Repos/ChapterRepo.php @@ -69,7 +69,7 @@ class ChapterRepo extends EntityRepo public function getBySlug($slug, $bookId) { $chapter = $this->chapterQuery()->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first(); - if ($chapter === null) throw new NotFoundException('Chapter not found'); + if ($chapter === null) throw new NotFoundException(trans('errors.chapter_not_found')); return $chapter; } diff --git a/app/Repos/PageRepo.php b/app/Repos/PageRepo.php index e6d713f77..14463c12d 100644 --- a/app/Repos/PageRepo.php +++ b/app/Repos/PageRepo.php @@ -66,7 +66,7 @@ class PageRepo extends EntityRepo public function getBySlug($slug, $bookId) { $page = $this->pageQuery()->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first(); - if ($page === null) throw new NotFoundException('Page not found'); + if ($page === null) throw new NotFoundException(trans('errors.page_not_found')); return $page; } @@ -134,7 +134,7 @@ class PageRepo extends EntityRepo $draftPage->draft = false; $draftPage->save(); - $this->saveRevision($draftPage, 'Initial Publish'); + $this->saveRevision($draftPage, trans('entities.pages_initial_revision')); return $draftPage; } @@ -143,12 +143,12 @@ class PageRepo extends EntityRepo * Get a new draft page instance. * @param Book $book * @param Chapter|bool $chapter - * @return static + * @return Page */ public function getDraftPage(Book $book, $chapter = false) { $page = $this->page->newInstance(); - $page->name = 'New Page'; + $page->name = trans('entities.pages_initial_name'); $page->created_by = user()->id; $page->updated_by = user()->id; $page->draft = true; @@ -487,11 +487,9 @@ class PageRepo extends EntityRepo */ public function getUserPageDraftMessage(PageRevision $draft) { - $message = 'You are currently editing a draft that was last saved ' . $draft->updated_at->diffForHumans() . '.'; - if ($draft->page->updated_at->timestamp > $draft->updated_at->timestamp) { - $message .= "\n This page has been updated by since that time. It is recommended that you discard this draft."; - } - return $message; + $message = trans('entities.pages_editing_draft_notification', ['timeDiff' => $draft->updated_at->diffForHumans()]); + if ($draft->page->updated_at->timestamp <= $draft->updated_at->timestamp) return $message; + return $message . "\n" . trans('entities.pages_draft_edited_notification'); } /** @@ -519,10 +517,10 @@ class PageRepo extends EntityRepo public function getPageEditingActiveMessage(Page $page, $minRange = null) { $pageDraftEdits = $this->activePageEditingQuery($page, $minRange)->get(); - $userMessage = $pageDraftEdits->count() > 1 ? $pageDraftEdits->count() . ' users have' : $pageDraftEdits->first()->createdBy->name . ' has'; - $timeMessage = $minRange === null ? 'since the page was last updated' : 'in the last ' . $minRange . ' minutes'; - $message = '%s started editing this page %s. Take care not to overwrite each other\'s updates!'; - return sprintf($message, $userMessage, $timeMessage); + + $userMessage = $pageDraftEdits->count() > 1 ? trans('entities.pages_draft_edit_active.start_a', ['count' => $pageDraftEdits->count()]): trans('entities.pages_draft_edit_active.start_b', ['userName' => $pageDraftEdits->first()->createdBy->name]); + $timeMessage = $minRange === null ? trans('entities.pages_draft_edit_active.time_a') : trans('entities.pages_draft_edit_active.time_b', ['minCount'=>$minRange]); + return trans('entities.pages_draft_edit_active.message', ['start' => $userMessage, 'time' => $timeMessage]); } /** diff --git a/app/Repos/PermissionsRepo.php b/app/Repos/PermissionsRepo.php index 24497c911..e1c6d87b1 100644 --- a/app/Repos/PermissionsRepo.php +++ b/app/Repos/PermissionsRepo.php @@ -133,9 +133,9 @@ class PermissionsRepo // Prevent deleting admin role or default registration role. if ($role->system_name && in_array($role->system_name, $this->systemRoles)) { - throw new PermissionsException('This role is a system role and cannot be deleted'); + throw new PermissionsException(trans('errors.role_system_cannot_be_deleted')); } else if ($role->id == setting('registration-role')) { - throw new PermissionsException('This role cannot be deleted while set as the default registration role.'); + throw new PermissionsException(trans('errors.role_registration_default_cannot_delete')); } if ($migrateRoleId) { diff --git a/app/Repos/TagRepo.php b/app/Repos/TagRepo.php index 6d0857f8b..6e422c4f4 100644 --- a/app/Repos/TagRepo.php +++ b/app/Repos/TagRepo.php @@ -121,7 +121,7 @@ class TagRepo /** * Create a new Tag instance from user input. * @param $input - * @return static + * @return Tag */ protected function newInstanceFromInput($input) { diff --git a/app/Repos/UserRepo.php b/app/Repos/UserRepo.php index ab3716fca..22c92f3ce 100644 --- a/app/Repos/UserRepo.php +++ b/app/Repos/UserRepo.php @@ -3,7 +3,6 @@ use BookStack\Role; use BookStack\User; use Exception; -use Setting; class UserRepo { diff --git a/app/Services/AttachmentService.php b/app/Services/AttachmentService.php index e0ee3a04d..592d67e63 100644 --- a/app/Services/AttachmentService.php +++ b/app/Services/AttachmentService.php @@ -193,7 +193,7 @@ class AttachmentService extends UploadService try { $storage->put($attachmentStoragePath, $attachmentData); } catch (Exception $e) { - throw new FileUploadException('File path ' . $attachmentStoragePath . ' could not be uploaded to. Ensure it is writable to the server.'); + throw new FileUploadException(trans('errors.path_not_writable', ['filePath' => $attachmentStoragePath])); } return $attachmentPath; } diff --git a/app/Services/EmailConfirmationService.php b/app/Services/EmailConfirmationService.php index d4ec1e976..8eb52708c 100644 --- a/app/Services/EmailConfirmationService.php +++ b/app/Services/EmailConfirmationService.php @@ -33,7 +33,7 @@ class EmailConfirmationService public function sendConfirmation(User $user) { if ($user->email_confirmed) { - throw new ConfirmationEmailException('Email has already been confirmed, Try logging in.', '/login'); + throw new ConfirmationEmailException(trans('errors.email_already_confirmed'), '/login'); } $this->deleteConfirmationsByUser($user); @@ -63,7 +63,7 @@ class EmailConfirmationService * Gets an email confirmation by looking up the token, * Ensures the token has not expired. * @param string $token - * @return EmailConfirmation + * @return array|null|\stdClass * @throws UserRegistrationException */ public function getEmailConfirmationFromToken($token) @@ -72,14 +72,14 @@ class EmailConfirmationService // If not found show error if ($emailConfirmation === null) { - throw new UserRegistrationException('This confirmation token is not valid or has already been used, Please try registering again.', '/register'); + throw new UserRegistrationException(trans('errors.email_confirmation_invalid'), '/register'); } // If more than a day old if (Carbon::now()->subDay()->gt(new Carbon($emailConfirmation->created_at))) { $user = $this->users->getById($emailConfirmation->user_id); $this->sendConfirmation($user); - throw new UserRegistrationException('The confirmation token has expired, A new confirmation email has been sent.', '/register/confirm'); + throw new UserRegistrationException(trans('errors.email_confirmation_expired'), '/register/confirm'); } $emailConfirmation->user = $this->users->getById($emailConfirmation->user_id); diff --git a/app/Services/ImageService.php b/app/Services/ImageService.php index dfe2cf453..e34b3fb2b 100644 --- a/app/Services/ImageService.php +++ b/app/Services/ImageService.php @@ -59,7 +59,7 @@ class ImageService extends UploadService { $imageName = $imageName ? $imageName : basename($url); $imageData = file_get_contents($url); - if($imageData === false) throw new \Exception('Cannot get image from ' . $url); + if($imageData === false) throw new \Exception(trans('errors.cannot_get_image_from_url', ['url' => $url])); return $this->saveNew($imageName, $imageData, $type); } @@ -93,7 +93,7 @@ class ImageService extends UploadService $storage->put($fullPath, $imageData); $storage->setVisibility($fullPath, 'public'); } catch (Exception $e) { - throw new ImageUploadException('Image Path ' . $fullPath . ' is not writable by the server.'); + throw new ImageUploadException(trans('errors.path_not_writable', ['filePath' => $fullPath])); } if ($this->isLocal()) $fullPath = str_replace_first('/public', '', $fullPath); @@ -160,7 +160,7 @@ class ImageService extends UploadService $thumb = $this->imageTool->make($storage->get($imagePath)); } catch (Exception $e) { if ($e instanceof \ErrorException || $e instanceof NotSupportedException) { - throw new ImageUploadException('The server cannot create thumbnails. Please check you have the GD PHP extension installed.'); + throw new ImageUploadException(trans('errors.cannot_create_thumbs')); } else { throw $e; } diff --git a/app/Services/LdapService.php b/app/Services/LdapService.php index b7f101ad2..40b24f141 100644 --- a/app/Services/LdapService.php +++ b/app/Services/LdapService.php @@ -94,7 +94,7 @@ class LdapService $ldapBind = $this->ldap->bind($connection, $ldapDn, $ldapPass); } - if (!$ldapBind) throw new LdapException('LDAP access failed using ' . ($isAnonymous ? ' anonymous bind.' : ' given dn & pass details')); + if (!$ldapBind) throw new LdapException(($isAnonymous ? trans('errors.ldap_fail_anonymous') : trans('errors.ldap_fail_authed'))); } /** @@ -109,7 +109,7 @@ class LdapService // Check LDAP extension in installed if (!function_exists('ldap_connect') && config('app.env') !== 'testing') { - throw new LdapException('LDAP PHP extension not installed'); + throw new LdapException(trans('errors.ldap_extension_not_installed')); } // Get port from server string if specified. @@ -117,7 +117,7 @@ class LdapService $ldapConnection = $this->ldap->connect($ldapServer[0], count($ldapServer) > 1 ? $ldapServer[1] : 389); if ($ldapConnection === false) { - throw new LdapException('Cannot connect to ldap server, Initial connection failed'); + throw new LdapException(trans('errors.ldap_cannot_connect')); } // Set any required options diff --git a/app/Services/SocialAuthService.php b/app/Services/SocialAuthService.php index d76a7231b..fe554b8d7 100644 --- a/app/Services/SocialAuthService.php +++ b/app/Services/SocialAuthService.php @@ -70,12 +70,12 @@ class SocialAuthService // Check social account has not already been used if ($this->socialAccount->where('driver_id', '=', $socialUser->getId())->exists()) { - throw new UserRegistrationException('This ' . $socialDriver . ' account is already in use, Try logging in via the ' . $socialDriver . ' option.', '/login'); + throw new UserRegistrationException(trans('errors.social_account_in_use', ['socialAccount'=>$socialDriver]), '/login'); } if ($this->userRepo->getByEmail($socialUser->getEmail())) { $email = $socialUser->getEmail(); - throw new UserRegistrationException('The email ' . $email . ' is already in use. If you already have an account you can connect your ' . $socialDriver . ' account from your profile settings.', '/login'); + throw new UserRegistrationException(trans('errors.social_account_in_use', ['socialAccount'=>$socialDriver, 'email' => $email]), '/login'); } return $socialUser; @@ -113,27 +113,26 @@ class SocialAuthService if ($isLoggedIn && $socialAccount === null) { $this->fillSocialAccount($socialDriver, $socialUser); $currentUser->socialAccounts()->save($this->socialAccount); - session()->flash('success', title_case($socialDriver) . ' account was successfully attached to your profile.'); + session()->flash('success', trans('settings.users_social_connected', ['socialAccount' => title_case($socialDriver)])); return redirect($currentUser->getEditUrl()); } // When a user is logged in and the social account exists and is already linked to the current user. if ($isLoggedIn && $socialAccount !== null && $socialAccount->user->id === $currentUser->id) { - session()->flash('error', 'This ' . title_case($socialDriver) . ' account is already attached to your profile.'); + session()->flash('error', trans('errors.social_account_existing', ['socialAccount' => title_case($socialDriver)])); return redirect($currentUser->getEditUrl()); } // When a user is logged in, A social account exists but the users do not match. - // Change the user that the social account is assigned to. if ($isLoggedIn && $socialAccount !== null && $socialAccount->user->id != $currentUser->id) { - session()->flash('success', 'This ' . title_case($socialDriver) . ' account is already used by another user.'); + session()->flash('error', trans('errors.social_account_already_used_existing', ['socialAccount' => title_case($socialDriver)])); return redirect($currentUser->getEditUrl()); } // Otherwise let the user know this social account is not used by anyone. - $message = 'This ' . $socialDriver . ' account is not linked to any users. Please attach it in your profile settings'; + $message = trans('errors.social_account_not_used', ['socialAccount' => title_case($socialDriver)]); if (setting('registration-enabled')) { - $message .= ' or, If you do not yet have an account, You can register an account using the ' . $socialDriver . ' option'; + $message .= trans('errors.social_account_register_instructions', ['socialAccount' => title_case($socialDriver)]); } throw new SocialSignInException($message . '.', '/login'); @@ -157,8 +156,8 @@ class SocialAuthService { $driver = trim(strtolower($socialDriver)); - if (!in_array($driver, $this->validSocialDrivers)) abort(404, 'Social Driver Not Found'); - if (!$this->checkDriverConfigured($driver)) throw new SocialDriverNotConfigured("Your {$driver} social settings are not configured correctly."); + if (!in_array($driver, $this->validSocialDrivers)) abort(404, trans('errors.social_driver_not_found')); + if (!$this->checkDriverConfigured($driver)) throw new SocialDriverNotConfigured(trans('errors.social_driver_not_configured', ['socialAccount' => title_case($socialDriver)])); return $driver; } @@ -215,7 +214,7 @@ class SocialAuthService { session(); user()->socialAccounts()->where('driver', '=', $socialDriver)->delete(); - session()->flash('success', title_case($socialDriver) . ' account successfully detached'); + session()->flash('success', trans('settings.users_social_disconnected', ['socialAccount' => title_case($socialDriver)])); return redirect(user()->getEditUrl()); } diff --git a/config/setting-defaults.php b/config/setting-defaults.php index c681bb7f5..db35023d5 100644 --- a/config/setting-defaults.php +++ b/config/setting-defaults.php @@ -6,6 +6,7 @@ return [ 'app-name' => 'BookStack', + 'app-logo' => '', 'app-name-header' => true, 'app-editor' => 'wysiwyg', 'app-color' => '#0288D1', diff --git a/phpunit.xml b/phpunit.xml index 72e06a3fc..2e07cdbf8 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -22,6 +22,7 @@ + diff --git a/resources/assets/js/controllers.js b/resources/assets/js/controllers.js index 9d7f7ad70..0d57b09ad 100644 --- a/resources/assets/js/controllers.js +++ b/resources/assets/js/controllers.js @@ -2,6 +2,8 @@ import moment from 'moment'; import 'moment/locale/en-gb'; +import editorOptions from "./pages/page-form"; + moment.locale('en-gb'); export default function (ngApp, events) { @@ -23,14 +25,14 @@ export default function (ngApp, events) { $scope.searching = false; $scope.searchTerm = ''; - var page = 0; - var previousClickTime = 0; - var previousClickImage = 0; - var dataLoaded = false; - var callback = false; + let page = 0; + let previousClickTime = 0; + let previousClickImage = 0; + let dataLoaded = false; + let callback = false; - var preSearchImages = []; - var preSearchHasMore = false; + let preSearchImages = []; + let preSearchHasMore = false; /** * Used by dropzone to get the endpoint to upload to. @@ -62,7 +64,7 @@ export default function (ngApp, events) { $scope.$apply(() => { $scope.images.unshift(data); }); - events.emit('success', 'Image uploaded'); + events.emit('success', trans('components.image_upload_success')); }; /** @@ -79,9 +81,9 @@ export default function (ngApp, events) { * @param image */ $scope.imageSelect = function (image) { - var dblClickTime = 300; - var currentTime = Date.now(); - var timeDiff = currentTime - previousClickTime; + let dblClickTime = 300; + let currentTime = Date.now(); + let timeDiff = currentTime - previousClickTime; if (timeDiff < dblClickTime && image.id === previousClickImage) { // If double click @@ -137,22 +139,21 @@ export default function (ngApp, events) { $('#image-manager').find('.overlay').fadeOut(240); }; - var baseUrl = window.baseUrl('/images/' + $scope.imageType + '/all/'); + let baseUrl = window.baseUrl('/images/' + $scope.imageType + '/all/'); /** * Fetch the list image data from the server. */ function fetchData() { - var url = baseUrl + page + '?'; - var components = {}; + let url = baseUrl + page + '?'; + let components = {}; if ($scope.uploadedTo) components['page_id'] = $scope.uploadedTo; if ($scope.searching) components['term'] = $scope.searchTerm; - var urlQueryString = Object.keys(components).map((key) => { + url += Object.keys(components).map((key) => { return key + '=' + encodeURIComponent(components[key]); }).join('&'); - url += urlQueryString; $http.get(url).then((response) => { $scope.images = $scope.images.concat(response.data.images); @@ -205,13 +206,13 @@ export default function (ngApp, events) { */ $scope.saveImageDetails = function (event) { event.preventDefault(); - var url = window.baseUrl('/images/update/' + $scope.selectedImage.id); + let url = window.baseUrl('/images/update/' + $scope.selectedImage.id); $http.put(url, this.selectedImage).then(response => { - events.emit('success', 'Image details updated'); + events.emit('success', trans('components.image_update_success')); }, (response) => { if (response.status === 422) { - var errors = response.data; - var message = ''; + let errors = response.data; + let message = ''; Object.keys(errors).forEach((key) => { message += errors[key].join('\n'); }); @@ -230,13 +231,13 @@ export default function (ngApp, events) { */ $scope.deleteImage = function (event) { event.preventDefault(); - var force = $scope.dependantPages !== false; - var url = window.baseUrl('/images/' + $scope.selectedImage.id); + let force = $scope.dependantPages !== false; + let url = window.baseUrl('/images/' + $scope.selectedImage.id); if (force) url += '?force=true'; $http.delete(url).then((response) => { $scope.images.splice($scope.images.indexOf($scope.selectedImage), 1); $scope.selectedImage = false; - events.emit('success', 'Image successfully deleted'); + events.emit('success', trans('components.image_delete_success')); }, (response) => { // Pages failure if (response.status === 400) { @@ -266,11 +267,11 @@ export default function (ngApp, events) { $scope.searchBook = function (e) { e.preventDefault(); - var term = $scope.searchTerm; + let term = $scope.searchTerm; if (term.length == 0) return; $scope.searching = true; $scope.searchResults = ''; - var searchUrl = window.baseUrl('/search/book/' + $attrs.bookId); + let searchUrl = window.baseUrl('/search/book/' + $attrs.bookId); searchUrl += '?term=' + encodeURIComponent(term); $http.get(searchUrl).then((response) => { $scope.searchResults = $sce.trustAsHtml(response.data); @@ -294,27 +295,27 @@ export default function (ngApp, events) { ngApp.controller('PageEditController', ['$scope', '$http', '$attrs', '$interval', '$timeout', '$sce', function ($scope, $http, $attrs, $interval, $timeout, $sce) { - $scope.editorOptions = require('./pages/page-form'); + $scope.editorOptions = editorOptions(); $scope.editContent = ''; $scope.draftText = ''; - var pageId = Number($attrs.pageId); - var isEdit = pageId !== 0; - var autosaveFrequency = 30; // AutoSave interval in seconds. - var isMarkdown = $attrs.editorType === 'markdown'; + let pageId = Number($attrs.pageId); + let isEdit = pageId !== 0; + let autosaveFrequency = 30; // AutoSave interval in seconds. + let isMarkdown = $attrs.editorType === 'markdown'; $scope.draftsEnabled = $attrs.draftsEnabled === 'true'; $scope.isUpdateDraft = Number($attrs.pageUpdateDraft) === 1; $scope.isNewPageDraft = Number($attrs.pageNewDraft) === 1; // Set initial header draft text if ($scope.isUpdateDraft || $scope.isNewPageDraft) { - $scope.draftText = 'Editing Draft' + $scope.draftText = trans('entities.pages_editing_draft'); } else { - $scope.draftText = 'Editing Page' + $scope.draftText = trans('entities.pages_editing_page'); } - var autoSave = false; + let autoSave = false; - var currentContent = { + let currentContent = { title: false, html: false }; @@ -351,8 +352,8 @@ export default function (ngApp, events) { autoSave = $interval(() => { // Return if manually saved recently to prevent bombarding the server if (Date.now() - lastSave < (1000*autosaveFrequency)/2) return; - var newTitle = $('#name').val(); - var newHtml = $scope.editContent; + let newTitle = $('#name').val(); + let newHtml = $scope.editContent; if (newTitle !== currentContent.title || newHtml !== currentContent.html) { currentContent.html = newHtml; @@ -369,7 +370,7 @@ export default function (ngApp, events) { */ function saveDraft() { if (!$scope.draftsEnabled) return; - var data = { + let data = { name: $('#name').val(), html: isMarkdown ? $sce.getTrustedHtml($scope.displayContent) : $scope.editContent }; @@ -379,14 +380,14 @@ export default function (ngApp, events) { let url = window.baseUrl('/ajax/page/' + pageId + '/save-draft'); $http.put(url, data).then(responseData => { draftErroring = false; - var updateTime = moment.utc(moment.unix(responseData.data.timestamp)).toDate(); + let updateTime = moment.utc(moment.unix(responseData.data.timestamp)).toDate(); $scope.draftText = responseData.data.message + moment(updateTime).format('HH:mm'); if (!$scope.isNewPageDraft) $scope.isUpdateDraft = true; showDraftSaveNotification(); lastSave = Date.now(); }, errorRes => { if (draftErroring) return; - events.emit('error', 'Failed to save draft. Ensure you have internet connection before saving this page.') + events.emit('error', trans('errors.page_draft_autosave_fail')); draftErroring = true; }); } @@ -419,7 +420,7 @@ export default function (ngApp, events) { let url = window.baseUrl('/ajax/page/' + pageId); $http.get(url).then((responseData) => { if (autoSave) $interval.cancel(autoSave); - $scope.draftText = 'Editing Page'; + $scope.draftText = trans('entities.pages_editing_page'); $scope.isUpdateDraft = false; $scope.$broadcast('html-update', responseData.data.html); $scope.$broadcast('markdown-update', responseData.data.markdown || responseData.data.html); @@ -427,7 +428,7 @@ export default function (ngApp, events) { $timeout(() => { startAutoSave(); }, 1000); - events.emit('success', 'Draft discarded, The editor has been updated with the current page content'); + events.emit('success', trans('entities.pages_draft_discarded')); }); }; @@ -505,20 +506,6 @@ export default function (ngApp, events) { } }; - /** - * Save the tags to the current page. - */ - $scope.saveTags = function() { - setTagOrder(); - let postData = {tags: $scope.tags}; - let url = window.baseUrl('/ajax/tags/update/page/' + pageId); - $http.post(url, postData).then((responseData) => { - $scope.tags = responseData.data.tags; - addEmptyTag(); - events.emit('success', responseData.data.message); - }) - }; - /** * Remove a tag from the current list. * @param tag @@ -588,7 +575,7 @@ export default function (ngApp, events) { * Get files for the current page from the server. */ function getFiles() { - let url = window.baseUrl(`/attachments/get/page/${pageId}`) + let url = window.baseUrl(`/attachments/get/page/${pageId}`); $http.get(url).then(resp => { $scope.files = resp.data; currentOrder = resp.data.map(file => {return file.id}).join(':'); @@ -606,7 +593,7 @@ export default function (ngApp, events) { $scope.$apply(() => { $scope.files.push(data); }); - events.emit('success', 'File uploaded'); + events.emit('success', trans('entities.attachments_file_uploaded')); }; /** @@ -624,7 +611,7 @@ export default function (ngApp, events) { data.link = ''; } }); - events.emit('success', 'File updated'); + events.emit('success', trans('entities.attachments_file_updated')); }; /** @@ -650,7 +637,7 @@ export default function (ngApp, events) { file.uploaded_to = pageId; $http.post(window.baseUrl('/attachments/link'), file).then(resp => { $scope.files.push(resp.data); - events.emit('success', 'Link attached'); + events.emit('success', trans('entities.attachments_link_attached')); $scope.file = getCleanFile(); }, checkError('link')); }; @@ -684,7 +671,7 @@ export default function (ngApp, events) { $scope.editFile.link = ''; } $scope.editFile = false; - events.emit('success', 'Attachment details updated'); + events.emit('success', trans('entities.attachments_updated_success')); }, checkError('edit')); }; diff --git a/resources/assets/js/directives.js b/resources/assets/js/directives.js index 44d1a14e1..ef8bcd85c 100644 --- a/resources/assets/js/directives.js +++ b/resources/assets/js/directives.js @@ -1,38 +1,8 @@ "use strict"; -const DropZone = require('dropzone'); -const markdown = require('marked'); +import DropZone from "dropzone"; +import markdown from "marked"; -module.exports = function (ngApp, events) { - - /** - * Toggle Switches - * Has basic on/off functionality. - * Use string values of 'true' & 'false' to dictate the current state. - */ - ngApp.directive('toggleSwitch', function () { - return { - restrict: 'A', - template: ` -
- -
-
- `, - scope: true, - link: function (scope, element, attrs) { - scope.name = attrs.name; - scope.value = attrs.value; - scope.isActive = scope.value == true && scope.value != 'false'; - scope.value = (scope.value == true && scope.value != 'false') ? 'true' : 'false'; - - scope.switch = function () { - scope.isActive = !scope.isActive; - scope.value = scope.isActive ? 'true' : 'false'; - } - - } - }; - }); +export default function (ngApp, events) { /** * Common tab controls using simple jQuery functions. @@ -65,7 +35,7 @@ module.exports = function (ngApp, events) { }); /** - * Sub form component to allow inner-form sections to act like thier own forms. + * Sub form component to allow inner-form sections to act like their own forms. */ ngApp.directive('subForm', function() { return { @@ -80,96 +50,13 @@ module.exports = function (ngApp, events) { element.find('button[type="submit"]').click(submitEvent); function submitEvent(e) { - e.preventDefault() + e.preventDefault(); if (attrs.subForm) scope.$eval(attrs.subForm); } } }; }); - - /** - * Image Picker - * Is a simple front-end interface that connects to an ImageManager if present. - */ - ngApp.directive('imagePicker', ['$http', 'imageManagerService', function ($http, imageManagerService) { - return { - restrict: 'E', - template: ` -
-
- Image Preview - Image Preview -
- -
- - - | - - - -
- `, - scope: { - name: '@', - resizeHeight: '@', - resizeWidth: '@', - resizeCrop: '@', - showRemove: '=', - currentImage: '@', - currentId: '@', - defaultImage: '@', - imageClass: '@' - }, - link: function (scope, element, attrs) { - let usingIds = typeof scope.currentId !== 'undefined' || scope.currentId === 'false'; - scope.image = scope.currentImage; - scope.value = scope.currentImage || ''; - if (usingIds) scope.value = scope.currentId; - - function setImage(imageModel, imageUrl) { - scope.image = imageUrl; - scope.value = usingIds ? imageModel.id : imageUrl; - } - - scope.reset = function () { - setImage({id: 0}, scope.defaultImage); - }; - - scope.remove = function () { - scope.image = 'none'; - scope.value = 'none'; - }; - - scope.showImageManager = function () { - imageManagerService.show((image) => { - scope.updateImageFromModel(image); - }); - }; - - scope.updateImageFromModel = function (model) { - let isResized = scope.resizeWidth && scope.resizeHeight; - - if (!isResized) { - scope.$apply(() => { - setImage(model, model.url); - }); - return; - } - - let cropped = scope.resizeCrop ? 'true' : 'false'; - let requestString = '/images/thumb/' + model.id + '/' + scope.resizeWidth + '/' + scope.resizeHeight + '/' + cropped; - requestString = window.baseUrl(requestString); - $http.get(requestString).then((response) => { - setImage(model, response.data.url); - }); - }; - - } - }; - }]); - /** * DropZone * Used for uploading images @@ -179,25 +66,26 @@ module.exports = function (ngApp, events) { restrict: 'E', template: `
-
Drop files or click here to upload
+
{{message}}
`, scope: { uploadUrl: '@', eventSuccess: '=', eventError: '=', - uploadedTo: '@' + uploadedTo: '@', }, link: function (scope, element, attrs) { + scope.message = attrs.message; if (attrs.placeholder) element[0].querySelector('.dz-message').textContent = attrs.placeholder; - var dropZone = new DropZone(element[0].querySelector('.dropzone-container'), { + let dropZone = new DropZone(element[0].querySelector('.dropzone-container'), { url: scope.uploadUrl, init: function () { - var dz = this; + let dz = this; dz.on('sending', function (file, xhr, data) { - var token = window.document.querySelector('meta[name=token]').getAttribute('content'); + let token = window.document.querySelector('meta[name=token]').getAttribute('content'); data.append('_token', token); - var uploadedTo = typeof scope.uploadedTo === 'undefined' ? 0 : scope.uploadedTo; + let uploadedTo = typeof scope.uploadedTo === 'undefined' ? 0 : scope.uploadedTo; data.append('uploaded_to', uploadedTo); }); if (typeof scope.eventSuccess !== 'undefined') dz.on('success', scope.eventSuccess); @@ -214,7 +102,7 @@ module.exports = function (ngApp, events) { $(file.previewElement).find('[data-dz-errormessage]').text(message); } - if (xhr.status === 413) setMessage('The server does not allow uploads of this size. Please try a smaller file.'); + if (xhr.status === 413) setMessage(trans('errors.server_upload_limit')); if (errorMessage.file) setMessage(errorMessage.file[0]); }); @@ -273,7 +161,7 @@ module.exports = function (ngApp, events) { function tinyMceSetup(editor) { editor.on('ExecCommand change NodeChange ObjectResized', (e) => { - var content = editor.getContent(); + let content = editor.getContent(); $timeout(() => { scope.mceModel = content; }); @@ -301,9 +189,9 @@ module.exports = function (ngApp, events) { // Custom tinyMCE plugins tinymce.PluginManager.add('customhr', function (editor) { editor.addCommand('InsertHorizontalRule', function () { - var hrElem = document.createElement('hr'); - var cNode = editor.selection.getNode(); - var parentNode = cNode.parentNode; + let hrElem = document.createElement('hr'); + let cNode = editor.selection.getNode(); + let parentNode = cNode.parentNode; parentNode.insertBefore(hrElem, cNode); }); @@ -373,15 +261,21 @@ module.exports = function (ngApp, events) { link: function (scope, element, attrs) { // Elements - const input = element.find('[markdown-input] textarea').first(); - const display = element.find('.markdown-display').first(); - const insertImage = element.find('button[data-action="insertImage"]'); - const insertEntityLink = element.find('button[data-action="insertEntityLink"]') + const $input = element.find('[markdown-input] textarea').first(); + const $display = element.find('.markdown-display').first(); + const $insertImage = element.find('button[data-action="insertImage"]'); + const $insertEntityLink = element.find('button[data-action="insertEntityLink"]'); + + // Prevent markdown display link click redirect + $display.on('click', 'a', function(event) { + event.preventDefault(); + window.open(this.getAttribute('href')); + }); let currentCaretPos = 0; - input.blur(event => { - currentCaretPos = input[0].selectionStart; + $input.blur(event => { + currentCaretPos = $input[0].selectionStart; }); // Scroll sync @@ -391,10 +285,10 @@ module.exports = function (ngApp, events) { displayHeight; function setScrollHeights() { - inputScrollHeight = input[0].scrollHeight; - inputHeight = input.height(); - displayScrollHeight = display[0].scrollHeight; - displayHeight = display.height(); + inputScrollHeight = $input[0].scrollHeight; + inputHeight = $input.height(); + displayScrollHeight = $display[0].scrollHeight; + displayHeight = $display.height(); } setTimeout(() => { @@ -403,29 +297,29 @@ module.exports = function (ngApp, events) { window.addEventListener('resize', setScrollHeights); let scrollDebounceTime = 800; let lastScroll = 0; - input.on('scroll', event => { + $input.on('scroll', event => { let now = Date.now(); if (now - lastScroll > scrollDebounceTime) { setScrollHeights() } - let scrollPercent = (input.scrollTop() / (inputScrollHeight - inputHeight)); + let scrollPercent = ($input.scrollTop() / (inputScrollHeight - inputHeight)); let displayScrollY = (displayScrollHeight - displayHeight) * scrollPercent; - display.scrollTop(displayScrollY); + $display.scrollTop(displayScrollY); lastScroll = now; }); // Editor key-presses - input.keydown(event => { + $input.keydown(event => { // Insert image shortcut if (event.which === 73 && event.ctrlKey && event.shiftKey) { event.preventDefault(); - let caretPos = input[0].selectionStart; - let currentContent = input.val(); + let caretPos = $input[0].selectionStart; + let currentContent = $input.val(); const mdImageText = "![](http://)"; - input.val(currentContent.substring(0, caretPos) + mdImageText + currentContent.substring(caretPos)); - input.focus(); - input[0].selectionStart = caretPos + ("![](".length); - input[0].selectionEnd = caretPos + ('![](http://'.length); + $input.val(currentContent.substring(0, caretPos) + mdImageText + currentContent.substring(caretPos)); + $input.focus(); + $input[0].selectionStart = caretPos + ("![](".length); + $input[0].selectionEnd = caretPos + ('![](http://'.length); return; } @@ -440,48 +334,48 @@ module.exports = function (ngApp, events) { }); // Insert image from image manager - insertImage.click(event => { + $insertImage.click(event => { window.ImageManager.showExternal(image => { let caretPos = currentCaretPos; - let currentContent = input.val(); + let currentContent = $input.val(); let mdImageText = "![" + image.name + "](" + image.thumbs.display + ")"; - input.val(currentContent.substring(0, caretPos) + mdImageText + currentContent.substring(caretPos)); - input.change(); + $input.val(currentContent.substring(0, caretPos) + mdImageText + currentContent.substring(caretPos)); + $input.change(); }); }); function showLinkSelector() { window.showEntityLinkSelector((entity) => { let selectionStart = currentCaretPos; - let selectionEnd = input[0].selectionEnd; + let selectionEnd = $input[0].selectionEnd; let textSelected = (selectionEnd !== selectionStart); - let currentContent = input.val(); + let currentContent = $input.val(); if (textSelected) { let selectedText = currentContent.substring(selectionStart, selectionEnd); let linkText = `[${selectedText}](${entity.link})`; - input.val(currentContent.substring(0, selectionStart) + linkText + currentContent.substring(selectionEnd)); + $input.val(currentContent.substring(0, selectionStart) + linkText + currentContent.substring(selectionEnd)); } else { let linkText = ` [${entity.name}](${entity.link}) `; - input.val(currentContent.substring(0, selectionStart) + linkText + currentContent.substring(selectionStart)) + $input.val(currentContent.substring(0, selectionStart) + linkText + currentContent.substring(selectionStart)) } - input.change(); + $input.change(); }); } - insertEntityLink.click(showLinkSelector); + $insertEntityLink.click(showLinkSelector); // Upload and insert image on paste function editorPaste(e) { e = e.originalEvent; if (!e.clipboardData) return - var items = e.clipboardData.items; + let items = e.clipboardData.items; if (!items) return; - for (var i = 0; i < items.length; i++) { + for (let i = 0; i < items.length; i++) { uploadImage(items[i].getAsFile()); } } - input.on('paste', editorPaste); + $input.on('paste', editorPaste); // Handle image drop, Uploads images to BookStack. function handleImageDrop(event) { @@ -493,17 +387,17 @@ module.exports = function (ngApp, events) { } } - input.on('drop', handleImageDrop); + $input.on('drop', handleImageDrop); // Handle image upload and add image into markdown content function uploadImage(file) { if (file.type.indexOf('image') !== 0) return; - var formData = new FormData(); - var ext = 'png'; - var xhr = new XMLHttpRequest(); + let formData = new FormData(); + let ext = 'png'; + let xhr = new XMLHttpRequest(); if (file.name) { - var fileNameMatches = file.name.match(/\.(.+)$/); + let fileNameMatches = file.name.match(/\.(.+)$/); if (fileNameMatches) { ext = fileNameMatches[1]; } @@ -511,17 +405,17 @@ module.exports = function (ngApp, events) { // Insert image into markdown let id = "image-" + Math.random().toString(16).slice(2); - let selectStart = input[0].selectionStart; - let selectEnd = input[0].selectionEnd; - let content = input[0].value; + let selectStart = $input[0].selectionStart; + let selectEnd = $input[0].selectionEnd; + let content = $input[0].value; let selectText = content.substring(selectStart, selectEnd); let placeholderImage = window.baseUrl(`/loading.gif#upload${id}`); let innerContent = ((selectEnd > selectStart) ? `![${selectText}]` : '![]') + `(${placeholderImage})`; - input[0].value = content.substring(0, selectStart) + innerContent + content.substring(selectEnd); + $input[0].value = content.substring(0, selectStart) + innerContent + content.substring(selectEnd); - input.focus(); - input[0].selectionStart = selectStart; - input[0].selectionEnd = selectStart; + $input.focus(); + $input[0].selectionStart = selectStart; + $input[0].selectionEnd = selectStart; let remoteFilename = "image-" + Date.now() + "." + ext; formData.append('file', file, remoteFilename); @@ -529,20 +423,20 @@ module.exports = function (ngApp, events) { xhr.open('POST', window.baseUrl('/images/gallery/upload')); xhr.onload = function () { - let selectStart = input[0].selectionStart; + let selectStart = $input[0].selectionStart; if (xhr.status === 200 || xhr.status === 201) { - var result = JSON.parse(xhr.responseText); - input[0].value = input[0].value.replace(placeholderImage, result.thumbs.display); - input.change(); + let result = JSON.parse(xhr.responseText); + $input[0].value = $input[0].value.replace(placeholderImage, result.thumbs.display); + $input.change(); } else { - console.log('An error occurred uploading the image'); + console.log(trans('errors.image_upload_error')); console.log(xhr.responseText); - input[0].value = input[0].value.replace(innerContent, ''); - input.change(); + $input[0].value = $input[0].value.replace(innerContent, ''); + $input.change(); } - input.focus(); - input[0].selectionStart = selectStart; - input[0].selectionEnd = selectStart; + $input.focus(); + $input[0].selectionStart = selectStart; + $input[0].selectionEnd = selectStart; }; xhr.send(formData); } @@ -680,8 +574,7 @@ module.exports = function (ngApp, events) { } // Enter or tab key else if ((event.keyCode === 13 || event.keyCode === 9) && !event.shiftKey) { - let text = suggestionElems[active].textContent; - currentInput[0].value = text; + currentInput[0].value = suggestionElems[active].textContent; currentInput.focus(); $suggestionBox.hide(); isShowing = false; @@ -732,14 +625,13 @@ module.exports = function (ngApp, events) { // Build suggestions $suggestionBox[0].innerHTML = ''; for (let i = 0; i < suggestions.length; i++) { - var suggestion = document.createElement('li'); + let suggestion = document.createElement('li'); suggestion.textContent = suggestions[i]; suggestion.onclick = suggestionClick; if (i === 0) { - suggestion.className = 'active' + suggestion.className = 'active'; active = 0; } - ; $suggestionBox[0].appendChild(suggestion); } @@ -748,12 +640,11 @@ module.exports = function (ngApp, events) { // Suggestion click event function suggestionClick(event) { - let text = this.textContent; - currentInput[0].value = text; + currentInput[0].value = this.textContent; currentInput.focus(); $suggestionBox.hide(); isShowing = false; - }; + } // Get suggestions & cache function getSuggestions(input, url) { @@ -779,7 +670,7 @@ module.exports = function (ngApp, events) { ngApp.directive('entityLinkSelector', [function($http) { return { - restict: 'A', + restrict: 'A', link: function(scope, element, attrs) { const selectButton = element.find('.entity-link-selector-confirm'); @@ -843,7 +734,7 @@ module.exports = function (ngApp, events) { const input = element.find('[entity-selector-input]').first(); // Detect double click events - var lastClick = 0; + let lastClick = 0; function isDoubleClick() { let now = Date.now(); let answer = now - lastClick < 300; diff --git a/resources/assets/js/global.js b/resources/assets/js/global.js index 9aa5dff52..94462ed64 100644 --- a/resources/assets/js/global.js +++ b/resources/assets/js/global.js @@ -1,11 +1,11 @@ "use strict"; // AngularJS - Create application and load components -var angular = require('angular'); -var ngResource = require('angular-resource'); -var ngAnimate = require('angular-animate'); -var ngSanitize = require('angular-sanitize'); -require('angular-ui-sortable'); +import angular from "angular"; +import "angular-resource"; +import "angular-animate"; +import "angular-sanitize"; +import "angular-ui-sortable"; // Url retrieval function window.baseUrl = function(path) { @@ -15,7 +15,13 @@ window.baseUrl = function(path) { return basePath + '/' + path; }; -var ngApp = angular.module('bookStack', ['ngResource', 'ngAnimate', 'ngSanitize', 'ui.sortable']); +let ngApp = angular.module('bookStack', ['ngResource', 'ngAnimate', 'ngSanitize', 'ui.sortable']); + +// Translation setup +// Creates a global function with name 'trans' to be used in the same way as Laravel's translation system +import Translations from "./translations" +let translator = new Translations(window.translations); +window.trans = translator.get.bind(translator); // Global Event System class EventManager { @@ -25,9 +31,9 @@ class EventManager { emit(eventName, eventData) { if (typeof this.listeners[eventName] === 'undefined') return this; - var eventsToStart = this.listeners[eventName]; + let eventsToStart = this.listeners[eventName]; for (let i = 0; i < eventsToStart.length; i++) { - var event = eventsToStart[i]; + let event = eventsToStart[i]; event(eventData); } return this; @@ -70,93 +76,83 @@ jQuery.expr[":"].contains = $.expr.createPseudo(function (arg) { }); // Global jQuery Elements -$(function () { - - var notifications = $('.notification'); - var successNotification = notifications.filter('.pos'); - var errorNotification = notifications.filter('.neg'); - var warningNotification = notifications.filter('.warning'); - // Notification Events - window.Events.listen('success', function (text) { - successNotification.hide(); - successNotification.find('span').text(text); - setTimeout(() => { - successNotification.show(); - }, 1); - }); - window.Events.listen('warning', function (text) { - warningNotification.find('span').text(text); - warningNotification.show(); - }); - window.Events.listen('error', function (text) { - errorNotification.find('span').text(text); - errorNotification.show(); - }); - - // Notification hiding - notifications.click(function () { - $(this).fadeOut(100); - }); - - // Chapter page list toggles - $('.chapter-toggle').click(function (e) { - e.preventDefault(); - $(this).toggleClass('open'); - $(this).closest('.chapter').find('.inset-list').slideToggle(180); - }); - - // Back to top button - $('#back-to-top').click(function() { - $('#header').smoothScrollTo(); - }); - var scrollTopShowing = false; - var scrollTop = document.getElementById('back-to-top'); - var scrollTopBreakpoint = 1200; - window.addEventListener('scroll', function() { - let scrollTopPos = document.documentElement.scrollTop || document.body.scrollTop || 0; - if (!scrollTopShowing && scrollTopPos > scrollTopBreakpoint) { - scrollTop.style.display = 'block'; - scrollTopShowing = true; - setTimeout(() => { - scrollTop.style.opacity = 0.4; - }, 1); - } else if (scrollTopShowing && scrollTopPos < scrollTopBreakpoint) { - scrollTop.style.opacity = 0; - scrollTopShowing = false; - setTimeout(() => { - scrollTop.style.display = 'none'; - }, 500); - } - }); - - // Common jQuery actions - $('[data-action="expand-entity-list-details"]').click(function() { - $('.entity-list.compact').find('p').not('.empty-text').slideToggle(240); - }); - - // Popup close - $('.popup-close').click(function() { - $(this).closest('.overlay').fadeOut(240); - }); - $('.overlay').click(function(event) { - if (!$(event.target).hasClass('overlay')) return; - $(this).fadeOut(240); - }); - - // Prevent markdown display link click redirect - $('.markdown-display').on('click', 'a', function(event) { - event.preventDefault(); - window.open($(this).attr('href')); - }); - - // Detect IE for css - if(navigator.userAgent.indexOf('MSIE')!==-1 - || navigator.appVersion.indexOf('Trident/') > 0 - || navigator.userAgent.indexOf('Safari') !== -1){ - $('body').addClass('flexbox-support'); - } - +let notifications = $('.notification'); +let successNotification = notifications.filter('.pos'); +let errorNotification = notifications.filter('.neg'); +let warningNotification = notifications.filter('.warning'); +// Notification Events +window.Events.listen('success', function (text) { + successNotification.hide(); + successNotification.find('span').text(text); + setTimeout(() => { + successNotification.show(); + }, 1); +}); +window.Events.listen('warning', function (text) { + warningNotification.find('span').text(text); + warningNotification.show(); +}); +window.Events.listen('error', function (text) { + errorNotification.find('span').text(text); + errorNotification.show(); }); +// Notification hiding +notifications.click(function () { + $(this).fadeOut(100); +}); + +// Chapter page list toggles +$('.chapter-toggle').click(function (e) { + e.preventDefault(); + $(this).toggleClass('open'); + $(this).closest('.chapter').find('.inset-list').slideToggle(180); +}); + +// Back to top button +$('#back-to-top').click(function() { + $('#header').smoothScrollTo(); +}); +let scrollTopShowing = false; +let scrollTop = document.getElementById('back-to-top'); +let scrollTopBreakpoint = 1200; +window.addEventListener('scroll', function() { + let scrollTopPos = document.documentElement.scrollTop || document.body.scrollTop || 0; + if (!scrollTopShowing && scrollTopPos > scrollTopBreakpoint) { + scrollTop.style.display = 'block'; + scrollTopShowing = true; + setTimeout(() => { + scrollTop.style.opacity = 0.4; + }, 1); + } else if (scrollTopShowing && scrollTopPos < scrollTopBreakpoint) { + scrollTop.style.opacity = 0; + scrollTopShowing = false; + setTimeout(() => { + scrollTop.style.display = 'none'; + }, 500); + } +}); + +// Common jQuery actions +$('[data-action="expand-entity-list-details"]').click(function() { + $('.entity-list.compact').find('p').not('.empty-text').slideToggle(240); +}); + +// Popup close +$('.popup-close').click(function() { + $(this).closest('.overlay').fadeOut(240); +}); +$('.overlay').click(function(event) { + if (!$(event.target).hasClass('overlay')) return; + $(this).fadeOut(240); +}); + +// Detect IE for css +if(navigator.userAgent.indexOf('MSIE')!==-1 + || navigator.appVersion.indexOf('Trident/') > 0 + || navigator.userAgent.indexOf('Safari') !== -1){ + $('body').addClass('flexbox-support'); +} + // Page specific items -require('./pages/page-show'); +import "./pages/page-show"; diff --git a/resources/assets/js/pages/page-form.js b/resources/assets/js/pages/page-form.js index 1fb8b915f..e1c0cfe8f 100644 --- a/resources/assets/js/pages/page-form.js +++ b/resources/assets/js/pages/page-form.js @@ -60,108 +60,108 @@ function registerEditorShortcuts(editor) { editor.addShortcut('meta+shift+E', '', ['FormatBlock', false, 'code']); } -var mceOptions = module.exports = { - selector: '#html-editor', - content_css: [ - window.baseUrl('/css/styles.css'), - window.baseUrl('/libs/material-design-iconic-font/css/material-design-iconic-font.min.css') - ], - body_class: 'page-content', - relative_urls: false, - remove_script_host: false, - document_base_url: window.baseUrl('/'), - statusbar: false, - menubar: false, - paste_data_images: false, - extended_valid_elements: 'pre[*]', - automatic_uploads: false, - valid_children: "-div[p|pre|h1|h2|h3|h4|h5|h6|blockquote]", - plugins: "image table textcolor paste link fullscreen imagetools code customhr autosave lists", - imagetools_toolbar: 'imageoptions', - toolbar: "undo redo | styleselect | bold italic underline strikethrough superscript subscript | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table image-insert link hr | removeformat code fullscreen", - content_style: "body {padding-left: 15px !important; padding-right: 15px !important; margin:0!important; margin-left:auto!important;margin-right:auto!important;}", - style_formats: [ - {title: "Header Large", format: "h2"}, - {title: "Header Medium", format: "h3"}, - {title: "Header Small", format: "h4"}, - {title: "Header Tiny", format: "h5"}, - {title: "Paragraph", format: "p", exact: true, classes: ''}, - {title: "Blockquote", format: "blockquote"}, - {title: "Code Block", icon: "code", format: "pre"}, - {title: "Inline Code", icon: "code", inline: "code"}, - {title: "Callouts", items: [ - {title: "Success", block: 'p', exact: true, attributes : {'class' : 'callout success'}}, - {title: "Info", block: 'p', exact: true, attributes : {'class' : 'callout info'}}, - {title: "Warning", block: 'p', exact: true, attributes : {'class' : 'callout warning'}}, - {title: "Danger", block: 'p', exact: true, attributes : {'class' : 'callout danger'}} - ]} - ], - style_formats_merge: false, - formats: { - alignleft: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-left'}, - aligncenter: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-center'}, - alignright: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-right'}, - }, - file_browser_callback: function (field_name, url, type, win) { +export default function() { + let settings = { + selector: '#html-editor', + content_css: [ + window.baseUrl('/css/styles.css'), + window.baseUrl('/libs/material-design-iconic-font/css/material-design-iconic-font.min.css') + ], + body_class: 'page-content', + relative_urls: false, + remove_script_host: false, + document_base_url: window.baseUrl('/'), + statusbar: false, + menubar: false, + paste_data_images: false, + extended_valid_elements: 'pre[*]', + automatic_uploads: false, + valid_children: "-div[p|pre|h1|h2|h3|h4|h5|h6|blockquote]", + plugins: "image table textcolor paste link fullscreen imagetools code customhr autosave lists", + imagetools_toolbar: 'imageoptions', + toolbar: "undo redo | styleselect | bold italic underline strikethrough superscript subscript | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table image-insert link hr | removeformat code fullscreen", + content_style: "body {padding-left: 15px !important; padding-right: 15px !important; margin:0!important; margin-left:auto!important;margin-right:auto!important;}", + style_formats: [ + {title: "Header Large", format: "h2"}, + {title: "Header Medium", format: "h3"}, + {title: "Header Small", format: "h4"}, + {title: "Header Tiny", format: "h5"}, + {title: "Paragraph", format: "p", exact: true, classes: ''}, + {title: "Blockquote", format: "blockquote"}, + {title: "Code Block", icon: "code", format: "pre"}, + {title: "Inline Code", icon: "code", inline: "code"}, + {title: "Callouts", items: [ + {title: "Success", block: 'p', exact: true, attributes : {'class' : 'callout success'}}, + {title: "Info", block: 'p', exact: true, attributes : {'class' : 'callout info'}}, + {title: "Warning", block: 'p', exact: true, attributes : {'class' : 'callout warning'}}, + {title: "Danger", block: 'p', exact: true, attributes : {'class' : 'callout danger'}} + ]} + ], + style_formats_merge: false, + formats: { + alignleft: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-left'}, + aligncenter: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-center'}, + alignright: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-right'}, + }, + file_browser_callback: function (field_name, url, type, win) { - if (type === 'file') { - window.showEntityLinkSelector(function(entity) { - let originalField = win.document.getElementById(field_name); - originalField.value = entity.link; - $(originalField).closest('.mce-form').find('input').eq(2).val(entity.name); - }); - } + if (type === 'file') { + window.showEntityLinkSelector(function(entity) { + let originalField = win.document.getElementById(field_name); + originalField.value = entity.link; + $(originalField).closest('.mce-form').find('input').eq(2).val(entity.name); + }); + } - if (type === 'image') { - // Show image manager - window.ImageManager.showExternal(function (image) { + if (type === 'image') { + // Show image manager + window.ImageManager.showExternal(function (image) { - // Set popover link input to image url then fire change event - // to ensure the new value sticks - win.document.getElementById(field_name).value = image.url; - if ("createEvent" in document) { - let evt = document.createEvent("HTMLEvents"); - evt.initEvent("change", false, true); - win.document.getElementById(field_name).dispatchEvent(evt); - } else { - win.document.getElementById(field_name).fireEvent("onchange"); - } + // Set popover link input to image url then fire change event + // to ensure the new value sticks + win.document.getElementById(field_name).value = image.url; + if ("createEvent" in document) { + let evt = document.createEvent("HTMLEvents"); + evt.initEvent("change", false, true); + win.document.getElementById(field_name).dispatchEvent(evt); + } else { + win.document.getElementById(field_name).fireEvent("onchange"); + } - // Replace the actively selected content with the linked image - let html = ``; - html += `${image.name}`; - html += ''; - win.tinyMCE.activeEditor.execCommand('mceInsertContent', false, html); - }); - } + // Replace the actively selected content with the linked image + let html = ``; + html += `${image.name}`; + html += ''; + win.tinyMCE.activeEditor.execCommand('mceInsertContent', false, html); + }); + } - }, - paste_preprocess: function (plugin, args) { - let content = args.content; - if (content.indexOf('`; - html += `${image.name}`; - html += ''; - editor.execCommand('mceInsertContent', false, html); - }); - } - }); + // Custom Image picker button + editor.addButton('image-insert', { + title: 'My title', + icon: 'image', + tooltip: 'Insert an image', + onclick: function () { + window.ImageManager.showExternal(function (image) { + let html = ``; + html += `${image.name}`; + html += ''; + editor.execCommand('mceInsertContent', false, html); + }); + } + }); - // Paste image-uploads - editor.on('paste', function(event) { - editorPaste(event, editor); - }); - } -}; \ No newline at end of file + // Paste image-uploads + editor.on('paste', function(event) { + editorPaste(event, editor); + }); + } + }; + return settings; +} \ No newline at end of file diff --git a/resources/assets/js/pages/page-show.js b/resources/assets/js/pages/page-show.js index 41b92453f..0cdde790d 100644 --- a/resources/assets/js/pages/page-show.js +++ b/resources/assets/js/pages/page-show.js @@ -1,16 +1,13 @@ "use strict"; // Configure ZeroClipboard -var zeroClipBoard = require('zeroclipboard'); -zeroClipBoard.config({ - swfPath: window.baseUrl('/ZeroClipboard.swf') -}); +import zeroClipBoard from "zeroclipboard"; -window.setupPageShow = module.exports = function (pageId) { +export default window.setupPageShow = function (pageId) { // Set up pointer - var $pointer = $('#pointer').detach(); - var $pointerInner = $pointer.children('div.pointer').first(); - var isSelection = false; + let $pointer = $('#pointer').detach(); + let $pointerInner = $pointer.children('div.pointer').first(); + let isSelection = false; // Select all contents on input click $pointer.on('click', 'input', function (e) { @@ -19,6 +16,9 @@ window.setupPageShow = module.exports = function (pageId) { }); // Set up copy-to-clipboard + zeroClipBoard.config({ + swfPath: window.baseUrl('/ZeroClipboard.swf') + }); new zeroClipBoard($pointer.find('button').first()[0]); // Hide pointer when clicking away @@ -31,11 +31,11 @@ window.setupPageShow = module.exports = function (pageId) { // Show pointer when selecting a single block of tagged content $('.page-content [id^="bkmrk"]').on('mouseup keyup', function (e) { e.stopPropagation(); - var selection = window.getSelection(); + let selection = window.getSelection(); if (selection.toString().length === 0) return; // Show pointer and set link - var $elem = $(this); + let $elem = $(this); let link = window.baseUrl('/link/' + pageId + '#' + $elem.attr('id')); if (link.indexOf('http') !== 0) link = window.location.protocol + "//" + window.location.host + link; $pointer.find('input').val(link); @@ -44,9 +44,9 @@ window.setupPageShow = module.exports = function (pageId) { $pointer.show(); // Set pointer to sit near mouse-up position - var pointerLeftOffset = (e.pageX - $elem.offset().left - ($pointerInner.width() / 2)); + let pointerLeftOffset = (e.pageX - $elem.offset().left - ($pointerInner.width() / 2)); if (pointerLeftOffset < 0) pointerLeftOffset = 0; - var pointerLeftOffsetPercent = (pointerLeftOffset / $elem.width()) * 100; + let pointerLeftOffsetPercent = (pointerLeftOffset / $elem.width()) * 100; $pointerInner.css('left', pointerLeftOffsetPercent + '%'); isSelection = true; @@ -57,7 +57,7 @@ window.setupPageShow = module.exports = function (pageId) { // Go to, and highlight if necessary, the specified text. function goToText(text) { - var idElem = $('.page-content #' + text).first(); + let idElem = $('.page-content #' + text).first(); if (idElem.length !== 0) { idElem.smoothScrollTo(); idElem.css('background-color', 'rgba(244, 249, 54, 0.25)'); @@ -68,19 +68,19 @@ window.setupPageShow = module.exports = function (pageId) { // Check the hash on load if (window.location.hash) { - var text = window.location.hash.replace(/\%20/g, ' ').substr(1); + let text = window.location.hash.replace(/\%20/g, ' ').substr(1); goToText(text); } // Make the book-tree sidebar stick in view on scroll - var $window = $(window); - var $bookTree = $(".book-tree"); - var $bookTreeParent = $bookTree.parent(); + let $window = $(window); + let $bookTree = $(".book-tree"); + let $bookTreeParent = $bookTree.parent(); // Check the page is scrollable and the content is taller than the tree - var pageScrollable = ($(document).height() > $window.height()) && ($bookTree.height() < $('.page-content').height()); + let pageScrollable = ($(document).height() > $window.height()) && ($bookTree.height() < $('.page-content').height()); // Get current tree's width and header height - var headerHeight = $("#header").height() + $(".toolbar").height(); - var isFixed = $window.scrollTop() > headerHeight; + let headerHeight = $("#header").height() + $(".toolbar").height(); + let isFixed = $window.scrollTop() > headerHeight; // Function to fix the tree as a sidebar function stickTree() { $bookTree.width($bookTreeParent.width() + 15); @@ -95,7 +95,7 @@ window.setupPageShow = module.exports = function (pageId) { } // Checks if the tree stickiness state should change function checkTreeStickiness(skipCheck) { - var shouldBeFixed = $window.scrollTop() > headerHeight; + let shouldBeFixed = $window.scrollTop() > headerHeight; if (shouldBeFixed && (!isFixed || skipCheck)) { stickTree(); } else if (!shouldBeFixed && (isFixed || skipCheck)) { diff --git a/resources/assets/js/translations.js b/resources/assets/js/translations.js new file mode 100644 index 000000000..306c696b6 --- /dev/null +++ b/resources/assets/js/translations.js @@ -0,0 +1,47 @@ +/** + * Translation Manager + * Handles the JavaScript side of translating strings + * in a way which fits with Laravel. + */ +class Translator { + + /** + * Create an instance, Passing in the required translations + * @param translations + */ + constructor(translations) { + this.store = translations; + } + + /** + * Get a translation, Same format as laravel's 'trans' helper + * @param key + * @param replacements + * @returns {*} + */ + get(key, replacements) { + let splitKey = key.split('.'); + let value = splitKey.reduce((a, b) => { + return a != undefined ? a[b] : a; + }, this.store); + + if (value === undefined) { + console.log(`Translation with key "${key}" does not exist`); + value = key; + } + + if (replacements === undefined) return value; + + let replaceMatches = value.match(/:([\S]+)/g); + if (replaceMatches === null) return value; + replaceMatches.forEach(match => { + let key = match.substring(1); + if (typeof replacements[key] === 'undefined') return; + value = value.replace(match, replacements[key]); + }); + return value; + } + +} + +export default Translator diff --git a/resources/assets/sass/_components.scss b/resources/assets/sass/_components.scss index 2f9051a52..c8fd8bcfa 100644 --- a/resources/assets/sass/_components.scss +++ b/resources/assets/sass/_components.scss @@ -465,4 +465,8 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group { border-bottom-width: 3px; } } +} + +.image-picker .none { + display: none; } \ No newline at end of file diff --git a/resources/assets/sass/_forms.scss b/resources/assets/sass/_forms.scss index 4e643dcda..62a7b4001 100644 --- a/resources/assets/sass/_forms.scss +++ b/resources/assets/sass/_forms.scss @@ -267,9 +267,4 @@ input.outline { .image-picker img { background-color: #BBB; -} - -div[toggle-switch] { - height: 18px; - width: 150px; } \ No newline at end of file diff --git a/resources/assets/sass/_lists.scss b/resources/assets/sass/_lists.scss index e98e5bfcd..6acc47468 100644 --- a/resources/assets/sass/_lists.scss +++ b/resources/assets/sass/_lists.scss @@ -322,6 +322,9 @@ ul.pagination { font-size: 0.75em; margin-top: $-xs; } + .text-muted p.text-muted { + margin-top: 0; + } .page.draft .text-page { color: $color-page-draft; } diff --git a/resources/assets/sass/_tables.scss b/resources/assets/sass/_tables.scss index 37c61159d..21553b839 100644 --- a/resources/assets/sass/_tables.scss +++ b/resources/assets/sass/_tables.scss @@ -35,6 +35,12 @@ table.table { tr:hover { background-color: #EEE; } + .text-right { + text-align: right; + } + .text-center { + text-align: center; + } } table.no-style { diff --git a/resources/assets/sass/_text.scss b/resources/assets/sass/_text.scss index 9bad2e83d..dd2f32e1c 100644 --- a/resources/assets/sass/_text.scss +++ b/resources/assets/sass/_text.scss @@ -109,6 +109,9 @@ em, i, .italic { small, p.small, span.small, .text-small { font-size: 0.8em; color: lighten($text-dark, 20%); + small, p.small, span.small, .text-small { + font-size: 1em; + } } sup, .superscript { diff --git a/resources/lang/de/settings.php b/resources/lang/de/settings.php index 183480faa..0017acd1d 100644 --- a/resources/lang/de/settings.php +++ b/resources/lang/de/settings.php @@ -16,7 +16,7 @@ return [ 'app_name_desc' => 'Dieser Name wird im Header und E-Mails angezeigt.', 'app_name_header' => 'Anwendungsname im Header anzeigen?', 'app_public_viewing' => 'Öffentliche Ansicht erlauben?', - 'app_secure_images' => 'Erh&oml;hte Sicherheit für Bilduploads aktivieren?', + 'app_secure_images' => 'Erhöhte Sicherheit für Bilduploads aktivieren?', 'app_secure_images_desc' => 'Aus Leistungsgründen sind alle Bilder öffentlich sichtbar. Diese Option fügt zufällige, schwer zu eratene, Zeichenketten vor die Bild-URLs hinzu. Stellen sie sicher, dass Verzeichnindexes deaktiviert sind, um einen einfachen Zugrif zu verhindern.', 'app_editor' => 'Seiteneditor', 'app_editor_desc' => 'Wählen sie den Editor aus, der von allen Benutzern genutzt werden soll, um Seiten zu editieren.', diff --git a/resources/lang/en/auth.php b/resources/lang/en/auth.php index ffdb1cf45..b734828fc 100644 --- a/resources/lang/en/auth.php +++ b/resources/lang/en/auth.php @@ -14,7 +14,49 @@ return [ 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', /** - * Email Confirmation Text + * Login & Register + */ + 'sign_up' => 'Sign up', + 'log_in' => 'Log in', + 'logout' => 'Logout', + + 'name' => 'Name', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'password_confirm' => 'Confirm Password', + 'password_hint' => 'Must be over 5 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', + '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_success' => 'A password reset link has been sent to :email.', + 'reset_password_success' => 'Your password has been successfully reset.', + + 'email_reset_subject' => 'Reset your :appName password', + 'email_reset_text' => 'You are receiving this email because we received a password reset request for your account.', + 'email_reset_not_requested' => 'If you did not request a password reset, no further action is required.', + + + /** + * Email Confirmation */ 'email_confirm_subject' => 'Confirm your email on :appName', 'email_confirm_greeting' => 'Thanks for joining :appName!', @@ -23,4 +65,10 @@ return [ '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', ]; \ No newline at end of file diff --git a/resources/lang/en/common.php b/resources/lang/en/common.php new file mode 100644 index 000000000..31ef42e97 --- /dev/null +++ b/resources/lang/en/common.php @@ -0,0 +1,58 @@ + 'Cancel', + 'confirm' => 'Confirm', + 'back' => 'Back', + 'save' => 'Save', + 'continue' => 'Continue', + 'select' => 'Select', + + /** + * Form Labels + */ + 'name' => 'Name', + 'description' => 'Description', + 'role' => 'Role', + + /** + * Actions + */ + 'actions' => 'Actions', + 'view' => 'View', + 'create' => 'Create', + 'update' => 'Update', + 'edit' => 'Edit', + 'sort' => 'Sort', + 'move' => 'Move', + 'delete' => 'Delete', + 'search' => 'Search', + 'search_clear' => 'Clear Search', + 'reset' => 'Reset', + 'remove' => 'Remove', + + + /** + * 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', + + /** + * Header + */ + 'view_profile' => 'View Profile', + 'edit_profile' => 'Edit Profile', + + /** + * 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', +]; \ No newline at end of file diff --git a/resources/lang/en/components.php b/resources/lang/en/components.php new file mode 100644 index 000000000..b9108702a --- /dev/null +++ b/resources/lang/en/components.php @@ -0,0 +1,24 @@ + '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_confirm' => 'This image is used in the pages below, 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' +]; \ No newline at end of file diff --git a/resources/lang/en/entities.php b/resources/lang/en/entities.php new file mode 100644 index 000000000..033d9614e --- /dev/null +++ b/resources/lang/en/entities.php @@ -0,0 +1,225 @@ + '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_update' => 'Recently Updated', + 'recently_viewed' => 'Recently Viewed', + 'recent_activity' => 'Recent Activity', + 'create_now' => 'Create one now', + 'revisions' => 'Revisions', + 'meta_created' => 'Created :timeLength', + 'meta_created_name' => 'Created :timeLength by :user', + 'meta_updated' => 'Updated :timeLength', + 'meta_updated_name' => 'Updated :timeLength by :user', + 'x_pages' => ':count Pages', + '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', + + /** + * 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_results_page' => 'Page Search Results', + 'search_results_chapter' => 'Chapter Search Results', + 'search_results_book' => 'Book Search Results', + 'search_clear' => 'Clear Search', + 'search_view_pages' => 'View all matches pages', + 'search_view_chapters' => 'View all matches chapters', + 'search_view_books' => 'View all matches books', + 'search_no_pages' => 'No pages matched this search', + 'search_for_term' => 'Search for :term', + 'search_page_for_term' => 'Page search for :term', + 'search_chapter_for_term' => 'Chapter search for :term', + 'search_book_for_term' => 'Books search for :term', + + /** + * Books + */ + 'book' => 'Book', + 'books' => 'Books', + 'books_empty' => 'No books have been created', + 'books_popular' => 'Popular Books', + 'books_recent' => 'Recent Books', + 'books_popular_empty' => 'The most popular 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_or' => 'or', + '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_show_other' => 'Show Other Books', + 'books_sort_save' => 'Save New Order', + + /** + * Chapters + */ + 'chapter' => 'Chapter', + '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', + + /** + * Pages + */ + 'page' => 'Page', + 'pages' => '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_toggle_header' => 'Toggle header', + '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_not_in_chapter' => 'Page is not in a chapter', + 'pages_move' => 'Move Page', + 'pages_move_success' => 'Page moved to ":parentName"', + 'pages_permissions' => 'Page Permissions', + 'pages_permissions_success' => 'Page permissions updated', + '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_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_export' => 'Export', + 'pages_export_html' => 'Contained Web File', + 'pages_export_pdf' => 'PDF File', + 'pages_export_text' => 'Plain Text File', + 'pages_copy_link' => 'Copy Link', + '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 pages 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', + + /** + * Editor sidebar + */ + 'page_tags' => 'Page Tags', + 'tag' => 'Tag', + 'tags' => '', + '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', + 'attachments' => 'Attachments', + 'attachments_explain' => 'Upload some files or attach some link 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', + + /** + * 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', +]; \ No newline at end of file diff --git a/resources/lang/en/errors.php b/resources/lang/en/errors.php index b1a252bf3..c4578a37a 100644 --- a/resources/lang/en/errors.php +++ b/resources/lang/en/errors.php @@ -6,7 +6,65 @@ return [ * Error text strings. */ - // Pages + // Permissions 'permission' => 'You do not have permission to access the requested page.', - 'permissionJson' => 'You do not have permission to perform the requested action.' + '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.', + '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', + 'social_no_action_defined' => 'No action defined', + '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.', + + // 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.', + 'image_upload_error' => 'An error occurred uploading the image', + + // Attachments + 'attachment_page_mismatch' => 'Page mismatch during attachment update', + + // Pages + 'page_draft_autosave_fail' => 'Failed to save draft. Ensure you have internet connection before saving this page', + + // Entities + 'entity_not_found' => 'Entity 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', + + // Error pages + '404_page_not_found' => 'Page Not Found', + 'sorry_page_not_found' => 'Sorry, The page you were looking for could not be found.', + 'return_home' => 'Return to home', + 'error_occurred' => 'An Error Occurred', + 'app_down' => ':appName is down right now', + 'back_soon' => 'It will be back up soon.', ]; \ No newline at end of file diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index 1b0bcad33..e61df19d9 100644 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -10,7 +10,12 @@ return [ 'settings' => 'Settings', 'settings_save' => 'Save Settings', - + 'settings_save_success' => 'Settings saved', + + /** + * App settings + */ + 'app_settings' => 'App Settings', 'app_name' => 'Application name', 'app_name_desc' => 'This name is shown in the header and any emails.', @@ -27,6 +32,10 @@ return [ 'app_primary_color' => 'Application primary color', 'app_primary_color_desc' => 'This should be a hex value.
Leave empty to reset to the default color.', + /** + * Registration settings + */ + 'reg_settings' => 'Registration Settings', 'reg_allow' => 'Allow registration?', 'reg_default_role' => 'Default user role after registration', @@ -36,4 +45,96 @@ return [ 'reg_confirm_restrict_domain_desc' => 'Enter a comma separated list of email domains you would like to restrict registration to. Users will be sent an email to confirm their address before being allowed to interact with the application.
Note that users will be able to change their email addresses after successful registration.', 'reg_confirm_restrict_domain_placeholder' => 'No restriction set', -]; \ No newline at end of file + /** + * Role settings + */ + + 'roles' => 'Roles', + 'role_user_roles' => 'User Roles', + 'role_create' => 'Create New Role', + 'role_create_success' => 'Role successfully created', + 'role_delete' => 'Delete Role', + 'role_delete_confirm' => 'This will delete the role with the name \':roleName\'.', + 'role_delete_users_assigned' => 'This role has :userCount users assigned to it. If you would like to migrate the users from this role select a new role below.', + 'role_delete_no_migration' => "Don't migrate users", + 'role_delete_sure' => 'Are you sure you want to delete this role?', + 'role_delete_success' => 'Role successfully deleted', + 'role_edit' => 'Edit Role', + 'role_details' => 'Role Details', + 'role_name' => 'Role Name', + 'role_desc' => 'Short Description of Role', + 'role_system' => 'System Permissions', + 'role_manage_users' => 'Manage users', + 'role_manage_roles' => 'Manage roles & role permissions', + 'role_manage_entity_permissions' => 'Manage all book, chapter & page permissions', + 'role_manage_own_entity_permissions' => 'Manage permissions on own book, chapter & pages', + 'role_manage_settings' => 'Manage app settings', + 'role_asset' => 'Asset Permissions', + 'role_asset_desc' => 'These permissions control default access to the assets within the system. Permissions on Books, Chapters and Pages will override these permissions.', + 'role_all' => 'All', + 'role_own' => 'Own', + 'role_controlled_by_asset' => 'Controlled by the asset they are uploaded to', + 'role_save' => 'Save Role', + 'role_update_success' => 'Role successfully updated', + 'role_users' => 'Users in this role', + 'role_users_none' => 'No users are currently assigned to this role', + + /** + * Users + */ + + 'users' => 'Users', + 'user_profile' => 'User Profile', + 'users_add_new' => 'Add New User', + 'users_search' => 'Search Users', + 'users_role' => 'User Roles', + 'users_external_auth_id' => 'External Authentication ID', + 'users_password_warning' => 'Only fill the below if you would like to change your password:', + 'users_system_public' => 'This user represents any guest users that visit your instance. It cannot be used to log in but is assigned automatically.', + 'users_delete' => 'Delete User', + 'users_delete_named' => 'Delete ser :userName', + 'users_delete_warning' => 'This will fully delete this user with the name \':userName\' from the system.', + 'users_delete_confirm' => 'Are you sure you want to delete this user?', + 'users_delete_success' => 'Users successfully removed', + 'users_edit' => 'Edit User', + 'users_edit_profile' => 'Edit Profile', + 'users_edit_success' => 'User successfully updated', + 'users_avatar' => 'User Avatar', + 'users_avatar_desc' => 'This image should be approx 256px square.', + 'users_social_accounts' => 'Social Accounts', + 'users_social_accounts_info' => 'Here you can connect your other accounts for quicker and easier login. Disconnecting an account here does not previously authorized access. Revoke access from your profile settings on the connected social account.', + 'users_social_connect' => 'Connect Account', + 'users_social_disconnect' => 'Disconnect Account', + 'users_social_connected' => ':socialAccount account was successfully attached to your profile.', + 'users_social_disconnected' => ':socialAccount account was successfully disconnected from your profile.', +]; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/lang/en/validation.php b/resources/lang/en/validation.php index 20acc9a68..b75af7485 100644 --- a/resources/lang/en/validation.php +++ b/resources/lang/en/validation.php @@ -87,8 +87,8 @@ return [ */ 'custom' => [ - 'attribute-name' => [ - 'rule-name' => 'custom-message', + 'password-confirm' => [ + 'required_with' => 'Password confirmation required', ], ], diff --git a/resources/views/auth/forms/login/ldap.blade.php b/resources/views/auth/forms/login/ldap.blade.php index 5230d43ca..b52b5f13e 100644 --- a/resources/views/auth/forms/login/ldap.blade.php +++ b/resources/views/auth/forms/login/ldap.blade.php @@ -1,19 +1,19 @@
- + @include('form/text', ['name' => 'username', 'tabindex' => 1])
@if(session('request-email', false) === true)
- + @include('form/text', ['name' => 'email', 'tabindex' => 1]) - Please enter an email to use for this account. + {{ trans('auth.ldap_email_hint') }}
@endif
- + @include('form/password', ['name' => 'password', 'tabindex' => 2])
\ No newline at end of file diff --git a/resources/views/auth/forms/login/standard.blade.php b/resources/views/auth/forms/login/standard.blade.php index abefd21a1..4ea1f35ba 100644 --- a/resources/views/auth/forms/login/standard.blade.php +++ b/resources/views/auth/forms/login/standard.blade.php @@ -1,10 +1,10 @@
- + @include('form/text', ['name' => 'email', 'tabindex' => 1])
- + @include('form/password', ['name' => 'password', 'tabindex' => 2]) - Forgot Password? + {{ trans('auth.forgot_password') }}
\ No newline at end of file diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index 4fa97c1d5..295d1a801 100644 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -2,7 +2,7 @@ @section('header-buttons') @if(setting('registration-enabled', false)) - Sign up + {{ trans('auth.sign_up') }} @endif @stop @@ -10,7 +10,7 @@
-

Log In

+

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

{!! csrf_field() !!} @@ -19,20 +19,20 @@ @include('auth/forms/login/' . $authMethod)
- +
- +
@if(count($socialDrivers) > 0)
-

Social Login

+

{{ trans('auth.social_login') }}

@if(isset($socialDrivers['google'])) @endif diff --git a/resources/views/auth/passwords/email.blade.php b/resources/views/auth/passwords/email.blade.php index 115785ab2..07bd2c383 100644 --- a/resources/views/auth/passwords/email.blade.php +++ b/resources/views/auth/passwords/email.blade.php @@ -1,9 +1,9 @@ @extends('public') @section('header-buttons') - Sign in + {{ trans('auth.log_in') }} @if(setting('registration-enabled')) - Sign up + {{ trans('auth.sign_up') }} @endif @stop @@ -12,20 +12,20 @@
-

Reset Password

+

{{ trans('auth.reset_password') }}

-

Enter your email below and you will be sent an email with a password reset link.

+

{{ trans('auth.reset_password_send_instructions') }}

{!! csrf_field() !!}
- + @include('form/text', ['name' => 'email'])
- +
diff --git a/resources/views/auth/passwords/reset.blade.php b/resources/views/auth/passwords/reset.blade.php index 612b50ff8..a463eef45 100644 --- a/resources/views/auth/passwords/reset.blade.php +++ b/resources/views/auth/passwords/reset.blade.php @@ -1,9 +1,9 @@ @extends('public') @section('header-buttons') - Sign in + {{ trans('auth.log_in') }} @if(setting('registration-enabled')) - Sign up + {{ trans('auth.sign_up') }} @endif @stop @@ -14,29 +14,29 @@
-

Reset Password

+

{{ trans('auth.reset_password') }}

{!! csrf_field() !!}
- + @include('form/text', ['name' => 'email'])
- + @include('form/password', ['name' => 'password'])
- + @include('form/password', ['name' => 'password_confirmation'])
- +
diff --git a/resources/views/auth/register-confirm.blade.php b/resources/views/auth/register-confirm.blade.php index 97fd65ab5..364df9266 100644 --- a/resources/views/auth/register-confirm.blade.php +++ b/resources/views/auth/register-confirm.blade.php @@ -2,7 +2,7 @@ @section('header-buttons') @if(!$signedIn) - Sign in + {{ trans('auth.log_in') }} @endif @stop @@ -10,10 +10,9 @@
-

Thanks for registering!

-

Please check your email and click the confirmation button to access {{ setting('app-name', 'BookStack') }}.

+

{{ trans('auth.register_thanks') }}

+

{{ trans('auth.register_confirm', ['appName' => setting('app-name')]) }}

- @stop diff --git a/resources/views/auth/register.blade.php b/resources/views/auth/register.blade.php index 8ae5fcf50..7a119ddba 100644 --- a/resources/views/auth/register.blade.php +++ b/resources/views/auth/register.blade.php @@ -1,42 +1,42 @@ @extends('public') @section('header-buttons') - Sign in + {{ trans('auth.log_in') }} @stop @section('content')
-

Sign Up

+

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

{!! csrf_field() !!}
- + @include('form/text', ['name' => 'name'])
- + @include('form/text', ['name' => 'email'])
- - @include('form/password', ['name' => 'password', 'placeholder' => 'Must be over 5 characters']) + + @include('form/password', ['name' => 'password', 'placeholder' => trans('auth.password_hint')])
- +
@if(count($socialDrivers) > 0)
-

Social Registration

-

Register and sign in using another service.

+

{{ trans('auth.social_registration') }}

+

{{ trans('auth.social_registration_text') }}

@if(isset($socialDrivers['google'])) @endif diff --git a/resources/views/auth/user-unconfirmed.blade.php b/resources/views/auth/user-unconfirmed.blade.php index 08178e891..13567b412 100644 --- a/resources/views/auth/user-unconfirmed.blade.php +++ b/resources/views/auth/user-unconfirmed.blade.php @@ -4,16 +4,16 @@
-

Email Address not confirmed

-

Your email address has not yet been confirmed.
- Please click the link in the email that was sent shortly after you registered.
- If you cannot find the email you can re-send the confirmation email by submitting the form below. +

{{ trans('auth.email_not_confirmed') }}

+

{{ trans('auth.email_not_confirmed_text') }}
+ {{ trans('auth.email_not_confirmed_click_link') }}
+ {{ trans('auth.email_not_confirmed_resend') }}


{!! csrf_field() !!}
- + @if(auth()->check()) @include('form/text', ['name' => 'email', 'model' => auth()->user()]) @else @@ -21,7 +21,7 @@ @endif
- +
diff --git a/resources/views/base.blade.php b/resources/views/base.blade.php index 08acf725d..43f22d89a 100644 --- a/resources/views/base.blade.php +++ b/resources/views/base.blade.php @@ -17,6 +17,7 @@ + @yield('head') @@ -53,32 +54,16 @@
@if(isset($signedIn) && $signedIn) - + @include('partials._header-dropdown', ['currentUser' => $currentUser]) @endif
@@ -93,7 +78,7 @@
- Back to top + {{ trans('common.back_to_top') }}
@yield('bottom') diff --git a/resources/views/books/_breadcrumbs.blade.php b/resources/views/books/_breadcrumbs.blade.php new file mode 100644 index 000000000..e588127ce --- /dev/null +++ b/resources/views/books/_breadcrumbs.blade.php @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/resources/views/books/create.blade.php b/resources/views/books/create.blade.php index 60f4f65bd..2c629e699 100644 --- a/resources/views/books/create.blade.php +++ b/resources/views/books/create.blade.php @@ -3,7 +3,7 @@ @section('content')
-

Create New Book

+

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

@include('books/form')
diff --git a/resources/views/books/delete.blade.php b/resources/views/books/delete.blade.php index 68f755131..0b1e67d4a 100644 --- a/resources/views/books/delete.blade.php +++ b/resources/views/books/delete.blade.php @@ -2,16 +2,26 @@ @section('content') +
+
+
+
+ @include('books._breadcrumbs', ['book' => $book]) +
+
+
+
+
-

Delete Book

-

This will delete the book with the name '{{$book->name}}', All pages and chapters will be removed.

-

Are you sure you want to delete this book?

+

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

+

{{ trans('entities.books_delete_explain', ['bookName' => $book->name]) }}

+

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

{!! csrf_field() !!} - Cancel - + {{ trans('common.cancel') }} +
diff --git a/resources/views/books/edit.blade.php b/resources/views/books/edit.blade.php index e67e6f459..2419b68da 100644 --- a/resources/views/books/edit.blade.php +++ b/resources/views/books/edit.blade.php @@ -2,8 +2,18 @@ @section('content') +
+
+
+
+ @include('books._breadcrumbs', ['book' => $book]) +
+
+
+
+
-

Edit Book

+

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

@include('books/form', ['model' => $book]) diff --git a/resources/views/books/form.blade.php b/resources/views/books/form.blade.php index dc0fd0a3f..514abf42c 100644 --- a/resources/views/books/form.blade.php +++ b/resources/views/books/form.blade.php @@ -1,16 +1,16 @@ {{ csrf_field() }}
- + @include('form/text', ['name' => 'name'])
- + @include('form/textarea', ['name' => 'description'])
- Cancel - + {{ trans('common.cancel') }} +
\ No newline at end of file diff --git a/resources/views/books/index.blade.php b/resources/views/books/index.blade.php index 91906e7b8..c090a127e 100644 --- a/resources/views/books/index.blade.php +++ b/resources/views/books/index.blade.php @@ -9,7 +9,7 @@
@if($currentUser->can('book-create-all')) - Add new book + {{ trans('entities.books_create') }} @endif
@@ -21,7 +21,7 @@
-

Books

+

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

@if(count($books) > 0) @foreach($books as $book) @include('books/list-item', ['book' => $book]) @@ -29,27 +29,27 @@ @endforeach {!! $books->render() !!} @else -

No books have been created.

+

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

@if(userCan('books-create-all')) - Create one now + {{ trans('entities.create_one_now') }} @endif @endif
@if($recents) -
 
-

Recently Viewed

+
 
+

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

@include('partials/entity-list', ['entities' => $recents]) @endif
 
diff --git a/resources/views/books/restrictions.blade.php b/resources/views/books/restrictions.blade.php index 7fdd3abef..f558fdfce 100644 --- a/resources/views/books/restrictions.blade.php +++ b/resources/views/books/restrictions.blade.php @@ -6,9 +6,7 @@
- + @include('books._breadcrumbs', ['book' => $book])
@@ -16,7 +14,7 @@
-

Book Permissions

+

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

@include('form/restriction-form', ['model' => $book])
diff --git a/resources/views/books/show.blade.php b/resources/views/books/show.blade.php index 129851d5e..6a18302bc 100644 --- a/resources/views/books/show.blade.php +++ b/resources/views/books/show.blade.php @@ -5,29 +5,32 @@
-
+
+ @include('books._breadcrumbs', ['book' => $book]) +
+
@if(userCan('page-create', $book)) - New Page + {{ trans('entities.pages_new') }} @endif @if(userCan('chapter-create', $book)) - New Chapter + {{ trans('entities.chapters_new') }} @endif @if(userCan('book-update', $book)) - Edit + {{ trans('common.edit') }} @endif @if(userCan('book-update', $book) || userCan('restrictions-manage', $book) || userCan('book-delete', $book)) @@ -59,23 +62,19 @@
@endforeach @else -

No pages or chapters have been created for this book.

+

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

- Create a new page -   -or-    - Add a chapter + {{ trans('entities.books_empty_create_page') }} +   -{{ trans('entities.books_empty_or') }}-    + {{ trans('entities.books_empty_add_chapter') }}


@endif -

- Created {{$book->created_at->diffForHumans()}} @if($book->createdBy) by {{$book->createdBy->name}} @endif -
- Last Updated {{$book->updated_at->diffForHumans()}} @if($book->updatedBy) by {{$book->updatedBy->name}} @endif -

+ @include('partials.entity-meta', ['entity' => $book])
-

Search Results Clear Search

+

{{ trans('entities.search_results') }} {{ trans('entities.search_clear') }}

@include('partials/loading-icon')
@@ -90,21 +89,21 @@ @if($book->restricted)

@if(userCan('restrictions-manage', $book)) - Book Permissions Active + {{ trans('entities.books_permissions_active') }} @else - Book Permissions Active + {{ trans('entities.books_permissions_active') }} @endif

@endif
-

Recent Activity

+

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

@include('partials/activity-list', ['activity' => Activity::entityActivity($book, 20, 0)])
diff --git a/resources/views/books/sort.blade.php b/resources/views/books/sort.blade.php index 984db0ce6..d96f502f1 100644 --- a/resources/views/books/sort.blade.php +++ b/resources/views/books/sort.blade.php @@ -6,8 +6,18 @@ @section('content') +
+
+
+
+ @include('books._breadcrumbs', ['book' => $book]) +
+
+
+
+
-

Sorting Pages & ChaptersFor {{ $book->name }}

+

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

@@ -17,7 +27,7 @@ @if(count($books) > 1)
-

Show Other Books

+

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

@foreach($books as $otherBook) @if($otherBook->id !== $book->id) @@ -37,8 +47,8 @@
- Cancel - + {{ trans('common.cancel') }} +
diff --git a/resources/views/chapters/_breadcrumbs.blade.php b/resources/views/chapters/_breadcrumbs.blade.php new file mode 100644 index 000000000..9064cc7c3 --- /dev/null +++ b/resources/views/chapters/_breadcrumbs.blade.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/resources/views/chapters/create.blade.php b/resources/views/chapters/create.blade.php index b81cb15d7..afdbfa99d 100644 --- a/resources/views/chapters/create.blade.php +++ b/resources/views/chapters/create.blade.php @@ -3,7 +3,7 @@ @section('content')
-

Create New Chapter

+

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

@include('chapters/form')
diff --git a/resources/views/chapters/delete.blade.php b/resources/views/chapters/delete.blade.php index e9573f228..bacb8dca3 100644 --- a/resources/views/chapters/delete.blade.php +++ b/resources/views/chapters/delete.blade.php @@ -2,17 +2,26 @@ @section('content') +
+
+
+
+ @include('chapters._breadcrumbs', ['chapter' => $chapter]) +
+
+
+
+
-

Delete Chapter

-

This will delete the chapter with the name '{{$chapter->name}}', All pages will be removed - and added directly to the book.

-

Are you sure you want to delete this chapter?

+

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

+

{{ trans('entities.chapters_delete_explain', ['chapterName' => $chapter->name]) }}

+

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

{!! csrf_field() !!} - Cancel - + {{ trans('common.cancel') }} +
diff --git a/resources/views/chapters/edit.blade.php b/resources/views/chapters/edit.blade.php index 0363da96d..272543e67 100644 --- a/resources/views/chapters/edit.blade.php +++ b/resources/views/chapters/edit.blade.php @@ -3,7 +3,7 @@ @section('content')
-

Edit Chapter

+

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

@include('chapters/form', ['model' => $chapter]) diff --git a/resources/views/chapters/form.blade.php b/resources/views/chapters/form.blade.php index 70df4737a..54722a58a 100644 --- a/resources/views/chapters/form.blade.php +++ b/resources/views/chapters/form.blade.php @@ -2,16 +2,16 @@ {!! csrf_field() !!}
- + @include('form/text', ['name' => 'name'])
- + @include('form/textarea', ['name' => 'description'])
- Cancel - + {{ trans('common.cancel') }} +
diff --git a/resources/views/chapters/list-item.blade.php b/resources/views/chapters/list-item.blade.php index f70e59244..8487a63a3 100644 --- a/resources/views/chapters/list-item.blade.php +++ b/resources/views/chapters/list-item.blade.php @@ -17,7 +17,7 @@ @endif @if(!isset($hidePages) && count($chapter->pages) > 0) -

{{ count($chapter->pages) }} Pages

+

{{ trans('entities.x_pages', ['count' => $chapter->pages->count()]) }}

@foreach($chapter->pages as $page)
{{$page->name}}
diff --git a/resources/views/chapters/move.blade.php b/resources/views/chapters/move.blade.php index 37d56d30d..9e6ddb521 100644 --- a/resources/views/chapters/move.blade.php +++ b/resources/views/chapters/move.blade.php @@ -6,27 +6,23 @@
- + @include('chapters._breadcrumbs', ['chapter' => $chapter])
-

Move Chapter {{$chapter->name}}

+

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

{!! csrf_field() !!} - @include('partials/entity-selector', ['name' => 'entity_selection', 'selectorSize' => 'large', 'entityTypes' => 'book']) + @include('components.entity-selector', ['name' => 'entity_selection', 'selectorSize' => 'large', 'entityTypes' => 'book']) - Cancel - + {{ trans('common.cancel') }} +
diff --git a/resources/views/chapters/restrictions.blade.php b/resources/views/chapters/restrictions.blade.php index 771665037..7b908ee15 100644 --- a/resources/views/chapters/restrictions.blade.php +++ b/resources/views/chapters/restrictions.blade.php @@ -6,18 +6,14 @@
- + @include('chapters._breadcrumbs', ['chapter' => $chapter])
-

Chapter Permissions

+

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

@include('form/restriction-form', ['model' => $chapter])
diff --git a/resources/views/chapters/show.blade.php b/resources/views/chapters/show.blade.php index 70b09e9ce..93eee6424 100644 --- a/resources/views/chapters/show.blade.php +++ b/resources/views/chapters/show.blade.php @@ -6,30 +6,28 @@
- + @include('chapters._breadcrumbs', ['chapter' => $chapter])
@if(userCan('page-create', $chapter)) - New Page + {{ trans('entities.pages_new') }} @endif @if(userCan('chapter-update', $chapter)) - Edit + {{ trans('common.edit') }} @endif @if(userCan('chapter-update', $chapter) || userCan('restrictions-manage', $chapter) || userCan('chapter-delete', $chapter)) @@ -57,26 +55,22 @@
@else
-

No pages are currently in this chapter.

+

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

@if(userCan('page-create', $chapter)) - Create a new page + {{ trans('entities.books_empty_create_page') }} @endif @if(userCan('page-create', $chapter) && userCan('book-update', $book)) -   -or-    +   -{{ trans('entities.books_empty_or') }}-    @endif @if(userCan('book-update', $book)) - Sort the current book + {{ trans('entities.books_empty_sort_current_book') }} @endif


@endif -

- Created {{ $chapter->created_at->diffForHumans() }} @if($chapter->createdBy) by {{ $chapter->createdBy->name}} @endif -
- Last Updated {{ $chapter->updated_at->diffForHumans() }} @if($chapter->updatedBy) by {{ $chapter->updatedBy->name}} @endif -

+ @include('partials.entity-meta', ['entity' => $chapter])
@@ -84,19 +78,20 @@
@if($book->restricted) - @if(userCan('restrictions-manage', $book)) - Book Permissions Active - @else - Book Permissions Active - @endif -
+

+ @if(userCan('restrictions-manage', $book)) + {{ trans('entities.books_permissions_active') }} + @else + {{ trans('entities.books_permissions_active') }} + @endif +

@endif @if($chapter->restricted) @if(userCan('restrictions-manage', $chapter)) - Chapter Permissions Active + {{ trans('entities.chapters_permissions_active') }} @else - Chapter Permissions Active + {{ trans('entities.chapters_permissions_active') }} @endif @endif
diff --git a/resources/views/partials/entity-selector-popup.blade.php b/resources/views/components/entity-selector-popup.blade.php similarity index 63% rename from resources/views/partials/entity-selector-popup.blade.php rename to resources/views/components/entity-selector-popup.blade.php index b9166896a..1c4d1fadb 100644 --- a/resources/views/partials/entity-selector-popup.blade.php +++ b/resources/views/components/entity-selector-popup.blade.php @@ -2,12 +2,12 @@
diff --git a/resources/views/partials/entity-selector.blade.php b/resources/views/components/entity-selector.blade.php similarity index 67% rename from resources/views/partials/entity-selector.blade.php rename to resources/views/components/entity-selector.blade.php index 59e174155..8fb2187e6 100644 --- a/resources/views/partials/entity-selector.blade.php +++ b/resources/views/components/entity-selector.blade.php @@ -1,8 +1,8 @@
- -
@include('partials/loading-icon')
+ +
@include('partials.loading-icon')
\ No newline at end of file diff --git a/resources/views/partials/image-manager.blade.php b/resources/views/components/image-manager.blade.php similarity index 70% rename from resources/views/partials/image-manager.blade.php rename to resources/views/components/image-manager.blade.php index 83625ad88..39f3bcd3c 100644 --- a/resources/views/partials/image-manager.blade.php +++ b/resources/views/components/image-manager.blade.php @@ -3,7 +3,7 @@
@@ -51,15 +51,14 @@
- +

- This image is used in the pages below, Click delete again to confirm you want to delete - this image. + {{ trans('components.image_delete_confirm') }}

  • @@ -73,13 +72,13 @@
- +
diff --git a/resources/views/components/image-picker.blade.php b/resources/views/components/image-picker.blade.php new file mode 100644 index 000000000..47fb2b8b7 --- /dev/null +++ b/resources/views/components/image-picker.blade.php @@ -0,0 +1,66 @@ +
+ +
+ {{ trans('components.image_preview') }} +
+ + +
+ + + @if ($showRemove) + | + + @endif + + +
+ + \ No newline at end of file diff --git a/resources/views/components/toggle-switch.blade.php b/resources/views/components/toggle-switch.blade.php new file mode 100644 index 000000000..ad54d5ab1 --- /dev/null +++ b/resources/views/components/toggle-switch.blade.php @@ -0,0 +1,15 @@ +
+ +
+
+ \ No newline at end of file diff --git a/resources/views/errors/404.blade.php b/resources/views/errors/404.blade.php index 19565bccb..c9e600ceb 100644 --- a/resources/views/errors/404.blade.php +++ b/resources/views/errors/404.blade.php @@ -4,9 +4,28 @@
-

{{ $message or 'Page Not Found' }}

-

Sorry, The page you were looking for could not be found.

- Return To Home + + +

{{ $message or trans('errors.404_page_not_found') }}

+

{{ trans('errors.sorry_page_not_found') }}

+

{{ trans('errors.return_home') }}

+ +
+ +
+
+

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

+ @include('partials.entity-list', ['entities' => Views::getPopular(10, 0, [\BookStack\Page::class]), 'style' => 'compact']) +
+
+

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

+ @include('partials.entity-list', ['entities' => Views::getPopular(10, 0, [\BookStack\Book::class]), 'style' => 'compact']) +
+
+

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

+ @include('partials.entity-list', ['entities' => Views::getPopular(10, 0, [\BookStack\Chapter::class]), 'style' => 'compact']) +
+
@stop \ No newline at end of file diff --git a/resources/views/errors/500.blade.php b/resources/views/errors/500.blade.php index 2a58461ba..6dd96cdcc 100644 --- a/resources/views/errors/500.blade.php +++ b/resources/views/errors/500.blade.php @@ -3,7 +3,7 @@ @section('content')
-

An Error Occurred

+

{{ trans('errors.error_occurred') }}

{{ $message }}

diff --git a/resources/views/errors/503.blade.php b/resources/views/errors/503.blade.php index c79d0f68b..1ea39a7b8 100644 --- a/resources/views/errors/503.blade.php +++ b/resources/views/errors/503.blade.php @@ -3,8 +3,8 @@ @section('content')
-

{{ setting('app-name') }} is down right now

-

It will be back up soon.

+

{{ trans('errors.app_down', ['appName' => setting('app-name')]) }}

+

{{ trans('errors.back_soon') }}

@stop \ No newline at end of file diff --git a/resources/views/form/delete-button.blade.php b/resources/views/form/delete-button.blade.php index a5b1f2809..6c53effae 100644 --- a/resources/views/form/delete-button.blade.php +++ b/resources/views/form/delete-button.blade.php @@ -1,5 +1,5 @@
{{ csrf_field() }} - +
\ No newline at end of file diff --git a/resources/views/form/restriction-form.blade.php b/resources/views/form/restriction-form.blade.php index 7472fe65e..7a1605197 100644 --- a/resources/views/form/restriction-form.blade.php +++ b/resources/views/form/restriction-form.blade.php @@ -2,31 +2,31 @@ {!! csrf_field() !!} -

Once enabled, These permissions will take priority over any set role permissions.

+

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

- @include('form/checkbox', ['name' => 'restricted', 'label' => 'Enable custom permissions']) + @include('form/checkbox', ['name' => 'restricted', 'label' => trans('entities.permissions_enable')])
- - + + @foreach($roles as $role) - + @if(!$model->isA('page')) - + @endif - - + + @endforeach
RoleisA('page')) colspan="3" @else colspan="4" @endif>Actions{{ trans('common.role') }}isA('page')) colspan="3" @else colspan="4" @endif>{{ trans('common.actions') }}
{{ $role->display_name }}@include('form/restriction-checkbox', ['name'=>'restrictions', 'label' => 'View', 'action' => 'view'])@include('form/restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.view'), 'action' => 'view'])@include('form/restriction-checkbox', ['name'=>'restrictions', 'label' => 'Create', 'action' => 'create'])@include('form/restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.create'), 'action' => 'create'])@include('form/restriction-checkbox', ['name'=>'restrictions', 'label' => 'Update', 'action' => 'update'])@include('form/restriction-checkbox', ['name'=>'restrictions', 'label' => 'Delete', 'action' => 'delete'])@include('form/restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.update'), 'action' => 'update'])@include('form/restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.delete'), 'action' => 'delete'])
- Cancel - + {{ trans('common.cancel') }} + \ No newline at end of file diff --git a/resources/views/home.blade.php b/resources/views/home.blade.php index 2fb4ac855..0d97a6a4b 100644 --- a/resources/views/home.blade.php +++ b/resources/views/home.blade.php @@ -5,14 +5,9 @@
- @@ -25,44 +20,44 @@
@if(count($draftPages) > 0) -

My Recent Drafts

+

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

@include('partials/entity-list', ['entities' => $draftPages, 'style' => 'compact']) @endif
@if($signedIn) -

My Recently Viewed

+

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

@else -

Recent Books

+

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

@endif @include('partials/entity-list', [ 'entities' => $recents, 'style' => 'compact', - 'emptyText' => $signedIn ? 'You have not viewed any pages' : 'No books have been created' + 'emptyText' => $signedIn ? trans('entities.no_pages_viewed') : trans('entities.books_empty') ])
-

Recently Created Pages

+

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

@include('partials/entity-list', [ 'entities' => $recentlyCreatedPages, 'style' => 'compact', - 'emptyText' => 'No pages have been recently created' + 'emptyText' => trans('entities.no_pages_recently_created') ])
-

Recently Updated Pages

+

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

@include('partials/entity-list', [ 'entities' => $recentlyUpdatedPages, 'style' => 'compact', - 'emptyText' => 'No pages have been recently updated' + 'emptyText' => trans('entites.no_pages_recently_updated') ])
-

Recent Activity

+

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

@include('partials/activity-list', ['activity' => $activity])
diff --git a/resources/views/pages/_breadcrumbs.blade.php b/resources/views/pages/_breadcrumbs.blade.php new file mode 100644 index 000000000..0d2a61ab2 --- /dev/null +++ b/resources/views/pages/_breadcrumbs.blade.php @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/resources/views/pages/delete.blade.php b/resources/views/pages/delete.blade.php index 57cc86054..f94a614fb 100644 --- a/resources/views/pages/delete.blade.php +++ b/resources/views/pages/delete.blade.php @@ -2,15 +2,25 @@ @section('content') +
+
+
+
+ @include('pages._breadcrumbs', ['page' => $page]) +
+
+
+
+
-

Delete {{ $page->draft ? 'Draft' : '' }} Page

-

Are you sure you want to delete this {{ $page->draft ? 'draft' : '' }} page?

+

{{ $page->draft ? trans('entities.pages_delete_draft') : trans('entities.pages_delete') }}

+

{{ $page->draft ? trans('entities.pages_delete_draft_confirm'): trans('entities.pages_delete_confirm') }}

{!! csrf_field() !!} - Cancel - + {{ trans('common.cancel') }} +
diff --git a/resources/views/pages/edit.blade.php b/resources/views/pages/edit.blade.php index e50cc7c5b..e1c0a169d 100644 --- a/resources/views/pages/edit.blade.php +++ b/resources/views/pages/edit.blade.php @@ -20,7 +20,7 @@
- @include('partials/image-manager', ['imageType' => 'gallery', 'uploaded_to' => $page->id]) - @include('partials/entity-selector-popup') + @include('components.image-manager', ['imageType' => 'gallery', 'uploaded_to' => $page->id]) + @include('components.entity-selector-popup') @stop \ No newline at end of file diff --git a/resources/views/pages/export.blade.php b/resources/views/pages/export.blade.php index 96f06290e..19a635563 100644 --- a/resources/views/pages/export.blade.php +++ b/resources/views/pages/export.blade.php @@ -15,15 +15,11 @@
- @include('pages/page-display') + @include('pages.page-display')
-

- Created {{$page->created_at->toDayDateTimeString()}} @if($page->createdBy) by {{$page->createdBy->name}} @endif -
- Last Updated {{$page->updated_at->toDayDateTimeString()}} @if($page->updatedBy) by {{$page->updatedBy->name}} @endif -

+ @include('partials.entity-meta', ['entity' => $page])
diff --git a/resources/views/pages/form-toolbox.blade.php b/resources/views/pages/form-toolbox.blade.php index a6e66a24a..ecf7619b7 100644 --- a/resources/views/pages/form-toolbox.blade.php +++ b/resources/views/pages/form-toolbox.blade.php @@ -3,22 +3,22 @@
- + @if(userCan('attachment-create-all')) - + @endif
-

Page Tags

+

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

-

Add some tags to better categorise your content.
You can assign a value to a tag for more in-depth organisation.

+

{!! nl2br(e(trans('entities.tags_explain'))) !!}

- - + + @@ -28,7 +28,7 @@ @@ -39,17 +39,17 @@ @if(userCan('attachment-create-all'))
-

Attachments

+

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

-

Upload some files or attach some link to display on your page. These are visible in the page sidebar. Changes here are saved instantly.

+

{{ trans('entities.attachments_explain') }} {{ trans('entities.attachments_explain_instant_save') }}

- +
@@ -59,9 +59,9 @@ @@ -71,25 +71,25 @@
- Click delete again to confirm you want to delete this attachment. + {{ trans('entities.attachments_delete_confirm') }}
- Cancel + {{ trans('common.cancel') }}

- No files have been uploaded. + {{ trans('entities.attachments_no_files') }}

- +
-

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.

+

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

- - + +

- - + +

- +
@@ -97,34 +97,34 @@
-
Edit File
+
{{ trans('entities.attachments_edit_file') }}
- - + +

- +
- - + +

- - + +
diff --git a/resources/views/pages/form.blade.php b/resources/views/pages/form.blade.php index c4baf38f7..eb5ebb0bd 100644 --- a/resources/views/pages/form.blade.php +++ b/resources/views/pages/form.blade.php @@ -9,8 +9,8 @@
@@ -34,16 +34,16 @@
- +
@@ -53,7 +53,7 @@ {{--Title input--}}
- @include('form/text', ['name' => 'name', 'placeholder' => 'Page Title']) + @include('form/text', ['name' => 'name', 'placeholder' => trans('entities.pages_title')])
@@ -78,24 +78,24 @@
- Editor + {{ trans('entities.pages_md_editor') }}
- +  |  - +
+ @if($errors->has('markdown')) class="neg" @endif>@if(isset($model) || old('markdown')){{htmlspecialchars( old('markdown') ? old('markdown') : ($model->markdown === '' ? $model->html : $model->markdown))}}@endif
-
Preview
+
{{ trans('entities.pages_md_preview') }}
diff --git a/resources/views/pages/guest-create.blade.php b/resources/views/pages/guest-create.blade.php index 00d9f5560..10e16cb97 100644 --- a/resources/views/pages/guest-create.blade.php +++ b/resources/views/pages/guest-create.blade.php @@ -3,19 +3,19 @@ @section('content')
-

Create Page

+

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

{!! csrf_field() !!}
- + @include('form/text', ['name' => 'name'])
- Cancel - + {{ trans('common.cancel') }} +
diff --git a/resources/views/pages/list-item.blade.php b/resources/views/pages/list-item.blade.php index 7aa5d7933..70b309e7d 100644 --- a/resources/views/pages/list-item.blade.php +++ b/resources/views/pages/list-item.blade.php @@ -12,8 +12,7 @@ @if(isset($style) && $style === 'detailed')
- Created {{$page->created_at->diffForHumans()}} @if($page->createdBy)by {{$page->createdBy->name}}@endif
- Last updated {{ $page->updated_at->diffForHumans() }} @if($page->updatedBy)by {{$page->updatedBy->name}} @endif + @include('partials.entity-meta', ['entity' => $page])
{{ $page->book->getShortName(30) }} @@ -21,7 +20,7 @@ @if($page->chapter) {{ $page->chapter->getShortName(30) }} @else - Page is not in a chapter + {{ trans('entities.pages_not_in_chapter') }} @endif
diff --git a/resources/views/pages/move.blade.php b/resources/views/pages/move.blade.php index d0fae60ca..a9b6d69d7 100644 --- a/resources/views/pages/move.blade.php +++ b/resources/views/pages/move.blade.php @@ -6,34 +6,23 @@
- + @include('pages._breadcrumbs', ['page' => $page])
-

Move Page {{$page->name}}

+

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

{!! csrf_field() !!} - @include('partials/entity-selector', ['name' => 'entity_selection', 'selectorSize' => 'large', 'entityTypes' => 'book,chapter']) + @include('components.entity-selector', ['name' => 'entity_selection', 'selectorSize' => 'large', 'entityTypes' => 'book,chapter']) - Cancel - + {{ trans('common.cancel') }} +
diff --git a/resources/views/pages/pdf.blade.php b/resources/views/pages/pdf.blade.php index 5c9fd5eea..7e43c5e1a 100644 --- a/resources/views/pages/pdf.blade.php +++ b/resources/views/pages/pdf.blade.php @@ -36,6 +36,5 @@ max-width: none; display: none; } - @stop \ No newline at end of file diff --git a/resources/views/pages/restrictions.blade.php b/resources/views/pages/restrictions.blade.php index bd88919df..cfef2ed21 100644 --- a/resources/views/pages/restrictions.blade.php +++ b/resources/views/pages/restrictions.blade.php @@ -6,26 +6,15 @@
- + @include('pages._breadcrumbs', ['page' => $page])
-

Page Permissions

- @include('form/restriction-form', ['model' => $page]) +

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

+ @include('form.restriction-form', ['model' => $page])
@stop diff --git a/resources/views/pages/revision.blade.php b/resources/views/pages/revision.blade.php index bc054ef83..fe0dd9511 100644 --- a/resources/views/pages/revision.blade.php +++ b/resources/views/pages/revision.blade.php @@ -7,14 +7,12 @@
- @include('pages/page-display') + @include('pages.page-display')
- - @include('partials/highlight') - + @include('partials.highlight') @stop diff --git a/resources/views/pages/revisions.blade.php b/resources/views/pages/revisions.blade.php index 720e34fea..3549f5f05 100644 --- a/resources/views/pages/revisions.blade.php +++ b/resources/views/pages/revisions.blade.php @@ -6,37 +6,24 @@
- + @include('pages._breadcrumbs', ['page' => $page])
- -
-

Page Revisions For "{{ $page->name }}"

+

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

@if(count($page->revisions) > 0) - - - - - + + + + + @foreach($page->revisions as $index => $revision) @@ -46,19 +33,19 @@ {{ $revision->createdBy->name }} @endif - + @@ -66,7 +53,7 @@
NameCreated ByRevision DateChangelogActions{{ trans('entities.pages_name') }}{{ trans('entities.pages_revisions_created_by') }}{{ trans('entities.pages_revisions_date') }}{{ trans('entities.pages_revisions_changelog') }}{{ trans('common.actions') }}
@if($revision->createdBy) {{ $revision->createdBy->name }} @else Deleted User @endif @if($revision->createdBy) {{ $revision->createdBy->name }} @else {{ trans('common.deleted_user') }} @endif {{ $revision->created_at->format('jS F, Y H:i:s') }}
({{ $revision->created_at->diffForHumans() }})
{{ $revision->summary }} - Changes + {{ trans('entities.pages_revisions_changes') }}  |  @if ($index === 0) - Current Version + {{ trans('entities.pages_revisions_current') }} @else - Preview + {{ trans('entities.pages_revisions_preview') }}  |  - Restore + {{ trans('entities.pages_revisions_restore') }} @endif
@else -

This page has no revisions.

+

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

@endif
diff --git a/resources/views/pages/show.blade.php b/resources/views/pages/show.blade.php index 50c6f5d2c..a734b1b95 100644 --- a/resources/views/pages/show.blade.php +++ b/resources/views/pages/show.blade.php @@ -6,43 +6,34 @@
- + @include('pages._breadcrumbs', ['page' => $page])
-
Export
+
{{ trans('entities.pages_export') }}
@if(userCan('page-update', $page)) - Edit + {{ trans('common.edit') }} @endif @if(userCan('page-update', $page) || userCan('restrictions-manage', $page) || userCan('page-delete', $page)) @@ -64,7 +55,7 @@
- +
@@ -72,11 +63,7 @@
-

- Created {{ $page->created_at->diffForHumans() }} @if($page->createdBy) by {{$page->createdBy->name}} @endif -
- Last Updated {{ $page->updated_at->diffForHumans() }} @if($page->updatedBy) by {{$page->updatedBy->name}} @endif -

+ @include('partials.entity-meta', ['entity' => $page])
@@ -88,27 +75,27 @@ @if($book->restricted) @if(userCan('restrictions-manage', $book)) - Book Permissions Active + {{ trans('entities.books_permissions_active') }} @else - Book Permissions Active + {{ trans('entities.books_permissions_active') }} @endif
@endif @if($page->chapter && $page->chapter->restricted) @if(userCan('restrictions-manage', $page->chapter)) - Chapter Permissions Active + {{ trans('entities.chapters_permissions_active') }} @else - Chapter Permissions Active + {{ trans('entities.chapters_permissions_active') }} @endif
@endif @if($page->restricted) @if(userCan('restrictions-manage', $page)) - Page Permissions Active + {{ trans('entities.pages_permissions_active') }} @else - Page Permissions Active + {{ trans('entities.pages_permissions_active') }} @endif
@endif diff --git a/resources/views/pages/sidebar-tree-list.blade.php b/resources/views/pages/sidebar-tree-list.blade.php index 5309cb774..87eebed49 100644 --- a/resources/views/pages/sidebar-tree-list.blade.php +++ b/resources/views/pages/sidebar-tree-list.blade.php @@ -18,16 +18,16 @@ @endif @if (isset($page) && $page->attachments->count() > 0) -
Attachments
+
{{ trans('entities.pages_attachments') }}
@foreach($page->attachments as $attachment) @endforeach @endif @if (isset($pageNav) && $pageNav) -
Page Navigation
+
{{ trans('entities.pages_navigation') }}
@endif -
Book Navigation
+
{{ trans('entities.books_navigation') }}
@else -

No activity to show

+

{{ trans('common.no_activity') }}

@endif \ No newline at end of file diff --git a/resources/views/partials/custom-styles.blade.php b/resources/views/partials/custom-styles.blade.php index 885cc2729..62bcc881f 100644 --- a/resources/views/partials/custom-styles.blade.php +++ b/resources/views/partials/custom-styles.blade.php @@ -1,4 +1,4 @@ -