From e6fe299c4f694002f914e188d1bad030408ea56f Mon Sep 17 00:00:00 2001 From: James Geiger Date: Thu, 17 Oct 2019 13:46:18 -0500 Subject: [PATCH 002/191] added additional color settings into UI Adds new options in the customization section of the settings to change the shelf, book, chapter, page, and draft colors. --- app/Config/setting-defaults.php | 5 ++ resources/js/components/index.js | 2 + .../js/components/setting-app-color-picker.js | 9 +- .../js/components/setting-color-picker.js | 18 ++++ resources/lang/en/settings.php | 15 +++- .../views/partials/custom-styles.blade.php | 7 +- resources/views/settings/index.blade.php | 82 ++++++++++++++++++- 7 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 resources/js/components/setting-color-picker.js diff --git a/app/Config/setting-defaults.php b/app/Config/setting-defaults.php index c6080df1d..d84c0c264 100644 --- a/app/Config/setting-defaults.php +++ b/app/Config/setting-defaults.php @@ -16,6 +16,11 @@ return [ 'app-editor' => 'wysiwyg', 'app-color' => '#206ea7', 'app-color-light' => 'rgba(32,110,167,0.15)', + 'bookshelf-color' => '#a94747', + 'book-color' => '#077b70', + 'chapter-color' => '#af4d0d', + 'page-color' => '#206ea7', + 'page-draft-color' => '#7e50b1', 'app-custom-head' => false, 'registration-enabled' => false, diff --git a/resources/js/components/index.js b/resources/js/components/index.js index 14cf08ae2..bbe059898 100644 --- a/resources/js/components/index.js +++ b/resources/js/components/index.js @@ -26,6 +26,7 @@ import permissionsTable from "./permissions-table"; import customCheckbox from "./custom-checkbox"; import bookSort from "./book-sort"; import settingAppColorPicker from "./setting-app-color-picker"; +import settingColorPicker from "./setting-color-picker"; import entityPermissionsEditor from "./entity-permissions-editor"; import templateManager from "./template-manager"; import newUserPassword from "./new-user-password"; @@ -59,6 +60,7 @@ const componentMapping = { 'custom-checkbox': customCheckbox, 'book-sort': bookSort, 'setting-app-color-picker': settingAppColorPicker, + 'setting-color-picker': settingColorPicker, 'entity-permissions-editor': entityPermissionsEditor, 'template-manager': templateManager, 'new-user-password': newUserPassword, diff --git a/resources/js/components/setting-app-color-picker.js b/resources/js/components/setting-app-color-picker.js index 6c0c0b31d..02512e109 100644 --- a/resources/js/components/setting-app-color-picker.js +++ b/resources/js/components/setting-app-color-picker.js @@ -6,11 +6,16 @@ class SettingAppColorPicker { this.colorInput = elem.querySelector('input[type=color]'); this.lightColorInput = elem.querySelector('input[name="setting-app-color-light"]'); this.resetButton = elem.querySelector('[setting-app-color-picker-reset]'); + this.defaultButton = elem.querySelector('[setting-app-color-picker-default]') this.colorInput.addEventListener('change', this.updateColor.bind(this)); this.colorInput.addEventListener('input', this.updateColor.bind(this)); this.resetButton.addEventListener('click', event => { - this.colorInput.value = '#206ea7'; + this.colorInput.value = this.colorInput.dataset.current; + this.updateColor(); + }); + this.defaultButton.addEventListener('click', event => { + this.colorInput.value = this.colorInput.dataset.default; this.updateColor(); }); } @@ -53,4 +58,4 @@ class SettingAppColorPicker { } -export default SettingAppColorPicker; \ No newline at end of file +export default SettingAppColorPicker; diff --git a/resources/js/components/setting-color-picker.js b/resources/js/components/setting-color-picker.js new file mode 100644 index 000000000..4d8ce0f93 --- /dev/null +++ b/resources/js/components/setting-color-picker.js @@ -0,0 +1,18 @@ + +class SettingColorPicker { + + constructor(elem) { + this.elem = elem; + this.colorInput = elem.querySelector('input[type=color]'); + this.resetButton = elem.querySelector('[setting-color-picker-reset]'); + this.defaultButton = elem.querySelector('[setting-color-picker-default]'); + this.resetButton.addEventListener('click', event => { + this.colorInput.value = this.colorInput.dataset.current; + }); + this.defaultButton.addEventListener('click', event => { + this.colorInput.value = this.colorInput.dataset.default; + }); + } +} + +export default SettingColorPicker; diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index 026308a34..e709fedfe 100755 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -33,7 +33,7 @@ return [ 'app_logo' => 'Application Logo', 'app_logo_desc' => 'This image should be 43px in height.
Large images will be scaled down.', 'app_primary_color' => 'Application Primary Color', - 'app_primary_color_desc' => 'This should be a hex value.
Leave empty to reset to the default color.', + 'app_primary_color_desc' => 'Sets the primary color for the application including the banner, buttons, and links.', 'app_homepage' => 'Application Homepage', 'app_homepage_desc' => 'Select a view to show on the homepage instead of the default view. Page permissions are ignored for selected pages.', 'app_homepage_select' => 'Select a page', @@ -41,6 +41,19 @@ return [ 'app_disable_comments_toggle' => 'Disable comments', 'app_disable_comments_desc' => 'Disables comments across all pages in the application.
Existing comments are not shown.', + // Color settings + 'bookshelf_color' => 'Shelf Color', + 'bookshelf_color_desc' => 'Sets the color indicator for shelves.', + 'book_color' => 'Book Color', + 'book_color_desc' => 'Sets the color indicator for books.', + 'chapter_color' => 'Chapter Color', + 'chapter_color_desc' => 'Sets the color indicator for chapters.', + 'page_color' => 'Page Color', + 'page_color_desc' => 'Sets the color indicator for pages.', + 'page_draft_color' => 'Page Draft Color', + 'page_draft_color_desc' => 'Sets the color indicator for page drafts.', + + // Registration Settings 'reg_settings' => 'Registration', 'reg_enable' => 'Enable Registration', diff --git a/resources/views/partials/custom-styles.blade.php b/resources/views/partials/custom-styles.blade.php index 908079082..f81939109 100644 --- a/resources/views/partials/custom-styles.blade.php +++ b/resources/views/partials/custom-styles.blade.php @@ -2,5 +2,10 @@ :root { --color-primary: {{ setting('app-color') }}; --color-primary-light: {{ setting('app-color-light') }}; + --color-bookshelf: {{ setting('bookshelf-color')}}; + --color-book: {{ setting('book-color')}}; + --color-chapter: {{ setting('chapter-color')}}; + --color-page: {{ setting('page-color')}}; + --color-page-draft: {{ setting('page-draft-color')}}; } - \ No newline at end of file + diff --git a/resources/views/settings/index.blade.php b/resources/views/settings/index.blade.php index a52774186..4da1d90b0 100644 --- a/resources/views/settings/index.blade.php +++ b/resources/views/settings/index.blade.php @@ -130,19 +130,97 @@ +

{!! trans('settings.app_primary_color_desc') !!}

- +
+ + |
+ +
+
+ +

{!! trans('settings.bookshelf_color_desc') !!}

+
+
+ +
+ + | + +
+
+ + +
+
+ +

{!! trans('settings.book_color_desc') !!}

+
+
+ +
+ + | + +
+
+ + +
+
+ +

{!! trans('settings.chapter_color_desc') !!}

+
+
+ +
+ + | + +
+
+ + +
+
+ +

{!! trans('settings.page_color_desc') !!}

+
+
+ +
+ + | + +
+
+ + +
+
+ +

{!! trans('settings.page_draft_color_desc') !!}

+
+
+ +
+ + | + +
+
+
@@ -246,4 +324,4 @@ @include('components.image-manager', ['imageType' => 'system']) @include('components.entity-selector-popup', ['entityTypes' => 'page']) -@stop \ No newline at end of file +@stop From 48c44958f5b1c7e31e0175149d91d6de4ba959d2 Mon Sep 17 00:00:00 2001 From: Albergoni Andrea Date: Fri, 18 Oct 2019 16:34:38 +0200 Subject: [PATCH 003/191] Added support for Pascal language --- resources/assets/js/services/code.js | 2 ++ resources/views/components/code-editor.blade.php | 1 + 2 files changed, 3 insertions(+) diff --git a/resources/assets/js/services/code.js b/resources/assets/js/services/code.js index 1e0e48289..fe8da7773 100644 --- a/resources/assets/js/services/code.js +++ b/resources/assets/js/services/code.js @@ -24,6 +24,7 @@ import 'codemirror/mode/sql/sql'; import 'codemirror/mode/toml/toml'; import 'codemirror/mode/xml/xml'; import 'codemirror/mode/yaml/yaml'; +import 'codemirror/mode/pascal/pascal' // Addons import 'codemirror/addon/scroll/scrollpastend'; @@ -70,6 +71,7 @@ const modeMap = { xml: 'xml', yaml: 'yaml', yml: 'yaml', + pascal: 'text/x-pascal', }; /** diff --git a/resources/views/components/code-editor.blade.php b/resources/views/components/code-editor.blade.php index 31a583182..869651a5c 100644 --- a/resources/views/components/code-editor.blade.php +++ b/resources/views/components/code-editor.blade.php @@ -32,6 +32,7 @@ SQL XML YAML + Pascal
From 19ce6da0d3bb08523936475b35b1654b7b2d75d2 Mon Sep 17 00:00:00 2001 From: User Date: Mon, 21 Oct 2019 03:44:38 +0900 Subject: [PATCH 004/191] Update Korean translation --- resources/.DS_Store | Bin 0 -> 10244 bytes resources/lang/.DS_Store | Bin 0 -> 10244 bytes resources/lang/ko/.DS_Store | Bin 0 -> 6148 bytes resources/lang/ko/activities.php | 62 ++-- resources/lang/ko/auth.php | 102 +++--- resources/lang/ko/common.php | 78 ++--- resources/lang/ko/components.php | 40 +-- resources/lang/ko/entities.php | 546 +++++++++++++++---------------- resources/lang/ko/errors.php | 116 +++---- resources/lang/ko/passwords.php | 10 +- resources/lang/ko/settings.php | 219 +++++++------ resources/lang/ko/validation.php | 156 ++++----- 12 files changed, 665 insertions(+), 664 deletions(-) create mode 100644 resources/.DS_Store create mode 100644 resources/lang/.DS_Store create mode 100644 resources/lang/ko/.DS_Store diff --git a/resources/.DS_Store b/resources/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..4e23096917d4948939d3105c7373b4b4b25cb503 GIT binary patch literal 10244 zcmeHMTWl0n826vA+R9|F z@bwiw0zLvh0zLvh0zLv)2LiNbvm(@S>DN92J_0@hB?Q>_Awmz6aZgTj>3%w>a*qHc zgQRu~wdow-#zZ_B_vAE}ZYYh(PY>vYqIbkV9!~ZMb0-=1QwTJpA z9@(+78-n1M6i#1)d#f@B&iqu=m*?En@>(&c8Rymp)x3k_l z-cMx>-F8}AKgB>zuy)Q|K@jSMdBWX^F>5^GC{Et)R&x7UZwd z<4Jjbk7YWFZfZF)K+`NL$BLG%^`$ zZ|{gkVzKtlsVPwit%%*)cOWxyc=GOnZ-(vq>i92AhEBOIzlyoW|^fY0JoG zOgkwzrWGTdHxx(fGK_?NShI&5?U2J-`)n)c^tg^gI>j!*(w0?g+tzRHx-jpW23cy7<_{KhTTdC(EmdYYk*AiMBS|$kl znZ75dQO(uTiqJ|?R)l_=Cd`LeEk#Ay7W?m`m&!wLmSTdeiUWp{(hRQZkU9nVPI0in zQRB)D(k7u1qv8-ci{v05I%;_;VbwW zzJYJyd-wrTW*bakrmj_O8oo0I|(yzjyU%TT!b%(Z{HEueum$$78@{x z&A1rDxCB??jkpG*xR#i93vR%T*yFNo8}7p0*pCCa2a~8^ni!`Mj%#5tgD9 zTS(+g!!k!n$9@4puxaD5t2Q}I|5|P5}U5%3Z45%3Z45%3YX>JX^mGm5bL|1E#~ z|Nm7tZ+}8Q0zLx&90C~ZP4srtc*WCt_0R!QMCds{4=c=XnoBo?D(1rU?sYtM*mb;n sTR}SSp2D@qJ-=x#-EfL?!%6bn{D1w=fWLep<)8ok^FNXKe|Y}?9e&*Bng9R* literal 0 HcmV?d00001 diff --git a/resources/lang/.DS_Store b/resources/lang/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..b097e45b02d92876f6f973b94a5457f979494146 GIT binary patch literal 10244 zcmeI1U2GIp6vxk5sLX7^P7zr_T2~4Ip(slcL{YaNeAF)pEwn(j>~=>wvOBZx%(gY_YK|m9ug!mDk1bHw~RE$bQF{lv(M)bjuX!OAszaIQ}&~xvd-MuqRV|+mqXOfva zbN=_t@7{CI%-p*R0N7H@Bmm+7pwP}rZ9E+UHm0-voGs#7dZw6#!je=yJgZXM?^^qZ75u+6t3tlF;KXZJ?_>^y5)!{g*%|T_&}G8?g|Ato$ep! z)d7>D43A+1!U&uj0k(FJKne=k&4~`*`kmWzR$E&-Yo)24@}P70m;9ll%_X0ll^Ipb z_e=M~`HUQaKCr!j9R2@@px__Kcvez}Y%N%U-a6IGe*Ss8_PgRUV@o$DT-d>$-B$}kk z%spLYrl&@whru-h_z@a)-*fXxE$=7UW#-f!WhVEL^VzQja{8g@?cwQLIEU;qXVW2x z!?jAU{F;}Oq}$Q>7~pt0$Cs4sGH3fKi9^q`%0-(M%v`K)0(^XGq#kuhVdE*PgMO0_aUxxJ&`8tiaVPSI{j6*jV~ z)hVYx?Vfj9RRWvg;zfXq{R8>{f zUTwbos>Eg{u5aIz+q!M&-r@V6X2U^~7jK%H5YcMQw4*XaeD z%3iI;rU10}S?213&h)N6D_hK&cCS|3m&*1PvnfY!&SpD|ZMxm<==V76Y=dnToK{}3 z+aO(#WPt*_C^!5Gln$j#PJJuv>_sh2g(p0{A}(&p0>F09d_6Qh&51`OLsXZ5v% zM#kx1pR)UOGh>*WH&Fac$GFqb3u-O?u6CNKoPJuXxp2bd*d?*mDse{bVb?7?5zczj=~(B8JneQDW%h<28&zFi8iX5t#)pq z!4$4nMH7maQP*ZuX+0}U3!{q^?Pj%WKtxR#mqf2qYOzu6rVnY3+HDK-4Y8!69Z~LJ z>|0W{vnsEfglD~Ip=PaT_U24R&nSx8ken?>nfJ6I$sZW@`?~^D;7UlsO6Z~2ULLl> zPS^#H!9I8a4#LauCLD(k;6wNbK7}vgYxoAfh40`8_z`}FUl1{h)i@q6!OL+v&cK;C z2b*vqF2cpQ6qn(0T#4IhSl%e7S?$Z>b#)p` z7;&l2sEblYt6ZBsgS3dNG|nSs3?;A75(}brS{3D~@LRMv8r8;9A`A7prKDa!DJ#@u zGpWEHDfOS{-1Be%-k^Lt1!v$Z%C+w)&whhHu?lN2hEs4F)?q!)!YgntHsU{1+w#g&PT^NhwL(E{}zeEwaSOmuLW?b=zZeQM5^VSiByzmk}5L?_mr8Q z8WnPIjR1axrq1384o+Cd`$=}0dGwt!ll#c=^lM(uYPubbn+;pMpUn4nm+UgV z`N$l<=H<8(92*9_oMR$C$S!ksYj0F?lWUde`L#ffsE zsE~te zc=;Lu%7jkn^70S=;ZfnBhl~x-V a%MnqMg|_qlXFzEs9IpSv_5c5L{r?vTXwWhM literal 0 HcmV?d00001 diff --git a/resources/lang/ko/.DS_Store b/resources/lang/ko/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 '페이지 생성', - 'page_create_notification' => '페이지를 만들었습니다.', - 'page_update' => '페이지 업데이트', - 'page_update_notification' => '페이지를 업데이트하였습니다.', - 'page_delete' => '페이지 삭제', - 'page_delete_notification' => '페이지를 삭제하였습니다.', - 'page_restore' => '페이지 복원', - 'page_restore_notification' => '페이지를 복원하였습니다.', - 'page_move' => '페이지 이동', + 'page_create' => '문서 만들기', + 'page_create_notification' => '문서 만듦', + 'page_update' => '문서 수정', + 'page_update_notification' => '문서 수정함', + 'page_delete' => '문서 지우기', + 'page_delete_notification' => '문서 지움', + 'page_restore' => '문서 복원', + 'page_restore_notification' => '문서 복원함', + 'page_move' => '문서 옮기기', // Chapters - 'chapter_create' => '챕터 만들기', - 'chapter_create_notification' => '챕터를 만들었습니다.', - 'chapter_update' => '챕터 업데이트', - 'chapter_update_notification' => '챕터를 업데이트하였습니다.', - 'chapter_delete' => '챕터 삭제', - 'chapter_delete_notification' => '챔터를 삭제하였습니다.', - 'chapter_move' => '챕터 이동', + 'chapter_create' => '장절 만들기', + 'chapter_create_notification' => '장절 만듦', + 'chapter_update' => '장절 바꾸기', + 'chapter_update_notification' => '장절 바꿈', + 'chapter_delete' => '장절 지우기', + 'chapter_delete_notification' => '장절 지움', + 'chapter_move' => '장절 옮기기', // Books - 'book_create' => '책 만들기', - 'book_create_notification' => '책을 만들었습니다.', - 'book_update' => '책 업데이트', - 'book_update_notification' => '책을 업데이트하였습니다.', - 'book_delete' => '책 삭제', - 'book_delete_notification' => '책을 삭제하였습니다.', - 'book_sort' => '책 정렬', - 'book_sort_notification' => '책을 정렬하였습니다.', + 'book_create' => '서적 만들기', + 'book_create_notification' => '서적 만듦', + 'book_update' => '서적 바꾸기', + 'book_update_notification' => '서적 바꿈', + 'book_delete' => '서적 지우기', + 'book_delete_notification' => '서적 지움', + 'book_sort' => '서적 정렬', + 'book_sort_notification' => '서적 정렬함', // Bookshelves - 'bookshelf_create' => 'created Bookshelf', - 'bookshelf_create_notification' => 'Bookshelf Successfully Created', - 'bookshelf_update' => 'updated bookshelf', - 'bookshelf_update_notification' => 'Bookshelf Successfully Updated', - 'bookshelf_delete' => 'deleted bookshelf', - 'bookshelf_delete_notification' => 'Bookshelf Successfully Deleted', + 'bookshelf_create' => '서가 만들기', + 'bookshelf_create_notification' => '서가 만듦', + 'bookshelf_update' => '서가 바꾸기', + 'bookshelf_update_notification' => '서가 바꿈', + 'bookshelf_delete' => '서가 지우기', + 'bookshelf_delete_notification' => '서가 지움', // Other - 'commented_on' => 'commented on', + 'commented_on' => '댓글 쓰기', ]; diff --git a/resources/lang/ko/auth.php b/resources/lang/ko/auth.php index 86b55dc2c..a89706a74 100644 --- a/resources/lang/ko/auth.php +++ b/resources/lang/ko/auth.php @@ -6,72 +6,72 @@ */ return [ - 'failed' => '이 자격 증명은 등록되어 있지 않습니다.', - 'throttle' => '로그인 시도 횟수 제한을 초과했습니다. :seconds초 후에 다시 시도하십시오.', + 'failed' => '가입하지 않았거나 비밀번호가 틀립니다.', + 'throttle' => '여러 번 실패했습니다. :seconds초 후에 다시 시도하세요.', // Login & Register - 'sign_up' => '신규등록', + 'sign_up' => '가입', 'log_in' => '로그인', - 'log_in_with' => ':socialDriver에 로그인', - 'sign_up_with' => ':socialDriver로 등록', + 'log_in_with' => ':socialDriver로 로그인', + 'sign_up_with' => ':socialDriver로 가입', 'logout' => '로그아웃', 'name' => '이름', - 'username' => '사용자이름', - 'email' => '이메일', + 'username' => '사용자 이름', + 'email' => '메일 주소', 'password' => '비밀번호', - 'password_confirm' => '비밀번호 (확인)', - 'password_hint' => '7자 이상이어야 합니다.', - 'forgot_password' => '비밀번호를 잊으셨습니까?', - 'remember_me' => '자동로그인', - 'ldap_email_hint' => '이 계정에서 사용하는 이메일을 입력해 주세요.', - 'create_account' => '계정 만들기', - 'already_have_account' => 'Already have an account?', - 'dont_have_account' => 'Don\'t have an account?', - 'social_login' => 'SNS로그인', - 'social_registration' => 'SNS등록', - 'social_registration_text' => '다른 서비스를 사용하여 등록하고 로그인.', + 'password_confirm' => '비밀번호 확인', + 'password_hint' => '네 글자를 넘어야 합니다.', + 'forgot_password' => '비밀번호를 잊었나요?', + 'remember_me' => '로그인 유지', + 'ldap_email_hint' => '이 계정에 대한 메일 주소를 입력하세요.', + 'create_account' => '가입', + 'already_have_account' => '계정이 있나요?', + 'dont_have_account' => '계정이 없나요?', + 'social_login' => '소셜 로그인', + 'social_registration' => '소셜 가입', + 'social_registration_text' => '소셜 계정으로 가입하고 로그인합니다.', - 'register_thanks' => '등록이완료되었습니다!', - 'register_confirm' => '당신의 이메일을 확인하신후 확인 버튼을 눌러 :appName에 액세스하십시오.', - 'registrations_disabled' => '현재 등록이 불가합니다.', - 'registration_email_domain_invalid' => '해당 이메일 도메인으로 액세스 할 수 없습니다.', - 'register_success' => '등록을 완료하고 로그인 할 수 있습니다!', + 'register_thanks' => '가입해 주셔서 감사합니다!', + 'register_confirm' => '메일을 확인한 후 버튼을 눌러 :appName에 접근하세요.', + 'registrations_disabled' => '가입할 수 없습니다.', + 'registration_email_domain_invalid' => '이 메일 주소로는 이 사이트에 접근할 수 없습니다.', + 'register_success' => '가입했습니다! 이제 로그인할 수 있습니다.', // Password Reset - 'reset_password' => '암호 재설정', - 'reset_password_send_instructions' => '다음에 메일 주소를 입력하면 비밀번호 재설정 링크가 포함 된 이메일이 전송됩니다.', - 'reset_password_send_button' => '재설정 링크 보내기', - 'reset_password_sent_success' => ':email로 재설정 링크를 보냈습니다.', - 'reset_password_success' => '비밀번호가 재설정되었습니다.', - 'email_reset_subject' => ':appName 암호를 재설정', - 'email_reset_text' => '귀하의 계정에 대한 비밀번호 재설정 요청을 받았기 때문에 본 이메일이 발송되었습니다.', - 'email_reset_not_requested' => '암호 재설정을 요청하지 않은 경우 더 이상의 조치는 필요하지 않습니다.', + 'reset_password' => '비밀번호 바꾸기', + 'reset_password_send_instructions' => '메일 주소를 입력하세요. 이 주소로 해당 과정을 위한 링크를 보낼 것입니다.', + 'reset_password_send_button' => '메일 보내기', + 'reset_password_sent_success' => ':email로 메일을 보냈습니다.', + 'reset_password_success' => '비밀번호를 바꿨습니다.', + 'email_reset_subject' => ':appName 비밀번호 바꾸기', + 'email_reset_text' => '비밀번호를 바꿉니다.', + 'email_reset_not_requested' => '원하지 않는다면 이 과정은 필요 없습니다.', // Email Confirmation - 'email_confirm_subject' => ':appName의 이메일 주소 확인', - 'email_confirm_greeting' => ':appName에 가입 ​​해 주셔서 감사합니다!', - 'email_confirm_text' => '다음 버튼을 눌러 이메일 주소를 확인하십시오', - 'email_confirm_action' => '이메일 주소를 확인', - 'email_confirm_send_error' => 'E메일 확인이 필요하지만 시스템에서 메일을 보낼 수 없습니다. 관리자에게 문의하여 메일이 제대로 설정되어 있는지 확인하십시오.', - 'email_confirm_success' => '메일 주소가 확인되었습니다.', - 'email_confirm_resent' => '확인 메일을 다시 보냈습니다. 받은 편지함을 확인하십시오.', + 'email_confirm_subject' => ':appName 메일 인증', + 'email_confirm_greeting' => ':appName로 가입해 주셔서 감사합니다!', + 'email_confirm_text' => '다음 버튼을 눌러 인증하세요:', + 'email_confirm_action' => '메일 인증', + 'email_confirm_send_error' => '메일을 보낼 수 없었습니다.', + 'email_confirm_success' => '인증했습니다!', + 'email_confirm_resent' => '다시 보냈습니다. 메일함을 확인하세요.', - 'email_not_confirmed' => '메일 주소가 확인되지 않습니다', - 'email_not_confirmed_text' => '메일 주소 확인이 완료되지 않습니다.', - 'email_not_confirmed_click_link' => '등록시 받은 이메일을 확인하고 확인 링크를 클릭하십시오.', - 'email_not_confirmed_resend' => '메일이 없으면 아래 양식을 통해 다시 제출하십시오.', - 'email_not_confirmed_resend_button' => '확인 메일을 다시 전송', + 'email_not_confirmed' => '인증하지 않았습니다.', + 'email_not_confirmed_text' => '인증을 완료하지 않았습니다.', + 'email_not_confirmed_click_link' => '메일을 확인하고 인증 링크를 클릭하세요.', + 'email_not_confirmed_resend' => '메일 주소가 없다면 다음을 입력하세요.', + 'email_not_confirmed_resend_button' => '다시 보내기', // User Invite - 'user_invite_email_subject' => 'You have been invited to join :appName!', - 'user_invite_email_greeting' => 'An account has been created for you on :appName.', - 'user_invite_email_text' => 'Click the button below to set an account password and gain access:', - 'user_invite_email_action' => 'Set Account Password', - 'user_invite_page_welcome' => 'Welcome to :appName!', - 'user_invite_page_text' => 'To finalise your account and gain access you need to set a password which will be used to log-in to :appName on future visits.', - 'user_invite_page_confirm_button' => 'Confirm Password', - 'user_invite_success' => 'Password set, you now have access to :appName!' + 'user_invite_email_subject' => ':appName에서 권유를 받았습니다.', + 'user_invite_email_greeting' => ':appName에서 가입한 기록이 있습니다.', + 'user_invite_email_text' => '다음 버튼을 눌러 확인하세요:', + 'user_invite_email_action' => '비밀번호 설정', + 'user_invite_page_welcome' => ':appName로 접속했습니다.', + 'user_invite_page_text' => ':appName에 로그인할 때 입력할 비밀번호를 설정하세요.', + 'user_invite_page_confirm_button' => '비밀번호 확인', + 'user_invite_success' => '이제 :appName에 접근할 수 있습니다.' ]; \ No newline at end of file diff --git a/resources/lang/ko/common.php b/resources/lang/ko/common.php index 31d3e5024..8d3a148a5 100644 --- a/resources/lang/ko/common.php +++ b/resources/lang/ko/common.php @@ -9,68 +9,68 @@ return [ 'confirm' => '확인', 'back' => '뒤로', 'save' => '저장', - 'continue' => '계속하기', + 'continue' => '계속', 'select' => '선택', - 'toggle_all' => 'Toggle All', - 'more' => '더보기', + 'toggle_all' => '모두 보기', + 'more' => '더 보기', // Form Labels 'name' => '이름', 'description' => '설명', - 'role' => '역할', + 'role' => '권한', 'cover_image' => '대표 이미지', - 'cover_image_description' => '이 이미지는 약 440x250px 정도의 크기여야 합니다.', + 'cover_image_description' => '이미지 규격은 440x250px 내외입니다.', // Actions - 'actions' => 'Actions', - 'view' => '뷰', - 'view_all' => 'View All', - 'create' => '생성', - 'update' => '업데이트', + 'actions' => '활동', + 'view' => '보기', + 'view_all' => '모두 보기', + 'create' => '만들기', + 'update' => '바꾸기', 'edit' => '수정', 'sort' => '정렬', - 'move' => '이동', + 'move' => '옮기기', 'copy' => '복사', - 'reply' => 'Reply', - 'delete' => '삭제', + 'reply' => '답글', + 'delete' => '지우기', 'search' => '검색', - 'search_clear' => '검색기록 삭제', - 'reset' => '초기화', + 'search_clear' => '기록 지우기', + 'reset' => '리셋', 'remove' => '제거', 'add' => '추가', // Sort Options - 'sort_options' => 'Sort Options', - 'sort_direction_toggle' => 'Sort Direction Toggle', - 'sort_ascending' => 'Sort Ascending', - 'sort_descending' => 'Sort Descending', - 'sort_name' => 'Name', - 'sort_created_at' => 'Created Date', - 'sort_updated_at' => 'Updated Date', + 'sort_options' => '정렬 기준', + 'sort_direction_toggle' => '순서 반전', + 'sort_ascending' => '오름차 순서', + 'sort_descending' => '내림차 순서', + 'sort_name' => '제목', + 'sort_created_at' => '만든 날짜', + 'sort_updated_at' => '수정한 날짜', // Misc - 'deleted_user' => '삭제된 사용자', - 'no_activity' => '활동내역이 없음', - 'no_items' => '사용가능한 항목이 없음', - 'back_to_top' => '맨위로', - 'toggle_details' => '상세 토글', - 'toggle_thumbnails' => '썸내일 토글', - 'details' => '상세', - 'grid_view' => '그리드 뷰', - 'list_view' => '리스트뷰', - 'default' => '기본설정', - 'breadcrumb' => 'Breadcrumb', + 'deleted_user' => '삭제한 사용자', + 'no_activity' => '활동 없음', + 'no_items' => '항목 없음', + 'back_to_top' => '맨 위로', + 'toggle_details' => '내용 보기', + 'toggle_thumbnails' => '섬네일 보기', + 'details' => '정보', + 'grid_view' => '격자 보기', + 'list_view' => '목록 보기', + 'default' => '기본 설정', + 'breadcrumb' => '탐색 경로', // Header - 'profile_menu' => 'Profile Menu', - 'view_profile' => '프로파일 보기', - 'edit_profile' => '프로파일 수정하기', + 'profile_menu' => '프로필', + 'view_profile' => '프로필 보기', + 'edit_profile' => '프로필 바꾸기', // Layout tabs - 'tab_info' => 'Info', - 'tab_content' => 'Content', + 'tab_info' => '정보', + 'tab_content' => '내용', // Email Content - 'email_action_help' => '":actionText"버튼을 클릭하는 데 문제가 있으면 아래 URL을 복사하여 웹 브라우저에 붙여 넣으십시오:', + 'email_action_help' => ':actionText를 클릭할 수 없을 때는 웹 브라우저에서 다음 링크로 접속할 수 있습니다.', 'email_rights' => 'All rights reserved', ]; diff --git a/resources/lang/ko/components.php b/resources/lang/ko/components.php index fd7839e2f..101ac3c51 100644 --- a/resources/lang/ko/components.php +++ b/resources/lang/ko/components.php @@ -6,28 +6,28 @@ return [ // Image Manager 'image_select' => '이미지 선택', - 'image_all' => '전체', - 'image_all_title' => '모든 이미지 보기', - 'image_book_title' => '이 책에 업로드된 이미지 보기', - 'image_page_title' => '이 페이지에 업로드된 이미지 보기', - 'image_search_hint' => '이미지 이름으로 검색', - 'image_uploaded' => ':uploadedDate에 업로드됨', - 'image_load_more' => '더 불러오기', + 'image_all' => '모든 이미지', + 'image_all_title' => '모든 이미지', + 'image_book_title' => '이 서적에서 쓰고 있는 이미지', + 'image_page_title' => '이 문서에서 쓰고 있는 이미지', + 'image_search_hint' => '이미지 이름 검색', + 'image_uploaded' => '올림 :uploadedDate', + 'image_load_more' => '더 로드하기', 'image_image_name' => '이미지 이름', - 'image_delete_used' => '이 이미지는 다음 페이지에서 이용되고 있습니다.', - 'image_delete_confirm' => '삭제해도 괜찮으시면 다시 삭제 버튼을 눌러주세요.', - 'image_select_image' => '선택', - 'image_dropzone' => '업로드를 위해 이미지를 가져와 놓거나 클릭하세요', - 'images_deleted' => '이미지 삭제', - 'image_preview' => '이미지 미리보기', - 'image_upload_success' => '이미지 업로드가 완료되었습니다.', - 'image_update_success' => '이미지 상세정보가 업데이트 되었습니다.', - 'image_delete_success' => '이미지가 삭제되었습니다.', - 'image_upload_remove' => '제거', + 'image_delete_used' => '이 이미지는 다음 문서들이 쓰고 있습니다.', + 'image_delete_confirm' => '이 이미지를 지울 건가요?', + 'image_select_image' => '이미지 선택', + 'image_dropzone' => '여기에 이미지를 드롭하거나 여기를 클릭하세요. 이미지를 올릴 수 있습니다.', + 'images_deleted' => '이미지 삭제함', + 'image_preview' => '이미지 미리 보기', + 'image_upload_success' => '이미지 올림', + 'image_update_success' => '이미지 정보 수정함', + 'image_delete_success' => '이미지 삭제함', + 'image_upload_remove' => '삭제', // Code Editor 'code_editor' => '코드 수정', - 'code_language' => '코드 언어', - 'code_content' => '코드 내용', - 'code_save' => '코드 저장', + 'code_language' => '언어', + 'code_content' => '내용', + 'code_save' => '저장', ]; diff --git a/resources/lang/ko/entities.php b/resources/lang/ko/entities.php index 4e2692bc5..48b5d74bd 100644 --- a/resources/lang/ko/entities.php +++ b/resources/lang/ko/entities.php @@ -6,309 +6,309 @@ return [ // Shared - 'recently_created' => '최근작성', - 'recently_created_pages' => '최근 작성된 페이지', - 'recently_updated_pages' => '최근 업데이트된 페이지', - 'recently_created_chapters' => '최근 만들어진 챕터', - 'recently_created_books' => '최근 만들어진 책', - 'recently_created_shelves' => 'Recently Created Shelves', - 'recently_update' => '최근 작성', - 'recently_viewed' => '검색 기록', - 'recent_activity' => '최근 활동', - 'create_now' => '지금 만들기', - 'revisions' => '변경이력', - 'meta_revision' => '수정 #:revisionCount', - 'meta_created' => '작성: :timeLength', - 'meta_created_name' => '작성: :timeLength by :user', - 'meta_updated' => '업데이트 :timeLength', - 'meta_updated_name' => '업데이트 :timeLength by :user', - 'entity_select' => '엔티티선택', + 'recently_created' => '최근에 수정함', + 'recently_created_pages' => '최근에 만든 문서', + 'recently_updated_pages' => '최근에 수정한 문서', + 'recently_created_chapters' => '최근에 만든 장절', + 'recently_created_books' => '최근에 만든 서적', + 'recently_created_shelves' => '최근에 만든 서가', + 'recently_update' => '최근에 수정함', + 'recently_viewed' => '최근에 읽음', + 'recent_activity' => '최근에 활동함', + 'create_now' => '바로 만들기', + 'revisions' => '수정본', + 'meta_revision' => '판본 #:revisionCount', + 'meta_created' => '만듦 :timeLength', + 'meta_created_name' => '만듦 :timeLength, :user', + 'meta_updated' => '수정함 :timeLength', + 'meta_updated_name' => '수정함 :timeLength, :user', + 'entity_select' => '항목 선택', 'images' => '이미지', - 'my_recent_drafts' => '내 최근 초안', - 'my_recently_viewed' => '검색 기록', - 'no_pages_viewed' => '조회한 페이지가 없습니다.', - 'no_pages_recently_created' => '최근 만들어진 페이지가 없습니다', - 'no_pages_recently_updated' => '최근 업데이트된 페이지가없습니다', - 'export' => '내보내기', - 'export_html' => 'html 내보내기', + 'my_recent_drafts' => '쓰다 만 문서', + 'my_recently_viewed' => '내가 읽은 문서', + 'no_pages_viewed' => '문서 없음', + 'no_pages_recently_created' => '문서 없음', + 'no_pages_recently_updated' => '문서 없음', + 'export' => '파일로 받기', + 'export_html' => 'Contained Web(.html) 파일', 'export_pdf' => 'PDF 파일', - 'export_text' => '일반 텍스트 파일', + 'export_text' => 'Plain Text(.txt) 파일', // Permissions and restrictions 'permissions' => '권한', - 'permissions_intro' => '이 설정은 각 사용자의 역할보다 우선하여 적용됩니다.', - 'permissions_enable' => '커스텀 권한 활성화', + 'permissions_intro' => '한번 허용하면 이 설정은 사용자 권한에 우선합니다.', + 'permissions_enable' => '설정 허용', 'permissions_save' => '권한 저장', // Search 'search_results' => '검색 결과', - 'search_total_results_found' => ':count 개의 결과를 찾았습니다.|총 :count 개의 결과를 찾았습니다.', - 'search_clear' => '검색기록 초기화', - 'search_no_pages' => '검색결과가 없습니다.', - 'search_for_term' => ':term 을(를) 검색합니다.', - 'search_more' => '결과 더보기', - 'search_filters' => '검색 필터', - 'search_content_type' => '컨텐츠 타입', - 'search_exact_matches' => '정확히 일치합니다.', - 'search_tags' => '테그 검색', - 'search_options' => '설정', - 'search_viewed_by_me' => '내가본것', - 'search_not_viewed_by_me' => '내가안본것', - 'search_permissions_set' => '권한 설정', + 'search_total_results_found' => ':count개|총 :count개', + 'search_clear' => '기록 지우기', + 'search_no_pages' => '결과 없음', + 'search_for_term' => ':term 검색', + 'search_more' => '더 많은 결과', + 'search_filters' => '고급 검색', + 'search_content_type' => '형식', + 'search_exact_matches' => '정확히 일치', + 'search_tags' => '꼬리표 일치', + 'search_options' => '선택', + 'search_viewed_by_me' => '내가 읽음', + 'search_not_viewed_by_me' => '내가 읽지 않음', + 'search_permissions_set' => '권한 설정함', 'search_created_by_me' => '내가 만듦', - 'search_updated_by_me' => '내가 업데이트함', - 'search_date_options' => '날짜 설정', - 'search_updated_before' => '이전에 업데이트함', - 'search_updated_after' => '이후에 업데이트함', - 'search_created_before' => '이전에 생성함', - 'search_created_after' => '이후에 생성함', + 'search_updated_by_me' => '내가 수정함', + 'search_date_options' => '날짜', + 'search_updated_before' => '이전에 수정함', + 'search_updated_after' => '이후에 수정함', + 'search_created_before' => '이전에 만듦', + 'search_created_after' => '이후에 만듦', 'search_set_date' => '날짜 설정', - 'search_update' => '검색 업데이트', + 'search_update' => '검색', // Shelves - 'shelf' => '책꽃이', - 'shelves' => '책꽃이', - 'x_shelves' => ':count Shelf|:count Shelves', - 'shelves_long' => '책꽃이', - 'shelves_empty' => '책꽃이가 만들어지지 않았습니다.', - 'shelves_create' => '새책꽃이 만들기', - 'shelves_popular' => '인기있는 책꽃이', - 'shelves_new' => '새로운 책꽃이', - 'shelves_new_action' => 'New Shelf', - 'shelves_popular_empty' => '인기있는 책꽃이가 여기에 나타납니다.', - 'shelves_new_empty' => '가장 최근에 만들어진 책꽃이가 여기에 나타납니다.', - 'shelves_save' => '책꽃이 저장', - 'shelves_books' => '이 책꽃이에 있는 책', - 'shelves_add_books' => '이 책꽃이에 책을 추가합니다', - 'shelves_drag_books' => '이 책꽃이에 책을 추가하기 위해 끌어놓으세요.', - 'shelves_empty_contents' => '이책꽃이엔 등록된 책이 없습니다.', - 'shelves_edit_and_assign' => '책을 등록하기 위해 책꽃이를 수정', - 'shelves_edit_named' => ':name 책꽃이 수정', - 'shelves_edit' => '책꽃이 수정', - 'shelves_delete' => '책꽃이 삭제', - 'shelves_delete_named' => ':name 책꽃이를 삭제합니다.', - 'shelves_delete_explain' => "':name' 이름의 책꽃이가 삭제됩니다. 포함된 책은 삭제되지 않습니다.", - 'shelves_delete_confirmation' => '이 책꽃이를 삭제하시겠습니까?', - 'shelves_permissions' => '책꽃이 권한', - 'shelves_permissions_updated' => '책꽃이 권한이 업데이트 되었습니다.', - 'shelves_permissions_active' => '책꽃이 권한 활성화', - 'shelves_copy_permissions_to_books' => '책에 권한을 복사합니다.', - 'shelves_copy_permissions' => '권한 복사', - 'shelves_copy_permissions_explain' => '이 책꽂이의 현재 권한 설정이 안에 포함 된 모든 책에 적용됩니다. 활성화하기 전에이 책꽂이의 사용 권한이 변경되었는지 확인하십시오.', - 'shelves_copy_permission_success' => '책꽃이의 권한이 :count 개의 책에 복사되었습니다.', + 'shelf' => '서가', + 'shelves' => '서가', + 'x_shelves' => '서가 :count개|총 :count개', + 'shelves_long' => '서가', + 'shelves_empty' => '만든 서가가 없습니다.', + 'shelves_create' => '서가 만들기', + 'shelves_popular' => '많이 읽은 서가', + 'shelves_new' => '새로운 서가', + 'shelves_new_action' => '새로운 서가', + 'shelves_popular_empty' => '많이 읽은 서가 목록', + 'shelves_new_empty' => '새로운 서가 목록', + 'shelves_save' => '저장', + 'shelves_books' => '이 서가에 있는 서적들', + 'shelves_add_books' => '이 서가에 서적 추가', + 'shelves_drag_books' => '여기에 서적을 드롭하세요.', + 'shelves_empty_contents' => '이 서가에 서적이 없습니다.', + 'shelves_edit_and_assign' => '서가 바꾸기로 서적을 추가하세요.', + 'shelves_edit_named' => ':name 바꾸기', + 'shelves_edit' => '서가 바꾸기', + 'shelves_delete' => '서가 지우기', + 'shelves_delete_named' => ':name 지우기', + 'shelves_delete_explain' => ':name을 지웁니다. 서적은 지우지 않습니다.', + 'shelves_delete_confirmation' => '이 서가를 지울 건가요?', + 'shelves_permissions' => '서가 권한', + 'shelves_permissions_updated' => '서가 권한 바꿈', + 'shelves_permissions_active' => '서가 권한 허용함', + 'shelves_copy_permissions_to_books' => '권한 맞춤', + 'shelves_copy_permissions' => '실행', + 'shelves_copy_permissions_explain' => '서가의 모든 서적에 이 권한을 적용합니다. 서가의 권한을 저장했는지 확인하세요.', + 'shelves_copy_permission_success' => '서적 :count개 권한 바꿈', // Books - 'book' => '책', - 'books' => '책들', - 'x_books' => ':count 책|:count 책들', - 'books_empty' => '책이 만들어지지 않았습니다.', - 'books_popular' => '인기있는 책', - 'books_recent' => '최근 책', - 'books_new' => '새로운 책', - 'books_new_action' => 'New Book', - 'books_popular_empty' => '가장 인기있는 책이 여기에 보입니다.', - 'books_new_empty' => '가장 최근에 만든 책이 여기에 표시됩니다.', - 'books_create' => '새로운 책 만들기', - 'books_delete' => '책 삭제하기', - 'books_delete_named' => ':bookName 책 삭제하기', - 'books_delete_explain' => '\':bookName\' 이름의 책이 삭제됩니다. 모든 페이지와 챕터가 삭제됩니다.', - 'books_delete_confirmation' => '이 책을 삭제 하시겠습니까?', - 'books_edit' => '책 수정', - 'books_edit_named' => ':bookName 책 수정', - 'books_form_book_name' => '책 이름', - 'books_save' => '책 저장', - 'books_permissions' => '책 권한', - 'books_permissions_updated' => '책 권한이 업데이트 되었습니다.', - 'books_empty_contents' => '이 책에 대한 페이지 또는 장이 작성되지 않았습니다.', - 'books_empty_create_page' => '새로운 페이지 만들기', - 'books_empty_sort_current_book' => '현제 책 정렬하기', - 'books_empty_add_chapter' => '챕터 추가하기', - 'books_permissions_active' => '책 권한 활성화', - 'books_search_this' => '이책 찾기', - 'books_navigation' => '책 네비게이션', - 'books_sort' => '책 구성 정렬하기', - 'books_sort_named' => ':bookName 책 정렬하기', - 'books_sort_name' => 'Sort by Name', - 'books_sort_created' => 'Sort by Created Date', - 'books_sort_updated' => 'Sort by Updated Date', - 'books_sort_chapters_first' => 'Chapters First', - 'books_sort_chapters_last' => 'Chapters Last', - 'books_sort_show_other' => '다른책 보기', - 'books_sort_save' => '새로운 순서 저장', + 'book' => '서고', + 'books' => '서고', + 'x_books' => '서적 :count개|총 :count개', + 'books_empty' => '만든 서적이 없습니다.', + 'books_popular' => '많이 읽은 서적', + 'books_recent' => '최근에 읽은 서적', + 'books_new' => '새로운 서적', + 'books_new_action' => '새로운 서적', + 'books_popular_empty' => '많이 읽은 서적 목록', + 'books_new_empty' => '새로운 서적 목록', + 'books_create' => '서적 만들기', + 'books_delete' => '서적 지우기', + 'books_delete_named' => ':bookName(을)를 지웁니다.', + 'books_delete_explain' => ':bookName에 있는 모든 장절과 문서도 지웁니다.', + 'books_delete_confirmation' => '이 서적을 지울 건가요?', + 'books_edit' => '서적 바꾸기', + 'books_edit_named' => ':bookName(을)를 바꿉니다.', + 'books_form_book_name' => '서적 이름', + 'books_save' => '저장', + 'books_permissions' => '서적 권한', + 'books_permissions_updated' => '권한 저장함', + 'books_empty_contents' => '이 서적에 장절이나 문서가 없습니다.', + 'books_empty_create_page' => '문서 만들기', + 'books_empty_sort_current_book' => '읽고 있는 서적 정렬', + 'books_empty_add_chapter' => '장절 만들기', + 'books_permissions_active' => '서적 권한 허용함', + 'books_search_this' => '이 서적에서 검색', + 'books_navigation' => '목차', + 'books_sort' => '다른 서적들', + 'books_sort_named' => ':bookName 정렬', + 'books_sort_name' => '제목', + 'books_sort_created' => '만든 날짜', + 'books_sort_updated' => '수정한 날짜', + 'books_sort_chapters_first' => '장절 우선', + 'books_sort_chapters_last' => '문서 우선', + 'books_sort_show_other' => '다른 서적들', + 'books_sort_save' => '적용', // Chapters - 'chapter' => '챕터', - 'chapters' => '챕터', - 'x_chapters' => ':count 개 챕터|:count 챔터들', - 'chapters_popular' => '인기있는 챕터', - 'chapters_new' => '새로운 챕처', - 'chapters_create' => '새로운 챕터 만들기', - 'chapters_delete' => '챕터 삭제', - 'chapters_delete_named' => ':chapterName 챕터 지우기', - 'chapters_delete_explain' => '\':chapterName\' 챕터를 지웁니다. 챕터에서 모든 페이지가 삭제되며 페이지가 상위 책에 추가됩니다.', - 'chapters_delete_confirm' => '정말로 챕터를 지우시겠습니따?', - 'chapters_edit' => '챕터 수정', - 'chapters_edit_named' => ':chapterName 챕터 수정', - 'chapters_save' => '챕터 저장', - 'chapters_move' => '챕터 이동', - 'chapters_move_named' => ':chapterName 챕터 이동', - 'chapter_move_success' => ':bookName 으로 챕터를 이동하였습니다.', - 'chapters_permissions' => '챕터 권한', - 'chapters_empty' => '챕터에 포함된 페이지가 없습니다.', - 'chapters_permissions_active' => '챕터 권한 활동', - 'chapters_permissions_success' => '챕터 권한 수정됨', - 'chapters_search_this' => '이 챕터 찾기', + 'chapter' => '장절', + 'chapters' => '장절', + 'x_chapters' => '장절 :count개|총 :count개', + 'chapters_popular' => '많이 읽은 장절', + 'chapters_new' => '새로운 장절', + 'chapters_create' => '장절 만들기', + 'chapters_delete' => '장절 지우기', + 'chapters_delete_named' => ':chapterName(을)를 지웁니다.', + 'chapters_delete_explain' => ':chapterName에 있는 모든 문서는 장절에서 벗어날 뿐 지우지 않습니다.', + 'chapters_delete_confirm' => '이 장절을 지울 건가요?', + 'chapters_edit' => '장절 바꾸기', + 'chapters_edit_named' => ':chapterName 바꾸기', + 'chapters_save' => '저장', + 'chapters_move' => '장절 옮기기', + 'chapters_move_named' => ':chapterName 옮기기', + 'chapter_move_success' => ':bookName(으)로 옮김', + 'chapters_permissions' => '장절 권한', + 'chapters_empty' => '이 장절에 문서가 없습니다.', + 'chapters_permissions_active' => '문서 권한 허용함', + 'chapters_permissions_success' => '권한 저장함', + 'chapters_search_this' => '이 장절에서 검색', // Pages - 'page' => '페이지', - 'pages' => '페이지들', - 'x_pages' => ':count 개의 페이지|:count 개의 페이지들', - 'pages_popular' => '인기있는 페이지', - 'pages_new' => '새로운 페이지', - 'pages_attachments' => '첨부파일', - 'pages_navigation' => '페이지 네비게이션', - 'pages_delete' => '페이지 지우기', - 'pages_delete_named' => ':pageName 페이지 지우기', - 'pages_delete_draft_named' => ':pageName 초안 페이지 지우기', - 'pages_delete_draft' => '초안 페이지 지우기', - 'pages_delete_success' => '페이지 삭제됨', - 'pages_delete_draft_success' => '초안페이지 삭제됨', - 'pages_delete_confirm' => '정말로 이 페이지를 지우시겠습니까?', - 'pages_delete_draft_confirm' => '정말로 초안페이지를 지우시겠습니까?', - 'pages_editing_named' => ':pageName 페이지 수정', - 'pages_edit_draft_options' => 'Draft Options', - 'pages_edit_save_draft' => '초안 저장', - 'pages_edit_draft' => '페이지 초안 수정', - 'pages_editing_draft' => '초안 수정중', - 'pages_editing_page' => '페이지 수정중', - 'pages_edit_draft_save_at' => '초안이 저장됨 ', - 'pages_edit_delete_draft' => '초안 삭제', - 'pages_edit_discard_draft' => '초안 버리기', - 'pages_edit_set_changelog' => '변경내역 남기기', - 'pages_edit_enter_changelog_desc' => '어떤 내용에 대하여 변경하셨나요?', - 'pages_edit_enter_changelog' => '변경내역 입력', - 'pages_save' => '페이지 저장', - 'pages_title' => '페이지 제목', - 'pages_name' => '페이지 이름', - 'pages_md_editor' => '편집자', - 'pages_md_preview' => 'Preview', - 'pages_md_insert_image' => '이미지 삽입', - 'pages_md_insert_link' => '전체링크 입력', - 'pages_md_insert_drawing' => '드로잉 넣기', - 'pages_not_in_chapter' => '페이지가 챕터에 있지않습니다.', - 'pages_move' => '페이지 옮기기', - 'pages_move_success' => '":parentName"로 페이지를 이동하였습니다.', - 'pages_copy' => '페이지 복사', - 'pages_copy_desination' => '경로(desination) 복사', - 'pages_copy_success' => '페이지가 성공적으로 복사되었습니다', - 'pages_permissions' => '페이지 권한', - 'pages_permissions_success' => '페이지 권한이 업데이트 되었습니다.', - 'pages_revision' => '변경이력', - 'pages_revisions' => '페이지 변경이력', - 'pages_revisions_named' => ':pageName페이지의 변경이력내역', - 'pages_revision_named' => ':pageName페이지의 변경이력', - 'pages_revisions_created_by' => 'Created By', - 'pages_revisions_date' => '변경일', - 'pages_revisions_number' => '#', - 'pages_revisions_numbered' => 'Revision #:id', - 'pages_revisions_numbered_changes' => 'Revision #:id Changes', - 'pages_revisions_changelog' => '변경내역', - 'pages_revisions_changes' => '변경사항 보기', - 'pages_revisions_current' => '현재 버전', - 'pages_revisions_preview' => '미리보기', - 'pages_revisions_restore' => '되돌리기', - 'pages_revisions_none' => '이 페이지에는 변경이력이 없습니다.', - 'pages_copy_link' => '링크복사', - 'pages_edit_content_link' => '링크 수정', - 'pages_permissions_active' => '페이지 권한 활성화', - 'pages_initial_revision' => '최초 작성', - 'pages_initial_name' => '새 페이지', - 'pages_editing_draft_notification' => ':timeDiff 전에 저장된 초안을 최근 편집하셨습니다.', - 'pages_draft_edited_notification' => '이 페이지는 그 이후로 업데이트되었습니다. 이 초안을 폐기하는 것이 좋습니다.', + 'page' => '문서', + 'pages' => '문서', + 'x_pages' => '문서 :count개|총 :count개', + 'pages_popular' => '많이 읽은 문서', + 'pages_new' => '새로운 문서', + 'pages_attachments' => '첨부', + 'pages_navigation' => '목차', + 'pages_delete' => '문서 지우기', + 'pages_delete_named' => ':pageName 지우기', + 'pages_delete_draft_named' => ':pageName 지우기', + 'pages_delete_draft' => '쓰다 만 문서 지우기', + 'pages_delete_success' => '문서 지움', + 'pages_delete_draft_success' => '쓰다 만 문서 지움', + 'pages_delete_confirm' => '이 문서를 지울 건가요?', + 'pages_delete_draft_confirm' => '쓰다 만 문서를 지울 건가요?', + 'pages_editing_named' => ':pageName 수정', + 'pages_edit_draft_options' => '쓰다 만 문서 선택', + 'pages_edit_save_draft' => '보관', + 'pages_edit_draft' => '쓰다 만 문서 수정', + 'pages_editing_draft' => '쓰다 만 문서 수정', + 'pages_editing_page' => '문서 수정', + 'pages_edit_draft_save_at' => '보관함: ', + 'pages_edit_delete_draft' => '삭제', + 'pages_edit_discard_draft' => '폐기', + 'pages_edit_set_changelog' => '수정본 설명', + 'pages_edit_enter_changelog_desc' => '수정본 설명', + 'pages_edit_enter_changelog' => '설명', + 'pages_save' => '저장', + 'pages_title' => '문서 제목', + 'pages_name' => '문서 이름', + 'pages_md_editor' => '에디터', + 'pages_md_preview' => '미리 보기', + 'pages_md_insert_image' => '이미지 추가', + 'pages_md_insert_link' => '내부 링크', + 'pages_md_insert_drawing' => '드로잉 추가', + 'pages_not_in_chapter' => '장절에 있는 문서가 아닙니다.', + 'pages_move' => '문서 옮기기', + 'pages_move_success' => ':parentName(으)로 옮김', + 'pages_copy' => '문서 복제', + 'pages_copy_desination' => '복제할 위치', + 'pages_copy_success' => '복제함', + 'pages_permissions' => '문서 권한', + 'pages_permissions_success' => '문서 권한 바꿈', + 'pages_revision' => '수정본', + 'pages_revisions' => '문서 수정본', + 'pages_revisions_named' => ':pageName 수정본', + 'pages_revision_named' => ':pageName 수정본', + 'pages_revisions_created_by' => '만든 사용자', + 'pages_revisions_date' => '수정한 날짜', + 'pages_revisions_number' => 'No.', + 'pages_revisions_numbered' => '수정본 :id', + 'pages_revisions_numbered_changes' => '수정본 :id에서 바꾼 부분', + 'pages_revisions_changelog' => '설명', + 'pages_revisions_changes' => '바꾼 부분', + 'pages_revisions_current' => '현재 판본', + 'pages_revisions_preview' => '미리 보기', + 'pages_revisions_restore' => '복원', + 'pages_revisions_none' => '수정본이 없습니다.', + 'pages_copy_link' => '주소 복사', + 'pages_edit_content_link' => '수정', + 'pages_permissions_active' => '문서 권한 허용함', + 'pages_initial_revision' => '처음 판본', + 'pages_initial_name' => '제목 없음', + 'pages_editing_draft_notification' => ':timeDiff에 쓰다 만 문서입니다.', + 'pages_draft_edited_notification' => '최근에 수정한 문서이기 때문에 쓰다 만 문서를 폐기하는 편이 좋습니다.', 'pages_draft_edit_active' => [ - 'start_a' => ':count명의 사용자가 이 페이지를 수정중입니다.', - 'start_b' => ':userName가(이) 페이지를 수정중입니다.', - 'time_a' => '페이지가 마지막으로 업데이트 된 이후', - 'time_b' => '지난 :minCount분 동안', - 'message' => ':start :time. 서로의 업데이트를 덮어 쓰지 않도록 주의하십시오!', + 'start_a' => ':count명이 이 문서를 수정하고 있습니다.', + 'start_b' => ':userName이 이 문서를 수정하고 있습니다.', + 'time_a' => '수정본이 생겼습니다.', + 'time_b' => '(:minCount분 전)', + 'message' => ':start :time. 다른 사용자의 수정본을 덮어쓰지 않도록 주의하세요.', ], - 'pages_draft_discarded' => '초안이 삭제되었습니다. 편집기가 현재 페이지 작성자로 업데이트되었습니다.', - 'pages_specific' => '특정 페이지', - 'pages_is_template' => 'Page Template', + 'pages_draft_discarded' => '쓰다 만 문서를 지웠습니다. 에디터에 현재 판본이 나타납니다.', + 'pages_specific' => '특정한 문서', + 'pages_is_template' => '템플릿', // Editor Sidebar - 'page_tags' => '페이지 테그', - 'chapter_tags' => '챕터 테그', - 'book_tags' => '책 테그', - 'shelf_tags' => '책꽃이 테그', - 'tag' => '테그', - 'tags' => '테그들', - 'tag_name' => 'Tag Name', - 'tag_value' => '테그 값 (선택사항)', - 'tags_explain' => "컨텐츠를 더 잘 분류하기 위해 테그를 추가하세요! \n 보다 상세한 구성을 위해 태그값을 할당 할 수 있습니다.", - 'tags_add' => '다른 테그 추가', - 'tags_remove' => 'Remove this tag', - 'attachments' => '첨부', - 'attachments_explain' => '일부 파일을 업로드하거나 페이지에 표시 할 링크를 첨부하십시오. 페이지 사이드 바에 표시됩니다.', - 'attachments_explain_instant_save' => '변경 사항은 즉시 저장됩니다.', - 'attachments_items' => '첨부된 항목', - 'attachments_upload' => '차일 업로드', - 'attachments_link' => '링크 첨부', + 'page_tags' => '문서 꼬리표', + 'chapter_tags' => '장절 꼬리표', + 'book_tags' => '서적 꼬리표', + 'shelf_tags' => '서가 꼬리표', + 'tag' => '꼬리표', + 'tags' => '꼬리표', + 'tag_name' => '꼬리표 이름', + 'tag_value' => '리스트 값 (선택 사항)', + 'tags_explain' => '태그로 문서를 분류하세요.', + 'tags_add' => '태그 추가', + 'tags_remove' => '태그 삭제', + 'attachments' => '첨부 파일', + 'attachments_explain' => '파일이나 링크를 첨부하세요. 정보 탭에 나타납니다.', + 'attachments_explain_instant_save' => '여기에서 바꾼 내용은 바로 적용합니다.', + 'attachments_items' => '첨부한 파일들', + 'attachments_upload' => '파일 올리기', + 'attachments_link' => '링크로 첨부', 'attachments_set_link' => '링크 설정', - 'attachments_delete_confirm' => '삭제를 다시 클릭하면 첨부파일이 완전히 삭제됩니다.', - 'attachments_dropzone' => '파일 놓기 또는 여기를 클릭하여 파일 첨부', - 'attachments_no_files' => '업로드 된 파일이 없습니다.', - 'attachments_explain_link' => '파일을 업로드하지 않으려는 경우 링크를 첨부 할 수 있습니다. 이 링크는 다른 페이지에 대한 링크이거나 클라우드에있는 파일에 대한 링크 일 수 있습니다.', + 'attachments_delete_confirm' => '삭제하려면 버튼을 한 번 더 클릭하세요.', + 'attachments_dropzone' => '여기에 파일을 드롭하거나 여기를 클릭하세요.', + 'attachments_no_files' => '올린 파일 없음', + 'attachments_explain_link' => '파일을 올리지 않고 링크로 첨부할 수 있습니다.', 'attachments_link_name' => '링크 이름', - 'attachment_link' => '첨부 링크', - 'attachments_link_url' => '파일로 첨부', - 'attachments_link_url_hint' => 'Url, 사이트 또는 파일', - 'attach' => '첨부', + 'attachment_link' => '파일 주소', + 'attachments_link_url' => '파일로 링크', + 'attachments_link_url_hint' => '파일 주소', + 'attach' => '파일 첨부', 'attachments_edit_file' => '파일 수정', - 'attachments_edit_file_name' => '파일이름', - 'attachments_edit_drop_upload' => '파일을 놓거나 여기를 클릭하여 업로드 및 덮어 쓰기', - 'attachments_order_updated' => '첨부 순서 업데이트', - 'attachments_updated_success' => '첨부파일 상세내용 업데이트 성공', - 'attachments_deleted' => '첨부파일 삭제', - 'attachments_file_uploaded' => '파일이 성공적으로 업로드 되었습니다.', - 'attachments_file_updated' => '파일이 성공적으로 업데이트 되었습니다.', - 'attachments_link_attached' => '링크가 성공적으로 페이지에 첨부되었습니다.', - 'templates' => 'Templates', - 'templates_set_as_template' => 'Page is a template', - 'templates_explain_set_as_template' => 'You can set this page as a template so its contents be utilized when creating other pages. Other users will be able to use this template if they have view permissions for this page.', - 'templates_replace_content' => 'Replace page content', - 'templates_append_content' => 'Append to page content', - 'templates_prepend_content' => 'Prepend to page content', + 'attachments_edit_file_name' => '파일 이름', + 'attachments_edit_drop_upload' => '여기에 파일을 드롭하거나 여기를 클릭하세요. 파일을 올리거나 덮어쓸 수 있습니다.', + 'attachments_order_updated' => '첨부 순서 바꿈', + 'attachments_updated_success' => '첨부 파일 정보 수정함', + 'attachments_deleted' => '첨부 파일 삭제함', + 'attachments_file_uploaded' => '파일 올림', + 'attachments_file_updated' => '파일 바꿈', + 'attachments_link_attached' => '링크 첨부함', + 'templates' => '템플릿', + 'templates_set_as_template' => '템플릿', + 'templates_explain_set_as_template' => '템플릿은 보기 권한만 있어도 문서에 쓸 수 있습니다.', + 'templates_replace_content' => '문서 대체', + 'templates_append_content' => '문서 앞에 추가', + 'templates_prepend_content' => '문서 뒤에 추가', // Profile View - 'profile_user_for_x' => ':time 전에 작성', - 'profile_created_content' => '생성한 컨텐츠', - 'profile_not_created_pages' => ':userName가 작성한 페이지가 없습니다.', - 'profile_not_created_chapters' => ':userName가 작성한 챕터가 없습니다.', - 'profile_not_created_books' => ':userName가 작성한 책이 없습니다.', - 'profile_not_created_shelves' => ':userName has not created any shelves', + 'profile_user_for_x' => ':time 전에 가입함', + 'profile_created_content' => '활동한 이력', + 'profile_not_created_pages' => ':userName(이)가 만든 문서 없음', + 'profile_not_created_chapters' => ':userName(이)가 만든 장절 없음', + 'profile_not_created_books' => ':userName(이)가 만든 서적 없음', + 'profile_not_created_shelves' => ':userName(이)가 만든 서가 없음', // Comments - 'comment' => '코멘트', - 'comments' => '코멘트들', - 'comment_add' => '코멘트 추가', - 'comment_placeholder' => '여기에 코멘트를 남기세요', - 'comment_count' => '{0} 코멘트 없음|{1} 1개 코멘트|[2,*] :count개의 코멘트', - 'comment_save' => '코멘트 저장', - 'comment_saving' => '코멘트 저장중...', - 'comment_deleting' => '코멘트 삭제중...', - 'comment_new' => '새로운 코멘트', - 'comment_created' => '코멘트를 작성하였습니다. :createDiff', - 'comment_updated' => ':username이 코멘트를 수정하였습니다 :updateDiff', - 'comment_deleted_success' => '코멘트 삭제성공', - 'comment_created_success' => '코멘트 추가성공', - 'comment_updated_success' => '코멘트 업데이트 성공', - 'comment_delete_confirm' => '정말로 코멘트를 지우시겠습니까?', - 'comment_in_reply_to' => ':commentId 응답', + 'comment' => '댓글', + 'comments' => '댓글', + 'comment_add' => '댓글 쓰기', + 'comment_placeholder' => '이곳에 댓글을 쓰세요...', + 'comment_count' => '{0} 댓글 없음|{1} 댓글 1개|[2,*] 댓글 :count개', + 'comment_save' => '등록', + 'comment_saving' => '저장하는 중...', + 'comment_deleting' => '삭제하는 중...', + 'comment_new' => '새로운 댓글', + 'comment_created' => '댓글 등록함 :createDiff', + 'comment_updated' => ':username(이)가 댓글 수정함 :updateDiff', + 'comment_deleted_success' => '댓글 지움', + 'comment_created_success' => '댓글 등록함', + 'comment_updated_success' => '댓글 수정함', + 'comment_delete_confirm' => '이 댓글을 지울 건가요?', + 'comment_in_reply_to' => ':commentId(을)를 향한 답글', // Revision - 'revision_delete_confirm' => '해당 개정판을 지우시겠습니까??', - 'revision_restore_confirm' => 'Are you sure you want to restore this revision? The current page contents will be replaced.', - 'revision_delete_success' => '개정판 삭제성공', - 'revision_cannot_delete_latest' => '최신버전은 지울수 없습니다.' + 'revision_delete_confirm' => '이 수정본을 지울 건가요?', + 'revision_restore_confirm' => '이 수정본을 되돌릴 건가요? 현재 판본을 바꿉니다.', + 'revision_delete_success' => '수정본 지움', + 'revision_cannot_delete_latest' => '현재 판본은 지울 수 없습니다.' ]; \ No newline at end of file diff --git a/resources/lang/ko/errors.php b/resources/lang/ko/errors.php index 1a88dd4e3..2f0352f9c 100644 --- a/resources/lang/ko/errors.php +++ b/resources/lang/ko/errors.php @@ -5,81 +5,81 @@ return [ // Permissions - 'permission' => '요청한 페이지에 권한이 없습니다.', - 'permissionJson' => '요청한 작업을 수행 할 권한이 없습니다.', + 'permission' => '권한이 없습니다.', + 'permissionJson' => '권한이 없습니다.', // Auth - 'error_user_exists_different_creds' => '전자 메일 :email을 가진 사용자가 이미 존재하지만 자격 증명이 다릅니다.', - 'email_already_confirmed' => '이메일이 이미 확인되었습니다. 로그인 해주세요.', - 'email_confirmation_invalid' => '이 확인 토큰이 유효하지 않거나 이미 사용되었습니다. 다시 등록하세요.', - 'email_confirmation_expired' => '확인 토큰이 만료되었습니다. 새 확인 이메일이 전송되었습니다.', - 'ldap_fail_anonymous' => '익명 바인드를 이용한 LDAP 액세스에 실패하였습니다.', - 'ldap_fail_authed' => '주어진 dn 및 비밀번호 세부 정보를 사용하여 LDAP 액세스하는 것이 실패했습니다.', - 'ldap_extension_not_installed' => 'LDAP PHP 확장기능이 설치되지 않았습니다.', - 'ldap_cannot_connect' => 'LDAP 서버에 연결할 수 없습니다. 초기 연결에 실패했습니다.', - 'social_no_action_defined' => '동작이 정의되지 않았습니다.', - 'social_login_bad_response' => ":socialAccount 로그인에 실패하였습니다 : \n:error", - 'social_account_in_use' => '이 :socialAccount 계정이 이미 사용 중입니다. :socialAccount 옵션을 통해 로그인하십시오.', - 'social_account_email_in_use' => ' 이메일 :email이 이미 사용 중입니다. 이미 계정이있는 경우 프로필 설정에서 :socialAccount 계정을 연결할 수 있습니다.', - 'social_account_existing' => ':socialAccount가 이미 프로필에 첨부되어 있습니다.', - 'social_account_already_used_existing' => '이 :socialAccount 계정은 이미 다른 사용자가 사용하고 있습니다.', - 'social_account_not_used' => '이 :socialAccount 계정이 모든 사용자에게 연결되어 있지 않습니다. 프로필 설정에 첨부하십시오. ', - 'social_account_register_instructions' => '아직 계정이없는 경우 :socialAccount 옵션을 사용하여 계정을 등록 할 수 있습니다.', - 'social_driver_not_found' => '소셜 드라이버를 찾을 수 없음', - 'social_driver_not_configured' => '귀하의 :socialAccount 소셜 설정이 올바르게 구성되지 않았습니다.', - 'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.', + 'error_user_exists_different_creds' => ':email(을)를 가진 다른 사용자가 있습니다.', + 'email_already_confirmed' => '확인이 끝난 메일 주소입니다. 로그인하세요.', + 'email_confirmation_invalid' => '이 링크는 더 이상 유효하지 않습니다. 다시 가입하세요.', + 'email_confirmation_expired' => '이 링크는 더 이상 유효하지 않습니다. 메일을 다시 보냈습니다.', + 'ldap_fail_anonymous' => '익명 정보로 LDAP 서버에 접근할 수 없습니다.', + 'ldap_fail_authed' => '이 정보로 LDAP 서버에 접근할 수 없습니다.', + 'ldap_extension_not_installed' => 'PHP에 LDAP 확장 도구를 설치하세요.', + 'ldap_cannot_connect' => 'LDAP 서버에 연결할 수 없습니다.', + 'social_no_action_defined' => '무슨 활동인지 알 수 없습니다.', + 'social_login_bad_response' => ':socialAccount에 로그인할 수 없습니다. : \n:error', + 'social_account_in_use' => ':socialAccount(을)를 가진 사용자가 있습니다. :socialAccount로 로그인하세요.', + 'social_account_email_in_use' => ':email(을)를 가진 사용자가 있습니다. 쓰고 있는 계정을 :socialAccount에 연결하세요.', + 'social_account_existing' => ':socialAccount(와)과 연결 상태입니다.', + 'social_account_already_used_existing' => ':socialAccount(와)과 연결한 다른 계정이 있습니다.', + 'social_account_not_used' => ':socialAccount(와)과 연결한 계정이 없습니다. 쓰고 있는 계정을 연결하세요.', + 'social_account_register_instructions' => '계정이 없어도 :socialAccount로 가입할 수 있습니다.', + 'social_driver_not_found' => '가입할 수 없습니다.', + 'social_driver_not_configured' => ':socialAccount가 유효하지 않습니다.', + 'invite_token_expired' => '이 링크는 더 이상 유효하지 않습니다. 비밀번호를 바꾸세요.', // System - 'path_not_writable' => '파일 경로 :filePath에 업로드 할 수 없습니다. 서버에 쓰기 기능이 활성화 되어있는지 확인하세요.', - 'cannot_get_image_from_url' => ':url에서 이미지를 가져올 수 없습니다.', - 'cannot_create_thumbs' => '서버에서 썸네일을 생성할 수 없습니다. GD PHP확장기능이 설치되어있는지 확인하세요.', - 'server_upload_limit' => '해당 크기의 파일을 업로드하는것이 서버에서 제한됩니다. 파일 사이즈를 작게 줄이거나 서버 설정을 변경하세요.', - 'uploaded' => '해당 크기의 파일을 업로드하는것이 서버에서 제한됩니다. 파일 사이즈를 작게 줄이거나 서버 설정을 변경하세요.', - 'image_upload_error' => '이미지를 업로드하는 중에 오류가 발생했습니다.', - 'image_upload_type_error' => '업로드중인 이미지 유형이 잘못되었습니다.', - 'file_upload_timeout' => '파일 업로드가 시간 초과되었습니다.', + 'path_not_writable' => ':filePath에 쓰는 것을 서버에서 허용하지 않습니다.', + 'cannot_get_image_from_url' => ':url에서 이미지를 불러올 수 없습니다.', + 'cannot_create_thumbs' => '섬네일을 못 만들었습니다. PHP에 GD 확장 도구를 설치하세요.', + 'server_upload_limit' => '파일 크기가 서버에서 허용하는 수치를 넘습니다.', + 'uploaded' => '파일 크기가 서버에서 허용하는 수치를 넘습니다.', + 'image_upload_error' => '이미지를 올리다 문제가 생겼습니다.', + 'image_upload_type_error' => '유효하지 않은 이미지 형식입니다.', + 'file_upload_timeout' => '파일을 올리는 데 걸리는 시간이 서버에서 허용하는 수치를 넘습니다.', // Attachments - 'attachment_page_mismatch' => '첨부 파일 업데이트 중 페이지 불일치하였습니다.', - 'attachment_not_found' => '첨부 파일을 찾을 수 없습니다.', + 'attachment_page_mismatch' => '올리는 위치와 현재 문서가 다릅니다.', + 'attachment_not_found' => '첨부 파일이 없습니다.', // Pages - 'page_draft_autosave_fail' => '초안을 저장하지 못했습니다. 이 페이지를 저장하기 전에 인터넷에 연결되어 있는지 확인하십시오.', - 'page_custom_home_deletion' => '홈페이지로 설정되어있는 페이지는 삭제할 수 없습니다.', + 'page_draft_autosave_fail' => '쓰다 만 문서를 유실했습니다. 인터넷 연결 상태를 확인하세요.', + 'page_custom_home_deletion' => '처음 페이지는 지울 수 없습니다.', // Entities - 'entity_not_found' => '개체(Entity)를 찾을 수 없음.', - 'bookshelf_not_found' => '책꽂이를 찾을 수 없음.', - 'book_not_found' => '책을 찾을 수 없음.', - 'page_not_found' => '페이지를 찾을 수 없음.', - 'chapter_not_found' => '챕터를 찾을 수 없음.', - 'selected_book_not_found' => '선택한 책을 찾을 수 없습니다.', - 'selected_book_chapter_not_found' => '선택한 책 또는 챕터를 찾을 수 없습니다.', - 'guests_cannot_save_drafts' => '게스트는 임시저장을 할 수 없습니다.', + 'entity_not_found' => '항목이 없습니다.', + 'bookshelf_not_found' => '서가가 없습니다.', + 'book_not_found' => '서적이 없습니다.', + 'page_not_found' => '문서가 없습니다.', + 'chapter_not_found' => '장절이 없습니다.', + 'selected_book_not_found' => '고른 서적이 없습니다.', + 'selected_book_chapter_not_found' => '고른 서적이나 장절이 없습니다.', + 'guests_cannot_save_drafts' => 'Guest는 쓰다 만 문서를 보관할 수 없습니다.', // Users - 'users_cannot_delete_only_admin' => '어드민 계정은 삭제할 수 없습니다.', - 'users_cannot_delete_guest' => '게스트 사용자는 삭제할 수 없습니다.', + 'users_cannot_delete_only_admin' => 'Admin을 삭제할 수 없습니다.', + 'users_cannot_delete_guest' => 'Guest를 삭제할 수 없습니다.', // Roles - 'role_cannot_be_edited' => '역할을 수정할 수 없습니다.', - 'role_system_cannot_be_deleted' => '이 역할은 시스템 역할입니다. 삭제할 수 없습니다.', - 'role_registration_default_cannot_delete' => '이 역할은 기본 등록 역할로 설정되어있는 동안 삭제할 수 없습니다.', - 'role_cannot_remove_only_admin' => 'This user is the only user assigned to the administrator role. Assign the administrator role to another user before attempting to remove it here.', + 'role_cannot_be_edited' => '권한을 수정할 수 없습니다.', + 'role_system_cannot_be_deleted' => '시스템 권한을 지울 수 없습니다.', + 'role_registration_default_cannot_delete' => '가입한 사용자의 기본 권한을 지울 수 있어야 합니다.', + 'role_cannot_remove_only_admin' => 'Admin을 가진 사용자가 적어도 한 명 있어야 합니다.', // Comments - 'comment_list' => '댓글을 가져 오는 중에 오류가 발생했습니다.', - 'cannot_add_comment_to_draft' => '초안에 주석을 추가 할 수 없습니다.', - 'comment_add' => '댓글을 추가 / 업데이트하는 중에 오류가 발생했습니다.', - 'comment_delete' => '댓글을 삭제하는 중에 오류가 발생했습니다.', - 'empty_comment' => '빈 주석을 추가 할 수 없습니다.', + 'comment_list' => '댓글을 가져오다 문제가 생겼습니다.', + 'cannot_add_comment_to_draft' => '쓰다 만 문서에 댓글을 달 수 없습니다.', + 'comment_add' => '댓글을 등록하다 문제가 생겼습니다.', + 'comment_delete' => '댓글을 지우다 문제가 생겼습니다.', + 'empty_comment' => '빈 댓글은 등록할 수 없습니다.', // Error pages - '404_page_not_found' => '페이지를 찾을 수 없습니다.', - 'sorry_page_not_found' => '죄송합니다, 찾고 있던 페이지를 찾을 수 없습니다.', - 'return_home' => 'home으로 가기', - 'error_occurred' => '오류가 발생하였습니다.', - 'app_down' => ':appName가 다운되었습니다.', - 'back_soon' => '곧 복구될 예정입니다.', + '404_page_not_found' => '404 Not Found', + 'sorry_page_not_found' => '문서를 못 찾았습니다.', + 'return_home' => '처음으로 돌아가기', + 'error_occurred' => '문제가 생겼습니다.', + 'app_down' => ':appName에 문제가 있는 것 같습니다', + 'back_soon' => '곧 되돌아갑니다.', ]; diff --git a/resources/lang/ko/passwords.php b/resources/lang/ko/passwords.php index 26790e95e..144736c3b 100644 --- a/resources/lang/ko/passwords.php +++ b/resources/lang/ko/passwords.php @@ -6,10 +6,10 @@ */ return [ - 'password' => '비밀번호는 6자 이상이어야 하며 확인과 일치해야 합니다.', - 'user' => "해당 이메일 주소의 사용자가 없습니다.", - 'token' => '해당 비밀번호의 초기화 토큰이 만료되었습니다.', - 'sent' => '페스워드 초기화 링크를 메일로 보냈습니다!', - 'reset' => '비밀번호가 초기화 되었습니다!', + 'password' => '여덟 글자를 넘어야 합니다.', + 'user' => '메일 주소를 가진 사용자가 없습니다.', + 'token' => '이 링크는 더 이상 유효하지 않습니다.', + 'sent' => '메일을 보냈습니다.', + 'reset' => '비밀번호를 바꿨습니다.', ]; diff --git a/resources/lang/ko/settings.php b/resources/lang/ko/settings.php index 346e7f6a8..a212dded0 100755 --- a/resources/lang/ko/settings.php +++ b/resources/lang/ko/settings.php @@ -8,135 +8,136 @@ return [ // Common Messages 'settings' => '설정', - 'settings_save' => '설정 저장', - 'settings_save_success' => '설정이 저장되었습니다.', + 'settings_save' => '적용', + 'settings_save_success' => '설정 적용함', // App Settings - 'app_customization' => 'Customization', - 'app_features_security' => 'Features & Security', - 'app_name' => '어플리케이션 이름', - 'app_name_desc' => '해당 이름은 헤더와 모든 이메일에 표시됩니다.', - 'app_name_header' => '헤더에 어플리케이션 이름을 표시하시겠습니까?', - 'app_public_access' => 'Public Access', - 'app_public_access_desc' => 'Enabling this option will allow visitors, that are not logged-in, to access content in your BookStack instance.', - 'app_public_access_desc_guest' => 'Access for public visitors can be controlled through the "Guest" user.', - 'app_public_access_toggle' => 'Allow public access', - 'app_public_viewing' => '공개 보기를 허용하시겠습니까?', - 'app_secure_images' => '더 높은 보안 이미지 업로드를 사용하시겠습니까?', - 'app_secure_images_toggle' => 'Enable higher security image uploads', - 'app_secure_images_desc' => '성능상의 이유로 모든 이미지를 공개합니다. 해당 옵션은 이미지 URL 앞에 추측하기 어려운 임의의 문자열을 추가합니다. 간편한 접근을 방지하기 위해 디렉토리 색인을 비활성화하십시오.', - 'app_editor' => '페이지 에디터', - 'app_editor_desc' => '모든 사용자가 페이지를 편집하는데 사용할 에디터를 선택하십시오.', - 'app_custom_html' => '사용자 정의 HTML 헤드 컨텐츠', - 'app_custom_html_desc' => '여기에 추가된 모든 내용은 모든 페이지의 섹션 아래쪽에 삽입됩니다. 이는 스타일 오버라이딩이나 분석 코드 삽입에 편리합니다.', - 'app_custom_html_disabled_notice' => 'Custom HTML head content is disabled on this settings page to ensure any breaking changes can be reverted.', - 'app_logo' => '어플리케이션 로고', - 'app_logo_desc' => '해당 이미지는 반드시 높이가 43픽셀이어야 합니다.
대용량 이미지는 축소됩니다.', - 'app_primary_color' => '어플리케이션 기본 색상', - 'app_primary_color_desc' => '해당 값은 16진수이어야 합니다.
입력하지 않으면 기본 색상으로 재설정됩니다.', - 'app_homepage' => '어플리케이션 홈페이지', - 'app_homepage_desc' => '기본 화면 대신에 홈페이지에 표시할 화면을 선택하십시오. 선택된 페이지에서는 페이지 권한이 무시됩니다.', - 'app_homepage_select' => '페이지를 선택하십시오', - 'app_disable_comments' => '주석 비활성화', - 'app_disable_comments_toggle' => 'Disable comments', - 'app_disable_comments_desc' => '어플리케이션의 모든 페이지에서 주석을 비활성화합니다. 기존의 주석은 표시되지 않습니다.', + 'app_customization' => '맞춤', + 'app_features_security' => '보안', + 'app_name' => '사이트 제목', + 'app_name_desc' => '메일을 보낼 때 이 제목을 씁니다.', + 'app_name_header' => '사이트 헤더 사용', + 'app_public_access' => '사이트 공개', + 'app_public_access_desc' => '계정 없는 사용자가 문서를 볼 수 있습니다.', + 'app_public_access_desc_guest' => '이들의 권한은 사용자 이름이 Guest인 사용자로 관리할 수 있습니다.', + 'app_public_access_toggle' => '사이트 공개', + 'app_public_viewing' => '공개할 건가요?', + 'app_secure_images' => '이미지 주소 보호', + 'app_secure_images_toggle' => '이미지 주소 보호', + 'app_secure_images_desc' => '성능상의 문제로 이미지에 누구나 접근할 수 있기 때문에 이미지 주소를 무작위한 문자로 구성합니다. 폴더 색인을 끄세요.', + 'app_editor' => '에디터', + 'app_editor_desc' => '모든 사용자에게 적용합니다.', + 'app_custom_html' => '헤드 작성', + 'app_custom_html_desc' => '설정 페이지를 제외한 모든 페이지 head 태그 끝머리에 추가합니다.', + 'app_custom_html_disabled_notice' => '문제가 생겨도 설정 페이지에서 되돌릴 수 있어요.', + 'app_logo' => '사이트 로고', + 'app_logo_desc' => '높이를 43px로 구성하세요. 큰 이미지는 축소합니다.', + 'app_primary_color' => '사이트 색채', + 'app_primary_color_desc' => '16진수로 구성하세요. 비웠을 때는 기본 색채로 설정합니다.', + 'app_homepage' => '처음 페이지', + 'app_homepage_desc' => '고른 페이지에 설정한 권한은 무시합니다.', + 'app_homepage_select' => '문서 고르기', + 'app_disable_comments' => '댓글 사용 안 함', + 'app_disable_comments_toggle' => '댓글 사용 안 함', + 'app_disable_comments_desc' => '모든 페이지에서 댓글을 숨깁니다.', // Registration Settings - 'reg_settings' => '등록 설정', - 'reg_enable' => 'Enable Registration', - 'reg_enable_toggle' => 'Enable registration', - 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', - 'reg_default_role' => '등록 후 기본 사용자 역할', - 'reg_email_confirmation' => 'Email Confirmation', - 'reg_email_confirmation_toggle' => 'Require email confirmation', - 'reg_confirm_email_desc' => '도메인 제한이 사용되면 이메일 확인이 요구되며, 하단의 값은 무시됩니다.', - 'reg_confirm_restrict_domain' => '도메인 등록 제한', - 'reg_confirm_restrict_domain_desc' => '등록을 제한할 이메일 도메인의 목록을 쉼표로 구분하여 입력해주십시오. 사용자는 어플리케이션과의 상호작용을 허가받기 전에 이메일 주소를 확인하는 이메일을 받게 됩니다,
등록이 완료된 후에는 이메일 주소를 변경할 수 있습니다.', - 'reg_confirm_restrict_domain_placeholder' => '제한 없음 설정', + 'reg_settings' => '가입', + 'reg_enable' => '사이트 가입 허용', + 'reg_enable_toggle' => '사이트 가입 허용', + 'reg_enable_desc' => '가입한 사용자는 단일한 권한을 가집니다.', + 'reg_default_role' => '가입한 사용자의 기본 권한', + 'reg_email_confirmation' => '메일 주소 확인', + 'reg_email_confirmation_toggle' => '주소 확인 요구', + 'reg_confirm_email_desc' => '도메인 차단을 쓰고 있으면 메일 주소를 확인해야 하고, 이 설정은 무시합니다.', + 'reg_confirm_restrict_domain' => '도메인 차단', + 'reg_confirm_restrict_domain_desc' => '쉼표로 분리해서 가입을 차단할 메일 주소 도메인을 쓰세요. 이 설정과 관계없이 사용자가 메일을 보내고, 가입한 사용자가 메일 주소를 바꿀 수 있습니다.', + 'reg_confirm_restrict_domain_placeholder' => '없음', // Maintenance settings - 'maint' => 'Maintenance', + 'maint' => '데이터', 'maint_image_cleanup' => '이미지 정리', - 'maint_image_cleanup_desc' => "페이지를 스캔하여 현재 사용중인 이미지와 도면에서 수정된 내용 및 중복된 이미지를 확인합니다. 이를 실행하기 전에 전체 데이터베이스와 이미지의 백업을 작성했는지 확인하십시오.", - 'maint_image_cleanup_ignore_revisions' => '수정본의 이미지를 무시합니다.', - 'maint_image_cleanup_run' => '정리 실행', - 'maint_image_cleanup_warning' => '잠재적으로 사용되지 않는 이미지를 찾았습니다. 해당 이미지들을 삭제하시겠습니까?', - 'maint_image_cleanup_success' => ':잠재적으로 사용되지 않는 이미지들이 삭제되었습니다.', - 'maint_image_cleanup_nothing_found' => '사용되지 않는 이미지를 찾을 수 없습니다. 아무것도 삭제되지 않았습니다.', + 'maint_image_cleanup_desc' => '중복한 이미지를 찾습니다. 실행하기 전에 이미지를 백업하세요.', + 'maint_image_cleanup_ignore_revisions' => '수정본에 있는 이미지 제외', + 'maint_image_cleanup_run' => '실행', + 'maint_image_cleanup_warning' => '이미지 :count개를 지울 건가요?', + 'maint_image_cleanup_success' => '이미지 :count개 삭제함', + 'maint_image_cleanup_nothing_found' => '삭제한 것 없음', // Role Settings - 'roles' => '역할', - 'role_user_roles' => '사용자 역할', - 'role_create' => '신규 역할 생성', - 'role_create_success' => '역할이 생성되었습니다.', - 'role_delete' => '역할을 삭제합니다.', - 'role_delete_confirm' => '\':roleName\'(이)라는 이름의 역할이 삭제됩니다.', - 'role_delete_users_assigned' => '해당 역할에 :userCount 명의 사용자가 할당되어 있습니다. 이 역할로부터 사용자를 재할당하고 싶다면 아래에서 새 역할을 선택하십시오.', - 'role_delete_no_migration' => "사용자 재배치 안함", - 'role_delete_sure' => '이 역할을 삭제하시겠습니까?', - 'role_delete_success' => '역할이 삭제되었습니다.', - 'role_edit' => '역할 편집', - 'role_details' => '역할 상세정보', - 'role_name' => '역할명', - 'role_desc' => '역할에 대한 간략한 설명', - 'role_external_auth_id' => '외부 인증 ID', + 'roles' => '권한', + 'role_user_roles' => '사용자 권한', + 'role_create' => '권한 만들기', + 'role_create_success' => '권한 만듦', + 'role_delete' => '권한 지우기', + 'role_delete_confirm' => ':roleName(을)를 지웁니다.', + 'role_delete_users_assigned' => '이 권한을 가진 사용자 :userCount명에 할당할 권한을 고르세요.', + 'role_delete_no_migration' => '할당하지 않음', + 'role_delete_sure' => '이 권한을 지울 건가요?', + 'role_delete_success' => '권한 지움', + 'role_edit' => '권한 수정', + 'role_details' => '권한 정보', + 'role_name' => '권한 이름', + 'role_desc' => '설명', + 'role_external_auth_id' => 'LDAP 확인', 'role_system' => '시스템 권한', 'role_manage_users' => '사용자 관리', - 'role_manage_roles' => '역할 및 역할 권한 관리', - 'role_manage_entity_permissions' => '모든 책, 챕터, 페이지 관리', - 'role_manage_own_entity_permissions' => '보유한 책, 챕터, 페이지에 대한 권한 관리', - 'role_manage_page_templates' => 'Manage page templates', - 'role_manage_settings' => '어플리케이선 설정 관리', - 'role_asset' => '자산 관리', - 'role_asset_desc' => '해당 권한들은 시스템 내의 Assets 파일에 대한 기본적인 접근을 제어합니다.', - 'role_asset_admins' => '관리자는 모든 컨텐츠에 대한 접근 권한을 자동으로 부여받지만, 해당 옵션들은 UI 옵션을 표시하거나 숨길 수 있습니다.', - 'role_all' => '전체', - 'role_own' => '보유한 것만', - 'role_controlled_by_asset' => '업로드된 Assets 파일에 의해 제어됩니다.', - 'role_save' => '역할 저장', - 'role_update_success' => '역할이 업데이트되었습니다.', - 'role_users' => '해당 역할의 사용자', - 'role_users_none' => '현재 이 역할에 할당된 사용자가 없습니다.', + 'role_manage_roles' => '권한 관리', + 'role_manage_entity_permissions' => '문서별 권한 관리', + 'role_manage_own_entity_permissions' => '직접 만든 문서별 권한 관리', + 'role_manage_page_templates' => '템플릿 관리', + 'role_manage_settings' => '사이트 설정 관리', + 'role_asset' => '권한 항목', + 'role_asset_desc' => '서적, 장절, 문서별 권한은 이 설정에 우선합니다.', + 'role_asset_admins' => 'Admin 권한은 어디든 접근할 수 있지만 이 설정은 사용자 인터페이스에서 해당 활동을 표시할지 결정합니다.', + 'role_all' => '모든 항목', + 'role_own' => '직접 만든 항목', + 'role_controlled_by_asset' => '저마다 다름', + 'role_save' => '저장', + 'role_update_success' => '권한 저장함', + 'role_users' => '이 권한을 가진 사용자들', + 'role_users_none' => '그런 사용자가 없습니다.', // Users 'users' => '사용자', 'user_profile' => '사용자 프로필', - 'users_add_new' => '사용자 추가', + 'users_add_new' => '사용자 만들기', 'users_search' => '사용자 검색', - 'users_details' => 'User Details', - 'users_details_desc' => 'Set a display name and an email address for this user. The email address will be used for logging into the application.', - 'users_details_desc_no_email' => 'Set a display name for this user so others can recognise them.', - 'users_role' => '사용자 역할', - 'users_role_desc' => 'Select which roles this user will be assigned to. If a user is assigned to multiple roles the permissions from those roles will stack and they will receive all abilities of the assigned roles.', - 'users_password' => 'User Password', - 'users_password_desc' => 'Set a password used to log-in to the application. This must be at least 6 characters long.', - 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', - 'users_send_invite_option' => 'Send user invite email', - 'users_external_auth_id' => '외부 인증 ID', - 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your LDAP system.', - 'users_password_warning' => '비밀번호를 변경하시려면 다음을 입력하십시오:', - 'users_system_public' => '이 사용자는 당신의 인스턴스를 방문하는 게스트 사용자를 나타냅니다. 로그인하는 데는 사용할 수 없지만 자동으로 할당됩니다.', + 'users_details' => '사용자 정보', + 'users_details_desc' => '메일 주소로 로그인합니다.', + 'users_details_desc_no_email' => '사용자 이름을 바꿉니다.', + 'users_role' => '사용자 권한', + 'users_role_desc' => '고른 권한 모두를 적용합니다.', + 'users_password' => '비밀번호', + 'users_password_desc' => '여섯 글자를 넘어야 합니다.', + 'users_send_invite_text' => '비밀번호 설정을 권유하는 메일을 보내거나 내가 정할 수 있습니다.', + 'users_send_invite_option' => '메일 보내기', + 'users_external_auth_id' => 'LDAP 확인', + 'users_external_auth_id_desc' => 'LDAP 서버에 연결할 때 사용자를 확인합니다.', + 'users_password_warning' => '비밀번호를 바꿀 때만 쓰세요.', + 'users_system_public' => '계정 없는 모든 사용자에 할당한 사용자입니다. 이 사용자로 로그인할 수 없어요.', 'users_delete' => '사용자 삭제', - 'users_delete_named' => '사용자 :userName 삭제', - 'users_delete_warning' => '시스템에서 \':userName\'(이)라는 사용자가 완전히 삭제됩니다.', - 'users_delete_confirm' => '이 사용자를 삭제하시겠습니까?', - 'users_delete_success' => '사용자가 삭제되었습니다.', - 'users_edit' => '사용자 편집', - 'users_edit_profile' => '프로필 편집', - 'users_edit_success' => '사용자가 업데이트되었습니다.', - 'users_avatar' => '사용자 아바타', - 'users_avatar_desc' => '해당 이미지는 256픽셀의 정사각형 이미지여야합니다.', - 'users_preferred_language' => '선호하는 언어', - 'users_preferred_language_desc' => 'This option will change the language used for the user-interface of the application. This will not affect any user-created content.', + 'users_delete_named' => ':userName 삭제', + 'users_delete_warning' => ':userName에 관한 데이터를 지웁니다.', + 'users_delete_confirm' => '이 사용자를 지울 건가요?', + 'users_delete_success' => '사용자 삭제함', + 'users_edit' => '사용자 수정', + 'users_edit_profile' => '프로필 바꾸기', + 'users_edit_success' => '프로필 바꿈', + 'users_avatar' => '프로필 이미지', + 'users_avatar_desc' => '이미지 규격은 256x256px 내외입니다.', + 'users_preferred_language' => '언어', + 'users_preferred_language_desc' => '문서 내용에는 아무런 영향을 주지 않습니다.', 'users_social_accounts' => '소셜 계정', - 'users_social_accounts_info' => '여기에서 다른 계정을 연결하여 더 빠르고 쉽게 로그인할 수 있습니다. 여기에서 계정 연결을 해제하면 이전에 승인된 접근이 제공되지 않습니다 연결된 소셜 계정의 프로필 설정에서 접근 권한을 취소하십시오.', + 'users_social_accounts_info' => '다른 계정으로 간단하게 로그인하세요. 여기에서 계정 연결을 끊는 것과 소셜 계정에서 접근 권한을 취소하는 것은 별개입니다.', 'users_social_connect' => '계정 연결', - 'users_social_disconnect' => '계정 연결 해제', - 'users_social_connected' => ':socialAccount 계정이 당신의 프로필에 연결되었습니다.', - 'users_social_disconnected' => ':socialAccount 계정이 당신의 프로필에서 연결해제되었습니다.', + 'users_social_disconnect' => '계정 연결 끊기', + 'users_social_connected' => ':socialAccount(와)과 연결했습니다.', + 'users_social_disconnected' => ':socialAccount(와)과의 연결을 끊었습니다.', - //! If editing translations files directly please ignore this in all - //! languages apart from en. Content will be auto-copied from en. + //! Since these labels are already localized this array does not need to be + //! translated in the language-specific files. + //! DELETE BELOW IF COPIED FROM EN //!//////////////////////////////// 'language_select' => [ 'en' => 'English', diff --git a/resources/lang/ko/validation.php b/resources/lang/ko/validation.php index 07ecdd021..180faa35f 100644 --- a/resources/lang/ko/validation.php +++ b/resources/lang/ko/validation.php @@ -8,104 +8,104 @@ return [ // Standard laravel validation lines - 'accepted' => ':attribute가 반드시 허용되어야 합니다.', - 'active_url' => ':attribute가 올바른 URL이 아닙니다.', - 'after' => ':attribute는 :date이후 날짜여야 합니다.', - 'alpha' => ':attribute는 문자만 포함해야 합니다.', - 'alpha_dash' => ':attribute는 문자, 숫자, 대시만 포함해야 합니다.', - 'alpha_num' => ':attribute는 문자와 숫자만 포함됩니다.', - 'array' => ':attribute는 배열이어야 합니다.', - 'before' => ':attribute는 :date이전 날짜여야 합니다.', + 'accepted' => ':attribute(을)를 허용하세요.', + 'active_url' => ':attribute(을)를 유효한 주소로 구성하세요.', + 'after' => ':attribute(을)를 :date 후로 설정하세요.', + 'alpha' => ':attribute(을)를 문자로만 구성하세요.', + 'alpha_dash' => ':attribute(을)를 문자, 숫자, -, _로만 구성하세요.', + 'alpha_num' => ':attribute(을)를 문자, 숫자로만 구성하세요.', + 'array' => ':attribute(을)를 배열로 구성하세요.', + 'before' => ':attribute(을)를 :date 전으로 설정하세요.', 'between' => [ - 'numeric' => ':attribute는 반드시 :min이상 :max이하여야 합니다.', - 'file' => ':attribute는 반드시 :min이상 :max kilobytes이하여야 합니다.', - 'string' => ':attribute는 반드시 :min이상 :max 문자 이하여야 합니다.', - 'array' => ':attribute는 반드시 :min이상 :max이하 항목이어야 합니다.', + 'numeric' => ':attribute(을)를 :min~:max(으)로 구성하세요.', + 'file' => ':attribute(을)를 :min~:max킬로바이트로 구성하세요.', + 'string' => ':attribute(을)를 :min~:max바이트로 구성하세요.', + 'array' => ':attribute(을)를 :min~:max개로 구성하세요.', ], - 'boolean' => ':attribute 는 true혹은 false값만 가능합니다.', - 'confirmed' => ':attribute 확인이 일치하지 않습니다.', - 'date' => ':attribute 는 잘못된 날짜입니다.', - 'date_format' => ':attribute 이 :format 포멧과 일치하지 않습니다.', - 'different' => ':attribute 와 :other는 반드시 달라야 합니다.', - 'digits' => ':attribute 는 반드시 :digits 숫자(digit)여야 합니다.', - 'digits_between' => ':attribute 는 반드시 :min이상 :max이하 숫자여야 합니다.', - 'email' => ':attribute 는 반드시 이메일 이어야 합니다.', - 'ends_with' => 'The :attribute must end with one of the following: :values', - 'filled' => ':attribute 항목이 꼭 필요합니다.', + 'boolean' => ':attribute(을)를 true나 false로만 구성하세요.', + 'confirmed' => ':attribute(와)과 다릅니다.', + 'date' => ':attribute(을)를 유효한 날짜로 구성하세요.', + 'date_format' => ':attribute(은)는 :format(와)과 다릅니다.', + 'different' => ':attribute(와)과 :other(을)를 다르게 구성하세요.', + 'digits' => ':attribute(을)를 :digits자리로 구성하세요.', + 'digits_between' => ':attribute(을)를 :min~:max자리로 구성하세요.', + 'email' => ':attribute(을)를 유효한 메일 주소로 구성하세요.', + 'ends_with' => ':attribute(을)를 :values(으)로 끝나게 구성하세요.', + 'filled' => ':attribute(을)를 구성하세요.', 'gt' => [ - 'numeric' => 'The :attribute must be greater than :value.', - 'file' => 'The :attribute must be greater than :value kilobytes.', - 'string' => 'The :attribute must be greater than :value characters.', - 'array' => 'The :attribute must have more than :value items.', + 'numeric' => ':attribute(을)를 :value(이)가 넘게 구성하세요.', + 'file' => ':attribute(을)를 :value킬로바이트가 넘게 구성하세요.', + 'string' => ':attribute(을)를 :value바이트가 넘게 구성하세요.', + 'array' => ':attribute(을)를 :value개가 넘게 구성하세요.', ], 'gte' => [ - 'numeric' => 'The :attribute must be greater than or equal :value.', - 'file' => 'The :attribute must be greater than or equal :value kilobytes.', - 'string' => 'The :attribute must be greater than or equal :value characters.', - 'array' => 'The :attribute must have :value items or more.', + 'numeric' => ':attribute(을)를 적어도 :value(으)로 구성하세요.', + 'file' => ':attribute(을)를 적어도 :value킬로바이트로 구성하세요.', + 'string' => ':attribute(을)를 적어도 :value바이트로 구성하세요.', + 'array' => ':attribute(을)를 적어도 :value개로 구성하세요..', ], - 'exists' => '선택된 :attribute 은(는) 사용 불가합니다.', - 'image' => ':attribute 는 반드시 이미지여야 합니다.', - 'image_extension' => 'The :attribute must have a valid & supported image extension.', - 'in' => '선택된 :attribute 은(는) 사용 불가합니다.', - 'integer' => ':attribute 는 반드시(integer)여야 합니다.', - 'ip' => ':attribute 는 반드시 IP주소 여야 합니다.', - 'ipv4' => 'The :attribute must be a valid IPv4 address.', - 'ipv6' => 'The :attribute must be a valid IPv6 address.', - 'json' => 'The :attribute must be a valid JSON string.', + 'exists' => '고른 :attribute(이)가 유효하지 않습니다.', + 'image' => ':attribute(을)를 이미지로 구성하세요.', + 'image_extension' => ':attribute(을)를 유효한 이미지 확장자로 구성하세요.', + 'in' => '고른 :attribute(이)가 유효하지 않습니다.', + 'integer' => ':attribute(을)를 정수로 구성하세요.', + 'ip' => ':attribute(을)를 유효한 IP 주소로 구성하세요.', + 'ipv4' => ':attribute(을)를 유효한 IPv4 주소로 구성하세요.', + 'ipv6' => ':attribute(을)를 유효한 IPv6 주소로 구성하세요.', + 'json' => ':attribute(을)를 유효한 JSON으로 구성하세요.', 'lt' => [ - 'numeric' => 'The :attribute must be less than :value.', - 'file' => 'The :attribute must be less than :value kilobytes.', - 'string' => 'The :attribute must be less than :value characters.', - 'array' => 'The :attribute must have less than :value items.', + 'numeric' => ':attribute(을)를 :value(이)가 안 되게 구성하세요.', + 'file' => ':attribute(을)를 :value킬로바이트가 안 되게 구성하세요.', + 'string' => ':attribute(을)를 :value바이트가 안 되게 구성하세요.', + 'array' => ':attribute(을)를 :value개가 안 되게 구성하세요.', ], 'lte' => [ - 'numeric' => 'The :attribute must be less than or equal :value.', - 'file' => 'The :attribute must be less than or equal :value kilobytes.', - 'string' => 'The :attribute must be less than or equal :value characters.', - 'array' => 'The :attribute must not have more than :value items.', + 'numeric' => ':attribute(을)를 많아야 :max(으)로 구성하세요.', + 'file' => ':attribute(을)를 많아야 :max킬로바이트로 구성하세요.', + 'string' => ':attribute(을)를 많아야 :max바이트로 구성하세요.', + 'array' => ':attribute(을)를 많아야 :max개로 구성하세요.', ], 'max' => [ - 'numeric' => ':attribute :max 보다 크면 안됩니다.', - 'file' => ':attribute :max kilobytes보다 크면 안됩니다.', - 'string' => ':attribute :max 문자보다 길면 안됩니다.', - 'array' => ':attribute :max 를 초과하면 안됩니다.', + 'numeric' => ':attribute(을)를 많아야 :max(으)로 구성하세요.', + 'file' => ':attribute(을)를 많아야 :max킬로바이트로 구성하세요.', + 'string' => ':attribute(을)를 많아야 :max바이트로 구성하세요.', + 'array' => ':attribute(을)를 많아야 :max개로 구성하세요.', ], - 'mimes' => ':attribute 은(는) 반드시 :values 타입이어야 합니다.', + 'mimes' => ':attribute(을)를 :values 형식으로 구성하세요.', 'min' => [ - 'numeric' => ':attribute 은(는) 최소한 :min 이어야 합니다.', - 'file' => ':attribute 은(는) 최소한 :min kilobytes여야 합니다.', - 'string' => ':attribute 은(는) 최소한 :min 개 문자여야 합니다.', - 'array' => ':attribute 은(는) 적어도 :min 개의 항목이어야 합니다.', + 'numeric' => ':attribute(을)를 적어도 :value(으)로 구성하세요.', + 'file' => ':attribute(을)를 적어도 :value킬로바이트로 구성하세요.', + 'string' => ':attribute(을)를 적어도 :value바이트로 구성하세요.', + 'array' => ':attribute(을)를 적어도 :value개로 구성하세요..', ], - 'no_double_extension' => 'The :attribute must only have a single file extension.', - 'not_in' => '선택된 :attribute 는 사용할 수 없습니다', - 'not_regex' => 'The :attribute format is invalid.', - 'numeric' => ':attribute 반드시 숫자여야 합니다.', - 'regex' => ':attribute 포멧이 잘못되었습니다.', - 'required' => ':attribute 항목은 필수입니다..', - 'required_if' => ':attribute 은(는) :other 가 :value 일때 필수항목입니다.', - 'required_with' => ':attribute 은(는) :values 가 있을때 필수항목입니다.', - 'required_with_all' => ':attribute 은(는) :values 가 있을때 필수항목입니다.', - 'required_without' => ':attribute 은(는) :values 가 없을때 필수항목입니다.', - 'required_without_all' => ':attribute 은(는) :values 가 전혀 없을때 필수항목입니다.', - 'same' => ':attribute 와 :other 은(는) 반드시 일치해야합니다.', + 'no_double_extension' => ':attribute(이)가 단일한 확장자를 가져야 합니다.', + 'not_in' => '고른 :attribute(이)가 유효하지 않습니다.', + 'not_regex' => ':attribute(은)는 유효하지 않은 형식입니다.', + 'numeric' => ':attribute(을)를 숫자로만 구성하세요.', + 'regex' => ':attribute(은)는 유효하지 않은 형식입니다.', + 'required' => ':attribute(을)를 구성하세요.', + 'required_if' => ':other(이)가 :value일 때 :attribute(을)를 구성해야 합니다.', + 'required_with' => ':values(이)가 있을 때 :attribute(을)를 구성해야 합니다.', + 'required_with_all' => ':values(이)가 모두 있을 때 :attribute(을)를 구성해야 합니다.', + 'required_without' => ':values(이)가 없을 때 :attribute(을)를 구성해야 합니다.', + 'required_without_all' => ':values(이)가 모두 없을 때 :attribute(을)를 구성해야 합니다.', + 'same' => ':attribute(와)과 :other(을)를 똑같이 구성하세요.', 'size' => [ - 'numeric' => ':attribute 은(는) :size 여야합니다.', - 'file' => ':attribute 은(는) :size kilobytes여야합니다.', - 'string' => ':attribute 은(는) :size 문자여야합니다.', - 'array' => ':attribute 은(는) :size 개 항목을 포함해야 합니다.', + 'numeric' => ':attribute(을)를 :size(으)로 구성하세요.', + 'file' => ':attribute(을)를 :size킬로바이트로 구성하세요.', + 'string' => ':attribute(을)를 :size바이트로 구성하세요.', + 'array' => ':attribute(을)를 :size개로 구성하세요..', ], - 'string' => ':attribute 문자열이어야 합니다.', - 'timezone' => ':attribute 정상적인 지역(zone)이어야 합니다.', - 'unique' => ':attribute 은(는) 이미 사용중입니다..', - 'url' => ':attribute 포멧이 사용 불가합니다.', - 'uploaded' => 'The file could not be uploaded. The server may not accept files of this size.', + 'string' => ':attribute(을)를 문자로 구성하세요.', + 'timezone' => ':attribute(을)를 유효한 시간대로 구성하세요.', + 'unique' => ':attribute(은)는 이미 있습니다.', + 'url' => ':attribute(은)는 유효하지 않은 형식입니다.', + 'uploaded' => '파일 크기가 서버에서 허용하는 수치를 넘습니다.', // Custom validation lines 'custom' => [ 'password-confirm' => [ - 'required_with' => '비밀번호 확인이 필요합니다.', + 'required_with' => '같은 비밀번호를 다시 입력하세요.', ], ], From 2eb6f178c2f5fd08e1fac8ddaf7a513b3539bea6 Mon Sep 17 00:00:00 2001 From: User Date: Mon, 21 Oct 2019 03:51:55 +0900 Subject: [PATCH 005/191] Banish .DS_Store --- .gitignore | 3 ++- resources/.DS_Store | Bin 10244 -> 0 bytes resources/lang/.DS_Store | Bin 10244 -> 0 bytes resources/lang/ko/.DS_Store | Bin 6148 -> 0 bytes 4 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 resources/.DS_Store delete mode 100644 resources/lang/.DS_Store delete mode 100644 resources/lang/ko/.DS_Store diff --git a/.gitignore b/.gitignore index e5579e4a6..fc0f10a00 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,5 @@ nbproject .project .settings/ webpack-stats.json -.phpunit.result.cache \ No newline at end of file +.phpunit.result.cache +.DS_Store \ No newline at end of file diff --git a/resources/.DS_Store b/resources/.DS_Store deleted file mode 100644 index 4e23096917d4948939d3105c7373b4b4b25cb503..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10244 zcmeHMTWl0n826vA+R9|F z@bwiw0zLvh0zLvh0zLv)2LiNbvm(@S>DN92J_0@hB?Q>_Awmz6aZgTj>3%w>a*qHc zgQRu~wdow-#zZ_B_vAE}ZYYh(PY>vYqIbkV9!~ZMb0-=1QwTJpA z9@(+78-n1M6i#1)d#f@B&iqu=m*?En@>(&c8Rymp)x3k_l z-cMx>-F8}AKgB>zuy)Q|K@jSMdBWX^F>5^GC{Et)R&x7UZwd z<4Jjbk7YWFZfZF)K+`NL$BLG%^`$ zZ|{gkVzKtlsVPwit%%*)cOWxyc=GOnZ-(vq>i92AhEBOIzlyoW|^fY0JoG zOgkwzrWGTdHxx(fGK_?NShI&5?U2J-`)n)c^tg^gI>j!*(w0?g+tzRHx-jpW23cy7<_{KhTTdC(EmdYYk*AiMBS|$kl znZ75dQO(uTiqJ|?R)l_=Cd`LeEk#Ay7W?m`m&!wLmSTdeiUWp{(hRQZkU9nVPI0in zQRB)D(k7u1qv8-ci{v05I%;_;VbwW zzJYJyd-wrTW*bakrmj_O8oo0I|(yzjyU%TT!b%(Z{HEueum$$78@{x z&A1rDxCB??jkpG*xR#i93vR%T*yFNo8}7p0*pCCa2a~8^ni!`Mj%#5tgD9 zTS(+g!!k!n$9@4puxaD5t2Q}I|5|P5}U5%3Z45%3Z45%3YX>JX^mGm5bL|1E#~ z|Nm7tZ+}8Q0zLx&90C~ZP4srtc*WCt_0R!QMCds{4=c=XnoBo?D(1rU?sYtM*mb;n sTR}SSp2D@qJ-=x#-EfL?!%6bn{D1w=fWLep<)8ok^FNXKe|Y}?9e&*Bng9R* diff --git a/resources/lang/.DS_Store b/resources/lang/.DS_Store deleted file mode 100644 index b097e45b02d92876f6f973b94a5457f979494146..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10244 zcmeI1U2GIp6vxk5sLX7^P7zr_T2~4Ip(slcL{YaNeAF)pEwn(j>~=>wvOBZx%(gY_YK|m9ug!mDk1bHw~RE$bQF{lv(M)bjuX!OAszaIQ}&~xvd-MuqRV|+mqXOfva zbN=_t@7{CI%-p*R0N7H@Bmm+7pwP}rZ9E+UHm0-voGs#7dZw6#!je=yJgZXM?^^qZ75u+6t3tlF;KXZJ?_>^y5)!{g*%|T_&}G8?g|Ato$ep! z)d7>D43A+1!U&uj0k(FJKne=k&4~`*`kmWzR$E&-Yo)24@}P70m;9ll%_X0ll^Ipb z_e=M~`HUQaKCr!j9R2@@px__Kcvez}Y%N%U-a6IGe*Ss8_PgRUV@o$DT-d>$-B$}kk z%spLYrl&@whru-h_z@a)-*fXxE$=7UW#-f!WhVEL^VzQja{8g@?cwQLIEU;qXVW2x z!?jAU{F;}Oq}$Q>7~pt0$Cs4sGH3fKi9^q`%0-(M%v`K)0(^XGq#kuhVdE*PgMO0_aUxxJ&`8tiaVPSI{j6*jV~ z)hVYx?Vfj9RRWvg;zfXq{R8>{f zUTwbos>Eg{u5aIz+q!M&-r@V6X2U^~7jK%H5YcMQw4*XaeD z%3iI;rU10}S?213&h)N6D_hK&cCS|3m&*1PvnfY!&SpD|ZMxm<==V76Y=dnToK{}3 z+aO(#WPt*_C^!5Gln$j#PJJuv>_sh2g(p0{A}(&p0>F09d_6Qh&51`OLsXZ5v% zM#kx1pR)UOGh>*WH&Fac$GFqb3u-O?u6CNKoPJuXxp2bd*d?*mDse{bVb?7?5zczj=~(B8JneQDW%h<28&zFi8iX5t#)pq z!4$4nMH7maQP*ZuX+0}U3!{q^?Pj%WKtxR#mqf2qYOzu6rVnY3+HDK-4Y8!69Z~LJ z>|0W{vnsEfglD~Ip=PaT_U24R&nSx8ken?>nfJ6I$sZW@`?~^D;7UlsO6Z~2ULLl> zPS^#H!9I8a4#LauCLD(k;6wNbK7}vgYxoAfh40`8_z`}FUl1{h)i@q6!OL+v&cK;C z2b*vqF2cpQ6qn(0T#4IhSl%e7S?$Z>b#)p` z7;&l2sEblYt6ZBsgS3dNG|nSs3?;A75(}brS{3D~@LRMv8r8;9A`A7prKDa!DJ#@u zGpWEHDfOS{-1Be%-k^Lt1!v$Z%C+w)&whhHu?lN2hEs4F)?q!)!YgntHsU{1+w#g&PT^NhwL(E{}zeEwaSOmuLW?b=zZeQM5^VSiByzmk}5L?_mr8Q z8WnPIjR1axrq1384o+Cd`$=}0dGwt!ll#c=^lM(uYPubbn+;pMpUn4nm+UgV z`N$l<=H<8(92*9_oMR$C$S!ksYj0F?lWUde`L#ffsE zsE~te zc=;Lu%7jkn^70S=;ZfnBhl~x-V a%MnqMg|_qlXFzEs9IpSv_5c5L{r?vTXwWhM diff --git a/resources/lang/ko/.DS_Store b/resources/lang/ko/.DS_Store deleted file mode 100644 index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 Date: Mon, 21 Oct 2019 04:17:52 +0900 Subject: [PATCH 006/191] Update auth.php Edit for 'Must be over 7 characters'. --- resources/lang/ko/auth.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/lang/ko/auth.php b/resources/lang/ko/auth.php index a89706a74..9701bdf70 100644 --- a/resources/lang/ko/auth.php +++ b/resources/lang/ko/auth.php @@ -21,7 +21,7 @@ return [ 'email' => '메일 주소', 'password' => '비밀번호', 'password_confirm' => '비밀번호 확인', - 'password_hint' => '네 글자를 넘어야 합니다.', + 'password_hint' => '일곱 글자를 넘어야 합니다.', 'forgot_password' => '비밀번호를 잊었나요?', 'remember_me' => '로그인 유지', 'ldap_email_hint' => '이 계정에 대한 메일 주소를 입력하세요.', @@ -74,4 +74,4 @@ return [ 'user_invite_page_text' => ':appName에 로그인할 때 입력할 비밀번호를 설정하세요.', 'user_invite_page_confirm_button' => '비밀번호 확인', 'user_invite_success' => '이제 :appName에 접근할 수 있습니다.' -]; \ No newline at end of file +]; From b8a7ef15bd8a4512ec1f3dd03ca16e362d31cdf8 Mon Sep 17 00:00:00 2001 From: Mattia Della Mina Date: Thu, 31 Oct 2019 22:04:04 +0100 Subject: [PATCH 007/191] improve italian translation --- resources/lang/it/entities.php | 6 +++--- resources/lang/it/errors.php | 10 +++++----- resources/lang/it/settings.php | 13 ++++++++++--- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/resources/lang/it/entities.php b/resources/lang/it/entities.php index 89beb9af5..4865c8877 100755 --- a/resources/lang/it/entities.php +++ b/resources/lang/it/entities.php @@ -95,7 +95,7 @@ return [ 'shelves_copy_permissions_to_books' => 'Copia Permessi ai Libri', 'shelves_copy_permissions' => 'Copia Permessi', 'shelves_copy_permissions_explain' => 'Verranno applicati tutti i permessi della libreria ai libri contenuti. Prima di attivarlo, assicurati che ogni permesso di questa libreria sia salvato.', - 'shelves_copy_permission_success' => 'Permessi della libreria copiati in :count books', + 'shelves_copy_permission_success' => 'Permessi della libreria copiati in :count libri', // Books 'book' => 'Libro', @@ -212,7 +212,7 @@ return [ 'pages_revisions_number' => '#', 'pages_revisions_numbered' => 'Revisione #:id', 'pages_revisions_numbered_changes' => 'Modifiche Revisione #:id', - 'pages_revisions_changelog' => 'Cambiamenti', + 'pages_revisions_changelog' => 'Changelog', 'pages_revisions_changes' => 'Cambiamenti', 'pages_revisions_current' => 'Versione Corrente', 'pages_revisions_preview' => 'Anteprima', @@ -258,7 +258,7 @@ return [ 'attachments_delete_confirm' => 'Clicca elimina nuovamente per confermare l\'eliminazione di questo allegato.', 'attachments_dropzone' => 'Rilascia file o clicca qui per allegare un file', 'attachments_no_files' => 'Nessun file è stato caricato', - 'attachments_explain_link' => 'Puoi allegare un link se preferisci non caricare un file. Questo può essere un link a un\'altra pagina o a un file in un cloud.', + 'attachments_explain_link' => 'Puoi allegare un link se preferisci non caricare un file. Questo può essere un link a un\'altra pagina o a un file nel cloud.', 'attachments_link_name' => 'Nome Link', 'attachment_link' => 'Link allegato', 'attachments_link_url' => 'Link al file', diff --git a/resources/lang/it/errors.php b/resources/lang/it/errors.php index 466aabcd5..a365c875e 100755 --- a/resources/lang/it/errors.php +++ b/resources/lang/it/errors.php @@ -22,7 +22,7 @@ return [ 'social_account_in_use' => 'Questo account :socialAccount è già utilizzato, prova a loggarti usando l\'opzione :socialAccount.', 'social_account_email_in_use' => 'La mail :email è già in uso. Se hai già un account puoi connettere il tuo account :socialAccount dalle impostazioni del tuo profilo.', 'social_account_existing' => 'Questo account :socialAccount è già connesso al tuo profilo.', - 'social_account_already_used_existing' => 'Questo accoutn :socialAccount è già utilizzato da un altro utente.', + 'social_account_already_used_existing' => 'Questo account :socialAccount è già utilizzato da un altro utente.', 'social_account_not_used' => 'Questo account :socialAccount non è collegato a nessun utente. Collegalo nelle impostazioni del profilo. ', 'social_account_register_instructions' => 'Se non hai ancora un account, puoi registrarti usando l\'opzione :socialAccount.', 'social_driver_not_found' => 'Driver social non trovato', @@ -30,14 +30,14 @@ return [ 'invite_token_expired' => 'Il link di invito è scaduto. Puoi provare a resettare la password del tuo account.', // System - 'path_not_writable' => 'La path :filePath non può essere scritta. Controlla che abbia i permessi corretti.', + 'path_not_writable' => 'Il percorso :filePath non è scrivibile. Controlla che abbia i permessi corretti.', 'cannot_get_image_from_url' => 'Impossibile scaricare immagine da :url', 'cannot_create_thumbs' => 'Il server non può creare thumbnail. Controlla che l\'estensione GD sia installata.', 'server_upload_limit' => 'Il server non permette un upload di questa grandezza. Prova con un file più piccolo.', 'uploaded' => 'Il server non consente upload di questa grandezza. Prova un file più piccolo.', 'image_upload_error' => 'C\'è stato un errore caricando l\'immagine', - 'image_upload_type_error' => 'Il tipo di immagine in upload non è valido', - 'file_upload_timeout' => 'Il caricamento del file è scaduto.', + 'image_upload_type_error' => 'Il tipo di immagine caricata non è valido', + 'file_upload_timeout' => 'Il caricamento del file è andato in timeout.', // Attachments 'attachment_page_mismatch' => 'La pagina non è corrisposta durante l\'aggiornamento dell\'allegato', @@ -58,7 +58,7 @@ return [ 'guests_cannot_save_drafts' => 'Gli ospiti non possono salvare bozze', // Users - 'users_cannot_delete_only_admin' => 'Non puoi eliminare l\'unico adin', + 'users_cannot_delete_only_admin' => 'Non puoi eliminare l\'unico admin', 'users_cannot_delete_guest' => 'Non puoi eliminare l\'utente ospite', // Roles diff --git a/resources/lang/it/settings.php b/resources/lang/it/settings.php index fe3127965..90d5c89ea 100755 --- a/resources/lang/it/settings.php +++ b/resources/lang/it/settings.php @@ -45,7 +45,7 @@ return [ 'reg_settings' => 'Impostazioni Registrazione', 'reg_enable' => 'Abilita Registrazione', 'reg_enable_toggle' => 'Abilita registrazione', - 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', + 'reg_enable_desc' => 'Quando la registrazione è abilitata, l\utente sarà in grado di registrarsi all\'applicazione. Al momento della registrazione gli verrà associato un ruolo utente predefinito.', 'reg_default_role' => 'Ruolo predefinito dopo la registrazione', 'reg_email_confirmation' => 'Conferma Email', 'reg_email_confirmation_toggle' => 'Richiedi conferma email', @@ -57,12 +57,19 @@ return [ // Maintenance settings 'maint' => 'Manutenzione', 'maint_image_cleanup' => 'Pulizia Immagini', - 'maint_image_cleanup_desc' => "Scans page & revision content to check which images and drawings are currently in use and which images are redundant. Ensure you create a full database and image backup before running this.", + 'maint_image_cleanup_desc' => "Esegue la scansione del contenuto delle pagine e delle revisioni per verificare quali immagini e disegni sono attualmente in uso e quali immagini sono ridondanti. Assicurati di creare backup completo del database e delle immagini prima di eseguire la pulizia.", 'maint_image_cleanup_ignore_revisions' => 'Ignora le immagini nelle revisioni', 'maint_image_cleanup_run' => 'Esegui Pulizia', 'maint_image_cleanup_warning' => ':count immagini potenzialmente inutilizzate sono state trovate. Sei sicuro di voler eliminare queste immagini?', 'maint_image_cleanup_success' => ':count immagini potenzialmente inutilizzate trovate e eliminate!', - 'maint_image_cleanup_nothing_found' => 'No unused images found, Nothing deleted!', + 'maint_image_cleanup_nothing_found' => 'Nessuna immagine non utilizzata trovata, Nulla è stato cancellato!', + 'maint_send_test_email' => 'Invia un Email di Test', + 'maint_send_test_email_desc' => 'Questo invia un\'email di prova al tuo indirizzo email specificato nel tuo profilo.', + 'maint_send_test_email_run' => 'Invia email di test', + 'maint_send_test_email_success' => 'Email inviata a :address', + 'maint_send_test_email_mail_subject' => 'Email di Test', + 'maint_send_test_email_mail_greeting' => 'L\'invio delle email sembra funzionare!', + 'maint_send_test_email_mail_text' => 'Congratulazioni! Siccome hai ricevuto questa notifica email, le tue impostazioni sembrano essere configurate correttamente.', // Role Settings 'roles' => 'Ruoli', From ffd05f1584f55665dd0b54ed6376e8d21b38be7e Mon Sep 17 00:00:00 2001 From: User Date: Thu, 7 Nov 2019 15:19:15 +0900 Subject: [PATCH 008/191] Update some terms --- resources/lang/ko/activities.php | 30 ++++----- resources/lang/ko/components.php | 2 +- resources/lang/ko/entities.php | 104 +++++++++++++++---------------- resources/lang/ko/errors.php | 8 +-- resources/lang/ko/settings.php | 2 +- 5 files changed, 73 insertions(+), 73 deletions(-) diff --git a/resources/lang/ko/activities.php b/resources/lang/ko/activities.php index e75954ba7..c3fedeb45 100644 --- a/resources/lang/ko/activities.php +++ b/resources/lang/ko/activities.php @@ -17,23 +17,23 @@ return [ 'page_move' => '문서 옮기기', // Chapters - 'chapter_create' => '장절 만들기', - 'chapter_create_notification' => '장절 만듦', - 'chapter_update' => '장절 바꾸기', - 'chapter_update_notification' => '장절 바꿈', - 'chapter_delete' => '장절 지우기', - 'chapter_delete_notification' => '장절 지움', - 'chapter_move' => '장절 옮기기', + 'chapter_create' => '챕터 만들기', + 'chapter_create_notification' => '챕터 만듦', + 'chapter_update' => '챕터 바꾸기', + 'chapter_update_notification' => '챕터 바꿈', + 'chapter_delete' => '챕터 지우기', + 'chapter_delete_notification' => '챕터 지움', + 'chapter_move' => '챕터 옮기기', // Books - 'book_create' => '서적 만들기', - 'book_create_notification' => '서적 만듦', - 'book_update' => '서적 바꾸기', - 'book_update_notification' => '서적 바꿈', - 'book_delete' => '서적 지우기', - 'book_delete_notification' => '서적 지움', - 'book_sort' => '서적 정렬', - 'book_sort_notification' => '서적 정렬함', + 'book_create' => '책자 만들기', + 'book_create_notification' => '책자 만듦', + 'book_update' => '책자 바꾸기', + 'book_update_notification' => '책자 바꿈', + 'book_delete' => '책자 지우기', + 'book_delete_notification' => '책자 지움', + 'book_sort' => '책자 정렬', + 'book_sort_notification' => '책자 정렬함', // Bookshelves 'bookshelf_create' => '서가 만들기', diff --git a/resources/lang/ko/components.php b/resources/lang/ko/components.php index 101ac3c51..397d0d187 100644 --- a/resources/lang/ko/components.php +++ b/resources/lang/ko/components.php @@ -8,7 +8,7 @@ return [ 'image_select' => '이미지 선택', 'image_all' => '모든 이미지', 'image_all_title' => '모든 이미지', - 'image_book_title' => '이 서적에서 쓰고 있는 이미지', + 'image_book_title' => '이 책자에서 쓰고 있는 이미지', 'image_page_title' => '이 문서에서 쓰고 있는 이미지', 'image_search_hint' => '이미지 이름 검색', 'image_uploaded' => '올림 :uploadedDate', diff --git a/resources/lang/ko/entities.php b/resources/lang/ko/entities.php index 48b5d74bd..f224346b1 100644 --- a/resources/lang/ko/entities.php +++ b/resources/lang/ko/entities.php @@ -9,8 +9,8 @@ return [ 'recently_created' => '최근에 수정함', 'recently_created_pages' => '최근에 만든 문서', 'recently_updated_pages' => '최근에 수정한 문서', - 'recently_created_chapters' => '최근에 만든 장절', - 'recently_created_books' => '최근에 만든 서적', + 'recently_created_chapters' => '최근에 만든 챕터', + 'recently_created_books' => '최근에 만든 책자', 'recently_created_shelves' => '최근에 만든 서가', 'recently_update' => '최근에 수정함', 'recently_viewed' => '최근에 읽음', @@ -78,86 +78,86 @@ return [ 'shelves_popular_empty' => '많이 읽은 서가 목록', 'shelves_new_empty' => '새로운 서가 목록', 'shelves_save' => '저장', - 'shelves_books' => '이 서가에 있는 서적들', - 'shelves_add_books' => '이 서가에 서적 추가', - 'shelves_drag_books' => '여기에 서적을 드롭하세요.', - 'shelves_empty_contents' => '이 서가에 서적이 없습니다.', - 'shelves_edit_and_assign' => '서가 바꾸기로 서적을 추가하세요.', + 'shelves_books' => '이 서가에 있는 책자들', + 'shelves_add_books' => '이 서가에 책자 추가', + 'shelves_drag_books' => '여기에 책자을 드롭하세요.', + 'shelves_empty_contents' => '이 서가에 책자이 없습니다.', + 'shelves_edit_and_assign' => '서가 바꾸기로 책자을 추가하세요.', 'shelves_edit_named' => ':name 바꾸기', 'shelves_edit' => '서가 바꾸기', 'shelves_delete' => '서가 지우기', 'shelves_delete_named' => ':name 지우기', - 'shelves_delete_explain' => ':name을 지웁니다. 서적은 지우지 않습니다.', + 'shelves_delete_explain' => ':name을 지웁니다. 책자은 지우지 않습니다.', 'shelves_delete_confirmation' => '이 서가를 지울 건가요?', 'shelves_permissions' => '서가 권한', 'shelves_permissions_updated' => '서가 권한 바꿈', 'shelves_permissions_active' => '서가 권한 허용함', 'shelves_copy_permissions_to_books' => '권한 맞춤', 'shelves_copy_permissions' => '실행', - 'shelves_copy_permissions_explain' => '서가의 모든 서적에 이 권한을 적용합니다. 서가의 권한을 저장했는지 확인하세요.', - 'shelves_copy_permission_success' => '서적 :count개 권한 바꿈', + 'shelves_copy_permissions_explain' => '서가의 모든 책자에 이 권한을 적용합니다. 서가의 권한을 저장했는지 확인하세요.', + 'shelves_copy_permission_success' => '책자 :count개 권한 바꿈', // Books 'book' => '서고', 'books' => '서고', - 'x_books' => '서적 :count개|총 :count개', - 'books_empty' => '만든 서적이 없습니다.', - 'books_popular' => '많이 읽은 서적', - 'books_recent' => '최근에 읽은 서적', - 'books_new' => '새로운 서적', - 'books_new_action' => '새로운 서적', - 'books_popular_empty' => '많이 읽은 서적 목록', - 'books_new_empty' => '새로운 서적 목록', - 'books_create' => '서적 만들기', - 'books_delete' => '서적 지우기', + 'x_books' => '책자 :count개|총 :count개', + 'books_empty' => '만든 책자이 없습니다.', + 'books_popular' => '많이 읽은 책자', + 'books_recent' => '최근에 읽은 책자', + 'books_new' => '새로운 책자', + 'books_new_action' => '새로운 책자', + 'books_popular_empty' => '많이 읽은 책자 목록', + 'books_new_empty' => '새로운 책자 목록', + 'books_create' => '책자 만들기', + 'books_delete' => '책자 지우기', 'books_delete_named' => ':bookName(을)를 지웁니다.', - 'books_delete_explain' => ':bookName에 있는 모든 장절과 문서도 지웁니다.', - 'books_delete_confirmation' => '이 서적을 지울 건가요?', - 'books_edit' => '서적 바꾸기', + 'books_delete_explain' => ':bookName에 있는 모든 챕터과 문서도 지웁니다.', + 'books_delete_confirmation' => '이 책자을 지울 건가요?', + 'books_edit' => '책자 바꾸기', 'books_edit_named' => ':bookName(을)를 바꿉니다.', - 'books_form_book_name' => '서적 이름', + 'books_form_book_name' => '책자 이름', 'books_save' => '저장', - 'books_permissions' => '서적 권한', + 'books_permissions' => '책자 권한', 'books_permissions_updated' => '권한 저장함', - 'books_empty_contents' => '이 서적에 장절이나 문서가 없습니다.', + 'books_empty_contents' => '이 책자에 챕터이나 문서가 없습니다.', 'books_empty_create_page' => '문서 만들기', - 'books_empty_sort_current_book' => '읽고 있는 서적 정렬', - 'books_empty_add_chapter' => '장절 만들기', - 'books_permissions_active' => '서적 권한 허용함', - 'books_search_this' => '이 서적에서 검색', + 'books_empty_sort_current_book' => '읽고 있는 책자 정렬', + 'books_empty_add_chapter' => '챕터 만들기', + 'books_permissions_active' => '책자 권한 허용함', + 'books_search_this' => '이 책자에서 검색', 'books_navigation' => '목차', - 'books_sort' => '다른 서적들', + 'books_sort' => '다른 책자들', 'books_sort_named' => ':bookName 정렬', 'books_sort_name' => '제목', 'books_sort_created' => '만든 날짜', 'books_sort_updated' => '수정한 날짜', - 'books_sort_chapters_first' => '장절 우선', + 'books_sort_chapters_first' => '챕터 우선', 'books_sort_chapters_last' => '문서 우선', - 'books_sort_show_other' => '다른 서적들', + 'books_sort_show_other' => '다른 책자들', 'books_sort_save' => '적용', // Chapters - 'chapter' => '장절', - 'chapters' => '장절', - 'x_chapters' => '장절 :count개|총 :count개', - 'chapters_popular' => '많이 읽은 장절', - 'chapters_new' => '새로운 장절', - 'chapters_create' => '장절 만들기', - 'chapters_delete' => '장절 지우기', + 'chapter' => '챕터', + 'chapters' => '챕터', + 'x_chapters' => '챕터 :count개|총 :count개', + 'chapters_popular' => '많이 읽은 챕터', + 'chapters_new' => '새로운 챕터', + 'chapters_create' => '챕터 만들기', + 'chapters_delete' => '챕터 지우기', 'chapters_delete_named' => ':chapterName(을)를 지웁니다.', - 'chapters_delete_explain' => ':chapterName에 있는 모든 문서는 장절에서 벗어날 뿐 지우지 않습니다.', - 'chapters_delete_confirm' => '이 장절을 지울 건가요?', - 'chapters_edit' => '장절 바꾸기', + 'chapters_delete_explain' => ':chapterName에 있는 모든 문서는 챕터에서 벗어날 뿐 지우지 않습니다.', + 'chapters_delete_confirm' => '이 챕터을 지울 건가요?', + 'chapters_edit' => '챕터 바꾸기', 'chapters_edit_named' => ':chapterName 바꾸기', 'chapters_save' => '저장', - 'chapters_move' => '장절 옮기기', + 'chapters_move' => '챕터 옮기기', 'chapters_move_named' => ':chapterName 옮기기', 'chapter_move_success' => ':bookName(으)로 옮김', - 'chapters_permissions' => '장절 권한', - 'chapters_empty' => '이 장절에 문서가 없습니다.', + 'chapters_permissions' => '챕터 권한', + 'chapters_empty' => '이 챕터에 문서가 없습니다.', 'chapters_permissions_active' => '문서 권한 허용함', 'chapters_permissions_success' => '권한 저장함', - 'chapters_search_this' => '이 장절에서 검색', + 'chapters_search_this' => '이 챕터에서 검색', // Pages 'page' => '문서', @@ -195,7 +195,7 @@ return [ 'pages_md_insert_image' => '이미지 추가', 'pages_md_insert_link' => '내부 링크', 'pages_md_insert_drawing' => '드로잉 추가', - 'pages_not_in_chapter' => '장절에 있는 문서가 아닙니다.', + 'pages_not_in_chapter' => '챕터에 있는 문서가 아닙니다.', 'pages_move' => '문서 옮기기', 'pages_move_success' => ':parentName(으)로 옮김', 'pages_copy' => '문서 복제', @@ -238,8 +238,8 @@ return [ // Editor Sidebar 'page_tags' => '문서 꼬리표', - 'chapter_tags' => '장절 꼬리표', - 'book_tags' => '서적 꼬리표', + 'chapter_tags' => '챕터 꼬리표', + 'book_tags' => '책자 꼬리표', 'shelf_tags' => '서가 꼬리표', 'tag' => '꼬리표', 'tags' => '꼬리표', @@ -284,8 +284,8 @@ return [ 'profile_user_for_x' => ':time 전에 가입함', 'profile_created_content' => '활동한 이력', 'profile_not_created_pages' => ':userName(이)가 만든 문서 없음', - 'profile_not_created_chapters' => ':userName(이)가 만든 장절 없음', - 'profile_not_created_books' => ':userName(이)가 만든 서적 없음', + 'profile_not_created_chapters' => ':userName(이)가 만든 챕터 없음', + 'profile_not_created_books' => ':userName(이)가 만든 책자 없음', 'profile_not_created_shelves' => ':userName(이)가 만든 서가 없음', // Comments diff --git a/resources/lang/ko/errors.php b/resources/lang/ko/errors.php index 2f0352f9c..39289d001 100644 --- a/resources/lang/ko/errors.php +++ b/resources/lang/ko/errors.php @@ -50,11 +50,11 @@ return [ // Entities 'entity_not_found' => '항목이 없습니다.', 'bookshelf_not_found' => '서가가 없습니다.', - 'book_not_found' => '서적이 없습니다.', + 'book_not_found' => '책자이 없습니다.', 'page_not_found' => '문서가 없습니다.', - 'chapter_not_found' => '장절이 없습니다.', - 'selected_book_not_found' => '고른 서적이 없습니다.', - 'selected_book_chapter_not_found' => '고른 서적이나 장절이 없습니다.', + 'chapter_not_found' => '챕터이 없습니다.', + 'selected_book_not_found' => '고른 책자이 없습니다.', + 'selected_book_chapter_not_found' => '고른 책자이나 챕터이 없습니다.', 'guests_cannot_save_drafts' => 'Guest는 쓰다 만 문서를 보관할 수 없습니다.', // Users diff --git a/resources/lang/ko/settings.php b/resources/lang/ko/settings.php index a212dded0..712902b66 100755 --- a/resources/lang/ko/settings.php +++ b/resources/lang/ko/settings.php @@ -88,7 +88,7 @@ return [ 'role_manage_page_templates' => '템플릿 관리', 'role_manage_settings' => '사이트 설정 관리', 'role_asset' => '권한 항목', - 'role_asset_desc' => '서적, 장절, 문서별 권한은 이 설정에 우선합니다.', + 'role_asset_desc' => '책자, 챕터, 문서별 권한은 이 설정에 우선합니다.', 'role_asset_admins' => 'Admin 권한은 어디든 접근할 수 있지만 이 설정은 사용자 인터페이스에서 해당 활동을 표시할지 결정합니다.', 'role_all' => '모든 항목', 'role_own' => '직접 만든 항목', From 7c7098b601f15cda00e5aa28b8b084309a536a7e Mon Sep 17 00:00:00 2001 From: User Date: Thu, 7 Nov 2019 16:54:38 +0900 Subject: [PATCH 009/191] Update some postpositional particles --- resources/lang/ko/entities.php | 18 +++++++++--------- resources/lang/ko/errors.php | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/resources/lang/ko/entities.php b/resources/lang/ko/entities.php index f224346b1..4d5e1bc83 100644 --- a/resources/lang/ko/entities.php +++ b/resources/lang/ko/entities.php @@ -80,14 +80,14 @@ return [ 'shelves_save' => '저장', 'shelves_books' => '이 서가에 있는 책자들', 'shelves_add_books' => '이 서가에 책자 추가', - 'shelves_drag_books' => '여기에 책자을 드롭하세요.', - 'shelves_empty_contents' => '이 서가에 책자이 없습니다.', - 'shelves_edit_and_assign' => '서가 바꾸기로 책자을 추가하세요.', + 'shelves_drag_books' => '여기에 책자를 드롭하세요.', + 'shelves_empty_contents' => '이 서가에 책자가 없습니다.', + 'shelves_edit_and_assign' => '서가 바꾸기로 책자를 추가하세요.', 'shelves_edit_named' => ':name 바꾸기', 'shelves_edit' => '서가 바꾸기', 'shelves_delete' => '서가 지우기', 'shelves_delete_named' => ':name 지우기', - 'shelves_delete_explain' => ':name을 지웁니다. 책자은 지우지 않습니다.', + 'shelves_delete_explain' => ':name을 지웁니다. 책자는 지우지 않습니다.', 'shelves_delete_confirmation' => '이 서가를 지울 건가요?', 'shelves_permissions' => '서가 권한', 'shelves_permissions_updated' => '서가 권한 바꿈', @@ -101,7 +101,7 @@ return [ 'book' => '서고', 'books' => '서고', 'x_books' => '책자 :count개|총 :count개', - 'books_empty' => '만든 책자이 없습니다.', + 'books_empty' => '만든 책자가 없습니다.', 'books_popular' => '많이 읽은 책자', 'books_recent' => '최근에 읽은 책자', 'books_new' => '새로운 책자', @@ -111,15 +111,15 @@ return [ 'books_create' => '책자 만들기', 'books_delete' => '책자 지우기', 'books_delete_named' => ':bookName(을)를 지웁니다.', - 'books_delete_explain' => ':bookName에 있는 모든 챕터과 문서도 지웁니다.', - 'books_delete_confirmation' => '이 책자을 지울 건가요?', + 'books_delete_explain' => ':bookName에 있는 모든 챕터와 문서도 지웁니다.', + 'books_delete_confirmation' => '이 책자를 지울 건가요?', 'books_edit' => '책자 바꾸기', 'books_edit_named' => ':bookName(을)를 바꿉니다.', 'books_form_book_name' => '책자 이름', 'books_save' => '저장', 'books_permissions' => '책자 권한', 'books_permissions_updated' => '권한 저장함', - 'books_empty_contents' => '이 책자에 챕터이나 문서가 없습니다.', + 'books_empty_contents' => '이 책자에 챕터나 문서가 없습니다.', 'books_empty_create_page' => '문서 만들기', 'books_empty_sort_current_book' => '읽고 있는 책자 정렬', 'books_empty_add_chapter' => '챕터 만들기', @@ -146,7 +146,7 @@ return [ 'chapters_delete' => '챕터 지우기', 'chapters_delete_named' => ':chapterName(을)를 지웁니다.', 'chapters_delete_explain' => ':chapterName에 있는 모든 문서는 챕터에서 벗어날 뿐 지우지 않습니다.', - 'chapters_delete_confirm' => '이 챕터을 지울 건가요?', + 'chapters_delete_confirm' => '이 챕터를 지울 건가요?', 'chapters_edit' => '챕터 바꾸기', 'chapters_edit_named' => ':chapterName 바꾸기', 'chapters_save' => '저장', diff --git a/resources/lang/ko/errors.php b/resources/lang/ko/errors.php index 39289d001..5982a09da 100644 --- a/resources/lang/ko/errors.php +++ b/resources/lang/ko/errors.php @@ -50,11 +50,11 @@ return [ // Entities 'entity_not_found' => '항목이 없습니다.', 'bookshelf_not_found' => '서가가 없습니다.', - 'book_not_found' => '책자이 없습니다.', + 'book_not_found' => '책자가 없습니다.', 'page_not_found' => '문서가 없습니다.', - 'chapter_not_found' => '챕터이 없습니다.', - 'selected_book_not_found' => '고른 책자이 없습니다.', - 'selected_book_chapter_not_found' => '고른 책자이나 챕터이 없습니다.', + 'chapter_not_found' => '챕터가 없습니다.', + 'selected_book_not_found' => '고른 책자가 없습니다.', + 'selected_book_chapter_not_found' => '고른 책자나 챕터가 없습니다.', 'guests_cannot_save_drafts' => 'Guest는 쓰다 만 문서를 보관할 수 없습니다.', // Users From 23a716a3ac82acb33c40d4f9d0ff233a2b7bb687 Mon Sep 17 00:00:00 2001 From: abublihi Date: Wed, 20 Nov 2019 14:00:20 +0300 Subject: [PATCH 010/191] Fix "Declaration of Middleware\TrustProxies::handle should be compatible with Fideloper\Proxy\TrustProxies::handle" --- app/Http/Middleware/TrustProxies.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Middleware/TrustProxies.php b/app/Http/Middleware/TrustProxies.php index 878c2f164..7b01d0aab 100644 --- a/app/Http/Middleware/TrustProxies.php +++ b/app/Http/Middleware/TrustProxies.php @@ -28,7 +28,7 @@ class TrustProxies extends Middleware * @param Closure $next * @return mixed */ - public function handle($request, Closure $next) + public function handle(Request $request, Closure $next) { $setProxies = config('app.proxies'); if ($setProxies !== '**' && $setProxies !== '*' && $setProxies !== '') { From 9bed57e40eccf6a0b0ae325007d4cb365a7893fb Mon Sep 17 00:00:00 2001 From: qianmengnet Date: Fri, 22 Nov 2019 16:35:47 +0800 Subject: [PATCH 011/191] Modify Chinese language pack Modify Chinese language pack --- resources/lang/zh_CN/auth.php | 22 +++++------ resources/lang/zh_CN/common.php | 28 +++++++------- resources/lang/zh_CN/entities.php | 44 ++++++++++----------- resources/lang/zh_CN/errors.php | 6 +-- resources/lang/zh_CN/settings.php | 60 ++++++++++++++--------------- resources/lang/zh_CN/validation.php | 46 +++++++++++----------- 6 files changed, 103 insertions(+), 103 deletions(-) diff --git a/resources/lang/zh_CN/auth.php b/resources/lang/zh_CN/auth.php index 62cd0c243..0eec01508 100644 --- a/resources/lang/zh_CN/auth.php +++ b/resources/lang/zh_CN/auth.php @@ -26,11 +26,11 @@ return [ 'remember_me' => '记住我', 'ldap_email_hint' => '请输入用于此帐户的电子邮件。', 'create_account' => '创建账户', - 'already_have_account' => 'Already have an account?', - 'dont_have_account' => 'Don\'t have an account?', + 'already_have_account' => '您已经有账号?', + 'dont_have_account' => '您还没注册?', 'social_login' => 'SNS登录', 'social_registration' => 'SNS注册', - 'social_registration_text' => '其他服务注册/登录.', + 'social_registration_text' => '其他服务注册/登录。', 'register_thanks' => '注册完成!', 'register_confirm' => '请点击查收您的Email,并点击确认。', @@ -66,12 +66,12 @@ return [ 'email_not_confirmed_resend_button' => '重新发送确认Email', // User Invite - 'user_invite_email_subject' => 'You have been invited to join :appName!', - 'user_invite_email_greeting' => 'An account has been created for you on :appName.', - 'user_invite_email_text' => 'Click the button below to set an account password and gain access:', - 'user_invite_email_action' => 'Set Account Password', - 'user_invite_page_welcome' => 'Welcome to :appName!', - 'user_invite_page_text' => 'To finalise your account and gain access you need to set a password which will be used to log-in to :appName on future visits.', - 'user_invite_page_confirm_button' => 'Confirm Password', - 'user_invite_success' => 'Password set, you now have access to :appName!' + 'user_invite_email_subject' => '您已受邀加入 :appName!', + 'user_invite_email_greeting' => ' :appName 已为您创建了一个帐户。', + 'user_invite_email_text' => '点击下面的按钮以设置帐户密码并获得访问权限:', + 'user_invite_email_action' => '设置帐号密码', + 'user_invite_page_welcome' => '欢迎来到 :appName!', + 'user_invite_page_text' => '要完成您的帐户并获得访问权限,您需要设置一个密码,该密码将在以后访问时用于登录 :appName。', + 'user_invite_page_confirm_button' => '确认密码', + 'user_invite_success' => '已设置密码,您现在可以访问 :appName!' ]; \ No newline at end of file diff --git a/resources/lang/zh_CN/common.php b/resources/lang/zh_CN/common.php index 04a826e6f..37cb608a7 100644 --- a/resources/lang/zh_CN/common.php +++ b/resources/lang/zh_CN/common.php @@ -11,7 +11,7 @@ return [ 'save' => '保存', 'continue' => '继续', 'select' => '选择', - 'toggle_all' => 'Toggle All', + 'toggle_all' => '切换全部', 'more' => '更多', // Form Labels @@ -24,7 +24,7 @@ return [ // Actions 'actions' => '操作', 'view' => '浏览', - 'view_all' => 'View All', + 'view_all' => '查看全部', 'create' => '创建', 'update' => '更新', 'edit' => '编辑', @@ -40,13 +40,13 @@ return [ 'add' => '添加', // Sort Options - 'sort_options' => 'Sort Options', - 'sort_direction_toggle' => 'Sort Direction Toggle', - 'sort_ascending' => 'Sort Ascending', - 'sort_descending' => 'Sort Descending', - 'sort_name' => 'Name', - 'sort_created_at' => 'Created Date', - 'sort_updated_at' => 'Updated Date', + 'sort_options' => '排序选项', + 'sort_direction_toggle' => '排序方向切换', + 'sort_ascending' => '升序', + 'sort_descending' => '降序', + 'sort_name' => '名称', + 'sort_created_at' => '创建时间', + 'sort_updated_at' => '更新时间', // Misc 'deleted_user' => '删除用户', @@ -59,18 +59,18 @@ return [ 'grid_view' => '网格视图', 'list_view' => '列表视图', 'default' => '默认', - 'breadcrumb' => 'Breadcrumb', + 'breadcrumb' => '面包屑导航', // Header - 'profile_menu' => 'Profile Menu', + 'profile_menu' => '个人资料', 'view_profile' => '查看资料', 'edit_profile' => '编辑资料', // Layout tabs - 'tab_info' => 'Info', - 'tab_content' => 'Content', + 'tab_info' => '信息', + 'tab_content' => '内容', // Email Content 'email_action_help' => '如果您无法点击“:actionText”按钮,请将下面的网址复制到您的浏览器中打开:', - 'email_rights' => 'All rights reserved', + 'email_rights' => '版权所有', ]; diff --git a/resources/lang/zh_CN/entities.php b/resources/lang/zh_CN/entities.php index 04e8e25bc..3efcef6a3 100644 --- a/resources/lang/zh_CN/entities.php +++ b/resources/lang/zh_CN/entities.php @@ -8,10 +8,10 @@ return [ // Shared 'recently_created' => '最近创建', 'recently_created_pages' => '最近创建的页面', - 'recently_updated_pages' => '最新页面', + 'recently_updated_pages' => '最近更新的页面', 'recently_created_chapters' => '最近创建的章节', 'recently_created_books' => '最近创建的图书', - 'recently_created_shelves' => 'Recently Created Shelves', + 'recently_created_shelves' => '最近创建的书架', 'recently_update' => '最近更新', 'recently_viewed' => '最近查看', 'recent_activity' => '近期活动', @@ -68,13 +68,13 @@ return [ // Shelves 'shelf' => '书架', 'shelves' => '书架', - 'x_shelves' => ':count Shelf|:count Shelves', + 'x_shelves' => ':count 书架|:count 书架', 'shelves_long' => '书架', 'shelves_empty' => '当前未创建书架', 'shelves_create' => '创建新书架', 'shelves_popular' => '热门书架', 'shelves_new' => '新书架', - 'shelves_new_action' => 'New Shelf', + 'shelves_new_action' => '新书架', 'shelves_popular_empty' => '最热门的书架', 'shelves_new_empty' => '最新创建的书架', 'shelves_save' => '保存书架', @@ -105,7 +105,7 @@ return [ 'books_popular' => '热门图书', 'books_recent' => '最近的书', 'books_new' => '新书', - 'books_new_action' => 'New Book', + 'books_new_action' => '新书', 'books_popular_empty' => '最受欢迎的图书将出现在这里。', 'books_new_empty' => '最近创建的图书将出现在这里。', 'books_create' => '创建图书', @@ -128,11 +128,11 @@ return [ 'books_navigation' => '图书导航', 'books_sort' => '排序图书内容', 'books_sort_named' => '排序图书「:bookName」', - 'books_sort_name' => 'Sort by Name', - 'books_sort_created' => 'Sort by Created Date', - 'books_sort_updated' => 'Sort by Updated Date', - 'books_sort_chapters_first' => 'Chapters First', - 'books_sort_chapters_last' => 'Chapters Last', + 'books_sort_name' => '按名称排序', + 'books_sort_created' => '创建时间排序', + 'books_sort_updated' => '按更新时间排序', + 'books_sort_chapters_first' => '章节正序', + 'books_sort_chapters_last' => '章节倒序', 'books_sort_show_other' => '显示其他图书', 'books_sort_save' => '保存新顺序', @@ -210,8 +210,8 @@ return [ 'pages_revisions_created_by' => '创建者', 'pages_revisions_date' => '修订日期', 'pages_revisions_number' => '#', - 'pages_revisions_numbered' => 'Revision #:id', - 'pages_revisions_numbered_changes' => 'Revision #:id Changes', + 'pages_revisions_numbered' => '修订 #:id', + 'pages_revisions_numbered_changes' => '修改 #:id ', 'pages_revisions_changelog' => '更新说明', 'pages_revisions_changes' => '说明', 'pages_revisions_current' => '当前版本', @@ -234,7 +234,7 @@ return [ ], 'pages_draft_discarded' => '草稿已丢弃,编辑器已更新到当前页面内容。', 'pages_specific' => '具体页面', - 'pages_is_template' => 'Page Template', + 'pages_is_template' => '页面模板', // Editor Sidebar 'page_tags' => '页面标签', @@ -243,14 +243,14 @@ return [ 'shelf_tags' => '书架标签', 'tag' => '标签', 'tags' => '标签', - 'tag_name' => 'Tag Name', + 'tag_name' => '标签名称', 'tag_value' => '标签值 (Optional)', 'tags_explain' => "添加一些标签以更好地对您的内容进行分类。\n您可以为标签分配一个值,以进行更深入的组织。", 'tags_add' => '添加另一个标签', 'tags_remove' => 'Remove this tag', 'attachments' => '附件', 'attachments_explain' => '上传一些文件或附加一些链接显示在您的网页上。这些在页面的侧边栏中可见。', - 'attachments_explain_instant_save' => '这里的更改将立即保存。Changes here are saved instantly.', + 'attachments_explain_instant_save' => '这里的更改将立即保存。', 'attachments_items' => '附加项目', 'attachments_upload' => '上传文件', 'attachments_link' => '附加链接', @@ -273,12 +273,12 @@ return [ 'attachments_file_uploaded' => '附件上传成功', 'attachments_file_updated' => '附件更新成功', 'attachments_link_attached' => '链接成功附加到页面', - 'templates' => 'Templates', - 'templates_set_as_template' => 'Page is a template', - 'templates_explain_set_as_template' => 'You can set this page as a template so its contents be utilized when creating other pages. Other users will be able to use this template if they have view permissions for this page.', - 'templates_replace_content' => 'Replace page content', - 'templates_append_content' => 'Append to page content', - 'templates_prepend_content' => 'Prepend to page content', + 'templates' => '模板', + 'templates_set_as_template' => '设置为模板', + 'templates_explain_set_as_template' => '您可以将此页面设置为模板,以便在创建其他页面时利用其内容。 如果其他用户对此页面具有查看权限,则将可以使用此模板。', + 'templates_replace_content' => '替换页面内容', + 'templates_append_content' => '附加到页面内容', + 'templates_prepend_content' => '追加到页面内容', // Profile View 'profile_user_for_x' => '来这里:time了', @@ -286,7 +286,7 @@ return [ 'profile_not_created_pages' => ':userName尚未创建任何页面', 'profile_not_created_chapters' => ':userName尚未创建任何章节', 'profile_not_created_books' => ':userName尚未创建任何图书', - 'profile_not_created_shelves' => ':userName has not created any shelves', + 'profile_not_created_shelves' => ':userName 尚未创建任何书架', // Comments 'comment' => '评论', diff --git a/resources/lang/zh_CN/errors.php b/resources/lang/zh_CN/errors.php index f500a58dc..7b70102dd 100644 --- a/resources/lang/zh_CN/errors.php +++ b/resources/lang/zh_CN/errors.php @@ -27,14 +27,14 @@ return [ 'social_account_register_instructions' => '如果您还没有帐户,您可以使用 :socialAccount 选项注册账户。', 'social_driver_not_found' => '未找到社交驱动程序', 'social_driver_not_configured' => '您的:socialAccount社交设置不正确。', - 'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.', + 'invite_token_expired' => '此邀请链接已过期。 您可以尝试重置您的帐户密码。', // System 'path_not_writable' => '无法上传到文件路径“:filePath”,请确保它可写入服务器。', 'cannot_get_image_from_url' => '无法从 :url 中获取图片', 'cannot_create_thumbs' => '服务器无法创建缩略图,请检查您是否安装了GD PHP扩展。', 'server_upload_limit' => '服务器不允许上传此大小的文件。 请尝试较小的文件。', - 'uploaded' => 'The server does not allow uploads of this size. Please try a smaller file size.', + 'uploaded' => '服务器不允许上传此大小的文件。 请尝试较小的文件。', 'image_upload_error' => '上传图片时发生错误', 'image_upload_type_error' => '上传的图像类型无效', 'file_upload_timeout' => '文件上传已超时。', @@ -65,7 +65,7 @@ return [ 'role_cannot_be_edited' => '无法编辑该角色', 'role_system_cannot_be_deleted' => '无法删除系统角色', 'role_registration_default_cannot_delete' => '无法删除设置为默认注册的角色', - 'role_cannot_remove_only_admin' => 'This user is the only user assigned to the administrator role. Assign the administrator role to another user before attempting to remove it here.', + 'role_cannot_remove_only_admin' => '该用户是分配给管理员角色的唯一用户。 在尝试在此处删除管理员角色之前,请将其分配给其他用户。', // Comments 'comment_list' => '提取评论时出现错误。', diff --git a/resources/lang/zh_CN/settings.php b/resources/lang/zh_CN/settings.php index bc489376c..40cc7c49a 100755 --- a/resources/lang/zh_CN/settings.php +++ b/resources/lang/zh_CN/settings.php @@ -12,43 +12,43 @@ return [ 'settings_save_success' => '设置已保存', // App Settings - 'app_customization' => 'Customization', - 'app_features_security' => 'Features & Security', - 'app_name' => 'App名', + 'app_customization' => '定制', + 'app_features_security' => '功能与安全', + 'app_name' => '站点名称', 'app_name_desc' => '此名称将在网页头部和Email中显示。', 'app_name_header' => '在网页头部显示应用名?', - 'app_public_access' => 'Public Access', - 'app_public_access_desc' => 'Enabling this option will allow visitors, that are not logged-in, to access content in your BookStack instance.', - 'app_public_access_desc_guest' => 'Access for public visitors can be controlled through the "Guest" user.', - 'app_public_access_toggle' => 'Allow public access', + 'app_public_access' => '访问权限', + 'app_public_access_desc' => '启用此选项将允许未登录的用户访问站点内容。', + 'app_public_access_desc_guest' => '可以通过“访客”用户来控制公共访问者的访问。', + 'app_public_access_toggle' => '允许公众访问', 'app_public_viewing' => '允许公众查看?', 'app_secure_images' => '启用更高安全性的图片上传?', - 'app_secure_images_toggle' => 'Enable higher security image uploads', + 'app_secure_images_toggle' => '启用更高安全性的图片上传', 'app_secure_images_desc' => '出于性能原因,所有图像都是公开的。这个选项会在图像的网址前添加一个随机的,难以猜测的字符串,从而使直接访问变得困难。', 'app_editor' => '页面编辑器', 'app_editor_desc' => '选择所有用户将使用哪个编辑器来编辑页面。', 'app_custom_html' => '自定义HTML头部内容', 'app_custom_html_desc' => '此处添加的任何内容都将插入到每个页面的部分的底部,这对于覆盖样式或添加分析代码很方便。', - 'app_custom_html_disabled_notice' => 'Custom HTML head content is disabled on this settings page to ensure any breaking changes can be reverted.', - 'app_logo' => 'App Logo', + 'app_custom_html_disabled_notice' => '在此设置页面上禁用了自定义HTML标题内容,以确保可以恢复所有重大更改。', + 'app_logo' => '站点Logo', 'app_logo_desc' => '这个图片的高度应该为43px。
大图片将会被缩小。', - 'app_primary_color' => 'App主色', + 'app_primary_color' => '站点主色', 'app_primary_color_desc' => '这应该是一个十六进制值。
保留为空以重置为默认颜色。', - 'app_homepage' => 'App主页', + 'app_homepage' => '站点主页', 'app_homepage_desc' => '选择要在主页上显示的页面来替换默认的视图,选定页面的访问权限将被忽略。', - 'app_homepage_select' => 'Select a page', + 'app_homepage_select' => '选择一个页面', 'app_disable_comments' => '禁用评论', - 'app_disable_comments_toggle' => 'Disable comments', - 'app_disable_comments_desc' => '在App的所有页面上禁用评论,现有评论也不会显示出来。', + 'app_disable_comments_toggle' => '禁用评论', + 'app_disable_comments_desc' => '在站点的所有页面上禁用评论,现有评论也不会显示出来。', // Registration Settings 'reg_settings' => '注册设置', - 'reg_enable' => 'Enable Registration', - 'reg_enable_toggle' => 'Enable registration', - 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', + 'reg_enable' => '启用注册', + 'reg_enable_toggle' => '启用注册', + 'reg_enable_desc' => '启用注册后,用户将可以自己注册为站点用户。 注册后,他们将获得一个默认的单一用户角色。', 'reg_default_role' => '注册后的默认用户角色', - 'reg_email_confirmation' => 'Email Confirmation', - 'reg_email_confirmation_toggle' => 'Require email confirmation', + 'reg_email_confirmation' => '邮箱确认n', + 'reg_email_confirmation_toggle' => '需要电子邮件确认', 'reg_confirm_email_desc' => '如果使用域名限制,则需要Email验证,并且该值将被忽略。', 'reg_confirm_restrict_domain' => '域名限制', 'reg_confirm_restrict_domain_desc' => '输入您想要限制注册的Email域名列表,用逗号隔开。在被允许与应用程序交互之前,用户将被发送一封Email来确认他们的地址。
注意用户在注册成功后可以修改他们的Email地址。', @@ -103,17 +103,17 @@ return [ 'user_profile' => '用户资料', 'users_add_new' => '添加用户', 'users_search' => '搜索用户', - 'users_details' => 'User Details', - 'users_details_desc' => 'Set a display name and an email address for this user. The email address will be used for logging into the application.', - 'users_details_desc_no_email' => 'Set a display name for this user so others can recognise them.', + 'users_details' => '用户详细资料', + 'users_details_desc' => '设置该用户的显示名称和电子邮件地址。 该电子邮件地址将用于登录本站。', + 'users_details_desc_no_email' => '设置此用户的昵称,以便其他人识别。', 'users_role' => '用户角色', - 'users_role_desc' => 'Select which roles this user will be assigned to. If a user is assigned to multiple roles the permissions from those roles will stack and they will receive all abilities of the assigned roles.', - 'users_password' => 'User Password', - 'users_password_desc' => 'Set a password used to log-in to the application. This must be at least 6 characters long.', - 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', - 'users_send_invite_option' => 'Send user invite email', + 'users_role_desc' => '选择将分配给该用户的角色。 如果将一个用户分配给多个角色,则这些角色的权限将堆叠在一起,并且他们将获得分配的角色的所有功能。', + 'users_password' => '用户密码', + 'users_password_desc' => '设置用于登录应用程序的密码。 该长度必须至少为6个字符。', + 'users_send_invite_text' => '您可以向该用户发送邀请电子邮件,允许他们设置自己的密码,否则,您可以自己设置他们的密码。', + 'users_send_invite_option' => '发送邀请用户电子邮件', 'users_external_auth_id' => '外部身份认证ID', - 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your LDAP system.', + 'users_external_auth_id_desc' => '与LDAP系统通信时,此ID用于匹配该用户。', 'users_password_warning' => '如果您想更改密码,请填写以下内容:', 'users_system_public' => '此用户代表访问您的App的任何访客。它不能用于登录,而是自动分配。', 'users_delete' => '删除用户', @@ -127,7 +127,7 @@ return [ 'users_avatar' => '用户头像', 'users_avatar_desc' => '当前图片应该为约256px的正方形。', 'users_preferred_language' => '语言', - 'users_preferred_language_desc' => 'This option will change the language used for the user-interface of the application. This will not affect any user-created content.', + 'users_preferred_language_desc' => '此选项将更改用于应用程序用户界面的语言。 这不会影响任何用户创建的内容。', 'users_social_accounts' => '社交账户', 'users_social_accounts_info' => '在这里,您可以绑定您的其他帐户,以便更快更轻松地登录。如果您选择解除绑定,之后将不能通过此社交账户登录,请设置社交账户来取消本App的访问权限。', 'users_social_connect' => '绑定账户', diff --git a/resources/lang/zh_CN/validation.php b/resources/lang/zh_CN/validation.php index e328f6c38..9755413fc 100644 --- a/resources/lang/zh_CN/validation.php +++ b/resources/lang/zh_CN/validation.php @@ -30,40 +30,40 @@ return [ 'digits' => ':attribute 必须为:digits位数。', 'digits_between' => ':attribute 必须为:min到:max位数。', 'email' => ':attribute 必须是有效的电子邮件地址。', - 'ends_with' => 'The :attribute must end with one of the following: :values', + 'ends_with' => ' :attribute 必须以 :values 后缀结尾', 'filled' => ':attribute 字段是必需的。', 'gt' => [ - 'numeric' => 'The :attribute must be greater than :value.', - 'file' => 'The :attribute must be greater than :value kilobytes.', - 'string' => 'The :attribute must be greater than :value characters.', - 'array' => 'The :attribute must have more than :value items.', + 'numeric' => ':attribute必须大于 :value.', + 'file' => ':attribute 必须大于 :value k', + 'string' => ':attribute 必须大于 :value 字符。', + 'array' => ':attribute 必须包含多个 :value 项目。', ], 'gte' => [ - 'numeric' => 'The :attribute must be greater than or equal :value.', - 'file' => 'The :attribute must be greater than or equal :value kilobytes.', - 'string' => 'The :attribute must be greater than or equal :value characters.', - 'array' => 'The :attribute must have :value items or more.', + 'numeric' => ':attribute 必须大于或等于 :value.', + 'file' => ':attribute 必须大于或等于 :value k。', + 'string' => ':attribute 必须大于或等于 :value 字符。', + 'array' => ':attribute 必须具有 :value 项或更多', ], 'exists' => '选中的 :attribute 无效。', 'image' => ':attribute 必须是一个图片。', - 'image_extension' => 'The :attribute must have a valid & supported image extension.', + 'image_extension' => ':attribute 必须具有有效且受支持的图像扩展名。', 'in' => '选中的 :attribute 无效。', 'integer' => ':attribute 必须是一个整数。', 'ip' => ':attribute 必须是一个有效的IP地址。', - 'ipv4' => 'The :attribute must be a valid IPv4 address.', - 'ipv6' => 'The :attribute must be a valid IPv6 address.', - 'json' => 'The :attribute must be a valid JSON string.', + 'ipv4' => ':attribute 必须是有效的IPv4地址。', + 'ipv6' => ':attribute必须是有效的IPv6地址。', + 'json' => ':attribute 必须是JSON类型.', 'lt' => [ - 'numeric' => 'The :attribute must be less than :value.', - 'file' => 'The :attribute must be less than :value kilobytes.', - 'string' => 'The :attribute must be less than :value characters.', - 'array' => 'The :attribute must have less than :value items.', + 'numeric' => ':attribute 必须小于 :value.', + 'file' => ':attribute 必须小于 :value k。', + 'string' => ':attribute 必须小于 :value 字符。', + 'array' => ':attribute 必须小于 :value 项.', ], 'lte' => [ - 'numeric' => 'The :attribute must be less than or equal :value.', - 'file' => 'The :attribute must be less than or equal :value kilobytes.', - 'string' => 'The :attribute must be less than or equal :value characters.', - 'array' => 'The :attribute must not have more than :value items.', + 'numeric' => ':attribute 必须小于或等于 :value.', + 'file' => ':attribute 必须小于或等于 :value k。', + 'string' => ':attribute 必须小于或等于 :value 字符。', + 'array' => ':attribute 不得超过 :value 项。', ], 'max' => [ 'numeric' => ':attribute 不能超过:max。', @@ -78,7 +78,7 @@ return [ 'string' => ':attribute 至少为:min个字符。', 'array' => ':attribute 至少有:min项。', ], - 'no_double_extension' => 'The :attribute must only have a single file extension.', + 'no_double_extension' => ':attribute 必须具有一个扩展名。', 'not_in' => '选中的 :attribute 无效。', 'not_regex' => 'The :attribute format is invalid.', 'numeric' => ':attribute 必须是一个数。', @@ -100,7 +100,7 @@ return [ 'timezone' => ':attribute 必须是有效的区域。', 'unique' => ':attribute 已经被使用。', 'url' => ':attribute 格式无效。', - 'uploaded' => 'The file could not be uploaded. The server may not accept files of this size.', + 'uploaded' => '无法上传文件。 服务器可能不接受此大小的文件。', // Custom validation lines 'custom' => [ From abb5cc18524ece99fa5246ed28c97104d288de7b Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 22 Nov 2019 22:23:22 +0000 Subject: [PATCH 012/191] Added a translator attriubtion file Added list of users that have provided translations along with the languages they have provided. Github users, starting with an '@', were added via manually going through past pull requests and inspecting the user and language. --- .github/translators.txt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .github/translators.txt diff --git a/.github/translators.txt b/.github/translators.txt new file mode 100644 index 000000000..b8e784123 --- /dev/null +++ b/.github/translators.txt @@ -0,0 +1,8 @@ +Name :: Languages +cipi1965 :: Italian +Mykola Ronik (Mantikor) :: Ukrainian +furkanoyk :: Turkish +m0uch0 :: Spanish +Maxim Zalata (zlatin) :: Russian; Ukrainian +nutsflag :: French +Leonardo Mario Martinez (leonardo.m.martinez) :: Spanish, Argentina From 1bcb24a92168d3e891902b2793c1f81de3cce696 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 22 Nov 2019 22:41:00 +0000 Subject: [PATCH 013/191] Added in the github translators that didn't save in the last comit --- .github/translators.txt | 46 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/.github/translators.txt b/.github/translators.txt index b8e784123..5435cfc4d 100644 --- a/.github/translators.txt +++ b/.github/translators.txt @@ -1,8 +1,52 @@ Name :: Languages +@robertlandes :: German +@SergioMendolia :: French +@NakaharaL :: Portuguese, Brazilian +@ReeseSebastian :: German +@arietimmerman :: Dutch +@diegoseso :: Spanish +@S64 :: Japanese +@JachuPL :: Polish +@Joorem :: French +@timoschwarzer :: German +@sanderdw :: Dutch +@lbguilherme :: Portuguese, Brazilian +@marcusforsberg :: Swedish +@artur-trzesiok :: Polish +@Alwaysin :: French +@msaus :: Japanese +@moucho :: Spanish +@vriic :: German +@DeehSlash :: Portuguese, Brazilian +@alex2702 :: German +@nicobubulle :: French +@kmoj86 :: Arabic +@houbaron :: Chinese Traditional; Chinese Simplified +@mullinsmikey :: Russian +@limkukhyun :: Korean +@CliffyPrime :: German +@kejjang :: Chinese Traditional +@TheLastOperator :: French +@qianmengnet :: Chinese Simplified +@ezzra :: German Informal +@vasiliev123 :: Polish +@Mant1kor :: Ukrainian +@Xiphoseer German; German Informal +@maantje :: Dutch +@cima :: Czech +@agvol :: Russian +@Hambern :: Swedish +@NootoNooto :: Dutch +@kostefun :: Russian +@lucaguindani :: French +@miles75 :: Hungarian +@danielroehrig-mm :: German +@oykenfurkan :: Turkish +@qligier :: French cipi1965 :: Italian Mykola Ronik (Mantikor) :: Ukrainian furkanoyk :: Turkish m0uch0 :: Spanish Maxim Zalata (zlatin) :: Russian; Ukrainian nutsflag :: French -Leonardo Mario Martinez (leonardo.m.martinez) :: Spanish, Argentina +Leonardo Mario Martinez (leonardo.m.martinez) :: Spanish, Argentina \ No newline at end of file From 000059f6cff43c5f5622ec88874fa360e7a34af2 Mon Sep 17 00:00:00 2001 From: Artur Skoczylas Date: Thu, 28 Nov 2019 15:39:54 +0100 Subject: [PATCH 014/191] Update polish language --- resources/lang/pl/activities.php | 16 ++--- resources/lang/pl/auth.php | 20 +++--- resources/lang/pl/common.php | 20 +++--- resources/lang/pl/entities.php | 110 +++++++++++++++---------------- resources/lang/pl/errors.php | 16 +++-- resources/lang/pl/settings.php | 55 +++++++++------- resources/lang/pl/validation.php | 46 ++++++------- 7 files changed, 148 insertions(+), 135 deletions(-) diff --git a/resources/lang/pl/activities.php b/resources/lang/pl/activities.php index 08a35c30d..f641ca232 100644 --- a/resources/lang/pl/activities.php +++ b/resources/lang/pl/activities.php @@ -26,14 +26,14 @@ return [ 'chapter_move' => 'przeniesiono rozdział', // Books - 'book_create' => 'utworzono podręcznik', - 'book_create_notification' => 'Podręcznik utworzony pomyślnie', - 'book_update' => 'zaktualizowano podręcznik', - 'book_update_notification' => 'Podręcznik zaktualizowany pomyślnie', - 'book_delete' => 'usunięto podręcznik', - 'book_delete_notification' => 'Podręcznik usunięty pomyślnie', - 'book_sort' => 'posortowano podręcznik', - 'book_sort_notification' => 'Podręcznik posortowany pomyślnie', + 'book_create' => 'utworzono książkę', + 'book_create_notification' => 'Książkę utworzony pomyślnie', + 'book_update' => 'zaktualizowano książkę', + 'book_update_notification' => 'Książkę zaktualizowany pomyślnie', + 'book_delete' => 'usunięto książkę', + 'book_delete_notification' => 'Książkę usunięty pomyślnie', + 'book_sort' => 'posortowano książkę', + 'book_sort_notification' => 'Książkę posortowany pomyślnie', // Bookshelves 'bookshelf_create' => 'utworzono półkę', diff --git a/resources/lang/pl/auth.php b/resources/lang/pl/auth.php index 1e135880e..a85159a1b 100644 --- a/resources/lang/pl/auth.php +++ b/resources/lang/pl/auth.php @@ -26,8 +26,8 @@ return [ 'remember_me' => 'Zapamiętaj mnie', 'ldap_email_hint' => 'Wprowadź adres e-mail dla tego konta.', 'create_account' => 'Utwórz konto', - 'already_have_account' => 'Already have an account?', - 'dont_have_account' => 'Don\'t have an account?', + 'already_have_account' => 'Masz już konto?', + 'dont_have_account' => 'Nie masz konta?', 'social_login' => 'Logowanie za pomocą konta społecznościowego', 'social_registration' => 'Rejestracja za pomocą konta społecznościowego', 'social_registration_text' => 'Zarejestruj się za pomocą innej usługi.', @@ -66,12 +66,12 @@ return [ 'email_not_confirmed_resend_button' => 'Wyślij ponownie wiadomość z potwierdzeniem', // User Invite - 'user_invite_email_subject' => 'You have been invited to join :appName!', - 'user_invite_email_greeting' => 'An account has been created for you on :appName.', - 'user_invite_email_text' => 'Click the button below to set an account password and gain access:', - 'user_invite_email_action' => 'Set Account Password', - 'user_invite_page_welcome' => 'Welcome to :appName!', - 'user_invite_page_text' => 'To finalise your account and gain access you need to set a password which will be used to log-in to :appName on future visits.', - 'user_invite_page_confirm_button' => 'Confirm Password', - 'user_invite_success' => 'Password set, you now have access to :appName!' + 'user_invite_email_subject' => 'Zostałeś zaproszony do :appName!', + 'user_invite_email_greeting' => 'Zostało dla Ciebie utworzone konto w :appName.', + 'user_invite_email_text' => 'Kliknij przycisk poniżej, aby ustawić hasło do konta i uzyskać do niego dostęp:', + 'user_invite_email_action' => 'Ustaw hasło do konta', + 'user_invite_page_welcome' => 'Witaj w :appName!', + 'user_invite_page_text' => 'Aby zakończyć tworzenie konta musisz ustawić hasło, które będzie używane do logowania do :appName w przyszłości.', + 'user_invite_page_confirm_button' => 'Potwierdź hasło', + 'user_invite_success' => 'Hasło zostało ustawione, teraz masz dostęp do :appName!' ]; \ No newline at end of file diff --git a/resources/lang/pl/common.php b/resources/lang/pl/common.php index d5bf0f199..664e7c4c5 100644 --- a/resources/lang/pl/common.php +++ b/resources/lang/pl/common.php @@ -11,7 +11,7 @@ return [ 'save' => 'Zapisz', 'continue' => 'Kontynuuj', 'select' => 'Wybierz', - 'toggle_all' => 'Toggle All', + 'toggle_all' => 'Przełącz wszystko', 'more' => 'Więcej', // Form Labels @@ -40,13 +40,13 @@ return [ 'add' => 'Dodaj', // Sort Options - 'sort_options' => 'Sort Options', - 'sort_direction_toggle' => 'Sort Direction Toggle', - 'sort_ascending' => 'Sort Ascending', - 'sort_descending' => 'Sort Descending', - 'sort_name' => 'Name', - 'sort_created_at' => 'Created Date', - 'sort_updated_at' => 'Updated Date', + 'sort_options' => 'Opcje sortowania', + 'sort_direction_toggle' => 'Przełącz kierunek sortowania', + 'sort_ascending' => 'Sortuj rosnąco', + 'sort_descending' => 'Sortuj malejąco', + 'sort_name' => 'Nazwa', + 'sort_created_at' => 'Data utworzenia', + 'sort_updated_at' => 'Data aktualizacji', // Misc 'deleted_user' => 'Użytkownik usunięty', @@ -67,8 +67,8 @@ return [ 'edit_profile' => 'Edytuj profil', // Layout tabs - 'tab_info' => 'Info', - 'tab_content' => 'Content', + 'tab_info' => 'Informacje', + 'tab_content' => 'Treść', // Email Content 'email_action_help' => 'Jeśli masz problem z kliknięciem przycisku ":actionText", skopiuj i wklej poniższy adres URL w nowej karcie swojej przeglądarki:', diff --git a/resources/lang/pl/entities.php b/resources/lang/pl/entities.php index a87959598..267ac69e4 100644 --- a/resources/lang/pl/entities.php +++ b/resources/lang/pl/entities.php @@ -10,8 +10,8 @@ return [ 'recently_created_pages' => 'Ostatnio utworzone strony', 'recently_updated_pages' => 'Ostatnio zaktualizowane strony', 'recently_created_chapters' => 'Ostatnio utworzone rozdziały', - 'recently_created_books' => 'Ostatnio utworzone podręczniki', - 'recently_created_shelves' => 'Recently Created Shelves', + 'recently_created_books' => 'Ostatnio utworzone książki', + 'recently_created_shelves' => 'Ostatnio utworzone półki', 'recently_update' => 'Ostatnio zaktualizowane', 'recently_viewed' => 'Ostatnio wyświetlane', 'recent_activity' => 'Ostatnia aktywność', @@ -74,66 +74,66 @@ return [ 'shelves_create' => 'Utwórz półkę', 'shelves_popular' => 'Popularne półki', 'shelves_new' => 'Nowe półki', - 'shelves_new_action' => 'New Shelf', + 'shelves_new_action' => 'Nowa półka', 'shelves_popular_empty' => 'Najpopularniejsze półki pojawią się w tym miejscu.', 'shelves_new_empty' => 'Tutaj pojawią się ostatnio utworzone półki.', 'shelves_save' => 'Zapisz półkę', - 'shelves_books' => 'Podręczniki na tej półce', - 'shelves_add_books' => 'Dodaj podręczniki do tej półki', - 'shelves_drag_books' => 'Przeciągnij podręczniki tutaj aby dodać je do półki', - 'shelves_empty_contents' => 'Ta półka nie ma przypisanych żadnych podręczników', - 'shelves_edit_and_assign' => 'Edytuj półkę aby przypisać podręczniki', + 'shelves_books' => 'Książki na tej półce', + 'shelves_add_books' => 'Dodaj książkę do tej półki', + 'shelves_drag_books' => 'Przeciągnij książki tutaj aby dodać je do półki', + 'shelves_empty_contents' => 'Ta półka nie ma przypisanych żadnych książek', + 'shelves_edit_and_assign' => 'Edytuj półkę aby przypisać książki', 'shelves_edit_named' => 'Edytuj półkę :name', 'shelves_edit' => 'Edytuj półkę', 'shelves_delete' => 'Usuń półkę', 'shelves_delete_named' => 'Usuń półkę :name', - 'shelves_delete_explain' => "Ta operacja usunie półkę o nazwie ':name'. Podręczniki z tej półki nie zostaną usunięte.", + 'shelves_delete_explain' => "Ta operacja usunie półkę o nazwie ':name'. Książki z tej półki nie zostaną usunięte.", 'shelves_delete_confirmation' => 'Czy jesteś pewien, że chcesz usunąć tę półkę?', 'shelves_permissions' => 'Uprawnienia półki', 'shelves_permissions_updated' => 'Uprawnienia półki zostały zaktualizowane', 'shelves_permissions_active' => 'Uprawnienia półki są aktywne', - 'shelves_copy_permissions_to_books' => 'Skopiuj uprawnienia do podręczników', + 'shelves_copy_permissions_to_books' => 'Skopiuj uprawnienia do książek', 'shelves_copy_permissions' => 'Skopiuj uprawnienia', - 'shelves_copy_permissions_explain' => 'To spowoduje zastosowanie obecnych ustawień uprawnień dla tej półki do wszystkich podręczników w niej zawartych. Przed aktywacją upewnij się, że wszelkie zmiany w uprawnieniach do tej półki zostały zapisane.', - 'shelves_copy_permission_success' => 'Uprawnienia półki zostały skopiowane do :count podręczników', + 'shelves_copy_permissions_explain' => 'To spowoduje zastosowanie obecnych ustawień uprawnień dla tej półki do wszystkich książek w niej zawartych. Przed aktywacją upewnij się, że wszelkie zmiany w uprawnieniach do tej półki zostały zapisane.', + 'shelves_copy_permission_success' => 'Uprawnienia półki zostały skopiowane do :count książek', // Books - 'book' => 'Podręcznik', - 'books' => 'Podręczniki', - 'x_books' => ':count Podręcznik|:count Podręczniki', - 'books_empty' => 'Brak utworzonych podręczników', - 'books_popular' => 'Popularne podręczniki', - 'books_recent' => 'Ostatnie podręczniki', - 'books_new' => 'Nowe podręczniki', + 'book' => 'Książka', + 'books' => 'Książki', + 'x_books' => ':count Książka|:count Książki', + 'books_empty' => 'Brak utworzonych książek', + 'books_popular' => 'Popularne książki', + 'books_recent' => 'Ostatnie książki', + 'books_new' => 'Nowe książki', 'books_new_action' => 'New Book', - 'books_popular_empty' => 'Najpopularniejsze podręczniki pojawią się w tym miejscu.', - 'books_new_empty' => 'Tutaj pojawią się ostatnio utworzone podręczniki.', - 'books_create' => 'Utwórz podręcznik', - 'books_delete' => 'Usuń podręcznik', - 'books_delete_named' => 'Usuń podręcznik :bookName', - 'books_delete_explain' => 'To spowoduje usunięcie podręcznika \':bookName\', Wszystkie strony i rozdziały zostaną usunięte.', - 'books_delete_confirmation' => 'Czy na pewno chcesz usunąc ten podręcznik?', - 'books_edit' => 'Edytuj podręcznik', - 'books_edit_named' => 'Edytuj podręcznik :bookName', - 'books_form_book_name' => 'Nazwa podręcznika', - 'books_save' => 'Zapisz podręcznik', - 'books_permissions' => 'Uprawnienia podręcznika', - 'books_permissions_updated' => 'Zaktualizowano uprawnienia podręcznika', - 'books_empty_contents' => 'Brak stron lub rozdziałów w tym podręczniku.', + 'books_popular_empty' => 'Najpopularniejsze książki pojawią się w tym miejscu.', + 'books_new_empty' => 'Tutaj pojawią się ostatnio utworzone książki.', + 'books_create' => 'Utwórz książkę', + 'books_delete' => 'Usuń książkę', + 'books_delete_named' => 'Usuń książkę :bookName', + 'books_delete_explain' => 'To spowoduje usunięcie książki \':bookName\', Wszystkie strony i rozdziały zostaną usunięte.', + 'books_delete_confirmation' => 'Czy na pewno chcesz usunąc tę książkę?', + 'books_edit' => 'Edytuj książkę', + 'books_edit_named' => 'Edytuj książkę :bookName', + 'books_form_book_name' => 'Nazwa książki', + 'books_save' => 'Zapisz książkę', + 'books_permissions' => 'Uprawnienia książki', + 'books_permissions_updated' => 'Zaktualizowano uprawnienia książki', + 'books_empty_contents' => 'Brak stron lub rozdziałów w tej książce.', 'books_empty_create_page' => 'Utwórz nową stronę', - 'books_empty_sort_current_book' => 'posortuj bieżący podręcznik', + 'books_empty_sort_current_book' => 'posortuj bieżącą książkę', 'books_empty_add_chapter' => 'Dodaj rozdział', - 'books_permissions_active' => 'Uprawnienia podręcznika są aktywne', - 'books_search_this' => 'Wyszukaj w tym podręczniku', - 'books_navigation' => 'Nawigacja po podręczniku', - 'books_sort' => 'Sortuj zawartość podręcznika', - 'books_sort_named' => 'Sortuj podręcznik :bookName', - 'books_sort_name' => 'Sort by Name', - 'books_sort_created' => 'Sort by Created Date', - 'books_sort_updated' => 'Sort by Updated Date', - 'books_sort_chapters_first' => 'Chapters First', - 'books_sort_chapters_last' => 'Chapters Last', - 'books_sort_show_other' => 'Pokaż inne podręczniki', + 'books_permissions_active' => 'Uprawnienia książki są aktywne', + 'books_search_this' => 'Wyszukaj w tej książce', + 'books_navigation' => 'Nawigacja po książce', + 'books_sort' => 'Sortuj zawartość książki', + 'books_sort_named' => 'Sortuj książkę :bookName', + 'books_sort_name' => 'Sortuj według nazwy', + 'books_sort_created' => 'Sortuj według daty utworzenia', + 'books_sort_updated' => 'Sortuj według daty modyfikacji', + 'books_sort_chapters_first' => 'Rozdziały na początku', + 'books_sort_chapters_last' => 'Rozdziały na końcu', + 'books_sort_show_other' => 'Pokaż inne książki', 'books_sort_save' => 'Zapisz nową kolejność', // Chapters @@ -177,7 +177,7 @@ return [ 'pages_delete_confirm' => 'Czy na pewno chcesz usunąć tę stronę?', 'pages_delete_draft_confirm' => 'Czy na pewno chcesz usunąć wersje roboczą strony?', 'pages_editing_named' => 'Edytowanie strony :pageName', - 'pages_edit_draft_options' => 'Draft Options', + 'pages_edit_draft_options' => 'Ustawienia wersji roboczej', 'pages_edit_save_draft' => 'Zapisano wersje roboczą o ', 'pages_edit_draft' => 'Edytuj wersje roboczą', 'pages_editing_draft' => 'Edytowanie wersji roboczej', @@ -211,8 +211,8 @@ return [ 'pages_revisions_created_by' => 'Utworzona przez', 'pages_revisions_date' => 'Data wersji', 'pages_revisions_number' => '#', - 'pages_revisions_numbered' => 'Revision #:id', - 'pages_revisions_numbered_changes' => 'Revision #:id Changes', + 'pages_revisions_numbered' => 'Wersja #:id', + 'pages_revisions_numbered_changes' => 'Zmiany w wersji #:id', 'pages_revisions_changelog' => 'Dziennik zmian', 'pages_revisions_changes' => 'Zmiany', 'pages_revisions_current' => 'Obecna wersja', @@ -275,11 +275,11 @@ return [ 'attachments_file_updated' => 'Plik zaktualizowany pomyślnie', 'attachments_link_attached' => 'Link pomyślnie dodany do strony', 'templates' => 'Templates', - 'templates_set_as_template' => 'Page is a template', - 'templates_explain_set_as_template' => 'You can set this page as a template so its contents be utilized when creating other pages. Other users will be able to use this template if they have view permissions for this page.', - 'templates_replace_content' => 'Replace page content', - 'templates_append_content' => 'Append to page content', - 'templates_prepend_content' => 'Prepend to page content', + 'templates_set_as_template' => 'Strona jest szablonem', + 'templates_explain_set_as_template' => 'Możesz ustawić tę stronę jako szablon, tak aby jej zawartość była wykorzystywana przy tworzeniu innych stron. Inni użytkownicy będą mogli korzystać z tego szablonu, jeśli mają uprawnienia do przeglądania tej strony.', + 'templates_replace_content' => 'Zmień zawartość strony', + 'templates_append_content' => 'Dodaj do zawartośći strony na końcu', + 'templates_prepend_content' => 'Dodaj do zawartośći strony na początku', // Profile View 'profile_user_for_x' => 'Użytkownik od :time', @@ -287,7 +287,7 @@ return [ 'profile_not_created_pages' => ':userName nie utworzył żadnych stron', 'profile_not_created_chapters' => ':userName nie utworzył żadnych rozdziałów', 'profile_not_created_books' => ':userName nie utworzył żadnych podręczników', - 'profile_not_created_shelves' => ':userName has not created any shelves', + 'profile_not_created_shelves' => ':userName nie utworzył żadnych półek', // Comments 'comment' => 'Komentarz', @@ -309,7 +309,7 @@ return [ // Revision 'revision_delete_confirm' => 'Czy na pewno chcesz usunąć tę wersję?', - 'revision_restore_confirm' => 'Are you sure you want to restore this revision? The current page contents will be replaced.', + 'revision_restore_confirm' => 'Czu ma pewno chcesz przywrócić tą wersję? Aktualna zawartość strony zostanie nadpisana.', 'revision_delete_success' => 'Usunięto wersję', 'revision_cannot_delete_latest' => 'Nie można usunąć najnowszej wersji.' ]; \ No newline at end of file diff --git a/resources/lang/pl/errors.php b/resources/lang/pl/errors.php index 5a6375243..406755c35 100644 --- a/resources/lang/pl/errors.php +++ b/resources/lang/pl/errors.php @@ -17,6 +17,12 @@ return [ 'ldap_fail_authed' => 'Dostęp LDAP przy użyciu tego DN i hasła nie powiódł się', 'ldap_extension_not_installed' => 'Rozszerzenie LDAP PHP nie zostało zainstalowane', 'ldap_cannot_connect' => 'Nie można połączyć z serwerem LDAP, połączenie nie zostało ustanowione', + 'saml_already_logged_in' => 'Już zalogowany', + 'saml_user_not_registered' => 'Użytkownik :name nie jest zarejestrowany i automatyczna rejestracja jest wyłączona', + 'saml_no_email_address' => 'Nie można odnaleźć adresu email dla tego użytkownika w danych dostarczonych przez zewnętrzny system uwierzytelniania', + 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', + 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', + 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => 'Brak zdefiniowanej akcji', 'social_login_bad_response' => "Podczas próby logowania :socialAccount wystąpił błąd: \n:error", 'social_account_in_use' => 'To konto :socialAccount jest już w użyciu. Spróbuj zalogować się za pomocą opcji :socialAccount.', @@ -27,7 +33,7 @@ return [ 'social_account_register_instructions' => 'Jeśli nie masz jeszcze konta, możesz zarejestrować je używając opcji :socialAccount.', 'social_driver_not_found' => 'Funkcja społecznościowa nie została odnaleziona', 'social_driver_not_configured' => 'Ustawienia konta :socialAccount nie są poprawne.', - 'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.', + 'invite_token_expired' => 'Zaproszenie wygasło. Możesz spróować zresetować swoje hasło.', // System 'path_not_writable' => 'Zapis do ścieżki :filePath jest niemożliwy. Upewnij się że aplikacja ma prawa do zapisu plików na serwerze.', @@ -50,11 +56,11 @@ return [ // Entities 'entity_not_found' => 'Nie znaleziono obiektu', 'bookshelf_not_found' => 'Nie znaleziono półki', - 'book_not_found' => 'Nie znaleziono podręcznika', + 'book_not_found' => 'Nie znaleziono książki', 'page_not_found' => 'Nie znaleziono strony', 'chapter_not_found' => 'Nie znaleziono rozdziału', - 'selected_book_not_found' => 'Wybrany podręcznik nie został znaleziony', - 'selected_book_chapter_not_found' => 'Wybrany podręcznik lub rozdział nie został znaleziony', + 'selected_book_not_found' => 'Wybrana książka nie została znaleziona', + 'selected_book_chapter_not_found' => 'Wybrana książka lub rozdział nie został znaleziony', 'guests_cannot_save_drafts' => 'Goście nie mogą zapisywać wersji roboczych', // Users @@ -65,7 +71,7 @@ return [ 'role_cannot_be_edited' => 'Ta rola nie może być edytowana', 'role_system_cannot_be_deleted' => 'Ta rola jest rolą systemową i nie może zostać usunięta', 'role_registration_default_cannot_delete' => 'Ta rola nie może zostać usunięta, dopóki jest ustawiona jako domyślna rola użytkownika', - 'role_cannot_remove_only_admin' => 'This user is the only user assigned to the administrator role. Assign the administrator role to another user before attempting to remove it here.', + 'role_cannot_remove_only_admin' => 'Ten użytkownik jest jedynym użytkownikiem przypisanym do roli administratora. Przypisz rolę administratora innemu użytkownikowi przed próbą usunięcia.', // Comments 'comment_list' => 'Wystąpił błąd podczas pobierania komentarzy.', diff --git a/resources/lang/pl/settings.php b/resources/lang/pl/settings.php index 2c17657e4..1918118ba 100644 --- a/resources/lang/pl/settings.php +++ b/resources/lang/pl/settings.php @@ -12,24 +12,24 @@ return [ 'settings_save_success' => 'Ustawienia zapisane', // App Settings - 'app_customization' => 'Customization', - 'app_features_security' => 'Features & Security', + 'app_customization' => 'Dostosowywanie', + 'app_features_security' => 'Funkcje i bezpieczeństwo', 'app_name' => 'Nazwa aplikacji', 'app_name_desc' => 'Ta nazwa jest wyświetlana w nagłówku i e-mailach.', 'app_name_header' => 'Pokazać nazwę aplikacji w nagłówku?', - 'app_public_access' => 'Public Access', - 'app_public_access_desc' => 'Enabling this option will allow visitors, that are not logged-in, to access content in your BookStack instance.', - 'app_public_access_desc_guest' => 'Access for public visitors can be controlled through the "Guest" user.', - 'app_public_access_toggle' => 'Allow public access', + 'app_public_access' => 'Dostęp publiczny', + 'app_public_access_desc' => 'Włączenie tej opcji umożliwi niezalogowanym odwiedzającym dostęp do treści w Twojej instancji BookStack.', + 'app_public_access_desc_guest' => 'Dostęp dla niezalogowanych odwiedzających jest dostępny poprzez użytkownika "Guest".', + 'app_public_access_toggle' => 'Zezwalaj na dostęp publiczny', 'app_public_viewing' => 'Zezwolić na publiczne przeglądanie?', 'app_secure_images' => 'Włączyć przesyłanie obrazów o wyższym poziomie bezpieczeństwa?', - 'app_secure_images_toggle' => 'Enable higher security image uploads', + 'app_secure_images_toggle' => 'Włącz wyższy poziom bezpieczeństwa dla obrazów', 'app_secure_images_desc' => 'Ze względów wydajnościowych wszystkie obrazki są publiczne. Ta opcja dodaje dodatkowy, trudny do odgadnięcia losowy ciąg na początku nazwy obrazka. Upewnij się że indeksowanie katalogów jest zablokowane, aby uniemożliwić łatwy dostęp do obrazków.', 'app_editor' => 'Edytor strony', 'app_editor_desc' => 'Wybierz edytor używany przez użytkowników do edycji zawartości.', 'app_custom_html' => 'Własna zawartość w tagu ', 'app_custom_html_desc' => 'Zawartość dodana tutaj zostanie dołączona na dole sekcji każdej strony. Przydatne przy nadpisywaniu styli lub dodawaniu analityki.', - 'app_custom_html_disabled_notice' => 'Custom HTML head content is disabled on this settings page to ensure any breaking changes can be reverted.', + 'app_custom_html_disabled_notice' => 'Niestandardowa zawartość nagłówka HTML jest wyłączona na tej stronie ustawień aby zapewnić, że wszystkie błedne zmiany (braking change) mogą zostać cofnięte.', 'app_logo' => 'Logo aplikacji', 'app_logo_desc' => 'Ten obrazek powinien mieć nie więcej niż 43px wysokosci.
Większe obrazki zostaną zmniejszone.', 'app_primary_color' => 'Podstawowy kolor aplikacji', @@ -43,12 +43,12 @@ return [ // Registration Settings 'reg_settings' => 'Ustawienia rejestracji', - 'reg_enable' => 'Enable Registration', - 'reg_enable_toggle' => 'Enable registration', - 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', + 'reg_enable' => 'Włącz rejestrację', + 'reg_enable_toggle' => 'Włącz rejestrację', + 'reg_enable_desc' => 'Kiedy rejestracja jest włączona użytkownicy mogą się rejestrować. Po rejestracji otrzymują jedną domyślną rolę użytkownika.', 'reg_default_role' => 'Domyślna rola użytkownika po rejestracji', - 'reg_email_confirmation' => 'Email Confirmation', - 'reg_email_confirmation_toggle' => 'Require email confirmation', + 'reg_email_confirmation' => 'Potwierdzenie adresu email', + 'reg_email_confirmation_toggle' => 'Wymagaj potwierdzenia adresu email', 'reg_confirm_email_desc' => 'Jeśli restrykcje domenowe zostały ustawione, potwierdzenie adresu stanie się konieczne, a poniższa wartośc zostanie zignorowana.', 'reg_confirm_restrict_domain' => 'Restrykcje domenowe dot. adresu e-mail', 'reg_confirm_restrict_domain_desc' => 'Wprowadź listę domen adresów e-mail, rozdzieloną przecinkami, którym chciałbyś zezwolić na rejestrację. Wymusi to konieczność potwierdzenia adresu e-mail przez użytkownika przed uzyskaniem dostępu do aplikacji.
Pamiętaj, że użytkownicy będą mogli zmienić adres e-mail po rejestracji.', @@ -63,6 +63,13 @@ return [ 'maint_image_cleanup_warning' => 'Znaleziono :count potencjalnie niepotrzebnych obrazków. Czy na pewno chcesz je usunąć?', 'maint_image_cleanup_success' => ':count potencjalnie nieużywane obrazki zostały znalezione i usunięte!', 'maint_image_cleanup_nothing_found' => 'Nie znaleziono żadnych nieużywanych obrazków. Nic nie zostało usunięte!', + 'maint_send_test_email' => 'Wyślij testową wiadomość e-mail', + 'maint_send_test_email_desc' => 'Ta opcje wyśle wiadomość testową na adres e-mail podany w Twoim profilu', + 'maint_send_test_email_run' => 'Wyślij testową wiadomość e-mail', + 'maint_send_test_email_success' => 'E-mail wysłany na adres :address', + 'maint_send_test_email_mail_subject' => 'E-mail testowy', + 'maint_send_test_email_mail_greeting' => 'Wygląda na to, że wysyłka wiadomości e-mail działa!', + 'maint_send_test_email_mail_text' => 'Gratulacje! Otrzymałeś tego e-maila więc Twoje ustawienia poczty elektronicznej wydają się być prawidłowo skonfigurowane.', // Role Settings 'roles' => 'Role', @@ -85,7 +92,7 @@ return [ 'role_manage_roles' => 'Zarządzanie rolami i uprawnieniami ról', 'role_manage_entity_permissions' => 'Zarządzanie uprawnieniami podręczników, rozdziałów i stron', 'role_manage_own_entity_permissions' => 'Zarządzanie uprawnieniami własnych podręczników, rozdziałów i stron', - 'role_manage_page_templates' => 'Manage page templates', + 'role_manage_page_templates' => 'Zarządzaj szablonami stron', 'role_manage_settings' => 'Zarządzanie ustawieniami aplikacji', 'role_asset' => 'Zarządzanie zasobami', 'role_asset_desc' => 'Te ustawienia kontrolują zarządzanie zasobami systemu. Uprawnienia podręczników, rozdziałów i stron nadpisują te ustawienia.', @@ -103,17 +110,17 @@ return [ 'user_profile' => 'Profil użytkownika', 'users_add_new' => 'Dodaj użytkownika', 'users_search' => 'Wyszukaj użytkownika', - 'users_details' => 'User Details', - 'users_details_desc' => 'Set a display name and an email address for this user. The email address will be used for logging into the application.', - 'users_details_desc_no_email' => 'Set a display name for this user so others can recognise them.', + 'users_details' => 'Szczegóły użytkownika', + 'users_details_desc' => 'Ustaw wyświetlaną nazwę i adres e-mail dla tego użytkownika. Adres e-mail zostanie wykorzystany do zalogowania się do aplikacji.', + 'users_details_desc_no_email' => 'Ustaw wyświetlaną nazwę dla tego użytkownika, aby inni mogli go rozpoznać.', 'users_role' => 'Role użytkownika', - 'users_role_desc' => 'Select which roles this user will be assigned to. If a user is assigned to multiple roles the permissions from those roles will stack and they will receive all abilities of the assigned roles.', - 'users_password' => 'User Password', - 'users_password_desc' => 'Set a password used to log-in to the application. This must be at least 6 characters long.', - 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', - 'users_send_invite_option' => 'Send user invite email', + 'users_role_desc' => 'Wybierz role, do których ten użytkownik zostanie przypisany. Jeśli użytkownik jest przypisany do wielu ról, uprawnienia z tych ról zostaną nałożone i otrzyma wszystkie uprawnienia przypisanych ról.', + 'users_password' => 'Hasło użytkownika', + 'users_password_desc' => 'Ustaw hasło logowania do aplikacji. Hasło musi mieć przynajmniej 6 znaków.', + 'users_send_invite_text' => 'Możesz wybrać wysłanie do tego użytkownika wiadomości e-mail z zaproszeniem, która pozwala mu ustawić własne hasło, w przeciwnym razie możesz ustawić je samemu.', + 'users_send_invite_option' => 'Wyślij e-mail z zaproszeniem', 'users_external_auth_id' => 'Zewnętrzne identyfikatory autentykacji', - 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your LDAP system.', + 'users_external_auth_id_desc' => 'Jest to identyfikator używany do autoryzacji tego użytkownika podczas komunikacji z systemem LDAP.', 'users_password_warning' => 'Wypełnij poniżej tylko jeśli chcesz zmienić swoje hasło:', 'users_system_public' => 'Ten użytkownik reprezentuje każdego gościa odwiedzającego tę aplikację. Nie można się na niego zalogować, lecz jest przyznawany automatycznie.', 'users_delete' => 'Usuń użytkownika', @@ -127,7 +134,7 @@ return [ 'users_avatar' => 'Avatar użytkownika', 'users_avatar_desc' => 'Ten obrazek powinien posiadać wymiary 256x256px.', 'users_preferred_language' => 'Preferowany język', - 'users_preferred_language_desc' => 'This option will change the language used for the user-interface of the application. This will not affect any user-created content.', + 'users_preferred_language_desc' => 'Opcja ta zmieni język używany w interfejsie użytkownika aplikacji. Nie wpłynie to na zawartość stworzoną przez użytkownika.', 'users_social_accounts' => 'Konta społecznościowe', 'users_social_accounts_info' => 'Tutaj możesz połączyć kilka kont społecznościowych w celu łatwiejszego i szybszego logowania. Odłączenie konta tutaj nie autoryzowało dostępu. Odwołaj dostęp z ustawień profilu na podłączonym koncie społecznościowym.', 'users_social_connect' => 'Podłącz konto', diff --git a/resources/lang/pl/validation.php b/resources/lang/pl/validation.php index d5e5ab343..bedffae41 100644 --- a/resources/lang/pl/validation.php +++ b/resources/lang/pl/validation.php @@ -30,40 +30,40 @@ return [ 'digits' => ':attribute musi mieć :digits cyfr.', 'digits_between' => ':attribute musi mieć od :min do :max cyfr.', 'email' => ':attribute musi być prawidłowym adresem e-mail.', - 'ends_with' => 'The :attribute must end with one of the following: :values', + 'ends_with' => ':attribute musi kończyć się jedną z poniższych wartości: :values', 'filled' => ':attribute jest wymagany.', 'gt' => [ - 'numeric' => 'The :attribute must be greater than :value.', - 'file' => 'The :attribute must be greater than :value kilobytes.', - 'string' => 'The :attribute must be greater than :value characters.', - 'array' => 'The :attribute must have more than :value items.', + 'numeric' => ':attribute musi być większy niż :value.', + 'file' => ':attribute musi mieć rozmiar większy niż :value kilobajtów.', + 'string' => ':attribute musi mieć więcej niż :value znaków.', + 'array' => ':attribute musi mieć więcej niż :value elementów.', ], 'gte' => [ - 'numeric' => 'The :attribute must be greater than or equal :value.', - 'file' => 'The :attribute must be greater than or equal :value kilobytes.', - 'string' => 'The :attribute must be greater than or equal :value characters.', - 'array' => 'The :attribute must have :value items or more.', + 'numeric' => ':attribute musi być większy lub równy :value.', + 'file' => ':attribute musi mieć rozmiar większy niż lub równy :value kilobajtów.', + 'string' => ':attribute musi mieć :value lub więcej znaków.', + 'array' => ':attribute musi mieć :value lub więcej elementów.', ], 'exists' => 'Wybrana wartość :attribute jest nieprawidłowa.', 'image' => ':attribute musi być obrazkiem.', - 'image_extension' => 'The :attribute must have a valid & supported image extension.', + 'image_extension' => ':attribute musi mieć prawidłowe i wspierane rozszerzenie', 'in' => 'Wybrana wartość :attribute jest nieprawidłowa.', 'integer' => ':attribute musi być liczbą całkowitą.', 'ip' => ':attribute musi być prawidłowym adresem IP.', - 'ipv4' => 'The :attribute must be a valid IPv4 address.', - 'ipv6' => 'The :attribute must be a valid IPv6 address.', - 'json' => 'The :attribute must be a valid JSON string.', + 'ipv4' => ':attribute musi być prawidłowym adresem IPv4.', + 'ipv6' => ':attribute musi być prawidłowym adresem IPv6.', + 'json' => ':attribute musi być prawidłowym ciągiem JSON.', 'lt' => [ - 'numeric' => 'The :attribute must be less than :value.', - 'file' => 'The :attribute must be less than :value kilobytes.', - 'string' => 'The :attribute must be less than :value characters.', - 'array' => 'The :attribute must have less than :value items.', + 'numeric' => ':attribute musi być mniejszy niż :value.', + 'file' => ':attribute musi mieć rozmiar mniejszy niż :value kilobajtów.', + 'string' => ':attribute musi mieć mniej niż :value znaków.', + 'array' => ':attribute musi mieć mniej niż :value elementów.', ], 'lte' => [ - 'numeric' => 'The :attribute must be less than or equal :value.', - 'file' => 'The :attribute must be less than or equal :value kilobytes.', - 'string' => 'The :attribute must be less than or equal :value characters.', - 'array' => 'The :attribute must not have more than :value items.', + 'numeric' => ':attribute musi być mniejszy lub równy :value.', + 'file' => ':attribute musi mieć rozmiar mniejszy lub równy:value kilobajtów.', + 'string' => ':attribute nie może mieć więcej niż :value znaków.', + 'array' => ':attribute nie może mieć więcej niż :value elementów.', ], 'max' => [ 'numeric' => 'Wartość :attribute nie może być większa niż :max.', @@ -78,7 +78,7 @@ return [ 'string' => 'Długość :attribute nie może być mniejsza niż :min znaków.', 'array' => 'Rozmiar :attribute musi posiadać co najmniej :min elementy.', ], - 'no_double_extension' => 'The :attribute must only have a single file extension.', + 'no_double_extension' => ':attribute może mieć tylko jedno rozszerzenie.', 'not_in' => 'Wartość :attribute jest nieprawidłowa.', 'not_regex' => 'The :attribute format is invalid.', 'numeric' => ':attribute musi być liczbą.', @@ -100,7 +100,7 @@ return [ 'timezone' => ':attribute musi być prawidłową strefą czasową.', 'unique' => ':attribute zostało już zajęte.', 'url' => 'Format :attribute jest nieprawidłowy.', - 'uploaded' => 'The file could not be uploaded. The server may not accept files of this size.', + 'uploaded' => 'Plik nie może zostać wysłany. Serwer nie akceptuje plików o takim rozmiarze.', // Custom validation lines 'custom' => [ From 6bc6543402c8e7be7f25ad1391b631959efe1213 Mon Sep 17 00:00:00 2001 From: Artur Skoczylas Date: Thu, 28 Nov 2019 15:55:18 +0100 Subject: [PATCH 015/191] consistent of book translation --- resources/lang/pl/components.php | 2 +- resources/lang/pl/entities.php | 6 +++--- resources/lang/pl/settings.php | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/resources/lang/pl/components.php b/resources/lang/pl/components.php index 9c044d237..b189c8171 100644 --- a/resources/lang/pl/components.php +++ b/resources/lang/pl/components.php @@ -8,7 +8,7 @@ return [ 'image_select' => 'Wybór obrazka', 'image_all' => 'Wszystkie', 'image_all_title' => 'Zobacz wszystkie obrazki', - 'image_book_title' => 'Zobacz obrazki zapisane w tym podręczniku', + 'image_book_title' => 'Zobacz obrazki zapisane w tej książce', 'image_page_title' => 'Zobacz obrazki zapisane na tej stronie', 'image_search_hint' => 'Szukaj po nazwie obrazka', 'image_uploaded' => 'Przesłano :uploadedDate', diff --git a/resources/lang/pl/entities.php b/resources/lang/pl/entities.php index 267ac69e4..122139b67 100644 --- a/resources/lang/pl/entities.php +++ b/resources/lang/pl/entities.php @@ -146,7 +146,7 @@ return [ 'chapters_delete' => 'Usuń rozdział', 'chapters_delete_named' => 'Usuń rozdział :chapterName', 'chapters_delete_explain' => 'To spowoduje usunięcie rozdziału \':chapterName\', Wszystkie strony zostaną usunięte - i dodane bezpośrednio do podręcznika nadrzędnego.', + i dodane bezpośrednio do książki.', 'chapters_delete_confirm' => 'Czy na pewno chcesz usunąć ten rozdział?', 'chapters_edit' => 'Edytuj rozdział', 'chapters_edit_named' => 'Edytuj rozdział :chapterName', @@ -240,7 +240,7 @@ return [ // Editor Sidebar 'page_tags' => 'Tagi strony', 'chapter_tags' => 'Tagi rozdziału', - 'book_tags' => 'Tagi podręcznika', + 'book_tags' => 'Tagi książki', 'shelf_tags' => 'Tagi półki', 'tag' => 'Tag', 'tags' => 'Tagi', @@ -286,7 +286,7 @@ return [ 'profile_created_content' => 'Utworzona zawartość', 'profile_not_created_pages' => ':userName nie utworzył żadnych stron', 'profile_not_created_chapters' => ':userName nie utworzył żadnych rozdziałów', - 'profile_not_created_books' => ':userName nie utworzył żadnych podręczników', + 'profile_not_created_books' => ':userName nie utworzył żadnych książek', 'profile_not_created_shelves' => ':userName nie utworzył żadnych półek', // Comments diff --git a/resources/lang/pl/settings.php b/resources/lang/pl/settings.php index 1918118ba..2117238cf 100644 --- a/resources/lang/pl/settings.php +++ b/resources/lang/pl/settings.php @@ -90,12 +90,12 @@ return [ 'role_system' => 'Uprawnienia systemowe', 'role_manage_users' => 'Zarządzanie użytkownikami', 'role_manage_roles' => 'Zarządzanie rolami i uprawnieniami ról', - 'role_manage_entity_permissions' => 'Zarządzanie uprawnieniami podręczników, rozdziałów i stron', - 'role_manage_own_entity_permissions' => 'Zarządzanie uprawnieniami własnych podręczników, rozdziałów i stron', + 'role_manage_entity_permissions' => 'Zarządzanie uprawnieniami książek, rozdziałów i stron', + 'role_manage_own_entity_permissions' => 'Zarządzanie uprawnieniami własnych książek, rozdziałów i stron', 'role_manage_page_templates' => 'Zarządzaj szablonami stron', 'role_manage_settings' => 'Zarządzanie ustawieniami aplikacji', 'role_asset' => 'Zarządzanie zasobami', - 'role_asset_desc' => 'Te ustawienia kontrolują zarządzanie zasobami systemu. Uprawnienia podręczników, rozdziałów i stron nadpisują te ustawienia.', + 'role_asset_desc' => 'Te ustawienia kontrolują zarządzanie zasobami systemu. Uprawnienia książek, rozdziałów i stron nadpisują te ustawienia.', 'role_asset_admins' => 'Administratorzy mają automatycznie dostęp do wszystkich treści, ale te opcję mogą być pokazywać lub ukrywać opcje interfejsu użytkownika.', 'role_all' => 'Wszyscy', 'role_own' => 'Własne', From 701d105b9e866c2be64464bcb072f6444f6e6cdd Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 7 Dec 2019 15:54:25 +0000 Subject: [PATCH 016/191] Updated details and attribution for translators --- .github/ISSUE_TEMPLATE/language_request.md | 13 +++++++++++++ readme.md | 19 +++++-------------- 2 files changed, 18 insertions(+), 14 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/language_request.md diff --git a/.github/ISSUE_TEMPLATE/language_request.md b/.github/ISSUE_TEMPLATE/language_request.md new file mode 100644 index 000000000..19f23038c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/language_request.md @@ -0,0 +1,13 @@ +--- +name: Language Request +about: Request a new language to be added to Crowdin for you to translate + +--- + +### Language To Add + +_Specify here the language you want to add._ + +---- + +_This issue template is to request a new language be added to our [Crowdin translation management project](https://crowdin.com/project/bookstack). Please don't use this template to simple request a new language that you are not prepared to provide translations for._ \ No newline at end of file diff --git a/readme.md b/readme.md index f86e661ea..fb26cede3 100644 --- a/readme.md +++ b/readme.md @@ -107,22 +107,11 @@ The docker-compose setup runs an instance of [MailHog](https://github.com/mailho ## 🌎 Translations -All text strings can be found in the `resources/lang` folder where each language option has its own folder. To add a new language you should copy the `en` folder to an new folder (eg. `fr` for french) then go through and translate all text strings in those files, leaving the keys and file-names intact. If a language string is missing then the `en` translation will be used. To show the language option in the user preferences language drop-down you will need to add your language to the options found at the bottom of the `resources/lang/en/settings.php` file. A system-wide language can also be set in the `.env` file like so: `APP_LANG=en`. +Translations for text within BookStack is managed through the [BookStack project on Crowdin](https://crowdin.com/project/bookstack). Some strings have colon-prefixed variables in such as `:userName`. Leave these values as they are as they will be replaced at run-time. Crowdin is the preferred way to provide translations, otherwise the raw translations files can be found within the `resources/lang` path. -You will also need to add the language to the `locales` array in the `config/app.php` file. +If you'd like a new language to be added to Crowdin, for you to be able to provide translations for, please [open a new issue here](https://github.com/BookStackApp/BookStack/issues/new?template=language_request.md). -There is a script available which compares translation content to `en` files to see what items are missing or redundant. This can be ran like so from your BookStack install folder: - -```bash -# Syntax -php resources/lang/check.php - -# Examples -php resources/lang/check.php fr -php resources/lang/check.php pt_BR -``` - -Some strings have colon-prefixed variables in such as `:userName`. Leave these values as they are as they will be replaced at run-time. +Please note, translations in BookStack are provided to the "Crowdin Global Translation Memory" which helps BookStack and other projects with finding translations. If you are not happy with contributing to this then providing translations to BookStack, even manually via GitHub, is not advised. ## 🎁 Contributing, Issues & Pull Requests @@ -156,6 +145,8 @@ The BookStack source is provided under the MIT License. The libraries used by, a The great people that have worked to build and improve BookStack can [be seen here](https://github.com/BookStackApp/BookStack/graphs/contributors). +The wonderful people that have provided translations, either through GitHub or via Crowdin [can be seen here](https://github.com/BookStackApp/BookStack/blob/master/.github/translators.txt). + These are the great open-source projects used to help build BookStack: * [Laravel](http://laravel.com/) From 1746f2c2499c13f6b624d0b5f20648127020068f Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 7 Dec 2019 15:57:07 +0000 Subject: [PATCH 017/191] Fixed issue template wording --- .github/ISSUE_TEMPLATE/language_request.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/language_request.md b/.github/ISSUE_TEMPLATE/language_request.md index 19f23038c..249ef7871 100644 --- a/.github/ISSUE_TEMPLATE/language_request.md +++ b/.github/ISSUE_TEMPLATE/language_request.md @@ -10,4 +10,4 @@ _Specify here the language you want to add._ ---- -_This issue template is to request a new language be added to our [Crowdin translation management project](https://crowdin.com/project/bookstack). Please don't use this template to simple request a new language that you are not prepared to provide translations for._ \ No newline at end of file +_This issue template is to request a new language be added to our [Crowdin translation management project](https://crowdin.com/project/bookstack). Please don't use this template to request a new language that you are not prepared to provide translations for._ \ No newline at end of file From 7af6fe491761d5a2bcc7eabf097e759b77823f57 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 7 Dec 2019 15:57:58 +0000 Subject: [PATCH 018/191] Standardised issue template name casing --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- .github/ISSUE_TEMPLATE/feature_request.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 8b3d29c2d..c4444f242 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,5 +1,5 @@ --- -name: Bug report +name: Bug Report about: Create a report to help us improve --- diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 7f38b9cdc..781cca5b8 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,5 +1,5 @@ --- -name: Feature request +name: Feature Request about: Suggest an idea for this project --- From a6bbe4698741a5221f22fa7818a0a3037a54430a Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 7 Dec 2019 16:23:44 +0000 Subject: [PATCH 019/191] Updated code system to dynamically set php codemirror mode - Codemirror mode mapping value can now be a function to dynamically set mode depending on actual code content. - Used above system to set php mode type, depending on if ' { + return content.includes('/gi ,'\n'); + const content = elem.textContent.trim(); + let mode = ''; if (innerCodeElem !== null) { - let langName = innerCodeElem.className.replace('language-', ''); - mode = getMode(langName); + const langName = innerCodeElem.className.replace('language-', ''); + mode = getMode(langName, content); } - elem.innerHTML = elem.innerHTML.replace(//gi ,'\n'); - let content = elem.textContent.trim(); - let cm = CodeMirror(function(elt) { + const cm = CodeMirror(function(elt) { elem.parentNode.replaceChild(elt, elem); }, { value: content, @@ -142,12 +146,24 @@ function addCopyIcon(cmInstance) { /** * Search for a codemirror code based off a user suggestion - * @param suggestion + * @param {String} suggestion + * @param {String} content * @returns {string} */ -function getMode(suggestion) { +function getMode(suggestion, content) { suggestion = suggestion.trim().replace(/^\./g, '').toLowerCase(); - return (typeof modeMap[suggestion] !== 'undefined') ? modeMap[suggestion] : ''; + + const modeMapType = typeof modeMap[suggestion]; + + if (modeMapType === 'undefined') { + return ''; + } + + if (modeMapType === 'function') { + return modeMap[suggestion](content); + } + + return modeMap[suggestion]; } /** @@ -165,8 +181,8 @@ function getTheme() { * @returns {{wrap: Element, editor: *}} */ function wysiwygView(elem) { - let doc = elem.ownerDocument; - let codeElem = elem.querySelector('code'); + const doc = elem.ownerDocument; + const codeElem = elem.querySelector('code'); let lang = (elem.className || '').replace('language-', ''); if (lang === '' && codeElem) { @@ -174,9 +190,9 @@ function wysiwygView(elem) { } elem.innerHTML = elem.innerHTML.replace(//gi ,'\n'); - let content = elem.textContent; - let newWrap = doc.createElement('div'); - let newTextArea = doc.createElement('textarea'); + const content = elem.textContent; + const newWrap = doc.createElement('div'); + const newTextArea = doc.createElement('textarea'); newWrap.className = 'CodeMirrorContainer'; newWrap.setAttribute('data-lang', lang); @@ -192,7 +208,7 @@ function wysiwygView(elem) { newWrap.appendChild(elt); }, { value: content, - mode: getMode(lang), + mode: getMode(lang, content), lineNumbers: true, lineWrapping: false, theme: getTheme(), @@ -211,14 +227,14 @@ function wysiwygView(elem) { * @returns {*} */ function popupEditor(elem, modeSuggestion) { - let content = elem.textContent; + const content = elem.textContent; return CodeMirror(function(elt) { elem.parentNode.insertBefore(elt, elem); elem.style.display = 'none'; }, { value: content, - mode: getMode(modeSuggestion), + mode: getMode(modeSuggestion, content), lineNumbers: true, lineWrapping: false, theme: getTheme() @@ -230,8 +246,8 @@ function popupEditor(elem, modeSuggestion) { * @param cmInstance * @param modeSuggestion */ -function setMode(cmInstance, modeSuggestion) { - cmInstance.setOption('mode', getMode(modeSuggestion)); +function setMode(cmInstance, modeSuggestion, content) { + cmInstance.setOption('mode', getMode(modeSuggestion, content)); } /** diff --git a/resources/js/vues/code-editor.js b/resources/js/vues/code-editor.js index c6df6b1a5..e0472a973 100644 --- a/resources/js/vues/code-editor.js +++ b/resources/js/vues/code-editor.js @@ -9,7 +9,7 @@ const methods = { this.$refs.overlay.components.overlay.hide(); }, updateEditorMode(language) { - codeLib.setMode(this.editor, language); + codeLib.setMode(this.editor, language, this.editor.getValue()); }, updateLanguage(lang) { this.language = lang; From 5a533fff8bc09e1520276c3fbb91740b432c8a3b Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 7 Dec 2019 16:54:34 +0000 Subject: [PATCH 020/191] Updated codeblock editor to work with fade animation - Added fadeIn to animation JS service. - Updated overlay to use anim service and to recieve a callback for after-anim actions. - Updated code editor popup to refresh Codemirror instance layout after animation has completed. Fixes #1672 --- resources/js/components/overlay.js | 29 ++++++++--------------------- resources/js/services/animations.js | 16 ++++++++++++++++ resources/js/services/code.js | 11 ++++++++++- resources/js/vues/code-editor.js | 4 +++- 4 files changed, 37 insertions(+), 23 deletions(-) diff --git a/resources/js/components/overlay.js b/resources/js/components/overlay.js index ad6a01061..6963ba9d1 100644 --- a/resources/js/components/overlay.js +++ b/resources/js/components/overlay.js @@ -1,3 +1,4 @@ +import {fadeIn, fadeOut} from "../services/animations"; class Overlay { @@ -19,29 +20,15 @@ class Overlay { } } - hide() { this.toggle(false); } - show() { this.toggle(true); } + hide(onComplete = null) { this.toggle(false, onComplete); } + show(onComplete = null) { this.toggle(true, onComplete); } - toggle(show = true) { - let start = Date.now(); - let duration = 240; - - function setOpacity() { - let elapsedTime = (Date.now() - start); - let targetOpacity = show ? (elapsedTime / duration) : 1-(elapsedTime / duration); - this.container.style.opacity = targetOpacity; - if (elapsedTime > duration) { - this.container.style.display = show ? 'flex' : 'none'; - if (show) { - this.focusOnBody(); - } - this.container.style.opacity = ''; - } else { - requestAnimationFrame(setOpacity.bind(this)); - } + toggle(show = true, onComplete) { + if (show) { + fadeIn(this.container, 240, onComplete); + } else { + fadeOut(this.container, 240, onComplete); } - - requestAnimationFrame(setOpacity.bind(this)); } focusOnBody() { diff --git a/resources/js/services/animations.js b/resources/js/services/animations.js index b6158ea5f..278a765d5 100644 --- a/resources/js/services/animations.js +++ b/resources/js/services/animations.js @@ -5,6 +5,22 @@ */ const animateStylesCleanupMap = new WeakMap(); +/** + * Fade in the given element. + * @param {Element} element + * @param {Number} animTime + * @param {Function|null} onComplete + */ +export function fadeIn(element, animTime = 400, onComplete = null) { + cleanupExistingElementAnimation(element); + element.style.display = 'block'; + animateStyles(element, { + opacity: ['0', '1'] + }, animTime, () => { + if (onComplete) onComplete(); + }); +} + /** * Fade out the given element. * @param {Element} element diff --git a/resources/js/services/code.js b/resources/js/services/code.js index 3fcf74125..533940e3b 100644 --- a/resources/js/services/code.js +++ b/resources/js/services/code.js @@ -258,10 +258,18 @@ function setMode(cmInstance, modeSuggestion, content) { function setContent(cmInstance, codeContent) { cmInstance.setValue(codeContent); setTimeout(() => { - cmInstance.refresh(); + updateLayout(cmInstance); }, 10); } +/** + * Update the layout (codemirror refresh) of a cm instance. + * @param cmInstance + */ +function updateLayout(cmInstance) { + cmInstance.refresh(); +} + /** * Get a CodeMirror instance to use for the markdown editor. * @param {HTMLElement} elem @@ -301,6 +309,7 @@ export default { popupEditor: popupEditor, setMode: setMode, setContent: setContent, + updateLayout: updateLayout, markdownEditor: markdownEditor, getMetaKey: getMetaKey, }; diff --git a/resources/js/vues/code-editor.js b/resources/js/vues/code-editor.js index e0472a973..48b4e1766 100644 --- a/resources/js/vues/code-editor.js +++ b/resources/js/vues/code-editor.js @@ -3,7 +3,9 @@ import codeLib from "../services/code"; const methods = { show() { if (!this.editor) this.editor = codeLib.popupEditor(this.$refs.editor, this.language); - this.$refs.overlay.components.overlay.show(); + this.$refs.overlay.components.overlay.show(() => { + codeLib.updateLayout(this.editor); + }); }, hide() { this.$refs.overlay.components.overlay.hide(); From cee4dccc5543a237710ea4d84653b8af1738121a Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 7 Dec 2019 21:23:15 +0000 Subject: [PATCH 021/191] Compacted entity color options in settings view - Also extracted the view code into it's own blade template - Made smaller color input styles --- .../js/components/setting-app-color-picker.js | 2 +- resources/lang/en/settings.php | 8 +- resources/sass/_colors.scss | 5 ++ resources/sass/_forms.scss | 5 ++ .../setting-entity-color-picker.blade.php | 21 +++++ resources/views/settings/index.blade.php | 84 ++++--------------- 6 files changed, 48 insertions(+), 77 deletions(-) create mode 100644 resources/views/components/setting-entity-color-picker.blade.php diff --git a/resources/js/components/setting-app-color-picker.js b/resources/js/components/setting-app-color-picker.js index 02512e109..ee894c932 100644 --- a/resources/js/components/setting-app-color-picker.js +++ b/resources/js/components/setting-app-color-picker.js @@ -6,7 +6,7 @@ class SettingAppColorPicker { this.colorInput = elem.querySelector('input[type=color]'); this.lightColorInput = elem.querySelector('input[name="setting-app-color-light"]'); this.resetButton = elem.querySelector('[setting-app-color-picker-reset]'); - this.defaultButton = elem.querySelector('[setting-app-color-picker-default]') + this.defaultButton = elem.querySelector('[setting-app-color-picker-default]'); this.colorInput.addEventListener('change', this.updateColor.bind(this)); this.colorInput.addEventListener('input', this.updateColor.bind(this)); diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index efb849077..8255b4cbe 100755 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -42,17 +42,13 @@ return [ 'app_disable_comments_desc' => 'Disables comments across all pages in the application.
Existing comments are not shown.', // Color settings + 'content_colors' => 'Content Colors', + 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', 'bookshelf_color' => 'Shelf Color', - 'bookshelf_color_desc' => 'Sets the color indicator for shelves.', 'book_color' => 'Book Color', - 'book_color_desc' => 'Sets the color indicator for books.', 'chapter_color' => 'Chapter Color', - 'chapter_color_desc' => 'Sets the color indicator for chapters.', 'page_color' => 'Page Color', - 'page_color_desc' => 'Sets the color indicator for pages.', 'page_draft_color' => 'Page Draft Color', - 'page_draft_color_desc' => 'Sets the color indicator for page drafts.', - // Registration Settings 'reg_settings' => 'Registration', diff --git a/resources/sass/_colors.scss b/resources/sass/_colors.scss index 8623d374a..77f51b324 100644 --- a/resources/sass/_colors.scss +++ b/resources/sass/_colors.scss @@ -40,6 +40,11 @@ fill: #575757 !important; } +.text-dark { + color: #222 !important; + fill: #222 !important; +} + /* * Entity text colors */ diff --git a/resources/sass/_forms.scss b/resources/sass/_forms.scss index 64308b29e..1e0c908f9 100644 --- a/resources/sass/_forms.scss +++ b/resources/sass/_forms.scss @@ -172,6 +172,11 @@ input[type=date] { input[type=color] { height: 60px; + &.small { + height: 42px; + width: 60px; + padding: 2px; + } } .toggle-switch { diff --git a/resources/views/components/setting-entity-color-picker.blade.php b/resources/views/components/setting-entity-color-picker.blade.php new file mode 100644 index 000000000..fffb4220e --- /dev/null +++ b/resources/views/components/setting-entity-color-picker.blade.php @@ -0,0 +1,21 @@ +{{-- + @type - Name of entity type +--}} +
+
+ + + | + +
+
+ +
+
\ No newline at end of file diff --git a/resources/views/settings/index.blade.php b/resources/views/settings/index.blade.php index 4da1d90b0..1bc454385 100644 --- a/resources/views/settings/index.blade.php +++ b/resources/views/settings/index.blade.php @@ -146,78 +146,22 @@
- -
+ +
- -

{!! trans('settings.bookshelf_color_desc') !!}

+ +

{!! trans('settings.content_colors_desc') !!}

-
- -
- - | - -
-
- - -
-
- -

{!! trans('settings.book_color_desc') !!}

-
-
- -
- - | - -
-
- - -
-
- -

{!! trans('settings.chapter_color_desc') !!}

-
-
- -
- - | - -
-
- - -
-
- -

{!! trans('settings.page_color_desc') !!}

-
-
- -
- - | - -
-
- - -
-
- -

{!! trans('settings.page_draft_color_desc') !!}

-
-
- -
- - | - +
+
+ @include('components.setting-entity-color-picker', ['type' => 'bookshelf']) + @include('components.setting-entity-color-picker', ['type' => 'book']) + @include('components.setting-entity-color-picker', ['type' => 'chapter']) +
+
+ @include('components.setting-entity-color-picker', ['type' => 'page']) + @include('components.setting-entity-color-picker', ['type' => 'page-draft']) +
From 02af69ddf29e0a2d03cc3a8660bfca9a65175afc Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Wed, 11 Dec 2019 21:21:19 +0000 Subject: [PATCH 022/191] Added command to copy shelf permissions Has options to run for all or to specify a slug for a specific shelf. Closes #1091 --- app/Console/Commands/CopyShelfPermissions.php | 88 +++++++++++++++++++ app/Entities/Repos/BookshelfRepo.php | 6 +- tests/CommandsTest.php | 48 ++++++++++ 3 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 app/Console/Commands/CopyShelfPermissions.php diff --git a/app/Console/Commands/CopyShelfPermissions.php b/app/Console/Commands/CopyShelfPermissions.php new file mode 100644 index 000000000..d9a1c1d72 --- /dev/null +++ b/app/Console/Commands/CopyShelfPermissions.php @@ -0,0 +1,88 @@ +bookshelfRepo = $repo; + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + $shelfSlug = $this->option('slug'); + $cascadeAll = $this->option('all'); + $shelves = null; + + if (!$cascadeAll && !$shelfSlug) { + $this->error('Either a --slug or --all option must be provided.'); + return; + } + + if ($cascadeAll) { + $continue = $this->confirm( + 'Permission settings for all shelves will be cascaded. '. + 'Books assigned to multiple shelves will receive only the permissions of it\'s last processed shelf. '. + 'Are you sure you want to proceed?' + ); + + if (!$continue && !$this->hasOption('no-interaction')) { + return; + } + + $shelves = Bookshelf::query()->get(['id', 'restricted']); + } + + if ($shelfSlug) { + $shelves = Bookshelf::query()->where('slug', '=', $shelfSlug)->get(['id', 'restricted']); + if ($shelves->count() === 0) { + $this->info('No shelves found with the given slug.'); + } + } + + foreach ($shelves as $shelf) { + $this->bookshelfRepo->copyDownPermissions($shelf, false); + $this->info('Copied permissions for shelf [' . $shelf->id . ']'); + } + + $this->info('Permissions copied for ' . $shelves->count() . ' shelves.'); + } +} diff --git a/app/Entities/Repos/BookshelfRepo.php b/app/Entities/Repos/BookshelfRepo.php index ab4a51805..03b54f009 100644 --- a/app/Entities/Repos/BookshelfRepo.php +++ b/app/Entities/Repos/BookshelfRepo.php @@ -139,15 +139,15 @@ class BookshelfRepo /** * Copy down the permissions of the given shelf to all child books. */ - public function copyDownPermissions(Bookshelf $shelf): int + public function copyDownPermissions(Bookshelf $shelf, $checkUserPermissions = true): int { $shelfPermissions = $shelf->permissions()->get(['role_id', 'action'])->toArray(); - $shelfBooks = $shelf->books()->get(); + $shelfBooks = $shelf->books()->get(['id', 'restricted']); $updatedBookCount = 0; /** @var Book $book */ foreach ($shelfBooks as $book) { - if (!userCan('restrictions-manage', $book)) { + if ($checkUserPermissions && !userCan('restrictions-manage', $book)) { continue; } $book->permissions()->delete(); diff --git a/tests/CommandsTest.php b/tests/CommandsTest.php index 4aef0ed26..099af2939 100644 --- a/tests/CommandsTest.php +++ b/tests/CommandsTest.php @@ -1,6 +1,7 @@ assertTrue(User::where('email', '=', 'admintest@example.com')->first()->hasSystemRole('admin'), 'User has admin role as expected'); $this->assertTrue(\Auth::attempt(['email' => 'admintest@example.com', 'password' => 'testing-4']), 'Password stored as expected'); } + + public function test_copy_shelf_permissions_command_shows_error_when_no_required_option_given() + { + $this->artisan('bookstack:copy-shelf-permissions') + ->expectsOutput('Either a --slug or --all option must be provided.') + ->assertExitCode(0); + } + + public function test_copy_shelf_permissions_command_using_slug() + { + $shelf = Bookshelf::first(); + $child = $shelf->books()->first(); + $editorRole = $this->getEditor()->roles()->first(); + $this->assertFalse(boolval($child->restricted), "Child book should not be restricted by default"); + $this->assertTrue($child->permissions()->count() === 0, "Child book should have no permissions by default"); + + $this->setEntityRestrictions($shelf, ['view', 'update'], [$editorRole]); + $this->artisan('bookstack:copy-shelf-permissions', [ + '--slug' => $shelf->slug, + ]); + $child = $shelf->books()->first(); + + $this->assertTrue(boolval($child->restricted), "Child book should now be restricted"); + $this->assertTrue($child->permissions()->count() === 2, "Child book should have copied permissions"); + $this->assertDatabaseHas('entity_permissions', ['restrictable_id' => $child->id, 'action' => 'view', 'role_id' => $editorRole->id]); + $this->assertDatabaseHas('entity_permissions', ['restrictable_id' => $child->id, 'action' => 'update', 'role_id' => $editorRole->id]); + } + + public function test_copy_shelf_permissions_command_using_all() + { + $shelf = Bookshelf::query()->first(); + Bookshelf::query()->where('id', '!=', $shelf->id)->delete(); + $child = $shelf->books()->first(); + $editorRole = $this->getEditor()->roles()->first(); + $this->assertFalse(boolval($child->restricted), "Child book should not be restricted by default"); + $this->assertTrue($child->permissions()->count() === 0, "Child book should have no permissions by default"); + + $this->setEntityRestrictions($shelf, ['view', 'update'], [$editorRole]); + $this->artisan('bookstack:copy-shelf-permissions --all') + ->expectsQuestion('Permission settings for all shelves will be cascaded. Books assigned to multiple shelves will receive only the permissions of it\'s last processed shelf. Are you sure you want to proceed?', 'y'); + $child = $shelf->books()->first(); + + $this->assertTrue(boolval($child->restricted), "Child book should now be restricted"); + $this->assertTrue($child->permissions()->count() === 2, "Child book should have copied permissions"); + $this->assertDatabaseHas('entity_permissions', ['restrictable_id' => $child->id, 'action' => 'view', 'role_id' => $editorRole->id]); + $this->assertDatabaseHas('entity_permissions', ['restrictable_id' => $child->id, 'action' => 'update', 'role_id' => $editorRole->id]); + } } From f122bebae71cb0600bf62ac7c7f63384d8110b24 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 16 Dec 2019 11:44:28 +0000 Subject: [PATCH 023/191] Prevented whitespace in codeblocks being trimmed For #1771 --- resources/js/services/code.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/services/code.js b/resources/js/services/code.js index 533940e3b..93c3e431f 100644 --- a/resources/js/services/code.js +++ b/resources/js/services/code.js @@ -97,7 +97,7 @@ function highlight() { function highlightElem(elem) { const innerCodeElem = elem.querySelector('code[class^=language-]'); elem.innerHTML = elem.innerHTML.replace(//gi ,'\n'); - const content = elem.textContent.trim(); + const content = elem.textContent; let mode = ''; if (innerCodeElem !== null) { From 017703ff1a697d825219a9fd9d68d778b12e8733 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 16 Dec 2019 11:54:53 +0000 Subject: [PATCH 024/191] Updated page delete to return to chapter if within one - Added test to cover Closes #1715 --- app/Http/Controllers/PageController.php | 3 ++- tests/Entity/EntityTest.php | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/PageController.php b/app/Http/Controllers/PageController.php index 630f888ed..b216c19a8 100644 --- a/app/Http/Controllers/PageController.php +++ b/app/Http/Controllers/PageController.php @@ -304,11 +304,12 @@ class PageController extends Controller $this->checkOwnablePermission('page-delete', $page); $book = $page->book; + $parent = $page->chapter ?? $book; $this->pageRepo->destroy($page); Activity::addMessage('page_delete', $page->name, $book->id); $this->showSuccessNotification(trans('entities.pages_delete_success')); - return redirect($book->getUrl()); + return redirect($parent->getUrl()); } /** diff --git a/tests/Entity/EntityTest.php b/tests/Entity/EntityTest.php index 3d12ed749..97684ea4d 100644 --- a/tests/Entity/EntityTest.php +++ b/tests/Entity/EntityTest.php @@ -315,4 +315,14 @@ class EntityTest extends BrowserKitTest ->seePageIs($book->getUrl()); } + public function test_page_within_chapter_deletion_returns_to_chapter() + { + $chapter = Chapter::query()->first(); + $page = $chapter->pages()->first(); + + $this->asEditor()->visit($page->getUrl('/delete')) + ->submitForm('Confirm') + ->seePageIs($chapter->getUrl()); + } + } From f9fa6904b95409908e1ad8cbb344c7d1773bfc66 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 16 Dec 2019 12:38:35 +0000 Subject: [PATCH 025/191] Made LDAP auth ID attribute configurable - Allows the field that gets stored as the "External Authentication ID" to be configurable. Defined as LDAP_ID_ATTRIBUTE=uid in .env. - Added test to cover usage. - Also now auto-lowercases when searching for attributes in LDAP response since PHP always provides them as lower case. Closes #592. --- .env.example.complete | 1 + app/Auth/Access/LdapService.php | 101 ++++++++++++-------------------- app/Config/services.php | 1 + tests/Auth/LdapTest.php | 29 ++++++++- 4 files changed, 66 insertions(+), 66 deletions(-) diff --git a/.env.example.complete b/.env.example.complete index e8c212f39..a13c8b7d0 100644 --- a/.env.example.complete +++ b/.env.example.complete @@ -191,6 +191,7 @@ LDAP_PASS=false LDAP_USER_FILTER=false LDAP_VERSION=false LDAP_TLS_INSECURE=false +LDAP_ID_ATTRIBUTE=uid LDAP_EMAIL_ATTRIBUTE=mail LDAP_DISPLAY_NAME_ATTRIBUTE=cn LDAP_FOLLOW_REFERRALS=true diff --git a/app/Auth/Access/LdapService.php b/app/Auth/Access/LdapService.php index b0700322f..554bc4b48 100644 --- a/app/Auth/Access/LdapService.php +++ b/app/Auth/Access/LdapService.php @@ -1,17 +1,16 @@ ldap = $ldap; $this->config = config('services.ldap'); @@ -43,13 +40,10 @@ class LdapService extends Access\ExternalAuthService } /** - * Search for attributes for a specific user on the ldap - * @param string $userName - * @param array $attributes - * @return null|array + * Search for attributes for a specific user on the ldap. * @throws LdapException */ - private function getUserWithAttributes($userName, $attributes) + private function getUserWithAttributes(string $userName, array $attributes): ?array { $ldapConnection = $this->getConnection(); $this->bindSystemUser($ldapConnection); @@ -71,16 +65,15 @@ class LdapService extends Access\ExternalAuthService /** * Get the details of a user from LDAP using the given username. * User found via configurable user filter. - * @param $userName - * @return array|null * @throws LdapException */ - public function getUserDetails($userName) + public function getUserDetails(string $userName): ?array { + $idAttr = $this->config['id_attribute']; $emailAttr = $this->config['email_attribute']; $displayNameAttr = $this->config['display_name_attribute']; - $user = $this->getUserWithAttributes($userName, ['cn', 'uid', 'dn', $emailAttr, $displayNameAttr]); + $user = $this->getUserWithAttributes($userName, ['cn', 'dn', $idAttr, $emailAttr, $displayNameAttr]); if ($user === null) { return null; @@ -88,7 +81,7 @@ class LdapService extends Access\ExternalAuthService $userCn = $this->getUserResponseProperty($user, 'cn', null); return [ - 'uid' => $this->getUserResponseProperty($user, 'uid', $user['dn']), + 'uid' => $this->getUserResponseProperty($user, $idAttr, $user['dn']), 'name' => $this->getUserResponseProperty($user, $displayNameAttr, $userCn), 'dn' => $user['dn'], 'email' => $this->getUserResponseProperty($user, $emailAttr, null), @@ -98,13 +91,10 @@ class LdapService extends Access\ExternalAuthService /** * Get a property from an LDAP user response fetch. * Handles properties potentially being part of an array. - * @param array $userDetails - * @param string $propertyKey - * @param $defaultValue - * @return mixed */ protected function getUserResponseProperty(array $userDetails, string $propertyKey, $defaultValue) { + $propertyKey = strtolower($propertyKey); if (isset($userDetails[$propertyKey])) { return (is_array($userDetails[$propertyKey]) ? $userDetails[$propertyKey][0] : $userDetails[$propertyKey]); } @@ -113,13 +103,10 @@ class LdapService extends Access\ExternalAuthService } /** - * @param Authenticatable $user - * @param string $username - * @param string $password - * @return bool + * Check if the given credentials are valid for the given user. * @throws LdapException */ - public function validateUserCredentials(Authenticatable $user, $username, $password) + public function validateUserCredentials(Authenticatable $user, string $username, string $password): bool { $ldapUser = $this->getUserDetails($username); if ($ldapUser === null) { @@ -133,7 +120,7 @@ class LdapService extends Access\ExternalAuthService $ldapConnection = $this->getConnection(); try { $ldapBind = $this->ldap->bind($ldapConnection, $ldapUser['dn'], $password); - } catch (\ErrorException $e) { + } catch (ErrorException $e) { $ldapBind = false; } @@ -203,12 +190,10 @@ class LdapService extends Access\ExternalAuthService } /** - * Parse a LDAP server string and return the host and port for - * a connection. Is flexible to formats such as 'ldap.example.com:8069' or 'ldaps://ldap.example.com' - * @param $serverString - * @return array + * Parse a LDAP server string and return the host and port for a connection. + * Is flexible to formats such as 'ldap.example.com:8069' or 'ldaps://ldap.example.com'. */ - protected function parseServerString($serverString) + protected function parseServerString(string $serverString): array { $serverNameParts = explode(':', $serverString); @@ -225,11 +210,8 @@ class LdapService extends Access\ExternalAuthService /** * Build a filter string by injecting common variables. - * @param string $filterString - * @param array $attrs - * @return string */ - protected function buildFilter($filterString, array $attrs) + protected function buildFilter(string $filterString, array $attrs): string { $newAttrs = []; foreach ($attrs as $key => $attrText) { @@ -240,12 +222,10 @@ class LdapService extends Access\ExternalAuthService } /** - * Get the groups a user is a part of on ldap - * @param string $userName - * @return array + * Get the groups a user is a part of on ldap. * @throws LdapException */ - public function getUserGroups($userName) + public function getUserGroups(string $userName): array { $groupsAttr = $this->config['group_attribute']; $user = $this->getUserWithAttributes($userName, [$groupsAttr]); @@ -260,40 +240,36 @@ class LdapService extends Access\ExternalAuthService } /** - * Get the parent groups of an array of groups - * @param array $groupsArray - * @param array $checked - * @return array + * Get the parent groups of an array of groups. * @throws LdapException */ - private function getGroupsRecursive($groupsArray, $checked) + private function getGroupsRecursive(array $groupsArray, array $checked): array { - $groups_to_add = []; + $groupsToAdd = []; foreach ($groupsArray as $groupName) { if (in_array($groupName, $checked)) { continue; } - $groupsToAdd = $this->getGroupGroups($groupName); - $groups_to_add = array_merge($groups_to_add, $groupsToAdd); + $parentGroups = $this->getGroupGroups($groupName); + $groupsToAdd = array_merge($groupsToAdd, $parentGroups); $checked[] = $groupName; } - $groupsArray = array_unique(array_merge($groupsArray, $groups_to_add), SORT_REGULAR); - if (!empty($groups_to_add)) { - return $this->getGroupsRecursive($groupsArray, $checked); - } else { + $groupsArray = array_unique(array_merge($groupsArray, $groupsToAdd), SORT_REGULAR); + + if (empty($groupsToAdd)) { return $groupsArray; } + + return $this->getGroupsRecursive($groupsArray, $checked); } /** - * Get the parent groups of a single group - * @param string $groupName - * @return array + * Get the parent groups of a single group. * @throws LdapException */ - private function getGroupGroups($groupName) + private function getGroupGroups(string $groupName): array { $ldapConnection = $this->getConnection(); $this->bindSystemUser($ldapConnection); @@ -310,17 +286,14 @@ class LdapService extends Access\ExternalAuthService return []; } - $groupGroups = $this->groupFilter($groups[0]); - return $groupGroups; + return $this->groupFilter($groups[0]); } /** - * Filter out LDAP CN and DN language in a ldap search return - * Gets the base CN (common name) of the string - * @param array $userGroupSearchResponse - * @return array + * Filter out LDAP CN and DN language in a ldap search return. + * Gets the base CN (common name) of the string. */ - protected function groupFilter(array $userGroupSearchResponse) + protected function groupFilter(array $userGroupSearchResponse): array { $groupsAttr = strtolower($this->config['group_attribute']); $ldapGroups = []; @@ -341,9 +314,7 @@ class LdapService extends Access\ExternalAuthService } /** - * Sync the LDAP groups to the user roles for the current user - * @param \BookStack\Auth\User $user - * @param string $username + * Sync the LDAP groups to the user roles for the current user. * @throws LdapException */ public function syncGroups(User $user, string $username) diff --git a/app/Config/services.php b/app/Config/services.php index a3ddf4f4d..a0bdd078a 100644 --- a/app/Config/services.php +++ b/app/Config/services.php @@ -123,6 +123,7 @@ return [ 'base_dn' => env('LDAP_BASE_DN', false), 'user_filter' => env('LDAP_USER_FILTER', '(&(uid=${user}))'), 'version' => env('LDAP_VERSION', false), + 'id_attribute' => env('LDAP_ID_ATTRIBUTE', 'uid'), 'email_attribute' => env('LDAP_EMAIL_ATTRIBUTE', 'mail'), 'display_name_attribute' => env('LDAP_DISPLAY_NAME_ATTRIBUTE', 'cn'), 'follow_referrals' => env('LDAP_FOLLOW_REFERRALS', false), diff --git a/tests/Auth/LdapTest.php b/tests/Auth/LdapTest.php index fe28698df..5d7bbfb1e 100644 --- a/tests/Auth/LdapTest.php +++ b/tests/Auth/LdapTest.php @@ -24,6 +24,7 @@ class LdapTest extends BrowserKitTest 'services.ldap.base_dn' => 'dc=ldap,dc=local', 'services.ldap.email_attribute' => 'mail', 'services.ldap.display_name_attribute' => 'cn', + 'services.ldap.id_attribute' => 'uid', 'services.ldap.user_to_groups' => false, 'auth.providers.users.driver' => 'ldap', ]); @@ -102,6 +103,32 @@ class LdapTest extends BrowserKitTest ->seeInDatabase('users', ['email' => $this->mockUser->email, 'email_confirmed' => false, 'external_auth_id' => $ldapDn]); } + public function test_a_custom_uid_attribute_can_be_specified_and_is_used_properly() + { + config()->set(['services.ldap.id_attribute' => 'my_custom_id']); + $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId); + $this->mockLdap->shouldReceive('setVersion')->once(); + $ldapDn = 'cn=test-user,dc=test' . config('services.ldap.base_dn'); + $this->mockLdap->shouldReceive('setOption')->times(2); + $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2) + ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) + ->andReturn(['count' => 1, 0 => [ + 'cn' => [$this->mockUser->name], + 'dn' => $ldapDn, + 'my_custom_id' => ['cooluser456'], + 'mail' => [$this->mockUser->email] + ]]); + + + $this->mockLdap->shouldReceive('bind')->times(3)->andReturn(true); + $this->mockEscapes(2); + + $this->mockUserLogin() + ->seePageIs('/') + ->see($this->mockUser->name) + ->seeInDatabase('users', ['email' => $this->mockUser->email, 'email_confirmed' => false, 'external_auth_id' => 'cooluser456']); + } + public function test_initial_incorrect_details() { $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId); @@ -365,7 +392,7 @@ class LdapTest extends BrowserKitTest 'uid' => [$this->mockUser->name], 'cn' => [$this->mockUser->name], 'dn' => ['dc=test' . config('services.ldap.base_dn')], - 'displayName' => 'displayNameAttribute' + 'displayname' => 'displayNameAttribute' ]]); $this->mockLdap->shouldReceive('bind')->times(6)->andReturn(true); $this->mockEscapes(4); From a9634b6b6625c98448cd1a1927b9b7d6b1609757 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 16 Dec 2019 13:15:11 +0000 Subject: [PATCH 026/191] Set a default outline color and width - Applied since the browser defaults caused outlines to appear very large in some cases. - Set default color to use app primary color, to help them blend into the design a little. For #1738 --- resources/sass/_html.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/sass/_html.scss b/resources/sass/_html.scss index de48c8ed1..e4a8c14bb 100644 --- a/resources/sass/_html.scss +++ b/resources/sass/_html.scss @@ -1,6 +1,7 @@ * { box-sizing: border-box; - outline-color: #444444; + outline-color: var(--color-primary); + outline-width: 1px; } *:focus { From b93f8a4d4680cfe34e3b64db95f0f9683152c22a Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 16 Dec 2019 13:27:17 +0000 Subject: [PATCH 027/191] Auto-expand collapsible sections if containing error For #1693 --- resources/js/components/collapsible.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/resources/js/components/collapsible.js b/resources/js/components/collapsible.js index 464f394c1..a630f38f2 100644 --- a/resources/js/components/collapsible.js +++ b/resources/js/components/collapsible.js @@ -12,8 +12,8 @@ class Collapsible { this.content = elem.querySelector('[collapsible-content]'); if (!this.trigger) return; - this.trigger.addEventListener('click', this.toggle.bind(this)); + this.openIfContainsError(); } open() { @@ -36,6 +36,13 @@ class Collapsible { } } + openIfContainsError() { + const error = this.content.querySelector('.text-neg'); + if (error) { + this.open(); + } + } + } export default Collapsible; \ No newline at end of file From 50ed56f65dc736e9b0db5902ca8360b0e1300ac8 Mon Sep 17 00:00:00 2001 From: Zero Date: Tue, 17 Dec 2019 16:52:39 +0800 Subject: [PATCH 028/191] update translation --- resources/lang/zh_TW/entities.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/lang/zh_TW/entities.php b/resources/lang/zh_TW/entities.php index 8d49ff2ff..725e4aee9 100644 --- a/resources/lang/zh_TW/entities.php +++ b/resources/lang/zh_TW/entities.php @@ -74,7 +74,7 @@ return [ 'shelves_create' => '建立書架', 'shelves_popular' => '熱門書架', 'shelves_new' => '新書架', - 'shelves_new_action' => 'New Shelf', + 'shelves_new_action' => '建立新的書架', 'shelves_popular_empty' => '最受歡迎的書架將出現在這裡。', 'shelves_new_empty' => '最近建立的書架將出現在這裡。', 'shelves_save' => '儲存書架', @@ -105,7 +105,7 @@ return [ 'books_popular' => '熱門書本', 'books_recent' => '最近的書', 'books_new' => '新書', - 'books_new_action' => 'New Book', + 'books_new_action' => '新增一本書', 'books_popular_empty' => '最受歡迎的書本將出現在這裡。', 'books_new_empty' => '最近建立的書本將出現在這裡。', 'books_create' => '建立書本', @@ -311,4 +311,4 @@ return [ 'revision_restore_confirm' => 'Are you sure you want to restore this revision? The current page contents will be replaced.', 'revision_delete_success' => '修訂刪除', 'revision_cannot_delete_latest' => '無法刪除最新版本。' -]; \ No newline at end of file +]; From ceeb9d35a0f9c99a1b14a07f4df70b4e1af39719 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 21 Dec 2019 13:30:41 +0000 Subject: [PATCH 029/191] Updated JS dependancies --- package-lock.json | 1636 ++++++++++++++++++++------------------------- package.json | 26 +- 2 files changed, 756 insertions(+), 906 deletions(-) diff --git a/package-lock.json b/package-lock.json index 47afc27a1..7142eebd2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -197,21 +197,15 @@ "dev": true }, "acorn": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", - "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", - "dev": true - }, - "acorn-dynamic-import": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", - "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz", + "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==", "dev": true }, "ajv": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", - "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -221,15 +215,15 @@ } }, "ajv-errors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.0.tgz", - "integrity": "sha1-7PAh+hCP0X37Xms4Py3SM+Mf/Fk=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", "dev": true }, "ajv-keywords": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.1.0.tgz", - "integrity": "sha1-rCsnk5xUPpXSwG5/f1wnvkqlQ74=", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", "dev": true }, "amdefine": { @@ -406,9 +400,9 @@ "dev": true }, "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "dev": true }, "async-foreach": { @@ -417,6 +411,12 @@ "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", "dev": true }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -436,9 +436,9 @@ "dev": true }, "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz", + "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==", "dev": true }, "balanced-match": { @@ -499,19 +499,13 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true } } }, "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", "dev": true }, "bcrypt-pbkdf": { @@ -524,17 +518,27 @@ } }, "big.js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true }, "binary-extensions": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.10.0.tgz", - "integrity": "sha1-muuabF6IY4qtFx4Wf1kAq+JINdA=", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, "block-stream": { "version": "0.0.9", "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", @@ -545,9 +549,9 @@ } }, "bluebird": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", - "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, "bn.js": { @@ -636,14 +640,6 @@ "des.js": "^1.0.0", "inherits": "^2.0.1", "safe-buffer": "^5.1.2" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } } }, "browserify-rsa": { @@ -681,9 +677,9 @@ } }, "buffer": { - "version": "4.9.1", - "resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", "dev": true, "requires": { "base64-js": "^1.0.2", @@ -716,31 +712,32 @@ "dev": true }, "cacache": { - "version": "11.3.2", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz", - "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==", + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz", + "integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==", "dev": true, "requires": { - "bluebird": "^3.5.3", + "bluebird": "^3.5.5", "chownr": "^1.1.1", "figgy-pudding": "^3.5.1", - "glob": "^7.1.3", + "glob": "^7.1.4", "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", "lru-cache": "^5.1.1", "mississippi": "^3.0.0", "mkdirp": "^0.5.1", "move-concurrently": "^1.0.1", "promise-inflight": "^1.0.1", - "rimraf": "^2.6.2", + "rimraf": "^2.6.3", "ssri": "^6.0.1", "unique-filename": "^1.1.1", "y18n": "^4.0.0" }, "dependencies": { "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", "dev": true }, "lru-cache": { @@ -759,9 +756,9 @@ "dev": true }, "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true } } @@ -825,9 +822,9 @@ } }, "chokidar": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz", - "integrity": "sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "dev": true, "requires": { "anymatch": "^2.0.0", @@ -845,9 +842,9 @@ } }, "chownr": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", - "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", + "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==", "dev": true }, "chrome-trace-event": { @@ -914,23 +911,14 @@ } }, "clone-deep": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz", - "integrity": "sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "dev": true, "requires": { - "for-own": "^1.0.0", "is-plain-object": "^2.0.4", - "kind-of": "^6.0.0", - "shallow-clone": "^1.0.0" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" } }, "code-point-at": { @@ -940,9 +928,9 @@ "dev": true }, "codemirror": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.47.0.tgz", - "integrity": "sha512-kV49Fr+NGFHFc/Imsx6g180hSlkGhuHxTSDDmDHOuyln0MQYFLixDY4+bFkBVeCEiepYfDimAF/e++9jPJk4QA==" + "version": "5.50.0", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.50.0.tgz", + "integrity": "sha512-32LAmGcBNhKtJP4WGgkcaCVQDyChAyaWA6jasg778ziZzo3PWBuhpAQIJMO8//Id45RoaLyXjuhcRUBoS8Vg+Q==" }, "collection-visit": { "version": "1.0.0", @@ -979,9 +967,9 @@ } }, "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, "commondir": { @@ -1015,13 +1003,10 @@ } }, "console-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", - "dev": true, - "requires": { - "date-now": "^0.1.4" - } + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true }, "console-control-strings": { "version": "1.1.0", @@ -1128,56 +1113,23 @@ } }, "css-loader": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-2.1.1.tgz", - "integrity": "sha512-OcKJU/lt232vl1P9EEDamhoO9iKY3tIjY5GU+XDLblAykTdgs6Ux9P1hTHve8nFKy5KPpOXOsVI/hIwi3841+w==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.4.0.tgz", + "integrity": "sha512-JornYo4RAXl1Mzt0lOSVPmArzAMV3rGY2VuwtaDc732WTWjdwTaeS19nCGWMcSCf305Q396lhhDAJEWWM0SgPQ==", "dev": true, "requires": { - "camelcase": "^5.2.0", - "icss-utils": "^4.1.0", + "camelcase": "^5.3.1", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", "loader-utils": "^1.2.3", "normalize-path": "^3.0.0", - "postcss": "^7.0.14", + "postcss": "^7.0.23", "postcss-modules-extract-imports": "^2.0.0", - "postcss-modules-local-by-default": "^2.0.6", - "postcss-modules-scope": "^2.1.0", - "postcss-modules-values": "^2.0.0", - "postcss-value-parser": "^3.3.0", - "schema-utils": "^1.0.0" - }, - "dependencies": { - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true - }, - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "loader-utils": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", - "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^2.0.0", - "json5": "^1.0.1" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } + "postcss-modules-local-by-default": "^3.0.2", + "postcss-modules-scope": "^2.1.1", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.0.2", + "schema-utils": "^2.6.0" } }, "cssesc": { @@ -1196,9 +1148,9 @@ } }, "cyclist": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", - "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", "dev": true }, "dashdash": { @@ -1210,12 +1162,6 @@ "assert-plus": "^1.0.0" } }, - "date-now": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", - "dev": true - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -1284,12 +1230,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true } } }, @@ -1311,9 +1251,9 @@ "dev": true }, "des.js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", - "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", "dev": true, "requires": { "inherits": "^2.0.1", @@ -1371,9 +1311,9 @@ } }, "elliptic": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", - "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", + "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", "dev": true, "requires": { "bn.js": "^4.4.0", @@ -1385,6 +1325,12 @@ "minimalistic-crypto-utils": "^1.0.0" } }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "emojis-list": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", @@ -1392,29 +1338,41 @@ "dev": true }, "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, "requires": { "once": "^1.4.0" } }, "enhanced-resolve": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", - "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz", + "integrity": "sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA==", "dev": true, "requires": { "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", + "memory-fs": "^0.5.0", "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } } }, "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", + "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==" }, "errno": { "version": "0.1.7", @@ -1484,9 +1442,9 @@ } }, "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, "events": { @@ -1668,12 +1626,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true } } }, @@ -1690,9 +1642,9 @@ "dev": true }, "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, "figgy-pudding": { @@ -1701,6 +1653,13 @@ "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", "dev": true }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -1736,66 +1695,25 @@ } }, "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { - "locate-path": "^3.0.0" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", "dev": true, "requires": { "detect-file": "^1.0.0", - "is-glob": "^3.1.0", + "is-glob": "^4.0.0", "micromatch": "^3.0.4", "resolve-dir": "^1.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } } }, "flush-write-stream": { @@ -1806,38 +1724,6 @@ "requires": { "inherits": "^2.0.3", "readable-stream": "^2.3.6" - }, - "dependencies": { - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } } }, "for-in": { @@ -1846,15 +1732,6 @@ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "dev": true, - "requires": { - "for-in": "^1.0.1" - } - }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -1910,14 +1787,15 @@ "dev": true }, "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.11.tgz", + "integrity": "sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==", "dev": true, "optional": true, "requires": { + "bindings": "^1.5.0", "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" + "node-pre-gyp": "*" }, "dependencies": { "abbrev": { @@ -1965,7 +1843,7 @@ } }, "chownr": { - "version": "1.1.1", + "version": "1.1.3", "bundled": true, "dev": true, "optional": true @@ -1995,7 +1873,7 @@ "optional": true }, "debug": { - "version": "4.1.1", + "version": "3.2.6", "bundled": true, "dev": true, "optional": true, @@ -2022,12 +1900,12 @@ "optional": true }, "fs-minipass": { - "version": "1.2.5", + "version": "1.2.7", "bundled": true, "dev": true, "optional": true, "requires": { - "minipass": "^2.2.1" + "minipass": "^2.6.0" } }, "fs.realpath": { @@ -2053,7 +1931,7 @@ } }, "glob": { - "version": "7.1.3", + "version": "7.1.6", "bundled": true, "dev": true, "optional": true, @@ -2082,7 +1960,7 @@ } }, "ignore-walk": { - "version": "3.0.1", + "version": "3.0.3", "bundled": true, "dev": true, "optional": true, @@ -2101,7 +1979,7 @@ } }, "inherits": { - "version": "2.0.3", + "version": "2.0.4", "bundled": true, "dev": true, "optional": true @@ -2143,7 +2021,7 @@ "optional": true }, "minipass": { - "version": "2.3.5", + "version": "2.9.0", "bundled": true, "dev": true, "optional": true, @@ -2153,12 +2031,12 @@ } }, "minizlib": { - "version": "1.2.1", + "version": "1.3.3", "bundled": true, "dev": true, "optional": true, "requires": { - "minipass": "^2.2.1" + "minipass": "^2.9.0" } }, "mkdirp": { @@ -2171,24 +2049,24 @@ } }, "ms": { - "version": "2.1.1", + "version": "2.1.2", "bundled": true, "dev": true, "optional": true }, "needle": { - "version": "2.3.0", + "version": "2.4.0", "bundled": true, "dev": true, "optional": true, "requires": { - "debug": "^4.1.0", + "debug": "^3.2.6", "iconv-lite": "^0.4.4", "sax": "^1.2.4" } }, "node-pre-gyp": { - "version": "0.12.0", + "version": "0.14.0", "bundled": true, "dev": true, "optional": true, @@ -2202,7 +2080,7 @@ "rc": "^1.2.7", "rimraf": "^2.6.1", "semver": "^5.3.0", - "tar": "^4" + "tar": "^4.4.2" } }, "nopt": { @@ -2216,13 +2094,22 @@ } }, "npm-bundled": { - "version": "1.0.6", + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", "bundled": true, "dev": true, "optional": true }, "npm-packlist": { - "version": "1.4.1", + "version": "1.4.7", "bundled": true, "dev": true, "optional": true, @@ -2293,7 +2180,7 @@ "optional": true }, "process-nextick-args": { - "version": "2.0.0", + "version": "2.0.1", "bundled": true, "dev": true, "optional": true @@ -2334,7 +2221,7 @@ } }, "rimraf": { - "version": "2.6.3", + "version": "2.7.1", "bundled": true, "dev": true, "optional": true, @@ -2361,7 +2248,7 @@ "optional": true }, "semver": { - "version": "5.7.0", + "version": "5.7.1", "bundled": true, "dev": true, "optional": true @@ -2414,18 +2301,18 @@ "optional": true }, "tar": { - "version": "4.4.8", + "version": "4.4.13", "bundled": true, "dev": true, "optional": true, "requires": { "chownr": "^1.1.1", "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", "mkdirp": "^0.5.0", "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" + "yallist": "^3.0.3" } }, "util-deprecate": { @@ -2450,7 +2337,7 @@ "optional": true }, "yallist": { - "version": "3.0.3", + "version": "3.1.1", "bundled": true, "dev": true, "optional": true @@ -2537,9 +2424,9 @@ } }, "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -2572,14 +2459,25 @@ } }, "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", "dev": true, "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" + "global-prefix": "^3.0.0" + }, + "dependencies": { + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + } + } } }, "global-prefix": { @@ -2596,9 +2494,9 @@ } }, "globule": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", - "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.0.tgz", + "integrity": "sha512-YlD4kdMqRCQHrhVdonet4TdRtv1/sZKepvoxNT4Nrhrp5HI8XFfc8kFlGlBn2myBo80aGp8Eft259mbcUJhgSg==", "dev": true, "requires": { "glob": "~7.1.1", @@ -2767,12 +2665,6 @@ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", "dev": true }, - "icss-replace-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", - "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", - "dev": true - }, "icss-utils": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", @@ -2831,10 +2723,10 @@ "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", "dev": true }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", "dev": true }, "inflight": { @@ -2848,9 +2740,9 @@ } }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, "ini": { @@ -2878,6 +2770,17 @@ "dev": true, "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "is-arrayish": { @@ -2923,6 +2826,17 @@ "dev": true, "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "is-date-object": { @@ -2996,6 +2910,17 @@ "dev": true, "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "is-plain-obj": { @@ -3122,10 +3047,13 @@ "dev": true }, "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } }, "jsonify": { "version": "0.0.0", @@ -3146,13 +3074,10 @@ } }, "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true }, "lcid": { "version": "1.0.0", @@ -3164,22 +3089,22 @@ } }, "linkify-it": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz", - "integrity": "sha1-2UpGSPmxwXnWT6lykSaL22zpQ08=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", "requires": { "uc.micro": "^1.0.1" } }, "livereload": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/livereload/-/livereload-0.8.0.tgz", - "integrity": "sha512-Hi5Na6VIK3e8zlgOS50fu+iOTKWj5hM0BE7NKpZkwnfWTnktTjA38ZUXa2NlJww8/GrdVhpnxdqlLad5fkO27g==", + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/livereload/-/livereload-0.8.2.tgz", + "integrity": "sha512-8wCvhiCL4cGVoT3U5xoe+UjpiiVZLrlOvr6dbhb1VlyC5QarhrlyRRt4z7EMGO4KSgXj+tKF/dr284F28/wI+g==", "dev": true, "requires": { "chokidar": "^2.1.5", "opts": ">= 1.2.0", - "ws": "^1.1.5" + "ws": "^6.2.1" } }, "load-json-file": { @@ -3210,14 +3135,14 @@ "dev": true }, "loader-utils": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", - "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", "dev": true, "requires": { - "big.js": "^3.1.3", + "big.js": "^5.2.2", "emojis-list": "^2.0.0", - "json5": "^0.5.0" + "json5": "^1.0.1" } }, "locate-path": { @@ -3228,6 +3153,14 @@ "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } } }, "lodash": { @@ -3236,12 +3169,6 @@ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, - "lodash.tail": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz", - "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=", - "dev": true - }, "loud-rejection": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", @@ -3317,12 +3244,12 @@ } }, "markdown-it": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", - "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", + "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", "requires": { "argparse": "^1.0.7", - "entities": "~1.1.1", + "entities": "~2.0.0", "linkify-it": "^2.0.0", "mdurl": "^1.0.1", "uc.micro": "^1.0.5" @@ -3342,14 +3269,6 @@ "hash-base": "^3.0.0", "inherits": "^2.0.1", "safe-buffer": "^5.1.2" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } } }, "mdurl": { @@ -3400,14 +3319,6 @@ "read-pkg-up": "^1.0.1", "redent": "^1.0.0", "trim-newlines": "^1.0.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } } }, "micromatch": { @@ -3429,14 +3340,6 @@ "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } } }, "miller-rabin": { @@ -3450,18 +3353,18 @@ } }, "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "version": "1.42.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", + "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==", "dev": true }, "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "version": "2.1.25", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", + "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", "dev": true, "requires": { - "mime-db": "1.40.0" + "mime-db": "1.42.0" } }, "mimic-fn": { @@ -3471,15 +3374,28 @@ "dev": true }, "mini-css-extract-plugin": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.7.0.tgz", - "integrity": "sha512-RQIw6+7utTYn8DBGsf/LpRgZCJMpZt+kuawJ/fju0KiOL6nAaTBNmCJwS7HtwSCXfS47gCkmtBFS7HdsquhdxQ==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz", + "integrity": "sha512-lp3GeY7ygcgAmVIcRPBVhIkf8Us7FZjA+ILpal44qLdSu11wmjKQ3d9k15lfD7pO4esu9eUIAW7qiYIBppv40A==", "dev": true, "requires": { "loader-utils": "^1.1.0", "normalize-url": "1.9.1", "schema-utils": "^1.0.0", "webpack-sources": "^1.1.0" + }, + "dependencies": { + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } } }, "minimalistic-assert": { @@ -3504,9 +3420,9 @@ } }, "minimist": { - "version": "0.0.8", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, "mississippi": { @@ -3548,24 +3464,6 @@ } } }, - "mixin-object": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", - "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", - "dev": true, - "requires": { - "for-in": "^0.1.3", - "is-extendable": "^0.1.1" - }, - "dependencies": { - "for-in": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", - "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=", - "dev": true - } - } - }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", @@ -3573,6 +3471,14 @@ "dev": true, "requires": { "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } } }, "move-concurrently": { @@ -3618,20 +3524,12 @@ "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } } }, "neo-async": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz", - "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", "dev": true }, "nice-try": { @@ -3669,9 +3567,9 @@ } }, "node-libs-browser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.0.tgz", - "integrity": "sha512-5MQunG/oyOaBdttrL40dA7bUfPORLRWMUJLQtMg7nluxUvk5XwnLdL9twQHFAjRx/y7mIMkLKT9++qPbbk6BZA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", "dev": true, "requires": { "assert": "^1.1.1", @@ -3684,7 +3582,7 @@ "events": "^3.0.0", "https-browserify": "^1.0.0", "os-browserify": "^0.3.0", - "path-browserify": "0.0.0", + "path-browserify": "0.0.1", "process": "^0.11.10", "punycode": "^1.2.4", "querystring-es3": "^0.2.0", @@ -3696,13 +3594,21 @@ "tty-browserify": "0.0.0", "url": "^0.11.0", "util": "^0.11.0", - "vm-browserify": "0.0.4" + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } } }, "node-sass": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.12.0.tgz", - "integrity": "sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.0.tgz", + "integrity": "sha512-W1XBrvoJ1dy7VsvTAS5q1V45lREbTlZQqFbiHb3R3OTTCma0XBtuG6xZ6Z4506nR4lmHPTqVRwxT6KgtWC97CA==", "dev": true, "requires": { "async-foreach": "^0.1.3", @@ -3712,7 +3618,7 @@ "get-stdin": "^4.0.1", "glob": "^7.0.3", "in-publish": "^2.0.0", - "lodash": "^4.17.11", + "lodash": "^4.17.15", "meow": "^3.7.0", "mkdirp": "^0.5.1", "nan": "^2.13.2", @@ -3928,6 +3834,15 @@ "requires": { "is-descriptor": "^0.1.0" } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } } } }, @@ -3964,16 +3879,10 @@ "wrappy": "1" } }, - "options": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", - "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", - "dev": true - }, "opts": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/opts/-/opts-1.2.6.tgz", - "integrity": "sha1-0YXAQlz9652h0YKQi2W1wCOP67M=", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/opts/-/opts-1.2.7.tgz", + "integrity": "sha512-hwZhzGGG/GQ7igxAVFOEun2N4fWul31qE9nfBdCnZGQCB5+L7tN9xZ+94B4aUpLOJx/of3zZs5XsuubayQYQjA==", "dev": true }, "os-browserify": { @@ -4032,9 +3941,9 @@ "dev": true }, "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -4062,20 +3971,20 @@ "dev": true }, "parallel-transform": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", - "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", "dev": true, "requires": { - "cyclist": "~0.2.2", + "cyclist": "^1.0.1", "inherits": "^2.0.3", "readable-stream": "^2.1.5" } }, "parse-asn1": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", - "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", "dev": true, "requires": { "asn1.js": "^4.0.0", @@ -4108,9 +4017,9 @@ "dev": true }, "path-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", - "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", "dev": true }, "path-dirname": { @@ -4120,10 +4029,13 @@ "dev": true }, "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } }, "path-is-absolute": { "version": "1.0.1", @@ -4209,6 +4121,17 @@ "dev": true, "requires": { "find-up": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + } } }, "posix-character-classes": { @@ -4218,9 +4141,9 @@ "dev": true }, "postcss": { - "version": "7.0.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.16.tgz", - "integrity": "sha512-MOo8zNSlIqh22Uaa3drkdIAgUGEL+AD1ESiSdmElLUmE2uVDo1QloiT/IfW9qRw8Gw+Y/w69UVMGwbufMSftxA==", + "version": "7.0.25", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.25.tgz", + "integrity": "sha512-NXXVvWq9icrm/TgQC0O6YVFi4StfJz46M1iNd/h6B26Nvh/HKI+q4YZtFN/EjcInZliEscO/WL10BXnc1E5nwg==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -4271,20 +4194,21 @@ } }, "postcss-modules-local-by-default": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz", - "integrity": "sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.2.tgz", + "integrity": "sha512-jM/V8eqM4oJ/22j0gx4jrp63GSvDH6v86OqyTHHUvk4/k1vceipZsaymiZ5PvocqZOl5SFHiFJqjs3la0wnfIQ==", "dev": true, "requires": { - "postcss": "^7.0.6", - "postcss-selector-parser": "^6.0.0", - "postcss-value-parser": "^3.3.1" + "icss-utils": "^4.1.1", + "postcss": "^7.0.16", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.0.0" } }, "postcss-modules-scope": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz", - "integrity": "sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.1.1.tgz", + "integrity": "sha512-OXRUPecnHCg8b9xWvldG/jUpRIGPNRka0r4D4j0ESUU2/5IOnpsjfPPmDprM3Ih8CgZ8FXjWqaniK5v4rWt3oQ==", "dev": true, "requires": { "postcss": "^7.0.6", @@ -4292,12 +4216,12 @@ } }, "postcss-modules-values": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz", - "integrity": "sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", + "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", "dev": true, "requires": { - "icss-replace-symbols": "^1.1.0", + "icss-utils": "^4.0.0", "postcss": "^7.0.6" } }, @@ -4313,9 +4237,9 @@ } }, "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz", + "integrity": "sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ==", "dev": true }, "prepend-http": { @@ -4331,9 +4255,9 @@ "dev": true }, "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, "promise-inflight": { @@ -4355,9 +4279,9 @@ "dev": true }, "psl": { - "version": "1.1.32", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.32.tgz", - "integrity": "sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.6.0.tgz", + "integrity": "sha512-SYKKmVel98NCOYXpkwUqZqh0ahZeeKfmisiLIcEZdsb+WbLv02g/dI5BUmZnIyOe7RzZtLax81nnb2HbvC2tzA==", "dev": true }, "public-encrypt": { @@ -4372,14 +4296,6 @@ "parse-asn1": "^5.0.0", "randombytes": "^2.0.1", "safe-buffer": "^5.1.2" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } } }, "pump": { @@ -4416,9 +4332,9 @@ } }, "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, "qs": { @@ -4487,41 +4403,20 @@ "requires": { "find-up": "^1.0.0", "read-pkg": "^1.0.0" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - } } }, "readable-stream": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", + "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", - "string_decoder": "~1.0.3", + "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, @@ -4563,9 +4458,9 @@ "dev": true }, "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", "dev": true }, "repeat-string": { @@ -4609,14 +4504,6 @@ "tough-cookie": "~2.4.3", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } } }, "require-directory": { @@ -4648,6 +4535,19 @@ "requires": { "expand-tilde": "^2.0.0", "global-modules": "^1.0.0" + }, + "dependencies": { + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + } } }, "resolve-from": { @@ -4669,12 +4569,12 @@ "dev": true }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "ripemd160": { @@ -4697,9 +4597,9 @@ } }, "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, "safe-regex": { @@ -4730,28 +4630,34 @@ } }, "sass-loader": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.1.0.tgz", - "integrity": "sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-8.0.0.tgz", + "integrity": "sha512-+qeMu563PN7rPdit2+n5uuYVR0SSVwm0JsOUsaJXzgYcClWSlmX0iHDnmeOobPkf5kUglVot3QS6SyLyaQoJ4w==", "dev": true, "requires": { - "clone-deep": "^2.0.1", - "loader-utils": "^1.0.1", - "lodash.tail": "^4.1.1", - "neo-async": "^2.5.0", - "pify": "^3.0.0", - "semver": "^5.5.0" + "clone-deep": "^4.0.1", + "loader-utils": "^1.2.3", + "neo-async": "^2.6.1", + "schema-utils": "^2.1.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.1.tgz", + "integrity": "sha512-0WXHDs1VDJyo+Zqs9TKLKyD/h7yDpHUhEFsM2CzkICFdoX1av+GBq/J2xRTFfsQO5kBfhZzANf2VcIm84jqDbg==", "dev": true, "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1" } }, "scss-tokenizer": { @@ -4787,9 +4693,9 @@ "dev": true }, "serialize-javascript": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.7.0.tgz", - "integrity": "sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", + "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", "dev": true }, "set-blocking": { @@ -4838,22 +4744,12 @@ } }, "shallow-clone": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", - "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "dev": true, "requires": { - "is-extendable": "^0.1.1", - "kind-of": "^5.0.0", - "mixin-object": "^2.0.1" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } + "kind-of": "^6.0.2" } }, "shebang-command": { @@ -4979,12 +4875,6 @@ "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true } } }, @@ -4995,6 +4885,17 @@ "dev": true, "requires": { "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "sort-keys": { @@ -5007,14 +4908,14 @@ } }, "sortablejs": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.9.0.tgz", - "integrity": "sha512-Ot6bYJ6PoqPmpsqQYXjn1+RKrY2NWQvQt/o4jfd/UYwVWndyO5EPO8YHbnm5HIykf8ENsm4JUrdAvolPT86yYA==" + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.10.1.tgz", + "integrity": "sha512-N6r7GrVmO8RW1rn0cTdvK3JR0BcqecAJ0PmYMCL3ZuqTH3pY+9QyqkmJSkkLyyDvd+AJnwaxTP22Ybr/83V9hQ==" }, "source-list-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", - "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", "dev": true }, "source-map": { @@ -5037,9 +4938,9 @@ } }, "source-map-support": { - "version": "0.5.12", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", - "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -5185,44 +5086,12 @@ "readable-stream": "^2.3.6", "to-arraybuffer": "^1.0.0", "xtend": "^4.0.0" - }, - "dependencies": { - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } } }, "stream-shift": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", "dev": true }, "strict-uri-encode": { @@ -5254,9 +5123,9 @@ } }, "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -5296,13 +5165,13 @@ } }, "style-loader": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", - "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.1.1.tgz", + "integrity": "sha512-oIVF12trRq0od4Yojg7q0K3Lq/O6Ix/AYgVosykrVg+kWxxxUyk8KhKCCmekyGSUiVK1xxlAQymLWWdh6S9lOg==", "dev": true, "requires": { - "loader-utils": "^1.1.0", - "schema-utils": "^1.0.0" + "loader-utils": "^1.2.3", + "schema-utils": "^2.0.1" } }, "supports-color": { @@ -5332,65 +5201,43 @@ } }, "terser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.0.0.tgz", - "integrity": "sha512-dOapGTU0hETFl1tCo4t56FN+2jffoKyER9qBGoUFyZ6y7WLoKT0bF+lAYi6B6YsILcGF3q1C2FBh8QcKSCgkgA==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.4.3.tgz", + "integrity": "sha512-0ikKraVtRDKGzHrzkCv5rUNDzqlhmhowOBqC0XqUHFpW+vJ45+20/IFBcebwKfiS2Z9fJin6Eo+F1zLZsxi8RA==", "dev": true, "requires": { - "commander": "^2.19.0", + "commander": "^2.20.0", "source-map": "~0.6.1", - "source-map-support": "~0.5.10" + "source-map-support": "~0.5.12" } }, "terser-webpack-plugin": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.3.0.tgz", - "integrity": "sha512-W2YWmxPjjkUcOWa4pBEv4OP4er1aeQJlSo2UhtCFQCuRXEHjOFscO8VyWHj9JLlA0RzQb8Y2/Ta78XZvT54uGg==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz", + "integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==", "dev": true, "requires": { - "cacache": "^11.3.2", - "find-cache-dir": "^2.0.0", + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", "is-wsl": "^1.1.0", - "loader-utils": "^1.2.3", "schema-utils": "^1.0.0", - "serialize-javascript": "^1.7.0", + "serialize-javascript": "^2.1.2", "source-map": "^0.6.1", - "terser": "^4.0.0", - "webpack-sources": "^1.3.0", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", "worker-farm": "^1.7.0" }, "dependencies": { - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true - }, - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "dev": true, "requires": { - "minimist": "^1.2.0" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" } - }, - "loader-utils": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", - "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^2.0.0", - "json5": "^1.0.1" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true } } }, @@ -5402,44 +5249,12 @@ "requires": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" - }, - "dependencies": { - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } } }, "timers-browserify": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", - "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", + "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", "dev": true, "requires": { "setimmediate": "^1.0.4" @@ -5463,6 +5278,17 @@ "dev": true, "requires": { "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, "to-regex": { @@ -5495,6 +5321,14 @@ "requires": { "psl": "^1.1.24", "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } } }, "trim-newlines": { @@ -5513,9 +5347,9 @@ } }, "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", "dev": true }, "tty-browserify": { @@ -5546,15 +5380,9 @@ "dev": true }, "uc.micro": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.5.tgz", - "integrity": "sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg==" - }, - "ultron": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", - "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=", - "dev": true + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" }, "union-value": { "version": "1.0.1", @@ -5584,9 +5412,9 @@ } }, "unique-slug": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.1.tgz", - "integrity": "sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", "dev": true, "requires": { "imurmurhash": "^0.1.4" @@ -5633,9 +5461,9 @@ } }, "upath": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", - "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", "dev": true }, "uri-js": { @@ -5645,14 +5473,6 @@ "dev": true, "requires": { "punycode": "^2.1.0" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - } } }, "urix": { @@ -5692,6 +5512,14 @@ "dev": true, "requires": { "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } } }, "util-deprecate": { @@ -5701,9 +5529,9 @@ "dev": true }, "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", "dev": true }, "v8-compile-cache": { @@ -5734,25 +5562,22 @@ } }, "vm-browserify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", - "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", - "dev": true, - "requires": { - "indexof": "0.0.1" - } + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true }, "vue": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.10.tgz", - "integrity": "sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==" + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.11.tgz", + "integrity": "sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ==" }, "vuedraggable": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-2.21.0.tgz", - "integrity": "sha512-UDp0epjaZikuInoJA9rlEIJaSTQThabq0R9x7TqBdl0qGVFKKzo6glP6ubfzWBmV4iRIfbSOs2DV06s3B5h5tA==", + "version": "2.23.2", + "resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-2.23.2.tgz", + "integrity": "sha512-PgHCjUpxEAEZJq36ys49HfQmXglattf/7ofOzUrW2/rRdG7tu6fK84ir14t1jYv4kdXewTEa2ieKEAhhEMdwkQ==", "requires": { - "sortablejs": "^1.9.0" + "sortablejs": "^1.10.1" } }, "watchpack": { @@ -5764,140 +5589,108 @@ "chokidar": "^2.0.2", "graceful-fs": "^4.1.2", "neo-async": "^2.5.0" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" - } } }, "webpack": { - "version": "4.32.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.32.2.tgz", - "integrity": "sha512-F+H2Aa1TprTQrpodRAWUMJn7A8MgDx82yQiNvYMaj3d1nv3HetKU0oqEulL9huj8enirKi8KvEXQ3QtuHF89Zg==", + "version": "4.41.4", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.4.tgz", + "integrity": "sha512-Lc+2uB6NjpCWsHI3trkoISOI64h9QYIXenbEWj3bn3oyjfB1lEBXjWAfAyY2sM0rZn41oD5V91OLwKRwS6Wp8Q==", "dev": true, "requires": { "@webassemblyjs/ast": "1.8.5", "@webassemblyjs/helper-module-context": "1.8.5", "@webassemblyjs/wasm-edit": "1.8.5", "@webassemblyjs/wasm-parser": "1.8.5", - "acorn": "^6.0.5", - "acorn-dynamic-import": "^4.0.0", - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0", - "chrome-trace-event": "^1.0.0", + "acorn": "^6.2.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^4.1.0", - "eslint-scope": "^4.0.0", + "eslint-scope": "^4.0.3", "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.3.0", - "loader-utils": "^1.1.0", - "memory-fs": "~0.4.1", - "micromatch": "^3.1.8", - "mkdirp": "~0.5.0", - "neo-async": "^2.5.0", - "node-libs-browser": "^2.0.0", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.1", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", "schema-utils": "^1.0.0", - "tapable": "^1.1.0", - "terser-webpack-plugin": "^1.1.0", - "watchpack": "^1.5.0", - "webpack-sources": "^1.3.0" + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.6.0", + "webpack-sources": "^1.4.1" }, "dependencies": { - "is-accessor-descriptor": { + "schema-utils": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, "requires": { - "kind-of": "^6.0.0" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, "webpack-cli": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.2.tgz", - "integrity": "sha512-FLkobnaJJ+03j5eplxlI0TUxhGCOdfewspIGuvDVtpOlrAuKMFC57K42Ukxqs1tn8947/PM6tP95gQc0DCzRYA==", + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.10.tgz", + "integrity": "sha512-u1dgND9+MXaEt74sJR4PR7qkPxXUSQ0RXYq8x1L6Jg1MYVEmGPrH6Ah6C4arD4r0J1P5HKjRqpab36k0eIzPqg==", "dev": true, "requires": { - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "enhanced-resolve": "^4.1.0", - "findup-sync": "^2.0.0", - "global-modules": "^1.0.0", - "import-local": "^2.0.0", - "interpret": "^1.1.0", - "loader-utils": "^1.1.0", - "supports-color": "^5.5.0", - "v8-compile-cache": "^2.0.2", - "yargs": "^12.0.5" + "chalk": "2.4.2", + "cross-spawn": "6.0.5", + "enhanced-resolve": "4.1.0", + "findup-sync": "3.0.0", + "global-modules": "2.0.0", + "import-local": "2.0.0", + "interpret": "1.2.0", + "loader-utils": "1.2.3", + "supports-color": "6.1.0", + "v8-compile-cache": "2.0.3", + "yargs": "13.2.4" }, "dependencies": { "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" } }, "cross-spawn": { @@ -5913,6 +5706,32 @@ "which": "^1.2.9" } }, + "enhanced-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", + "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "tapable": "^1.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, "invert-kv": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", @@ -5945,23 +5764,39 @@ "mem": "^4.0.0" } }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { + "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "strip-ansi": "^5.1.0" } }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" } }, "which-module": { @@ -5970,30 +5805,46 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, - "yargs": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "dev": true, "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yargs": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", + "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==", + "dev": true, + "requires": { + "cliui": "^5.0.0", "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", + "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", - "string-width": "^2.0.0", + "string-width": "^3.0.0", "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" + "y18n": "^4.0.0", + "yargs-parser": "^13.1.0" } }, "yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", "dev": true, "requires": { "camelcase": "^5.0.0", @@ -6003,9 +5854,9 @@ } }, "webpack-sources": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz", - "integrity": "sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", "dev": true, "requires": { "source-list-map": "^2.0.0", @@ -6062,19 +5913,18 @@ "dev": true }, "ws": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", - "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", "dev": true, "requires": { - "options": ">=0.0.5", - "ultron": "1.0.x" + "async-limiter": "~1.0.0" } }, "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "dev": true }, "y18n": { diff --git a/package.json b/package.json index 0d1afbb0c..8877cb9e8 100644 --- a/package.json +++ b/package.json @@ -10,25 +10,25 @@ "permissions": "chown -R $USER:$USER bootstrap/cache storage public/uploads" }, "devDependencies": { - "css-loader": "^2.1.1", - "livereload": "^0.8.0", - "mini-css-extract-plugin": "^0.7.0", - "node-sass": "^4.12.0", + "css-loader": "^3.4.0", + "livereload": "^0.8.2", + "mini-css-extract-plugin": "^0.9.0", + "node-sass": "^4.13.0", "npm-run-all": "^4.1.5", - "sass-loader": "^7.1.0", - "style-loader": "^0.23.1", - "webpack": "^4.32.2", - "webpack-cli": "^3.3.2" + "sass-loader": "^8.0.0", + "style-loader": "^1.1.1", + "webpack": "^4.41.4", + "webpack-cli": "^3.3.10" }, "dependencies": { "clipboard": "^2.0.4", - "codemirror": "^5.47.0", + "codemirror": "^5.50.0", "dropzone": "^5.5.1", - "markdown-it": "^8.4.2", + "markdown-it": "^10.0.0", "markdown-it-task-lists": "^2.1.1", - "sortablejs": "^1.9.0", - "vue": "^2.6.10", - "vuedraggable": "^2.21.0" + "sortablejs": "^1.10.1", + "vue": "^2.6.11", + "vuedraggable": "^2.23.2" }, "browser": { "vue": "vue/dist/vue.common.js" From 5491bd62a2879f10c5bfe3ff06dced34780b7980 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 21 Dec 2019 13:48:44 +0000 Subject: [PATCH 030/191] Fixed test failing due to redirect changes - Also set APP_THEME param during testing to avoid local conflicts --- phpunit.xml | 1 + tests/Permissions/RolesTest.php | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/phpunit.xml b/phpunit.xml index 48eba5e99..546829247 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -22,6 +22,7 @@ + diff --git a/tests/Permissions/RolesTest.php b/tests/Permissions/RolesTest.php index 371cffc0f..2ef72fb0a 100644 --- a/tests/Permissions/RolesTest.php +++ b/tests/Permissions/RolesTest.php @@ -637,14 +637,14 @@ class RolesTest extends BrowserKitTest $ownPage->getUrl() => 'Delete' ]); - $bookUrl = $ownPage->book->getUrl(); + $parent = $ownPage->chapter ?? $ownPage->book; $this->visit($otherPage->getUrl()) ->dontSeeInElement('.action-buttons', 'Delete') ->visit($otherPage->getUrl() . '/delete') ->seePageIs('/'); $this->visit($ownPage->getUrl())->visit($ownPage->getUrl() . '/delete') ->press('Confirm') - ->seePageIs($bookUrl) + ->seePageIs($parent->getUrl()) ->dontSeeInElement('.book-content', $ownPage->name); } @@ -658,10 +658,10 @@ class RolesTest extends BrowserKitTest $otherPage->getUrl() => 'Delete' ]); - $bookUrl = $otherPage->book->getUrl(); + $parent = $otherPage->chapter ?? $otherPage->book; $this->visit($otherPage->getUrl())->visit($otherPage->getUrl() . '/delete') ->press('Confirm') - ->seePageIs($bookUrl) + ->seePageIs($parent->getUrl()) ->dontSeeInElement('.book-content', $otherPage->name); } From a83a7f34f4d4c85bfb208eb1abfdd77743856680 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 21 Dec 2019 15:48:03 +0000 Subject: [PATCH 031/191] Better standardised and fixes areas of image pasting - Extracted logic to get images from paste/drop event into own file to align usage in both events for both editors. - Fixed non-ability to drag+drop into WYSIWYG editor. - Updated check for table data to look for table specific rich-text instead of just any text since some the old check was too general and was preventing some legitimate image paste events. Tested on Chrome and FireFox on Ubuntu. Attempted to test on Safari via browserstack but environment was unreliable and could not access folders to test drag/drop of files. Relates to #1651 and #1697 --- resources/js/components/markdown-editor.js | 27 ++++++----- resources/js/components/wysiwyg-editor.js | 36 +++++++++------ resources/js/services/clipboard.js | 54 ++++++++++++++++++++++ 3 files changed, 89 insertions(+), 28 deletions(-) create mode 100644 resources/js/services/clipboard.js diff --git a/resources/js/components/markdown-editor.js b/resources/js/components/markdown-editor.js index de256a846..331cf2f01 100644 --- a/resources/js/components/markdown-editor.js +++ b/resources/js/components/markdown-editor.js @@ -1,6 +1,7 @@ import MarkdownIt from "markdown-it"; import mdTasksLists from 'markdown-it-task-lists'; import code from '../services/code'; +import Clipboard from "../services/clipboard"; import {debounce} from "../services/util"; import DrawIO from "../services/drawio"; @@ -215,20 +216,16 @@ class MarkdownEditor { // Handle image paste cm.on('paste', (cm, event) => { - const clipboardItems = event.clipboardData.items; - if (!event.clipboardData || !clipboardItems) return; + const clipboard = new Clipboard(event.clipboardData || event.dataTransfer); - // Don't handle if clipboard includes text content - for (let clipboardItem of clipboardItems) { - if (clipboardItem.type.includes('text/')) { - return; - } + // Don't handle the event ourselves if no items exist of contains table-looking data + if (!clipboard.hasItems() || clipboard.containsTabularData()) { + return; } - for (let clipboardItem of clipboardItems) { - if (clipboardItem.type.includes("image")) { - uploadImage(clipboardItem.getAsFile()); - } + const images = clipboard.getImages(); + for (const image of images) { + uploadImage(image); } }); @@ -246,13 +243,15 @@ class MarkdownEditor { }); } - if (event.dataTransfer && event.dataTransfer.files && event.dataTransfer.files.length > 0) { + const clipboard = new Clipboard(event.dataTransfer); + if (clipboard.hasItems()) { const cursorPos = cm.coordsChar({left: event.pageX, top: event.pageY}); cm.setCursor(cursorPos); event.stopPropagation(); event.preventDefault(); - for (let i = 0; i < event.dataTransfer.files.length; i++) { - uploadImage(event.dataTransfer.files[i]); + const images = clipboard.getImages(); + for (const image of images) { + uploadImage(image); } } diff --git a/resources/js/components/wysiwyg-editor.js b/resources/js/components/wysiwyg-editor.js index 41ce2705a..b9e3340a8 100644 --- a/resources/js/components/wysiwyg-editor.js +++ b/resources/js/components/wysiwyg-editor.js @@ -1,5 +1,6 @@ import Code from "../services/code"; import DrawIO from "../services/drawio"; +import Clipboard from "../services/clipboard"; /** * Handle pasting images from clipboard. @@ -8,30 +9,33 @@ import DrawIO from "../services/drawio"; * @param editor */ function editorPaste(event, editor, wysiwygComponent) { - const clipboardItems = event.clipboardData.items; - if (!event.clipboardData || !clipboardItems) return; + const clipboard = new Clipboard(event.clipboardData || event.dataTransfer); - // Don't handle if clipboard includes text content - for (let clipboardItem of clipboardItems) { - if (clipboardItem.type.includes('text/')) { - return; - } + // Don't handle the event ourselves if no items exist of contains table-looking data + if (!clipboard.hasItems() || clipboard.containsTabularData()) { + return; } - for (let clipboardItem of clipboardItems) { - if (!clipboardItem.type.includes("image")) { - continue; - } + const images = clipboard.getImages(); + for (const imageFile of images) { const id = "image-" + Math.random().toString(16).slice(2); const loadingImage = window.baseUrl('/loading.gif'); - const file = clipboardItem.getAsFile(); + event.preventDefault(); setTimeout(() => { editor.insertContent(`

`); - uploadImageFile(file, wysiwygComponent).then(resp => { - editor.dom.setAttrib(id, 'src', resp.thumbs.display); + uploadImageFile(imageFile, wysiwygComponent).then(resp => { + const safeName = resp.name.replace(/"/g, ''); + const newImageHtml = `${safeName}`; + + const newEl = editor.dom.create('a', { + target: '_blank', + href: resp.url, + }, newImageHtml); + + editor.dom.replace(newEl, id); }).catch(err => { editor.dom.remove(id); window.$events.emit('error', trans('errors.image_upload_error')); @@ -634,6 +638,10 @@ class WysiwygEditor { }); } + if (!event.isDefaultPrevented()) { + editorPaste(event, editor, context); + } + wrap = null; }); diff --git a/resources/js/services/clipboard.js b/resources/js/services/clipboard.js new file mode 100644 index 000000000..da921e515 --- /dev/null +++ b/resources/js/services/clipboard.js @@ -0,0 +1,54 @@ + +class Clipboard { + + /** + * Constructor + * @param {DataTransfer} clipboardData + */ + constructor(clipboardData) { + this.data = clipboardData; + } + + /** + * Check if the clipboard has any items. + */ + hasItems() { + return Boolean(this.data) && Boolean(this.data.types) && this.data.types.length > 0; + } + + /** + * Check if the given event has tabular-looking data in the clipboard. + * @return {boolean} + */ + containsTabularData() { + const rtfData = this.data.getData( 'text/rtf'); + return rtfData && rtfData.includes('\\trowd'); + } + + /** + * Get the images that are in the clipboard data. + * @return {Array} + */ + getImages() { + const types = this.data.types; + const files = this.data.files; + const images = []; + + for (const type of types) { + if (type.includes('image')) { + const item = this.data.getData(type); + images.push(item.getAsFile()); + } + } + + for (const file of files) { + if (file.type.includes('image')) { + images.push(file); + } + } + + return images; + } +} + +export default Clipboard; \ No newline at end of file From 32e7f0a2e672226384f58a0f7ba96e0b17535d4a Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 22 Dec 2019 12:44:49 +0000 Subject: [PATCH 032/191] Made display thumbnail generation use original data if smaller Thumbnail generation would sometimes create a file larger than the original, if the original was already well optimized, therefore making the thumbnail counter-productive. This change compares the sizes of the original and the generated thumbnail, and uses the smaller of the two if the thumbnail does not change the aspect ratio of the image. Fixes #1751 --- app/Uploads/ImageRepo.php | 104 +++++++++------------------------ app/Uploads/ImageService.php | 11 +++- tests/Uploads/ImageTest.php | 24 ++++++++ tests/Uploads/UsesImages.php | 25 ++++---- tests/test-data/compressed.png | Bin 0 -> 732 bytes 5 files changed, 76 insertions(+), 88 deletions(-) create mode 100644 tests/test-data/compressed.png diff --git a/app/Uploads/ImageRepo.php b/app/Uploads/ImageRepo.php index da0b7d379..01b65f882 100644 --- a/app/Uploads/ImageRepo.php +++ b/app/Uploads/ImageRepo.php @@ -2,6 +2,8 @@ use BookStack\Auth\Permissions\PermissionService; use BookStack\Entities\Page; +use BookStack\Exceptions\ImageUploadException; +use Exception; use Illuminate\Database\Eloquent\Builder; use Symfony\Component\HttpFoundation\File\UploadedFile; @@ -15,10 +17,6 @@ class ImageRepo /** * ImageRepo constructor. - * @param Image $image - * @param ImageService $imageService - * @param \BookStack\Auth\Permissions\PermissionService $permissionService - * @param \BookStack\Entities\Page $page */ public function __construct( Image $image, @@ -35,10 +33,8 @@ class ImageRepo /** * Get an image with the given id. - * @param $id - * @return Image */ - public function getById($id) + public function getById($id): Image { return $this->image->findOrFail($id); } @@ -46,13 +42,8 @@ class ImageRepo /** * Execute a paginated query, returning in a standard format. * Also runs the query through the restriction system. - * @param $query - * @param int $page - * @param int $pageSize - * @param bool $filterOnPage - * @return array */ - private function returnPaginated($query, $page = 1, $pageSize = 24) + private function returnPaginated($query, $page = 1, $pageSize = 24): array { $images = $query->orderBy('created_at', 'desc')->skip($pageSize * ($page - 1))->take($pageSize + 1)->get(); $hasMore = count($images) > $pageSize; @@ -71,13 +62,6 @@ class ImageRepo /** * Fetch a list of images in a paginated format, filtered by image type. * Can be filtered by uploaded to and also by name. - * @param string $type - * @param int $page - * @param int $pageSize - * @param int $uploadedTo - * @param string|null $search - * @param callable|null $whereClause - * @return array */ public function getPaginatedByType( string $type, @@ -86,7 +70,8 @@ class ImageRepo int $uploadedTo = null, string $search = null, callable $whereClause = null - ) { + ): array + { $imageQuery = $this->image->newQuery()->where('type', '=', strtolower($type)); if ($uploadedTo !== null) { @@ -109,13 +94,6 @@ class ImageRepo /** * Get paginated gallery images within a specific page or book. - * @param string $type - * @param string $filterType - * @param int $page - * @param int $pageSize - * @param int|null $uploadedTo - * @param string|null $search - * @return array */ public function getEntityFiltered( string $type, @@ -124,7 +102,8 @@ class ImageRepo int $pageSize = 24, int $uploadedTo = null, string $search = null - ) { + ): array + { $contextPage = $this->page->findOrFail($uploadedTo); $parentFilter = null; @@ -144,16 +123,9 @@ class ImageRepo /** * Save a new image into storage and return the new image. - * @param UploadedFile $uploadFile - * @param string $type - * @param int $uploadedTo - * @param int|null $resizeWidth - * @param int|null $resizeHeight - * @param bool $keepRatio - * @return Image - * @throws \BookStack\Exceptions\ImageUploadException + * @throws ImageUploadException */ - public function saveNew(UploadedFile $uploadFile, $type, $uploadedTo = 0, int $resizeWidth = null, int $resizeHeight = null, bool $keepRatio = true) + public function saveNew(UploadedFile $uploadFile, string $type, int $uploadedTo = 0, int $resizeWidth = null, int $resizeHeight = null, bool $keepRatio = true): Image { $image = $this->imageService->saveNewFromUpload($uploadFile, $type, $uploadedTo, $resizeWidth, $resizeHeight, $keepRatio); $this->loadThumbs($image); @@ -161,29 +133,22 @@ class ImageRepo } /** - * Save a drawing the the database; - * @param string $base64Uri - * @param int $uploadedTo - * @return Image - * @throws \BookStack\Exceptions\ImageUploadException + * Save a drawing the the database. + * @throws ImageUploadException */ - public function saveDrawing(string $base64Uri, int $uploadedTo) + public function saveDrawing(string $base64Uri, int $uploadedTo): Image { $name = 'Drawing-' . user()->getShortName(40) . '-' . strval(time()) . '.png'; - $image = $this->imageService->saveNewFromBase64Uri($base64Uri, $name, 'drawio', $uploadedTo); - return $image; + return $this->imageService->saveNewFromBase64Uri($base64Uri, $name, 'drawio', $uploadedTo); } /** * Update the details of an image via an array of properties. - * @param Image $image - * @param array $updateDetails - * @return Image - * @throws \BookStack\Exceptions\ImageUploadException - * @throws \Exception + * @throws ImageUploadException + * @throws Exception */ - public function updateImageDetails(Image $image, $updateDetails) + public function updateImageDetails(Image $image, $updateDetails): Image { $image->fill($updateDetails); $image->save(); @@ -191,14 +156,11 @@ class ImageRepo return $image; } - /** * Destroys an Image object along with its revisions, files and thumbnails. - * @param Image $image - * @return bool - * @throws \Exception + * @throws Exception */ - public function destroyImage(Image $image = null) + public function destroyImage(Image $image = null): bool { if ($image) { $this->imageService->destroy($image); @@ -208,8 +170,7 @@ class ImageRepo /** * Destroy all images of a certain type. - * @param string $imageType - * @throws \Exception + * @throws Exception */ public function destroyByType(string $imageType) { @@ -222,9 +183,7 @@ class ImageRepo /** * Load thumbnails onto an image object. - * @param Image $image - * @throws \BookStack\Exceptions\ImageUploadException - * @throws \Exception + * @throws Exception */ protected function loadThumbs(Image $image) { @@ -238,42 +197,33 @@ class ImageRepo * Get the thumbnail for an image. * If $keepRatio is true only the width will be used. * Checks the cache then storage to avoid creating / accessing the filesystem on every check. - * @param Image $image - * @param int $width - * @param int $height - * @param bool $keepRatio - * @return string - * @throws \BookStack\Exceptions\ImageUploadException - * @throws \Exception + * @throws Exception */ - protected function getThumbnail(Image $image, $width = 220, $height = 220, $keepRatio = false) + protected function getThumbnail(Image $image, ?int $width = 220, ?int $height = 220, bool $keepRatio = false): ?string { try { return $this->imageService->getThumbnail($image, $width, $height, $keepRatio); - } catch (\Exception $exception) { + } catch (Exception $exception) { return null; } } /** * Get the raw image data from an Image. - * @param Image $image - * @return null|string */ - public function getImageData(Image $image) + public function getImageData(Image $image): ?string { try { return $this->imageService->getImageData($image); - } catch (\Exception $exception) { + } catch (Exception $exception) { return null; } } /** * Get the validation rules for image files. - * @return string */ - public function getImageValidationRules() + public function getImageValidationRules(): string { return 'image_extension|no_double_extension|mimes:jpeg,png,gif,bmp,webp,tiff'; } diff --git a/app/Uploads/ImageService.php b/app/Uploads/ImageService.php index e7668471b..756149fe7 100644 --- a/app/Uploads/ImageService.php +++ b/app/Uploads/ImageService.php @@ -254,7 +254,16 @@ class ImageService extends UploadService } else { $thumb->fit($width, $height); } - return (string)$thumb->encode(); + + $thumbData = (string)$thumb->encode(); + + // Use original image data if we're keeping the ratio + // and the resizing does not save any space. + if ($keepRatio && strlen($thumbData) > strlen($imageData)) { + return $imageData; + } + + return $thumbData; } /** diff --git a/tests/Uploads/ImageTest.php b/tests/Uploads/ImageTest.php index 0615a95ce..3f6c021a7 100644 --- a/tests/Uploads/ImageTest.php +++ b/tests/Uploads/ImageTest.php @@ -36,6 +36,30 @@ class ImageTest extends TestCase ]); } + public function test_image_display_thumbnail_generation_does_not_increase_image_size() + { + $page = Page::first(); + $admin = $this->getAdmin(); + $this->actingAs($admin); + + $originalFile = $this->getTestImageFilePath('compressed.png'); + $originalFileSize = filesize($originalFile); + $imgDetails = $this->uploadGalleryImage($page, 'compressed.png'); + $relPath = $imgDetails['path']; + + $this->assertTrue(file_exists(public_path($relPath)), 'Uploaded image found at path: '. public_path($relPath)); + $displayImage = $imgDetails['response']->thumbs->display; + + $displayImageRelPath = implode('/', array_slice(explode('/', $displayImage), 3)); + $displayImagePath = public_path($displayImageRelPath); + $displayFileSize = filesize($displayImagePath); + + $this->deleteImage($relPath); + $this->deleteImage($displayImageRelPath); + + $this->assertEquals($originalFileSize, $displayFileSize, 'Display thumbnail generation should not increase image size'); + } + public function test_image_edit() { $editor = $this->getEditor(); diff --git a/tests/Uploads/UsesImages.php b/tests/Uploads/UsesImages.php index aa5ffe4c7..9ce559acd 100644 --- a/tests/Uploads/UsesImages.php +++ b/tests/Uploads/UsesImages.php @@ -10,9 +10,13 @@ trait UsesImages * Get the path to our basic test image. * @return string */ - protected function getTestImageFilePath() + protected function getTestImageFilePath(?string $fileName = null) { - return base_path('tests/test-data/test-image.png'); + if (is_null($fileName)) { + $fileName = 'test-image.png'; + } + + return base_path('tests/test-data/' . $fileName); } /** @@ -20,9 +24,9 @@ trait UsesImages * @param $fileName * @return UploadedFile */ - protected function getTestImage($fileName) + protected function getTestImage($fileName, ?string $testDataFileName = null) { - return new UploadedFile($this->getTestImageFilePath(), $fileName, 'image/png', 5238, null, true); + return new UploadedFile($this->getTestImageFilePath($testDataFileName), $fileName, 'image/png', 5238, null, true); } /** @@ -52,9 +56,9 @@ trait UsesImages * @param string $contentType * @return \Illuminate\Foundation\Testing\TestResponse */ - protected function uploadImage($name, $uploadedTo = 0, $contentType = 'image/png') + protected function uploadImage($name, $uploadedTo = 0, $contentType = 'image/png', ?string $testDataFileName = null) { - $file = $this->getTestImage($name); + $file = $this->getTestImage($name, $testDataFileName); return $this->withHeader('Content-Type', $contentType) ->call('POST', '/images/gallery', ['uploaded_to' => $uploadedTo], [], ['file' => $file], []); } @@ -66,22 +70,23 @@ trait UsesImages * @param Page|null $page * @return array */ - protected function uploadGalleryImage(Page $page = null) + protected function uploadGalleryImage(Page $page = null, ?string $testDataFileName = null) { if ($page === null) { $page = Page::query()->first(); } - $imageName = 'first-image.png'; + $imageName = $testDataFileName ?? 'first-image.png'; $relPath = $this->getTestImagePath('gallery', $imageName); $this->deleteImage($relPath); - $upload = $this->uploadImage($imageName, $page->id); + $upload = $this->uploadImage($imageName, $page->id, 'image/png', $testDataFileName); $upload->assertStatus(200); return [ 'name' => $imageName, 'path' => $relPath, - 'page' => $page + 'page' => $page, + 'response' => json_decode($upload->getContent()), ]; } diff --git a/tests/test-data/compressed.png b/tests/test-data/compressed.png new file mode 100644 index 0000000000000000000000000000000000000000..e42ef58f0af576984d28ffe46c8d9a244020b62f GIT binary patch literal 732 zcmV<20wev2P)a0Igld}m45;vD{mztwF;&vEd`{ARv=OpNu1^3lst=*LcM`b z|9-=WMRZZ+(QLt9lvjnA=jxh3beb8#IAW1s_wOMxh<%6N`=3wmAUX*>XASabM-(i> zf}H-dA}aG7K0+IgyU1p1K~!uEK2qiWTBJR*l_OP}`RkC&6Y_{@WGJc2MkBk9y7oy# zB27;qLZ*il*jGeoWl_y-X+a2utfqvfl)&y%2V9QgZFKC}k$Obqq-z8u2(8F&fQ6LX zp>~BJ3tD_Pu#C;lHHeAMEJ)pz%T=6>m$f^EeC7=DyY0)l(BHNbVMA1Y7^&N#8~g2) ze(Z*}*}eWkJacf_>Si;gsb2ttP|uu81rdDan8?*N7r|$ak6@fb@nUUyDi;X@(^I*K zpGebFxk#pGJ(Y?0>7tMEkX(tm!a}@Cin+ooB0i4zDFY$)m4}4E z7sA+B79x`_ivx4x583kD{8(q-(9uWJ`Lo3f?!YL?W)RiOv O0000 Date: Sun, 22 Dec 2019 13:17:14 +0000 Subject: [PATCH 033/191] Removed setting override system due to confusing behaviour - Was only used to disable registration when LDAP was enabled. - Caused saved option not to show on settings page causing confusion. - Extended setting logic where used to take ldap into account instead of global override. - Added warning on setting page to show registration enable setting is not used while ldap is active. For #1541 --- app/Auth/Access/SocialAuthService.php | 2 +- .../Controllers/Auth/RegisterController.php | 2 +- app/Settings/SettingService.php | 22 ------------------- resources/lang/en/settings.php | 1 + resources/views/auth/login.blade.php | 2 +- resources/views/common/header.blade.php | 2 +- resources/views/settings/index.blade.php | 4 ++++ tests/Auth/{Saml2.php => Saml2Test.php} | 2 +- tests/Uploads/UsesImages.php | 2 +- 9 files changed, 11 insertions(+), 28 deletions(-) rename tests/Auth/{Saml2.php => Saml2Test.php} (99%) diff --git a/app/Auth/Access/SocialAuthService.php b/app/Auth/Access/SocialAuthService.php index 9c8d1a81f..bc5b7a4d5 100644 --- a/app/Auth/Access/SocialAuthService.php +++ b/app/Auth/Access/SocialAuthService.php @@ -137,7 +137,7 @@ class SocialAuthService // Otherwise let the user know this social account is not used by anyone. $message = trans('errors.social_account_not_used', ['socialAccount' => $titleCaseDriver]); - if (setting('registration-enabled')) { + if (setting('registration-enabled') && config('auth.method') !== 'ldap') { $message .= trans('errors.social_account_register_instructions', ['socialAccount' => $titleCaseDriver]); } diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 000833029..8e4dd57c3 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -89,7 +89,7 @@ class RegisterController extends Controller */ protected function checkRegistrationAllowed() { - if (!setting('registration-enabled')) { + if (!setting('registration-enabled') || config('auth.method') === 'ldap') { throw new UserRegistrationException(trans('auth.registrations_disabled'), '/login'); } } diff --git a/app/Settings/SettingService.php b/app/Settings/SettingService.php index dede8fcc4..1c053b384 100644 --- a/app/Settings/SettingService.php +++ b/app/Settings/SettingService.php @@ -98,12 +98,6 @@ class SettingService */ protected function getValueFromStore($key, $default) { - // Check for an overriding value - $overrideValue = $this->getOverrideValue($key); - if ($overrideValue !== null) { - return $overrideValue; - } - // Check the cache $cacheKey = $this->cachePrefix . $key; $cacheVal = $this->cache->get($cacheKey, null); @@ -255,20 +249,4 @@ class SettingService { return $this->setting->where('setting_key', '=', $key)->first(); } - - - /** - * Returns an override value for a setting based on certain app conditions. - * Used where certain configuration options overrule others. - * Returns null if no override value is available. - * @param $key - * @return bool|null - */ - protected function getOverrideValue($key) - { - if ($key === 'registration-enabled' && config('auth.method') === 'ldap') { - return false; - } - return null; - } } diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index 8255b4cbe..6be7cc9cb 100755 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -56,6 +56,7 @@ return [ 'reg_enable_toggle' => 'Enable registration', 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', 'reg_default_role' => 'Default user role after registration', + 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', 'reg_email_confirmation' => 'Email Confirmation', 'reg_email_confirmation_toggle' => 'Require email confirmation', 'reg_confirm_email_desc' => 'If domain restriction is used then email confirmation will be required and this option will be ignored.', diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index 836150d69..098ce2100 100644 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -55,7 +55,7 @@
@endif - @if(setting('registration-enabled', false)) + @if(setting('registration-enabled') && config('auth.method') !== 'ldap')

{{ trans('auth.dont_have_account') }} diff --git a/resources/views/common/header.blade.php b/resources/views/common/header.blade.php index 192996950..b06036031 100644 --- a/resources/views/common/header.blade.php +++ b/resources/views/common/header.blade.php @@ -42,7 +42,7 @@ @endif @if(!signedInUser()) - @if(setting('registration-enabled', false)) + @if(setting('registration-enabled') && config('auth.method') !== 'ldap') @icon('new-user') {{ trans('auth.sign_up') }} @endif @icon('login') {{ trans('auth.log_in') }} diff --git a/resources/views/settings/index.blade.php b/resources/views/settings/index.blade.php index 1bc454385..94605da6f 100644 --- a/resources/views/settings/index.blade.php +++ b/resources/views/settings/index.blade.php @@ -219,6 +219,10 @@ 'label' => trans('settings.reg_enable_toggle') ]) + @if(config('auth.method') === 'ldap') +
{{ trans('settings.reg_enable_ldap_warning') }}
+ @endif + +
From a82d9fdba5175054a9f1707e41d0fd6577447b00 Mon Sep 17 00:00:00 2001 From: ezzra Date: Fri, 21 Jun 2019 14:24:04 +0200 Subject: [PATCH 035/191] fix translate for "actions" --- resources/views/pages/show.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/pages/show.blade.php b/resources/views/pages/show.blade.php index 51ab5bbbe..dfe0a9d7d 100644 --- a/resources/views/pages/show.blade.php +++ b/resources/views/pages/show.blade.php @@ -113,7 +113,7 @@
-
Actions
+
{{ trans('common.actions') }}
From a4eb5c326875af570d8aa8567639b37e4d0e6f90 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:37:56 +0000 Subject: [PATCH 036/191] New translations errors.php (Hungarian) --- resources/lang/hu/errors.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/resources/lang/hu/errors.php b/resources/lang/hu/errors.php index d2456a222..10e560c35 100644 --- a/resources/lang/hu/errors.php +++ b/resources/lang/hu/errors.php @@ -17,6 +17,12 @@ return [ 'ldap_fail_authed' => 'Az LDAP hozzáférés nem sikerült a megadott DN és jelszó beállításokkal', 'ldap_extension_not_installed' => 'LDAP PHP kiterjesztés nincs telepítve', 'ldap_cannot_connect' => 'Nem lehet kapcsolódni az LDAP kiszolgálóhoz, a kezdeti kapcsolatfelvétel nem sikerült', + 'saml_already_logged_in' => 'Már bejelentkezett', + 'saml_user_not_registered' => ':name felhasználó nincs regisztrálva és az automatikus regisztráció le van tiltva', + 'saml_no_email_address' => 'Ehhez a felhasználóhoz nem található email cím a külső hitelesítő rendszer által átadott adatokban', + 'saml_invalid_response_id' => 'A külső hitelesítő rendszerből érkező kérést nem ismerte fel az alkalmazás által indított folyamat. Bejelentkezés után az előző oldalra történő visszalépés okozhatja ezt a hibát.', + 'saml_fail_authed' => 'Bejelentkezés :system használatával sikertelen, a rendszer nem biztosított sikeres meghatalmazást', + 'saml_email_exists' => 'A regisztráció sikertelen mivel már létezik felhasználó ":email" email címmel', 'social_no_action_defined' => 'Nincs művelet meghatározva', 'social_login_bad_response' => "Hiba történt :socialAccount bejelentkezés közben:\n:error", 'social_account_in_use' => ':socialAccount fiók már használatban van. :socialAccount opción keresztül érdemes megpróbálni a bejelentkezést.', @@ -27,7 +33,7 @@ return [ 'social_account_register_instructions' => ':socialAccount beállítása használatával is lehet fiókot regisztrálni, ha még nem volt fiók létrehozva.', 'social_driver_not_found' => 'Közösségi meghajtó nem található', 'social_driver_not_configured' => ':socialAccount közösségi beállítások nem megfelelőek.', - 'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.', + 'invite_token_expired' => 'Ez a meghívó hivatkozás lejárt. Helyette meg lehet próbálni új jelszót megadni a fiókhoz.', // System 'path_not_writable' => ':filePath elérési út nem tölthető fel. Ellenőrizni kell, hogy az útvonal a kiszolgáló számára írható.', From 8235677b31a2e618fa0bdf0dec03d29f85c1c1cf Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:37:58 +0000 Subject: [PATCH 037/191] New translations errors.php (Italian) --- resources/lang/it/errors.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resources/lang/it/errors.php b/resources/lang/it/errors.php index a365c875e..e444f2968 100755 --- a/resources/lang/it/errors.php +++ b/resources/lang/it/errors.php @@ -17,6 +17,12 @@ return [ 'ldap_fail_authed' => 'Accesso LDAP fallito usando il dn e la password inseriti', 'ldap_extension_not_installed' => 'L\'estensione PHP LDAP non è installata', 'ldap_cannot_connect' => 'Impossibile connettersi al server ldap, connessione iniziale fallita', + 'saml_already_logged_in' => 'Già loggato', + 'saml_user_not_registered' => 'L\'utente :name non è registrato e la registrazione automatica è disabilitata', + 'saml_no_email_address' => 'Impossibile trovare un indirizzo email per questo utente nei dati forniti dal sistema di autenticazione esterno', + 'saml_invalid_response_id' => 'La richiesta dal sistema di autenticazione esterno non è riconosciuta da un processo iniziato da questa applicazione. Tornare indietro dopo un login potrebbe causare questo problema.', + 'saml_fail_authed' => 'Accesso con :system non riuscito, il sistema non ha fornito l\'autorizzazione corretta', + 'saml_email_exists' => 'Registrazione non riuscita poiché esiste già un utente con indirizzo email ":email"', 'social_no_action_defined' => 'Nessuna azione definita', 'social_login_bad_response' => "Ricevuto error durante il login con :socialAccount : \n:error", 'social_account_in_use' => 'Questo account :socialAccount è già utilizzato, prova a loggarti usando l\'opzione :socialAccount.', From 6c9e16282121c7381a275590ed4f274482cb2fae Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:37:59 +0000 Subject: [PATCH 038/191] New translations entities.php (Italian) --- resources/lang/it/entities.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lang/it/entities.php b/resources/lang/it/entities.php index 4865c8877..9f6acd133 100755 --- a/resources/lang/it/entities.php +++ b/resources/lang/it/entities.php @@ -212,7 +212,7 @@ return [ 'pages_revisions_number' => '#', 'pages_revisions_numbered' => 'Revisione #:id', 'pages_revisions_numbered_changes' => 'Modifiche Revisione #:id', - 'pages_revisions_changelog' => 'Changelog', + 'pages_revisions_changelog' => 'Cambiamenti', 'pages_revisions_changes' => 'Cambiamenti', 'pages_revisions_current' => 'Versione Corrente', 'pages_revisions_preview' => 'Anteprima', From 5e2908c996c071a8bf7e79e9544fccad4d0e0ef1 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:01 +0000 Subject: [PATCH 039/191] New translations common.php (Italian) --- resources/lang/it/common.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lang/it/common.php b/resources/lang/it/common.php index 1873a100c..9b10457f4 100755 --- a/resources/lang/it/common.php +++ b/resources/lang/it/common.php @@ -38,6 +38,7 @@ return [ 'reset' => 'Azzera', 'remove' => 'Rimuovi', 'add' => 'Aggiungi', + 'fullscreen' => 'Fullscreen', // Sort Options 'sort_options' => 'Opzioni Ordinamento', From 15df902a32c738c36fe30e565386d0f55fb68a7e Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:02 +0000 Subject: [PATCH 040/191] New translations validation.php (Hungarian) --- resources/lang/hu/validation.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/lang/hu/validation.php b/resources/lang/hu/validation.php index 023f9f0a4..8b292318f 100644 --- a/resources/lang/hu/validation.php +++ b/resources/lang/hu/validation.php @@ -30,12 +30,12 @@ return [ 'digits' => ':attribute :digits számból kell álljon.', 'digits_between' => ':attribute hosszának :min és :max számjegy között kell lennie.', 'email' => ':attribute érvényes email cím kell legyen.', - 'ends_with' => 'The :attribute must end with one of the following: :values', + 'ends_with' => ':attribute attribútumnak a következők egyikével kell végződnie: :values', 'filled' => ':attribute mező kötelező.', 'gt' => [ - 'numeric' => 'The :attribute must be greater than :value.', - 'file' => 'The :attribute must be greater than :value kilobytes.', - 'string' => 'The :attribute must be greater than :value characters.', + 'numeric' => ':attribute nagyobb kell, hogy legyen, mint :value.', + 'file' => ':attribute nagyobb kell, hogy legyen, mint :value kilobájt.', + 'string' => ':attribute nagyobb kell legyen mint :value karakter.', 'array' => 'The :attribute must have more than :value items.', ], 'gte' => [ From 047b711fc42140e1f7576ec31939ed410e96ad7b Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:04 +0000 Subject: [PATCH 041/191] New translations settings.php (Hungarian) --- resources/lang/hu/settings.php | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/resources/lang/hu/settings.php b/resources/lang/hu/settings.php index 058784dc7..7059f112a 100644 --- a/resources/lang/hu/settings.php +++ b/resources/lang/hu/settings.php @@ -29,7 +29,7 @@ return [ 'app_editor_desc' => 'Annak kiválasztása, hogy a felhasználók melyik szerkesztőt használhatják az oldalak szerkesztéséhez.', 'app_custom_html' => 'Egyéni HTML fejléc tartalom', 'app_custom_html_desc' => 'Az itt hozzáadott bármilyen tartalom be lesz illesztve minden oldal szekciójának aljára. Ez hasznos a stílusok felülírásához van analitikai kódok hozzáadásához.', - 'app_custom_html_disabled_notice' => 'Custom HTML head content is disabled on this settings page to ensure any breaking changes can be reverted.', + 'app_custom_html_disabled_notice' => 'Az egyéni HTML fejléc tartalom le van tiltva ezen a beállítási oldalon, hogy az esetleg hibásan megadott módosításokat vissza lehessen állítani.', 'app_logo' => 'Alkalmazás logó', 'app_logo_desc' => 'A képnek 43px magasnak kell lennie.
A nagy képek át lesznek méretezve.', 'app_primary_color' => 'Alkalmazás elsődleges színe', @@ -41,12 +41,22 @@ return [ 'app_disable_comments_toggle' => 'Megjegyzések letiltása', 'app_disable_comments_desc' => 'Megjegyzések letiltása az alkalmazás összes oldalán.
A már létező megjegyzések el lesznek rejtve.', + // Color settings + 'content_colors' => 'Tartalomszínek', + 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'bookshelf_color' => 'Polc színe', + 'book_color' => 'Könyv színe', + 'chapter_color' => 'Fejezet színe', + 'page_color' => 'Oldal színe', + 'page_draft_color' => 'Oldalvázlat színe', + // Registration Settings 'reg_settings' => 'Regisztráció', 'reg_enable' => 'Regisztráció engedélyezése', 'reg_enable_toggle' => 'Regisztráció engedélyezése', 'reg_enable_desc' => 'Ha a regisztráció engedélyezett, akkor a felhasználó képes lesz bejelentkezni mint az alkalmazás egy felhasználója. Regisztráció után egy egyszerű, alapértelmezés szerinti felhasználói szerepkör lesz hozzárendelve.', 'reg_default_role' => 'Regisztráció utáni alapértelmezett felhasználói szerepkör', + 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', 'reg_email_confirmation' => 'Email megerősítés', 'reg_email_confirmation_toggle' => 'Email megerősítés szükséges', 'reg_confirm_email_desc' => 'Ha a tartomány korlátozás be van állítva, akkor email megerősítés szükséges és ez a beállítás figyelmen kívül lesz hagyva.', @@ -63,6 +73,13 @@ return [ 'maint_image_cleanup_warning' => ':count potenciálisan nem használt képet találtam. Biztosan törölhetőek ezek a képek?', 'maint_image_cleanup_success' => ':count potenciálisan nem használt kép megtalálva és törölve!', 'maint_image_cleanup_nothing_found' => 'Nincsenek nem használt képek, semmi sem lett törölve!', + 'maint_send_test_email' => 'Teszt e-mail küldése', + 'maint_send_test_email_desc' => 'Ez elküld egy teszt emailt a profilban megadott email címre.', + 'maint_send_test_email_run' => 'Teszt e-mail küldése', + 'maint_send_test_email_success' => 'Email elküldve :address címre', + 'maint_send_test_email_mail_subject' => 'Teszt e-mail', + 'maint_send_test_email_mail_greeting' => 'Az email kézbesítés működőképesnek tűnik!', + 'maint_send_test_email_mail_text' => 'Gratulálunk! Mivel ez az email figyelmeztetés megérkezett az email beállítások megfelelőek.', // Role Settings 'roles' => 'Szerepkörök', @@ -85,7 +102,7 @@ return [ 'role_manage_roles' => 'Szerepkörök és szerepkör engedélyek kezelése', 'role_manage_entity_permissions' => 'Minden könyv, fejezet és oldalengedély kezelése', 'role_manage_own_entity_permissions' => 'Saját könyv, fejezet és oldalak engedélyeinek kezelése', - 'role_manage_page_templates' => 'Manage page templates', + 'role_manage_page_templates' => 'Oldalsablonok kezelése', 'role_manage_settings' => 'Alkalmazás beállításainak kezelése', 'role_asset' => 'Eszköz jogosultságok', 'role_asset_desc' => 'Ezek a jogosultság vezérlik a alapértelmezés szerinti hozzáférést a rendszerben található eszközökhöz. A könyvek, fejezetek és oldalak jogosultságai felülírják ezeket a jogosultságokat.', @@ -110,8 +127,8 @@ return [ 'users_role_desc' => 'A felhasználó melyik szerepkörhöz lesz rendelve. Ha a felhasználó több szerepkörhöz van rendelve, akkor ezeknek a szerepköröknek a jogosultságai összeadódnak, és a a felhasználó a hozzárendelt szerepkörök minden képességét megkapja.', 'users_password' => 'Felhasználó jelszava', 'users_password_desc' => 'Az alkalmazásba bejelentkezéshez használható jelszó beállítása. Legalább 5 karakter hosszúnak kell lennie.', - 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', - 'users_send_invite_option' => 'Send user invite email', + 'users_send_invite_text' => 'Lehetséges egy meghívó emailt küldeni ennek a felhasználónak ami lehetővé teszi, hogy beállíthassa a saját jelszavát. Máskülönben a jelszót az erre jogosult felhasználónak kell beállítania.', + 'users_send_invite_option' => 'Felhasználó meghívó levél küldése', 'users_external_auth_id' => 'Külső hitelesítés azonosítója', 'users_external_auth_id_desc' => 'Ez az azonosító lesz használva a felhasználó ellenőrzéséhez mikor az LDAP rendszerrel kommunikál.', 'users_password_warning' => 'A lenti mezőket csak a jelszó módosításához kell kitölteni.', From 33e17aed6eb45de3b4f1e74d6338ac277b33bc9e Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:07 +0000 Subject: [PATCH 042/191] New translations entities.php (Hungarian) --- resources/lang/hu/entities.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/resources/lang/hu/entities.php b/resources/lang/hu/entities.php index 29f5822dc..6593212f0 100644 --- a/resources/lang/hu/entities.php +++ b/resources/lang/hu/entities.php @@ -162,7 +162,7 @@ return [ // Pages 'page' => 'Oldal', 'pages' => 'Oldalak', - 'x_pages' => ':count oldal|:count oldalak', + 'x_pages' => ':count oldal|:count oldal', 'pages_popular' => 'Népszerű oldalak', 'pages_new' => 'Új oldal', 'pages_attachments' => 'Csatolmányok', @@ -176,7 +176,7 @@ return [ 'pages_delete_confirm' => 'Biztosan törölhető ez az oldal?', 'pages_delete_draft_confirm' => 'Biztosan törölhető ez a vázlatoldal?', 'pages_editing_named' => ':pageName oldal szerkesztése', - 'pages_edit_draft_options' => 'Draft Options', + 'pages_edit_draft_options' => 'Vázlatbeállítások', 'pages_edit_save_draft' => 'Vázlat mentése', 'pages_edit_draft' => 'Oldal vázlat szerkesztése', 'pages_editing_draft' => 'Vázlat szerkesztése', @@ -234,7 +234,7 @@ return [ ], 'pages_draft_discarded' => 'Vázlat elvetve, a szerkesztő frissítve lesz az oldal aktuális tartalmával', 'pages_specific' => 'Egy bizonyos oldal', - 'pages_is_template' => 'Page Template', + 'pages_is_template' => 'Oldalsablon', // Editor Sidebar 'page_tags' => 'Oldal címkék', @@ -243,11 +243,11 @@ return [ 'shelf_tags' => 'Polc címkék', 'tag' => 'Címke', 'tags' => 'Címkék', - 'tag_name' => 'Tag Name', + 'tag_name' => 'Címkenév', 'tag_value' => 'Címke érték (nem kötelező)', 'tags_explain' => "Címkék hozzáadása a tartalom jobb kategorizálásához.\nA mélyebb szervezettség megvalósításához hozzá lehet rendelni egy értéket a címkéhez.", 'tags_add' => 'Másik címke hozzáadása', - 'tags_remove' => 'Remove this tag', + 'tags_remove' => 'Címke eltávolítása', 'attachments' => 'Csatolmányok', 'attachments_explain' => 'Az oldalon megjelenő fájlok feltöltése vagy hivatkozások csatolása. Az oldal oldalsávjában fognak megjelenni.', 'attachments_explain_instant_save' => 'Az itt történt módosítások azonnal el lesznek mentve.', @@ -273,12 +273,12 @@ return [ 'attachments_file_uploaded' => 'Fájl sikeresen feltöltve', 'attachments_file_updated' => 'Fájl sikeresen frissítve', 'attachments_link_attached' => 'Hivatkozás sikeresen hozzácsatolva az oldalhoz', - 'templates' => 'Templates', - 'templates_set_as_template' => 'Page is a template', - 'templates_explain_set_as_template' => 'You can set this page as a template so its contents be utilized when creating other pages. Other users will be able to use this template if they have view permissions for this page.', - 'templates_replace_content' => 'Replace page content', - 'templates_append_content' => 'Append to page content', - 'templates_prepend_content' => 'Prepend to page content', + 'templates' => 'Sablonok', + 'templates_set_as_template' => 'Az oldal egy sablon', + 'templates_explain_set_as_template' => 'Ez az oldal sablonnak lett beállítva, így a tartalma felhasználható más oldalak létrehozásakor. Más felhasználók is használhatják ezt a sablont ha megtekintési jogosultságuk van ehhez az oldalhoz.', + 'templates_replace_content' => 'Oldal tartalmának cseréje', + 'templates_append_content' => 'Hozzáfűzés az oldal tartalmához', + 'templates_prepend_content' => 'Hozzáadás az oldal tartalmának elejéhez', // Profile View 'profile_user_for_x' => 'Felhasználó ez óta: :time', From 4df112661f34879b814e03ffcbaab94ac1cccf4c Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:09 +0000 Subject: [PATCH 043/191] New translations common.php (Hungarian) --- resources/lang/hu/common.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/resources/lang/hu/common.php b/resources/lang/hu/common.php index 4bf5b5030..adfaf7759 100644 --- a/resources/lang/hu/common.php +++ b/resources/lang/hu/common.php @@ -38,12 +38,13 @@ return [ 'reset' => 'Visszaállítás', 'remove' => 'Eltávolítás', 'add' => 'Hozzáadás', + 'fullscreen' => 'Fullscreen', // Sort Options - 'sort_options' => 'Sort Options', - 'sort_direction_toggle' => 'Sort Direction Toggle', - 'sort_ascending' => 'Sort Ascending', - 'sort_descending' => 'Sort Descending', + 'sort_options' => 'Rendezési beállítások', + 'sort_direction_toggle' => 'Rendezési irány váltása', + 'sort_ascending' => 'Növekvő sorrend', + 'sort_descending' => 'Csökkenő sorrend', 'sort_name' => 'Név', 'sort_created_at' => 'Létrehozás dátuma', 'sort_updated_at' => 'Frissítés dátuma', @@ -59,10 +60,10 @@ return [ 'grid_view' => 'Rács nézet', 'list_view' => 'Lista nézet', 'default' => 'Alapértelmezés szerinti', - 'breadcrumb' => 'Breadcrumb', + 'breadcrumb' => 'Morzsa', // Header - 'profile_menu' => 'Profile Menu', + 'profile_menu' => 'Profil menü', 'view_profile' => 'Profil megtekintése', 'edit_profile' => 'Profil szerkesztése', From f1777280c3a72583887e63e4fa880ed9c832f7f4 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:10 +0000 Subject: [PATCH 044/191] New translations auth.php (Hungarian) --- resources/lang/hu/auth.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/resources/lang/hu/auth.php b/resources/lang/hu/auth.php index b55add879..dce23545e 100644 --- a/resources/lang/hu/auth.php +++ b/resources/lang/hu/auth.php @@ -66,12 +66,12 @@ return [ 'email_not_confirmed_resend_button' => 'Megerősítő email újraküldése', // User Invite - 'user_invite_email_subject' => 'You have been invited to join :appName!', - 'user_invite_email_greeting' => 'An account has been created for you on :appName.', - 'user_invite_email_text' => 'Click the button below to set an account password and gain access:', - 'user_invite_email_action' => 'Set Account Password', - 'user_invite_page_welcome' => 'Welcome to :appName!', - 'user_invite_page_text' => 'To finalise your account and gain access you need to set a password which will be used to log-in to :appName on future visits.', - 'user_invite_page_confirm_button' => 'Confirm Password', - 'user_invite_success' => 'Password set, you now have access to :appName!' + 'user_invite_email_subject' => 'Ez egy meghívó :appName weboldalhoz!', + 'user_invite_email_greeting' => 'Létre lett hozva egy fiók az :appName weboldalon.', + 'user_invite_email_text' => 'Jelszó beállításához és hozzáféréshez a lenti gombra kell kattintani:', + 'user_invite_email_action' => 'Fiók jelszó beállítása', + 'user_invite_page_welcome' => ':appName üdvözöl!', + 'user_invite_page_text' => 'A fiók véglegesítéséhez és a hozzáféréshez be kell állítani egy jelszót ami :appName weboldalon lesz használva a bejelentkezéshez.', + 'user_invite_page_confirm_button' => 'Jelszó megerősítése', + 'user_invite_success' => 'Jelszó beállítva, :appName most már elérhető!' ]; \ No newline at end of file From 4b19ba9ed12c58247c39fca0ef161313563fd76a Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:12 +0000 Subject: [PATCH 045/191] New translations validation.php (German) --- resources/lang/de/validation.php | 42 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/resources/lang/de/validation.php b/resources/lang/de/validation.php index 1cf2176d5..b6105d192 100644 --- a/resources/lang/de/validation.php +++ b/resources/lang/de/validation.php @@ -30,19 +30,19 @@ return [ 'digits' => ':attribute muss :digits Stellen haben.', 'digits_between' => ':attribute muss zwischen :min und :max Stellen haben.', 'email' => ':attribute muss eine valide E-Mail-Adresse sein.', - 'ends_with' => 'The :attribute must end with one of the following: :values', + 'ends_with' => ':attribute muss mit einem der folgenden Werte: :values enden', 'filled' => ':attribute ist erforderlich.', 'gt' => [ - 'numeric' => 'The :attribute must be greater than :value.', - 'file' => 'The :attribute must be greater than :value kilobytes.', - 'string' => 'The :attribute must be greater than :value characters.', - 'array' => 'The :attribute must have more than :value items.', + 'numeric' => ':attribute muss größer als :value sein.', + 'file' => ':attribute muss mindestens :value Kilobytes groß sein.', + 'string' => ':attribute muss mehr als :value Zeichen haben.', + 'array' => ':attribute muss mindestens :value Elemente haben.', ], 'gte' => [ - 'numeric' => 'The :attribute must be greater than or equal :value.', - 'file' => 'The :attribute must be greater than or equal :value kilobytes.', - 'string' => 'The :attribute must be greater than or equal :value characters.', - 'array' => 'The :attribute must have :value items or more.', + 'numeric' => ':attribute muss größer-gleich :value sein.', + 'file' => ':attribute muss mindestens :value Kilobytes groß sein.', + 'string' => ':attribute muss mindestens :value Zeichen enthalten.', + 'array' => ':attribute muss :value Elemente oder mehr haben.', ], 'exists' => ':attribute ist ungültig.', 'image' => ':attribute muss ein Bild sein.', @@ -50,20 +50,20 @@ return [ 'in' => ':attribute ist ungültig.', 'integer' => ':attribute muss eine Zahl sein.', 'ip' => ':attribute muss eine valide IP-Adresse sein.', - 'ipv4' => 'The :attribute must be a valid IPv4 address.', - 'ipv6' => 'The :attribute must be a valid IPv6 address.', - 'json' => 'The :attribute must be a valid JSON string.', + 'ipv4' => ':attribute muss eine gültige IPv4 Adresse sein.', + 'ipv6' => ':attribute muss eine gültige IPv6-Adresse sein.', + 'json' => 'Das Attribut muss eine gültige JSON-Zeichenfolge sein.', 'lt' => [ - 'numeric' => 'The :attribute must be less than :value.', - 'file' => 'The :attribute must be less than :value kilobytes.', - 'string' => 'The :attribute must be less than :value characters.', - 'array' => 'The :attribute must have less than :value items.', + 'numeric' => ':attribute muss kleiner sein :value sein.', + 'file' => ':attribute muss kleiner als :value Kilobytes sein.', + 'string' => ':attribute muss weniger als :value Zeichen haben.', + 'array' => ':attribute muss weniger als :value Elemente haben.', ], 'lte' => [ - 'numeric' => 'The :attribute must be less than or equal :value.', - 'file' => 'The :attribute must be less than or equal :value kilobytes.', - 'string' => 'The :attribute must be less than or equal :value characters.', - 'array' => 'The :attribute must not have more than :value items.', + 'numeric' => ':attribute muss kleiner oder gleich :value sein.', + 'file' => ':attribute muss kleiner oder gleich :value Kilobytes sein.', + 'string' => ':attribute darf höchstens :value Zeichen besitzen.', + 'array' => ':attribute darf höchstens :value Elemente haben.', ], 'max' => [ 'numeric' => ':attribute darf nicht größer als :max sein.', @@ -80,7 +80,7 @@ return [ ], 'no_double_extension' => ':attribute darf nur eine gültige Dateiendung', 'not_in' => ':attribute ist ungültig.', - 'not_regex' => 'The :attribute format is invalid.', + 'not_regex' => ':attribute ist kein valides Format.', 'numeric' => ':attribute muss eine Zahl sein.', 'regex' => ':attribute ist in einem ungültigen Format.', 'required' => ':attribute ist erforderlich.', From 76f43b95d43cc73352a5b6015f8fcd25da4be59c Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:13 +0000 Subject: [PATCH 046/191] New translations settings.php (German) --- resources/lang/de/settings.php | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/resources/lang/de/settings.php b/resources/lang/de/settings.php index fa7df43f8..103515739 100644 --- a/resources/lang/de/settings.php +++ b/resources/lang/de/settings.php @@ -23,13 +23,13 @@ return [ 'app_public_access_toggle' => 'Öffentlichen Zugriff erlauben', 'app_public_viewing' => 'Öffentliche Ansicht erlauben?', 'app_secure_images' => 'Erhöhte Sicherheit für hochgeladene Bilder aktivieren?', - 'app_secure_images_toggle' => 'Enable higher security image uploads', + 'app_secure_images_toggle' => 'Aktiviere Bild-Upload höherer Sicherheit', 'app_secure_images_desc' => 'Aus Leistungsgründen sind alle Bilder öffentlich sichtbar. Diese Option fügt zufällige, schwer zu eratene, Zeichenketten zu Bild-URLs hinzu. Stellen sie sicher, dass Verzeichnisindizes deaktiviert sind, um einen einfachen Zugriff zu verhindern.', 'app_editor' => 'Seiteneditor', 'app_editor_desc' => 'Wählen Sie den Editor aus, der von allen Benutzern genutzt werden soll, um Seiten zu editieren.', 'app_custom_html' => 'Benutzerdefinierter HTML Inhalt', 'app_custom_html_desc' => 'Jeder Inhalt, der hier hinzugefügt wird, wird am Ende der Sektion jeder Seite eingefügt. Diese kann praktisch sein, um CSS Styles anzupassen oder Analytics-Code hinzuzufügen.', - 'app_custom_html_disabled_notice' => 'Custom HTML head content is disabled on this settings page to ensure any breaking changes can be reverted.', + 'app_custom_html_disabled_notice' => 'Benutzerdefinierte HTML-Kopfzeileninhalte sind auf dieser Einstellungsseite deaktiviert, um sicherzustellen, dass alle Änderungen rückgängig gemacht werden können.', 'app_logo' => 'Anwendungslogo', 'app_logo_desc' => 'Dieses Bild sollte 43px hoch sein. Größere Bilder werden verkleinert.', @@ -43,12 +43,22 @@ Wenn Sie nicht eingeben, wird die Anwendung auf die Standardfarbe zurückgesetzt 'app_disable_comments_toggle' => 'Kommentare deaktivieren', 'app_disable_comments_desc' => 'Deaktiviert Kommentare über alle Seiten in der Anwendung. Vorhandene Kommentare werden nicht angezeigt.', + // Color settings + 'content_colors' => 'Inhaltsfarben', + 'content_colors_desc' => 'Legt Farben für alle Elemente in der Seitenorganisationshierarchie fest. Die Auswahl von Farben mit einer ähnlichen Helligkeit wie die Standardfarben wird zur Lesbarkeit empfohlen.', + 'bookshelf_color' => 'Regalfarbe', + 'book_color' => 'Buchfarbe', + 'chapter_color' => 'Kapitelfarbe', + 'page_color' => 'Seitenfarbe', + 'page_draft_color' => 'Seitenentwurfsfarbe', + // Registration Settings 'reg_settings' => 'Registrierungseinstellungen', 'reg_enable' => 'Registrierung erlauben?', 'reg_enable_toggle' => 'Registrierung erlauben', 'reg_enable_desc' => 'Wenn die Registrierung erlaubt ist, kann sich der Benutzer als Anwendungsbenutzer anmelden. Bei der Registrierung erhält er eine einzige, voreingestellte Benutzerrolle.', 'reg_default_role' => 'Standard-Benutzerrolle nach Registrierung', + 'reg_enable_ldap_warning' => 'Die obige Option wird während der LDAP-Authentifizierung nicht verwendet. Benutzerkonten für nicht existierende Mitglieder werden automatisch erzeugt, wenn die Authentifizierung gegen das verwendete LDAP-System erfolgreich ist.', 'reg_email_confirmation' => 'Bestätigung per E-Mail', 'reg_email_confirmation_toggle' => 'Bestätigung per E-Mail erforderlich', 'reg_confirm_email_desc' => 'Falls die Einschränkung für Domains genutzt wird, ist die Bestätigung per E-Mail zwingend erforderlich und der untenstehende Wert wird ignoriert.', @@ -66,6 +76,13 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'maint_image_cleanup_warning' => ':count eventuell unbenutze Bilder wurden gefunden. Möchten Sie diese Bilder löschen?', 'maint_image_cleanup_success' => ':count eventuell unbenutze Bilder wurden gefunden und gelöscht.', 'maint_image_cleanup_nothing_found' => 'Keine unbenutzen Bilder gefunden. Nichts zu löschen!', + 'maint_send_test_email' => 'Test Email versenden', + 'maint_send_test_email_desc' => 'Dies sendet eine Test E-Mail an Ihre in Ihrem Profil angegebene E-Mail-Adresse.', + 'maint_send_test_email_run' => 'Sende eine Test E-Mail', + 'maint_send_test_email_success' => 'E-Mail wurde an :address gesendet', + 'maint_send_test_email_mail_subject' => 'Test E-Mail', + 'maint_send_test_email_mail_greeting' => 'E-Mail-Versand scheint zu funktionieren!', + 'maint_send_test_email_mail_text' => 'Glückwunsch! Da Sie diese E-Mail Benachrichtigung erhalten haben, scheinen Ihre E-Mail-Einstellungen korrekt konfiguriert zu sein.', // Role Settings 'roles' => 'Rollen', @@ -88,7 +105,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'role_manage_roles' => 'Rollen und Rollen-Berechtigungen verwalten', 'role_manage_entity_permissions' => 'Alle Buch-, Kapitel- und Seiten-Berechtigungen verwalten', 'role_manage_own_entity_permissions' => 'Nur Berechtigungen eigener Bücher, Kapitel und Seiten verwalten', - 'role_manage_page_templates' => 'Manage page templates', + 'role_manage_page_templates' => 'Seitenvorlagen verwalten', 'role_manage_settings' => 'Globaleinstellungen verwalten', 'role_asset' => 'Berechtigungen', 'role_asset_desc' => 'Diese Berechtigungen gelten für den Standard-Zugriff innerhalb des Systems. Berechtigungen für Bücher, Kapitel und Seiten überschreiben diese Berechtigungenen.', @@ -113,8 +130,8 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'users_role_desc' => 'Wählen Sie aus, welchen Rollen dieser Benutzer zugeordnet werden soll. Wenn ein Benutzer mehreren Rollen zugeordnet ist, werden die Berechtigungen dieser Rollen gestapelt und er erhält alle Fähigkeiten der zugewiesenen Rollen.', 'users_password' => 'Benutzerpasswort', 'users_password_desc' => 'Legen Sie ein Passwort fest, mit dem Sie sich anmelden möchten. Diese muss mindestens 5 Zeichen lang sein.', - 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', - 'users_send_invite_option' => 'Send user invite email', + 'users_send_invite_text' => 'Sie können diesem Benutzer eine Einladungs-E-Mail senden, die es ihm erlaubt, sein eigenes Passwort zu setzen, andernfalls können Sie sein Passwort selbst setzen.', + 'users_send_invite_option' => 'Benutzer-Einladungs-E-Mail senden', 'users_external_auth_id' => 'Externe Authentifizierungs-ID', 'users_external_auth_id_desc' => 'Dies ist die ID, die verwendet wird, um diesen Benutzer bei der Kommunikation mit Ihrem LDAP-System abzugleichen.', 'users_password_warning' => 'Füllen Sie die folgenden Felder nur aus, wenn Sie Ihr Passwort ändern möchten:', From a26027946394da4f44e70c15a77ed93a03ebf227 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:15 +0000 Subject: [PATCH 047/191] New translations errors.php (German) --- resources/lang/de/errors.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/resources/lang/de/errors.php b/resources/lang/de/errors.php index ff2bf8653..0ed6cea66 100644 --- a/resources/lang/de/errors.php +++ b/resources/lang/de/errors.php @@ -19,6 +19,10 @@ return [ 'ldap_cannot_connect' => 'Die Verbindung zum LDAP-Server ist fehlgeschlagen. Beim initialen Verbindungsaufbau trat ein Fehler auf.', 'saml_already_logged_in' => 'Sie sind bereits angemeldet', 'saml_user_not_registered' => 'Kein Benutzer mit ID :name registriert und die automatische Registrierung ist deaktiviert', + 'saml_no_email_address' => 'Es konnte keine E-Mail-Adresse für diesen Benutzer in den vom externen Authentifizierungssystem zur Verfügung gestellten Daten gefunden werden', + 'saml_invalid_response_id' => 'Die Anfrage vom externen Authentifizierungssystem wird von einem von dieser Anwendung gestarteten Prozess nicht erkannt. Das Zurückgehen nach einem Login könnte dieses Problem verursachen.', + 'saml_fail_authed' => 'Anmeldung mit :system fehlgeschlagen, System konnte keine erfolgreiche Autorisierung bereitstellen', + 'saml_email_exists' => 'Registrierung fehlgeschlagen, da bereits ein Benutzer mit der E-Mail-Adresse ":email" existiert', 'social_no_action_defined' => 'Es ist keine Aktion definiert', 'social_login_bad_response' => "Fehler bei der :socialAccount-Anmeldung: \n:error", 'social_account_in_use' => 'Dieses :socialAccount-Konto wird bereits verwendet. Bitte melden Sie sich mit dem :socialAccount-Konto an.', @@ -29,7 +33,7 @@ return [ 'social_account_register_instructions' => 'Wenn Sie bisher keinen Social-Media Konto besitzen, können Sie ein solches Konto mit der :socialAccount Option anlegen.', 'social_driver_not_found' => 'Treiber für Social-Media-Konten nicht gefunden', 'social_driver_not_configured' => 'Ihr :socialAccount-Konto ist nicht korrekt konfiguriert.', - 'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.', + 'invite_token_expired' => 'Dieser Einladungslink ist abgelaufen. Sie können stattdessen versuchen, Ihr Passwort zurückzusetzen.', // System 'path_not_writable' => 'Die Datei kann nicht in den angegebenen Pfad :filePath hochgeladen werden. Stellen Sie sicher, dass dieser Ordner auf dem Server beschreibbar ist.', From 8c224a57f08c62212deebf908ccdd628bbf96bf6 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:17 +0000 Subject: [PATCH 048/191] New translations entities.php (German) --- resources/lang/de/entities.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/resources/lang/de/entities.php b/resources/lang/de/entities.php index 164d7a794..e666c664c 100644 --- a/resources/lang/de/entities.php +++ b/resources/lang/de/entities.php @@ -176,7 +176,7 @@ return [ 'pages_delete_confirm' => 'Sind Sie sicher, dass Sie diese Seite löschen möchen?', 'pages_delete_draft_confirm' => 'Sind Sie sicher, dass Sie diesen Seitenentwurf löschen möchten?', 'pages_editing_named' => 'Seite ":pageName" bearbeiten', - 'pages_edit_draft_options' => 'Draft Options', + 'pages_edit_draft_options' => 'Entwurfsoptionen', 'pages_edit_save_draft' => 'Entwurf speichern', 'pages_edit_draft' => 'Seitenentwurf bearbeiten', 'pages_editing_draft' => 'Seitenentwurf bearbeiten', @@ -211,7 +211,7 @@ return [ 'pages_revisions_date' => 'Versionsdatum', 'pages_revisions_number' => '#', 'pages_revisions_numbered' => 'Revision #:id', - 'pages_revisions_numbered_changes' => 'Revision #:id Changes', + 'pages_revisions_numbered_changes' => 'Revision #:id Änderungen', 'pages_revisions_changelog' => 'Änderungsprotokoll', 'pages_revisions_changes' => 'Änderungen', 'pages_revisions_current' => 'Aktuelle Version', @@ -233,8 +233,8 @@ return [ 'message' => ':start :time. Achten Sie darauf, keine Änderungen von anderen Benutzern zu überschreiben!', ], 'pages_draft_discarded' => 'Entwurf verworfen. Der aktuelle Seiteninhalt wurde geladen.', - 'pages_specific' => 'Specific Page', - 'pages_is_template' => 'Page Template', + 'pages_specific' => 'Spezifische Seite', + 'pages_is_template' => 'Seitenvorlage', // Editor Sidebar 'page_tags' => 'Seiten-Schlagwörter', @@ -243,11 +243,11 @@ return [ 'shelf_tags' => 'Regal-Schlagwörter', 'tag' => 'Schlagwort', 'tags' => 'Schlagwörter', - 'tag_name' => 'Tag Name', + 'tag_name' => 'Schlagwort Name', 'tag_value' => 'Inhalt (Optional)', 'tags_explain' => "Fügen Sie Schlagwörter hinzu, um Ihren Inhalt zu kategorisieren.\nSie können einen erklärenden Inhalt hinzufügen, um eine genauere Unterteilung vorzunehmen.", 'tags_add' => 'Weiteres Schlagwort hinzufügen', - 'tags_remove' => 'Remove this tag', + 'tags_remove' => 'Diesen Tag entfernen', 'attachments' => 'Anhänge', 'attachments_explain' => 'Sie können auf Ihrer Seite Dateien hochladen oder Links hinzufügen. Diese werden in der Seitenleiste angezeigt.', 'attachments_explain_instant_save' => 'Änderungen werden direkt gespeichert.', @@ -273,12 +273,12 @@ return [ 'attachments_file_uploaded' => 'Datei erfolgreich hochgeladen', 'attachments_file_updated' => 'Datei erfolgreich aktualisiert', 'attachments_link_attached' => 'Link erfolgreich der Seite hinzugefügt', - 'templates' => 'Templates', - 'templates_set_as_template' => 'Page is a template', - 'templates_explain_set_as_template' => 'You can set this page as a template so its contents be utilized when creating other pages. Other users will be able to use this template if they have view permissions for this page.', - 'templates_replace_content' => 'Replace page content', - 'templates_append_content' => 'Append to page content', - 'templates_prepend_content' => 'Prepend to page content', + 'templates' => 'Vorlagen', + 'templates_set_as_template' => 'Seite ist eine Vorlage', + 'templates_explain_set_as_template' => 'Sie können diese Seite als Vorlage festlegen, damit deren Inhalt beim Erstellen anderer Seiten verwendet werden kann. Andere Benutzer können diese Vorlage verwenden, wenn sie die Zugriffsrechte für diese Seite haben.', + 'templates_replace_content' => 'Seiteninhalt ersetzen', + 'templates_append_content' => 'An Seiteninhalt anhängen', + 'templates_prepend_content' => 'Seiteninhalt voranstellen', // Profile View 'profile_user_for_x' => 'Benutzer seit :time', From 702ad28a9a272cc29c32bbe0ab89193400e1f8dc Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:18 +0000 Subject: [PATCH 049/191] New translations common.php (German) --- resources/lang/de/common.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/resources/lang/de/common.php b/resources/lang/de/common.php index 94e59d154..402e2b36d 100644 --- a/resources/lang/de/common.php +++ b/resources/lang/de/common.php @@ -38,12 +38,13 @@ return [ 'reset' => 'Zurücksetzen', 'remove' => 'Entfernen', 'add' => 'Hinzufügen', + 'fullscreen' => 'Vollbild', // Sort Options - 'sort_options' => 'Sort Options', - 'sort_direction_toggle' => 'Sort Direction Toggle', - 'sort_ascending' => 'Sort Ascending', - 'sort_descending' => 'Sort Descending', + 'sort_options' => 'Sortieroptionen', + 'sort_direction_toggle' => 'Sortierreihenfolge umkehren', + 'sort_ascending' => 'Aufsteigend sortieren', + 'sort_descending' => 'Absteigend sortieren', 'sort_name' => 'Name', 'sort_created_at' => 'Erstellungsdatum', 'sort_updated_at' => 'Aktualisierungsdatum', @@ -59,10 +60,10 @@ return [ 'grid_view' => 'Gitteransicht', 'list_view' => 'Listenansicht', 'default' => 'Voreinstellung', - 'breadcrumb' => 'Breadcrumb', + 'breadcrumb' => 'Brotkrumen', // Header - 'profile_menu' => 'Profile Menu', + 'profile_menu' => 'Profilmenü', 'view_profile' => 'Profil ansehen', 'edit_profile' => 'Profil bearbeiten', From e2fec5cb4ffe2c549a63cb591bd8b90a8578c88d Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:20 +0000 Subject: [PATCH 050/191] New translations settings.php (Italian) --- resources/lang/it/settings.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/resources/lang/it/settings.php b/resources/lang/it/settings.php index 90d5c89ea..ac66446e1 100755 --- a/resources/lang/it/settings.php +++ b/resources/lang/it/settings.php @@ -41,12 +41,22 @@ return [ 'app_disable_comments_toggle' => 'Disabilita commenti', 'app_disable_comments_desc' => 'Disabilita i commenti su tutte le pagine nell\'applicazione. I commenti esistenti non sono mostrati. ', + // Color settings + 'content_colors' => 'Content Colors', + 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'bookshelf_color' => 'Shelf Color', + 'book_color' => 'Book Color', + 'chapter_color' => 'Chapter Color', + 'page_color' => 'Page Color', + 'page_draft_color' => 'Page Draft Color', + // Registration Settings 'reg_settings' => 'Impostazioni Registrazione', 'reg_enable' => 'Abilita Registrazione', 'reg_enable_toggle' => 'Abilita registrazione', 'reg_enable_desc' => 'Quando la registrazione è abilitata, l\utente sarà in grado di registrarsi all\'applicazione. Al momento della registrazione gli verrà associato un ruolo utente predefinito.', 'reg_default_role' => 'Ruolo predefinito dopo la registrazione', + 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', 'reg_email_confirmation' => 'Conferma Email', 'reg_email_confirmation_toggle' => 'Richiedi conferma email', 'reg_confirm_email_desc' => 'Se la restrizione per dominio è usata la conferma della mail sarà richiesta e la scelta ignorata.', From 433d66e40634e71c48e99b2ff7c6b39c23da2b11 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:21 +0000 Subject: [PATCH 051/191] New translations activities.php (German) --- resources/lang/de/activities.php | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/resources/lang/de/activities.php b/resources/lang/de/activities.php index 170a19108..fadf5d638 100644 --- a/resources/lang/de/activities.php +++ b/resources/lang/de/activities.php @@ -6,33 +6,33 @@ return [ // Pages - 'page_create' => 'erstellt Seite', + 'page_create' => 'erstellte Seite', 'page_create_notification' => 'Die Seite wurde erfolgreich erstellt.', - 'page_update' => 'aktualisiert Seite', + 'page_update' => 'aktualisierte Seite', 'page_update_notification' => 'Die Seite wurde erfolgreich aktualisiert.', - 'page_delete' => 'löscht Seite', + 'page_delete' => 'gelöschte Seite', 'page_delete_notification' => 'Die Seite wurde erfolgreich gelöscht.', - 'page_restore' => 'stellt Seite wieder her', + 'page_restore' => 'wiederhergestellte Seite', 'page_restore_notification' => 'Die Seite wurde erfolgreich wiederhergestellt.', - 'page_move' => 'verschiebt Seite', + 'page_move' => 'Seite verschoben', // Chapters - 'chapter_create' => 'erstellt Kapitel', + 'chapter_create' => 'erstellte Kapitel', 'chapter_create_notification' => 'Das Kapitel wurde erfolgreich erstellt.', - 'chapter_update' => 'aktualisiert Kapitel', + 'chapter_update' => 'aktualisierte Kapitel', 'chapter_update_notification' => 'Das Kapitel wurde erfolgreich aktualisiert.', - 'chapter_delete' => 'löscht Kapitel', + 'chapter_delete' => 'löschte Kapitel', 'chapter_delete_notification' => 'Das Kapitel wurde erfolgreich gelöscht.', - 'chapter_move' => 'verschiebt Kapitel', + 'chapter_move' => 'verschob Kapitel', // Books - 'book_create' => 'erstellt Buch', + 'book_create' => 'erstellte Buch', 'book_create_notification' => 'Das Buch wurde erfolgreich erstellt.', - 'book_update' => 'aktualisiert Buch', + 'book_update' => 'aktualisierte Buch', 'book_update_notification' => 'Das Buch wurde erfolgreich aktualisiert.', - 'book_delete' => 'löscht Buch', + 'book_delete' => 'löschte Buch', 'book_delete_notification' => 'Das Buch wurde erfolgreich gelöscht.', - 'book_sort' => 'sortiert Buch', + 'book_sort' => 'sortierte Buch', 'book_sort_notification' => 'Das Buch wurde erfolgreich umsortiert.', // Bookshelves From 9b0d1f1328e8e02c43a835277daffdd510559515 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:23 +0000 Subject: [PATCH 052/191] New translations errors.php (Polish) --- resources/lang/pl/errors.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/lang/pl/errors.php b/resources/lang/pl/errors.php index 406755c35..fd378214a 100644 --- a/resources/lang/pl/errors.php +++ b/resources/lang/pl/errors.php @@ -20,9 +20,9 @@ return [ 'saml_already_logged_in' => 'Już zalogowany', 'saml_user_not_registered' => 'Użytkownik :name nie jest zarejestrowany i automatyczna rejestracja jest wyłączona', 'saml_no_email_address' => 'Nie można odnaleźć adresu email dla tego użytkownika w danych dostarczonych przez zewnętrzny system uwierzytelniania', - 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', - 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', - 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', + 'saml_invalid_response_id' => 'Żądanie z zewnętrznego systemu uwierzytelniania nie zostało rozpoznane przez proces rozpoczęty przez tę aplikację. Cofnięcie po zalogowaniu mogło spowodować ten problem.', + 'saml_fail_authed' => 'Logowanie przy użyciu :system nie powiodło się, system nie mógł pomyślnie ukończyć uwierzytelniania', + 'saml_email_exists' => 'Rejestracja nie powiodła się, ponieważ użytkownik z adresem email ":email" już istnieje', 'social_no_action_defined' => 'Brak zdefiniowanej akcji', 'social_login_bad_response' => "Podczas próby logowania :socialAccount wystąpił błąd: \n:error", 'social_account_in_use' => 'To konto :socialAccount jest już w użyciu. Spróbuj zalogować się za pomocą opcji :socialAccount.', From 8d3220c98af892c543c05dd85c7801d2e947d03e Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:25 +0000 Subject: [PATCH 053/191] New translations entities.php (Polish) --- resources/lang/pl/entities.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/resources/lang/pl/entities.php b/resources/lang/pl/entities.php index 122139b67..9a1b7f9d2 100644 --- a/resources/lang/pl/entities.php +++ b/resources/lang/pl/entities.php @@ -68,7 +68,7 @@ return [ // Shelves 'shelf' => 'Półka', 'shelves' => 'Półki', - 'x_shelves' => ':count Shelf|:count Shelves', + 'x_shelves' => ':count Półek|:count Półek', 'shelves_long' => 'Półki', 'shelves_empty' => 'Brak utworzonych półek', 'shelves_create' => 'Utwórz półkę', @@ -105,7 +105,7 @@ return [ 'books_popular' => 'Popularne książki', 'books_recent' => 'Ostatnie książki', 'books_new' => 'Nowe książki', - 'books_new_action' => 'New Book', + 'books_new_action' => 'Nowa księga', 'books_popular_empty' => 'Najpopularniejsze książki pojawią się w tym miejscu.', 'books_new_empty' => 'Tutaj pojawią się ostatnio utworzone książki.', 'books_create' => 'Utwórz książkę', @@ -235,7 +235,7 @@ return [ ], 'pages_draft_discarded' => 'Wersja robocza odrzucona, edytor został uzupełniony najnowszą wersją strony', 'pages_specific' => 'Określona strona', - 'pages_is_template' => 'Page Template', + 'pages_is_template' => 'Szablon strony', // Editor Sidebar 'page_tags' => 'Tagi strony', @@ -244,11 +244,11 @@ return [ 'shelf_tags' => 'Tagi półki', 'tag' => 'Tag', 'tags' => 'Tagi', - 'tag_name' => 'Tag Name', + 'tag_name' => 'Nazwa tagu', 'tag_value' => 'Wartość tagu (opcjonalnie)', 'tags_explain' => "Dodaj tagi by skategoryzować zawartość. \n W celu dokładniejszej organizacji zawartości możesz dodać wartości do tagów.", 'tags_add' => 'Dodaj kolejny tag', - 'tags_remove' => 'Remove this tag', + 'tags_remove' => 'Usuń ten tag', 'attachments' => 'Załączniki', 'attachments_explain' => 'Prześlij kilka plików lub załącz linki. Będą one widoczne na pasku bocznym strony.', 'attachments_explain_instant_save' => 'Zmiany są zapisywane natychmiastowo.', @@ -274,7 +274,7 @@ return [ 'attachments_file_uploaded' => 'Plik załączony pomyślnie', 'attachments_file_updated' => 'Plik zaktualizowany pomyślnie', 'attachments_link_attached' => 'Link pomyślnie dodany do strony', - 'templates' => 'Templates', + 'templates' => 'Szablony', 'templates_set_as_template' => 'Strona jest szablonem', 'templates_explain_set_as_template' => 'Możesz ustawić tę stronę jako szablon, tak aby jej zawartość była wykorzystywana przy tworzeniu innych stron. Inni użytkownicy będą mogli korzystać z tego szablonu, jeśli mają uprawnienia do przeglądania tej strony.', 'templates_replace_content' => 'Zmień zawartość strony', From 83e946f1461545945a9664b49e784ce501394c43 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:26 +0000 Subject: [PATCH 054/191] New translations common.php (Polish) --- resources/lang/pl/common.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/resources/lang/pl/common.php b/resources/lang/pl/common.php index 664e7c4c5..f91a682e5 100644 --- a/resources/lang/pl/common.php +++ b/resources/lang/pl/common.php @@ -24,7 +24,7 @@ return [ // Actions 'actions' => 'Akcje', 'view' => 'Widok', - 'view_all' => 'View All', + 'view_all' => 'Zobacz wszystkie', 'create' => 'Utwórz', 'update' => 'Zaktualizuj', 'edit' => 'Edytuj', @@ -38,6 +38,7 @@ return [ 'reset' => 'Resetuj', 'remove' => 'Usuń', 'add' => 'Dodaj', + 'fullscreen' => 'Fullscreen', // Sort Options 'sort_options' => 'Opcje sortowania', @@ -62,7 +63,7 @@ return [ 'breadcrumb' => 'Breadcrumb', // Header - 'profile_menu' => 'Profile Menu', + 'profile_menu' => 'Menu profilu', 'view_profile' => 'Zobacz profil', 'edit_profile' => 'Edytuj profil', From 78bd4829315d2f23128d985dd27a404eb5f68e9b Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:29 +0000 Subject: [PATCH 055/191] New translations settings.php (Korean) --- resources/lang/ko/settings.php | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/resources/lang/ko/settings.php b/resources/lang/ko/settings.php index 712902b66..be1747040 100755 --- a/resources/lang/ko/settings.php +++ b/resources/lang/ko/settings.php @@ -41,12 +41,22 @@ return [ 'app_disable_comments_toggle' => '댓글 사용 안 함', 'app_disable_comments_desc' => '모든 페이지에서 댓글을 숨깁니다.', + // Color settings + 'content_colors' => 'Content Colors', + 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'bookshelf_color' => 'Shelf Color', + 'book_color' => 'Book Color', + 'chapter_color' => 'Chapter Color', + 'page_color' => 'Page Color', + 'page_draft_color' => 'Page Draft Color', + // Registration Settings 'reg_settings' => '가입', 'reg_enable' => '사이트 가입 허용', 'reg_enable_toggle' => '사이트 가입 허용', 'reg_enable_desc' => '가입한 사용자는 단일한 권한을 가집니다.', 'reg_default_role' => '가입한 사용자의 기본 권한', + 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', 'reg_email_confirmation' => '메일 주소 확인', 'reg_email_confirmation_toggle' => '주소 확인 요구', 'reg_confirm_email_desc' => '도메인 차단을 쓰고 있으면 메일 주소를 확인해야 하고, 이 설정은 무시합니다.', @@ -57,12 +67,19 @@ return [ // Maintenance settings 'maint' => '데이터', 'maint_image_cleanup' => '이미지 정리', - 'maint_image_cleanup_desc' => '중복한 이미지를 찾습니다. 실행하기 전에 이미지를 백업하세요.', + 'maint_image_cleanup_desc' => "중복한 이미지를 찾습니다. 실행하기 전에 이미지를 백업하세요.", 'maint_image_cleanup_ignore_revisions' => '수정본에 있는 이미지 제외', 'maint_image_cleanup_run' => '실행', 'maint_image_cleanup_warning' => '이미지 :count개를 지울 건가요?', 'maint_image_cleanup_success' => '이미지 :count개 삭제함', 'maint_image_cleanup_nothing_found' => '삭제한 것 없음', + 'maint_send_test_email' => 'Send a Test Email', + 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', + 'maint_send_test_email_run' => 'Send test email', + 'maint_send_test_email_success' => 'Email sent to :address', + 'maint_send_test_email_mail_subject' => 'Test Email', + 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', + 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', // Role Settings 'roles' => '권한', @@ -72,7 +89,7 @@ return [ 'role_delete' => '권한 지우기', 'role_delete_confirm' => ':roleName(을)를 지웁니다.', 'role_delete_users_assigned' => '이 권한을 가진 사용자 :userCount명에 할당할 권한을 고르세요.', - 'role_delete_no_migration' => '할당하지 않음', + 'role_delete_no_migration' => "할당하지 않음", 'role_delete_sure' => '이 권한을 지울 건가요?', 'role_delete_success' => '권한 지움', 'role_edit' => '권한 수정', @@ -135,9 +152,8 @@ return [ 'users_social_connected' => ':socialAccount(와)과 연결했습니다.', 'users_social_disconnected' => ':socialAccount(와)과의 연결을 끊었습니다.', - //! Since these labels are already localized this array does not need to be - //! translated in the language-specific files. - //! DELETE BELOW IF COPIED FROM EN + //! If editing translations files directly please ignore this in all + //! languages apart from en. Content will be auto-copied from en. //!//////////////////////////////// 'language_select' => [ 'en' => 'English', From 7cf60afe14a2ae5ef10c186d47e26081dff26b79 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:30 +0000 Subject: [PATCH 056/191] New translations passwords.php (Korean) --- resources/lang/ko/passwords.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lang/ko/passwords.php b/resources/lang/ko/passwords.php index 144736c3b..35a2a5933 100644 --- a/resources/lang/ko/passwords.php +++ b/resources/lang/ko/passwords.php @@ -7,7 +7,7 @@ return [ 'password' => '여덟 글자를 넘어야 합니다.', - 'user' => '메일 주소를 가진 사용자가 없습니다.', + 'user' => "메일 주소를 가진 사용자가 없습니다.", 'token' => '이 링크는 더 이상 유효하지 않습니다.', 'sent' => '메일을 보냈습니다.', 'reset' => '비밀번호를 바꿨습니다.', From 58b14d9e89f2e5e76ef61bee4ec22f077b1f5ca9 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:32 +0000 Subject: [PATCH 057/191] New translations entities.php (Korean) --- resources/lang/ko/entities.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/lang/ko/entities.php b/resources/lang/ko/entities.php index 4d5e1bc83..a166cda40 100644 --- a/resources/lang/ko/entities.php +++ b/resources/lang/ko/entities.php @@ -87,7 +87,7 @@ return [ 'shelves_edit' => '서가 바꾸기', 'shelves_delete' => '서가 지우기', 'shelves_delete_named' => ':name 지우기', - 'shelves_delete_explain' => ':name을 지웁니다. 책자는 지우지 않습니다.', + 'shelves_delete_explain' => ":name을 지웁니다. 책자는 지우지 않습니다.", 'shelves_delete_confirmation' => '이 서가를 지울 건가요?', 'shelves_permissions' => '서가 권한', 'shelves_permissions_updated' => '서가 권한 바꿈', @@ -245,7 +245,7 @@ return [ 'tags' => '꼬리표', 'tag_name' => '꼬리표 이름', 'tag_value' => '리스트 값 (선택 사항)', - 'tags_explain' => '태그로 문서를 분류하세요.', + 'tags_explain' => "태그로 문서를 분류하세요.", 'tags_add' => '태그 추가', 'tags_remove' => '태그 삭제', 'attachments' => '첨부 파일', From cf473edcbd07276466b24830a5a553fdba2caffb Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:34 +0000 Subject: [PATCH 058/191] New translations common.php (Korean) --- resources/lang/ko/common.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lang/ko/common.php b/resources/lang/ko/common.php index 8d3a148a5..d50965752 100644 --- a/resources/lang/ko/common.php +++ b/resources/lang/ko/common.php @@ -38,6 +38,7 @@ return [ 'reset' => '리셋', 'remove' => '제거', 'add' => '추가', + 'fullscreen' => 'Fullscreen', // Sort Options 'sort_options' => '정렬 기준', From f5a83eccb759b75d07f7d6d1e9721e4fc6f3e702 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:35 +0000 Subject: [PATCH 059/191] New translations auth.php (Korean) --- resources/lang/ko/auth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lang/ko/auth.php b/resources/lang/ko/auth.php index 9701bdf70..5346c5540 100644 --- a/resources/lang/ko/auth.php +++ b/resources/lang/ko/auth.php @@ -74,4 +74,4 @@ return [ 'user_invite_page_text' => ':appName에 로그인할 때 입력할 비밀번호를 설정하세요.', 'user_invite_page_confirm_button' => '비밀번호 확인', 'user_invite_success' => '이제 :appName에 접근할 수 있습니다.' -]; +]; \ No newline at end of file From 5d214b184d2fa32a73ed87afe15e99f4834903f5 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:38 +0000 Subject: [PATCH 060/191] New translations settings.php (Japanese) --- resources/lang/ja/settings.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/resources/lang/ja/settings.php b/resources/lang/ja/settings.php index 34eb469e9..b69845d0e 100644 --- a/resources/lang/ja/settings.php +++ b/resources/lang/ja/settings.php @@ -41,12 +41,22 @@ return [ 'app_disable_comments_toggle' => 'Disable comments', 'app_disable_comments_desc' => 'アプリケーション内のすべてのページのコメントを無効にします。既存のコメントは表示されません。', + // Color settings + 'content_colors' => 'Content Colors', + 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'bookshelf_color' => 'Shelf Color', + 'book_color' => 'Book Color', + 'chapter_color' => 'Chapter Color', + 'page_color' => 'Page Color', + 'page_draft_color' => 'Page Draft Color', + // Registration Settings 'reg_settings' => '登録設定', 'reg_enable' => 'Enable Registration', 'reg_enable_toggle' => 'Enable registration', 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', 'reg_default_role' => '新規登録時のデフォルト役割', + 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', 'reg_email_confirmation' => 'Email Confirmation', 'reg_email_confirmation_toggle' => 'Require email confirmation', 'reg_confirm_email_desc' => 'ドメイン制限を有効にしている場合はEメール認証が必須となり、この項目は無視されます。', @@ -63,6 +73,13 @@ return [ 'maint_image_cleanup_warning' => ':count potentially unused images were found. Are you sure you want to delete these images?', 'maint_image_cleanup_success' => ':count potentially unused images found and deleted!', 'maint_image_cleanup_nothing_found' => 'No unused images found, Nothing deleted!', + 'maint_send_test_email' => 'Send a Test Email', + 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', + 'maint_send_test_email_run' => 'Send test email', + 'maint_send_test_email_success' => 'Email sent to :address', + 'maint_send_test_email_mail_subject' => 'Test Email', + 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', + 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', // Role Settings 'roles' => '役割', From f10808f6a098c5d5e54fab75b543753e8ac9e078 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:39 +0000 Subject: [PATCH 061/191] New translations errors.php (Japanese) --- resources/lang/ja/errors.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resources/lang/ja/errors.php b/resources/lang/ja/errors.php index c42a773b6..d02679f72 100644 --- a/resources/lang/ja/errors.php +++ b/resources/lang/ja/errors.php @@ -17,6 +17,12 @@ return [ 'ldap_fail_authed' => '識別名, パスワードを用いたLDAPアクセスに失敗しました', 'ldap_extension_not_installed' => 'LDAP PHP extensionがインストールされていません', 'ldap_cannot_connect' => 'LDAPサーバに接続できませんでした', + 'saml_already_logged_in' => 'Already logged in', + 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', + 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', + 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', + 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', + 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => 'アクションが定義されていません', 'social_login_bad_response' => "Error received during :socialAccount login: \n:error", 'social_account_in_use' => ':socialAccountアカウントは既に使用されています。:socialAccountのオプションからログインを試行してください。', From 85c2e3bc8e13b530135f2748d41d91ecbb5f987a Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:41 +0000 Subject: [PATCH 062/191] New translations common.php (Japanese) --- resources/lang/ja/common.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lang/ja/common.php b/resources/lang/ja/common.php index feac9c460..2a142e55f 100644 --- a/resources/lang/ja/common.php +++ b/resources/lang/ja/common.php @@ -38,6 +38,7 @@ return [ 'reset' => 'リセット', 'remove' => '削除', 'add' => '追加', + 'fullscreen' => 'Fullscreen', // Sort Options 'sort_options' => 'Sort Options', From f9969978a5b9b9095b4d454157eda73d54670d16 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:43 +0000 Subject: [PATCH 063/191] New translations auth.php (German) --- resources/lang/de/auth.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/resources/lang/de/auth.php b/resources/lang/de/auth.php index 3d0db9dc8..7216ffe48 100644 --- a/resources/lang/de/auth.php +++ b/resources/lang/de/auth.php @@ -66,12 +66,12 @@ return [ 'email_not_confirmed_resend_button' => 'Bestätigungs-E-Mail erneut senden', // User Invite - 'user_invite_email_subject' => 'You have been invited to join :appName!', - 'user_invite_email_greeting' => 'An account has been created for you on :appName.', - 'user_invite_email_text' => 'Click the button below to set an account password and gain access:', - 'user_invite_email_action' => 'Set Account Password', - 'user_invite_page_welcome' => 'Welcome to :appName!', - 'user_invite_page_text' => 'To finalise your account and gain access you need to set a password which will be used to log-in to :appName on future visits.', - 'user_invite_page_confirm_button' => 'Confirm Password', - 'user_invite_success' => 'Password set, you now have access to :appName!' + 'user_invite_email_subject' => 'Du wurdest eingeladen :appName beizutreten!', + 'user_invite_email_greeting' => 'Ein Konto wurde für Sie auf :appName erstellt.', + 'user_invite_email_text' => 'Klicken Sie auf die Schaltfläche unten, um ein Passwort festzulegen und Zugriff zu erhalten:', + 'user_invite_email_action' => 'Account-Passwort festlegen', + 'user_invite_page_welcome' => 'Willkommen bei :appName!', + 'user_invite_page_text' => 'Um die Anmeldung abzuschließen und Zugriff auf :appName zu bekommen muss noch ein Passwort festgelegt werden. Dieses wird in Zukunft zum Einloggen benötigt.', + 'user_invite_page_confirm_button' => 'Passwort wiederholen', + 'user_invite_success' => 'Passwort gesetzt, Sie haben nun Zugriff auf :appName!' ]; \ No newline at end of file From 7c5488f3181b8ad672c2999ac27e6718eb468011 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:44 +0000 Subject: [PATCH 064/191] New translations errors.php (Korean) --- resources/lang/ko/errors.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/resources/lang/ko/errors.php b/resources/lang/ko/errors.php index 5982a09da..d054a620f 100644 --- a/resources/lang/ko/errors.php +++ b/resources/lang/ko/errors.php @@ -17,8 +17,14 @@ return [ 'ldap_fail_authed' => '이 정보로 LDAP 서버에 접근할 수 없습니다.', 'ldap_extension_not_installed' => 'PHP에 LDAP 확장 도구를 설치하세요.', 'ldap_cannot_connect' => 'LDAP 서버에 연결할 수 없습니다.', + 'saml_already_logged_in' => 'Already logged in', + 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', + 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', + 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', + 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', + 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => '무슨 활동인지 알 수 없습니다.', - 'social_login_bad_response' => ':socialAccount에 로그인할 수 없습니다. : \n:error', + 'social_login_bad_response' => ":socialAccount에 로그인할 수 없습니다. : \\n:error", 'social_account_in_use' => ':socialAccount(을)를 가진 사용자가 있습니다. :socialAccount로 로그인하세요.', 'social_account_email_in_use' => ':email(을)를 가진 사용자가 있습니다. 쓰고 있는 계정을 :socialAccount에 연결하세요.', 'social_account_existing' => ':socialAccount(와)과 연결 상태입니다.', From ee9c53325d17d47fb489ba25ffac92b25aa7374a Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:45 +0000 Subject: [PATCH 065/191] New translations errors.php (Chinese Simplified) --- resources/lang/zh_CN/errors.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resources/lang/zh_CN/errors.php b/resources/lang/zh_CN/errors.php index 7b70102dd..fcce87dcc 100644 --- a/resources/lang/zh_CN/errors.php +++ b/resources/lang/zh_CN/errors.php @@ -17,6 +17,12 @@ return [ 'ldap_fail_authed' => '带有标识名称和密码的LDAP访问失败。', 'ldap_extension_not_installed' => '未安装LDAP PHP扩展程序', 'ldap_cannot_connect' => '无法连接到ldap服务器,初始连接失败', + 'saml_already_logged_in' => 'Already logged in', + 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', + 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', + 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', + 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', + 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => '没有定义行为', 'social_login_bad_response' => "在 :socialAccount 登录时遇到错误:\n:error", 'social_account_in_use' => ':socialAccount 账户已被使用,请尝试通过 :socialAccount 选项登录。', From d1a9ddf3dbaae15fe8faf6a691699503b2db144c Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:47 +0000 Subject: [PATCH 066/191] New translations errors.php (Chinese Traditional) --- resources/lang/zh_TW/errors.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resources/lang/zh_TW/errors.php b/resources/lang/zh_TW/errors.php index 39bdbd6f6..3042364b0 100644 --- a/resources/lang/zh_TW/errors.php +++ b/resources/lang/zh_TW/errors.php @@ -17,6 +17,12 @@ return [ 'ldap_fail_authed' => '帶有標識名稱和密碼的LDAP進入失敗。', 'ldap_extension_not_installed' => '未安裝LDAP PHP外掛程式', 'ldap_cannot_connect' => '無法連接到ldap伺服器,第一次連接失敗', + 'saml_already_logged_in' => 'Already logged in', + 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', + 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', + 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', + 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', + 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => '沒有定義行為', 'social_login_bad_response' => "在 :socialAccount 登錄時遇到錯誤:\n:error", 'social_account_in_use' => ':socialAccount 帳號已被使用,請嘗試透過 :socialAccount 選項登錄。', From bbb379919f68af1b3a77a129acf2c1333a57599c Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:48 +0000 Subject: [PATCH 067/191] New translations entities.php (Chinese Traditional) --- resources/lang/zh_TW/entities.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lang/zh_TW/entities.php b/resources/lang/zh_TW/entities.php index 725e4aee9..2383ab4c4 100644 --- a/resources/lang/zh_TW/entities.php +++ b/resources/lang/zh_TW/entities.php @@ -311,4 +311,4 @@ return [ 'revision_restore_confirm' => 'Are you sure you want to restore this revision? The current page contents will be replaced.', 'revision_delete_success' => '修訂刪除', 'revision_cannot_delete_latest' => '無法刪除最新版本。' -]; +]; \ No newline at end of file From 8240295c86fe5f769c11b0680e5a410db2412678 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:50 +0000 Subject: [PATCH 068/191] New translations common.php (Chinese Traditional) --- resources/lang/zh_TW/common.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lang/zh_TW/common.php b/resources/lang/zh_TW/common.php index 80147e91a..278d51357 100644 --- a/resources/lang/zh_TW/common.php +++ b/resources/lang/zh_TW/common.php @@ -38,6 +38,7 @@ return [ 'reset' => '重置', 'remove' => '刪除', 'add' => '新增', + 'fullscreen' => 'Fullscreen', // Sort Options 'sort_options' => 'Sort Options', From 3534082c8c884422456b8949e81894ba489dd05c Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:52 +0000 Subject: [PATCH 069/191] New translations settings.php (Chinese Simplified) --- resources/lang/zh_CN/settings.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/resources/lang/zh_CN/settings.php b/resources/lang/zh_CN/settings.php index 40cc7c49a..9fd6532fc 100755 --- a/resources/lang/zh_CN/settings.php +++ b/resources/lang/zh_CN/settings.php @@ -41,12 +41,22 @@ return [ 'app_disable_comments_toggle' => '禁用评论', 'app_disable_comments_desc' => '在站点的所有页面上禁用评论,现有评论也不会显示出来。', + // Color settings + 'content_colors' => 'Content Colors', + 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'bookshelf_color' => 'Shelf Color', + 'book_color' => 'Book Color', + 'chapter_color' => 'Chapter Color', + 'page_color' => 'Page Color', + 'page_draft_color' => 'Page Draft Color', + // Registration Settings 'reg_settings' => '注册设置', 'reg_enable' => '启用注册', 'reg_enable_toggle' => '启用注册', 'reg_enable_desc' => '启用注册后,用户将可以自己注册为站点用户。 注册后,他们将获得一个默认的单一用户角色。', 'reg_default_role' => '注册后的默认用户角色', + 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', 'reg_email_confirmation' => '邮箱确认n', 'reg_email_confirmation_toggle' => '需要电子邮件确认', 'reg_confirm_email_desc' => '如果使用域名限制,则需要Email验证,并且该值将被忽略。', @@ -63,6 +73,13 @@ return [ 'maint_image_cleanup_warning' => '发现了 :count 张可能未使用的图像。您确定要删除这些图像吗?', 'maint_image_cleanup_success' => '找到并删除了 :count 张可能未使用的图像!', 'maint_image_cleanup_nothing_found' => '找不到未使用的图像,没有删除!', + 'maint_send_test_email' => 'Send a Test Email', + 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', + 'maint_send_test_email_run' => 'Send test email', + 'maint_send_test_email_success' => 'Email sent to :address', + 'maint_send_test_email_mail_subject' => 'Test Email', + 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', + 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', // Role Settings 'roles' => '角色', From faf455e78c05974a8c0e8d6dcbb4e474ae058473 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:54 +0000 Subject: [PATCH 070/191] New translations entities.php (Chinese Simplified) --- resources/lang/zh_CN/entities.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lang/zh_CN/entities.php b/resources/lang/zh_CN/entities.php index 82e520cf2..d391856b8 100644 --- a/resources/lang/zh_CN/entities.php +++ b/resources/lang/zh_CN/entities.php @@ -311,4 +311,4 @@ return [ 'revision_restore_confirm' => '您确定要恢复到此修订版吗?恢复后原有内容将会被替换。', 'revision_delete_success' => '修订删除', 'revision_cannot_delete_latest' => '无法删除最新版本。' -]; +]; \ No newline at end of file From f6816db61594aea20b25b123174d6f593e3f5a80 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:56 +0000 Subject: [PATCH 071/191] New translations common.php (Chinese Simplified) --- resources/lang/zh_CN/common.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lang/zh_CN/common.php b/resources/lang/zh_CN/common.php index 37cb608a7..4e257a2b6 100644 --- a/resources/lang/zh_CN/common.php +++ b/resources/lang/zh_CN/common.php @@ -38,6 +38,7 @@ return [ 'reset' => '重置', 'remove' => '删除', 'add' => '添加', + 'fullscreen' => 'Fullscreen', // Sort Options 'sort_options' => '排序选项', From 0d9be20af80885ccc9a3e765102d1f2739649f7d Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:57 +0000 Subject: [PATCH 072/191] New translations auth.php (Chinese Simplified) --- resources/lang/zh_CN/auth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lang/zh_CN/auth.php b/resources/lang/zh_CN/auth.php index 4bb08e7d2..0eec01508 100644 --- a/resources/lang/zh_CN/auth.php +++ b/resources/lang/zh_CN/auth.php @@ -74,4 +74,4 @@ return [ 'user_invite_page_text' => '要完成您的帐户并获得访问权限,您需要设置一个密码,该密码将在以后访问时用于登录 :appName。', 'user_invite_page_confirm_button' => '确认密码', 'user_invite_success' => '已设置密码,您现在可以访问 :appName!' -]; +]; \ No newline at end of file From 5856998c60f87e5c6cfa63484ee82d96394b2cb7 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:38:59 +0000 Subject: [PATCH 073/191] New translations errors.php (Arabic) --- resources/lang/ar/errors.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resources/lang/ar/errors.php b/resources/lang/ar/errors.php index dd42338b5..955efbd23 100644 --- a/resources/lang/ar/errors.php +++ b/resources/lang/ar/errors.php @@ -17,6 +17,12 @@ return [ 'ldap_fail_authed' => 'فشل الوصول إلى LDAP باستخدام dn و password المعطاة', 'ldap_extension_not_installed' => 'لم يتم تثبيت إضافة LDAP PHP', 'ldap_cannot_connect' => 'لا يمكن الاتصال بخادم ldap, فشل الاتصال المبدئي', + 'saml_already_logged_in' => 'Already logged in', + 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', + 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', + 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', + 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', + 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => 'لم يتم تعريف أي إجراء', 'social_login_bad_response' => "حصل خطأ خلال تسجيل الدخول باستخدام :socialAccount \n:error", 'social_account_in_use' => 'حساب :socialAccount قيد الاستخدام حالياً, الرجاء محاولة الدخول باستخدام خيار :socialAccount.', From 9e6f208decf953235ee08651f5ee37ba2708b706 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:02 +0000 Subject: [PATCH 074/191] New translations common.php (Arabic) --- resources/lang/ar/common.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lang/ar/common.php b/resources/lang/ar/common.php index 9505b2a95..90c4e5159 100644 --- a/resources/lang/ar/common.php +++ b/resources/lang/ar/common.php @@ -38,6 +38,7 @@ return [ 'reset' => 'إعادة تعيين', 'remove' => 'إزالة', 'add' => 'إضافة', + 'fullscreen' => 'Fullscreen', // Sort Options 'sort_options' => 'Sort Options', From 82e344166e1c7bdadf18e2da5f37a4aa462a9e80 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:03 +0000 Subject: [PATCH 075/191] New translations settings.php (French) --- resources/lang/fr/settings.php | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/resources/lang/fr/settings.php b/resources/lang/fr/settings.php index fc25fb22c..095889a6f 100644 --- a/resources/lang/fr/settings.php +++ b/resources/lang/fr/settings.php @@ -41,12 +41,22 @@ return [ 'app_disable_comments_toggle' => 'Désactiver les commentaires', 'app_disable_comments_desc' => 'Désactive les commentaires sur toutes les pages de l\'application. Les commentaires existants ne sont pas affichés.', + // Color settings + 'content_colors' => 'Couleur du contenu', + 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'bookshelf_color' => 'Shelf Color', + 'book_color' => 'Couleur du livre', + 'chapter_color' => 'Couleur du chapitre', + 'page_color' => 'Couleur de la page', + 'page_draft_color' => 'Couleur du brouillon', + // Registration Settings 'reg_settings' => 'Préférence pour l\'inscription', 'reg_enable' => 'Activer l\'inscription', 'reg_enable_toggle' => 'Activer l\'inscription', 'reg_enable_desc' => 'Lorsque l\'inscription est activée, l\'utilisateur pourra s\'enregistrer en tant qu\'utilisateur de l\'application. Lors de l\'inscription, ils se voient attribuer un rôle par défaut.', 'reg_default_role' => 'Rôle par défaut lors de l\'inscription', + 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', 'reg_email_confirmation' => 'Confirmation de l\'e-mail', 'reg_email_confirmation_toggle' => 'Obliger la confirmation par e-mail ?', 'reg_confirm_email_desc' => 'Si la restriction de domaine est activée, la confirmation sera automatiquement obligatoire et cette valeur sera ignorée.', @@ -63,6 +73,13 @@ return [ 'maint_image_cleanup_warning' => ':count images potentiellement inutilisées trouvées. Etes-vous sûr de vouloir supprimer ces images ?', 'maint_image_cleanup_success' => ':count images potentiellement inutilisées trouvées et supprimées !', 'maint_image_cleanup_nothing_found' => 'Aucune image inutilisée trouvée, rien à supprimer !', + 'maint_send_test_email' => 'Envoyer un email de test', + 'maint_send_test_email_desc' => 'Ceci envoie un e-mail de test à votre adresse e-mail spécifiée dans votre profil.', + 'maint_send_test_email_run' => 'Envoyer un email de test', + 'maint_send_test_email_success' => 'Email envoyé à :address', + 'maint_send_test_email_mail_subject' => 'Email de test', + 'maint_send_test_email_mail_greeting' => 'La livraison d\'email semble fonctionner !', + 'maint_send_test_email_mail_text' => 'Félicitations ! Lorsque vous avez reçu cette notification par courriel, vos paramètres d\'email semblent être configurés correctement.', // Role Settings 'roles' => 'Rôles', @@ -85,7 +102,7 @@ return [ 'role_manage_roles' => 'Gérer les rôles et permissions', 'role_manage_entity_permissions' => 'Gérer les permissions sur les livres, chapitres et pages', 'role_manage_own_entity_permissions' => 'Gérer les permissions de ses propres livres, chapitres et pages', - 'role_manage_page_templates' => 'Manage page templates', + 'role_manage_page_templates' => 'Gérer les modèles de page', 'role_manage_settings' => 'Gérer les préférences de l\'application', 'role_asset' => 'Permissions des ressources', 'role_asset_desc' => 'Ces permissions contrôlent l\'accès par défaut des ressources dans le système. Les permissions dans les livres, les chapitres et les pages ignoreront ces permissions', @@ -110,8 +127,8 @@ return [ 'users_role_desc' => 'Sélectionnez les rôles auxquels cet utilisateur sera affecté. Si un utilisateur est affecté à plusieurs rôles, les permissions de ces rôles s\'empileront et ils recevront toutes les capacités des rôles affectés.', 'users_password' => 'Mot de passe de l\'utilisateur', 'users_password_desc' => 'Définissez un mot de passe utilisé pour vous connecter à l\'application. Il doit comporter au moins 5 caractères.', - 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', - 'users_send_invite_option' => 'Send user invite email', + 'users_send_invite_text' => 'Vous pouvez choisir d\'envoyer à cet utilisateur un email d\'invitation qui lui permet de définir son propre mot de passe, sinon vous pouvez définir son mot de passe vous-même.', + 'users_send_invite_option' => 'Envoyer l\'e-mail d\'invitation', 'users_external_auth_id' => 'Identifiant d\'authentification externe', 'users_external_auth_id_desc' => 'Il s\'agit de l\'identifiant utilisé pour appairer cet utilisateur lors de la communication avec votre système LDAP.', 'users_password_warning' => 'Remplissez ce formulaire uniquement si vous souhaitez changer de mot de passe:', From e4d847ab51b46b9f44d98f46edc8e5a634a1953b Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:05 +0000 Subject: [PATCH 076/191] New translations settings.php (Chinese Traditional) --- resources/lang/zh_TW/settings.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/resources/lang/zh_TW/settings.php b/resources/lang/zh_TW/settings.php index 0ad899a27..cd887c7be 100644 --- a/resources/lang/zh_TW/settings.php +++ b/resources/lang/zh_TW/settings.php @@ -41,12 +41,22 @@ return [ 'app_disable_comments_toggle' => 'Disable comments', 'app_disable_comments_desc' => '在App的所有頁面上關閉評論,已經存在的評論也不會顯示。', + // Color settings + 'content_colors' => 'Content Colors', + 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'bookshelf_color' => 'Shelf Color', + 'book_color' => 'Book Color', + 'chapter_color' => 'Chapter Color', + 'page_color' => 'Page Color', + 'page_draft_color' => 'Page Draft Color', + // Registration Settings 'reg_settings' => '註冊設定', 'reg_enable' => 'Enable Registration', 'reg_enable_toggle' => 'Enable registration', 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', 'reg_default_role' => '註冊後的預設使用者角色', + 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', 'reg_email_confirmation' => 'Email Confirmation', 'reg_email_confirmation_toggle' => 'Require email confirmation', 'reg_confirm_email_desc' => '如果使用網域名稱限制,則需要Email驗證,並且本設定將被忽略。', @@ -63,6 +73,13 @@ return [ 'maint_image_cleanup_warning' => '發現了 :count 張可能未使用的圖像。您確定要刪除這些圖像嗎?', 'maint_image_cleanup_success' => '找到並刪除了 :count 張可能未使用的圖像!', 'maint_image_cleanup_nothing_found' => '找不到未使用的圖像,沒有刪除!', + 'maint_send_test_email' => 'Send a Test Email', + 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', + 'maint_send_test_email_run' => 'Send test email', + 'maint_send_test_email_success' => 'Email sent to :address', + 'maint_send_test_email_mail_subject' => 'Test Email', + 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', + 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', // Role Settings 'roles' => '角色', From 003eb6ea26dc6d18b7a371585f88314cfc52d4e2 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:06 +0000 Subject: [PATCH 077/191] New translations settings.php (Arabic) --- resources/lang/ar/settings.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/resources/lang/ar/settings.php b/resources/lang/ar/settings.php index d867e30b5..4b12d0541 100755 --- a/resources/lang/ar/settings.php +++ b/resources/lang/ar/settings.php @@ -41,12 +41,22 @@ return [ 'app_disable_comments_toggle' => 'Disable comments', 'app_disable_comments_desc' => 'تعطيل التعليقات على جميع الصفحات داخل التطبيق. التعليقات الموجودة من الأصل لن تكون ظاهرة.', + // Color settings + 'content_colors' => 'Content Colors', + 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'bookshelf_color' => 'Shelf Color', + 'book_color' => 'Book Color', + 'chapter_color' => 'Chapter Color', + 'page_color' => 'Page Color', + 'page_draft_color' => 'Page Draft Color', + // Registration Settings 'reg_settings' => 'إعدادات التسجيل', 'reg_enable' => 'Enable Registration', 'reg_enable_toggle' => 'Enable registration', 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', 'reg_default_role' => 'دور المستخدم الأساسي بعد التسجيل', + 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', 'reg_email_confirmation' => 'Email Confirmation', 'reg_email_confirmation_toggle' => 'Require email confirmation', 'reg_confirm_email_desc' => 'إذا تم استخدام قيود للمجال سيصبح التأكيد عن طريق البريد الإلكتروني إلزامي وسيتم تجاهل القيمة أسفله.', @@ -63,6 +73,13 @@ return [ 'maint_image_cleanup_warning' => 'يوجد عدد :count من الصور المحتمل عدم استخدامها. تأكيد حذف الصور؟', 'maint_image_cleanup_success' => 'تم إيجاد وحذف عدد :count من الصور المحتمل عدم استخدامها!', 'maint_image_cleanup_nothing_found' => 'لم يتم حذف أي شيء لعدم وجود أي صور غير مسمتخدمة', + 'maint_send_test_email' => 'Send a Test Email', + 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', + 'maint_send_test_email_run' => 'Send test email', + 'maint_send_test_email_success' => 'Email sent to :address', + 'maint_send_test_email_mail_subject' => 'Test Email', + 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', + 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', // Role Settings 'roles' => 'الأدوار', From 601126ba2eab371f3cd47c25b378f1daff99e103 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:07 +0000 Subject: [PATCH 078/191] New translations errors.php (Dutch) --- resources/lang/nl/errors.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resources/lang/nl/errors.php b/resources/lang/nl/errors.php index f83f56a46..a6cdbf8f7 100644 --- a/resources/lang/nl/errors.php +++ b/resources/lang/nl/errors.php @@ -17,6 +17,12 @@ return [ 'ldap_fail_authed' => 'LDAP toegang was niet mogelijk met de opgegeven dn & wachtwoord', 'ldap_extension_not_installed' => 'LDAP PHP extension not installed', 'ldap_cannot_connect' => 'Kon niet met de LDAP server verbinden', + 'saml_already_logged_in' => 'Already logged in', + 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', + 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', + 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', + 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', + 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => 'Geen actie gedefineerd', 'social_login_bad_response' => "Error received during :socialAccount login: \n:error", 'social_account_in_use' => 'Dit :socialAccount account is al in gebruik, Probeer in te loggen met de :socialAccount optie.', From 3d187627d0952d88df795ec7a60ceaf87e4e7353 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:10 +0000 Subject: [PATCH 079/191] New translations errors.php (French) --- resources/lang/fr/errors.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resources/lang/fr/errors.php b/resources/lang/fr/errors.php index 11da312a4..bc5ef61d3 100644 --- a/resources/lang/fr/errors.php +++ b/resources/lang/fr/errors.php @@ -17,6 +17,12 @@ return [ 'ldap_fail_authed' => 'L\'accès LDAP n\'a pas abouti avec cet utilisateur et ce mot de passe', 'ldap_extension_not_installed' => 'L\'extension LDAP PHP n\'est pas installée', 'ldap_cannot_connect' => 'Impossible de se connecter au serveur LDAP, la connexion initiale a échoué', + 'saml_already_logged_in' => 'Déjà connecté', + 'saml_user_not_registered' => 'L\'utilisateur :name n\'est pas enregistré et l\'enregistrement automatique est désactivé', + 'saml_no_email_address' => 'Impossible de trouver une adresse e-mail, pour cet utilisateur, dans les données fournies par le système d\'authentification externe', + 'saml_invalid_response_id' => 'La requête du système d\'authentification externe n\'est pas reconnue par un processus démarré par cette application. Naviguer après une connexion peut causer ce problème.', + 'saml_fail_authed' => 'Connexion avec :system échoue, le système n\'a pas fourni l\'autorisation réussie', + 'saml_email_exists' => 'L\'enregistrement a échoué car un utilisateur existe déjà avec l\'adresse e-mail ":email"', 'social_no_action_defined' => 'Pas d\'action définie', 'social_login_bad_response' => "Erreur pendant la tentative de connexion à :socialAccount : \n:error", 'social_account_in_use' => 'Ce compte :socialAccount est déjà utilisé. Essayez de vous connecter via :socialAccount.', From c58214c6fda696296700cace18f40466ab1cec6a Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:12 +0000 Subject: [PATCH 080/191] New translations entities.php (French) --- resources/lang/fr/entities.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/resources/lang/fr/entities.php b/resources/lang/fr/entities.php index a6c665f9c..d52dbfda3 100644 --- a/resources/lang/fr/entities.php +++ b/resources/lang/fr/entities.php @@ -35,7 +35,7 @@ return [ 'export_text' => 'Document texte', // Permissions and restrictions - 'permissions' => 'Permissions', + 'permissions' => 'Autorisations', 'permissions_intro' => 'Une fois activées ces permissions prendront la priorité sur tous les sets de permissions préexistants.', 'permissions_enable' => 'Activer les permissions personnalisées', 'permissions_save' => 'Enregistrer les permissions', @@ -162,7 +162,7 @@ return [ // Pages 'page' => 'Page', 'pages' => 'Pages', - 'x_pages' => ':count Page|:count Pages', + 'x_pages' => ':count Page|:count pages', 'pages_popular' => 'Pages populaires', 'pages_new' => 'Nouvelle page', 'pages_attachments' => 'Fichiers joints', @@ -176,7 +176,7 @@ return [ 'pages_delete_confirm' => 'Êtes-vous sûr(e) de vouloir supprimer cette page ?', 'pages_delete_draft_confirm' => 'Êtes-vous sûr(e) de vouloir supprimer ce brouillon ?', 'pages_editing_named' => 'Modification de la page :pageName', - 'pages_edit_draft_options' => 'Draft Options', + 'pages_edit_draft_options' => 'Options du brouillon', 'pages_edit_save_draft' => 'Enregistrer le brouillon', 'pages_edit_draft' => 'Modifier le brouillon', 'pages_editing_draft' => 'Modification du brouillon', @@ -210,8 +210,8 @@ return [ 'pages_revisions_created_by' => 'Créé par', 'pages_revisions_date' => 'Date de révision', 'pages_revisions_number' => '#', - 'pages_revisions_numbered' => 'Revision #:id', - 'pages_revisions_numbered_changes' => 'Revision #:id Changes', + 'pages_revisions_numbered' => 'Révision #:id', + 'pages_revisions_numbered_changes' => 'Modification #:id', 'pages_revisions_changelog' => 'Journal des changements', 'pages_revisions_changes' => 'Changements', 'pages_revisions_current' => 'Version courante', @@ -243,11 +243,11 @@ return [ 'shelf_tags' => 'Mots-clés de l\'étagère', 'tag' => 'Mot-clé', 'tags' => 'Mots-clés', - 'tag_name' => 'Tag Name', + 'tag_name' => 'Nom du tag', 'tag_value' => 'Valeur du mot-clé (Optionnel)', 'tags_explain' => "Ajouter des mots-clés pour catégoriser votre contenu.", 'tags_add' => 'Ajouter un autre mot-clé', - 'tags_remove' => 'Remove this tag', + 'tags_remove' => 'Supprimer le tag', 'attachments' => 'Fichiers joints', 'attachments_explain' => 'Ajouter des fichiers ou des liens pour les afficher sur votre page. Ils seront affichés dans la barre latérale', 'attachments_explain_instant_save' => 'Ces changements sont enregistrés immédiatement.', @@ -275,7 +275,7 @@ return [ 'attachments_link_attached' => 'Lien attaché à la page avec succès', 'templates' => 'Modèles', 'templates_set_as_template' => 'La page est un modèle', - 'templates_explain_set_as_template' => 'You can set this page as a template so its contents be utilized when creating other pages. Other users will be able to use this template if they have view permissions for this page.', + 'templates_explain_set_as_template' => 'Vous pouvez définir cette page comme modèle pour que son contenu soit utilisé lors de la création d\'autres pages. Les autres utilisateurs pourront utiliser ce modèle s\'ils ont les permissions pour cette page.', 'templates_replace_content' => 'Remplacer le contenu de la page', 'templates_append_content' => 'Ajouter après le contenu de la page', 'templates_prepend_content' => 'Ajouter devant le contenu de la page', From dd4feb4f3dee424db0fcf13eccd15829b86e6891 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:14 +0000 Subject: [PATCH 081/191] New translations common.php (French) --- resources/lang/fr/common.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/lang/fr/common.php b/resources/lang/fr/common.php index 3fb19a303..af31f458a 100644 --- a/resources/lang/fr/common.php +++ b/resources/lang/fr/common.php @@ -38,6 +38,7 @@ return [ 'reset' => 'Réinitialiser', 'remove' => 'Enlever', 'add' => 'Ajouter', + 'fullscreen' => 'Fullscreen', // Sort Options 'sort_options' => 'Options de tri', @@ -67,7 +68,7 @@ return [ 'edit_profile' => 'Modifier le profil', // Layout tabs - 'tab_info' => 'Info', + 'tab_info' => 'Informations', 'tab_content' => 'Contenu', // Email Content From 740543d32dae274300d14fc67f50c66dd4cf5b06 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:16 +0000 Subject: [PATCH 082/191] New translations settings.php (Dutch) --- resources/lang/nl/settings.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/resources/lang/nl/settings.php b/resources/lang/nl/settings.php index dc5521797..2240d7198 100644 --- a/resources/lang/nl/settings.php +++ b/resources/lang/nl/settings.php @@ -41,12 +41,22 @@ return [ 'app_disable_comments_toggle' => 'Disable comments', 'app_disable_comments_desc' => 'Schakel opmerkingen uit op alle pagina\'s in de applicatie. Bestaande opmerkingen worden niet getoond.', + // Color settings + 'content_colors' => 'Content Colors', + 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'bookshelf_color' => 'Shelf Color', + 'book_color' => 'Book Color', + 'chapter_color' => 'Chapter Color', + 'page_color' => 'Page Color', + 'page_draft_color' => 'Page Draft Color', + // Registration Settings 'reg_settings' => 'Registratieinstellingen', 'reg_enable' => 'Enable Registration', 'reg_enable_toggle' => 'Enable registration', 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', 'reg_default_role' => 'Standaard rol na registratie', + 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', 'reg_email_confirmation' => 'Email Confirmation', 'reg_email_confirmation_toggle' => 'Require email confirmation', 'reg_confirm_email_desc' => 'Als domeinrestricties aan staan dan is altijd e-maibevestiging nodig. Onderstaande instelling wordt dan genegeerd.', @@ -63,6 +73,13 @@ return [ 'maint_image_cleanup_warning' => ':count potentially unused images were found. Are you sure you want to delete these images?', 'maint_image_cleanup_success' => ':count potentially unused images found and deleted!', 'maint_image_cleanup_nothing_found' => 'No unused images found, Nothing deleted!', + 'maint_send_test_email' => 'Send a Test Email', + 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', + 'maint_send_test_email_run' => 'Send test email', + 'maint_send_test_email_success' => 'Email sent to :address', + 'maint_send_test_email_mail_subject' => 'Test Email', + 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', + 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', // Role Settings 'roles' => 'Rollen', From c24905f606272e55a721f4b51cf0abae3545d255 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:20 +0000 Subject: [PATCH 083/191] New translations common.php (Czech) --- resources/lang/cs/common.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lang/cs/common.php b/resources/lang/cs/common.php index cad26410c..52d596838 100644 --- a/resources/lang/cs/common.php +++ b/resources/lang/cs/common.php @@ -38,6 +38,7 @@ return [ 'reset' => 'Reset', 'remove' => 'Odstranit', 'add' => 'Přidat', + 'fullscreen' => 'Fullscreen', // Sort Options 'sort_options' => 'Sort Options', From 7cf2fd72abfe8605f11232b5a8457d21436d0feb Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:21 +0000 Subject: [PATCH 084/191] New translations errors.php (Czech) --- resources/lang/cs/errors.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resources/lang/cs/errors.php b/resources/lang/cs/errors.php index fa00491b0..0e4757ed4 100644 --- a/resources/lang/cs/errors.php +++ b/resources/lang/cs/errors.php @@ -17,6 +17,12 @@ return [ 'ldap_fail_authed' => 'Přístup k adresáři LDAP pomocí zadaného jména (dn) a hesla selhal', 'ldap_extension_not_installed' => 'Není nainstalováno rozšíření LDAP pro PHP', 'ldap_cannot_connect' => 'Nelze se připojit k adresáři LDAP. Prvotní připojení selhalo.', + 'saml_already_logged_in' => 'Already logged in', + 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', + 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', + 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', + 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', + 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => 'Nebyla zvolena žádá akce', 'social_login_bad_response' => "Nastala chyba během přihlašování přes :socialAccount \n:error", 'social_account_in_use' => 'Tento účet na :socialAccount se již používá. Pokuste se s ním přihlásit volbou Přihlásit přes :socialAccount.', From 68750b5da44a62bdfc0b28952e872b4553b925e6 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:23 +0000 Subject: [PATCH 085/191] New translations settings.php (Czech) --- resources/lang/cs/settings.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/resources/lang/cs/settings.php b/resources/lang/cs/settings.php index bb6e6be09..57c874a53 100644 --- a/resources/lang/cs/settings.php +++ b/resources/lang/cs/settings.php @@ -41,12 +41,22 @@ return [ 'app_disable_comments_toggle' => 'Disable comments', 'app_disable_comments_desc' => 'Zakáže komentáře napříč všemi stránkami. Existující komentáře se přestanou zobrazovat.', + // Color settings + 'content_colors' => 'Content Colors', + 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'bookshelf_color' => 'Shelf Color', + 'book_color' => 'Book Color', + 'chapter_color' => 'Chapter Color', + 'page_color' => 'Page Color', + 'page_draft_color' => 'Page Draft Color', + // Registration Settings 'reg_settings' => 'Nastavení registrace', 'reg_enable' => 'Enable Registration', 'reg_enable_toggle' => 'Enable registration', 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', 'reg_default_role' => 'Role přiřazená po registraci', + 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', 'reg_email_confirmation' => 'Email Confirmation', 'reg_email_confirmation_toggle' => 'Require email confirmation', 'reg_confirm_email_desc' => 'Pokud zapnete omezení emailové domény, tak bude ověřování emailové adresy vyžadováno vždy.', @@ -63,6 +73,13 @@ return [ 'maint_image_cleanup_warning' => 'Nalezeno :count potenciálně nepoužitých obrázků. Jste si jistí, že je chcete smazat?', 'maint_image_cleanup_success' => 'Potenciálně nepoužité obrázky byly smazány. Celkem :count.', 'maint_image_cleanup_nothing_found' => 'Žádné potenciálně nepoužité obrázky nebyly nalezeny. Nic nebylo smazáno.', + 'maint_send_test_email' => 'Send a Test Email', + 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', + 'maint_send_test_email_run' => 'Send test email', + 'maint_send_test_email_success' => 'Email sent to :address', + 'maint_send_test_email_mail_subject' => 'Test Email', + 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', + 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', // Role Settings 'roles' => 'Role', From 1568f953b6ea013da0e2dd87062e3a8295875d5c Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:25 +0000 Subject: [PATCH 086/191] New translations common.php (Dutch) --- resources/lang/nl/common.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lang/nl/common.php b/resources/lang/nl/common.php index 87d5935a6..9e7d53fa7 100644 --- a/resources/lang/nl/common.php +++ b/resources/lang/nl/common.php @@ -38,6 +38,7 @@ return [ 'reset' => 'Reset', 'remove' => 'Verwijderen', 'add' => 'Toevoegen', + 'fullscreen' => 'Fullscreen', // Sort Options 'sort_options' => 'Sort Options', From 5ab6ad0526c60a31e90b8358482797848dae2ddc Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:27 +0000 Subject: [PATCH 087/191] New translations entities.php (Turkish) --- resources/lang/tr/entities.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/resources/lang/tr/entities.php b/resources/lang/tr/entities.php index f9eb54fb0..1163d09f0 100644 --- a/resources/lang/tr/entities.php +++ b/resources/lang/tr/entities.php @@ -176,7 +176,7 @@ return [ 'pages_delete_confirm' => 'Bu sayfayı silmek istediğinizden emin misiniz?', 'pages_delete_draft_confirm' => 'Bu taslak sayfayı silmek istediğinizden emin misiniz?', 'pages_editing_named' => ':pageName Sayfası Düzenleniyor', - 'pages_edit_draft_options' => 'Draft Options', + 'pages_edit_draft_options' => 'Taslak Seçenekleri', 'pages_edit_save_draft' => 'Taslağı Kaydet', 'pages_edit_draft' => 'Taslak Sayfasını Düzenle', 'pages_editing_draft' => 'Taslak Düzenleniyor', @@ -234,7 +234,7 @@ return [ ], 'pages_draft_discarded' => 'Taslak yok sayıldı, editör mevcut sayfa içeriği ile güncellendi', 'pages_specific' => 'Özel Sayfa', - 'pages_is_template' => 'Page Template', + 'pages_is_template' => 'Sayfa Şablonu', // Editor Sidebar 'page_tags' => 'Sayfa Etiketleri', @@ -243,11 +243,11 @@ return [ 'shelf_tags' => 'Kitaplık Etiketleri', 'tag' => 'Etiket', 'tags' => 'Etiketler', - 'tag_name' => 'Tag Name', + 'tag_name' => 'Etiket İsmi', 'tag_value' => 'Etiket İçeriği (Opsiyonel)', 'tags_explain' => "İçeriğini daha iyi kategorize etmek için bazı etiketler ekle. Etiketlere değer atayarak daha derin bir organizasyon yapısına sahip olabilirsin.", 'tags_add' => 'Başka etiket ekle', - 'tags_remove' => 'Remove this tag', + 'tags_remove' => 'Bu Etiketi Sil', 'attachments' => 'Ekler', 'attachments_explain' => 'Sayfanızda göstermek için bazı dosyalar yükleyin veya bazı bağlantılar ekleyin. Bunlar sayfanın sidebarında görülebilir.', 'attachments_explain_instant_save' => 'Burada yapılan değişiklikler anında kaydedilir.', @@ -273,12 +273,12 @@ return [ 'attachments_file_uploaded' => 'Dosya başarıyla yüklendi', 'attachments_file_updated' => 'Dosya başarıyla güncellendi', 'attachments_link_attached' => 'Link sayfaya başarıyla eklendi', - 'templates' => 'Templates', - 'templates_set_as_template' => 'Page is a template', - 'templates_explain_set_as_template' => 'You can set this page as a template so its contents be utilized when creating other pages. Other users will be able to use this template if they have view permissions for this page.', - 'templates_replace_content' => 'Replace page content', - 'templates_append_content' => 'Append to page content', - 'templates_prepend_content' => 'Prepend to page content', + 'templates' => 'Şablonlar', + 'templates_set_as_template' => 'Sayfa bir şablondur', + 'templates_explain_set_as_template' => 'Bu sayfayı şablon olarak seçebilirsiniz. Böylece taslağın içeriği diğer sayfaları oluştururken düzenlenebilir. Eğer yetkileri varsa diğer kullanıcılar da bu sayfayı görüntülerken bu şablonu kullanabilirler.', + 'templates_replace_content' => 'Sayfa içeriğini değiştir', + 'templates_append_content' => 'Sayfa içeriğine ekle', + 'templates_prepend_content' => 'Sayfa içeriğinin başına ekle', // Profile View 'profile_user_for_x' => 'Kullanıcı :time', From 8e4f3316740cd9bbee2d38ff89158aeba4afd7bc Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:29 +0000 Subject: [PATCH 088/191] New translations common.php (Turkish) --- resources/lang/tr/common.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/resources/lang/tr/common.php b/resources/lang/tr/common.php index a87a0d5db..c17c1cd8b 100644 --- a/resources/lang/tr/common.php +++ b/resources/lang/tr/common.php @@ -38,12 +38,13 @@ return [ 'reset' => 'Sıfırla', 'remove' => 'Kaldır', 'add' => 'Ekle', + 'fullscreen' => 'Fullscreen', // Sort Options - 'sort_options' => 'Sort Options', - 'sort_direction_toggle' => 'Sort Direction Toggle', - 'sort_ascending' => 'Sort Ascending', - 'sort_descending' => 'Sort Descending', + 'sort_options' => 'Sıralama Seçenekleri', + 'sort_direction_toggle' => 'Sıralama Yönünü Değiştir', + 'sort_ascending' => 'Artan Sıralama', + 'sort_descending' => 'Azalan Sıralama', 'sort_name' => 'İsim', 'sort_created_at' => 'Oluşturulma Tarihi', 'sort_updated_at' => 'Güncellenme Tarihi', @@ -59,10 +60,10 @@ return [ 'grid_view' => 'Grid görünümü', 'list_view' => 'Liste görünümü', 'default' => 'Varsayılan', - 'breadcrumb' => 'Breadcrumb', + 'breadcrumb' => 'Sayfa İşaretleri Yolu', // Header - 'profile_menu' => 'Profile Menu', + 'profile_menu' => 'Tercih menüsü', 'view_profile' => 'Profili Görüntüle', 'edit_profile' => 'Profili Düzenle', From e6a1b2ea973270fe17a55f5166f95c350a858bf4 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:30 +0000 Subject: [PATCH 089/191] New translations auth.php (Turkish) --- resources/lang/tr/auth.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/resources/lang/tr/auth.php b/resources/lang/tr/auth.php index 7019c51c5..2999f7cae 100644 --- a/resources/lang/tr/auth.php +++ b/resources/lang/tr/auth.php @@ -18,7 +18,7 @@ return [ 'name' => 'İsim', 'username' => 'Kullanıcı Adı', - 'email' => 'Email', + 'email' => 'E-Posta', 'password' => 'Şifre', 'password_confirm' => 'Şifreyi onayla', 'password_hint' => 'En az 5 karakter olmalı', @@ -66,12 +66,12 @@ return [ 'email_not_confirmed_resend_button' => 'Doğrulama Mailini Yeniden Yolla', // User Invite - 'user_invite_email_subject' => 'You have been invited to join :appName!', - 'user_invite_email_greeting' => 'An account has been created for you on :appName.', - 'user_invite_email_text' => 'Click the button below to set an account password and gain access:', - 'user_invite_email_action' => 'Set Account Password', - 'user_invite_page_welcome' => 'Welcome to :appName!', - 'user_invite_page_text' => 'To finalise your account and gain access you need to set a password which will be used to log-in to :appName on future visits.', - 'user_invite_page_confirm_button' => 'Confirm Password', - 'user_invite_success' => 'Password set, you now have access to :appName!' + 'user_invite_email_subject' => ':appName\'e katılma daveti aldınız!', + 'user_invite_email_greeting' => 'Sizin için :appName üzerinde bir hesap oluşturuldu.', + 'user_invite_email_text' => 'Parola belirlemek ve erişebilmek için aşağıdaki butona tıklayın:', + 'user_invite_email_action' => 'Hesap Şifresini Belirleyin', + 'user_invite_page_welcome' => ':appName\'e hoş geldiniz!', + 'user_invite_page_text' => 'Hesap açılışını tamamlamak ve erişim izni alabilmek için daha sonraki girişlerinizde kullanabilmek üzere bir şifre belirlemeniz gerekiyor.', + 'user_invite_page_confirm_button' => 'Parolayı Onayla', + 'user_invite_success' => 'Parolanız belirlendi, artık :appName\'e erişebilirsiniz!' ]; \ No newline at end of file From f55acc7cf107a94340eaf501c21312096eb5cc97 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:33 +0000 Subject: [PATCH 090/191] New translations settings.php (Swedish) --- resources/lang/sv/settings.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/resources/lang/sv/settings.php b/resources/lang/sv/settings.php index c848ac651..5dd472e1a 100644 --- a/resources/lang/sv/settings.php +++ b/resources/lang/sv/settings.php @@ -41,12 +41,22 @@ return [ 'app_disable_comments_toggle' => 'Inaktivera kommentarer', 'app_disable_comments_desc' => 'Inaktivera kommentarer på alla sidor i applikationen. Befintliga kommentarer visas inte.', + // Color settings + 'content_colors' => 'Content Colors', + 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'bookshelf_color' => 'Shelf Color', + 'book_color' => 'Book Color', + 'chapter_color' => 'Chapter Color', + 'page_color' => 'Page Color', + 'page_draft_color' => 'Page Draft Color', + // Registration Settings 'reg_settings' => 'Registreringsinställningar', 'reg_enable' => 'Tillåt registrering', 'reg_enable_toggle' => 'Tillåt registrering', 'reg_enable_desc' => 'När registrering tillåts kan användaren logga in som en användare. Vid registreringen ges de en förvald användarroll.', 'reg_default_role' => 'Standardroll efter registrering', + 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', 'reg_email_confirmation' => 'E-postbekräftelse', 'reg_email_confirmation_toggle' => 'Kräv e-postbekräftelse', 'reg_confirm_email_desc' => 'Om registrering begränas till vissa domäner kommer e-postbekräftelse alltid att krävas och den här inställningen kommer att ignoreras.', @@ -63,6 +73,13 @@ return [ 'maint_image_cleanup_warning' => 'Hittade :count bilder som potentiellt inte används. Vill du verkligen ta bort dessa bilder?', 'maint_image_cleanup_success' => 'Hittade och raderade :count bilder som potentiellt inte används!', 'maint_image_cleanup_nothing_found' => 'Hittade inga oanvända bilder, så inget har raderats!', + 'maint_send_test_email' => 'Send a Test Email', + 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', + 'maint_send_test_email_run' => 'Send test email', + 'maint_send_test_email_success' => 'Email sent to :address', + 'maint_send_test_email_mail_subject' => 'Test Email', + 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', + 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', // Role Settings 'roles' => 'Roller', From ed38be96720ecadd3f5ca7d9b1669a3e1b5958cd Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:35 +0000 Subject: [PATCH 091/191] New translations errors.php (Swedish) --- resources/lang/sv/errors.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resources/lang/sv/errors.php b/resources/lang/sv/errors.php index 64dbf4c16..ac7d117ae 100644 --- a/resources/lang/sv/errors.php +++ b/resources/lang/sv/errors.php @@ -17,6 +17,12 @@ return [ 'ldap_fail_authed' => 'LDAP-inloggning misslyckades med angivna dn- och lösenordsuppgifter', 'ldap_extension_not_installed' => 'LDAP PHP-tillägg inte installerat', 'ldap_cannot_connect' => 'Kan inte ansluta till ldap-servern. Anslutningen misslyckades', + 'saml_already_logged_in' => 'Already logged in', + 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', + 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', + 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', + 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', + 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => 'Ingen åtgärd definierad', 'social_login_bad_response' => "Ett fel inträffade vid inloggning genom :socialAccount: \n:error", 'social_account_in_use' => 'Detta konto från :socialAccount används redan. Testa att logga in med :socialAccount istället.', From 475a1f4dfff208d122c9eabb468485dc42494458 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:37 +0000 Subject: [PATCH 092/191] New translations common.php (Swedish) --- resources/lang/sv/common.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lang/sv/common.php b/resources/lang/sv/common.php index 4133ee642..1e49ad03e 100644 --- a/resources/lang/sv/common.php +++ b/resources/lang/sv/common.php @@ -38,6 +38,7 @@ return [ 'reset' => 'Återställ', 'remove' => 'Radera', 'add' => 'Lägg till', + 'fullscreen' => 'Fullscreen', // Sort Options 'sort_options' => 'Sort Options', From 51dd11410fa0f8df8168bec07be1dd201d765bd5 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:38 +0000 Subject: [PATCH 093/191] New translations settings.php (Spanish, Argentina) --- resources/lang/es_AR/settings.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/resources/lang/es_AR/settings.php b/resources/lang/es_AR/settings.php index e9aad7128..2f40ad985 100644 --- a/resources/lang/es_AR/settings.php +++ b/resources/lang/es_AR/settings.php @@ -41,12 +41,22 @@ return [ 'app_disable_comments_toggle' => 'Deshabilitar comentarios', 'app_disable_comments_desc' => 'Deshabilitar comentarios en todas las páginas de la aplicación. Los comentarios existentes no se muestran.', + // Color settings + 'content_colors' => 'Colores del contenido', + 'content_colors_desc' => 'Establece los colores para todos los elementos en la jerarquía de la organización de la página. Se recomienda elegir colores con un brillo similar al predeterminado para mayor legibilidad.', + 'bookshelf_color' => 'Color del estante', + 'book_color' => 'Color del libro', + 'chapter_color' => 'Color del capítulo', + 'page_color' => 'Color de la página', + 'page_draft_color' => 'Color del borrador de página', + // Registration Settings 'reg_settings' => 'Ajustes de registro', 'reg_enable' => 'Habilitar Registro', 'reg_enable_toggle' => 'Habilitar registro', 'reg_enable_desc' => 'Cuando se habilita el registro, el usuario podrá crear su usuario en la aplicación. Con el regsitro, se le otorga un rol de usuario único y por defecto.', 'reg_default_role' => 'Rol de usuario por defecto despúes del registro', + 'reg_enable_ldap_warning' => 'La opción anterior no se utiliza mientras la autenticación LDAP está activa. Las cuentas de usuario para los miembros no existentes se crearán automáticamente si la autenticación, contra el sistema LDAP en uso, es exitosa.', 'reg_email_confirmation' => 'Confirmación de correo electrónico', 'reg_email_confirmation_toggle' => 'Requerir confirmación de correo electrónico', 'reg_confirm_email_desc' => 'Si se utiliza la restricción por dominio, entonces se requerirá la confirmación por correo electrónico y se ignorará el valor a continuación.', @@ -63,6 +73,13 @@ return [ 'maint_image_cleanup_warning' => 'Se encontraron :count imágenes pontencialmente sin uso. Está seguro de que quiere eliminarlas?', 'maint_image_cleanup_success' => 'Se encontraron y se eliminaron :count imágenes pontencialmente sin uso!', 'maint_image_cleanup_nothing_found' => 'No se encotraron imágenes sin usar, Nada eliminado!', + 'maint_send_test_email' => 'Enviar un correo electrónico de prueba', + 'maint_send_test_email_desc' => 'Esto envía un correo electrónico de prueba a la dirección de correo electrónico especificada en tu perfil.', + 'maint_send_test_email_run' => 'Enviar correo electrónico de prueba', + 'maint_send_test_email_success' => 'Correo electrónico enviado a :address', + 'maint_send_test_email_mail_subject' => 'Probar correo electrónico', + 'maint_send_test_email_mail_greeting' => '¡El envío de correos electrónicos parece funcionar!', + 'maint_send_test_email_mail_text' => '¡Enhorabuena! Al recibir esta notificación de correo electrónico, tu configuración de correo electrónico parece estar ajustada correctamente.', // Role Settings 'roles' => 'Roles', From 63f9391f53b05464f8d8d11ac2c151ef4fb26a5e Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:40 +0000 Subject: [PATCH 094/191] New translations errors.php (Turkish) --- resources/lang/tr/errors.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/resources/lang/tr/errors.php b/resources/lang/tr/errors.php index 8a897b488..4b14edb4c 100644 --- a/resources/lang/tr/errors.php +++ b/resources/lang/tr/errors.php @@ -17,6 +17,12 @@ return [ 'ldap_fail_authed' => 'Verdiğiniz bilgiler ile LDAP girişi başarısız oldu.', 'ldap_extension_not_installed' => 'LDAP PHP eklentisi yüklenmedi', 'ldap_cannot_connect' => 'LDAP sunucusuna bağlanılamadı, ilk bağlantı başarısız oldu', + 'saml_already_logged_in' => 'Already logged in', + 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', + 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', + 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', + 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', + 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => 'Bir aksiyon tanımlanmadı', 'social_login_bad_response' => ":socialAccount girişi sırasında hata oluştu: \n:error", 'social_account_in_use' => 'Bu :socialAccount zaten kullanımda, :socialAccount hesabıyla giriş yapmayı deneyin.', @@ -27,7 +33,7 @@ return [ 'social_account_register_instructions' => 'Hala bir hesabınız yoksa :socialAccount ile kayıt olabilirsiniz.', 'social_driver_not_found' => 'Social driver bulunamadı', 'social_driver_not_configured' => ':socialAccount ayarlarınız doğru bir şekilde ayarlanmadı.', - 'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.', + 'invite_token_expired' => 'Davetiye linkinin süresi doldu. Bunun yerine parolanızı sıfırlamayı deneyebilirsiniz.', // System 'path_not_writable' => ':filePath dosya yolu yüklenemedi. Sunucuya yazılabilir olduğundan emin olun.', From 0105d4d5ddcee9f8454a93a924aea8bb4528cbb0 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:42 +0000 Subject: [PATCH 095/191] New translations validation.php (Ukrainian) --- resources/lang/uk/validation.php | 152 +++++++++++++++---------------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/resources/lang/uk/validation.php b/resources/lang/uk/validation.php index 5e8172889..47f15fe7f 100644 --- a/resources/lang/uk/validation.php +++ b/resources/lang/uk/validation.php @@ -8,98 +8,98 @@ return [ // Standard laravel validation lines - 'accepted' => ':attribute повинен бути прийнятий.', - 'active_url' => ':attribute не є дійсною URL-адресою.', - 'after' => ':attribute повинно бути датою після :date.', - 'alpha' => ':attribute може містити лише літери.', - 'alpha_dash' => ':attribute може містити лише літери, цифри та дефіси.', - 'alpha_num' => ':attribute може містити лише літери та цифри.', - 'array' => ':attribute повинен бути масивом.', - 'before' => ':attribute повинен бути датою до :date.', + 'accepted' => 'Ви повинні прийняти :attribute.', + 'active_url' => 'Поле :attribute не є правильним URL.', + 'after' => 'Поле :attribute має містити дату не раніше :date.', + 'alpha' => 'Поле :attribute має містити лише літери.', + 'alpha_dash' => 'Поле :attribute має містити лише літери, цифри, дефіси та підкреслення.', + 'alpha_num' => 'Поле :attribute має містити лише літери та цифри.', + 'array' => 'Поле :attribute має бути масивом.', + 'before' => 'Поле :attribute має містити дату не пізніше :date.', 'between' => [ - 'numeric' => ':attribute повинен бути між :min та :max.', - 'file' => ':attribute повинен бути між :min та :max кілобайт.', - 'string' => ':attribute повинен бути між :min та :max символів.', - 'array' => ':attribute повинен бути між :min та :max елементів.', + 'numeric' => 'Поле :attribute має бути між :min та :max.', + 'file' => 'Розмір файлу в полі :attribute має бути не менше :min та не більше :max кілобайт.', + 'string' => 'Текст в полі :attribute має бути не менше :min та не більше :max символів.', + 'array' => 'Поле :attribute має містити від :min до :max елементів.', ], - 'boolean' => ':attribute поле має бути true або false.', - 'confirmed' => ':attribute підтвердження не збігається.', - 'date' => ':attribute не є дійсною датою.', - 'date_format' => ':attribute не відповідає формату :format.', - 'different' => ':attribute та :other повинні бути різними.', - 'digits' => ':attribute повинні бути :digits цифрами.', - 'digits_between' => ':attribute має бути між :min та :max цифр.', - 'email' => ':attribute повинна бути дійсною електронною адресою.', - 'ends_with' => 'The :attribute must end with one of the following: :values', - 'filled' => ':attribute поле обов\'язкове.', + 'boolean' => 'Поле :attribute повинне містити true чи false.', + 'confirmed' => 'Поле :attribute не збігається з підтвердженням.', + 'date' => 'Поле :attribute не є датою.', + 'date_format' => 'Поле :attribute не відповідає формату :format.', + 'different' => 'Поля :attribute та :other повинні бути різними.', + 'digits' => 'Довжина цифрового поля :attribute повинна дорівнювати :digits.', + 'digits_between' => 'Довжина цифрового поля :attribute повинна бути від :min до :max.', + 'email' => 'Поле :attribute повинне містити коректну електронну адресу.', + 'ends_with' => 'Поле :attribute має закінчуватися одним з наступних значень: :values', + 'filled' => 'Поле :attribute є обов\'язковим для заповнення.', 'gt' => [ - 'numeric' => 'The :attribute must be greater than :value.', - 'file' => ':attribute має бути більшим ніж :value кілобайт.', - 'string' => 'The :attribute must be greater than :value characters.', - 'array' => 'The :attribute must have more than :value items.', + 'numeric' => 'Поле :attribute має бути більше ніж :value.', + 'file' => 'Поле :attribute має бути більше ніж :value кілобайт.', + 'string' => 'Поле :attribute має бути більше ніж :value символів.', + 'array' => 'Поле :attribute має містити більше ніж :value елементів.', ], 'gte' => [ - 'numeric' => 'The :attribute must be greater than or equal :value.', - 'file' => 'The :attribute must be greater than or equal :value kilobytes.', - 'string' => 'The :attribute must be greater than or equal :value characters.', - 'array' => 'The :attribute must have :value items or more.', + 'numeric' => 'Поле :attribute має дорівнювати чи бути більше ніж :value.', + 'file' => 'Поле :attribute має дорівнювати чи бути більше ніж :value кілобайт.', + 'string' => 'Поле :attribute має дорівнювати чи бути більше ніж :value символів.', + 'array' => 'Поле :attribute має містити :value чи більше елементів.', ], - 'exists' => 'Вибраний :attribute недійсний.', - 'image' => ':attribute повинен бути зображенням.', - 'image_extension' => ':attribute повинен мати дійсне та підтримуване розширення зображення.', - 'in' => 'Вибраний :attribute недійсний.', - 'integer' => ':attribute повинен бути цілим числом.', - 'ip' => ':attribute повинна бути дійсною IP-адресою.', - 'ipv4' => 'The :attribute must be a valid IPv4 address.', - 'ipv6' => 'The :attribute must be a valid IPv6 address.', - 'json' => 'The :attribute must be a valid JSON string.', + 'exists' => 'Вибране для :attribute значення не коректне.', + 'image' => 'Поле :attribute має містити зображення.', + 'image_extension' => 'Поле :attribute має містити дійсне та підтримуване розширення зображення.', + 'in' => 'Вибране для :attribute значення не коректне.', + 'integer' => 'Поле :attribute має містити ціле число.', + 'ip' => 'Поле :attribute має містити IP адресу.', + 'ipv4' => 'Поле :attribute має містити IPv4 адресу.', + 'ipv6' => 'Поле :attribute має містити IPv6 адресу.', + 'json' => 'Дані поля :attribute мають бути в форматі JSON.', 'lt' => [ - 'numeric' => 'The :attribute must be less than :value.', - 'file' => 'The :attribute must be less than :value kilobytes.', - 'string' => 'The :attribute must be less than :value characters.', - 'array' => 'The :attribute must have less than :value items.', + 'numeric' => 'Поле :attribute має бути менше ніж :value.', + 'file' => 'Поле :attribute має бути менше ніж :value кілобайт.', + 'string' => 'Поле :attribute має бути менше ніж :value символів.', + 'array' => 'Поле :attribute має містити менше ніж :value елементів.', ], 'lte' => [ - 'numeric' => 'The :attribute must be less than or equal :value.', - 'file' => 'The :attribute must be less than or equal :value kilobytes.', - 'string' => 'The :attribute must be less than or equal :value characters.', - 'array' => 'The :attribute must not have more than :value items.', + 'numeric' => 'Поле :attribute має дорівнювати чи бути менше ніж :value.', + 'file' => 'Поле :attribute має дорівнювати чи бути менше ніж :value кілобайт.', + 'string' => 'Поле :attribute має дорівнювати чи бути менше ніж :value символів.', + 'array' => 'Поле :attribute має містити не більше ніж :value елементів.', ], 'max' => [ - 'numeric' => ':attribute не може бути більшим за :max.', - 'file' => ':attribute не може бути більшим за :max кілобайт.', - 'string' => ':attribute не може бути більшим за :max символів.', - 'array' => ':attribute не може бути більше ніж :max елементів.', + 'numeric' => 'Поле :attribute має бути не більше :max.', + 'file' => 'Файл в полі :attribute має бути не більше :max кілобайт.', + 'string' => 'Текст в полі :attribute повинен мати довжину не більшу за :max.', + 'array' => 'Поле :attribute повинне містити не більше :max елементів.', ], - 'mimes' => ':attribute повинен бути файлом типу: :values.', + 'mimes' => 'Поле :attribute повинне містити файл одного з типів: :values.', 'min' => [ - 'numeric' => ':attribute повинен бути принаймні :min.', - 'file' => ':attribute повинен бути принаймні :min кілобайт.', - 'string' => ':attribute повинен бути принаймні :min символів.', - 'array' => ':attribute повинен містити принаймні :min елементів.', + 'numeric' => 'Поле :attribute повинне бути не менше :min.', + 'file' => 'Розмір файлу в полі :attribute має бути не меншим :min кілобайт.', + 'string' => 'Текст в полі :attribute повинен містити не менше :min символів.', + 'array' => 'Поле :attribute повинне містити не менше :min елементів.', ], - 'no_double_extension' => ':attribute повинен мати тільки одне розширення файлу.', - 'not_in' => 'Вибраний :attribute недійсний.', - 'not_regex' => 'The :attribute format is invalid.', - 'numeric' => ':attribute повинен бути числом.', - 'regex' => ':attribute формат недійсний.', - 'required' => ':attribute поле обов\'язкове.', - 'required_if' => ':attribute поле бов\'язкове, коли :other з значенням :value.', - 'required_with' => ':attribute поле бов\'язкове, коли :values встановлено.', - 'required_with_all' => ':attribute поле бов\'язкове, коли :values встановлені.', - 'required_without' => ':attribute поле бов\'язкове, коли :values не встановлені.', - 'required_without_all' => ':attribute поле бов\'язкове, коли жодне з :values не встановлене.', - 'same' => ':attribute та :other мають збігатись.', + 'no_double_extension' => 'Поле :attribute повинне містити тільки одне розширення файлу.', + 'not_in' => 'Вибране для :attribute значення не коректне.', + 'not_regex' => 'Формат поля :attribute не вірний.', + 'numeric' => 'Поле :attribute повинно містити число.', + 'regex' => 'Поле :attribute має хибний формат.', + 'required' => 'Поле :attribute є обов\'язковим для заповнення.', + 'required_if' => 'Поле :attribute є обов\'язковим для заповнення, коли :other є рівним :value.', + 'required_with' => 'Поле :attribute є обов\'язковим для заповнення, коли :values вказано.', + 'required_with_all' => 'Поле :attribute є обов\'язковим для заповнення, коли :values вказано.', + 'required_without' => 'Поле :attribute є обов\'язковим для заповнення, коли :values не вказано.', + 'required_without_all' => 'Поле :attribute є обов\'язковим для заповнення, коли :values не вказано.', + 'same' => 'Поля :attribute та :other мають збігатися.', 'size' => [ - 'numeric' => ':attribute має бути :size.', - 'file' => ':attribute має бути :size кілобайт.', - 'string' => ':attribute має бути :size символів.', - 'array' => ':attribute має містити :size елементів.', + 'numeric' => 'Поле :attribute має бути довжини :size.', + 'file' => 'Файл в полі :attribute має бути розміром :size кілобайт.', + 'string' => 'Текст в полі :attribute повинен містити :size символів.', + 'array' => 'Поле :attribute повинне містити :size елементів.', ], - 'string' => ':attribute повинен бути рядком.', - 'timezone' => ':attribute повинен бути дійсною зоною.', - 'unique' => ':attribute вже є.', - 'url' => ':attribute формат недійсний.', + 'string' => 'Поле :attribute повинне містити текст.', + 'timezone' => 'Поле :attribute повинне містити коректну часову зону.', + 'unique' => 'Вказане значення поля :attribute вже існує.', + 'url' => 'Формат поля :attribute неправильний.', 'uploaded' => 'Не вдалося завантажити файл. Сервер може не приймати файли такого розміру.', // Custom validation lines From 6ffb283014d13101c953be3e0952b02e8f76e0f3 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:45 +0000 Subject: [PATCH 096/191] New translations settings.php (German Informal) --- resources/lang/de_informal/settings.php | 27 ++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/resources/lang/de_informal/settings.php b/resources/lang/de_informal/settings.php index ed8d8a11f..afc111679 100644 --- a/resources/lang/de_informal/settings.php +++ b/resources/lang/de_informal/settings.php @@ -23,13 +23,13 @@ return [ 'app_public_access_toggle' => 'Öffentlichen Zugriff erlauben', 'app_public_viewing' => 'Öffentliche Ansicht erlauben?', 'app_secure_images' => 'Erhöhte Sicherheit für hochgeladene Bilder aktivieren?', - 'app_secure_images_toggle' => 'Enable higher security image uploads', + 'app_secure_images_toggle' => 'Aktiviere Bild-Upload höherer Sicherheit', 'app_secure_images_desc' => 'Aus Leistungsgründen sind alle Bilder öffentlich sichtbar. Diese Option fügt zufällige, schwer zu eratene, Zeichenketten zu Bild-URLs hinzu. Stellen sie sicher, dass Verzeichnisindizes deaktiviert sind, um einen einfachen Zugriff zu verhindern.', 'app_editor' => 'Seiteneditor', 'app_editor_desc' => 'Wähle den Editor aus, der von allen Benutzern genutzt werden soll, um Seiten zu editieren.', 'app_custom_html' => 'Benutzerdefinierter HTML Inhalt', 'app_custom_html_desc' => 'Jeder Inhalt, der hier hinzugefügt wird, wird am Ende der Sektion jeder Seite eingefügt. Diese kann praktisch sein, um CSS Styles anzupassen oder Analytics-Code hinzuzufügen.', - 'app_custom_html_disabled_notice' => 'Custom HTML head content is disabled on this settings page to ensure any breaking changes can be reverted.', + 'app_custom_html_disabled_notice' => 'Benutzerdefinierte HTML-Kopfzeileninhalte sind auf dieser Einstellungsseite deaktiviert, um sicherzustellen, dass alle Änderungen rückgängig gemacht werden können.', 'app_logo' => 'Anwendungslogo', 'app_logo_desc' => 'Dieses Bild sollte 43px hoch sein. Größere Bilder werden verkleinert.', @@ -43,12 +43,22 @@ Wenn Du nichts eingibst, wird die Anwendung auf die Standardfarbe zurückgesetzt 'app_disable_comments_toggle' => 'Kommentare deaktivieren', 'app_disable_comments_desc' => 'Deaktiviert Kommentare über alle Seiten in der Anwendung. Vorhandene Kommentare werden nicht angezeigt.', + // Color settings + 'content_colors' => 'Inhaltsfarben', + 'content_colors_desc' => 'Legt Farben für alle Elemente in der Seitenorganisationshierarchie fest. Die Auswahl von Farben mit einer ähnlichen Helligkeit wie die Standardfarben wird zur Lesbarkeit empfohlen.', + 'bookshelf_color' => 'Regalfarbe', + 'book_color' => 'Buchfarbe', + 'chapter_color' => 'Kapitelfarbe', + 'page_color' => 'Seitenfarbe', + 'page_draft_color' => 'Seitenentwurfsfarbe', + // Registration Settings 'reg_settings' => 'Registrierungseinstellungen', 'reg_enable' => 'Registrierung erlauben?', 'reg_enable_toggle' => 'Registrierung erlauben', 'reg_enable_desc' => 'Wenn die Registrierung erlaubt ist, kann sich der Benutzer als Anwendungsbenutzer anmelden. Bei der Registrierung erhält er eine einzige, voreingestellte Benutzerrolle.', 'reg_default_role' => 'Standard-Benutzerrolle nach Registrierung', + 'reg_enable_ldap_warning' => 'Die obige Option wird während der LDAP-Authentifizierung nicht verwendet. Benutzerkonten für nicht existierende Mitglieder werden automatisch erzeugt, wenn die Authentifizierung gegen das verwendete LDAP-System erfolgreich ist.', 'reg_email_confirmation' => 'Bestätigung per E-Mail', 'reg_email_confirmation_toggle' => 'Bestätigung per E-Mail erforderlich', 'reg_confirm_email_desc' => 'Falls die Einschränkung für Domains genutzt wird, ist die Bestätigung per E-Mail zwingend erforderlich und der untenstehende Wert wird ignoriert.', @@ -66,6 +76,13 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'maint_image_cleanup_warning' => ':count eventuell unbenutze Bilder wurden gefunden. Möchtest Du diese Bilder löschen?', 'maint_image_cleanup_success' => ':count eventuell unbenutze Bilder wurden gefunden und gelöscht.', 'maint_image_cleanup_nothing_found' => 'Keine unbenutzen Bilder gefunden. Nichts zu löschen!', + 'maint_send_test_email' => 'Test Email versenden', + 'maint_send_test_email_desc' => 'Dies sendet eine Test E-Mail an Ihre in Ihrem Profil angegebene E-Mail-Adresse.', + 'maint_send_test_email_run' => 'Sende eine Test E-Mail', + 'maint_send_test_email_success' => 'E-Mail wurde an :address gesendet', + 'maint_send_test_email_mail_subject' => 'Test E-Mail', + 'maint_send_test_email_mail_greeting' => 'E-Mail-Versand scheint zu funktionieren!', + 'maint_send_test_email_mail_text' => 'Glückwunsch! Da Sie diese E-Mail Benachrichtigung erhalten haben, scheinen Ihre E-Mail-Einstellungen korrekt konfiguriert zu sein.', // Role Settings 'roles' => 'Rollen', @@ -88,7 +105,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'role_manage_roles' => 'Rollen und Rollen-Berechtigungen verwalten', 'role_manage_entity_permissions' => 'Alle Buch-, Kapitel- und Seiten-Berechtigungen verwalten', 'role_manage_own_entity_permissions' => 'Nur Berechtigungen eigener Bücher, Kapitel und Seiten verwalten', - 'role_manage_page_templates' => 'Manage page templates', + 'role_manage_page_templates' => 'Seitenvorlagen verwalten', 'role_manage_settings' => 'Globaleinstellungen verwalten', 'role_asset' => 'Berechtigungen', 'role_asset_desc' => 'Diese Berechtigungen gelten für den Standard-Zugriff innerhalb des Systems. Berechtigungen für Bücher, Kapitel und Seiten überschreiben diese Berechtigungenen.', @@ -113,8 +130,8 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'users_role_desc' => 'Wählen Sie aus, welchen Rollen dieser Benutzer zugeordnet werden soll. Wenn ein Benutzer mehreren Rollen zugeordnet ist, werden die Berechtigungen dieser Rollen gestapelt und er erhält alle Fähigkeiten der zugewiesenen Rollen.', 'users_password' => 'Benutzerpasswort', 'users_password_desc' => 'Legen Sie ein Passwort fest, mit dem Sie sich anmelden möchten. Diese muss mindestens 5 Zeichen lang sein.', - 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', - 'users_send_invite_option' => 'Send user invite email', + 'users_send_invite_text' => 'Sie können diesem Benutzer eine Einladungs-E-Mail senden, die es ihm erlaubt, sein eigenes Passwort zu setzen, andernfalls können Sie sein Passwort selbst setzen.', + 'users_send_invite_option' => 'Benutzer-Einladungs-E-Mail senden', 'users_external_auth_id' => 'Externe Authentifizierungs-ID', 'users_external_auth_id_desc' => 'Dies ist die ID, die verwendet wird, um diesen Benutzer bei der Kommunikation mit Ihrem LDAP-System abzugleichen.', 'users_password_warning' => 'Fülle die folgenden Felder nur aus, wenn Du Dein Passwort ändern möchtest:', From e634391fd74fdbb2c077eec61b3de60ad0d0f7f1 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:46 +0000 Subject: [PATCH 097/191] New translations errors.php (German Informal) --- resources/lang/de_informal/errors.php | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/resources/lang/de_informal/errors.php b/resources/lang/de_informal/errors.php index e62350156..dc33f4239 100644 --- a/resources/lang/de_informal/errors.php +++ b/resources/lang/de_informal/errors.php @@ -9,11 +9,22 @@ return [ 'permissionJson' => 'Du hast keine Berechtigung, die angeforderte Aktion auszuführen.', // Auth - 'saml_already_logged_in' => 'Du bist bereits angemeldet', 'error_user_exists_different_creds' => 'Ein Benutzer mit der E-Mail-Adresse :email ist bereits mit anderen Anmeldedaten registriert.', 'email_already_confirmed' => 'Die E-Mail-Adresse ist bereits bestätigt. Bitte melde dich an.', 'email_confirmation_invalid' => 'Der Bestätigungslink ist nicht gültig oder wurde bereits verwendet. Bitte registriere dich erneut.', - + 'email_confirmation_expired' => 'Der Bestätigungslink ist abgelaufen. Es wurde eine neue Bestätigungs-E-Mail gesendet.', + 'ldap_fail_anonymous' => 'Anonymer LDAP-Zugriff ist fehlgeschlafgen', + 'ldap_fail_authed' => 'LDAP-Zugriff mit DN und Passwort ist fehlgeschlagen', + 'ldap_extension_not_installed' => 'LDAP-PHP-Erweiterung ist nicht installiert.', + 'ldap_cannot_connect' => 'Die Verbindung zum LDAP-Server ist fehlgeschlagen. Beim initialen Verbindungsaufbau trat ein Fehler auf.', + 'saml_already_logged_in' => 'Du bist bereits angemeldet', + 'saml_user_not_registered' => 'Kein Benutzer mit ID :name registriert und die automatische Registrierung ist deaktiviert', + 'saml_no_email_address' => 'Es konnte keine E-Mail-Adresse für diesen Benutzer in den vom externen Authentifizierungssystem zur Verfügung gestellten Daten gefunden werden', + 'saml_invalid_response_id' => 'Die Anfrage vom externen Authentifizierungssystem wird von einem von dieser Anwendung gestarteten Prozess nicht erkannt. Das Zurückgehen nach einem Login könnte dieses Problem verursachen.', + 'saml_fail_authed' => 'Anmeldung mit :system fehlgeschlagen, System konnte keine erfolgreiche Autorisierung bereitstellen', + 'saml_email_exists' => 'Registrierung fehlgeschlagen, da bereits ein Benutzer mit der E-Mail-Adresse ":email" existiert', + 'social_no_action_defined' => 'Es ist keine Aktion definiert', + 'social_login_bad_response' => "Fehler bei der :socialAccount-Anmeldung: \n:error", 'social_account_in_use' => 'Dieses :socialAccount-Konto wird bereits verwendet. Bitte melde dich mit dem :socialAccount-Konto an.', 'social_account_email_in_use' => 'Die E-Mail-Adresse ":email" ist bereits registriert. Wenn Du bereits registriert bist, kannst Du Dein :socialAccount-Konto in Deinen Profil-Einstellungen verknüpfen.', 'social_account_existing' => 'Dieses :socialAccount-Konto ist bereits mit Ihrem Profil verknüpft.', @@ -22,7 +33,7 @@ return [ 'social_account_register_instructions' => 'Wenn Du bisher kein Social-Media Konto besitzt, kannst Du ein solches Konto mit der :socialAccount Option anlegen.', 'social_driver_not_found' => 'Treiber für Social-Media-Konten nicht gefunden', 'social_driver_not_configured' => 'Ihr :socialAccount-Konto ist nicht korrekt konfiguriert.', - 'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.', + 'invite_token_expired' => 'Dieser Einladungslink ist abgelaufen. Sie können stattdessen versuchen, Ihr Passwort zurückzusetzen.', // System 'path_not_writable' => 'Die Datei kann nicht in den angegebenen Pfad :filePath hochgeladen werden. Stelle sicher, dass dieser Ordner auf dem Server beschreibbar ist.', From e9e6f11c2f7a9788f98a1bdf74845ad6cdf06ea5 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:48 +0000 Subject: [PATCH 098/191] New translations entities.php (German Informal) --- resources/lang/de_informal/entities.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/resources/lang/de_informal/entities.php b/resources/lang/de_informal/entities.php index 1a64f25a7..e0cbedf91 100644 --- a/resources/lang/de_informal/entities.php +++ b/resources/lang/de_informal/entities.php @@ -176,7 +176,7 @@ return [ 'pages_delete_confirm' => 'Bist Du sicher, dass Du diese Seite löschen möchtest?', 'pages_delete_draft_confirm' => 'Bist Du sicher, dass Du diesen Seitenentwurf löschen möchtest?', 'pages_editing_named' => 'Seite ":pageName" bearbeiten', - 'pages_edit_draft_options' => 'Draft Options', + 'pages_edit_draft_options' => 'Entwurfsoptionen', 'pages_edit_save_draft' => 'Entwurf speichern', 'pages_edit_draft' => 'Seitenentwurf bearbeiten', 'pages_editing_draft' => 'Seitenentwurf bearbeiten', @@ -211,7 +211,7 @@ return [ 'pages_revisions_date' => 'Versionsdatum', 'pages_revisions_number' => '#', 'pages_revisions_numbered' => 'Revision #:id', - 'pages_revisions_numbered_changes' => 'Revision #:id Changes', + 'pages_revisions_numbered_changes' => 'Revision #:id Änderungen', 'pages_revisions_changelog' => 'Änderungsprotokoll', 'pages_revisions_changes' => 'Änderungen', 'pages_revisions_current' => 'Aktuelle Version', @@ -233,8 +233,8 @@ return [ 'message' => ':start :time. Achte darauf, keine Änderungen von anderen Benutzern zu überschreiben!', ], 'pages_draft_discarded' => 'Entwurf verworfen. Der aktuelle Seiteninhalt wurde geladen.', - 'pages_specific' => 'Specific Page', - 'pages_is_template' => 'Page Template', + 'pages_specific' => 'Spezifische Seite', + 'pages_is_template' => 'Seitenvorlage', // Editor Sidebar 'page_tags' => 'Seiten-Schlagwörter', @@ -243,11 +243,11 @@ return [ 'shelf_tags' => 'Regal-Schlagwörter', 'tag' => 'Schlagwort', 'tags' => 'Schlagwörter', - 'tag_name' => 'Tag Name', + 'tag_name' => 'Schlagwort Name', 'tag_value' => 'Inhalt (Optional)', 'tags_explain' => "Füge Schlagwörter hinzu, um ihren Inhalt zu kategorisieren.\nDu kannst einen erklärenden Inhalt hinzufügen, um eine genauere Unterteilung vorzunehmen.", 'tags_add' => 'Weiteres Schlagwort hinzufügen', - 'tags_remove' => 'Remove this tag', + 'tags_remove' => 'Diesen Tag entfernen', 'attachments' => 'Anhänge', 'attachments_explain' => 'Du kannst auf Deiner Seite Dateien hochladen oder Links hinzufügen. Diese werden in der Seitenleiste angezeigt.', 'attachments_explain_instant_save' => 'Änderungen werden direkt gespeichert.', @@ -273,12 +273,12 @@ return [ 'attachments_file_uploaded' => 'Datei erfolgreich hochgeladen', 'attachments_file_updated' => 'Datei erfolgreich aktualisiert', 'attachments_link_attached' => 'Link erfolgreich der Seite hinzugefügt', - 'templates' => 'Templates', - 'templates_set_as_template' => 'Page is a template', - 'templates_explain_set_as_template' => 'You can set this page as a template so its contents be utilized when creating other pages. Other users will be able to use this template if they have view permissions for this page.', - 'templates_replace_content' => 'Replace page content', - 'templates_append_content' => 'Append to page content', - 'templates_prepend_content' => 'Prepend to page content', + 'templates' => 'Vorlagen', + 'templates_set_as_template' => 'Seite ist eine Vorlage', + 'templates_explain_set_as_template' => 'Sie können diese Seite als Vorlage festlegen, damit deren Inhalt beim Erstellen anderer Seiten verwendet werden kann. Andere Benutzer können diese Vorlage verwenden, wenn sie die Zugriffsrechte für diese Seite haben.', + 'templates_replace_content' => 'Seiteninhalt ersetzen', + 'templates_append_content' => 'An Seiteninhalt anhängen', + 'templates_prepend_content' => 'Seiteninhalt voranstellen', // Profile View 'profile_user_for_x' => 'Benutzer seit :time', From b5d1b611b15814146605f1acdcf73b1073e227b6 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:49 +0000 Subject: [PATCH 099/191] New translations common.php (German Informal) --- resources/lang/de_informal/common.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/resources/lang/de_informal/common.php b/resources/lang/de_informal/common.php index 8d9b3aeab..1fb2d6f78 100644 --- a/resources/lang/de_informal/common.php +++ b/resources/lang/de_informal/common.php @@ -38,12 +38,13 @@ return [ 'reset' => 'Zurücksetzen', 'remove' => 'Entfernen', 'add' => 'Hinzufügen', + 'fullscreen' => 'Vollbild', // Sort Options - 'sort_options' => 'Sort Options', - 'sort_direction_toggle' => 'Sort Direction Toggle', - 'sort_ascending' => 'Sort Ascending', - 'sort_descending' => 'Sort Descending', + 'sort_options' => 'Sortieroptionen', + 'sort_direction_toggle' => 'Sortierreihenfolge umkehren', + 'sort_ascending' => 'Aufsteigend sortieren', + 'sort_descending' => 'Absteigend sortieren', 'sort_name' => 'Name', 'sort_created_at' => 'Erstellungsdatum', 'sort_updated_at' => 'Aktualisierungsdatum', @@ -59,10 +60,10 @@ return [ 'grid_view' => 'Gitteransicht', 'list_view' => 'Listenansicht', 'default' => 'Voreinstellung', - 'breadcrumb' => 'Breadcrumb', + 'breadcrumb' => 'Brotkrumen', // Header - 'profile_menu' => 'Profile Menu', + 'profile_menu' => 'Profilmenü', 'view_profile' => 'Profil ansehen', 'edit_profile' => 'Profil bearbeiten', From f39f2ca48784a720e50983ae7d002e348acbc1b0 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:50 +0000 Subject: [PATCH 100/191] New translations auth.php (German Informal) --- resources/lang/de_informal/auth.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/resources/lang/de_informal/auth.php b/resources/lang/de_informal/auth.php index ffe518b93..c91cd4129 100644 --- a/resources/lang/de_informal/auth.php +++ b/resources/lang/de_informal/auth.php @@ -66,12 +66,12 @@ return [ 'email_not_confirmed_resend_button' => 'Bestätigungs-E-Mail erneut senden', // User Invite - 'user_invite_email_subject' => 'You have been invited to join :appName!', - 'user_invite_email_greeting' => 'An account has been created for you on :appName.', - 'user_invite_email_text' => 'Click the button below to set an account password and gain access:', - 'user_invite_email_action' => 'Set Account Password', - 'user_invite_page_welcome' => 'Welcome to :appName!', - 'user_invite_page_text' => 'To finalise your account and gain access you need to set a password which will be used to log-in to :appName on future visits.', - 'user_invite_page_confirm_button' => 'Confirm Password', - 'user_invite_success' => 'Password set, you now have access to :appName!' + 'user_invite_email_subject' => 'Du wurdest eingeladen :appName beizutreten!', + 'user_invite_email_greeting' => 'Ein Konto wurde für Sie auf :appName erstellt.', + 'user_invite_email_text' => 'Klicken Sie auf die Schaltfläche unten, um ein Passwort festzulegen und Zugriff zu erhalten:', + 'user_invite_email_action' => 'Account-Passwort festlegen', + 'user_invite_page_welcome' => 'Willkommen bei :appName!', + 'user_invite_page_text' => 'Um die Anmeldung abzuschließen und Zugriff auf :appName zu bekommen muss noch ein Passwort festgelegt werden. Dieses wird in Zukunft zum Einloggen benötigt.', + 'user_invite_page_confirm_button' => 'Passwort wiederholen', + 'user_invite_success' => 'Passwort gesetzt, Sie haben nun Zugriff auf :appName!' ]; \ No newline at end of file From dc5cc8c3ecc234cf21c6ea5850d987858892118b Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:52 +0000 Subject: [PATCH 101/191] New translations settings.php (Ukrainian) --- resources/lang/uk/settings.php | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/resources/lang/uk/settings.php b/resources/lang/uk/settings.php index 37428ec99..d15e85fa8 100644 --- a/resources/lang/uk/settings.php +++ b/resources/lang/uk/settings.php @@ -29,7 +29,7 @@ return [ 'app_editor_desc' => 'Виберіть, який редактор буде використовуватися всіма користувачами для редагування сторінок.', 'app_custom_html' => 'Користувацький вміст HTML-заголовку', 'app_custom_html_desc' => 'Будь-який доданий тут вміст буде вставлено в нижню частину розділу кожної сторінки. Це зручно для перевизначення стилів, або додавання коду аналітики.', - 'app_custom_html_disabled_notice' => 'Custom HTML head content is disabled on this settings page to ensure any breaking changes can be reverted.', + 'app_custom_html_disabled_notice' => 'На цій сторінці налаштувань відключений користувацький вміст заголовка HTML, щоб гарантувати, що будь-які невдалі зміни можна буде відновити.', 'app_logo' => 'Логотип програми', 'app_logo_desc' => 'Це зображення має бути висотою 43px.
Великі зображення будуть зменшені.', 'app_primary_color' => 'Основний колір програми', @@ -41,12 +41,22 @@ return [ 'app_disable_comments_toggle' => 'Вимкнути коментарі', 'app_disable_comments_desc' => 'Вимкнути коментарі на всіх сторінках програми. Існуючі коментарі не відображаються.', + // Color settings + 'content_colors' => 'Кольори вмісту', + 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'bookshelf_color' => 'Колір полиці', + 'book_color' => 'Колір книги', + 'chapter_color' => 'Chapter Color', + 'page_color' => 'Колір сторінки', + 'page_draft_color' => 'Колір чернетки', + // Registration Settings 'reg_settings' => 'Реєстрація', 'reg_enable' => 'Дозволити реєстрацію', 'reg_enable_toggle' => 'Дозволити реєстрацію', 'reg_enable_desc' => 'При включенні реєстрації відвідувач зможе зареєструватися як користувач програми. Після реєстрації їм надається єдина роль користувача за замовчуванням.', 'reg_default_role' => 'Роль користувача за умовчанням після реєстрації', + 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', 'reg_email_confirmation' => 'Підтвердження електронною поштою', 'reg_email_confirmation_toggle' => 'Необхідне підтвердження електронною поштою', 'reg_confirm_email_desc' => 'Якщо використовується обмеження домену, то підтвердження електронною поштою буде потрібно, а нижче значення буде проігноровано.', @@ -63,6 +73,13 @@ return [ 'maint_image_cleanup_warning' => ':count потенційно невикористаних зображень було знайдено. Ви впевнені, що хочете видалити ці зображення?', 'maint_image_cleanup_success' => ':count потенційно невикористані зображення знайдено і видалено!', 'maint_image_cleanup_nothing_found' => 'Не знайдено невикористовуваних зображень, нічого не видалено!', + 'maint_send_test_email' => 'Надіслати тестове повідомлення', + 'maint_send_test_email_desc' => 'Надіслати тестового листа на адресу електронної пошти, що вказана у вашому профілі.', + 'maint_send_test_email_run' => 'Надіслати тестовий лист', + 'maint_send_test_email_success' => 'Лист відправлений на : адреса', + 'maint_send_test_email_mail_subject' => 'Перевірка електронної пошти', + 'maint_send_test_email_mail_greeting' => 'Доставляння електронної пошти працює!', + 'maint_send_test_email_mail_text' => 'Вітаємо! Оскільки ви отримали цього листа, поштова скринька налаштована правильно.', // Role Settings 'roles' => 'Ролі', @@ -85,7 +102,7 @@ return [ 'role_manage_roles' => 'Керування правами ролей та ролями', 'role_manage_entity_permissions' => 'Керування всіма правами на книги, розділи та сторінки', 'role_manage_own_entity_permissions' => 'Керування дозволами на власну книгу, розділ та сторінки', - 'role_manage_page_templates' => 'Manage page templates', + 'role_manage_page_templates' => 'Управління шаблонами сторінок', 'role_manage_settings' => 'Керування налаштуваннями програми', 'role_asset' => 'Дозволи', 'role_asset_desc' => 'Ці дозволи контролюють стандартні доступи всередині системи. Права на книги, розділи та сторінки перевизначать ці дозволи.', @@ -110,8 +127,8 @@ return [ 'users_role_desc' => 'Виберіть, до яких ролей буде призначено цього користувача. Якщо користувачеві призначено декілька ролей, дозволи з цих ролей будуть складатись і вони отримуватимуть усі можливості призначених ролей.', 'users_password' => 'Пароль користувача', 'users_password_desc' => 'Встановіть пароль для входу. Він повинен містити принаймні 5 символів.', - 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', - 'users_send_invite_option' => 'Надіслати лист із запрошенням користувачу', + 'users_send_invite_text' => 'Ви можете надіслати цьому користувачеві лист із запрошенням, що дозволить йому встановити пароль власноруч, або ви можете встановити йому пароль самостійно.', + 'users_send_invite_option' => 'Надіслати листа із запрошенням користувачу', 'users_external_auth_id' => 'Зовнішній ID автентифікації', 'users_external_auth_id_desc' => 'Цей ID використовується для пошуку збігу цього користувача під час зв\'язку з LDAP.', 'users_password_warning' => 'Тільки якщо ви хочете змінити свій пароль, заповніть поля нижче:', From 063a7af846b59e3c38cfd475ba454724bcd5fe95 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:53 +0000 Subject: [PATCH 102/191] New translations settings.php (Turkish) --- resources/lang/tr/settings.php | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/resources/lang/tr/settings.php b/resources/lang/tr/settings.php index bb35fe323..7d5db1f2a 100755 --- a/resources/lang/tr/settings.php +++ b/resources/lang/tr/settings.php @@ -41,12 +41,22 @@ return [ 'app_disable_comments_toggle' => 'Yorumları engelle', 'app_disable_comments_desc' => 'Yorumları uygulamadaki bütün sayfalar için engelle.
Mevcut yorumlar gösterilmeyecektir.', + // Color settings + 'content_colors' => 'Content Colors', + 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'bookshelf_color' => 'Shelf Color', + 'book_color' => 'Book Color', + 'chapter_color' => 'Chapter Color', + 'page_color' => 'Page Color', + 'page_draft_color' => 'Page Draft Color', + // Registration Settings 'reg_settings' => 'Kayıt', 'reg_enable' => 'Kaydolmaya İzin Ver', 'reg_enable_toggle' => 'Kaydolmaya izin ver', 'reg_enable_desc' => 'Kayıt olmaya izin verdiğinizde kullanıcılar kendilerini uygulamaya kaydedebilecekler. Kayıt olduktan sonra kendilerine varsayılan kullanıcı rolü atanacaktır.', 'reg_default_role' => 'Kayıt olduktan sonra varsayılan kullanıcı rolü', + 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', 'reg_email_confirmation' => 'Email Doğrulama', 'reg_email_confirmation_toggle' => 'E-mail onayı gerektir', 'reg_confirm_email_desc' => 'Eğer domain kısıtlaması kullanılıyorsa o zaman email doğrulaması gereklidir ve bu seçenek yok sayılacaktır.', @@ -63,6 +73,13 @@ return [ 'maint_image_cleanup_warning' => ':count potansiyel kullanılmayan görsel bulundu. Bu görselleri silmek istediğinizden emin misiniz?', 'maint_image_cleanup_success' => ':count potanisyel kullanılmayan görsel bulundu ve silindi!', 'maint_image_cleanup_nothing_found' => 'Kullanılmayan görsel bulunamadı ve birşey silinmedi!', + 'maint_send_test_email' => 'Test E-Postası Gönder', + 'maint_send_test_email_desc' => 'Bu profilinizde girdiğiniz e-posta adresine bir test e-postası gönderir.', + 'maint_send_test_email_run' => 'Test E-Postasını gönder', + 'maint_send_test_email_success' => 'E-Posta :address adresine gönderildi', + 'maint_send_test_email_mail_subject' => 'Test e-postası', + 'maint_send_test_email_mail_greeting' => 'E-Posta gönderimi başarılı!', + 'maint_send_test_email_mail_text' => 'Tebrikler! Eğer bu e-posta bildirimini alıyorsanız, e-posta ayarlarınız doğru bir şekilde ayarlanmış demektir.', // Role Settings 'roles' => 'Roller', @@ -85,7 +102,7 @@ return [ 'role_manage_roles' => 'Rolleri ve rol izinlerini yönet', 'role_manage_entity_permissions' => 'Bütün kitap, bölüm ve sayfa izinlerini yönet', 'role_manage_own_entity_permissions' => 'Sahip olunan kitap, bölüm ve sayfaların izinlerini yönet', - 'role_manage_page_templates' => 'Manage page templates', + 'role_manage_page_templates' => 'Sayfa şablonlarını yönet', 'role_manage_settings' => 'Uygulama ayarlarını yönet', 'role_asset' => 'Asset Yetkileri', 'role_asset_desc' => 'Bu izinleri assetlere sistem içinden varsayılan erişimi kontrol eder. Kitaplar, bölümler ve sayfaların izinleri bu izinleri override eder.', @@ -110,8 +127,8 @@ return [ 'users_role_desc' => 'Bu kullanıcının hangi rollere atanabileceğini belirleyin. Eğer bir kullanıcıya birden fazla rol atanırsa, kullanıcı bütün rollerin özelliklerini kullanabilir.', 'users_password' => 'Kullanıcı Parolası', 'users_password_desc' => 'Kullanıcının giriş yaparken kullanacağı bir parola belirleyin. Parola en az 5 karakter olmalıdır.', - 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', - 'users_send_invite_option' => 'Send user invite email', + 'users_send_invite_text' => 'Bu kullanıcıya parolasını sıfırlayabilmesi için bir e-posta gönder veya şifresini sen belirle.', + 'users_send_invite_option' => 'Kullanıcıya davet e-postası gönder', 'users_external_auth_id' => 'Harici Authentication ID\'si', 'users_external_auth_id_desc' => 'Bu ID kullanıcı LDAP sunucu ile bağlantı kurarken kullanılır.', 'users_password_warning' => 'Sadece parolanızı değiştirmek istiyorsanız aşağıyı doldurunuz.', From 6a0627e1d1ea11bcde19bef311e9a668ba2ecdd5 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:54 +0000 Subject: [PATCH 103/191] New translations passwords.php (Ukrainian) --- resources/lang/uk/passwords.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/lang/uk/passwords.php b/resources/lang/uk/passwords.php index cae38db5e..1a0cd0341 100644 --- a/resources/lang/uk/passwords.php +++ b/resources/lang/uk/passwords.php @@ -6,10 +6,10 @@ */ return [ - 'password' => 'Паролі повинні містити принаймні шість символів і відповідати підтвердженню.', + 'password' => 'Пароль повинен містити не менше восьми символів і збігатись з підтвердженням.', 'user' => "Ми не можемо знайти користувача з цією адресою електронної пошти.", 'token' => 'Цей токен для скидання пароля недійсний.', - 'sent' => 'Ми надіслали вам електронний лист із посиланням на скидання пароля!', - 'reset' => 'Ваш пароль був скинутий!', + 'sent' => 'Ми надіслали Вам електронний лист із посиланням для скидання пароля!', + 'reset' => 'Ваш пароль скинуто!', ]; From d957e72047d93ae551965c7992c593d388a03b0b Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:56 +0000 Subject: [PATCH 104/191] New translations errors.php (Ukrainian) --- resources/lang/uk/errors.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/resources/lang/uk/errors.php b/resources/lang/uk/errors.php index 2dacf077e..461874573 100644 --- a/resources/lang/uk/errors.php +++ b/resources/lang/uk/errors.php @@ -17,6 +17,12 @@ return [ 'ldap_fail_authed' => 'LDAP-доступ невдалий, використовуючи задані параметри dn та password', 'ldap_extension_not_installed' => 'Розширення PHP LDAP не встановлено', 'ldap_cannot_connect' => 'Неможливо підключитися до ldap-сервера, Помилка з\'єднання', + 'saml_already_logged_in' => 'Вже увійшли', + 'saml_user_not_registered' => 'Користувач «:name» не зареєстрований, а автоматична реєстрація вимкнена', + 'saml_no_email_address' => 'Не вдалося знайти електронну адресу для цього користувача у даних, наданих зовнішньою системою аутентифікації', + 'saml_invalid_response_id' => 'Запит із зовнішньої системи аутентифікації не розпізнається процесом, розпочатим цим додатком. Повернення назад після входу могла спричинити цю проблему.', + 'saml_fail_authed' => 'Вхід із використанням «:system» не вдався, система не здійснила успішну авторизацію', + 'saml_email_exists' => 'Реєстрація не вдалася, оскільки користувач з електронною адресою «:email» вже існує', 'social_no_action_defined' => 'Жодних дій не визначено', 'social_login_bad_response' => "Помилка, отримана під час входу з :socialAccount помилка : \n:error", 'social_account_in_use' => 'Цей :socialAccount обліковий запис вже використовується, спробуйте ввійти з параметрами :socialAccount.', @@ -27,7 +33,7 @@ return [ 'social_account_register_instructions' => 'Якщо у вас ще немає облікового запису, ви можете зареєструвати обліковий запис за допомогою параметра :socialAccount.', 'social_driver_not_found' => 'Драйвер для СоціальноїМережі не знайдено', 'social_driver_not_configured' => 'Ваші соціальні настройки :socialAccount не правильно налаштовані.', - 'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.', + 'invite_token_expired' => 'Термін дії цього запрошення закінчився. Замість цього ви можете спробувати скинути пароль свого облікового запису.', // System 'path_not_writable' => 'Не вдається завантажити шлях до файлу :filePath. Переконайтеся, що він доступний для запису на сервер.', From d7d634a3d72d9a3e64647470c2206693d3bbd259 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:58 +0000 Subject: [PATCH 105/191] New translations entities.php (Ukrainian) --- resources/lang/uk/entities.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/lang/uk/entities.php b/resources/lang/uk/entities.php index 9c59fdb39..7f9417189 100644 --- a/resources/lang/uk/entities.php +++ b/resources/lang/uk/entities.php @@ -181,7 +181,7 @@ return [ 'pages_edit_draft' => 'Редагувати чернетку сторінки', 'pages_editing_draft' => 'Редагування чернетки', 'pages_editing_page' => 'Редагування сторінки', - 'pages_edit_draft_save_at' => 'Чернетку зберегти в ', + 'pages_edit_draft_save_at' => 'Чернетка збережена о ', 'pages_edit_delete_draft' => 'Видалити чернетку', 'pages_edit_discard_draft' => 'Відхилити чернетку', 'pages_edit_set_changelog' => 'Встановити журнал змін', @@ -275,10 +275,10 @@ return [ 'attachments_link_attached' => 'Посилання успішно додано до сторінки', 'templates' => 'Шаблони', 'templates_set_as_template' => 'Сторінка це шаблон', - 'templates_explain_set_as_template' => 'You can set this page as a template so its contents be utilized when creating other pages. Other users will be able to use this template if they have view permissions for this page.', + 'templates_explain_set_as_template' => 'Ви можете встановити цю сторінку як шаблон, щоб її вміст використовувався під час створення інших сторінок. Інші користувачі зможуть користуватися цим шаблоном, якщо вони мають права перегляду для цієї сторінки.', 'templates_replace_content' => 'Замінити вміст сторінки', 'templates_append_content' => 'Додати до вмісту сторінки', - 'templates_prepend_content' => 'Prepend to page content', + 'templates_prepend_content' => 'Додати на початок вмісту сторінки', // Profile View 'profile_user_for_x' => 'Користувач вже :time', From 3cb0742918c25f2d9ae61e34118c67e57b906454 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:39:59 +0000 Subject: [PATCH 106/191] New translations common.php (Ukrainian) --- resources/lang/uk/common.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/lang/uk/common.php b/resources/lang/uk/common.php index 651fb6d1a..214fbcb4e 100644 --- a/resources/lang/uk/common.php +++ b/resources/lang/uk/common.php @@ -38,6 +38,7 @@ return [ 'reset' => 'Скинути', 'remove' => 'Видалити', 'add' => 'Додати', + 'fullscreen' => 'Fullscreen', // Sort Options 'sort_options' => 'Параметри сортування', @@ -59,7 +60,7 @@ return [ 'grid_view' => 'Вигляд Сіткою', 'list_view' => 'Вигляд Списком', 'default' => 'За замовчуванням', - 'breadcrumb' => 'Breadcrumb', + 'breadcrumb' => 'Навігація', // Header 'profile_menu' => 'Меню профілю', From 303f4164f0842a2ea271547fe27704cc5b728337 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:00 +0000 Subject: [PATCH 107/191] New translations auth.php (Ukrainian) --- resources/lang/uk/auth.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/resources/lang/uk/auth.php b/resources/lang/uk/auth.php index 559c7be77..b8fcc06ad 100644 --- a/resources/lang/uk/auth.php +++ b/resources/lang/uk/auth.php @@ -12,25 +12,25 @@ return [ // Login & Register 'sign_up' => 'Реєстрація', 'log_in' => 'Увійти', - 'log_in_with' => 'Увійти з :socialDriver', - 'sign_up_with' => 'Зареєструватись з :socialDriver', + 'log_in_with' => 'Увійти через :socialDriver', + 'sign_up_with' => 'Зареєструватися через :socialDriver', 'logout' => 'Вихід', 'name' => 'Ім\'я', 'username' => 'Логін', - 'email' => 'Email', + 'email' => 'Адреса електронної пошти', 'password' => 'Пароль', 'password_confirm' => 'Підтвердження пароля', - 'password_hint' => 'Має бути більше 7 символів', + 'password_hint' => 'Має бути більше ніж 7 символів', 'forgot_password' => 'Забули пароль?', - 'remember_me' => 'Запам’ятати мене', + 'remember_me' => 'Запам\'ятати мене', 'ldap_email_hint' => 'Введіть email для цього облікового запису.', 'create_account' => 'Створити обліковий запис', 'already_have_account' => 'Вже є обліковий запис?', 'dont_have_account' => 'Немає облікового запису?', 'social_login' => 'Вхід через соціальну мережу', 'social_registration' => 'Реєстрація через соціальну мережу', - 'social_registration_text' => 'Реєстрація і вхід через інший сервіс', + 'social_registration_text' => 'Реєстрація і вхід через інший сервіс.', 'register_thanks' => 'Дякуємо за реєстрацію!', 'register_confirm' => 'Будь ласка, перевірте свою електронну пошту та натисніть кнопку підтвердження, щоб отримати доступ до :appName.', @@ -42,7 +42,7 @@ return [ // Password Reset 'reset_password' => 'Скинути пароль', 'reset_password_send_instructions' => 'Введіть адресу електронної пошти нижче, і вам буде надіслано електронне повідомлення з посиланням на зміну пароля.', - 'reset_password_send_button' => 'Надіслати посилання для скидання', + 'reset_password_send_button' => 'Надіслати посилання для скидання пароля', 'reset_password_sent_success' => 'Посилання для скидання пароля було надіслано на :email.', 'reset_password_success' => 'Ваш пароль успішно скинуто.', 'email_reset_subject' => 'Скинути ваш пароль :appName', @@ -59,7 +59,7 @@ return [ 'email_confirm_success' => 'Ваш електронну адресу підтверджено!', 'email_confirm_resent' => 'Лист з підтвердженням надіслано, перевірте свою пошту.', - 'email_not_confirmed' => 'Адреса Email не підтверджена', + 'email_not_confirmed' => 'Адресу електронної скриньки не підтверджено', 'email_not_confirmed_text' => 'Ваша електронна адреса ще не підтверджена.', 'email_not_confirmed_click_link' => 'Будь-ласка, натисніть на посилання в електронному листі, яке було надіслано після реєстрації.', 'email_not_confirmed_resend' => 'Якщо ви не можете знайти електронний лист, ви можете повторно надіслати підтвердження електронною поштою, на формі нижче.', From 026247be994ac9a298a13fe473c86f6a020c0d61 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:01 +0000 Subject: [PATCH 108/191] New translations activities.php (Ukrainian) --- resources/lang/uk/activities.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lang/uk/activities.php b/resources/lang/uk/activities.php index 2ed0d5560..900ccd2b8 100644 --- a/resources/lang/uk/activities.php +++ b/resources/lang/uk/activities.php @@ -36,7 +36,7 @@ return [ 'book_sort_notification' => 'Книгу успішно відновлено', // Bookshelves - 'bookshelf_create' => 'створено книжкову полицю', + 'bookshelf_create' => 'створив книжкову полицю', 'bookshelf_create_notification' => 'Книжкову полицю успішно створено', 'bookshelf_update' => 'оновив книжкову полицю', 'bookshelf_update_notification' => 'Книжкову полицю успішно оновлено', From 20ba63ce0e092df0171cc5b3e31840cac86693d6 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:03 +0000 Subject: [PATCH 109/191] New translations validation.php (Turkish) --- resources/lang/tr/validation.php | 42 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/resources/lang/tr/validation.php b/resources/lang/tr/validation.php index f0a12bc80..18328ce75 100644 --- a/resources/lang/tr/validation.php +++ b/resources/lang/tr/validation.php @@ -30,19 +30,19 @@ return [ 'digits' => ':attribute :digits basamaklı olmalıdır.', 'digits_between' => ':attribute :min ve :max basamaklı olmalıdır.', 'email' => ':attribute geçerli bir e-mail adresi olmalıdır.', - 'ends_with' => 'The :attribute must end with one of the following: :values', + 'ends_with' => ':attribute şunlardan biriyle bitmelidir: :values', 'filled' => ':attribute gerekli bir alandır.', 'gt' => [ - 'numeric' => 'The :attribute must be greater than :value.', - 'file' => 'The :attribute must be greater than :value kilobytes.', - 'string' => 'The :attribute must be greater than :value characters.', - 'array' => 'The :attribute must have more than :value items.', + 'numeric' => ':attribute :max değerinden büyük olmalı.', + 'file' => ':attribute değeri :value kilobayt değerinden büyük olmalıdır.', + 'string' => ':attribute değeri :value karakter değerinden büyük olmalıdır.', + 'array' => ':attribute, :value öğeden daha fazlasına sahip olamaz.', ], 'gte' => [ - 'numeric' => 'The :attribute must be greater than or equal :value.', - 'file' => 'The :attribute must be greater than or equal :value kilobytes.', - 'string' => 'The :attribute must be greater than or equal :value characters.', - 'array' => 'The :attribute must have :value items or more.', + 'numeric' => ':attribute, :value değerinden büyük veya eşit olmalı.', + 'file' => ':attribute, :value kilobayttan eşit ya da büyük olmalı.', + 'string' => ':attribute, :value kilobayttan eşit ya da büyük olmalı.', + 'array' => ':attribute, :value veya daha fazla maddeye sahip olmalıdır.', ], 'exists' => 'Seçilen :attribute geçerli bir alan değildir.', 'image' => ':attribute bir görsel olmalıdır.', @@ -50,20 +50,20 @@ return [ 'in' => 'Seçilen :attribute geçerli değildir.', 'integer' => ':attribute bir integer değeri olmalıdır.', 'ip' => ':attribute geçerli bir IP adresi olmalıdır.', - 'ipv4' => 'The :attribute must be a valid IPv4 address.', - 'ipv6' => 'The :attribute must be a valid IPv6 address.', - 'json' => 'The :attribute must be a valid JSON string.', + 'ipv4' => ': Özniteliği geçerli bir IPv4 adresi olmalıdır.', + 'ipv6' => ':attribute geçerli bir IPv6 adresi olmalıdır.', + 'json' => ':attribute geçerli bir JSON dizini olmalı.', 'lt' => [ - 'numeric' => 'The :attribute must be less than :value.', - 'file' => 'The :attribute must be less than :value kilobytes.', - 'string' => 'The :attribute must be less than :value characters.', - 'array' => 'The :attribute must have less than :value items.', + 'numeric' => ':attribute, :value değerinden küçük olmalıdır.', + 'file' => ':attribute, :value kilobayt boyutundan küçük olmalıdır.', + 'string' => ':attribute, :value karakterden küçük olmalıdır.', + 'array' => ':attribute, :value öğeden az olmalıdır.', ], 'lte' => [ - 'numeric' => 'The :attribute must be less than or equal :value.', - 'file' => 'The :attribute must be less than or equal :value kilobytes.', - 'string' => 'The :attribute must be less than or equal :value characters.', - 'array' => 'The :attribute must not have more than :value items.', + 'numeric' => ':attribute, :value değerinden küçük veya eşit olmalıdır.', + 'file' => ':attribute, :value kilobayttan küçük ya da eşit olmalıdır.', + 'string' => ':attribute, :value kilobayttan küçük ya da eşit olmalıdır.', + 'array' => ':attribute, :value öğeden daha fazlasına sahip olamaz.', ], 'max' => [ 'numeric' => ':attribute, :max değerinden büyük olmamalıdır.', @@ -80,7 +80,7 @@ return [ ], 'no_double_extension' => ':attribute sadece tek bir dosya tipinde olmalıdır.', 'not_in' => 'Seçili :attribute geçerli değildir.', - 'not_regex' => 'The :attribute format is invalid.', + 'not_regex' => ':attribute formatı geçerli değildir.', 'numeric' => ':attribute rakam olmalıdır.', 'regex' => ':attribute formatı geçerli değildir.', 'required' => 'The :attribute field is required. :attribute alanı gereklidir.', From 5800bd82fbb91af4b16fb437f23a3cd1ef774cea Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:04 +0000 Subject: [PATCH 110/191] New translations errors.php (Spanish, Argentina) --- resources/lang/es_AR/errors.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resources/lang/es_AR/errors.php b/resources/lang/es_AR/errors.php index fb3c5e913..5ad6aa8d9 100644 --- a/resources/lang/es_AR/errors.php +++ b/resources/lang/es_AR/errors.php @@ -17,6 +17,12 @@ return [ 'ldap_fail_authed' => 'El acceso LDAP usando el dn & password detallados', 'ldap_extension_not_installed' => 'La extensión LDAP PHP no se encuentra instalada', 'ldap_cannot_connect' => 'No se puede conectar con el servidor ldap, la conexión inicial ha fallado', + 'saml_already_logged_in' => 'Ya estás conectado', + 'saml_user_not_registered' => 'El usuario :name no está registrado y el registro automático está deshabilitado', + 'saml_no_email_address' => 'No se pudo encontrar una dirección de correo electrónico, para este usuario, en los datos proporcionados por el sistema de autenticación externo', + 'saml_invalid_response_id' => 'La solicitud del sistema de autenticación externo no está reconocida por un proceso iniciado por esta aplicación. Navegar hacia atrás después de un inicio de sesión podría causar este problema.', + 'saml_fail_authed' => 'El inicio de sesión con :system falló, el sistema no proporcionó una autorización correcta', + 'saml_email_exists' => 'Registro fallido porque un usuario ya existe con la dirección de correo electrónico ":email"', 'social_no_action_defined' => 'Acción no definida', 'social_login_bad_response' => "SE recibió un Error durante el acceso con :socialAccount : \n:error", 'social_account_in_use' => 'la cuenta :socialAccount ya se encuentra en uso, intente loguearse a través de la opcón :socialAccount .', From 96f1fd534a15e5cc414791f7c84dcb328f354fbb Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:05 +0000 Subject: [PATCH 111/191] New translations errors.php (Russian) --- resources/lang/ru/errors.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resources/lang/ru/errors.php b/resources/lang/ru/errors.php index 69c63b524..a812af677 100644 --- a/resources/lang/ru/errors.php +++ b/resources/lang/ru/errors.php @@ -17,6 +17,12 @@ return [ 'ldap_fail_authed' => 'Не удалось получить доступ к LDAP, используя данные dn & password', 'ldap_extension_not_installed' => 'LDAP расширения для PHP не установлено', 'ldap_cannot_connect' => 'Не удается подключиться к серверу ldap, не удалось выполнить начальное соединение', + 'saml_already_logged_in' => 'Already logged in', + 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', + 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', + 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', + 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', + 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => 'Действие не определено', 'social_login_bad_response' => "При попытке входа с :socialAccount произошла ошибка: \\n:error", 'social_account_in_use' => 'Этот :socialAccount аккаунт уже исопльзуется, попробуйте войти с параметрами :socialAccount.', From ce70738c934de9093e9e808aa66b757afa1c575c Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:07 +0000 Subject: [PATCH 112/191] New translations settings.php (Portuguese, Brazilian) --- resources/lang/pt_BR/settings.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/resources/lang/pt_BR/settings.php b/resources/lang/pt_BR/settings.php index 03283d752..f15b724c4 100644 --- a/resources/lang/pt_BR/settings.php +++ b/resources/lang/pt_BR/settings.php @@ -41,12 +41,22 @@ return [ 'app_disable_comments_toggle' => 'Desativar comentários', 'app_disable_comments_desc' => 'Desativar comentários em todas as páginas no aplicativo. Os comentários existentes não são exibidos.', + // Color settings + 'content_colors' => 'Content Colors', + 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'bookshelf_color' => 'Shelf Color', + 'book_color' => 'Book Color', + 'chapter_color' => 'Chapter Color', + 'page_color' => 'Page Color', + 'page_draft_color' => 'Page Draft Color', + // Registration Settings 'reg_settings' => 'Registro', 'reg_enable' => 'Habilitar Registro', 'reg_enable_toggle' => 'Habilitar registro', 'reg_enable_desc' => 'Quando o registro é habilitado, o usuário poderá se registrar como usuário do aplicativo. No registro, eles recebem um único perfil padrão.', 'reg_default_role' => 'Perfil padrão para usuários após o registro', + 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', 'reg_email_confirmation' => 'Confirmação de E-mail', 'reg_email_confirmation_toggle' => 'Requer confirmação de e-mail', 'reg_confirm_email_desc' => 'Se restrições de domínio são usadas a confirmação por e-mail será requerida e o valor abaixo será ignorado.', @@ -63,6 +73,13 @@ return [ 'maint_image_cleanup_warning' => ':count imagens potencialmente não utilizadas foram encontradas. Tem certeza de que deseja excluir estas imagens?', 'maint_image_cleanup_success' => ':count imagens potencialmente não utilizadas foram encontradas e excluídas!', 'maint_image_cleanup_nothing_found' => 'Nenhuma imagem não utilizada foi encontrada, nada foi excluído!', + 'maint_send_test_email' => 'Send a Test Email', + 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', + 'maint_send_test_email_run' => 'Send test email', + 'maint_send_test_email_success' => 'Email sent to :address', + 'maint_send_test_email_mail_subject' => 'Test Email', + 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', + 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', // Role Settings 'roles' => 'Perfis', From c163863b03de1c8e9658fb5103af2b370504a245 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:08 +0000 Subject: [PATCH 113/191] New translations passwords.php (Russian) --- resources/lang/ru/passwords.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/lang/ru/passwords.php b/resources/lang/ru/passwords.php index c3324e8de..5e7717803 100644 --- a/resources/lang/ru/passwords.php +++ b/resources/lang/ru/passwords.php @@ -7,9 +7,9 @@ return [ 'password' => 'Пароль должен содержать не менее шести символов и совпадать с подтверждением.', - 'user' => "Пользователь с указаным email отсутствует.", + 'user' => "Пользователя с таким адресом не существует.", 'token' => 'Токен сброса пароля недействителен.', - 'sent' => 'Ссылка для сброса пароля отправлена на email!', + 'sent' => 'Ссылка для сброса пароля отправлена на вашу почту!', 'reset' => 'Ваш пароль был сброшен!', ]; From f978ba303311bea2360058f6c8d2b77a508233ef Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:11 +0000 Subject: [PATCH 114/191] New translations entities.php (Russian) --- resources/lang/ru/entities.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/lang/ru/entities.php b/resources/lang/ru/entities.php index 475b454a0..e9fe6ba30 100644 --- a/resources/lang/ru/entities.php +++ b/resources/lang/ru/entities.php @@ -176,12 +176,12 @@ return [ 'pages_delete_confirm' => 'Вы действительно хотите удалить эту страницу?', 'pages_delete_draft_confirm' => 'Вы действительно хотите удалить этот черновик?', 'pages_editing_named' => 'Редактирование страницы :pageName', - 'pages_edit_draft_options' => 'Draft Options', + 'pages_edit_draft_options' => 'Параметры черновика', 'pages_edit_save_draft' => 'Сохранить черновик', 'pages_edit_draft' => 'Редактировать черновик', 'pages_editing_draft' => 'Редактирование черновика', 'pages_editing_page' => 'Редактирование страницы', - 'pages_edit_draft_save_at' => 'Черновик сохранить в ', + 'pages_edit_draft_save_at' => 'Черновик сохранён в ', 'pages_edit_delete_draft' => 'Удалить черновик', 'pages_edit_discard_draft' => 'отменить черновик', 'pages_edit_set_changelog' => 'Задать список изменений', From b44c27ba811806d035bf9a5b7b6f7bfad3d52250 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:13 +0000 Subject: [PATCH 115/191] New translations common.php (Russian) --- resources/lang/ru/common.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/lang/ru/common.php b/resources/lang/ru/common.php index 9ead2736a..cd6661d57 100644 --- a/resources/lang/ru/common.php +++ b/resources/lang/ru/common.php @@ -38,6 +38,7 @@ return [ 'reset' => 'Сбросить', 'remove' => 'Удалить', 'add' => 'Добавить', + 'fullscreen' => 'Fullscreen', // Sort Options 'sort_options' => 'Параметры сортировки', @@ -72,5 +73,5 @@ return [ // Email Content 'email_action_help' => 'Если у вас возникли проблемы с нажатием кнопки \':actionText\', то скопируйте и вставьте указанный URL-адрес в свой веб-браузер:', - 'email_rights' => 'Все права зарезервированы', + 'email_rights' => 'Все права защищены', ]; From eff87696bc601797e8a39675ed74d2647c33ad80 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:14 +0000 Subject: [PATCH 116/191] New translations auth.php (Russian) --- resources/lang/ru/auth.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/resources/lang/ru/auth.php b/resources/lang/ru/auth.php index e493ec197..490707c83 100644 --- a/resources/lang/ru/auth.php +++ b/resources/lang/ru/auth.php @@ -18,13 +18,13 @@ return [ 'name' => 'Имя', 'username' => 'Логин', - 'email' => 'Email', + 'email' => 'Адрес электронной почты', 'password' => 'Пароль', 'password_confirm' => 'Подтверждение пароля', 'password_hint' => 'Должен быть больше 7 символов', 'forgot_password' => 'Забыли пароль?', 'remember_me' => 'Запомнить меня', - 'ldap_email_hint' => 'Введите email адрес для данной учетной записи.', + 'ldap_email_hint' => 'Введите адрес электронной почты для этой учетной записи.', 'create_account' => 'Создать аккаунт', 'already_have_account' => 'Уже есть аккаунт?', 'dont_have_account' => 'У вас нет аккаунта?', @@ -53,13 +53,13 @@ return [ // Email Confirmation 'email_confirm_subject' => 'Подтвердите ваш почтовый адрес на :appName', 'email_confirm_greeting' => 'Благодарим за участие :appName!', - 'email_confirm_text' => 'Пожалуйста, подтвердите ваш email адрес кликнув на кнопку ниже:', - 'email_confirm_action' => 'Подтвердить email', + 'email_confirm_text' => 'Пожалуйста, подтвердите свой адрес электронной почты нажав на кнопку ниже:', + 'email_confirm_action' => 'Подтвердить адрес электронной почты', 'email_confirm_send_error' => 'Требуется подтверждение электронной почты, но система не может отправить письмо. Свяжитесь с администратором, чтобы убедиться, что адрес электронной почты настроен правильно.', - 'email_confirm_success' => 'Ваш email был подтвержден!', + 'email_confirm_success' => 'Ваш адрес подтвержден!', 'email_confirm_resent' => 'Письмо с подтверждение выслано снова. Пожалуйста, проверьте ваш почтовый ящик.', - 'email_not_confirmed' => 'email не подтвержден', + 'email_not_confirmed' => 'Адрес электронной почты не подтвержден', 'email_not_confirmed_text' => 'Ваш email адрес все еще не подтвержден.', 'email_not_confirmed_click_link' => 'Пожалуйста, нажмите на ссылку в письме, которое было отправлено при регистрации.', 'email_not_confirmed_resend' => 'Если вы не можете найти электронное письмо, вы можете снова отправить письмо с подтверждением по форме ниже.', From 971c0b1b8805b54a494b1c3bf94ae0a580bf7303 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:15 +0000 Subject: [PATCH 117/191] New translations activities.php (Russian) --- resources/lang/ru/activities.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/resources/lang/ru/activities.php b/resources/lang/ru/activities.php index 8be36b8bd..7c8efcacb 100644 --- a/resources/lang/ru/activities.php +++ b/resources/lang/ru/activities.php @@ -36,12 +36,12 @@ return [ 'book_sort_notification' => 'Книга успешно отсортирована', // Bookshelves - 'bookshelf_create' => 'created Bookshelf', - 'bookshelf_create_notification' => 'Bookshelf Successfully Created', - 'bookshelf_update' => 'updated bookshelf', - 'bookshelf_update_notification' => 'Bookshelf Successfully Updated', - 'bookshelf_delete' => 'deleted bookshelf', - 'bookshelf_delete_notification' => 'Bookshelf Successfully Deleted', + 'bookshelf_create' => 'создал книжную полку', + 'bookshelf_create_notification' => 'Книжная полка успешно создана', + 'bookshelf_update' => 'обновил книжную полку', + 'bookshelf_update_notification' => 'Книжная полка успешно обновлена', + 'bookshelf_delete' => 'удалил книжную полку', + 'bookshelf_delete_notification' => 'Книжная полка успешно удалена', // Other 'commented_on' => 'прокомментировал', From f85bf94c80f0cc839f095e0401bcbf95c1163ffb Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:17 +0000 Subject: [PATCH 118/191] New translations errors.php (Portuguese, Brazilian) --- resources/lang/pt_BR/errors.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resources/lang/pt_BR/errors.php b/resources/lang/pt_BR/errors.php index 150cb5911..fb254bc13 100644 --- a/resources/lang/pt_BR/errors.php +++ b/resources/lang/pt_BR/errors.php @@ -17,6 +17,12 @@ return [ 'ldap_fail_authed' => 'O acesso LDAP falhou ao tentar os detalhes do dn e senha fornecidos', 'ldap_extension_not_installed' => 'As extensões LDAP PHP não estão instaladas', 'ldap_cannot_connect' => 'Não foi possível conectar ao servidor LDAP. Conexão inicial falhou', + 'saml_already_logged_in' => 'Already logged in', + 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', + 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', + 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', + 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', + 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => 'Nenhuma ação definida', 'social_login_bad_response' => "Erro recebido durante o login :socialAccount: \n:error", 'social_account_in_use' => 'Essa conta :socialAccount já está em uso. Por favor, tente se logar usando a opção :socialAccount', From 312153befc9ce61a89de69576278142477113ff1 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:20 +0000 Subject: [PATCH 119/191] New translations common.php (Portuguese, Brazilian) --- resources/lang/pt_BR/common.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lang/pt_BR/common.php b/resources/lang/pt_BR/common.php index 03d9b1d8e..811446444 100644 --- a/resources/lang/pt_BR/common.php +++ b/resources/lang/pt_BR/common.php @@ -38,6 +38,7 @@ return [ 'reset' => 'Resetar', 'remove' => 'Remover', 'add' => 'Adicionar', + 'fullscreen' => 'Fullscreen', // Sort Options 'sort_options' => 'Sort Options', From f259bc2f154345c0b50b70f7ba07d868fc672e8c Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:22 +0000 Subject: [PATCH 120/191] New translations validation.php (Polish) --- resources/lang/pl/validation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lang/pl/validation.php b/resources/lang/pl/validation.php index bedffae41..249d20ca7 100644 --- a/resources/lang/pl/validation.php +++ b/resources/lang/pl/validation.php @@ -80,7 +80,7 @@ return [ ], 'no_double_extension' => ':attribute może mieć tylko jedno rozszerzenie.', 'not_in' => 'Wartość :attribute jest nieprawidłowa.', - 'not_regex' => 'The :attribute format is invalid.', + 'not_regex' => 'Format :attribute jest nieprawidłowy.', 'numeric' => ':attribute musi być liczbą.', 'regex' => 'Format :attribute jest nieprawidłowy.', 'required' => 'Pole :attribute jest wymagane.', From 420baa2f650ebd3c9fd81f83061bd1186ec9afcb Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:24 +0000 Subject: [PATCH 121/191] New translations settings.php (Polish) --- resources/lang/pl/settings.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/resources/lang/pl/settings.php b/resources/lang/pl/settings.php index 2117238cf..a9ec17cd9 100644 --- a/resources/lang/pl/settings.php +++ b/resources/lang/pl/settings.php @@ -38,15 +38,25 @@ return [ 'app_homepage_desc' => 'Wybierz widok, który będzie wyświetlany na stronie głównej zamiast w widoku domyślnego. Uprawnienia dostępowe są ignorowane dla wybranych stron.', 'app_homepage_select' => 'Wybierz stronę', 'app_disable_comments' => 'Wyłącz komentarze', - 'app_disable_comments_toggle' => 'Disable comments', + 'app_disable_comments_toggle' => 'Wyłącz komentowanie', 'app_disable_comments_desc' => 'Wyłącz komentarze na wszystkich stronach w aplikacji. Istniejące komentarze nie będą pokazywane.', + // Color settings + 'content_colors' => 'Kolory zawartości', + 'content_colors_desc' => 'Ustawia kolory dla wszystkich elementów w hierarchii organizacji stron. Wybór kolorów o podobnej jasności do domyślnych kolorów jest zalecany dla czytelności.', + 'bookshelf_color' => 'Kolor półki', + 'book_color' => 'Kolor książki', + 'chapter_color' => 'Kolor rozdziału', + 'page_color' => 'Kolor strony', + 'page_draft_color' => 'Kolor szkicu strony', + // Registration Settings 'reg_settings' => 'Ustawienia rejestracji', 'reg_enable' => 'Włącz rejestrację', 'reg_enable_toggle' => 'Włącz rejestrację', 'reg_enable_desc' => 'Kiedy rejestracja jest włączona użytkownicy mogą się rejestrować. Po rejestracji otrzymują jedną domyślną rolę użytkownika.', 'reg_default_role' => 'Domyślna rola użytkownika po rejestracji', + 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', 'reg_email_confirmation' => 'Potwierdzenie adresu email', 'reg_email_confirmation_toggle' => 'Wymagaj potwierdzenia adresu email', 'reg_confirm_email_desc' => 'Jeśli restrykcje domenowe zostały ustawione, potwierdzenie adresu stanie się konieczne, a poniższa wartośc zostanie zignorowana.', From 9798fa8ba7f8a37e896ce80fd7825d3241cb1aaf Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:25 +0000 Subject: [PATCH 122/191] New translations settings.php (Russian) --- resources/lang/ru/settings.php | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/resources/lang/ru/settings.php b/resources/lang/ru/settings.php index f268c7e4c..0dd3b97be 100755 --- a/resources/lang/ru/settings.php +++ b/resources/lang/ru/settings.php @@ -41,17 +41,27 @@ return [ 'app_disable_comments_toggle' => 'Отключить комментарии', 'app_disable_comments_desc' => 'Отключение комментов на всех страницах. Существующие комментарии отображаться не будут.', + // Color settings + 'content_colors' => 'Content Colors', + 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'bookshelf_color' => 'Shelf Color', + 'book_color' => 'Book Color', + 'chapter_color' => 'Chapter Color', + 'page_color' => 'Page Color', + 'page_draft_color' => 'Page Draft Color', + // Registration Settings 'reg_settings' => 'Настройки регистрации', 'reg_enable' => 'Разрешить регистрацию', 'reg_enable_toggle' => 'Разрешить регистрацию', 'reg_enable_desc' => 'Если регистрация разрешена, пользователь сможет зарегистрироваться в системе самостоятельно. При регистрации назначается роль пользователя по умолчанию', 'reg_default_role' => 'Роль пользователя по умолчанию после регистрации', - 'reg_email_confirmation' => 'Подтверждение электонной почты', + 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', + 'reg_email_confirmation' => 'Подтверждение электронной почты', 'reg_email_confirmation_toggle' => 'Требовать подтверждение по электронной почте', 'reg_confirm_email_desc' => 'При использовании ограничения по домену - подтверждение обязательно, этот пункт игнорируется.', 'reg_confirm_restrict_domain' => 'Ограничить регистрацию по домену', - 'reg_confirm_restrict_domain_desc' => 'Введите список доменов почты через запятую, для которых разрешена регистрация. Пользователям будет отправлено письмо для подтверждения адреса перед входом в приложение.
Обратите внимание, что пользователи смогут изменить свои адреса уже после регистрации.', + 'reg_confirm_restrict_domain_desc' => 'Введите список доменов почты через запятую, для которых разрешена регистрация. Пользователям будет отправлено письмо для подтверждения адреса перед входом в приложение.
Обратите внимание, что пользователи смогут изменять свой адрес после регистрации.', 'reg_confirm_restrict_domain_placeholder' => 'Без ограничений', // Maintenance settings @@ -63,6 +73,13 @@ return [ 'maint_image_cleanup_warning' => 'Найдено :count возможно бесполезных изображений. Вы уверены, что хотите удалить эти изображения?', 'maint_image_cleanup_success' => ':count возможно бесполезных изображений было найдено и удалено!', 'maint_image_cleanup_nothing_found' => 'Не найдено ни одного бесполезного изображения!', + 'maint_send_test_email' => 'Отправить тестовое письмо', + 'maint_send_test_email_desc' => 'Отправить тестовое письмо на адрес электронной почты, указанный в профиле.', + 'maint_send_test_email_run' => 'Отправить проверочное письмо', + 'maint_send_test_email_success' => 'На адрес :address отравлено письмо', + 'maint_send_test_email_mail_subject' => 'Проверка электронной почты', + 'maint_send_test_email_mail_greeting' => 'Доставка электронной почты работает!', + 'maint_send_test_email_mail_text' => 'Поздравляем! Поскольку вы получили это письмо, электронная почта настроена правильно.', // Role Settings 'roles' => 'Роли', @@ -104,14 +121,14 @@ return [ 'users_add_new' => 'Добавить пользователя', 'users_search' => 'Поиск пользователей', 'users_details' => 'Данные пользователя', - 'users_details_desc' => 'Задайте имя для этого пользователя, чтобы другие могли его узнать', + 'users_details_desc' => 'Укажите имя и адрес электронной почты для этого пользователя. Адрес электронной почты будет использоваться для входа в приложение.', 'users_details_desc_no_email' => 'Задайте имя для этого пользователя, чтобы другие могли его узнать', 'users_role' => 'Роли пользователя', 'users_role_desc' => 'Назначьте роли пользователю. Если назначено несколько ролей, разрешения будут суммироваться и пользователь получит все права назначенных ролей.', 'users_password' => 'Пароль пользователя', 'users_password_desc' => 'Установите пароль для входа в приложение. Должно быть не менее 6 символов.', 'users_send_invite_text' => 'Вы можете отправить этому пользователю email с приглашением, которое позволит ему установить пароль самостоятельно или задайте пароль сами.', - 'users_send_invite_option' => 'Отправить пользователю email с приглашением.', + 'users_send_invite_option' => 'Отправить пользователю письмо с приглашением', 'users_external_auth_id' => 'Внешний ID аутентификации', 'users_external_auth_id_desc' => 'Этот ID используется для связи с вашей LDAP системой.', 'users_password_warning' => 'Заполните ниже только если вы хотите сменить свой пароль.', From 8269f9911450451025516a98b9e31ed25c49003c Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:27 +0000 Subject: [PATCH 123/191] New translations common.php (Spanish, Argentina) --- resources/lang/es_AR/common.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lang/es_AR/common.php b/resources/lang/es_AR/common.php index 3d45ce6cb..b7201101c 100644 --- a/resources/lang/es_AR/common.php +++ b/resources/lang/es_AR/common.php @@ -38,6 +38,7 @@ return [ 'reset' => 'Restablecer', 'remove' => 'Remover', 'add' => 'Agregar', + 'fullscreen' => 'Pantalla completa', // Sort Options 'sort_options' => 'Opciones de Orden', From d7673c6a7b8187c91f586331aed542ee8790bac2 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:28 +0000 Subject: [PATCH 124/191] New translations common.php (Spanish) --- resources/lang/es/common.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lang/es/common.php b/resources/lang/es/common.php index a1c16cf95..45eff2d5f 100644 --- a/resources/lang/es/common.php +++ b/resources/lang/es/common.php @@ -38,6 +38,7 @@ return [ 'reset' => 'Resetear', 'remove' => 'Remover', 'add' => 'Añadir', + 'fullscreen' => 'Pantalla completa', // Sort Options 'sort_options' => 'Opciones de ordenación', From 2246b468bcbddf8aec1f30ef85bdab71a2b84905 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:30 +0000 Subject: [PATCH 125/191] New translations validation.php (Spanish) --- resources/lang/es/validation.php | 42 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/resources/lang/es/validation.php b/resources/lang/es/validation.php index c30e168fc..de6094a71 100644 --- a/resources/lang/es/validation.php +++ b/resources/lang/es/validation.php @@ -30,19 +30,19 @@ return [ 'digits' => ':attribute debe ser de :digits dígitos.', 'digits_between' => ':attribute debe ser un valor entre :min y :max dígios.', 'email' => ':attribute debe ser un correo electrónico válido.', - 'ends_with' => 'The :attribute must end with one of the following: :values', + 'ends_with' => 'El :attribute debe terminar con uno de los siguientes: :values', 'filled' => 'El campo :attribute es requerido.', 'gt' => [ - 'numeric' => 'The :attribute must be greater than :value.', - 'file' => 'The :attribute must be greater than :value kilobytes.', - 'string' => 'The :attribute must be greater than :value characters.', - 'array' => 'The :attribute must have more than :value items.', + 'numeric' => 'El :attribute debe ser mayor que :value.', + 'file' => 'El :attribute debe ser mayor que :value kilobytes.', + 'string' => 'El :attribute debe ser mayor que :value caracteres.', + 'array' => 'El :attribute debe tener más de :value elementos.', ], 'gte' => [ - 'numeric' => 'The :attribute must be greater than or equal :value.', - 'file' => 'The :attribute must be greater than or equal :value kilobytes.', - 'string' => 'The :attribute must be greater than or equal :value characters.', - 'array' => 'The :attribute must have :value items or more.', + 'numeric' => 'El :attribute debe ser mayor o igual que :value.', + 'file' => 'El :attribute debe ser mayor o igual que :value kilobytes.', + 'string' => 'El :attribute debe ser mayor o igual que :value caracteres.', + 'array' => 'El :attribute debe tener :value o más elementos.', ], 'exists' => 'El :attribute seleccionado es inválido.', 'image' => 'El :attribute debe ser una imagen.', @@ -50,20 +50,20 @@ return [ 'in' => 'El selected :attribute es inválio.', 'integer' => 'El :attribute debe ser un entero.', 'ip' => 'El :attribute debe ser una dirección IP válida.', - 'ipv4' => 'The :attribute must be a valid IPv4 address.', - 'ipv6' => 'The :attribute must be a valid IPv6 address.', - 'json' => 'The :attribute must be a valid JSON string.', + 'ipv4' => 'El :attribute debe ser una dirección IPv4 válida.', + 'ipv6' => 'El :attribute debe ser una dirección IPv6 válida.', + 'json' => 'El :attribute debe ser una cadena JSON válida.', 'lt' => [ - 'numeric' => 'The :attribute must be less than :value.', - 'file' => 'The :attribute must be less than :value kilobytes.', - 'string' => 'The :attribute must be less than :value characters.', - 'array' => 'The :attribute must have less than :value items.', + 'numeric' => 'El :attribute debe ser menor que :value.', + 'file' => 'El :attribute debe ser menor que :value kilobytes.', + 'string' => 'El :attribute debe ser menor que :value caracteres.', + 'array' => 'El :attribute debe tener menos de :value elementos.', ], 'lte' => [ - 'numeric' => 'The :attribute must be less than or equal :value.', - 'file' => 'The :attribute must be less than or equal :value kilobytes.', - 'string' => 'The :attribute must be less than or equal :value characters.', - 'array' => 'The :attribute must not have more than :value items.', + 'numeric' => 'El :attribute debe ser menor o igual que :value.', + 'file' => 'El :attribute debe ser menor o igual que :value kilobytes.', + 'string' => 'El :attribute debe ser menor o igual que :value caracteres.', + 'array' => 'El :attribute no debe tener más de :value elementos.', ], 'max' => [ 'numeric' => 'El :attribute no puede ser mayor que :max.', @@ -80,7 +80,7 @@ return [ ], 'no_double_extension' => 'El :attribute solo debe tener una extensión de archivo.', 'not_in' => 'El :attribute seleccionado es inválio.', - 'not_regex' => 'The :attribute format is invalid.', + 'not_regex' => 'El formato de :attribute es inválido.', 'numeric' => 'El :attribute debe ser numérico.', 'regex' => 'El formato de :attribute es inválido', 'required' => 'El :attribute es requerido.', From 0c446800a6362dc77f9d18313792a6e6a9994647 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:31 +0000 Subject: [PATCH 126/191] New translations settings.php (Spanish) --- resources/lang/es/settings.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/resources/lang/es/settings.php b/resources/lang/es/settings.php index f448bdd22..39faff2fd 100644 --- a/resources/lang/es/settings.php +++ b/resources/lang/es/settings.php @@ -41,12 +41,22 @@ return [ 'app_disable_comments_toggle' => 'Deshabilitar comentarios', 'app_disable_comments_desc' => 'Deshabilita los comentarios en todas las páginas de la aplicación.
Los comentarios existentes no se muestran.', + // Color settings + 'content_colors' => 'Colores del contenido', + 'content_colors_desc' => 'Establece los colores para todos los elementos en la jerarquía de la organización de la página. Se recomienda elegir colores con un brillo similar al predeterminado para mayor legibilidad.', + 'bookshelf_color' => 'Color del estante', + 'book_color' => 'Color del libro', + 'chapter_color' => 'Color del capítulo', + 'page_color' => 'Color de la página', + 'page_draft_color' => 'Color del borrador de página', + // Registration Settings 'reg_settings' => 'Registro', 'reg_enable' => 'Habilitar Registro', 'reg_enable_toggle' => 'Habilitar registro', 'reg_enable_desc' => 'Cuando se habilita el registro los usuarios podrán registrarse como usuarios de la aplicación. Al registrarse se les asigna un rol único por defecto.', 'reg_default_role' => 'Rol de usuario por defecto después del registro', + 'reg_enable_ldap_warning' => 'La opción anterior no se utiliza mientras la autenticación LDAP está activa. Las cuentas de usuario para los miembros no existentes se crearán automáticamente si la autenticación, contra el sistema LDAP en uso, es exitosa.', 'reg_email_confirmation' => 'Confirmación por Email', 'reg_email_confirmation_toggle' => 'Requerir confirmación por Email', 'reg_confirm_email_desc' => 'Si se emplea la restricción por dominio, entonces se requerirá la confirmación por correo electrónico y esta opción será ignorada.', @@ -63,6 +73,13 @@ return [ 'maint_image_cleanup_warning' => 'Se han encontrado :count imágenes posiblemente no utilizadas . ¿Estás seguro de querer borrar estas imágenes?', 'maint_image_cleanup_success' => '¡Se han encontrado y borrado :count imágenes posiblemente no utilizadas!', 'maint_image_cleanup_nothing_found' => '¡No se han encontrado imágenes sin utilizar, no se han borrado imágenes!', + 'maint_send_test_email' => 'Enviar un correo electrónico de prueba', + 'maint_send_test_email_desc' => 'Esto envía un correo electrónico de prueba a la dirección de correo electrónico especificada en tu perfil.', + 'maint_send_test_email_run' => 'Enviar correo electrónico de prueba', + 'maint_send_test_email_success' => 'Correo electrónico enviado a :address', + 'maint_send_test_email_mail_subject' => 'Probar correo electrónico', + 'maint_send_test_email_mail_greeting' => '¡El envío de correos electrónicos parece funcionar!', + 'maint_send_test_email_mail_text' => '¡Enhorabuena! Al recibir esta notificación de correo electrónico, tu configuración de correo electrónico parece estar ajustada correctamente.', // Role Settings 'roles' => 'Roles', From 0ec4ca033c28fc417e5a3431a143d852dddd8bc3 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:33 +0000 Subject: [PATCH 127/191] New translations errors.php (Spanish) --- resources/lang/es/errors.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/resources/lang/es/errors.php b/resources/lang/es/errors.php index 77d5520f4..8cc80e754 100644 --- a/resources/lang/es/errors.php +++ b/resources/lang/es/errors.php @@ -5,8 +5,8 @@ return [ // Permissions - 'permission' => 'No tiene permisos para visualizar la página solicitada.', - 'permissionJson' => 'No tiene permisos para ejecutar la acción solicitada.', + 'permission' => 'No tienes permisos para visualizar la página solicitada.', + 'permissionJson' => 'No tienes permisos para ejecutar la acción solicitada.', // Auth 'error_user_exists_different_creds' => 'Un usuario con el correo electrónico :email ya existe pero con credenciales diferentes.', @@ -17,6 +17,12 @@ return [ 'ldap_fail_authed' => 'El acceso LDAP ha fallado usando el dn & contraseña enviados', 'ldap_extension_not_installed' => 'La extensión LDAP PHP no se encuentra instalada', 'ldap_cannot_connect' => 'No se puede conectar con el servidor ldap, la conexión inicial ha fallado', + 'saml_already_logged_in' => 'Ya estás conectado', + 'saml_user_not_registered' => 'El usuario :name no está registrado y el registro automático está deshabilitado', + 'saml_no_email_address' => 'No se pudo encontrar una dirección de correo electrónico, para este usuario, en los datos proporcionados por el sistema de autenticación externo', + 'saml_invalid_response_id' => 'La solicitud del sistema de autenticación externo no está reconocida por un proceso iniciado por esta aplicación. Navegar hacia atrás después de un inicio de sesión podría causar este problema.', + 'saml_fail_authed' => 'El inicio de sesión con :system falló, el sistema no proporcionó una autorización correcta', + 'saml_email_exists' => 'Registro fallido porque un usuario ya existe con la dirección de correo electrónico ":email"', 'social_no_action_defined' => 'Acción no definida', 'social_login_bad_response' => "Se ha recibido un error durante el acceso con :socialAccount error: \n:error", 'social_account_in_use' => 'la cuenta :socialAccount ya se encuentra en uso, intente acceder a través de la opción :socialAccount .', From 4db8c1279acc01b030cf8452c2d151f8eabf1dac Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:35 +0000 Subject: [PATCH 128/191] New translations entities.php (Spanish) --- resources/lang/es/entities.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/resources/lang/es/entities.php b/resources/lang/es/entities.php index db87efda7..f67a0a3a3 100644 --- a/resources/lang/es/entities.php +++ b/resources/lang/es/entities.php @@ -18,10 +18,10 @@ return [ 'create_now' => 'Crear uno ahora', 'revisions' => 'Revisiones', 'meta_revision' => 'Revisión #:revisionCount', - 'meta_created' => 'Creado el :timeLength', - 'meta_created_name' => 'Creado el :timeLength por :user', - 'meta_updated' => 'Actualizado el :timeLength', - 'meta_updated_name' => 'Actualizado el :timeLength por :user', + 'meta_created' => 'Creado :timeLength', + 'meta_created_name' => 'Creado :timeLength por :user', + 'meta_updated' => 'Actualizado :timeLength', + 'meta_updated_name' => 'Actualizado :timeLength por :user', 'entity_select' => 'Seleccione entidad', 'images' => 'Imágenes', 'my_recent_drafts' => 'Mis borradores recientes', @@ -181,7 +181,7 @@ return [ 'pages_edit_draft' => 'Editar borrador de página', 'pages_editing_draft' => 'Editando borrador', 'pages_editing_page' => 'Editando página', - 'pages_edit_draft_save_at' => 'Borrador guardado el ', + 'pages_edit_draft_save_at' => 'Borrador guardado ', 'pages_edit_delete_draft' => 'Borrar borrador', 'pages_edit_discard_draft' => 'Descartar borrador', 'pages_edit_set_changelog' => 'Ajustar Log de cambios', From a8ebcfaef624bb5ac9b9c450f2a30efd6e8339b0 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:38 +0000 Subject: [PATCH 129/191] New translations settings.php (Slovak) --- resources/lang/sk/settings.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/resources/lang/sk/settings.php b/resources/lang/sk/settings.php index dc1e06bc5..c83d0fdb1 100644 --- a/resources/lang/sk/settings.php +++ b/resources/lang/sk/settings.php @@ -41,12 +41,22 @@ return [ 'app_disable_comments_toggle' => 'Disable comments', 'app_disable_comments_desc' => 'Zakázať komentáre na všetkých stránkach aplikácie. Existujúce komentáre sa nezobrazujú.', + // Color settings + 'content_colors' => 'Content Colors', + 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'bookshelf_color' => 'Shelf Color', + 'book_color' => 'Book Color', + 'chapter_color' => 'Chapter Color', + 'page_color' => 'Page Color', + 'page_draft_color' => 'Page Draft Color', + // Registration Settings 'reg_settings' => 'Nastavenia registrácie', 'reg_enable' => 'Enable Registration', 'reg_enable_toggle' => 'Enable registration', 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', 'reg_default_role' => 'Prednastavená používateľská rola po registrácii', + 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', 'reg_email_confirmation' => 'Email Confirmation', 'reg_email_confirmation_toggle' => 'Require email confirmation', 'reg_confirm_email_desc' => 'Ak je použité obmedzenie domény, potom bude vyžadované overenie emailu a hodnota nižšie bude ignorovaná.', @@ -63,6 +73,13 @@ return [ 'maint_image_cleanup_warning' => ':count potentially unused images were found. Are you sure you want to delete these images?', 'maint_image_cleanup_success' => ':count potentially unused images found and deleted!', 'maint_image_cleanup_nothing_found' => 'No unused images found, Nothing deleted!', + 'maint_send_test_email' => 'Send a Test Email', + 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', + 'maint_send_test_email_run' => 'Send test email', + 'maint_send_test_email_success' => 'Email sent to :address', + 'maint_send_test_email_mail_subject' => 'Test Email', + 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', + 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', // Role Settings 'roles' => 'Roly', From 426440d552e2c56e1eb363a87e959571fcb0b328 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:40 +0000 Subject: [PATCH 130/191] New translations errors.php (Slovak) --- resources/lang/sk/errors.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resources/lang/sk/errors.php b/resources/lang/sk/errors.php index 361711d9a..ab2ec88a2 100644 --- a/resources/lang/sk/errors.php +++ b/resources/lang/sk/errors.php @@ -17,6 +17,12 @@ return [ 'ldap_fail_authed' => 'LDAP access failed using given dn & password details', 'ldap_extension_not_installed' => 'LDAP PHP extension not installed', 'ldap_cannot_connect' => 'Cannot connect to ldap server, Initial connection failed', + 'saml_already_logged_in' => 'Already logged in', + 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', + 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', + 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', + 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', + 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => 'Nebola definovaná žiadna akcia', 'social_login_bad_response' => "Error received during :socialAccount login: \n:error", 'social_account_in_use' => 'Tento :socialAccount účet sa už používa, skúste sa prihlásiť pomocou možnosti :socialAccount.', From 77c2b2ef64eae65346b7e56c2408458bb53bee16 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:43 +0000 Subject: [PATCH 131/191] New translations common.php (Slovak) --- resources/lang/sk/common.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lang/sk/common.php b/resources/lang/sk/common.php index 1f915c71e..30faa9e77 100644 --- a/resources/lang/sk/common.php +++ b/resources/lang/sk/common.php @@ -38,6 +38,7 @@ return [ 'reset' => 'Reset', 'remove' => 'Odstrániť', 'add' => 'Add', + 'fullscreen' => 'Fullscreen', // Sort Options 'sort_options' => 'Sort Options', From 91081a0d72ec44c84a91cae86f171a9a73aff883 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 16:40:44 +0000 Subject: [PATCH 132/191] New translations validation.php (German Informal) --- resources/lang/de_informal/validation.php | 42 +++++++++++------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/resources/lang/de_informal/validation.php b/resources/lang/de_informal/validation.php index 1cf2176d5..b6105d192 100644 --- a/resources/lang/de_informal/validation.php +++ b/resources/lang/de_informal/validation.php @@ -30,19 +30,19 @@ return [ 'digits' => ':attribute muss :digits Stellen haben.', 'digits_between' => ':attribute muss zwischen :min und :max Stellen haben.', 'email' => ':attribute muss eine valide E-Mail-Adresse sein.', - 'ends_with' => 'The :attribute must end with one of the following: :values', + 'ends_with' => ':attribute muss mit einem der folgenden Werte: :values enden', 'filled' => ':attribute ist erforderlich.', 'gt' => [ - 'numeric' => 'The :attribute must be greater than :value.', - 'file' => 'The :attribute must be greater than :value kilobytes.', - 'string' => 'The :attribute must be greater than :value characters.', - 'array' => 'The :attribute must have more than :value items.', + 'numeric' => ':attribute muss größer als :value sein.', + 'file' => ':attribute muss mindestens :value Kilobytes groß sein.', + 'string' => ':attribute muss mehr als :value Zeichen haben.', + 'array' => ':attribute muss mindestens :value Elemente haben.', ], 'gte' => [ - 'numeric' => 'The :attribute must be greater than or equal :value.', - 'file' => 'The :attribute must be greater than or equal :value kilobytes.', - 'string' => 'The :attribute must be greater than or equal :value characters.', - 'array' => 'The :attribute must have :value items or more.', + 'numeric' => ':attribute muss größer-gleich :value sein.', + 'file' => ':attribute muss mindestens :value Kilobytes groß sein.', + 'string' => ':attribute muss mindestens :value Zeichen enthalten.', + 'array' => ':attribute muss :value Elemente oder mehr haben.', ], 'exists' => ':attribute ist ungültig.', 'image' => ':attribute muss ein Bild sein.', @@ -50,20 +50,20 @@ return [ 'in' => ':attribute ist ungültig.', 'integer' => ':attribute muss eine Zahl sein.', 'ip' => ':attribute muss eine valide IP-Adresse sein.', - 'ipv4' => 'The :attribute must be a valid IPv4 address.', - 'ipv6' => 'The :attribute must be a valid IPv6 address.', - 'json' => 'The :attribute must be a valid JSON string.', + 'ipv4' => ':attribute muss eine gültige IPv4 Adresse sein.', + 'ipv6' => ':attribute muss eine gültige IPv6-Adresse sein.', + 'json' => 'Das Attribut muss eine gültige JSON-Zeichenfolge sein.', 'lt' => [ - 'numeric' => 'The :attribute must be less than :value.', - 'file' => 'The :attribute must be less than :value kilobytes.', - 'string' => 'The :attribute must be less than :value characters.', - 'array' => 'The :attribute must have less than :value items.', + 'numeric' => ':attribute muss kleiner sein :value sein.', + 'file' => ':attribute muss kleiner als :value Kilobytes sein.', + 'string' => ':attribute muss weniger als :value Zeichen haben.', + 'array' => ':attribute muss weniger als :value Elemente haben.', ], 'lte' => [ - 'numeric' => 'The :attribute must be less than or equal :value.', - 'file' => 'The :attribute must be less than or equal :value kilobytes.', - 'string' => 'The :attribute must be less than or equal :value characters.', - 'array' => 'The :attribute must not have more than :value items.', + 'numeric' => ':attribute muss kleiner oder gleich :value sein.', + 'file' => ':attribute muss kleiner oder gleich :value Kilobytes sein.', + 'string' => ':attribute darf höchstens :value Zeichen besitzen.', + 'array' => ':attribute darf höchstens :value Elemente haben.', ], 'max' => [ 'numeric' => ':attribute darf nicht größer als :max sein.', @@ -80,7 +80,7 @@ return [ ], 'no_double_extension' => ':attribute darf nur eine gültige Dateiendung', 'not_in' => ':attribute ist ungültig.', - 'not_regex' => 'The :attribute format is invalid.', + 'not_regex' => ':attribute ist kein valides Format.', 'numeric' => ':attribute muss eine Zahl sein.', 'regex' => ':attribute ist in einem ungültigen Format.', 'required' => ':attribute ist erforderlich.', From cf743370a8ddf99ff6d03721197a2a8e1746432f Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 27 Dec 2019 17:14:34 +0000 Subject: [PATCH 133/191] Updated code block lang order and added extra pascal option - Fixed modal window sizing/positioning to be properly center and responsive. Related to #1730 --- resources/js/services/code.js | 5 +++-- resources/sass/_components.scss | 5 +++-- resources/views/components/code-editor.blade.php | 6 +++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/resources/js/services/code.js b/resources/js/services/code.js index 8e517dde4..26dee5bfb 100644 --- a/resources/js/services/code.js +++ b/resources/js/services/code.js @@ -25,7 +25,7 @@ import 'codemirror/mode/sql/sql'; import 'codemirror/mode/toml/toml'; import 'codemirror/mode/xml/xml'; import 'codemirror/mode/yaml/yaml'; -import 'codemirror/mode/pascal/pascal' +import 'codemirror/mode/pascal/pascal'; // Addons import 'codemirror/addon/scroll/scrollpastend'; @@ -62,6 +62,8 @@ const modeMap = { powershell: 'powershell', properties: 'properties', ocaml: 'mllike', + pascal: 'text/x-pascal', + pas: 'text/x-pascal', php: (content) => { return content.includes('JavaScript JSON Lua - PHP - Powershell MarkDown Nginx + Pascal + PHP + Powershell Python Ruby Shell/Bash SQL XML YAML - Pascal
From c055310507ba27154eaf71d70c7bc3082fb5fd1d Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 28 Dec 2019 13:01:42 +0000 Subject: [PATCH 134/191] Updated to latest laravel 6 version --- composer.json | 2 +- composer.lock | 859 +++++++++++++++++++++++++++----------------------- 2 files changed, 467 insertions(+), 394 deletions(-) diff --git a/composer.json b/composer.json index 98cfa1e2a..ccfffb569 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,7 @@ "fideloper/proxy": "^4.0", "gathercontent/htmldiff": "^0.2.1", "intervention/image": "^2.5", - "laravel/framework": "^6.0", + "laravel/framework": "^6.9", "laravel/socialite": "^4.2", "league/flysystem-aws-s3-v3": "^1.0", "onelogin/php-saml": "^3.3", diff --git a/composer.lock b/composer.lock index 346adb47c..b44554ac9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "140c7a04a20cef6d7ed8c1fc48257e66", + "content-hash": "e9b29fe5292928c55110f71cd2181afe", "packages": [ { "name": "aws/aws-sdk-php", - "version": "3.117.2", + "version": "3.130.2", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "3dc81df70f1cdf2842c85915548bffb870c1e1da" + "reference": "35289d9dd5184dd1106e49f99ef5074a84635b5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/3dc81df70f1cdf2842c85915548bffb870c1e1da", - "reference": "3dc81df70f1cdf2842c85915548bffb870c1e1da", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/35289d9dd5184dd1106e49f99ef5074a84635b5c", + "reference": "35289d9dd5184dd1106e49f99ef5074a84635b5c", "shasum": "" }, "require": { @@ -42,7 +42,8 @@ "nette/neon": "^2.3", "phpunit/phpunit": "^4.8.35|^5.4.3", "psr/cache": "^1.0", - "psr/simple-cache": "^1.0" + "psr/simple-cache": "^1.0", + "sebastian/comparator": "^1.2.3" }, "suggest": { "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", @@ -87,7 +88,7 @@ "s3", "sdk" ], - "time": "2019-11-15T19:21:02+00:00" + "time": "2019-12-23T19:12:28+00:00" }, { "name": "barryvdh/laravel-dompdf", @@ -259,16 +260,16 @@ }, { "name": "doctrine/cache", - "version": "1.9.1", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/doctrine/cache.git", - "reference": "89a5c76c39c292f7798f964ab3c836c3f8192a55" + "reference": "382e7f4db9a12dc6c19431743a2b096041bcdd62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/89a5c76c39c292f7798f964ab3c836c3f8192a55", - "reference": "89a5c76c39c292f7798f964ab3c836c3f8192a55", + "url": "https://api.github.com/repos/doctrine/cache/zipball/382e7f4db9a12dc6c19431743a2b096041bcdd62", + "reference": "382e7f4db9a12dc6c19431743a2b096041bcdd62", "shasum": "" }, "require": { @@ -335,10 +336,9 @@ "memcached", "php", "redis", - "riak", "xcache" ], - "time": "2019-11-15T14:31:57+00:00" + "time": "2019-11-29T15:36:20+00:00" }, { "name": "doctrine/dbal", @@ -759,16 +759,16 @@ }, { "name": "egulias/email-validator", - "version": "2.1.11", + "version": "2.1.12", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "92dd169c32f6f55ba570c309d83f5209cefb5e23" + "reference": "a6255605af39f2db7f5cb62e672bd8a7bad8d208" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/92dd169c32f6f55ba570c309d83f5209cefb5e23", - "reference": "92dd169c32f6f55ba570c309d83f5209cefb5e23", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/a6255605af39f2db7f5cb62e672bd8a7bad8d208", + "reference": "a6255605af39f2db7f5cb62e672bd8a7bad8d208", "shasum": "" }, "require": { @@ -813,7 +813,7 @@ "validation", "validator" ], - "time": "2019-08-13T17:33:27+00:00" + "time": "2019-12-20T12:49:39+00:00" }, { "name": "erusev/parsedown", @@ -863,16 +863,16 @@ }, { "name": "fideloper/proxy", - "version": "4.2.1", + "version": "4.2.2", "source": { "type": "git", "url": "https://github.com/fideloper/TrustedProxy.git", - "reference": "03085e58ec7bee24773fa5a8850751a6e61a7e8a" + "reference": "790194d5d3da89a713478875d2e2d05855a90a81" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fideloper/TrustedProxy/zipball/03085e58ec7bee24773fa5a8850751a6e61a7e8a", - "reference": "03085e58ec7bee24773fa5a8850751a6e61a7e8a", + "url": "https://api.github.com/repos/fideloper/TrustedProxy/zipball/790194d5d3da89a713478875d2e2d05855a90a81", + "reference": "790194d5d3da89a713478875d2e2d05855a90a81", "shasum": "" }, "require": { @@ -913,7 +913,7 @@ "proxy", "trusted proxy" ], - "time": "2019-09-03T16:45:42+00:00" + "time": "2019-12-20T13:11:11+00:00" }, { "name": "gathercontent/htmldiff", @@ -966,16 +966,16 @@ }, { "name": "guzzlehttp/guzzle", - "version": "6.4.1", + "version": "6.5.2", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "0895c932405407fd3a7368b6910c09a24d26db11" + "reference": "43ece0e75098b7ecd8d13918293029e555a50f82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/0895c932405407fd3a7368b6910c09a24d26db11", - "reference": "0895c932405407fd3a7368b6910c09a24d26db11", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/43ece0e75098b7ecd8d13918293029e555a50f82", + "reference": "43ece0e75098b7ecd8d13918293029e555a50f82", "shasum": "" }, "require": { @@ -990,12 +990,13 @@ "psr/log": "^1.1" }, "suggest": { + "ext-intl": "Required for Internationalized Domain Name (IDN) support", "psr/log": "Required for using the Log middleware" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "6.3-dev" + "dev-master": "6.5-dev" } }, "autoload": { @@ -1028,7 +1029,7 @@ "rest", "web service" ], - "time": "2019-10-23T15:58:00+00:00" + "time": "2019-12-23T11:57:10+00:00" }, { "name": "guzzlehttp/promises", @@ -1224,22 +1225,22 @@ }, { "name": "knplabs/knp-snappy", - "version": "v1.1.0", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/KnpLabs/snappy.git", - "reference": "ea037298d3c613454da77ecb9588cf0397d695e1" + "reference": "162633e3143f7f03b395e1dbd53df25e1e87d2f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/KnpLabs/snappy/zipball/ea037298d3c613454da77ecb9588cf0397d695e1", - "reference": "ea037298d3c613454da77ecb9588cf0397d695e1", + "url": "https://api.github.com/repos/KnpLabs/snappy/zipball/162633e3143f7f03b395e1dbd53df25e1e87d2f5", + "reference": "162633e3143f7f03b395e1dbd53df25e1e87d2f5", "shasum": "" }, "require": { "php": ">=7.1", "psr/log": "^1.0", - "symfony/process": "~3.4||~4.1" + "symfony/process": "~3.4||~4.3||~5.0" }, "require-dev": { "phpunit/phpunit": "~7.4" @@ -1286,20 +1287,20 @@ "thumbnail", "wkhtmltopdf" ], - "time": "2018-12-14T14:59:37+00:00" + "time": "2019-12-02T16:06:55+00:00" }, { "name": "laravel/framework", - "version": "v6.5.1", + "version": "v6.9.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "e47180500498cf8aa2a8ffb59a3b4daa007fa13d" + "reference": "60610be97ca389fa4b959d4d13fb3690970d9fb7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/e47180500498cf8aa2a8ffb59a3b4daa007fa13d", - "reference": "e47180500498cf8aa2a8ffb59a3b4daa007fa13d", + "url": "https://api.github.com/repos/laravel/framework/zipball/60610be97ca389fa4b959d4d13fb3690970d9fb7", + "reference": "60610be97ca389fa4b959d4d13fb3690970d9fb7", "shasum": "" }, "require": { @@ -1395,7 +1396,7 @@ "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (^1.0).", "moontoast/math": "Required to use ordered UUIDs (^1.1).", "pda/pheanstalk": "Required to use the beanstalk queue driver (^4.0).", - "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0)", + "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^4.0).", "symfony/cache": "Required to PSR-6 cache bridge (^4.3.4).", "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^1.2).", @@ -1432,20 +1433,20 @@ "framework", "laravel" ], - "time": "2019-11-12T15:20:18+00:00" + "time": "2019-12-19T18:16:22+00:00" }, { "name": "laravel/socialite", - "version": "v4.2.0", + "version": "v4.3.1", "source": { "type": "git", "url": "https://github.com/laravel/socialite.git", - "reference": "f509d06e1e7323997b804c5152874f8aad4508e9" + "reference": "2d670d5b100ef2dc72dc578126b2b97985791f52" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/socialite/zipball/f509d06e1e7323997b804c5152874f8aad4508e9", - "reference": "f509d06e1e7323997b804c5152874f8aad4508e9", + "url": "https://api.github.com/repos/laravel/socialite/zipball/2d670d5b100ef2dc72dc578126b2b97985791f52", + "reference": "2d670d5b100ef2dc72dc578126b2b97985791f52", "shasum": "" }, "require": { @@ -1496,20 +1497,20 @@ "laravel", "oauth" ], - "time": "2019-09-03T15:27:17+00:00" + "time": "2019-11-26T17:39:15+00:00" }, { "name": "league/flysystem", - "version": "1.0.57", + "version": "1.0.61", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "0e9db7f0b96b9f12dcf6f65bc34b72b1a30ea55a" + "reference": "4fb13c01784a6c9f165a351e996871488ca2d8c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/0e9db7f0b96b9f12dcf6f65bc34b72b1a30ea55a", - "reference": "0e9db7f0b96b9f12dcf6f65bc34b72b1a30ea55a", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/4fb13c01784a6c9f165a351e996871488ca2d8c9", + "reference": "4fb13c01784a6c9f165a351e996871488ca2d8c9", "shasum": "" }, "require": { @@ -1580,7 +1581,7 @@ "sftp", "storage" ], - "time": "2019-10-16T21:01:05+00:00" + "time": "2019-12-08T21:46:50+00:00" }, { "name": "league/flysystem-aws-s3-v3", @@ -1694,16 +1695,16 @@ }, { "name": "monolog/monolog", - "version": "2.0.1", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "f9d56fd2f5533322caccdfcddbb56aedd622ef1c" + "reference": "c861fcba2ca29404dc9e617eedd9eff4616986b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f9d56fd2f5533322caccdfcddbb56aedd622ef1c", - "reference": "f9d56fd2f5533322caccdfcddbb56aedd622ef1c", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c861fcba2ca29404dc9e617eedd9eff4616986b8", + "reference": "c861fcba2ca29404dc9e617eedd9eff4616986b8", "shasum": "" }, "require": { @@ -1771,7 +1772,7 @@ "logging", "psr-3" ], - "time": "2019-11-13T10:27:43+00:00" + "time": "2019-12-20T14:22:59+00:00" }, { "name": "mtdowling/jmespath.php", @@ -1830,22 +1831,22 @@ }, { "name": "nesbot/carbon", - "version": "2.26.0", + "version": "2.28.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "e01ecc0b71168febb52ae1fdc1cfcc95428e604e" + "reference": "e2bcbcd43e67ee6101d321d5de916251d2870ca8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/e01ecc0b71168febb52ae1fdc1cfcc95428e604e", - "reference": "e01ecc0b71168febb52ae1fdc1cfcc95428e604e", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/e2bcbcd43e67ee6101d321d5de916251d2870ca8", + "reference": "e2bcbcd43e67ee6101d321d5de916251d2870ca8", "shasum": "" }, "require": { "ext-json": "*", "php": "^7.1.8 || ^8.0", - "symfony/translation": "^3.4 || ^4.0" + "symfony/translation": "^3.4 || ^4.0 || ^5.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.14 || ^3.0", @@ -1860,6 +1861,9 @@ ], "type": "library", "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + }, "laravel": { "providers": [ "Carbon\\Laravel\\ServiceProvider" @@ -1893,20 +1897,20 @@ "datetime", "time" ], - "time": "2019-10-21T21:32:25+00:00" + "time": "2019-12-16T16:30:25+00:00" }, { "name": "onelogin/php-saml", - "version": "3.3.1", + "version": "3.4.1", "source": { "type": "git", "url": "https://github.com/onelogin/php-saml.git", - "reference": "bb34489635cd5c7eb1b42833e4c57ca1c786a81a" + "reference": "5fbf3486704ac9835b68184023ab54862c95f213" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/onelogin/php-saml/zipball/bb34489635cd5c7eb1b42833e4c57ca1c786a81a", - "reference": "bb34489635cd5c7eb1b42833e4c57ca1c786a81a", + "url": "https://api.github.com/repos/onelogin/php-saml/zipball/5fbf3486704ac9835b68184023ab54862c95f213", + "reference": "5fbf3486704ac9835b68184023ab54862c95f213", "shasum": "" }, "require": { @@ -1943,20 +1947,20 @@ "onelogin", "saml" ], - "time": "2019-11-06T16:59:38+00:00" + "time": "2019-11-25T17:30:07+00:00" }, { "name": "opis/closure", - "version": "3.4.1", + "version": "3.5.1", "source": { "type": "git", "url": "https://github.com/opis/closure.git", - "reference": "e79f851749c3caa836d7ccc01ede5828feb762c7" + "reference": "93ebc5712cdad8d5f489b500c59d122df2e53969" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opis/closure/zipball/e79f851749c3caa836d7ccc01ede5828feb762c7", - "reference": "e79f851749c3caa836d7ccc01ede5828feb762c7", + "url": "https://api.github.com/repos/opis/closure/zipball/93ebc5712cdad8d5f489b500c59d122df2e53969", + "reference": "93ebc5712cdad8d5f489b500c59d122df2e53969", "shasum": "" }, "require": { @@ -1969,7 +1973,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3.x-dev" + "dev-master": "3.5.x-dev" } }, "autoload": { @@ -2004,7 +2008,7 @@ "serialization", "serialize" ], - "time": "2019-10-19T18:38:51+00:00" + "time": "2019-11-29T22:36:02+00:00" }, { "name": "paragonie/random_compat", @@ -2130,33 +2134,34 @@ }, { "name": "phpoption/phpoption", - "version": "1.5.2", + "version": "1.7.2", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "2ba2586380f8d2b44ad1b9feb61c371020b27793" + "reference": "77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/2ba2586380f8d2b44ad1b9feb61c371020b27793", - "reference": "2ba2586380f8d2b44ad1b9feb61c371020b27793", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959", + "reference": "77f7c4d2e65413aff5b5a8cc8b3caf7a28d81959", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": "^5.5.9 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "^4.7|^5.0" + "bamarni/composer-bin-plugin": "^1.3", + "phpunit/phpunit": "^4.8.35 || ^5.0 || ^6.0 || ^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.5-dev" + "dev-master": "1.7-dev" } }, "autoload": { - "psr-0": { - "PhpOption\\": "src/" + "psr-4": { + "PhpOption\\": "src/PhpOption/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2167,6 +2172,10 @@ { "name": "Johannes M. Schmitt", "email": "schmittjoh@gmail.com" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com" } ], "description": "Option Type for PHP", @@ -2176,7 +2185,7 @@ "php", "type" ], - "time": "2019-11-06T22:27:00+00:00" + "time": "2019-12-15T19:35:24+00:00" }, { "name": "predis/predis", @@ -2464,44 +2473,46 @@ }, { "name": "ramsey/uuid", - "version": "3.8.0", + "version": "3.9.2", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "d09ea80159c1929d75b3f9c60504d613aeb4a1e3" + "reference": "7779489a47d443f845271badbdcedfe4df8e06fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/d09ea80159c1929d75b3f9c60504d613aeb4a1e3", - "reference": "d09ea80159c1929d75b3f9c60504d613aeb4a1e3", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/7779489a47d443f845271badbdcedfe4df8e06fb", + "reference": "7779489a47d443f845271badbdcedfe4df8e06fb", "shasum": "" }, "require": { - "paragonie/random_compat": "^1.0|^2.0|9.99.99", - "php": "^5.4 || ^7.0", + "ext-json": "*", + "paragonie/random_compat": "^1 | ^2 | 9.99.99", + "php": "^5.4 | ^7 | ^8", "symfony/polyfill-ctype": "^1.8" }, "replace": { "rhumsaa/uuid": "self.version" }, "require-dev": { - "codeception/aspect-mock": "^1.0 | ~2.0.0", - "doctrine/annotations": "~1.2.0", - "goaop/framework": "1.0.0-alpha.2 | ^1.0 | ~2.1.0", - "ircmaxell/random-lib": "^1.1", - "jakub-onderka/php-parallel-lint": "^0.9.0", - "mockery/mockery": "^0.9.9", + "codeception/aspect-mock": "^1 | ^2", + "doctrine/annotations": "^1.2", + "goaop/framework": "1.0.0-alpha.2 | ^1 | ^2.1", + "jakub-onderka/php-parallel-lint": "^1", + "mockery/mockery": "^0.9.11 | ^1", "moontoast/math": "^1.1", - "php-mock/php-mock-phpunit": "^0.3|^1.1", - "phpunit/phpunit": "^4.7|^5.0|^6.5", - "squizlabs/php_codesniffer": "^2.3" + "paragonie/random-lib": "^2", + "php-mock/php-mock-phpunit": "^0.3 | ^1.1", + "phpunit/phpunit": "^4.8 | ^5.4 | ^6.5", + "squizlabs/php_codesniffer": "^3.5" }, "suggest": { "ext-ctype": "Provides support for PHP Ctype functions", "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", + "ext-openssl": "Provides the OpenSSL extension for use with the OpenSslGenerator", "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", - "ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter", "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).", + "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid", "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." }, @@ -2514,13 +2525,21 @@ "autoload": { "psr-4": { "Ramsey\\Uuid\\": "src/" - } + }, + "files": [ + "src/functions.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + }, { "name": "Marijn Huizendveld", "email": "marijn.huizendveld@gmail.com" @@ -2528,11 +2547,6 @@ { "name": "Thibaud Fabre", "email": "thibaud@aztech.io" - }, - { - "name": "Ben Ramsey", - "email": "ben@benramsey.com", - "homepage": "https://benramsey.com" } ], "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", @@ -2542,7 +2556,7 @@ "identifier", "uuid" ], - "time": "2018-07-19T23:38:55+00:00" + "time": "2019-12-17T08:18:51+00:00" }, { "name": "robrichards/xmlseclibs", @@ -2970,27 +2984,28 @@ }, { "name": "symfony/console", - "version": "v4.3.8", + "version": "v4.4.2", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "831424efae0a1fe6642784bd52aae14ece6538e6" + "reference": "82437719dab1e6bdd28726af14cb345c2ec816d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/831424efae0a1fe6642784bd52aae14ece6538e6", - "reference": "831424efae0a1fe6642784bd52aae14ece6538e6", + "url": "https://api.github.com/repos/symfony/console/zipball/82437719dab1e6bdd28726af14cb345c2ec816d0", + "reference": "82437719dab1e6bdd28726af14cb345c2ec816d0", "shasum": "" }, "require": { "php": "^7.1.3", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php73": "^1.8", - "symfony/service-contracts": "^1.1" + "symfony/service-contracts": "^1.1|^2" }, "conflict": { "symfony/dependency-injection": "<3.4", - "symfony/event-dispatcher": "<4.3", + "symfony/event-dispatcher": "<4.3|>=5", + "symfony/lock": "<4.4", "symfony/process": "<3.3" }, "provide": { @@ -2998,12 +3013,12 @@ }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~3.4|~4.0", - "symfony/dependency-injection": "~3.4|~4.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", "symfony/event-dispatcher": "^4.3", - "symfony/lock": "~3.4|~4.0", - "symfony/process": "~3.4|~4.0", - "symfony/var-dumper": "^4.3" + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^4.3|^5.0" }, "suggest": { "psr/log": "For using the console logger", @@ -3014,7 +3029,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3041,20 +3056,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2019-11-13T07:29:07+00:00" + "time": "2019-12-17T10:32:23+00:00" }, { "name": "symfony/css-selector", - "version": "v4.3.8", + "version": "v4.4.2", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "f4b3ff6a549d9ed28b2b0ecd1781bf67cf220ee9" + "reference": "64acec7e0d67125e9f4656c68d4a38a42ab5a0b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/f4b3ff6a549d9ed28b2b0ecd1781bf67cf220ee9", - "reference": "f4b3ff6a549d9ed28b2b0ecd1781bf67cf220ee9", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/64acec7e0d67125e9f4656c68d4a38a42ab5a0b7", + "reference": "64acec7e0d67125e9f4656c68d4a38a42ab5a0b7", "shasum": "" }, "require": { @@ -3063,7 +3078,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3094,20 +3109,20 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2019-10-02T08:36:26+00:00" + "time": "2019-10-12T00:35:04+00:00" }, { "name": "symfony/debug", - "version": "v4.3.8", + "version": "v4.4.2", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "5ea9c3e01989a86ceaa0283f21234b12deadf5e2" + "reference": "5c4c1db977dc70bb3250e1308d3e8c6341aa38f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/5ea9c3e01989a86ceaa0283f21234b12deadf5e2", - "reference": "5ea9c3e01989a86ceaa0283f21234b12deadf5e2", + "url": "https://api.github.com/repos/symfony/debug/zipball/5c4c1db977dc70bb3250e1308d3e8c6341aa38f5", + "reference": "5c4c1db977dc70bb3250e1308d3e8c6341aa38f5", "shasum": "" }, "require": { @@ -3118,12 +3133,12 @@ "symfony/http-kernel": "<3.4" }, "require-dev": { - "symfony/http-kernel": "~3.4|~4.0" + "symfony/http-kernel": "^3.4|^4.0|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3150,20 +3165,76 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2019-10-28T17:07:32+00:00" + "time": "2019-12-16T14:46:54+00:00" }, { - "name": "symfony/event-dispatcher", - "version": "v4.3.8", + "name": "symfony/error-handler", + "version": "v4.4.2", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "0df002fd4f500392eabd243c2947061a50937287" + "url": "https://github.com/symfony/error-handler.git", + "reference": "6d7d7712a6ff5215ec26215672293b154f1db8c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/0df002fd4f500392eabd243c2947061a50937287", - "reference": "0df002fd4f500392eabd243c2947061a50937287", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/6d7d7712a6ff5215ec26215672293b154f1db8c1", + "reference": "6d7d7712a6ff5215ec26215672293b154f1db8c1", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "psr/log": "~1.0", + "symfony/debug": "^4.4", + "symfony/var-dumper": "^4.4|^5.0" + }, + "require-dev": { + "symfony/http-kernel": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony ErrorHandler Component", + "homepage": "https://symfony.com", + "time": "2019-12-16T14:46:54+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v4.4.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "b3c3068a72623287550fe20b84a2b01dcba2686f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b3c3068a72623287550fe20b84a2b01dcba2686f", + "reference": "b3c3068a72623287550fe20b84a2b01dcba2686f", "shasum": "" }, "require": { @@ -3179,12 +3250,12 @@ }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~3.4|~4.0", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/expression-language": "~3.4|~4.0", - "symfony/http-foundation": "^3.4|^4.0", - "symfony/service-contracts": "^1.1", - "symfony/stopwatch": "~3.4|~4.0" + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/dependency-injection": "", @@ -3193,7 +3264,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3220,7 +3291,7 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2019-11-03T09:04:05+00:00" + "time": "2019-11-28T13:33:56+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -3282,16 +3353,16 @@ }, { "name": "symfony/finder", - "version": "v4.3.8", + "version": "v4.4.2", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "72a068f77e317ae77c0a0495236ad292cfb5ce6f" + "reference": "ce8743441da64c41e2a667b8eb66070444ed911e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/72a068f77e317ae77c0a0495236ad292cfb5ce6f", - "reference": "72a068f77e317ae77c0a0495236ad292cfb5ce6f", + "url": "https://api.github.com/repos/symfony/finder/zipball/ce8743441da64c41e2a667b8eb66070444ed911e", + "reference": "ce8743441da64c41e2a667b8eb66070444ed911e", "shasum": "" }, "require": { @@ -3300,7 +3371,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3327,35 +3398,35 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2019-10-30T12:53:54+00:00" + "time": "2019-11-17T21:56:56+00:00" }, { "name": "symfony/http-foundation", - "version": "v4.3.8", + "version": "v4.4.2", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "cabe67275034e173350e158f3b1803d023880227" + "reference": "fcae1cff5b57b2a9c3aabefeb1527678705ddb62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/cabe67275034e173350e158f3b1803d023880227", - "reference": "cabe67275034e173350e158f3b1803d023880227", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/fcae1cff5b57b2a9c3aabefeb1527678705ddb62", + "reference": "fcae1cff5b57b2a9c3aabefeb1527678705ddb62", "shasum": "" }, "require": { "php": "^7.1.3", - "symfony/mime": "^4.3", + "symfony/mime": "^4.3|^5.0", "symfony/polyfill-mbstring": "~1.1" }, "require-dev": { "predis/predis": "~1.0", - "symfony/expression-language": "~3.4|~4.0" + "symfony/expression-language": "^3.4|^4.0|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3382,37 +3453,37 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2019-11-12T13:07:20+00:00" + "time": "2019-12-19T15:57:49+00:00" }, { "name": "symfony/http-kernel", - "version": "v4.3.8", + "version": "v4.4.2", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "5fdf186f26f9080de531d3f1d024348b2f0ab12f" + "reference": "fe310d2e95cd4c356836c8ecb0895a46d97fede2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/5fdf186f26f9080de531d3f1d024348b2f0ab12f", - "reference": "5fdf186f26f9080de531d3f1d024348b2f0ab12f", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/fe310d2e95cd4c356836c8ecb0895a46d97fede2", + "reference": "fe310d2e95cd4c356836c8ecb0895a46d97fede2", "shasum": "" }, "require": { "php": "^7.1.3", "psr/log": "~1.0", - "symfony/debug": "~3.4|~4.0", - "symfony/event-dispatcher": "^4.3", - "symfony/http-foundation": "^4.1.1", - "symfony/polyfill-ctype": "~1.8", + "symfony/error-handler": "^4.4", + "symfony/event-dispatcher": "^4.4", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-php73": "^1.9" }, "conflict": { "symfony/browser-kit": "<4.3", "symfony/config": "<3.4", + "symfony/console": ">=5", "symfony/dependency-injection": "<4.3", "symfony/translation": "<4.2", - "symfony/var-dumper": "<4.1.1", "twig/twig": "<1.34|<2.4,>=2" }, "provide": { @@ -3420,34 +3491,32 @@ }, "require-dev": { "psr/cache": "~1.0", - "symfony/browser-kit": "^4.3", - "symfony/config": "~3.4|~4.0", - "symfony/console": "~3.4|~4.0", - "symfony/css-selector": "~3.4|~4.0", - "symfony/dependency-injection": "^4.3", - "symfony/dom-crawler": "~3.4|~4.0", - "symfony/expression-language": "~3.4|~4.0", - "symfony/finder": "~3.4|~4.0", - "symfony/process": "~3.4|~4.0", - "symfony/routing": "~3.4|~4.0", - "symfony/stopwatch": "~3.4|~4.0", - "symfony/templating": "~3.4|~4.0", - "symfony/translation": "~4.2", - "symfony/translation-contracts": "^1.1", - "symfony/var-dumper": "^4.1.1", - "twig/twig": "^1.34|^2.4" + "symfony/browser-kit": "^4.3|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^4.3|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.2|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "twig/twig": "^1.34|^2.4|^3.0" }, "suggest": { "symfony/browser-kit": "", "symfony/config": "", "symfony/console": "", - "symfony/dependency-injection": "", - "symfony/var-dumper": "" + "symfony/dependency-injection": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3474,20 +3543,20 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", - "time": "2019-11-13T09:07:28+00:00" + "time": "2019-12-19T16:23:40+00:00" }, { "name": "symfony/mime", - "version": "v4.3.8", + "version": "v4.4.2", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "22aecf6b11638ef378fab25d6c5a2da8a31a1448" + "reference": "010cc488e56cafe5f7494dea70aea93100c234df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/22aecf6b11638ef378fab25d6c5a2da8a31a1448", - "reference": "22aecf6b11638ef378fab25d6c5a2da8a31a1448", + "url": "https://api.github.com/repos/symfony/mime/zipball/010cc488e56cafe5f7494dea70aea93100c234df", + "reference": "010cc488e56cafe5f7494dea70aea93100c234df", "shasum": "" }, "require": { @@ -3495,14 +3564,17 @@ "symfony/polyfill-intl-idn": "^1.10", "symfony/polyfill-mbstring": "^1.0" }, + "conflict": { + "symfony/mailer": "<4.4" + }, "require-dev": { "egulias/email-validator": "^2.1.10", - "symfony/dependency-injection": "~3.4|^4.1" + "symfony/dependency-injection": "^3.4|^4.1|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3533,20 +3605,20 @@ "mime", "mime-type" ], - "time": "2019-11-12T13:10:02+00:00" + "time": "2019-11-30T08:27:26+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.12.0", + "version": "v1.13.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "550ebaac289296ce228a706d0867afc34687e3f4" + "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4", - "reference": "550ebaac289296ce228a706d0867afc34687e3f4", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", + "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", "shasum": "" }, "require": { @@ -3558,7 +3630,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.12-dev" + "dev-master": "1.13-dev" } }, "autoload": { @@ -3591,20 +3663,20 @@ "polyfill", "portable" ], - "time": "2019-08-06T08:03:45+00:00" + "time": "2019-11-27T13:56:44+00:00" }, { "name": "symfony/polyfill-iconv", - "version": "v1.12.0", + "version": "v1.13.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-iconv.git", - "reference": "685968b11e61a347c18bf25db32effa478be610f" + "reference": "a019efccc03f1a335af6b4f20c30f5ea8060be36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/685968b11e61a347c18bf25db32effa478be610f", - "reference": "685968b11e61a347c18bf25db32effa478be610f", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/a019efccc03f1a335af6b4f20c30f5ea8060be36", + "reference": "a019efccc03f1a335af6b4f20c30f5ea8060be36", "shasum": "" }, "require": { @@ -3616,7 +3688,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.12-dev" + "dev-master": "1.13-dev" } }, "autoload": { @@ -3650,20 +3722,20 @@ "portable", "shim" ], - "time": "2019-08-06T08:03:45+00:00" + "time": "2019-11-27T13:56:44+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.12.0", + "version": "v1.13.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "6af626ae6fa37d396dc90a399c0ff08e5cfc45b2" + "reference": "6f9c239e61e1b0c9229a28ff89a812dc449c3d46" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/6af626ae6fa37d396dc90a399c0ff08e5cfc45b2", - "reference": "6af626ae6fa37d396dc90a399c0ff08e5cfc45b2", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/6f9c239e61e1b0c9229a28ff89a812dc449c3d46", + "reference": "6f9c239e61e1b0c9229a28ff89a812dc449c3d46", "shasum": "" }, "require": { @@ -3677,7 +3749,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.12-dev" + "dev-master": "1.13-dev" } }, "autoload": { @@ -3712,20 +3784,20 @@ "portable", "shim" ], - "time": "2019-08-06T08:03:45+00:00" + "time": "2019-11-27T13:56:44+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.12.0", + "version": "v1.13.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17" + "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/b42a2f66e8f1b15ccf25652c3424265923eb4f17", - "reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7b4aab9743c30be783b73de055d24a39cf4b954f", + "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f", "shasum": "" }, "require": { @@ -3737,7 +3809,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.12-dev" + "dev-master": "1.13-dev" } }, "autoload": { @@ -3771,20 +3843,20 @@ "portable", "shim" ], - "time": "2019-08-06T08:03:45+00:00" + "time": "2019-11-27T14:18:11+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.12.0", + "version": "v1.13.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "04ce3335667451138df4307d6a9b61565560199e" + "reference": "66fea50f6cb37a35eea048d75a7d99a45b586038" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/04ce3335667451138df4307d6a9b61565560199e", - "reference": "04ce3335667451138df4307d6a9b61565560199e", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/66fea50f6cb37a35eea048d75a7d99a45b586038", + "reference": "66fea50f6cb37a35eea048d75a7d99a45b586038", "shasum": "" }, "require": { @@ -3793,7 +3865,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.12-dev" + "dev-master": "1.13-dev" } }, "autoload": { @@ -3826,20 +3898,20 @@ "portable", "shim" ], - "time": "2019-08-06T08:03:45+00:00" + "time": "2019-11-27T13:56:44+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.12.0", + "version": "v1.13.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "2ceb49eaccb9352bff54d22570276bb75ba4a188" + "reference": "4b0e2222c55a25b4541305a053013d5647d3a25f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/2ceb49eaccb9352bff54d22570276bb75ba4a188", - "reference": "2ceb49eaccb9352bff54d22570276bb75ba4a188", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/4b0e2222c55a25b4541305a053013d5647d3a25f", + "reference": "4b0e2222c55a25b4541305a053013d5647d3a25f", "shasum": "" }, "require": { @@ -3848,7 +3920,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.12-dev" + "dev-master": "1.13-dev" } }, "autoload": { @@ -3884,20 +3956,20 @@ "portable", "shim" ], - "time": "2019-08-06T08:03:45+00:00" + "time": "2019-11-27T16:25:15+00:00" }, { "name": "symfony/process", - "version": "v4.3.8", + "version": "v4.4.2", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "3b2e0cb029afbb0395034509291f21191d1a4db0" + "reference": "b84501ad50adb72a94fb460a5b5c91f693e99c9b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/3b2e0cb029afbb0395034509291f21191d1a4db0", - "reference": "3b2e0cb029afbb0395034509291f21191d1a4db0", + "url": "https://api.github.com/repos/symfony/process/zipball/b84501ad50adb72a94fb460a5b5c91f693e99c9b", + "reference": "b84501ad50adb72a94fb460a5b5c91f693e99c9b", "shasum": "" }, "require": { @@ -3906,7 +3978,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -3933,20 +4005,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2019-10-28T17:07:32+00:00" + "time": "2019-12-06T10:06:46+00:00" }, { "name": "symfony/routing", - "version": "v4.3.8", + "version": "v4.4.2", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "533fd12a41fb9ce8d4e861693365427849487c0e" + "reference": "628bcafae1b2043969378dcfbf9c196539a38722" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/533fd12a41fb9ce8d4e861693365427849487c0e", - "reference": "533fd12a41fb9ce8d4e861693365427849487c0e", + "url": "https://api.github.com/repos/symfony/routing/zipball/628bcafae1b2043969378dcfbf9c196539a38722", + "reference": "628bcafae1b2043969378dcfbf9c196539a38722", "shasum": "" }, "require": { @@ -3960,11 +4032,11 @@ "require-dev": { "doctrine/annotations": "~1.2", "psr/log": "~1.0", - "symfony/config": "~4.2", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/expression-language": "~3.4|~4.0", - "symfony/http-foundation": "~3.4|~4.0", - "symfony/yaml": "~3.4|~4.0" + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { "doctrine/annotations": "For using the annotation loader", @@ -3976,7 +4048,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4009,7 +4081,7 @@ "uri", "url" ], - "time": "2019-11-04T20:23:03+00:00" + "time": "2019-12-12T12:53:52+00:00" }, { "name": "symfony/service-contracts", @@ -4071,26 +4143,27 @@ }, { "name": "symfony/translation", - "version": "v4.3.8", + "version": "v4.4.2", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "bbce239b35b0cd47bd75848b23e969f17dd970e7" + "reference": "f7669f48a9633bf8139bc026c755e894b7206677" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/bbce239b35b0cd47bd75848b23e969f17dd970e7", - "reference": "bbce239b35b0cd47bd75848b23e969f17dd970e7", + "url": "https://api.github.com/repos/symfony/translation/zipball/f7669f48a9633bf8139bc026c755e894b7206677", + "reference": "f7669f48a9633bf8139bc026c755e894b7206677", "shasum": "" }, "require": { "php": "^7.1.3", "symfony/polyfill-mbstring": "~1.0", - "symfony/translation-contracts": "^1.1.6" + "symfony/translation-contracts": "^1.1.6|^2" }, "conflict": { "symfony/config": "<3.4", "symfony/dependency-injection": "<3.4", + "symfony/http-kernel": "<4.4", "symfony/yaml": "<3.4" }, "provide": { @@ -4098,15 +4171,14 @@ }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~3.4|~4.0", - "symfony/console": "~3.4|~4.0", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/finder": "~2.8|~3.0|~4.0", - "symfony/http-kernel": "~3.4|~4.0", - "symfony/intl": "~3.4|~4.0", - "symfony/service-contracts": "^1.1.2", - "symfony/var-dumper": "~3.4|~4.0", - "symfony/yaml": "~3.4|~4.0" + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/finder": "~2.8|~3.0|~4.0|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/intl": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1.2|^2", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { "psr/log-implementation": "To use logging capability in translator", @@ -4116,7 +4188,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4143,7 +4215,7 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2019-11-06T23:21:49+00:00" + "time": "2019-12-12T12:53:52+00:00" }, { "name": "symfony/translation-contracts", @@ -4204,16 +4276,16 @@ }, { "name": "symfony/var-dumper", - "version": "v4.3.8", + "version": "v4.4.2", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "ea4940845535c85ff5c505e13b3205b0076d07bf" + "reference": "be330f919bdb395d1e0c3f2bfb8948512d6bdd99" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/ea4940845535c85ff5c505e13b3205b0076d07bf", - "reference": "ea4940845535c85ff5c505e13b3205b0076d07bf", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/be330f919bdb395d1e0c3f2bfb8948512d6bdd99", + "reference": "be330f919bdb395d1e0c3f2bfb8948512d6bdd99", "shasum": "" }, "require": { @@ -4227,9 +4299,9 @@ }, "require-dev": { "ext-iconv": "*", - "symfony/console": "~3.4|~4.0", - "symfony/process": "~3.4|~4.0", - "twig/twig": "~1.34|~2.4" + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.34|^2.4|^3.0" }, "suggest": { "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", @@ -4242,7 +4314,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -4276,7 +4348,7 @@ "debug", "dump" ], - "time": "2019-10-13T12:02:04+00:00" + "time": "2019-12-18T13:41:29+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -4456,16 +4528,16 @@ }, { "name": "barryvdh/laravel-ide-helper", - "version": "v2.6.5", + "version": "v2.6.6", "source": { "type": "git", "url": "https://github.com/barryvdh/laravel-ide-helper.git", - "reference": "8740a9a158d3dd5cfc706a9d4cc1bf7a518f99f3" + "reference": "b91b959364d97af658f268c733c75dccdbff197e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/8740a9a158d3dd5cfc706a9d4cc1bf7a518f99f3", - "reference": "8740a9a158d3dd5cfc706a9d4cc1bf7a518f99f3", + "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/b91b959364d97af658f268c733c75dccdbff197e", + "reference": "b91b959364d97af658f268c733c75dccdbff197e", "shasum": "" }, "require": { @@ -4523,7 +4595,7 @@ "phpstorm", "sublime" ], - "time": "2019-09-08T09:56:38+00:00" + "time": "2019-10-30T20:53:27+00:00" }, { "name": "barryvdh/reflection-docblock", @@ -4576,16 +4648,16 @@ }, { "name": "composer/ca-bundle", - "version": "1.2.4", + "version": "1.2.5", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "10bb96592168a0f8e8f6dcde3532d9fa50b0b527" + "reference": "62e8fc2dc550e5d6d8c9360c7721662670f58149" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/10bb96592168a0f8e8f6dcde3532d9fa50b0b527", - "reference": "10bb96592168a0f8e8f6dcde3532d9fa50b0b527", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/62e8fc2dc550e5d6d8c9360c7721662670f58149", + "reference": "62e8fc2dc550e5d6d8c9360c7721662670f58149", "shasum": "" }, "require": { @@ -4596,7 +4668,7 @@ "require-dev": { "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8", "psr/log": "^1.0", - "symfony/process": "^2.5 || ^3.0 || ^4.0" + "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0" }, "type": "library", "extra": { @@ -4628,7 +4700,7 @@ "ssl", "tls" ], - "time": "2019-08-30T08:44:50+00:00" + "time": "2019-12-11T14:44:42+00:00" }, { "name": "composer/composer", @@ -4934,16 +5006,16 @@ }, { "name": "facade/flare-client-php", - "version": "1.1.2", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/facade/flare-client-php.git", - "reference": "04c0bbd1881942f59e27877bac3b29ba57519666" + "reference": "24444ea0e1556f0a4b5fc8e61802caf72ae9a408" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/flare-client-php/zipball/04c0bbd1881942f59e27877bac3b29ba57519666", - "reference": "04c0bbd1881942f59e27877bac3b29ba57519666", + "url": "https://api.github.com/repos/facade/flare-client-php/zipball/24444ea0e1556f0a4b5fc8e61802caf72ae9a408", + "reference": "24444ea0e1556f0a4b5fc8e61802caf72ae9a408", "shasum": "" }, "require": { @@ -4951,7 +5023,7 @@ "illuminate/pipeline": "~5.5|~5.6|~5.7|~5.8|^6.0", "php": "^7.1", "symfony/http-foundation": "~3.3|~4.1", - "symfony/var-dumper": "^3.4|^4.0" + "symfony/var-dumper": "^3.4|^4.0|^5.0" }, "require-dev": { "larapack/dd": "^1.1", @@ -4984,26 +5056,26 @@ "flare", "reporting" ], - "time": "2019-11-08T11:11:17+00:00" + "time": "2019-12-15T18:28:38+00:00" }, { "name": "facade/ignition", - "version": "1.12.0", + "version": "1.13.0", "source": { "type": "git", "url": "https://github.com/facade/ignition.git", - "reference": "67736a01597b9e08f00a1fc8966b92b918dba5ea" + "reference": "1d2103aefecc9c4e6975bcc77fc5eceb330adb33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/ignition/zipball/67736a01597b9e08f00a1fc8966b92b918dba5ea", - "reference": "67736a01597b9e08f00a1fc8966b92b918dba5ea", + "url": "https://api.github.com/repos/facade/ignition/zipball/1d2103aefecc9c4e6975bcc77fc5eceb330adb33", + "reference": "1d2103aefecc9c4e6975bcc77fc5eceb330adb33", "shasum": "" }, "require": { "ext-json": "*", "ext-mbstring": "*", - "facade/flare-client-php": "^1.1", + "facade/flare-client-php": "^1.3", "facade/ignition-contracts": "^1.0", "filp/whoops": "^2.4", "illuminate/support": "~5.5.0 || ~5.6.0 || ~5.7.0 || ~5.8.0 || ^6.0", @@ -5055,7 +5127,7 @@ "laravel", "page" ], - "time": "2019-11-14T10:51:35+00:00" + "time": "2019-11-27T11:17:18+00:00" }, { "name": "facade/ignition-contracts", @@ -5103,16 +5175,16 @@ }, { "name": "filp/whoops", - "version": "2.5.0", + "version": "2.6.0", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "cde50e6720a39fdacb240159d3eea6865d51fd96" + "reference": "ecbc8f3ed2cafca3cfca3d5febaae5a9d2899508" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/cde50e6720a39fdacb240159d3eea6865d51fd96", - "reference": "cde50e6720a39fdacb240159d3eea6865d51fd96", + "url": "https://api.github.com/repos/filp/whoops/zipball/ecbc8f3ed2cafca3cfca3d5febaae5a9d2899508", + "reference": "ecbc8f3ed2cafca3cfca3d5febaae5a9d2899508", "shasum": "" }, "require": { @@ -5121,8 +5193,8 @@ }, "require-dev": { "mockery/mockery": "^0.9 || ^1.0", - "phpunit/phpunit": "^4.8.35 || ^5.7", - "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0", + "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0 || ^5.0" }, "suggest": { "symfony/var-dumper": "Pretty print complex values better with var-dumper available", @@ -5131,7 +5203,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2-dev" + "dev-master": "2.5-dev" } }, "autoload": { @@ -5146,8 +5218,8 @@ "authors": [ { "name": "Filipe Dobreira", - "role": "Developer", - "homepage": "https://github.com/filp" + "homepage": "https://github.com/filp", + "role": "Developer" } ], "description": "php error handling for cool kids", @@ -5160,20 +5232,20 @@ "throwable", "whoops" ], - "time": "2019-08-07T09:00:00+00:00" + "time": "2019-12-25T10:00:00+00:00" }, { "name": "fzaninotto/faker", - "version": "v1.9.0", + "version": "v1.9.1", "source": { "type": "git", "url": "https://github.com/fzaninotto/Faker.git", - "reference": "27a216cbe72327b2d6369fab721a5843be71e57d" + "reference": "fc10d778e4b84d5bd315dad194661e091d307c6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/27a216cbe72327b2d6369fab721a5843be71e57d", - "reference": "27a216cbe72327b2d6369fab721a5843be71e57d", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/fc10d778e4b84d5bd315dad194661e091d307c6f", + "reference": "fc10d778e4b84d5bd315dad194661e091d307c6f", "shasum": "" }, "require": { @@ -5186,7 +5258,9 @@ }, "type": "library", "extra": { - "branch-alias": [] + "branch-alias": { + "dev-master": "1.9-dev" + } }, "autoload": { "psr-4": { @@ -5208,7 +5282,7 @@ "faker", "fixtures" ], - "time": "2019-11-14T13:13:06+00:00" + "time": "2019-12-12T13:22:17+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -5536,16 +5610,16 @@ }, { "name": "mockery/mockery", - "version": "1.2.4", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/mockery/mockery.git", - "reference": "b3453f75fd23d9fd41685f2148f4abeacabc6405" + "reference": "f69bbde7d7a75d6b2862d9ca8fab1cd28014b4be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/b3453f75fd23d9fd41685f2148f4abeacabc6405", - "reference": "b3453f75fd23d9fd41685f2148f4abeacabc6405", + "url": "https://api.github.com/repos/mockery/mockery/zipball/f69bbde7d7a75d6b2862d9ca8fab1cd28014b4be", + "reference": "f69bbde7d7a75d6b2862d9ca8fab1cd28014b4be", "shasum": "" }, "require": { @@ -5559,7 +5633,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "1.3.x-dev" } }, "autoload": { @@ -5597,20 +5671,20 @@ "test double", "testing" ], - "time": "2019-09-30T08:30:27+00:00" + "time": "2019-12-26T09:49:15+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.9.3", + "version": "1.9.4", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea" + "reference": "579bb7356d91f9456ccd505f24ca8b667966a0a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/007c053ae6f31bba39dfa19a7726f56e9763bbea", - "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/579bb7356d91f9456ccd505f24ca8b667966a0a7", + "reference": "579bb7356d91f9456ccd505f24ca8b667966a0a7", "shasum": "" }, "require": { @@ -5645,7 +5719,7 @@ "object", "object graph" ], - "time": "2019-08-09T12:45:53+00:00" + "time": "2019-12-15T19:12:40+00:00" }, { "name": "nunomaduro/collision", @@ -5867,16 +5941,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.3.2", + "version": "4.3.3", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e" + "reference": "2ecaa9fef01634c83bfa8dc1fe35fb5cef223a62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/b83ff7cfcfee7827e1e78b637a5904fe6a96698e", - "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/2ecaa9fef01634c83bfa8dc1fe35fb5cef223a62", + "reference": "2ecaa9fef01634c83bfa8dc1fe35fb5cef223a62", "shasum": "" }, "require": { @@ -5914,7 +5988,7 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2019-09-12T14:27:41+00:00" + "time": "2019-12-20T13:40:23+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -6014,33 +6088,33 @@ }, { "name": "phpspec/prophecy", - "version": "1.9.0", + "version": "1.10.1", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203" + "reference": "cbe1df668b3fe136bcc909126a0f529a78d4cbbc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/f6811d96d97bdf400077a0cc100ae56aa32b9203", - "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/cbe1df668b3fe136bcc909126a0f529a78d4cbbc", + "reference": "cbe1df668b3fe136bcc909126a0f529a78d4cbbc", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", - "sebastian/comparator": "^1.1|^2.0|^3.0", + "sebastian/comparator": "^1.2.3|^2.0|^3.0", "sebastian/recursion-context": "^1.0|^2.0|^3.0" }, "require-dev": { - "phpspec/phpspec": "^2.5|^3.2", + "phpspec/phpspec": "^2.5 || ^3.2", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8.x-dev" + "dev-master": "1.10.x-dev" } }, "autoload": { @@ -6073,20 +6147,20 @@ "spy", "stub" ], - "time": "2019-10-03T11:07:50+00:00" + "time": "2019-12-22T21:05:45+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "7.0.8", + "version": "7.0.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "aa0d179a13284c7420fc281fc32750e6cc7c9e2f" + "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/aa0d179a13284c7420fc281fc32750e6cc7c9e2f", - "reference": "aa0d179a13284c7420fc281fc32750e6cc7c9e2f", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f1884187926fbb755a9aaf0b3836ad3165b478bf", + "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf", "shasum": "" }, "require": { @@ -6136,7 +6210,7 @@ "testing", "xunit" ], - "time": "2019-09-17T06:24:36+00:00" + "time": "2019-11-20T13:55:58+00:00" }, { "name": "phpunit/php-file-iterator", @@ -6329,16 +6403,16 @@ }, { "name": "phpunit/phpunit", - "version": "8.4.3", + "version": "8.5.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "67f9e35bffc0dd52d55d565ddbe4230454fd6a4e" + "reference": "7870c78da3c5e4883eaef36ae47853ebb3cb86f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/67f9e35bffc0dd52d55d565ddbe4230454fd6a4e", - "reference": "67f9e35bffc0dd52d55d565ddbe4230454fd6a4e", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7870c78da3c5e4883eaef36ae47853ebb3cb86f2", + "reference": "7870c78da3c5e4883eaef36ae47853ebb3cb86f2", "shasum": "" }, "require": { @@ -6382,7 +6456,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "8.4-dev" + "dev-master": "8.5-dev" } }, "autoload": { @@ -6408,20 +6482,20 @@ "testing", "xunit" ], - "time": "2019-11-06T09:42:23+00:00" + "time": "2019-12-25T14:49:39+00:00" }, { "name": "scrivo/highlight.php", - "version": "v9.15.10.0", + "version": "v9.17.1.0", "source": { "type": "git", "url": "https://github.com/scrivo/highlight.php.git", - "reference": "9ad3adb4456dc91196327498dbbce6aa1ba1239e" + "reference": "5451a9ad6d638559cf2a092880f935c39776134e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scrivo/highlight.php/zipball/9ad3adb4456dc91196327498dbbce6aa1ba1239e", - "reference": "9ad3adb4456dc91196327498dbbce6aa1ba1239e", + "url": "https://api.github.com/repos/scrivo/highlight.php/zipball/5451a9ad6d638559cf2a092880f935c39776134e", + "reference": "5451a9ad6d638559cf2a092880f935c39776134e", "shasum": "" }, "require": { @@ -6431,7 +6505,8 @@ }, "require-dev": { "phpunit/phpunit": "^4.8|^5.7", - "symfony/finder": "^2.8" + "symfony/finder": "^3.4", + "symfony/var-dumper": "^3.4" }, "suggest": { "ext-dom": "Needed to make use of the features in the utilities namespace" @@ -6453,18 +6528,18 @@ "authors": [ { "name": "Geert Bergman", - "role": "Project Author", - "homepage": "http://www.scrivo.org/" + "homepage": "http://www.scrivo.org/", + "role": "Project Author" }, { "name": "Vladimir Jimenez", - "role": "Contributor", - "homepage": "https://allejo.io" + "homepage": "https://allejo.io", + "role": "Maintainer" }, { "name": "Martin Folkers", - "role": "Contributor", - "homepage": "https://twobrain.io" + "homepage": "https://twobrain.io", + "role": "Contributor" } ], "description": "Server side syntax highlighter that supports 185 languages. It's a PHP port of highlight.js", @@ -6475,7 +6550,7 @@ "highlight.php", "syntax" ], - "time": "2019-08-27T04:27:48+00:00" + "time": "2019-12-13T21:54:06+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -6644,16 +6719,16 @@ }, { "name": "sebastian/environment", - "version": "4.2.2", + "version": "4.2.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404" + "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/f2a2c8e1c97c11ace607a7a667d73d47c19fe404", - "reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/464c90d7bdf5ad4e8a6aea15c091fec0603d4368", + "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368", "shasum": "" }, "require": { @@ -6693,7 +6768,7 @@ "environment", "hhvm" ], - "time": "2019-05-05T09:05:15+00:00" + "time": "2019-11-20T08:46:58+00:00" }, { "name": "sebastian/exporter", @@ -7226,16 +7301,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.5.2", + "version": "3.5.3", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "65b12cdeaaa6cd276d4c3033a95b9b88b12701e7" + "reference": "557a1fc7ac702c66b0bbfe16ab3d55839ef724cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/65b12cdeaaa6cd276d4c3033a95b9b88b12701e7", - "reference": "65b12cdeaaa6cd276d4c3033a95b9b88b12701e7", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/557a1fc7ac702c66b0bbfe16ab3d55839ef724cb", + "reference": "557a1fc7ac702c66b0bbfe16ab3d55839ef724cb", "shasum": "" }, "require": { @@ -7273,20 +7348,20 @@ "phpcs", "standards" ], - "time": "2019-10-28T04:36:32+00:00" + "time": "2019-12-04T04:46:47+00:00" }, { "name": "symfony/dom-crawler", - "version": "v4.3.8", + "version": "v4.4.2", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "4b9efd5708c3a38593e19b6a33e40867f4f89d72" + "reference": "36bbcab9369fc2f583220890efd43bf262d563fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/4b9efd5708c3a38593e19b6a33e40867f4f89d72", - "reference": "4b9efd5708c3a38593e19b6a33e40867f4f89d72", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/36bbcab9369fc2f583220890efd43bf262d563fd", + "reference": "36bbcab9369fc2f583220890efd43bf262d563fd", "shasum": "" }, "require": { @@ -7299,7 +7374,7 @@ }, "require-dev": { "masterminds/html5": "^2.6", - "symfony/css-selector": "~3.4|~4.0" + "symfony/css-selector": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/css-selector": "" @@ -7307,7 +7382,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -7334,20 +7409,20 @@ ], "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", - "time": "2019-10-28T17:07:32+00:00" + "time": "2019-10-29T11:38:30+00:00" }, { "name": "symfony/filesystem", - "version": "v4.3.8", + "version": "v4.4.2", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "9abbb7ef96a51f4d7e69627bc6f63307994e4263" + "reference": "40c2606131d56eff6f193b6e2ceb92414653b591" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/9abbb7ef96a51f4d7e69627bc6f63307994e4263", - "reference": "9abbb7ef96a51f4d7e69627bc6f63307994e4263", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/40c2606131d56eff6f193b6e2ceb92414653b591", + "reference": "40c2606131d56eff6f193b6e2ceb92414653b591", "shasum": "" }, "require": { @@ -7357,7 +7432,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "4.4-dev" } }, "autoload": { @@ -7384,7 +7459,7 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2019-08-20T14:07:54+00:00" + "time": "2019-11-26T23:16:41+00:00" }, { "name": "theseer/fdomdocument", @@ -7468,31 +7543,29 @@ }, { "name": "webmozart/assert", - "version": "1.5.0", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4" + "reference": "573381c0a64f155a0d9a23f4b0c797194805b925" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/88e6d84706d09a236046d686bbea96f07b3a34f4", - "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4", + "url": "https://api.github.com/repos/webmozart/assert/zipball/573381c0a64f155a0d9a23f4b0c797194805b925", + "reference": "573381c0a64f155a0d9a23f4b0c797194805b925", "shasum": "" }, "require": { "php": "^5.3.3 || ^7.0", "symfony/polyfill-ctype": "^1.8" }, + "conflict": { + "vimeo/psalm": "<3.6.0" + }, "require-dev": { "phpunit/phpunit": "^4.8.36 || ^7.5.13" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, "autoload": { "psr-4": { "Webmozart\\Assert\\": "src/" @@ -7514,7 +7587,7 @@ "check", "validate" ], - "time": "2019-08-24T08:43:50+00:00" + "time": "2019-11-24T13:36:37+00:00" }, { "name": "wnx/laravel-stats", From 04137e7c98cfe182f3c603e7d1acbc9a0ed524e7 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 28 Dec 2019 14:58:07 +0000 Subject: [PATCH 135/191] Started core API route work --- .env.example.complete | 3 + app/Api/ListingResponseBuilder.php | 82 +++++++++++++++++++ app/Config/api.php | 20 +++++ app/Http/Controllers/Api/ApiController.php | 20 +++++ .../Controllers/Api/BooksApiController.php | 18 ++++ app/Http/Kernel.php | 1 - app/Providers/RouteServiceProvider.php | 4 +- routes/api.php | 12 +++ 8 files changed, 157 insertions(+), 3 deletions(-) create mode 100644 app/Api/ListingResponseBuilder.php create mode 100644 app/Config/api.php create mode 100644 app/Http/Controllers/Api/ApiController.php create mode 100644 app/Http/Controllers/Api/BooksApiController.php create mode 100644 routes/api.php diff --git a/.env.example.complete b/.env.example.complete index a13c8b7d0..716d614a3 100644 --- a/.env.example.complete +++ b/.env.example.complete @@ -258,3 +258,6 @@ ALLOW_CONTENT_SCRIPTS=false # Contents of the robots.txt file can be overridden, making this option obsolete. ALLOW_ROBOTS=null +# The default and maximum item-counts for listing API requests. +API_DEFAULT_ITEM_COUNT=100 +API_MAX_ITEM_COUNT=500 \ No newline at end of file diff --git a/app/Api/ListingResponseBuilder.php b/app/Api/ListingResponseBuilder.php new file mode 100644 index 000000000..279fabd5d --- /dev/null +++ b/app/Api/ListingResponseBuilder.php @@ -0,0 +1,82 @@ +query = $query; + $this->fields = $fields; + } + + /** + * Get the response from this builder. + */ + public function toResponse() + { + $total = $this->query->count(); + $data = $this->fetchData(); + + return response()->json([ + 'data' => $data, + 'total' => $total, + ]); + } + + /** + * Fetch the data to return in the response. + */ + protected function fetchData(): Collection + { + $this->applyCountAndOffset($this->query); + $this->applySorting($this->query); + // TODO - Apply filtering + + return $this->query->get($this->fields); + } + + /** + * Apply sorting operations to the query from given parameters + * otherwise falling back to the first given field, ascending. + */ + protected function applySorting(Builder $query) + { + $defaultSortName = $this->fields[0]; + $direction = 'asc'; + + $sort = request()->get('sort', ''); + if (strpos($sort, '-') === 0) { + $direction = 'desc'; + } + + $sortName = ltrim($sort, '+- '); + if (!in_array($sortName, $this->fields)) { + $sortName = $defaultSortName; + } + + $query->orderBy($sortName, $direction); + } + + /** + * Apply count and offset for paging, based on params from the request while falling + * back to system defined default, taking the max limit into account. + */ + protected function applyCountAndOffset(Builder $query) + { + $offset = max(0, request()->get('offset', 0)); + $maxCount = config('api.max_item_count'); + $count = request()->get('count', config('api.default_item_count')); + $count = max(min($maxCount, $count), 1); + + $query->skip($offset)->take($count); + } +} diff --git a/app/Config/api.php b/app/Config/api.php new file mode 100644 index 000000000..dd54b2906 --- /dev/null +++ b/app/Config/api.php @@ -0,0 +1,20 @@ + env('API_DEFAULT_ITEM_COUNT', 100), + + // The maximum number of items that can be returned in a listing API request. + 'max_item_count' => env('API_MAX_ITEM_COUNT', 500), + +]; diff --git a/app/Http/Controllers/Api/ApiController.php b/app/Http/Controllers/Api/ApiController.php new file mode 100644 index 000000000..4971c0cde --- /dev/null +++ b/app/Http/Controllers/Api/ApiController.php @@ -0,0 +1,20 @@ +toResponse(); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Api/BooksApiController.php b/app/Http/Controllers/Api/BooksApiController.php new file mode 100644 index 000000000..d23aaf025 --- /dev/null +++ b/app/Http/Controllers/Api/BooksApiController.php @@ -0,0 +1,18 @@ +apiListingResponse($books, [ + 'id', 'name', 'slug', 'description', 'created_at', 'updated_at', 'created_by', 'updated_by', + 'restricted', 'image_id', + ]); + } +} \ No newline at end of file diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index f9752da09..cd3fc83ec 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -37,7 +37,6 @@ class Kernel extends HttpKernel ], 'api' => [ 'throttle:60,1', - 'bindings', ], ]; diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index c4c39d534..a37780e52 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -34,7 +34,7 @@ class RouteServiceProvider extends ServiceProvider public function map() { $this->mapWebRoutes(); -// $this->mapApiRoutes(); + $this->mapApiRoutes(); } /** * Define the "web" routes for the application. @@ -63,7 +63,7 @@ class RouteServiceProvider extends ServiceProvider { Route::group([ 'middleware' => 'api', - 'namespace' => $this->namespace, + 'namespace' => $this->namespace . '\Api', 'prefix' => 'api', ], function ($router) { require base_path('routes/api.php'); diff --git a/routes/api.php b/routes/api.php new file mode 100644 index 000000000..0604ffd29 --- /dev/null +++ b/routes/api.php @@ -0,0 +1,12 @@ + Date: Sun, 29 Dec 2019 13:02:26 +0000 Subject: [PATCH 136/191] Started work on API token controls - Added access-api permission. - Started user profile UI work. - Created database table and model for tokens. - Fixed incorrect templates down migration :( --- app/Api/ApiToken.php | 9 +++ app/Auth/User.php | 21 +++++-- .../Controllers/UserApiTokenController.php | 20 +++++++ app/Http/Controllers/UserController.php | 14 +++-- ...2019_07_07_112515_add_template_support.php | 4 +- .../2019_12_29_120917_add_api_auth.php | 59 +++++++++++++++++++ resources/lang/en/settings.php | 6 ++ resources/views/settings/roles/form.blade.php | 3 +- resources/views/users/edit.blade.php | 19 ++++++ routes/web.php | 3 + 10 files changed, 143 insertions(+), 15 deletions(-) create mode 100644 app/Api/ApiToken.php create mode 100644 app/Http/Controllers/UserApiTokenController.php create mode 100644 database/migrations/2019_12_29_120917_add_api_auth.php diff --git a/app/Api/ApiToken.php b/app/Api/ApiToken.php new file mode 100644 index 000000000..838e70abb --- /dev/null +++ b/app/Api/ApiToken.php @@ -0,0 +1,9 @@ +id); + return $this->hasMany(ApiToken::class); + } + + /** + * Get the url for editing this user. + */ + public function getEditUrl(string $path = ''): string + { + $uri = '/settings/users/' . $this->id . '/' . trim($path, '/'); + return url(rtrim($uri, '/')); } /** * Get the url that links to this user's profile. - * @return mixed */ - public function getProfileUrl() + public function getProfileUrl(): string { return url('/user/' . $this->id); } diff --git a/app/Http/Controllers/UserApiTokenController.php b/app/Http/Controllers/UserApiTokenController.php new file mode 100644 index 000000000..385352011 --- /dev/null +++ b/app/Http/Controllers/UserApiTokenController.php @@ -0,0 +1,20 @@ +checkPermission('access-api'); + + // TODO - Form + return 'test'; + } + + +} diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index b55398d2f..207466f38 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -116,22 +116,24 @@ class UserController extends Controller /** * Show the form for editing the specified user. - * @param int $id - * @param \BookStack\Auth\Access\SocialAuthService $socialAuthService - * @return Response */ - public function edit($id, SocialAuthService $socialAuthService) + public function edit(int $id, SocialAuthService $socialAuthService) { $this->checkPermissionOrCurrentUser('users-manage', $id); - $user = $this->user->findOrFail($id); + $user = $this->user->newQuery()->with(['apiTokens'])->findOrFail($id); $authMethod = ($user->system_name) ? 'system' : config('auth.method'); $activeSocialDrivers = $socialAuthService->getActiveDrivers(); $this->setPageTitle(trans('settings.user_profile')); $roles = $this->userRepo->getAllRoles(); - return view('users.edit', ['user' => $user, 'activeSocialDrivers' => $activeSocialDrivers, 'authMethod' => $authMethod, 'roles' => $roles]); + return view('users.edit', [ + 'user' => $user, + 'activeSocialDrivers' => $activeSocialDrivers, + 'authMethod' => $authMethod, + 'roles' => $roles + ]); } /** diff --git a/database/migrations/2019_07_07_112515_add_template_support.php b/database/migrations/2019_07_07_112515_add_template_support.php index a54508198..3fcc68227 100644 --- a/database/migrations/2019_07_07_112515_add_template_support.php +++ b/database/migrations/2019_07_07_112515_add_template_support.php @@ -46,9 +46,9 @@ class AddTemplateSupport extends Migration // Remove templates-manage permission $templatesManagePermission = DB::table('role_permissions') - ->where('name', '=', 'templates_manage')->first(); + ->where('name', '=', 'templates-manage')->first(); DB::table('permission_role')->where('permission_id', '=', $templatesManagePermission->id)->delete(); - DB::table('role_permissions')->where('name', '=', 'templates_manage')->delete(); + DB::table('role_permissions')->where('name', '=', 'templates-manage')->delete(); } } diff --git a/database/migrations/2019_12_29_120917_add_api_auth.php b/database/migrations/2019_12_29_120917_add_api_auth.php new file mode 100644 index 000000000..e80fe3ae4 --- /dev/null +++ b/database/migrations/2019_12_29_120917_add_api_auth.php @@ -0,0 +1,59 @@ +increments('id'); + $table->string('client_id')->index(); + $table->string('client_secret'); + $table->integer('user_id')->unsigned()->index(); + $table->timestamp('expires_at')->index(); + $table->nullableTimestamps(); + }); + + // Add access-api permission + $adminRoleId = DB::table('roles')->where('system_name', '=', 'admin')->first()->id; + $permissionId = DB::table('role_permissions')->insertGetId([ + 'name' => 'access-api', + 'display_name' => 'Access system API', + 'created_at' => Carbon::now()->toDateTimeString(), + 'updated_at' => Carbon::now()->toDateTimeString() + ]); + DB::table('permission_role')->insert([ + 'role_id' => $adminRoleId, + 'permission_id' => $permissionId + ]); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // Remove API tokens table + Schema::dropIfExists('api_tokens'); + + // Remove access-api permission + $apiAccessPermission = DB::table('role_permissions') + ->where('name', '=', 'access-api')->first(); + + DB::table('permission_role')->where('permission_id', '=', $apiAccessPermission->id)->delete(); + DB::table('role_permissions')->where('name', '=', 'access-api')->delete(); + } +} diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index 6be7cc9cb..bb750a780 100755 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -103,6 +103,7 @@ return [ 'role_manage_entity_permissions' => 'Manage all book, chapter & page permissions', 'role_manage_own_entity_permissions' => 'Manage permissions on own book, chapter & pages', 'role_manage_page_templates' => 'Manage page templates', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Manage app settings', 'role_asset' => 'Asset Permissions', 'role_asset_desc' => 'These permissions control default access to the assets within the system. Permissions on Books, Chapters and Pages will override these permissions.', @@ -151,6 +152,11 @@ return [ 'users_social_disconnect' => 'Disconnect Account', 'users_social_connected' => ':socialAccount account was successfully attached to your profile.', 'users_social_disconnected' => ':socialAccount account was successfully disconnected from your profile.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + + // API Tokens //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/views/settings/roles/form.blade.php b/resources/views/settings/roles/form.blade.php index 4617b1f52..1fbc80b1f 100644 --- a/resources/views/settings/roles/form.blade.php +++ b/resources/views/settings/roles/form.blade.php @@ -34,12 +34,13 @@ {{ trans('common.toggle_all') }}
+
@include('settings.roles.checkbox', ['permission' => 'settings-manage', 'label' => trans('settings.role_manage_settings')])
@include('settings.roles.checkbox', ['permission' => 'users-manage', 'label' => trans('settings.role_manage_users')])
@include('settings.roles.checkbox', ['permission' => 'user-roles-manage', 'label' => trans('settings.role_manage_roles')])
@include('settings.roles.checkbox', ['permission' => 'restrictions-manage-all', 'label' => trans('settings.role_manage_entity_permissions')])
@include('settings.roles.checkbox', ['permission' => 'restrictions-manage-own', 'label' => trans('settings.role_manage_own_entity_permissions')])
@include('settings.roles.checkbox', ['permission' => 'templates-manage', 'label' => trans('settings.role_manage_page_templates')])
-
@include('settings.roles.checkbox', ['permission' => 'settings-manage', 'label' => trans('settings.role_manage_settings')])
+
@include('settings.roles.checkbox', ['permission' => 'access-api', 'label' => trans('settings.role_access_api')])
diff --git a/resources/views/users/edit.blade.php b/resources/views/users/edit.blade.php index ff1e7cbe5..b3f73773b 100644 --- a/resources/views/users/edit.blade.php +++ b/resources/views/users/edit.blade.php @@ -87,6 +87,25 @@ @endif + + {{-- TODO - Review Control--}} + @if(($currentUser->id === $user->id && userCan('access-api')) || userCan('manage-users')) +
+
+

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

+
+ @if(userCan('access-api')) + {{ trans('settings.users_api_tokens_create') }} + @endif +
+
+ @if (count($user->apiTokens) > 0) + + @else +

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

+ @endif +
+ @endif @stop diff --git a/routes/web.php b/routes/web.php index 839e5a256..2a0e85dfe 100644 --- a/routes/web.php +++ b/routes/web.php @@ -187,6 +187,9 @@ Route::group(['middleware' => 'auth'], function () { Route::put('/users/{id}', 'UserController@update'); Route::delete('/users/{id}', 'UserController@destroy'); + // User API Tokens + Route::get('/users/{userId}/create-api-token', 'UserApiTokenController@create'); + // Roles Route::get('/roles', 'PermissionController@listRoles'); Route::get('/roles/new', 'PermissionController@createRole'); From dccb279c84a3f523f1c07ffc4ee4e2b526fd5384 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 29 Dec 2019 17:03:52 +0000 Subject: [PATCH 137/191] Built out interfaces & endpoints for API token managment --- app/Api/ApiToken.php | 4 +- app/Auth/UserRepo.php | 1 + .../Controllers/UserApiTokenController.php | 119 +++++++++++++++++- .../2019_12_29_120917_add_api_auth.php | 3 +- resources/lang/en/settings.php | 18 +++ resources/sass/_forms.scss | 3 + resources/views/form/date.blade.php | 9 ++ resources/views/form/text.blade.php | 1 + .../views/users/api-tokens/create.blade.php | 33 +++++ .../views/users/api-tokens/delete.blade.php | 26 ++++ .../views/users/api-tokens/edit.blade.php | 66 ++++++++++ .../views/users/api-tokens/form.blade.php | 21 ++++ resources/views/users/edit.blade.php | 22 +++- routes/web.php | 5 + 14 files changed, 325 insertions(+), 6 deletions(-) create mode 100644 resources/views/form/date.blade.php create mode 100644 resources/views/users/api-tokens/create.blade.php create mode 100644 resources/views/users/api-tokens/delete.blade.php create mode 100644 resources/views/users/api-tokens/edit.blade.php create mode 100644 resources/views/users/api-tokens/form.blade.php diff --git a/app/Api/ApiToken.php b/app/Api/ApiToken.php index 838e70abb..e7101387f 100644 --- a/app/Api/ApiToken.php +++ b/app/Api/ApiToken.php @@ -5,5 +5,7 @@ use Illuminate\Database\Eloquent\Model; class ApiToken extends Model { protected $fillable = ['name', 'expires_at']; - + protected $casts = [ + 'expires_at' => 'datetime:Y-m-d' + ]; } diff --git a/app/Auth/UserRepo.php b/app/Auth/UserRepo.php index a903e2c38..e082b2dd5 100644 --- a/app/Auth/UserRepo.php +++ b/app/Auth/UserRepo.php @@ -194,6 +194,7 @@ class UserRepo public function destroy(User $user) { $user->socialAccounts()->delete(); + $user->apiTokens()->delete(); $user->delete(); // Delete user profile images diff --git a/app/Http/Controllers/UserApiTokenController.php b/app/Http/Controllers/UserApiTokenController.php index 385352011..3bfb0175e 100644 --- a/app/Http/Controllers/UserApiTokenController.php +++ b/app/Http/Controllers/UserApiTokenController.php @@ -1,6 +1,11 @@ checkPermission('access-api'); + $this->checkPermissionOrCurrentUser('manage-users', $userId); - // TODO - Form - return 'test'; + $user = User::query()->findOrFail($userId); + return view('users.api-tokens.create', [ + 'user' => $user, + ]); } + /** + * Store a new API token in the system. + */ + public function store(Request $request, int $userId) + { + $this->checkPermission('access-api'); + $this->checkPermissionOrCurrentUser('manage-users', $userId); + + $this->validate($request, [ + 'name' => 'required|max:250', + 'expires_at' => 'date_format:Y-m-d', + ]); + + $user = User::query()->findOrFail($userId); + $secret = Str::random(32); + $expiry = $request->get('expires_at', (Carbon::now()->addYears(100))->format('Y-m-d')); + + $token = (new ApiToken())->forceFill([ + 'name' => $request->get('name'), + 'client_id' => Str::random(32), + 'client_secret' => Hash::make($secret), + 'user_id' => $user->id, + 'expires_at' => $expiry + ]); + + while (ApiToken::query()->where('client_id', '=', $token->client_id)->exists()) { + $token->client_id = Str::random(32); + } + + $token->save(); + // TODO - Notification and activity? + session()->flash('api-token-secret:' . $token->id, $secret); + return redirect($user->getEditUrl('/api-tokens/' . $token->id)); + } + + /** + * Show the details for a user API token, with access to edit. + */ + public function edit(int $userId, int $tokenId) + { + [$user, $token] = $this->checkPermissionAndFetchUserToken($userId, $tokenId); + $secret = session()->pull('api-token-secret:' . $token->id, null); + + return view('users.api-tokens.edit', [ + 'user' => $user, + 'token' => $token, + 'model' => $token, + 'secret' => $secret, + ]); + } + + /** + * Update the API token. + */ + public function update(Request $request, int $userId, int $tokenId) + { + $this->validate($request, [ + 'name' => 'required|max:250', + 'expires_at' => 'date_format:Y-m-d', + ]); + + [$user, $token] = $this->checkPermissionAndFetchUserToken($userId, $tokenId); + + $token->fill($request->all())->save(); + // TODO - Notification and activity? + return redirect($user->getEditUrl('/api-tokens/' . $token->id)); + } + + /** + * Show the delete view for this token. + */ + public function delete(int $userId, int $tokenId) + { + [$user, $token] = $this->checkPermissionAndFetchUserToken($userId, $tokenId); + return view('users.api-tokens.delete', [ + 'user' => $user, + 'token' => $token, + ]); + } + + /** + * Destroy a token from the system. + */ + public function destroy(int $userId, int $tokenId) + { + [$user, $token] = $this->checkPermissionAndFetchUserToken($userId, $tokenId); + $token->delete(); + + // TODO - Notification and activity?, Might have text in translations already (user_api_token_delete_success) + return redirect($user->getEditUrl('#api_tokens')); + } + + /** + * Check the permission for the current user and return an array + * where the first item is the user in context and the second item is their + * API token in context. + */ + protected function checkPermissionAndFetchUserToken(int $userId, int $tokenId): array + { + $this->checkPermission('access-api'); + $this->checkPermissionOrCurrentUser('manage-users', $userId); + + $user = User::query()->findOrFail($userId); + $token = ApiToken::query()->where('user_id', '=', $user->id)->where('id', '=', $tokenId)->firstOrFail(); + return [$user, $token]; + } } diff --git a/database/migrations/2019_12_29_120917_add_api_auth.php b/database/migrations/2019_12_29_120917_add_api_auth.php index e80fe3ae4..2af0b292e 100644 --- a/database/migrations/2019_12_29_120917_add_api_auth.php +++ b/database/migrations/2019_12_29_120917_add_api_auth.php @@ -18,7 +18,8 @@ class AddApiAuth extends Migration // Add API tokens table Schema::create('api_tokens', function(Blueprint $table) { $table->increments('id'); - $table->string('client_id')->index(); + $table->string('name'); + $table->string('client_id')->unique(); $table->string('client_secret'); $table->integer('user_id')->unsigned()->index(); $table->timestamp('expires_at')->index(); diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index bb750a780..a2148361a 100755 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -155,8 +155,26 @@ return [ 'users_api_tokens' => 'API Tokens', 'users_api_tokens_none' => 'No API tokens have been created for this user', 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "client id"" & "client secret" will be generated and displayed. The client secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token' => 'API Token', + 'user_api_token_client_id' => 'Client ID', + 'user_api_token_client_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_client_secret' => 'Client Secret', + 'user_api_token_client_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/sass/_forms.scss b/resources/sass/_forms.scss index 3e7ff60f3..da0f7ef4c 100644 --- a/resources/sass/_forms.scss +++ b/resources/sass/_forms.scss @@ -19,6 +19,9 @@ &.disabled, &[disabled] { background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAMUlEQVQIW2NkwAGuXbv2nxGbHEhCS0uLEUMSJgHShCKJLIEiiS4Bl8QmAZbEJQGSBAC62BuJ+tt7zgAAAABJRU5ErkJggg==); } + &[readonly] { + background-color: #f8f8f8; + } &:focus { border-color: var(--color-primary); outline: 1px solid var(--color-primary); diff --git a/resources/views/form/date.blade.php b/resources/views/form/date.blade.php new file mode 100644 index 000000000..c2e70b9e3 --- /dev/null +++ b/resources/views/form/date.blade.php @@ -0,0 +1,9 @@ +has($name)) class="text-neg" @endif + placeholder="{{ $placeholder ?? 'YYYY-MM-DD' }}" + @if($autofocus ?? false) autofocus @endif + @if($disabled ?? false) disabled="disabled" @endif + @if(isset($model) || old($name)) value="{{ old($name) ?? $model->$name->format('Y-m-d') ?? ''}}" @endif> +@if($errors->has($name)) +
{{ $errors->first($name) }}
+@endif diff --git a/resources/views/form/text.blade.php b/resources/views/form/text.blade.php index 4b3631a06..fabfab451 100644 --- a/resources/views/form/text.blade.php +++ b/resources/views/form/text.blade.php @@ -3,6 +3,7 @@ @if(isset($placeholder)) placeholder="{{$placeholder}}" @endif @if($autofocus ?? false) autofocus @endif @if($disabled ?? false) disabled="disabled" @endif + @if($readonly ?? false) readonly="readonly" @endif @if(isset($model) || old($name)) value="{{ old($name) ? old($name) : $model->$name}}" @endif> @if($errors->has($name))
{{ $errors->first($name) }}
diff --git a/resources/views/users/api-tokens/create.blade.php b/resources/views/users/api-tokens/create.blade.php new file mode 100644 index 000000000..46c3e0b8a --- /dev/null +++ b/resources/views/users/api-tokens/create.blade.php @@ -0,0 +1,33 @@ +@extends('simple-layout') + +@section('body') + +
+ +
+

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

+ +
+ {!! csrf_field() !!} + +
+ @include('users.api-tokens.form') + +
+

+ {{ trans('settings.user_api_token_create_secret_message') }} +

+
+
+ +
+ {{ trans('common.cancel') }} + +
+ +
+ +
+
+ +@stop diff --git a/resources/views/users/api-tokens/delete.blade.php b/resources/views/users/api-tokens/delete.blade.php new file mode 100644 index 000000000..8fcfcda95 --- /dev/null +++ b/resources/views/users/api-tokens/delete.blade.php @@ -0,0 +1,26 @@ +@extends('simple-layout') + +@section('body') +
+ +
+

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

+ +

{{ trans('settings.user_api_token_delete_warning', ['tokenName' => $token->name]) }}

+ +
+

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

+
+
+ {!! csrf_field() !!} + {!! method_field('delete') !!} + + {{ trans('common.cancel') }} + +
+
+
+ +
+
+@stop diff --git a/resources/views/users/api-tokens/edit.blade.php b/resources/views/users/api-tokens/edit.blade.php new file mode 100644 index 000000000..0ec9adbe6 --- /dev/null +++ b/resources/views/users/api-tokens/edit.blade.php @@ -0,0 +1,66 @@ +@extends('simple-layout') + +@section('body') + +
+ +
+

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

+ +
+ {!! method_field('put') !!} + {!! csrf_field() !!} + +
+ +
+
+ +

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

+
+
+ @include('form.text', ['name' => 'client_id', 'readonly' => true]) +
+
+ + + @if( $secret ) +
+
+ +

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

+
+
+ +
+
+ @endif + + @include('users.api-tokens.form', ['model' => $token]) +
+ +
+ +
+ + {{ trans('settings.user_api_token_created', ['timeAgo' => $token->created_at->diffForHumans()]) }} + +
+ + {{ trans('settings.user_api_token_updated', ['timeAgo' => $token->created_at->diffForHumans()]) }} + +
+ + +
+ +
+ +
+
+ +@stop diff --git a/resources/views/users/api-tokens/form.blade.php b/resources/views/users/api-tokens/form.blade.php new file mode 100644 index 000000000..d81a330d5 --- /dev/null +++ b/resources/views/users/api-tokens/form.blade.php @@ -0,0 +1,21 @@ + + +
+
+ +

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

+
+
+ @include('form.text', ['name' => 'name']) +
+
+ +
+
+ +

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

+
+
+ @include('form.date', ['name' => 'expires_at']) +
+
\ No newline at end of file diff --git a/resources/views/users/edit.blade.php b/resources/views/users/edit.blade.php index b3f73773b..54e0ee21a 100644 --- a/resources/views/users/edit.blade.php +++ b/resources/views/users/edit.blade.php @@ -90,7 +90,7 @@ {{-- TODO - Review Control--}} @if(($currentUser->id === $user->id && userCan('access-api')) || userCan('manage-users')) -
+

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

@@ -100,7 +100,25 @@
@if (count($user->apiTokens) > 0) - + + + + + + + @foreach($user->apiTokens as $token) + + + + + + @endforeach +
{{ trans('common.name') }}{{ trans('settings.users_api_tokens_expires') }}
+ {{ $token->name }}
+ {{ $token->client_id }} +
{{ $token->expires_at->format('Y-m-d') ?? '' }} + {{ trans('common.edit') }} +
@else

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

@endif diff --git a/routes/web.php b/routes/web.php index 2a0e85dfe..f38575b79 100644 --- a/routes/web.php +++ b/routes/web.php @@ -189,6 +189,11 @@ Route::group(['middleware' => 'auth'], function () { // User API Tokens Route::get('/users/{userId}/create-api-token', 'UserApiTokenController@create'); + Route::post('/users/{userId}/create-api-token', 'UserApiTokenController@store'); + Route::get('/users/{userId}/api-tokens/{tokenId}', 'UserApiTokenController@edit'); + Route::put('/users/{userId}/api-tokens/{tokenId}', 'UserApiTokenController@update'); + Route::get('/users/{userId}/api-tokens/{tokenId}/delete', 'UserApiTokenController@delete'); + Route::delete('/users/{userId}/api-tokens/{tokenId}', 'UserApiTokenController@destroy'); // Roles Route::get('/roles', 'PermissionController@listRoles'); From 832fbd65afcaa8d8f2953fe04de2e479053dbc29 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 29 Dec 2019 19:46:46 +0000 Subject: [PATCH 138/191] Added testing coverage to user API token interfaces --- app/Api/ApiToken.php | 2 +- .../Controllers/UserApiTokenController.php | 17 +- .../2019_12_29_120917_add_api_auth.php | 2 +- resources/lang/en/settings.php | 2 + resources/views/users/edit.blade.php | 3 +- tests/User/UserApiTokenTest.php | 165 ++++++++++++++++++ tests/{ => User}/UserPreferencesTest.php | 0 tests/{ => User}/UserProfileTest.php | 0 8 files changed, 180 insertions(+), 11 deletions(-) create mode 100644 tests/User/UserApiTokenTest.php rename tests/{ => User}/UserPreferencesTest.php (100%) rename tests/{ => User}/UserProfileTest.php (100%) diff --git a/app/Api/ApiToken.php b/app/Api/ApiToken.php index e7101387f..4ea12888e 100644 --- a/app/Api/ApiToken.php +++ b/app/Api/ApiToken.php @@ -6,6 +6,6 @@ class ApiToken extends Model { protected $fillable = ['name', 'expires_at']; protected $casts = [ - 'expires_at' => 'datetime:Y-m-d' + 'expires_at' => 'date:Y-m-d' ]; } diff --git a/app/Http/Controllers/UserApiTokenController.php b/app/Http/Controllers/UserApiTokenController.php index 3bfb0175e..9f5ebc49e 100644 --- a/app/Http/Controllers/UserApiTokenController.php +++ b/app/Http/Controllers/UserApiTokenController.php @@ -17,7 +17,7 @@ class UserApiTokenController extends Controller { // Ensure user is has access-api permission and is the current user or has permission to manage the current user. $this->checkPermission('access-api'); - $this->checkPermissionOrCurrentUser('manage-users', $userId); + $this->checkPermissionOrCurrentUser('users-manage', $userId); $user = User::query()->findOrFail($userId); return view('users.api-tokens.create', [ @@ -31,7 +31,7 @@ class UserApiTokenController extends Controller public function store(Request $request, int $userId) { $this->checkPermission('access-api'); - $this->checkPermissionOrCurrentUser('manage-users', $userId); + $this->checkPermissionOrCurrentUser('users-manage', $userId); $this->validate($request, [ 'name' => 'required|max:250', @@ -55,8 +55,10 @@ class UserApiTokenController extends Controller } $token->save(); - // TODO - Notification and activity? + $token->refresh(); + session()->flash('api-token-secret:' . $token->id, $secret); + $this->showSuccessNotification(trans('settings.user_api_token_create_success')); return redirect($user->getEditUrl('/api-tokens/' . $token->id)); } @@ -89,7 +91,7 @@ class UserApiTokenController extends Controller [$user, $token] = $this->checkPermissionAndFetchUserToken($userId, $tokenId); $token->fill($request->all())->save(); - // TODO - Notification and activity? + $this->showSuccessNotification(trans('settings.user_api_token_update_success')); return redirect($user->getEditUrl('/api-tokens/' . $token->id)); } @@ -113,7 +115,7 @@ class UserApiTokenController extends Controller [$user, $token] = $this->checkPermissionAndFetchUserToken($userId, $tokenId); $token->delete(); - // TODO - Notification and activity?, Might have text in translations already (user_api_token_delete_success) + $this->showSuccessNotification(trans('settings.user_api_token_delete_success')); return redirect($user->getEditUrl('#api_tokens')); } @@ -124,8 +126,9 @@ class UserApiTokenController extends Controller */ protected function checkPermissionAndFetchUserToken(int $userId, int $tokenId): array { - $this->checkPermission('access-api'); - $this->checkPermissionOrCurrentUser('manage-users', $userId); + $this->checkPermissionOr('users-manage', function () use ($userId) { + return $userId === user()->id && userCan('access-api'); + }); $user = User::query()->findOrFail($userId); $token = ApiToken::query()->where('user_id', '=', $user->id)->where('id', '=', $tokenId)->firstOrFail(); diff --git a/database/migrations/2019_12_29_120917_add_api_auth.php b/database/migrations/2019_12_29_120917_add_api_auth.php index 2af0b292e..c8a1a7781 100644 --- a/database/migrations/2019_12_29_120917_add_api_auth.php +++ b/database/migrations/2019_12_29_120917_add_api_auth.php @@ -22,7 +22,7 @@ class AddApiAuth extends Migration $table->string('client_id')->unique(); $table->string('client_secret'); $table->integer('user_id')->unsigned()->index(); - $table->timestamp('expires_at')->index(); + $table->date('expires_at')->index(); $table->nullableTimestamps(); }); diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index a2148361a..88eb22aa0 100755 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -164,6 +164,8 @@ return [ 'user_api_token_expiry' => 'Expiry Date', 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', 'user_api_token_create_secret_message' => 'Immediately after creating this token a "client id"" & "client secret" will be generated and displayed. The client secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', 'user_api_token' => 'API Token', 'user_api_token_client_id' => 'Client ID', 'user_api_token_client_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', diff --git a/resources/views/users/edit.blade.php b/resources/views/users/edit.blade.php index 54e0ee21a..ba76b022e 100644 --- a/resources/views/users/edit.blade.php +++ b/resources/views/users/edit.blade.php @@ -88,8 +88,7 @@
@endif - {{-- TODO - Review Control--}} - @if(($currentUser->id === $user->id && userCan('access-api')) || userCan('manage-users')) + @if(($currentUser->id === $user->id && userCan('access-api')) || userCan('users-manage'))

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

diff --git a/tests/User/UserApiTokenTest.php b/tests/User/UserApiTokenTest.php new file mode 100644 index 000000000..86c2b7bcc --- /dev/null +++ b/tests/User/UserApiTokenTest.php @@ -0,0 +1,165 @@ + 'My test API token', + 'expires_at' => '2099-04-01', + ]; + + public function test_tokens_section_not_visible_without_access_api_permission() + { + $user = $this->getEditor(); + + $resp = $this->actingAs($user)->get($user->getEditUrl()); + $resp->assertDontSeeText('API Tokens'); + + $this->giveUserPermissions($user, ['access-api']); + + $resp = $this->actingAs($user)->get($user->getEditUrl()); + $resp->assertSeeText('API Tokens'); + $resp->assertSeeText('Create Token'); + } + + public function test_those_with_manage_users_can_view_other_user_tokens_but_not_create() + { + $viewer = $this->getViewer(); + $editor = $this->getEditor(); + $this->giveUserPermissions($editor, ['users-manage']); + + $resp = $this->actingAs($editor)->get($viewer->getEditUrl()); + $resp->assertSeeText('API Tokens'); + $resp->assertDontSeeText('Create Token'); + } + + public function test_create_api_token() + { + $editor = $this->getEditor(); + + $resp = $this->asAdmin()->get($editor->getEditUrl('/create-api-token')); + $resp->assertStatus(200); + $resp->assertSee('Create API Token'); + $resp->assertSee('client secret'); + + $resp = $this->post($editor->getEditUrl('/create-api-token'), $this->testTokenData); + $token = ApiToken::query()->latest()->first(); + $resp->assertRedirect($editor->getEditUrl('/api-tokens/' . $token->id)); + $this->assertDatabaseHas('api_tokens', [ + 'user_id' => $editor->id, + 'name' => $this->testTokenData['name'], + 'expires_at' => $this->testTokenData['expires_at'], + ]); + + // Check secret token + $this->assertSessionHas('api-token-secret:' . $token->id); + $secret = session('api-token-secret:' . $token->id); + $this->assertDatabaseMissing('api_tokens', [ + 'client_secret' => $secret, + ]); + $this->assertTrue(\Hash::check($secret, $token->client_secret)); + + $this->assertTrue(strlen($token->client_id) === 32); + $this->assertTrue(strlen($secret) === 32); + + $this->assertSessionHas('success'); + } + + public function test_create_with_no_expiry_sets_expiry_hundred_years_away() + { + $editor = $this->getEditor(); + $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), ['name' => 'No expiry token']); + $token = ApiToken::query()->latest()->first(); + + $over = Carbon::now()->addYears(101); + $under = Carbon::now()->addYears(99); + $this->assertTrue( + ($token->expires_at < $over && $token->expires_at > $under), + "Token expiry set at 100 years in future" + ); + } + + public function test_created_token_displays_on_profile_page() + { + $editor = $this->getEditor(); + $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData); + $token = ApiToken::query()->latest()->first(); + + $resp = $this->get($editor->getEditUrl()); + $resp->assertElementExists('#api_tokens'); + $resp->assertElementContains('#api_tokens', $token->name); + $resp->assertElementContains('#api_tokens', $token->client_id); + $resp->assertElementContains('#api_tokens', $token->expires_at->format('Y-m-d')); + } + + public function test_client_secret_shown_once_after_creation() + { + $editor = $this->getEditor(); + $resp = $this->asAdmin()->followingRedirects()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData); + $resp->assertSeeText('Client Secret'); + + $token = ApiToken::query()->latest()->first(); + $this->assertNull(session('api-token-secret:' . $token->id)); + + $resp = $this->get($editor->getEditUrl('/api-tokens/' . $token->id)); + $resp->assertDontSeeText('Client Secret'); + } + + public function test_token_update() + { + $editor = $this->getEditor(); + $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData); + $token = ApiToken::query()->latest()->first(); + $updateData = [ + 'name' => 'My updated token', + 'expires_at' => '2011-01-01', + ]; + + $resp = $this->put($editor->getEditUrl('/api-tokens/' . $token->id), $updateData); + $resp->assertRedirect($editor->getEditUrl('/api-tokens/' . $token->id)); + + $this->assertDatabaseHas('api_tokens', array_merge($updateData, ['id' => $token->id])); + $this->assertSessionHas('success'); + } + + public function test_token_delete() + { + $editor = $this->getEditor(); + $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData); + $token = ApiToken::query()->latest()->first(); + + $tokenUrl = $editor->getEditUrl('/api-tokens/' . $token->id); + + $resp = $this->get($tokenUrl . '/delete'); + $resp->assertSeeText('Delete Token'); + $resp->assertSeeText($token->name); + $resp->assertElementExists('form[action="'.$tokenUrl.'"]'); + + $resp = $this->delete($tokenUrl); + $resp->assertRedirect($editor->getEditUrl('#api_tokens')); + $this->assertDatabaseMissing('api_tokens', ['id' => $token->id]); + } + + public function test_user_manage_can_delete_token_without_api_permission_themselves() + { + $viewer = $this->getViewer(); + $editor = $this->getEditor(); + $this->giveUserPermissions($editor, ['users-manage']); + + $this->asAdmin()->post($viewer->getEditUrl('/create-api-token'), $this->testTokenData); + $token = ApiToken::query()->latest()->first(); + + $resp = $this->actingAs($editor)->get($viewer->getEditUrl('/api-tokens/' . $token->id)); + $resp->assertStatus(200); + $resp->assertSeeText('Delete Token'); + + $resp = $this->actingAs($editor)->delete($viewer->getEditUrl('/api-tokens/' . $token->id)); + $resp->assertRedirect($viewer->getEditUrl('#api_tokens')); + $this->assertDatabaseMissing('api_tokens', ['id' => $token->id]); + } + +} \ No newline at end of file diff --git a/tests/UserPreferencesTest.php b/tests/User/UserPreferencesTest.php similarity index 100% rename from tests/UserPreferencesTest.php rename to tests/User/UserPreferencesTest.php diff --git a/tests/UserProfileTest.php b/tests/User/UserProfileTest.php similarity index 100% rename from tests/UserProfileTest.php rename to tests/User/UserProfileTest.php From 692fc46c7dfab76f4e9e28a9f1b4c419f60b5ded Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 29 Dec 2019 20:07:28 +0000 Subject: [PATCH 139/191] Removed token 'client' text, avoid confusion w/ oAuth - Instead have a token_id and a secret. - Displayed a 'Token ID' and 'Token Secret'. --- app/Http/Controllers/UserApiTokenController.php | 8 ++++---- .../migrations/2019_12_29_120917_add_api_auth.php | 4 ++-- resources/lang/en/settings.php | 10 +++++----- resources/views/users/api-tokens/edit.blade.php | 10 +++++----- resources/views/users/edit.blade.php | 2 +- tests/User/UserApiTokenTest.php | 14 +++++++------- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/app/Http/Controllers/UserApiTokenController.php b/app/Http/Controllers/UserApiTokenController.php index 9f5ebc49e..c18d52901 100644 --- a/app/Http/Controllers/UserApiTokenController.php +++ b/app/Http/Controllers/UserApiTokenController.php @@ -44,14 +44,14 @@ class UserApiTokenController extends Controller $token = (new ApiToken())->forceFill([ 'name' => $request->get('name'), - 'client_id' => Str::random(32), - 'client_secret' => Hash::make($secret), + 'token_id' => Str::random(32), + 'secret' => Hash::make($secret), 'user_id' => $user->id, 'expires_at' => $expiry ]); - while (ApiToken::query()->where('client_id', '=', $token->client_id)->exists()) { - $token->client_id = Str::random(32); + while (ApiToken::query()->where('token_id', '=', $token->token_id)->exists()) { + $token->token_id = Str::random(32); } $token->save(); diff --git a/database/migrations/2019_12_29_120917_add_api_auth.php b/database/migrations/2019_12_29_120917_add_api_auth.php index c8a1a7781..eff88247f 100644 --- a/database/migrations/2019_12_29_120917_add_api_auth.php +++ b/database/migrations/2019_12_29_120917_add_api_auth.php @@ -19,8 +19,8 @@ class AddApiAuth extends Migration Schema::create('api_tokens', function(Blueprint $table) { $table->increments('id'); $table->string('name'); - $table->string('client_id')->unique(); - $table->string('client_secret'); + $table->string('token_id')->unique(); + $table->string('secret'); $table->integer('user_id')->unsigned()->index(); $table->date('expires_at')->index(); $table->nullableTimestamps(); diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index 88eb22aa0..b1da5435f 100755 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -163,14 +163,14 @@ return [ 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', 'user_api_token_expiry' => 'Expiry Date', 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', - 'user_api_token_create_secret_message' => 'Immediately after creating this token a "client id"" & "client secret" will be generated and displayed. The client secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', 'user_api_token_create_success' => 'API token successfully created', 'user_api_token_update_success' => 'API token successfully updated', 'user_api_token' => 'API Token', - 'user_api_token_client_id' => 'Client ID', - 'user_api_token_client_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', - 'user_api_token_client_secret' => 'Client Secret', - 'user_api_token_client_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', 'user_api_token_created' => 'Token Created :timeAgo', 'user_api_token_updated' => 'Token Updated :timeAgo', 'user_api_token_delete' => 'Delete Token', diff --git a/resources/views/users/api-tokens/edit.blade.php b/resources/views/users/api-tokens/edit.blade.php index 0ec9adbe6..821a00d93 100644 --- a/resources/views/users/api-tokens/edit.blade.php +++ b/resources/views/users/api-tokens/edit.blade.php @@ -15,11 +15,11 @@
- -

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

+ +

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

- @include('form.text', ['name' => 'client_id', 'readonly' => true]) + @include('form.text', ['name' => 'token_id', 'readonly' => true])
@@ -27,8 +27,8 @@ @if( $secret )
- -

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

+ +

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

diff --git a/resources/views/users/edit.blade.php b/resources/views/users/edit.blade.php index ba76b022e..c69d101d4 100644 --- a/resources/views/users/edit.blade.php +++ b/resources/views/users/edit.blade.php @@ -109,7 +109,7 @@ {{ $token->name }}
- {{ $token->client_id }} + {{ $token->token_id }} {{ $token->expires_at->format('Y-m-d') ?? '' }} diff --git a/tests/User/UserApiTokenTest.php b/tests/User/UserApiTokenTest.php index 86c2b7bcc..012747296 100644 --- a/tests/User/UserApiTokenTest.php +++ b/tests/User/UserApiTokenTest.php @@ -44,7 +44,7 @@ class UserApiTokenTest extends TestCase $resp = $this->asAdmin()->get($editor->getEditUrl('/create-api-token')); $resp->assertStatus(200); $resp->assertSee('Create API Token'); - $resp->assertSee('client secret'); + $resp->assertSee('Token Secret'); $resp = $this->post($editor->getEditUrl('/create-api-token'), $this->testTokenData); $token = ApiToken::query()->latest()->first(); @@ -59,11 +59,11 @@ class UserApiTokenTest extends TestCase $this->assertSessionHas('api-token-secret:' . $token->id); $secret = session('api-token-secret:' . $token->id); $this->assertDatabaseMissing('api_tokens', [ - 'client_secret' => $secret, + 'secret' => $secret, ]); - $this->assertTrue(\Hash::check($secret, $token->client_secret)); + $this->assertTrue(\Hash::check($secret, $token->secret)); - $this->assertTrue(strlen($token->client_id) === 32); + $this->assertTrue(strlen($token->token_id) === 32); $this->assertTrue(strlen($secret) === 32); $this->assertSessionHas('success'); @@ -92,15 +92,15 @@ class UserApiTokenTest extends TestCase $resp = $this->get($editor->getEditUrl()); $resp->assertElementExists('#api_tokens'); $resp->assertElementContains('#api_tokens', $token->name); - $resp->assertElementContains('#api_tokens', $token->client_id); + $resp->assertElementContains('#api_tokens', $token->token_id); $resp->assertElementContains('#api_tokens', $token->expires_at->format('Y-m-d')); } - public function test_client_secret_shown_once_after_creation() + public function test_secret_shown_once_after_creation() { $editor = $this->getEditor(); $resp = $this->asAdmin()->followingRedirects()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData); - $resp->assertSeeText('Client Secret'); + $resp->assertSeeText('Token Secret'); $token = ApiToken::query()->latest()->first(); $this->assertNull(session('api-token-secret:' . $token->id)); From 2cfa37399c6b7f5b743db8223dd90d3dba68d6fa Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 29 Dec 2019 20:18:37 +0000 Subject: [PATCH 140/191] Fixed some empty-expiry conditions of token ui flows --- .../Controllers/UserApiTokenController.php | 14 ++++++++--- tests/User/UserApiTokenTest.php | 24 +++++++++++++++++-- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/app/Http/Controllers/UserApiTokenController.php b/app/Http/Controllers/UserApiTokenController.php index c18d52901..547ec0c2b 100644 --- a/app/Http/Controllers/UserApiTokenController.php +++ b/app/Http/Controllers/UserApiTokenController.php @@ -40,7 +40,11 @@ class UserApiTokenController extends Controller $user = User::query()->findOrFail($userId); $secret = Str::random(32); - $expiry = $request->get('expires_at', (Carbon::now()->addYears(100))->format('Y-m-d')); + + $expiry = $request->get('expires_at', null); + if (empty($expiry)) { + $expiry = Carbon::now()->addYears(100)->format('Y-m-d'); + } $token = (new ApiToken())->forceFill([ 'name' => $request->get('name'), @@ -83,14 +87,18 @@ class UserApiTokenController extends Controller */ public function update(Request $request, int $userId, int $tokenId) { - $this->validate($request, [ + $requestData = $this->validate($request, [ 'name' => 'required|max:250', 'expires_at' => 'date_format:Y-m-d', ]); [$user, $token] = $this->checkPermissionAndFetchUserToken($userId, $tokenId); - $token->fill($request->all())->save(); + if (empty($requestData['expires_at'])) { + $requestData['expires_at'] = Carbon::now()->addYears(100)->format('Y-m-d'); + } + + $token->fill($requestData)->save(); $this->showSuccessNotification(trans('settings.user_api_token_update_success')); return redirect($user->getEditUrl('/api-tokens/' . $token->id)); } diff --git a/tests/User/UserApiTokenTest.php b/tests/User/UserApiTokenTest.php index 012747296..460752fc2 100644 --- a/tests/User/UserApiTokenTest.php +++ b/tests/User/UserApiTokenTest.php @@ -9,7 +9,7 @@ class UserApiTokenTest extends TestCase protected $testTokenData = [ 'name' => 'My test API token', - 'expires_at' => '2099-04-01', + 'expires_at' => '2050-04-01', ]; public function test_tokens_section_not_visible_without_access_api_permission() @@ -72,7 +72,7 @@ class UserApiTokenTest extends TestCase public function test_create_with_no_expiry_sets_expiry_hundred_years_away() { $editor = $this->getEditor(); - $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), ['name' => 'No expiry token']); + $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), ['name' => 'No expiry token', 'expires_at' => '']); $token = ApiToken::query()->latest()->first(); $over = Carbon::now()->addYears(101); @@ -126,6 +126,26 @@ class UserApiTokenTest extends TestCase $this->assertSessionHas('success'); } + public function test_token_update_with_blank_expiry_sets_to_hundred_years_away() + { + $editor = $this->getEditor(); + $this->asAdmin()->post($editor->getEditUrl('/create-api-token'), $this->testTokenData); + $token = ApiToken::query()->latest()->first(); + + $resp = $this->put($editor->getEditUrl('/api-tokens/' . $token->id), [ + 'name' => 'My updated token', + 'expires_at' => '', + ]); + $token->refresh(); + + $over = Carbon::now()->addYears(101); + $under = Carbon::now()->addYears(99); + $this->assertTrue( + ($token->expires_at < $over && $token->expires_at > $under), + "Token expiry set at 100 years in future" + ); + } + public function test_token_delete() { $editor = $this->getEditor(); From 3de55ee6454667e2d4b3cb866625a165ccb9aee3 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 30 Dec 2019 02:16:07 +0000 Subject: [PATCH 141/191] Linked new API token system into middleware Base logic in place but needs review and refactor to see if can better fit into Laravel using 'Guard' system. Currently has issues due to cookies in use from active session on API. --- app/Api/ApiToken.php | 10 ++++ app/Http/Kernel.php | 30 ++++++++-- app/Http/Middleware/ApiAuthenticate.php | 78 +++++++++++++++++++++++++ app/Http/Middleware/Authenticate.php | 29 +-------- app/Http/Middleware/ConfirmEmails.php | 60 +++++++++++++++++++ app/helpers.php | 5 -- resources/lang/en/errors.php | 8 +++ 7 files changed, 183 insertions(+), 37 deletions(-) create mode 100644 app/Http/Middleware/ApiAuthenticate.php create mode 100644 app/Http/Middleware/ConfirmEmails.php diff --git a/app/Api/ApiToken.php b/app/Api/ApiToken.php index 4ea12888e..cdcb33a7b 100644 --- a/app/Api/ApiToken.php +++ b/app/Api/ApiToken.php @@ -1,6 +1,8 @@ 'date:Y-m-d' ]; + + /** + * Get the user that this token belongs to. + */ + public function user(): BelongsTo + { + return $this->belongsTo(User::class); + } } diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index cd3fc83ec..64782fedc 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -1,21 +1,38 @@ [ 'throttle:60,1', + \BookStack\Http\Middleware\EncryptCookies::class, + \Illuminate\Session\Middleware\StartSession::class, + \BookStack\Http\Middleware\ApiAuthenticate::class, + \BookStack\Http\Middleware\ConfirmEmails::class, ], ]; @@ -47,7 +68,6 @@ class Kernel extends HttpKernel */ protected $routeMiddleware = [ 'auth' => \BookStack\Http\Middleware\Authenticate::class, - 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \BookStack\Http\Middleware\RedirectIfAuthenticated::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, diff --git a/app/Http/Middleware/ApiAuthenticate.php b/app/Http/Middleware/ApiAuthenticate.php new file mode 100644 index 000000000..3e68cb3ae --- /dev/null +++ b/app/Http/Middleware/ApiAuthenticate.php @@ -0,0 +1,78 @@ +cookies->has($sessionCookieName)) { +// $sessionCookie = $request->cookies->get($sessionCookieName); +// $sessionCookie = decrypt($sessionCookie, false); +// dd($sessionCookie); +// } + + // Return if the user is already found to be signed in via session-based auth. + // This is to make it easy to browser the API via browser after just logging into the system. + if (signedInUser()) { + return $next($request); + } + + $authToken = trim($request->header('Authorization', '')); + if (empty($authToken)) { + return $this->unauthorisedResponse(trans('errors.api_no_authorization_found')); + } + + if (strpos($authToken, ':') === false || strpos($authToken, 'Token ') !== 0) { + return $this->unauthorisedResponse(trans('errors.api_bad_authorization_format')); + } + + [$id, $secret] = explode(':', str_replace('Token ', '', $authToken)); + $token = ApiToken::query() + ->where('token_id', '=', $id) + ->with(['user'])->first(); + + if ($token === null) { + return $this->unauthorisedResponse(trans('errors.api_user_token_not_found')); + } + + if (!Hash::check($secret, $token->secret)) { + return $this->unauthorisedResponse(trans('errors.api_incorrect_token_secret')); + } + + if (!$token->user->can('access-api')) { + return $this->unauthorisedResponse(trans('errors.api_user_no_api_permission'), 403); + } + + auth()->login($token->user); + + return $next($request); + } + + /** + * Provide a standard API unauthorised response. + */ + protected function unauthorisedResponse(string $message, int $code = 401) + { + return response()->json([ + 'error' => [ + 'code' => $code, + 'message' => $message, + ] + ], 401); + } +} diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php index d840a9b2e..40acc254b 100644 --- a/app/Http/Middleware/Authenticate.php +++ b/app/Http/Middleware/Authenticate.php @@ -2,41 +2,16 @@ namespace BookStack\Http\Middleware; +use BookStack\Http\Request; use Closure; -use Illuminate\Contracts\Auth\Guard; class Authenticate { - /** - * The Guard implementation. - * @var Guard - */ - protected $auth; - - /** - * Create a new filter instance. - * @param Guard $auth - */ - public function __construct(Guard $auth) - { - $this->auth = $auth; - } - /** * Handle an incoming request. - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @return mixed */ - public function handle($request, Closure $next) + public function handle(Request $request, Closure $next) { - if ($this->auth->check()) { - $requireConfirmation = (setting('registration-confirmation') || setting('registration-restrict')); - if ($requireConfirmation && !$this->auth->user()->email_confirmed) { - return redirect('/register/confirm/awaiting'); - } - } - if (!hasAppAccess()) { if ($request->ajax()) { return response('Unauthorized.', 401); diff --git a/app/Http/Middleware/ConfirmEmails.php b/app/Http/Middleware/ConfirmEmails.php new file mode 100644 index 000000000..3700e9973 --- /dev/null +++ b/app/Http/Middleware/ConfirmEmails.php @@ -0,0 +1,60 @@ +auth = $auth; + } + + /** + * Handle an incoming request. + */ + public function handle(Request $request, Closure $next) + { + if ($this->auth->check()) { + $requireConfirmation = (setting('registration-confirmation') || setting('registration-restrict')); + if ($requireConfirmation && !$this->auth->user()->email_confirmed) { + return $this->errorResponse($request); + } + } + + return $next($request); + } + + /** + * Provide an error response for when the current user's email is not confirmed + * in a system which requires it. + */ + protected function errorResponse(Request $request) + { + if ($request->wantsJson()) { + return response()->json([ + 'error' => [ + 'code' => 401, + 'message' => trans('errors.email_confirmation_awaiting') + ] + ], 401); + } + + return redirect('/register/confirm/awaiting'); + } +} diff --git a/app/helpers.php b/app/helpers.php index 6211f41be..65da1853b 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -42,7 +42,6 @@ function user(): User /** * Check if current user is a signed in user. - * @return bool */ function signedInUser(): bool { @@ -51,7 +50,6 @@ function signedInUser(): bool /** * Check if the current user has general access. - * @return bool */ function hasAppAccess(): bool { @@ -62,9 +60,6 @@ function hasAppAccess(): bool * Check if the current user has a permission. * If an ownable element is passed in the jointPermissions are checked against * that particular item. - * @param string $permission - * @param Ownable $ownable - * @return bool */ function userCan(string $permission, Ownable $ownable = null): bool { diff --git a/resources/lang/en/errors.php b/resources/lang/en/errors.php index a7c591c5d..85c498f48 100644 --- a/resources/lang/en/errors.php +++ b/resources/lang/en/errors.php @@ -13,6 +13,7 @@ return [ 'email_already_confirmed' => 'Email has already been confirmed, Try logging in.', 'email_confirmation_invalid' => 'This confirmation token is not valid or has already been used, Please try registering again.', 'email_confirmation_expired' => 'The confirmation token has expired, A new confirmation email has been sent.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'LDAP access failed using anonymous bind', 'ldap_fail_authed' => 'LDAP access failed using given dn & password details', 'ldap_extension_not_installed' => 'LDAP PHP extension not installed', @@ -88,4 +89,11 @@ return [ 'app_down' => ':appName is down right now', 'back_soon' => 'It will be back up soon.', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + ]; From 349b4629bef25e4631c1024749726415507b2cd5 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 30 Dec 2019 14:51:28 +0000 Subject: [PATCH 142/191] Extracted API auth into guard Also implemented more elegant solution to allowing session auth for API routes; A new 'StartSessionIfCookieExists' middleware, which wraps the default 'StartSession' middleware will run for API routes which only sets up the session if a session cookie is found on the request. Also decrypts only the session cookie. Also cleaned some TokenController codeclimate warnings. --- app/Api/ApiToken.php | 10 ++ app/Api/ApiTokenGuard.php | 135 ++++++++++++++++++ app/Config/auth.php | 4 +- app/Exceptions/ApiAuthException.php | 17 +++ .../Controllers/UserApiTokenController.php | 19 +-- app/Http/Kernel.php | 5 +- app/Http/Middleware/ApiAuthenticate.php | 50 ++----- .../Middleware/StartSessionIfCookieExists.php | 39 +++++ app/Providers/AuthServiceProvider.php | 5 +- 9 files changed, 224 insertions(+), 60 deletions(-) create mode 100644 app/Api/ApiTokenGuard.php create mode 100644 app/Exceptions/ApiAuthException.php create mode 100644 app/Http/Middleware/StartSessionIfCookieExists.php diff --git a/app/Api/ApiToken.php b/app/Api/ApiToken.php index cdcb33a7b..523c3b8b8 100644 --- a/app/Api/ApiToken.php +++ b/app/Api/ApiToken.php @@ -3,6 +3,7 @@ use BookStack\Auth\User; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Support\Carbon; class ApiToken extends Model { @@ -18,4 +19,13 @@ class ApiToken extends Model { return $this->belongsTo(User::class); } + + /** + * Get the default expiry value for an API token. + * Set to 100 years from now. + */ + public static function defaultExpiry(): string + { + return Carbon::now()->addYears(100)->format('Y-m-d'); + } } diff --git a/app/Api/ApiTokenGuard.php b/app/Api/ApiTokenGuard.php new file mode 100644 index 000000000..b347e536a --- /dev/null +++ b/app/Api/ApiTokenGuard.php @@ -0,0 +1,135 @@ +request = $request; + } + + + /** + * @inheritDoc + */ + public function user() + { + // Return the user if we've already retrieved them. + // Effectively a request-instance cache for this method. + if (!is_null($this->user)) { + return $this->user; + } + + $user = null; + try { + $user = $this->getAuthorisedUserFromRequest(); + } catch (ApiAuthException $exception) { + $this->lastAuthException = $exception; + } + + $this->user = $user; + return $user; + } + + /** + * Determine if current user is authenticated. If not, throw an exception. + * + * @return \Illuminate\Contracts\Auth\Authenticatable + * + * @throws ApiAuthException + */ + public function authenticate() + { + if (! is_null($user = $this->user())) { + return $user; + } + + if ($this->lastAuthException) { + throw $this->lastAuthException; + } + + throw new ApiAuthException('Unauthorized'); + } + + /** + * Check the API token in the request and fetch a valid authorised user. + * @throws ApiAuthException + */ + protected function getAuthorisedUserFromRequest(): Authenticatable + { + $authToken = trim($this->request->headers->get('Authorization', '')); + if (empty($authToken)) { + throw new ApiAuthException(trans('errors.api_no_authorization_found')); + } + + if (strpos($authToken, ':') === false || strpos($authToken, 'Token ') !== 0) { + throw new ApiAuthException(trans('errors.api_bad_authorization_format')); + } + + [$id, $secret] = explode(':', str_replace('Token ', '', $authToken)); + $token = ApiToken::query() + ->where('token_id', '=', $id) + ->with(['user'])->first(); + + if ($token === null) { + throw new ApiAuthException(trans('errors.api_user_token_not_found')); + } + + if (!Hash::check($secret, $token->secret)) { + throw new ApiAuthException(trans('errors.api_incorrect_token_secret')); + } + + if (!$token->user->can('access-api')) { + throw new ApiAuthException(trans('errors.api_user_no_api_permission'), 403); + } + + return $token->user; + } + + /** + * @inheritDoc + */ + public function validate(array $credentials = []) + { + if (empty($credentials['id']) || empty($credentials['secret'])) { + return false; + } + + $token = ApiToken::query() + ->where('token_id', '=', $credentials['id']) + ->with(['user'])->first(); + + if ($token === null) { + return false; + } + + return Hash::check($credentials['secret'], $token->secret); + } + +} \ No newline at end of file diff --git a/app/Config/auth.php b/app/Config/auth.php index 5535a6f9c..b3e22c7e1 100644 --- a/app/Config/auth.php +++ b/app/Config/auth.php @@ -34,9 +34,7 @@ return [ ], 'api' => [ - 'driver' => 'token', - 'provider' => 'users', - 'hash' => false, + 'driver' => 'api-token', ], ], diff --git a/app/Exceptions/ApiAuthException.php b/app/Exceptions/ApiAuthException.php new file mode 100644 index 000000000..0851dfa4a --- /dev/null +++ b/app/Exceptions/ApiAuthException.php @@ -0,0 +1,17 @@ +findOrFail($userId); $secret = Str::random(32); - $expiry = $request->get('expires_at', null); - if (empty($expiry)) { - $expiry = Carbon::now()->addYears(100)->format('Y-m-d'); - } - $token = (new ApiToken())->forceFill([ 'name' => $request->get('name'), 'token_id' => Str::random(32), 'secret' => Hash::make($secret), 'user_id' => $user->id, - 'expires_at' => $expiry + 'expires_at' => $request->get('expires_at') ?: ApiToken::defaultExpiry(), ]); while (ApiToken::query()->where('token_id', '=', $token->token_id)->exists()) { @@ -59,7 +54,6 @@ class UserApiTokenController extends Controller } $token->save(); - $token->refresh(); session()->flash('api-token-secret:' . $token->id, $secret); $this->showSuccessNotification(trans('settings.user_api_token_create_success')); @@ -87,18 +81,17 @@ class UserApiTokenController extends Controller */ public function update(Request $request, int $userId, int $tokenId) { - $requestData = $this->validate($request, [ + $this->validate($request, [ 'name' => 'required|max:250', 'expires_at' => 'date_format:Y-m-d', ]); [$user, $token] = $this->checkPermissionAndFetchUserToken($userId, $tokenId); + $token->fill([ + 'name' => $request->get('name'), + 'expires_at' => $request->get('expires_at') ?: ApiToken::defaultExpiry(), + ])->save(); - if (empty($requestData['expires_at'])) { - $requestData['expires_at'] = Carbon::now()->addYears(100)->format('Y-m-d'); - } - - $token->fill($requestData)->save(); $this->showSuccessNotification(trans('settings.user_api_token_update_success')); return redirect($user->getEditUrl('/api-tokens/' . $token->id)); } diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 64782fedc..6a6e736b9 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -1,6 +1,5 @@ [ 'throttle:60,1', - \BookStack\Http\Middleware\EncryptCookies::class, - \Illuminate\Session\Middleware\StartSession::class, + \BookStack\Http\Middleware\StartSessionIfCookieExists::class, \BookStack\Http\Middleware\ApiAuthenticate::class, \BookStack\Http\Middleware\ConfirmEmails::class, ], diff --git a/app/Http/Middleware/ApiAuthenticate.php b/app/Http/Middleware/ApiAuthenticate.php index 3e68cb3ae..86fb83d58 100644 --- a/app/Http/Middleware/ApiAuthenticate.php +++ b/app/Http/Middleware/ApiAuthenticate.php @@ -2,10 +2,9 @@ namespace BookStack\Http\Middleware; -use BookStack\Api\ApiToken; +use BookStack\Exceptions\ApiAuthException; use BookStack\Http\Request; use Closure; -use Hash; class ApiAuthenticate { @@ -15,58 +14,29 @@ class ApiAuthenticate */ public function handle(Request $request, Closure $next) { - // TODO - Look to extract a lot of the logic here into a 'Guard' - // Ideally would like to be able to request API via browser without having to boot - // the session middleware (in Kernel). - -// $sessionCookieName = config('session.cookie'); -// if ($request->cookies->has($sessionCookieName)) { -// $sessionCookie = $request->cookies->get($sessionCookieName); -// $sessionCookie = decrypt($sessionCookie, false); -// dd($sessionCookie); -// } - // Return if the user is already found to be signed in via session-based auth. // This is to make it easy to browser the API via browser after just logging into the system. if (signedInUser()) { return $next($request); } - $authToken = trim($request->header('Authorization', '')); - if (empty($authToken)) { - return $this->unauthorisedResponse(trans('errors.api_no_authorization_found')); + // Set our api guard to be the default for this request lifecycle. + auth()->shouldUse('api'); + + // Validate the token and it's users API access + try { + auth()->authenticate(); + } catch (ApiAuthException $exception) { + return $this->unauthorisedResponse($exception->getMessage(), $exception->getCode()); } - if (strpos($authToken, ':') === false || strpos($authToken, 'Token ') !== 0) { - return $this->unauthorisedResponse(trans('errors.api_bad_authorization_format')); - } - - [$id, $secret] = explode(':', str_replace('Token ', '', $authToken)); - $token = ApiToken::query() - ->where('token_id', '=', $id) - ->with(['user'])->first(); - - if ($token === null) { - return $this->unauthorisedResponse(trans('errors.api_user_token_not_found')); - } - - if (!Hash::check($secret, $token->secret)) { - return $this->unauthorisedResponse(trans('errors.api_incorrect_token_secret')); - } - - if (!$token->user->can('access-api')) { - return $this->unauthorisedResponse(trans('errors.api_user_no_api_permission'), 403); - } - - auth()->login($token->user); - return $next($request); } /** * Provide a standard API unauthorised response. */ - protected function unauthorisedResponse(string $message, int $code = 401) + protected function unauthorisedResponse(string $message, int $code) { return response()->json([ 'error' => [ diff --git a/app/Http/Middleware/StartSessionIfCookieExists.php b/app/Http/Middleware/StartSessionIfCookieExists.php new file mode 100644 index 000000000..99553e294 --- /dev/null +++ b/app/Http/Middleware/StartSessionIfCookieExists.php @@ -0,0 +1,39 @@ +cookies->has($sessionCookieName)) { + $this->decryptSessionCookie($request, $sessionCookieName); + return parent::handle($request, $next); + } + + return $next($request); + } + + /** + * Attempt decryption of the session cookie. + */ + protected function decryptSessionCookie(Request $request, string $sessionCookieName) + { + try { + $sessionCookie = $request->cookies->get($sessionCookieName); + $sessionCookie = decrypt($sessionCookie, false); + $request->cookies->set($sessionCookieName, $sessionCookie); + } catch (Exception $e) { + // + } + } +} diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index 6e5b6ffde..ab7dd5195 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -3,6 +3,7 @@ namespace BookStack\Providers; use Auth; +use BookStack\Api\ApiTokenGuard; use BookStack\Auth\Access\LdapService; use Illuminate\Support\ServiceProvider; @@ -15,7 +16,9 @@ class AuthServiceProvider extends ServiceProvider */ public function boot() { - // + Auth::extend('api-token', function ($app, $name, array $config) { + return new ApiTokenGuard($app['request']); + }); } /** From 6f1b88a6a6402c7acfdd3e9bef72f50eb5e975c1 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 30 Dec 2019 15:46:12 +0000 Subject: [PATCH 143/191] Change email confirmation from own middle to trait Email confirmation middleware caused more mess than good, As caused priority issues and it depended on auth actions. Instead its now a trai used on auth middlewares. Also used 'EncryptCookies' middleware on API instead of custom decryption in custom middleware since we'd need to do replicate all the same actions anyway. Shouldn't have too much effect since it only actions over cookies that exist, of which none should be there for most API requests. Also split out some large guard functions to be a little more readable and appease codeclimate. --- app/Api/ApiTokenGuard.php | 36 ++++++++--- app/Http/Kernel.php | 23 +------ app/Http/Middleware/ApiAuthenticate.php | 10 +++- app/Http/Middleware/Authenticate.php | 8 ++- .../Middleware/ChecksForEmailConfirmation.php | 42 +++++++++++++ app/Http/Middleware/ConfirmEmails.php | 60 ------------------- .../Middleware/StartSessionIfCookieExists.php | 17 ------ 7 files changed, 86 insertions(+), 110 deletions(-) create mode 100644 app/Http/Middleware/ChecksForEmailConfirmation.php delete mode 100644 app/Http/Middleware/ConfirmEmails.php diff --git a/app/Api/ApiTokenGuard.php b/app/Api/ApiTokenGuard.php index b347e536a..cd9c3b178 100644 --- a/app/Api/ApiTokenGuard.php +++ b/app/Api/ApiTokenGuard.php @@ -33,8 +33,7 @@ class ApiTokenGuard implements Guard { $this->request = $request; } - - + /** * @inheritDoc */ @@ -84,6 +83,24 @@ class ApiTokenGuard implements Guard protected function getAuthorisedUserFromRequest(): Authenticatable { $authToken = trim($this->request->headers->get('Authorization', '')); + $this->validateTokenHeaderValue($authToken); + + [$id, $secret] = explode(':', str_replace('Token ', '', $authToken)); + $token = ApiToken::query() + ->where('token_id', '=', $id) + ->with(['user'])->first(); + + $this->validateToken($token, $secret); + + return $token->user; + } + + /** + * Validate the format of the token header value string. + * @throws ApiAuthException + */ + protected function validateTokenHeaderValue(string $authToken): void + { if (empty($authToken)) { throw new ApiAuthException(trans('errors.api_no_authorization_found')); } @@ -91,12 +108,15 @@ class ApiTokenGuard implements Guard if (strpos($authToken, ':') === false || strpos($authToken, 'Token ') !== 0) { throw new ApiAuthException(trans('errors.api_bad_authorization_format')); } + } - [$id, $secret] = explode(':', str_replace('Token ', '', $authToken)); - $token = ApiToken::query() - ->where('token_id', '=', $id) - ->with(['user'])->first(); - + /** + * Validate the given secret against the given token and ensure the token + * currently has access to the instance API. + * @throws ApiAuthException + */ + protected function validateToken(?ApiToken $token, string $secret): void + { if ($token === null) { throw new ApiAuthException(trans('errors.api_user_token_not_found')); } @@ -108,8 +128,6 @@ class ApiTokenGuard implements Guard if (!$token->user->can('access-api')) { throw new ApiAuthException(trans('errors.api_user_no_api_permission'), 403); } - - return $token->user; } /** diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 6a6e736b9..978583a7f 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -13,26 +13,6 @@ class Kernel extends HttpKernel \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \BookStack\Http\Middleware\TrimStrings::class, \BookStack\Http\Middleware\TrustProxies::class, - - ]; - - /** - * The priority ordering of middleware. - */ - protected $middlewarePriority = [ - \BookStack\Http\Middleware\EncryptCookies::class, - \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, - \Illuminate\Session\Middleware\StartSession::class, - \BookStack\Http\Middleware\StartSessionIfCookieExists::class, - \Illuminate\View\Middleware\ShareErrorsFromSession::class, - \Illuminate\Routing\Middleware\ThrottleRequests::class, - \BookStack\Http\Middleware\VerifyCsrfToken::class, - \Illuminate\Routing\Middleware\SubstituteBindings::class, - \BookStack\Http\Middleware\Localization::class, - \BookStack\Http\Middleware\GlobalViewData::class, - \BookStack\Http\Middleware\Authenticate::class, - \BookStack\Http\Middleware\ApiAuthenticate::class, - \BookStack\Http\Middleware\ConfirmEmails::class, ]; /** @@ -50,13 +30,12 @@ class Kernel extends HttpKernel \BookStack\Http\Middleware\VerifyCsrfToken::class, \BookStack\Http\Middleware\Localization::class, \BookStack\Http\Middleware\GlobalViewData::class, - \BookStack\Http\Middleware\ConfirmEmails::class, ], 'api' => [ 'throttle:60,1', + \BookStack\Http\Middleware\EncryptCookies::class, \BookStack\Http\Middleware\StartSessionIfCookieExists::class, \BookStack\Http\Middleware\ApiAuthenticate::class, - \BookStack\Http\Middleware\ConfirmEmails::class, ], ]; diff --git a/app/Http/Middleware/ApiAuthenticate.php b/app/Http/Middleware/ApiAuthenticate.php index 86fb83d58..c7fed405c 100644 --- a/app/Http/Middleware/ApiAuthenticate.php +++ b/app/Http/Middleware/ApiAuthenticate.php @@ -3,11 +3,12 @@ namespace BookStack\Http\Middleware; use BookStack\Exceptions\ApiAuthException; -use BookStack\Http\Request; use Closure; +use Illuminate\Http\Request; class ApiAuthenticate { + use ChecksForEmailConfirmation; /** * Handle an incoming request. @@ -17,6 +18,9 @@ class ApiAuthenticate // Return if the user is already found to be signed in via session-based auth. // This is to make it easy to browser the API via browser after just logging into the system. if (signedInUser()) { + if ($this->awaitingEmailConfirmation()) { + return $this->emailConfirmationErrorResponse($request); + } return $next($request); } @@ -30,6 +34,10 @@ class ApiAuthenticate return $this->unauthorisedResponse($exception->getMessage(), $exception->getCode()); } + if ($this->awaitingEmailConfirmation()) { + return $this->emailConfirmationErrorResponse($request); + } + return $next($request); } diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php index 40acc254b..a171a8a2d 100644 --- a/app/Http/Middleware/Authenticate.php +++ b/app/Http/Middleware/Authenticate.php @@ -2,16 +2,22 @@ namespace BookStack\Http\Middleware; -use BookStack\Http\Request; use Closure; +use Illuminate\Http\Request; class Authenticate { + use ChecksForEmailConfirmation; + /** * Handle an incoming request. */ public function handle(Request $request, Closure $next) { + if ($this->awaitingEmailConfirmation()) { + return $this->emailConfirmationErrorResponse($request); + } + if (!hasAppAccess()) { if ($request->ajax()) { return response('Unauthorized.', 401); diff --git a/app/Http/Middleware/ChecksForEmailConfirmation.php b/app/Http/Middleware/ChecksForEmailConfirmation.php new file mode 100644 index 000000000..684a7e9bc --- /dev/null +++ b/app/Http/Middleware/ChecksForEmailConfirmation.php @@ -0,0 +1,42 @@ +check()) { + $requireConfirmation = (setting('registration-confirmation') || setting('registration-restrict')); + if ($requireConfirmation && !auth()->user()->email_confirmed) { + return true; + } + } + + return false; + } + + /** + * Provide an error response for when the current user's email is not confirmed + * in a system which requires it. + */ + protected function emailConfirmationErrorResponse(Request $request) + { + if ($request->wantsJson()) { + return response()->json([ + 'error' => [ + 'code' => 401, + 'message' => trans('errors.email_confirmation_awaiting') + ] + ], 401); + } + + return redirect('/register/confirm/awaiting'); + } +} \ No newline at end of file diff --git a/app/Http/Middleware/ConfirmEmails.php b/app/Http/Middleware/ConfirmEmails.php deleted file mode 100644 index 3700e9973..000000000 --- a/app/Http/Middleware/ConfirmEmails.php +++ /dev/null @@ -1,60 +0,0 @@ -auth = $auth; - } - - /** - * Handle an incoming request. - */ - public function handle(Request $request, Closure $next) - { - if ($this->auth->check()) { - $requireConfirmation = (setting('registration-confirmation') || setting('registration-restrict')); - if ($requireConfirmation && !$this->auth->user()->email_confirmed) { - return $this->errorResponse($request); - } - } - - return $next($request); - } - - /** - * Provide an error response for when the current user's email is not confirmed - * in a system which requires it. - */ - protected function errorResponse(Request $request) - { - if ($request->wantsJson()) { - return response()->json([ - 'error' => [ - 'code' => 401, - 'message' => trans('errors.email_confirmation_awaiting') - ] - ], 401); - } - - return redirect('/register/confirm/awaiting'); - } -} diff --git a/app/Http/Middleware/StartSessionIfCookieExists.php b/app/Http/Middleware/StartSessionIfCookieExists.php index 99553e294..456508d98 100644 --- a/app/Http/Middleware/StartSessionIfCookieExists.php +++ b/app/Http/Middleware/StartSessionIfCookieExists.php @@ -2,9 +2,7 @@ namespace BookStack\Http\Middleware; -use BookStack\Http\Request; use Closure; -use Exception; use Illuminate\Session\Middleware\StartSession as Middleware; class StartSessionIfCookieExists extends Middleware @@ -16,24 +14,9 @@ class StartSessionIfCookieExists extends Middleware { $sessionCookieName = config('session.cookie'); if ($request->cookies->has($sessionCookieName)) { - $this->decryptSessionCookie($request, $sessionCookieName); return parent::handle($request, $next); } return $next($request); } - - /** - * Attempt decryption of the session cookie. - */ - protected function decryptSessionCookie(Request $request, string $sessionCookieName) - { - try { - $sessionCookie = $request->cookies->get($sessionCookieName); - $sessionCookie = decrypt($sessionCookie, false); - $request->cookies->set($sessionCookieName, $sessionCookie); - } catch (Exception $e) { - // - } - } } From 3d11cba223cad16ad13faee010259e97b05dcee9 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 30 Dec 2019 19:42:46 +0000 Subject: [PATCH 144/191] Added testing coverage to API token auth --- app/Api/ApiTokenGuard.php | 7 ++ app/Auth/Role.php | 2 +- app/Http/Middleware/ApiAuthenticate.php | 2 +- .../Middleware/ChecksForEmailConfirmation.php | 4 +- database/seeds/DummyContentSeeder.php | 14 ++++ tests/Api/ApiAuthTest.php | 82 +++++++++++++++++++ tests/TestsApi.php | 16 ++++ tests/User/UserApiTokenTest.php | 6 +- 8 files changed, 126 insertions(+), 7 deletions(-) create mode 100644 tests/Api/ApiAuthTest.php create mode 100644 tests/TestsApi.php diff --git a/app/Api/ApiTokenGuard.php b/app/Api/ApiTokenGuard.php index cd9c3b178..ba0b4b5dd 100644 --- a/app/Api/ApiTokenGuard.php +++ b/app/Api/ApiTokenGuard.php @@ -150,4 +150,11 @@ class ApiTokenGuard implements Guard return Hash::check($credentials['secret'], $token->secret); } + /** + * "Log out" the currently authenticated user. + */ + public function logout() + { + $this->user = null; + } } \ No newline at end of file diff --git a/app/Auth/Role.php b/app/Auth/Role.php index 3342ef5a8..df9b1cea9 100644 --- a/app/Auth/Role.php +++ b/app/Auth/Role.php @@ -72,7 +72,7 @@ class Role extends Model */ public function detachPermission(RolePermission $permission) { - $this->permissions()->detach($permission->id); + $this->permissions()->detach([$permission->id]); } /** diff --git a/app/Http/Middleware/ApiAuthenticate.php b/app/Http/Middleware/ApiAuthenticate.php index c7fed405c..fffbd9ef6 100644 --- a/app/Http/Middleware/ApiAuthenticate.php +++ b/app/Http/Middleware/ApiAuthenticate.php @@ -35,7 +35,7 @@ class ApiAuthenticate } if ($this->awaitingEmailConfirmation()) { - return $this->emailConfirmationErrorResponse($request); + return $this->emailConfirmationErrorResponse($request, true); } return $next($request); diff --git a/app/Http/Middleware/ChecksForEmailConfirmation.php b/app/Http/Middleware/ChecksForEmailConfirmation.php index 684a7e9bc..df75c2f33 100644 --- a/app/Http/Middleware/ChecksForEmailConfirmation.php +++ b/app/Http/Middleware/ChecksForEmailConfirmation.php @@ -26,9 +26,9 @@ trait ChecksForEmailConfirmation * Provide an error response for when the current user's email is not confirmed * in a system which requires it. */ - protected function emailConfirmationErrorResponse(Request $request) + protected function emailConfirmationErrorResponse(Request $request, bool $forceJson = false) { - if ($request->wantsJson()) { + if ($request->wantsJson() || $forceJson) { return response()->json([ 'error' => [ 'code' => 401, diff --git a/database/seeds/DummyContentSeeder.php b/database/seeds/DummyContentSeeder.php index deb1aa11c..6d902a196 100644 --- a/database/seeds/DummyContentSeeder.php +++ b/database/seeds/DummyContentSeeder.php @@ -1,6 +1,8 @@ create($byData); $largeBook->shelves()->attach($shelves->pluck('id')); + // Assign API permission to editor role and create an API key + $apiPermission = RolePermission::getByName('access-api'); + $editorRole->attachPermission($apiPermission); + $token = (new ApiToken())->forceFill([ + 'user_id' => $editorUser->id, + 'name' => 'Testing API key', + 'expires_at' => ApiToken::defaultExpiry(), + 'secret' => Hash::make('password'), + 'token_id' => 'apitoken', + ]); + $token->save(); + app(PermissionService::class)->buildJointPermissions(); app(SearchService::class)->indexAllEntities(); } diff --git a/tests/Api/ApiAuthTest.php b/tests/Api/ApiAuthTest.php new file mode 100644 index 000000000..ef975d556 --- /dev/null +++ b/tests/Api/ApiAuthTest.php @@ -0,0 +1,82 @@ +getViewer(); + $resp = $this->get($this->endpoint); + $resp->assertStatus(401); + + $this->actingAs($viewer, 'web'); + + $resp = $this->get($this->endpoint); + $resp->assertStatus(200); + } + + public function test_no_token_throws_error() + { + $resp = $this->get($this->endpoint); + $resp->assertStatus(401); + $resp->assertJson($this->errorResponse("No authorization token found on the request", 401)); + } + + public function test_bad_token_format_throws_error() + { + $resp = $this->get($this->endpoint, ['Authorization' => "Token abc123"]); + $resp->assertStatus(401); + $resp->assertJson($this->errorResponse("An authorization token was found on the request but the format appeared incorrect", 401)); + } + + public function test_token_with_non_existing_id_throws_error() + { + $resp = $this->get($this->endpoint, ['Authorization' => "Token abc:123"]); + $resp->assertStatus(401); + $resp->assertJson($this->errorResponse("No matching API token was found for the provided authorization token", 401)); + } + + public function test_token_with_bad_secret_value_throws_error() + { + $resp = $this->get($this->endpoint, ['Authorization' => "Token {$this->apiTokenId}:123"]); + $resp->assertStatus(401); + $resp->assertJson($this->errorResponse("The secret provided for the given used API token is incorrect", 401)); + } + + public function test_api_access_permission_required_to_access_api() + { + $resp = $this->get($this->endpoint, ['Authorization' => "Token {$this->apiTokenId}:{$this->apiTokenSecret}"]); + $resp->assertStatus(200); + auth()->logout(); + + $accessApiPermission = RolePermission::getByName('access-api'); + $editorRole = $this->getEditor()->roles()->first(); + $editorRole->detachPermission($accessApiPermission); + + $resp = $this->get($this->endpoint, ['Authorization' => "Token {$this->apiTokenId}:{$this->apiTokenSecret}"]); + $resp->assertJson($this->errorResponse("The owner of the used API token does not have permission to make API calls", 403)); + } + + + public function test_email_confirmation_checked_on_auth_requets() + { + $editor = $this->getEditor(); + $editor->email_confirmed = false; + $editor->save(); + + // Set settings and get user instance + $this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true']); + + $resp = $this->get($this->endpoint, ['Authorization' => "Token {$this->apiTokenId}:{$this->apiTokenSecret}"]); + $resp->assertStatus(401); + $resp->assertJson($this->errorResponse("The email address for the account in use needs to be confirmed", 401)); + } + +} \ No newline at end of file diff --git a/tests/TestsApi.php b/tests/TestsApi.php new file mode 100644 index 000000000..2bc751f54 --- /dev/null +++ b/tests/TestsApi.php @@ -0,0 +1,16 @@ + ["code" => $code, "message" => $messge]]; + } + +} \ No newline at end of file diff --git a/tests/User/UserApiTokenTest.php b/tests/User/UserApiTokenTest.php index 460752fc2..7787e34fa 100644 --- a/tests/User/UserApiTokenTest.php +++ b/tests/User/UserApiTokenTest.php @@ -14,7 +14,7 @@ class UserApiTokenTest extends TestCase public function test_tokens_section_not_visible_without_access_api_permission() { - $user = $this->getEditor(); + $user = $this->getViewer(); $resp = $this->actingAs($user)->get($user->getEditUrl()); $resp->assertDontSeeText('API Tokens'); @@ -30,9 +30,9 @@ class UserApiTokenTest extends TestCase { $viewer = $this->getViewer(); $editor = $this->getEditor(); - $this->giveUserPermissions($editor, ['users-manage']); + $this->giveUserPermissions($viewer, ['users-manage']); - $resp = $this->actingAs($editor)->get($viewer->getEditUrl()); + $resp = $this->actingAs($viewer)->get($editor->getEditUrl()); $resp->assertSeeText('API Tokens'); $resp->assertDontSeeText('Create Token'); } From 3cacda6762bca67ae2beeb44cdcff39ad6d7ec60 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 30 Dec 2019 19:51:41 +0000 Subject: [PATCH 145/191] Added expiry checking to API token auth - Added test to cover to ensure its checked going forward --- app/Api/ApiTokenGuard.php | 6 ++++++ resources/lang/en/errors.php | 1 + tests/Api/ApiAuthTest.php | 24 ++++++++++++++++++++---- tests/TestsApi.php | 7 +++++++ 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/app/Api/ApiTokenGuard.php b/app/Api/ApiTokenGuard.php index ba0b4b5dd..e0a50ebe3 100644 --- a/app/Api/ApiTokenGuard.php +++ b/app/Api/ApiTokenGuard.php @@ -6,6 +6,7 @@ use BookStack\Exceptions\ApiAuthException; use Illuminate\Auth\GuardHelpers; use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\Guard; +use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Hash; use Symfony\Component\HttpFoundation\Request; @@ -125,6 +126,11 @@ class ApiTokenGuard implements Guard throw new ApiAuthException(trans('errors.api_incorrect_token_secret')); } + $now = Carbon::now(); + if ($token->expires_at <= $now) { + throw new ApiAuthException(trans('errors.api_user_token_expired'), 403); + } + if (!$token->user->can('access-api')) { throw new ApiAuthException(trans('errors.api_user_no_api_permission'), 403); } diff --git a/resources/lang/en/errors.php b/resources/lang/en/errors.php index 85c498f48..bb7b6148c 100644 --- a/resources/lang/en/errors.php +++ b/resources/lang/en/errors.php @@ -95,5 +95,6 @@ return [ 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', ]; diff --git a/tests/Api/ApiAuthTest.php b/tests/Api/ApiAuthTest.php index ef975d556..30d7f4ead 100644 --- a/tests/Api/ApiAuthTest.php +++ b/tests/Api/ApiAuthTest.php @@ -3,6 +3,7 @@ namespace Tests; use BookStack\Auth\Permissions\RolePermission; +use Carbon\Carbon; class ApiAuthTest extends TestCase { @@ -52,7 +53,7 @@ class ApiAuthTest extends TestCase public function test_api_access_permission_required_to_access_api() { - $resp = $this->get($this->endpoint, ['Authorization' => "Token {$this->apiTokenId}:{$this->apiTokenSecret}"]); + $resp = $this->get($this->endpoint, $this->apiAuthHeader()); $resp->assertStatus(200); auth()->logout(); @@ -60,12 +61,27 @@ class ApiAuthTest extends TestCase $editorRole = $this->getEditor()->roles()->first(); $editorRole->detachPermission($accessApiPermission); - $resp = $this->get($this->endpoint, ['Authorization' => "Token {$this->apiTokenId}:{$this->apiTokenSecret}"]); + $resp = $this->get($this->endpoint, $this->apiAuthHeader()); $resp->assertJson($this->errorResponse("The owner of the used API token does not have permission to make API calls", 403)); } + public function test_token_expiry_checked() + { + $editor = $this->getEditor(); + $token = $editor->apiTokens()->first(); - public function test_email_confirmation_checked_on_auth_requets() + $resp = $this->get($this->endpoint, $this->apiAuthHeader()); + $resp->assertStatus(200); + auth()->logout(); + + $token->expires_at = Carbon::now()->subDay()->format('Y-m-d'); + $token->save(); + + $resp = $this->get($this->endpoint, $this->apiAuthHeader()); + $resp->assertJson($this->errorResponse("The authorization token used has expired", 403)); + } + + public function test_email_confirmation_checked_using_api_auth() { $editor = $this->getEditor(); $editor->email_confirmed = false; @@ -74,7 +90,7 @@ class ApiAuthTest extends TestCase // Set settings and get user instance $this->setSettings(['registration-enabled' => 'true', 'registration-confirmation' => 'true']); - $resp = $this->get($this->endpoint, ['Authorization' => "Token {$this->apiTokenId}:{$this->apiTokenSecret}"]); + $resp = $this->get($this->endpoint, $this->apiAuthHeader()); $resp->assertStatus(401); $resp->assertJson($this->errorResponse("The email address for the account in use needs to be confirmed", 401)); } diff --git a/tests/TestsApi.php b/tests/TestsApi.php index 2bc751f54..4afcbdf22 100644 --- a/tests/TestsApi.php +++ b/tests/TestsApi.php @@ -13,4 +13,11 @@ trait TestsApi return ["error" => ["code" => $code, "message" => $messge]]; } + protected function apiAuthHeader() + { + return [ + "Authorization" => "Token {$this->apiTokenId}:{$this->apiTokenSecret}" + ]; + } + } \ No newline at end of file From 55abf7be241e0a81f1460da70fcebb7d8530d950 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 30 Dec 2019 20:48:23 +0000 Subject: [PATCH 146/191] Added tests to cover API config and listing code --- tests/Api/ApiConfigTest.php | 47 +++++++++++++++++++++++++++ tests/Api/ApiListingTest.php | 61 ++++++++++++++++++++++++++++++++++++ tests/TestsApi.php | 21 +++++++++++-- 3 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 tests/Api/ApiConfigTest.php create mode 100644 tests/Api/ApiListingTest.php diff --git a/tests/Api/ApiConfigTest.php b/tests/Api/ApiConfigTest.php new file mode 100644 index 000000000..99b063c69 --- /dev/null +++ b/tests/Api/ApiConfigTest.php @@ -0,0 +1,47 @@ +actingAsApiEditor(); + + config()->set(['api.default_item_count' => 5]); + $resp = $this->get($this->endpoint); + $resp->assertJsonCount(5, 'data'); + + config()->set(['api.default_item_count' => 1]); + $resp = $this->get($this->endpoint); + $resp->assertJsonCount(1, 'data'); + } + + public function test_default_item_count_does_not_limit_count_param() + { + $this->actingAsApiEditor(); + config()->set(['api.default_item_count' => 1]); + $resp = $this->get($this->endpoint . '?count=5'); + $resp->assertJsonCount(5, 'data'); + } + + public function test_max_item_count_limits_listing_requests() + { + $this->actingAsApiEditor(); + + config()->set(['api.max_item_count' => 2]); + $resp = $this->get($this->endpoint); + $resp->assertJsonCount(2, 'data'); + + $resp = $this->get($this->endpoint . '?count=5'); + $resp->assertJsonCount(2, 'data'); + } + +} \ No newline at end of file diff --git a/tests/Api/ApiListingTest.php b/tests/Api/ApiListingTest.php new file mode 100644 index 000000000..70d1140d7 --- /dev/null +++ b/tests/Api/ApiListingTest.php @@ -0,0 +1,61 @@ +actingAsApiEditor(); + $bookCount = min(Book::visible()->count(), 100); + + $resp = $this->get($this->endpoint); + $resp->assertJsonCount($bookCount, 'data'); + + $resp = $this->get($this->endpoint . '?count=1'); + $resp->assertJsonCount(1, 'data'); + } + + public function test_offset_parameter() + { + $this->actingAsApiEditor(); + $books = Book::visible()->orderBy('id')->take(3)->get(); + + $resp = $this->get($this->endpoint . '?count=1'); + $resp->assertJsonMissing(['name' => $books[1]->name ]); + + $resp = $this->get($this->endpoint . '?count=1&offset=1000'); + $resp->assertJsonCount(0, 'data'); + } + + public function test_sort_parameter() + { + $this->actingAsApiEditor(); + + $sortChecks = [ + '-id' => Book::visible()->orderBy('id', 'desc')->first(), + '+name' => Book::visible()->orderBy('name', 'asc')->first(), + 'name' => Book::visible()->orderBy('name', 'asc')->first(), + '-name' => Book::visible()->orderBy('name', 'desc')->first() + ]; + + foreach ($sortChecks as $sortOption => $result) { + $resp = $this->get($this->endpoint . '?count=1&sort=' . $sortOption); + $resp->assertJson(['data' => [ + [ + 'id' => $result->id, + 'name' => $result->name, + ] + ]]); + } + } + +} \ No newline at end of file diff --git a/tests/TestsApi.php b/tests/TestsApi.php index 4afcbdf22..0bb10a4cc 100644 --- a/tests/TestsApi.php +++ b/tests/TestsApi.php @@ -8,12 +8,27 @@ trait TestsApi protected $apiTokenId = 'apitoken'; protected $apiTokenSecret = 'password'; - protected function errorResponse(string $messge, int $code) + /** + * Set the API editor role as the current user via the API driver. + */ + protected function actingAsApiEditor() { - return ["error" => ["code" => $code, "message" => $messge]]; + $this->actingAs($this->getEditor(), 'api'); + return $this; } - protected function apiAuthHeader() + /** + * Format the given items into a standardised error format. + */ + protected function errorResponse(string $message, int $code): array + { + return ["error" => ["code" => $code, "message" => $message]]; + } + + /** + * Get an approved API auth header. + */ + protected function apiAuthHeader(): array { return [ "Authorization" => "Token {$this->apiTokenId}:{$this->apiTokenSecret}" From a7a97a53f1d7b9e180d9296cec02c42d0a987a89 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Wed, 1 Jan 2020 16:33:47 +0000 Subject: [PATCH 147/191] Added API listing filtering & cleaned ApiAuthenticate returns API listing endpoint filter can be found via &filter[name]=my+book query parameters. There are a range of operators that can be used such as &filter[id:gte]=4 --- app/Api/ListingResponseBuilder.php | 65 +++++++++++++++++-- app/Exceptions/ApiAuthException.php | 12 +--- app/Exceptions/UnauthorizedException.php | 17 +++++ app/Http/Controllers/Api/ApiController.php | 2 +- .../Controllers/Api/BooksApiController.php | 29 +++++++++ app/Http/Middleware/ApiAuthenticate.php | 40 +++++++----- app/Http/Middleware/Authenticate.php | 18 +++++ .../Middleware/ChecksForEmailConfirmation.php | 30 ++++----- tests/Api/ApiListingTest.php | 26 ++++++++ 9 files changed, 186 insertions(+), 53 deletions(-) create mode 100644 app/Exceptions/UnauthorizedException.php diff --git a/app/Api/ListingResponseBuilder.php b/app/Api/ListingResponseBuilder.php index 279fabd5d..2fa5644c3 100644 --- a/app/Api/ListingResponseBuilder.php +++ b/app/Api/ListingResponseBuilder.php @@ -2,19 +2,32 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; +use Illuminate\Http\Request; class ListingResponseBuilder { protected $query; + protected $request; protected $fields; + protected $filterOperators = [ + 'eq' => '=', + 'ne' => '!=', + 'gt' => '>', + 'lt' => '<', + 'gte' => '>=', + 'lte' => '<=', + 'like' => 'like' + ]; + /** * ListingResponseBuilder constructor. */ - public function __construct(Builder $query, array $fields) + public function __construct(Builder $query, Request $request, array $fields) { $this->query = $query; + $this->request = $request; $this->fields = $fields; } @@ -23,8 +36,8 @@ class ListingResponseBuilder */ public function toResponse() { - $total = $this->query->count(); $data = $this->fetchData(); + $total = $this->query->count(); return response()->json([ 'data' => $data, @@ -39,11 +52,51 @@ class ListingResponseBuilder { $this->applyCountAndOffset($this->query); $this->applySorting($this->query); - // TODO - Apply filtering + $this->applyFiltering($this->query); return $this->query->get($this->fields); } + /** + * Apply any filtering operations found in the request. + */ + protected function applyFiltering(Builder $query) + { + $requestFilters = $this->request->get('filter', []); + if (!is_array($requestFilters)) { + return; + } + + $queryFilters = collect($requestFilters)->map(function ($value, $key) { + return $this->requestFilterToQueryFilter($key, $value); + })->filter(function ($value) { + return !is_null($value); + })->values()->toArray(); + + $query->where($queryFilters); + } + + /** + * Convert a request filter query key/value pair into a [field, op, value] where condition. + */ + protected function requestFilterToQueryFilter($fieldKey, $value): ?array + { + $splitKey = explode(':', $fieldKey); + $field = $splitKey[0]; + $filterOperator = $splitKey[1] ?? 'eq'; + + if (!in_array($field, $this->fields)) { + return null; + } + + if (!in_array($filterOperator, array_keys($this->filterOperators))) { + $filterOperator = 'eq'; + } + + $queryOperator = $this->filterOperators[$filterOperator]; + return [$field, $queryOperator, $value]; + } + /** * Apply sorting operations to the query from given parameters * otherwise falling back to the first given field, ascending. @@ -53,7 +106,7 @@ class ListingResponseBuilder $defaultSortName = $this->fields[0]; $direction = 'asc'; - $sort = request()->get('sort', ''); + $sort = $this->request->get('sort', ''); if (strpos($sort, '-') === 0) { $direction = 'desc'; } @@ -72,9 +125,9 @@ class ListingResponseBuilder */ protected function applyCountAndOffset(Builder $query) { - $offset = max(0, request()->get('offset', 0)); + $offset = max(0, $this->request->get('offset', 0)); $maxCount = config('api.max_item_count'); - $count = request()->get('count', config('api.default_item_count')); + $count = $this->request->get('count', config('api.default_item_count')); $count = max(min($maxCount, $count), 1); $query->skip($offset)->take($count); diff --git a/app/Exceptions/ApiAuthException.php b/app/Exceptions/ApiAuthException.php index 0851dfa4a..cc68ba8cf 100644 --- a/app/Exceptions/ApiAuthException.php +++ b/app/Exceptions/ApiAuthException.php @@ -2,16 +2,6 @@ namespace BookStack\Exceptions; -use Exception; +class ApiAuthException extends UnauthorizedException { -class ApiAuthException extends Exception -{ - - /** - * ApiAuthException constructor. - */ - public function __construct($message, $code = 401) - { - parent::__construct($message, $code); - } } \ No newline at end of file diff --git a/app/Exceptions/UnauthorizedException.php b/app/Exceptions/UnauthorizedException.php new file mode 100644 index 000000000..525b431c7 --- /dev/null +++ b/app/Exceptions/UnauthorizedException.php @@ -0,0 +1,17 @@ +toResponse(); } } \ No newline at end of file diff --git a/app/Http/Controllers/Api/BooksApiController.php b/app/Http/Controllers/Api/BooksApiController.php index d23aaf025..3943b773a 100644 --- a/app/Http/Controllers/Api/BooksApiController.php +++ b/app/Http/Controllers/Api/BooksApiController.php @@ -4,6 +4,15 @@ use BookStack\Entities\Book; class BooksApiController extends ApiController { + public $validation = [ + 'create' => [ + // TODO + ], + 'update' => [ + // TODO + ], + ]; + /** * Get a listing of books visible to the user. */ @@ -15,4 +24,24 @@ class BooksApiController extends ApiController 'restricted', 'image_id', ]); } + + public function create() + { + // TODO - + } + + public function read() + { + // TODO - + } + + public function update() + { + // TODO - + } + + public function delete() + { + // TODO - + } } \ No newline at end of file diff --git a/app/Http/Middleware/ApiAuthenticate.php b/app/Http/Middleware/ApiAuthenticate.php index fffbd9ef6..655334450 100644 --- a/app/Http/Middleware/ApiAuthenticate.php +++ b/app/Http/Middleware/ApiAuthenticate.php @@ -2,7 +2,7 @@ namespace BookStack\Http\Middleware; -use BookStack\Exceptions\ApiAuthException; +use BookStack\Exceptions\UnauthorizedException; use Closure; use Illuminate\Http\Request; @@ -14,31 +14,37 @@ class ApiAuthenticate * Handle an incoming request. */ public function handle(Request $request, Closure $next) + { + // Validate the token and it's users API access + try { + $this->ensureAuthorizedBySessionOrToken(); + } catch (UnauthorizedException $exception) { + return $this->unauthorisedResponse($exception->getMessage(), $exception->getCode()); + } + + return $next($request); + } + + /** + * Ensure the current user can access authenticated API routes, either via existing session + * authentication or via API Token authentication. + * @throws UnauthorizedException + */ + protected function ensureAuthorizedBySessionOrToken(): void { // Return if the user is already found to be signed in via session-based auth. // This is to make it easy to browser the API via browser after just logging into the system. if (signedInUser()) { - if ($this->awaitingEmailConfirmation()) { - return $this->emailConfirmationErrorResponse($request); - } - return $next($request); + $this->ensureEmailConfirmedIfRequested(); + return; } // Set our api guard to be the default for this request lifecycle. auth()->shouldUse('api'); // Validate the token and it's users API access - try { - auth()->authenticate(); - } catch (ApiAuthException $exception) { - return $this->unauthorisedResponse($exception->getMessage(), $exception->getCode()); - } - - if ($this->awaitingEmailConfirmation()) { - return $this->emailConfirmationErrorResponse($request, true); - } - - return $next($request); + auth()->authenticate(); + $this->ensureEmailConfirmedIfRequested(); } /** @@ -51,6 +57,6 @@ class ApiAuthenticate 'code' => $code, 'message' => $message, ] - ], 401); + ], $code); } } diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php index a171a8a2d..9a8affa88 100644 --- a/app/Http/Middleware/Authenticate.php +++ b/app/Http/Middleware/Authenticate.php @@ -28,4 +28,22 @@ class Authenticate return $next($request); } + + /** + * Provide an error response for when the current user's email is not confirmed + * in a system which requires it. + */ + protected function emailConfirmationErrorResponse(Request $request) + { + if ($request->wantsJson()) { + return response()->json([ + 'error' => [ + 'code' => 401, + 'message' => trans('errors.email_confirmation_awaiting') + ] + ], 401); + } + + return redirect('/register/confirm/awaiting'); + } } diff --git a/app/Http/Middleware/ChecksForEmailConfirmation.php b/app/Http/Middleware/ChecksForEmailConfirmation.php index df75c2f33..4b1732810 100644 --- a/app/Http/Middleware/ChecksForEmailConfirmation.php +++ b/app/Http/Middleware/ChecksForEmailConfirmation.php @@ -2,10 +2,22 @@ namespace BookStack\Http\Middleware; +use BookStack\Exceptions\UnauthorizedException; use Illuminate\Http\Request; trait ChecksForEmailConfirmation { + /** + * Check if the current user has a confirmed email if the instance deems it as required. + * Throws if confirmation is required by the user. + * @throws UnauthorizedException + */ + protected function ensureEmailConfirmedIfRequested() + { + if ($this->awaitingEmailConfirmation()) { + throw new UnauthorizedException(trans('errors.email_confirmation_awaiting')); + } + } /** * Check if email confirmation is required and the current user is awaiting confirmation. @@ -21,22 +33,4 @@ trait ChecksForEmailConfirmation return false; } - - /** - * Provide an error response for when the current user's email is not confirmed - * in a system which requires it. - */ - protected function emailConfirmationErrorResponse(Request $request, bool $forceJson = false) - { - if ($request->wantsJson() || $forceJson) { - return response()->json([ - 'error' => [ - 'code' => 401, - 'message' => trans('errors.email_confirmation_awaiting') - ] - ], 401); - } - - return redirect('/register/confirm/awaiting'); - } } \ No newline at end of file diff --git a/tests/Api/ApiListingTest.php b/tests/Api/ApiListingTest.php index 70d1140d7..26014cdec 100644 --- a/tests/Api/ApiListingTest.php +++ b/tests/Api/ApiListingTest.php @@ -58,4 +58,30 @@ class ApiAuthTest extends TestCase } } + public function test_filter_parameter() + { + $this->actingAsApiEditor(); + $book = Book::visible()->first(); + $nameSubstr = substr($book->name, 0, 4); + $encodedNameSubstr = rawurlencode($nameSubstr); + + $filterChecks = [ + // Test different types of filter + "filter[id]={$book->id}" => 1, + "filter[id:ne]={$book->id}" => Book::visible()->where('id', '!=', $book->id)->count(), + "filter[id:gt]={$book->id}" => Book::visible()->where('id', '>', $book->id)->count(), + "filter[id:gte]={$book->id}" => Book::visible()->where('id', '>=', $book->id)->count(), + "filter[id:lt]={$book->id}" => Book::visible()->where('id', '<', $book->id)->count(), + "filter[name:like]={$encodedNameSubstr}%" => Book::visible()->where('name', 'like', $nameSubstr . '%')->count(), + + // Test mulitple filters 'and' together + "filter[id]={$book->id}&filter[name]=random_non_existing_string" => 0, + ]; + + foreach ($filterChecks as $filterOption => $resultCount) { + $resp = $this->get($this->endpoint . '?count=1&' . $filterOption); + $resp->assertJson(['total' => $resultCount]); + } + } + } \ No newline at end of file From a8595d8aaf96b2070b1173ee2ddb0c3738ba52b6 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Wed, 1 Jan 2020 17:01:36 +0000 Subject: [PATCH 148/191] Fixed test class names + add perm. check to api session auth --- app/Http/Middleware/ApiAuthenticate.php | 4 ++++ tests/Api/ApiAuthTest.php | 25 +++++++++++++++++++++++++ tests/Api/ApiConfigTest.php | 2 +- tests/Api/ApiListingTest.php | 2 +- 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/app/Http/Middleware/ApiAuthenticate.php b/app/Http/Middleware/ApiAuthenticate.php index 655334450..15962b3b0 100644 --- a/app/Http/Middleware/ApiAuthenticate.php +++ b/app/Http/Middleware/ApiAuthenticate.php @@ -2,6 +2,7 @@ namespace BookStack\Http\Middleware; +use BookStack\Exceptions\ApiAuthException; use BookStack\Exceptions\UnauthorizedException; use Closure; use Illuminate\Http\Request; @@ -36,6 +37,9 @@ class ApiAuthenticate // This is to make it easy to browser the API via browser after just logging into the system. if (signedInUser()) { $this->ensureEmailConfirmedIfRequested(); + if (!auth()->user()->can('access-api')) { + throw new ApiAuthException(trans('errors.api_user_no_api_permission'), 403); + } return; } diff --git a/tests/Api/ApiAuthTest.php b/tests/Api/ApiAuthTest.php index 30d7f4ead..b6b6b72ac 100644 --- a/tests/Api/ApiAuthTest.php +++ b/tests/Api/ApiAuthTest.php @@ -3,6 +3,7 @@ namespace Tests; use BookStack\Auth\Permissions\RolePermission; +use BookStack\Auth\User; use Carbon\Carbon; class ApiAuthTest extends TestCase @@ -14,6 +15,8 @@ class ApiAuthTest extends TestCase public function test_requests_succeed_with_default_auth() { $viewer = $this->getViewer(); + $this->giveUserPermissions($viewer, ['access-api']); + $resp = $this->get($this->endpoint); $resp->assertStatus(401); @@ -62,6 +65,28 @@ class ApiAuthTest extends TestCase $editorRole->detachPermission($accessApiPermission); $resp = $this->get($this->endpoint, $this->apiAuthHeader()); + $resp->assertStatus(403); + $resp->assertJson($this->errorResponse("The owner of the used API token does not have permission to make API calls", 403)); + } + + public function test_api_access_permission_required_to_access_api_with_session_auth() + { + $editor = $this->getEditor(); + $this->actingAs($editor, 'web'); + + $resp = $this->get($this->endpoint); + $resp->assertStatus(200); + auth('web')->logout(); + + $accessApiPermission = RolePermission::getByName('access-api'); + $editorRole = $this->getEditor()->roles()->first(); + $editorRole->detachPermission($accessApiPermission); + + $editor = User::query()->where('id', '=', $editor->id)->first(); + + $this->actingAs($editor, 'web'); + $resp = $this->get($this->endpoint); + $resp->assertStatus(403); $resp->assertJson($this->errorResponse("The owner of the used API token does not have permission to make API calls", 403)); } diff --git a/tests/Api/ApiConfigTest.php b/tests/Api/ApiConfigTest.php index 99b063c69..d9367741f 100644 --- a/tests/Api/ApiConfigTest.php +++ b/tests/Api/ApiConfigTest.php @@ -5,7 +5,7 @@ namespace Tests; use BookStack\Auth\Permissions\RolePermission; use Carbon\Carbon; -class ApiAuthTest extends TestCase +class ApiConfigTest extends TestCase { use TestsApi; diff --git a/tests/Api/ApiListingTest.php b/tests/Api/ApiListingTest.php index 26014cdec..fa28dfb36 100644 --- a/tests/Api/ApiListingTest.php +++ b/tests/Api/ApiListingTest.php @@ -6,7 +6,7 @@ use BookStack\Auth\Permissions\RolePermission; use BookStack\Entities\Book; use Carbon\Carbon; -class ApiAuthTest extends TestCase +class ApiListingTest extends TestCase { use TestsApi; From 04a86141361e941d2053ca16181e7561bff27650 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 12 Jan 2020 14:45:54 +0000 Subject: [PATCH 149/191] Filled out base Book API endpoints, added example responses --- app/Auth/User.php | 2 +- app/Entities/Book.php | 3 +- app/Http/Controllers/Api/ApiController.php | 10 +++ .../Controllers/Api/BooksApiController.php | 78 ++++++++++++++--- app/Uploads/Image.php | 1 + dev/api/responses/books-create.json | 10 +++ dev/api/responses/books-index.json | 27 ++++++ dev/api/responses/books-read.json | 47 ++++++++++ dev/api/responses/books-update.json | 11 +++ routes/api.php | 11 +-- tests/Api/BooksApiTest.php | 87 +++++++++++++++++++ tests/TestCase.php | 17 ++++ 12 files changed, 284 insertions(+), 20 deletions(-) create mode 100644 dev/api/responses/books-create.json create mode 100644 dev/api/responses/books-index.json create mode 100644 dev/api/responses/books-read.json create mode 100644 dev/api/responses/books-update.json create mode 100644 tests/Api/BooksApiTest.php diff --git a/app/Auth/User.php b/app/Auth/User.php index 69f424cac..35b3cd54f 100644 --- a/app/Auth/User.php +++ b/app/Auth/User.php @@ -47,7 +47,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon * The attributes excluded from the model's JSON form. * @var array */ - protected $hidden = ['password', 'remember_token']; + protected $hidden = ['password', 'remember_token', 'system_name', 'email_confirmed', 'external_auth_id', 'email']; /** * This holds the user's permissions when loaded. diff --git a/app/Entities/Book.php b/app/Entities/Book.php index 4e54457b8..919f60035 100644 --- a/app/Entities/Book.php +++ b/app/Entities/Book.php @@ -18,7 +18,8 @@ class Book extends Entity implements HasCoverImage { public $searchFactor = 2; - protected $fillable = ['name', 'description', 'image_id']; + protected $fillable = ['name', 'description']; + protected $hidden = ['restricted']; /** * Get the url for this book. diff --git a/app/Http/Controllers/Api/ApiController.php b/app/Http/Controllers/Api/ApiController.php index b3f1fb747..65a5bb99f 100644 --- a/app/Http/Controllers/Api/ApiController.php +++ b/app/Http/Controllers/Api/ApiController.php @@ -8,6 +8,8 @@ use Illuminate\Http\JsonResponse; class ApiController extends Controller { + protected $rules = []; + /** * Provide a paginated listing JSON response in a standard format * taking into account any pagination parameters passed by the user. @@ -17,4 +19,12 @@ class ApiController extends Controller $listing = new ListingResponseBuilder($query, request(), $fields); return $listing->toResponse(); } + + /** + * Get the validation rules for this controller. + */ + public function getValdationRules(): array + { + return $this->rules; + } } \ No newline at end of file diff --git a/app/Http/Controllers/Api/BooksApiController.php b/app/Http/Controllers/Api/BooksApiController.php index 3943b773a..e7a0217dc 100644 --- a/app/Http/Controllers/Api/BooksApiController.php +++ b/app/Http/Controllers/Api/BooksApiController.php @@ -1,47 +1,99 @@ [ - // TODO + 'name' => 'required|string|max:255', + 'description' => 'string|max:1000', ], 'update' => [ - // TODO + 'name' => 'string|min:1|max:255', + 'description' => 'string|max:1000', ], ]; + /** + * BooksApiController constructor. + */ + public function __construct(BookRepo $bookRepo) + { + $this->bookRepo = $bookRepo; + } + /** * Get a listing of books visible to the user. + * @api listing */ public function index() { $books = Book::visible(); return $this->apiListingResponse($books, [ - 'id', 'name', 'slug', 'description', 'created_at', 'updated_at', 'created_by', 'updated_by', - 'restricted', 'image_id', + 'id', 'name', 'slug', 'description', 'created_at', 'updated_at', 'created_by', 'updated_by', 'image_id', ]); } - public function create() + /** + * Create a new book. + * @throws \Illuminate\Validation\ValidationException + */ + public function create(Request $request) { - // TODO - + $this->checkPermission('book-create-all'); + $requestData = $this->validate($request, $this->rules['create']); + + $book = $this->bookRepo->create($requestData); + Activity::add($book, 'book_create', $book->id); + + return response()->json($book); } - public function read() + /** + * View the details of a single book. + */ + public function read(string $id) { - // TODO - + $book = Book::visible()->with(['tags', 'cover', 'createdBy', 'updatedBy'])->findOrFail($id); + return response()->json($book); } - public function update() + /** + * Update the details of a single book. + * @throws \Illuminate\Validation\ValidationException + */ + public function update(Request $request, string $id) { - // TODO - + $book = Book::visible()->findOrFail($id); + $this->checkOwnablePermission('book-update', $book); + + $requestData = $this->validate($request, $this->rules['update']); + $book = $this->bookRepo->update($book, $requestData); + Activity::add($book, 'book_update', $book->id); + + return response()->json($book); } - public function delete() + /** + * Delete a book from the system. + * @throws \BookStack\Exceptions\NotifyException + * @throws \Illuminate\Contracts\Container\BindingResolutionException + */ + public function delete(string $id) { - // TODO - + $book = Book::visible()->findOrFail($id); + $this->checkOwnablePermission('book-delete', $book); + + $this->bookRepo->destroy($book); + Activity::addMessage('book_delete', $book->name); + + return response('', 204); } } \ No newline at end of file diff --git a/app/Uploads/Image.php b/app/Uploads/Image.php index 6fa5db2a5..c76979d7c 100644 --- a/app/Uploads/Image.php +++ b/app/Uploads/Image.php @@ -8,6 +8,7 @@ class Image extends Ownable { protected $fillable = ['name']; + protected $hidden = []; /** * Get a thumbnail for this image. diff --git a/dev/api/responses/books-create.json b/dev/api/responses/books-create.json new file mode 100644 index 000000000..0b4336ab2 --- /dev/null +++ b/dev/api/responses/books-create.json @@ -0,0 +1,10 @@ +{ + "name": "My new book", + "description": "This is a book created via the API", + "created_by": 1, + "updated_by": 1, + "slug": "my-new-book", + "updated_at": "2020-01-12 14:05:11", + "created_at": "2020-01-12 14:05:11", + "id": 15 +} \ No newline at end of file diff --git a/dev/api/responses/books-index.json b/dev/api/responses/books-index.json new file mode 100644 index 000000000..29e83b1c0 --- /dev/null +++ b/dev/api/responses/books-index.json @@ -0,0 +1,27 @@ +{ + "data": [ + { + "id": 1, + "name": "BookStack User Guide", + "slug": "bookstack-user-guide", + "description": "This is a general guide on using BookStack on a day-to-day basis.", + "created_at": "2019-05-05 21:48:46", + "updated_at": "2019-12-11 20:57:31", + "created_by": 1, + "updated_by": 1, + "image_id": 3 + }, + { + "id": 2, + "name": "Inventore inventore quia voluptatem.", + "slug": "inventore-inventore-quia-voluptatem", + "description": "Veniam nihil voluptas enim laborum corporis quos sint. Ab rerum voluptas ut iste voluptas magni quibusdam ut. Amet omnis enim voluptate neque facilis.", + "created_at": "2019-05-05 22:10:14", + "updated_at": "2019-12-11 20:57:23", + "created_by": 4, + "updated_by": 3, + "image_id": 34 + } + ], + "total": 14 +} \ No newline at end of file diff --git a/dev/api/responses/books-read.json b/dev/api/responses/books-read.json new file mode 100644 index 000000000..e0570444f --- /dev/null +++ b/dev/api/responses/books-read.json @@ -0,0 +1,47 @@ +{ + "id": 16, + "name": "My own book", + "slug": "my-own-book", + "description": "This is my own little book", + "created_at": "2020-01-12 14:09:59", + "updated_at": "2020-01-12 14:11:51", + "created_by": { + "id": 1, + "name": "Admin", + "created_at": "2019-05-05 21:15:13", + "updated_at": "2019-12-16 12:18:37", + "image_id": 48 + }, + "updated_by": { + "id": 1, + "name": "Admin", + "created_at": "2019-05-05 21:15:13", + "updated_at": "2019-12-16 12:18:37", + "image_id": 48 + }, + "image_id": 452, + "tags": [ + { + "id": 13, + "entity_id": 16, + "entity_type": "BookStack\\Book", + "name": "Category", + "value": "Guide", + "order": 0, + "created_at": "2020-01-12 14:11:51", + "updated_at": "2020-01-12 14:11:51" + } + ], + "cover": { + "id": 452, + "name": "sjovall_m117hUWMu40.jpg", + "url": "http:\/\/bookstack.local\/uploads\/images\/cover_book\/2020-01\/sjovall_m117hUWMu40.jpg", + "created_at": "2020-01-12 14:11:51", + "updated_at": "2020-01-12 14:11:51", + "created_by": 1, + "updated_by": 1, + "path": "\/uploads\/images\/cover_book\/2020-01\/sjovall_m117hUWMu40.jpg", + "type": "cover_book", + "uploaded_to": 16 + } +} \ No newline at end of file diff --git a/dev/api/responses/books-update.json b/dev/api/responses/books-update.json new file mode 100644 index 000000000..8f20b5b9f --- /dev/null +++ b/dev/api/responses/books-update.json @@ -0,0 +1,11 @@ +{ + "id": 16, + "name": "My own book", + "slug": "my-own-book", + "description": "This is my own little book - updated", + "created_at": "2020-01-12 14:09:59", + "updated_at": "2020-01-12 14:16:10", + "created_by": 1, + "updated_by": 1, + "image_id": 452 +} \ No newline at end of file diff --git a/routes/api.php b/routes/api.php index 0604ffd29..3348d8907 100644 --- a/routes/api.php +++ b/routes/api.php @@ -2,11 +2,12 @@ /** * Routes for the BookStack API. - * * Routes have a uri prefix of /api/. + * Controllers are all within app/Http/Controllers/Api */ - -// TODO - Authenticate middleware - -Route::get('books', 'BooksApiController@index'); \ No newline at end of file +Route::get('books', 'BooksApiController@index'); +Route::post('books', 'BooksApiController@create'); +Route::get('books/{id}', 'BooksApiController@read'); +Route::put('books/{id}', 'BooksApiController@update'); +Route::delete('books/{id}', 'BooksApiController@delete'); diff --git a/tests/Api/BooksApiTest.php b/tests/Api/BooksApiTest.php new file mode 100644 index 000000000..f560bfffd --- /dev/null +++ b/tests/Api/BooksApiTest.php @@ -0,0 +1,87 @@ +actingAsApiEditor(); + $firstBook = Book::query()->orderBy('id', 'asc')->first(); + + $resp = $this->getJson($this->baseEndpoint . '?count=1&sort=+id'); + $resp->assertJson(['data' => [ + [ + 'id' => $firstBook->id, + 'name' => $firstBook->name, + 'slug' => $firstBook->slug, + ] + ]]); + } + + public function test_create_endpoint() + { + $this->actingAsApiEditor(); + $details = [ + 'name' => 'My API book', + 'description' => 'A book created via the API', + ]; + + $resp = $this->postJson($this->baseEndpoint, $details); + $resp->assertStatus(200); + $newItem = Book::query()->orderByDesc('id')->where('name', '=', $details['name'])->first(); + $resp->assertJson(array_merge($details, ['id' => $newItem->id, 'slug' => $newItem->slug])); + $this->assertActivityExists('book_create', $newItem); + } + + public function test_read_endpoint() + { + $this->actingAsApiEditor(); + $book = Book::visible()->first(); + + $resp = $this->getJson($this->baseEndpoint . "/{$book->id}"); + + $resp->assertStatus(200); + $resp->assertJson([ + 'id' => $book->id, + 'slug' => $book->slug, + 'created_by' => [ + 'name' => $book->createdBy->name, + ], + 'updated_by' => [ + 'name' => $book->createdBy->name, + ] + ]); + } + + public function test_update_endpoint() + { + $this->actingAsApiEditor(); + $book = Book::visible()->first(); + $details = [ + 'name' => 'My updated API book', + 'description' => 'A book created via the API', + ]; + + $resp = $this->putJson($this->baseEndpoint . "/{$book->id}", $details); + $book->refresh(); + + $resp->assertStatus(200); + $resp->assertJson(array_merge($details, ['id' => $book->id, 'slug' => $book->slug])); + $this->assertActivityExists('book_update', $book); + } + + public function test_delete_endpoint() + { + $this->actingAsApiEditor(); + $book = Book::visible()->first(); + $resp = $this->deleteJson($this->baseEndpoint . "/{$book->id}"); + + $resp->assertStatus(204); + $this->assertActivityExists('book_delete'); + } +} \ No newline at end of file diff --git a/tests/TestCase.php b/tests/TestCase.php index 939a1a91e..f20b20fd8 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -1,5 +1,6 @@ $key]; + + if ($entity) { + $detailsToCheck['entity_type'] = $entity->getMorphClass(); + $detailsToCheck['entity_id'] = $entity->id; + } + + $this->assertDatabaseHas('activities', $detailsToCheck); + } } \ No newline at end of file From bed24986675de1a42b1e3621d2c5135c6c9fbf14 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 12 Jan 2020 16:25:14 +0000 Subject: [PATCH 150/191] Started work on generating API docs --- app/Api/ApiDocsGenerator.php | 122 ++++++++++++++++++ .../Controllers/Api/ApiDocsController.php | 47 +++++++ .../Controllers/Api/BooksApiController.php | 1 - routes/api.php | 3 + 4 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 app/Api/ApiDocsGenerator.php create mode 100644 app/Http/Controllers/Api/ApiDocsController.php diff --git a/app/Api/ApiDocsGenerator.php b/app/Api/ApiDocsGenerator.php new file mode 100644 index 000000000..b63406696 --- /dev/null +++ b/app/Api/ApiDocsGenerator.php @@ -0,0 +1,122 @@ +getFlatApiRoutes(); + $apiRoutes = $this->loadDetailsFromControllers($apiRoutes); + $apiRoutes = $this->loadDetailsFromFiles($apiRoutes); + $apiRoutes = $apiRoutes->groupBy('base_model'); + return $apiRoutes; + } + + /** + * Load any API details stored in static files. + */ + protected function loadDetailsFromFiles(Collection $routes): Collection + { + return $routes->map(function (array $route) { + $exampleResponseFile = base_path('dev/api/responses/' . $route['name'] . '.json'); + $exampleResponse = file_exists($exampleResponseFile) ? file_get_contents($exampleResponseFile) : null; + $route['example_response'] = $exampleResponse; + return $route; + }); + } + + /** + * Load any details we can fetch from the controller and its methods. + */ + protected function loadDetailsFromControllers(Collection $routes): Collection + { + return $routes->map(function (array $route) { + $method = $this->getReflectionMethod($route['controller'], $route['controller_method']); + $comment = $method->getDocComment(); + $route['description'] = $comment ? $this->parseDescriptionFromMethodComment($comment) : null; + $route['body_params'] = $this->getBodyParamsFromClass($route['controller'], $route['controller_method']); + return $route; + }); + } + + /** + * Load body params and their rules by inspecting the given class and method name. + * @throws \Illuminate\Contracts\Container\BindingResolutionException + */ + protected function getBodyParamsFromClass(string $className, string $methodName): ?array + { + /** @var ApiController $class */ + $class = $this->controllerClasses[$className] ?? null; + if ($class === null) { + $class = app()->make($className); + $this->controllerClasses[$className] = $class; + } + + $rules = $class->getValdationRules()[$methodName] ?? []; + foreach ($rules as $param => $ruleString) { + $rules[$param] = explode('|', $ruleString); + } + return count($rules) > 0 ? $rules : null; + } + + /** + * Parse out the description text from a class method comment. + */ + protected function parseDescriptionFromMethodComment(string $comment) + { + $matches = []; + preg_match_all('/^\s*?\*\s((?![@\s]).*?)$/m', $comment, $matches); + return implode(' ', $matches[1] ?? []); + } + + /** + * Get a reflection method from the given class name and method name. + * @throws ReflectionException + */ + protected function getReflectionMethod(string $className, string $methodName): ReflectionMethod + { + $class = $this->reflectionClasses[$className] ?? null; + if ($class === null) { + $class = new ReflectionClass($className); + $this->reflectionClasses[$className] = $class; + } + + return $class->getMethod($methodName); + } + + /** + * Get the system API routes, formatted into a flat collection. + */ + protected function getFlatApiRoutes(): Collection + { + return collect(Route::getRoutes()->getRoutes())->filter(function ($route) { + return strpos($route->uri, 'api/') === 0; + })->map(function ($route) { + [$controller, $controllerMethod] = explode('@', $route->action['uses']); + $baseModelName = explode('/', $route->uri)[1]; + $shortName = $baseModelName . '-' . $controllerMethod; + return [ + 'name' => $shortName, + 'uri' => $route->uri, + 'method' => $route->methods[0], + 'controller' => $controller, + 'controller_method' => $controllerMethod, + 'base_model' => $baseModelName, + ]; + }); + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/Api/ApiDocsController.php b/app/Http/Controllers/Api/ApiDocsController.php new file mode 100644 index 000000000..bfb0c1834 --- /dev/null +++ b/app/Http/Controllers/Api/ApiDocsController.php @@ -0,0 +1,47 @@ +getDocs(); + dd($docs); + // TODO - Build view for API docs + return view(''); + } + + /** + * Show a JSON view of the API docs data. + */ + public function json() { + $docs = $this->getDocs(); + return response()->json($docs); + } + + /** + * Get the base docs data. + * Checks and uses the system cache for quick re-fetching. + */ + protected function getDocs(): Collection + { + $appVersion = trim(file_get_contents(base_path('version'))); + $cacheKey = 'api-docs::' . $appVersion; + if (Cache::has($cacheKey) && config('app.env') === 'production') { + $docs = Cache::get($cacheKey); + } else { + $docs = (new ApiDocsGenerator())->generate(); + Cache::put($cacheKey, $docs, 60*24); + } + + return $docs; + } + +} diff --git a/app/Http/Controllers/Api/BooksApiController.php b/app/Http/Controllers/Api/BooksApiController.php index e7a0217dc..8c62b7d7d 100644 --- a/app/Http/Controllers/Api/BooksApiController.php +++ b/app/Http/Controllers/Api/BooksApiController.php @@ -31,7 +31,6 @@ class BooksApiController extends ApiController /** * Get a listing of books visible to the user. - * @api listing */ public function index() { diff --git a/routes/api.php b/routes/api.php index 3348d8907..12b327798 100644 --- a/routes/api.php +++ b/routes/api.php @@ -6,6 +6,9 @@ * Controllers are all within app/Http/Controllers/Api */ +Route::get('docs', 'ApiDocsController@display'); +Route::get('docs.json', 'ApiDocsController@json'); + Route::get('books', 'BooksApiController@index'); Route::post('books', 'BooksApiController@create'); Route::get('books/{id}', 'BooksApiController@read'); From 4297d64e299eacfafdb96e1d98ea338c7ba310ad Mon Sep 17 00:00:00 2001 From: SoarinFerret Date: Tue, 14 Jan 2020 13:50:29 -0600 Subject: [PATCH 151/191] Add close icon to notifications --- resources/sass/_components.scss | 9 ++++++++- resources/views/partials/notifications.blade.php | 6 +++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/resources/sass/_components.scss b/resources/sass/_components.scss index 8ccf6cbdc..6ef53b719 100644 --- a/resources/sass/_components.scss +++ b/resources/sass/_components.scss @@ -15,7 +15,7 @@ transition: transform ease-in-out 280ms; transform: translateX(580px); display: grid; - grid-template-columns: 42px 1fr; + grid-template-columns: 42px 1fr 12px; color: #444; font-weight: 700; span, svg { @@ -29,6 +29,13 @@ padding-right: $-s; fill: currentColor; } + .dismiss { + margin-top: -8px; + svg { + height: 1.0rem; + color: #444; + } + } span { vertical-align: middle; line-height: 1.3; diff --git a/resources/views/partials/notifications.blade.php b/resources/views/partials/notifications.blade.php index 526871499..752920917 100644 --- a/resources/views/partials/notifications.blade.php +++ b/resources/views/partials/notifications.blade.php @@ -1,11 +1,11 @@ From 45b5e631e241e7809d8752279d781ec391245423 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Wed, 15 Jan 2020 20:18:02 +0000 Subject: [PATCH 152/191] Added a view for the API docs --- app/Api/ApiDocsGenerator.php | 2 +- .../Controllers/Api/ApiDocsController.php | 6 +-- .../Controllers/Api/BooksApiController.php | 15 +++--- .../js/components/details-highlighter.js | 18 +++++++ resources/js/components/index.js | 2 + resources/js/services/code.js | 18 +++++-- resources/sass/_blocks.scss | 22 ++++++++ resources/sass/_text.scss | 12 +++++ resources/views/api-docs/index.blade.php | 51 +++++++++++++++++++ 9 files changed, 133 insertions(+), 13 deletions(-) create mode 100644 resources/js/components/details-highlighter.js create mode 100644 resources/views/api-docs/index.blade.php diff --git a/app/Api/ApiDocsGenerator.php b/app/Api/ApiDocsGenerator.php index b63406696..41decd23d 100644 --- a/app/Api/ApiDocsGenerator.php +++ b/app/Api/ApiDocsGenerator.php @@ -106,7 +106,7 @@ class ApiDocsGenerator return strpos($route->uri, 'api/') === 0; })->map(function ($route) { [$controller, $controllerMethod] = explode('@', $route->action['uses']); - $baseModelName = explode('/', $route->uri)[1]; + $baseModelName = explode('.', explode('/', $route->uri)[1])[0]; $shortName = $baseModelName . '-' . $controllerMethod; return [ 'name' => $shortName, diff --git a/app/Http/Controllers/Api/ApiDocsController.php b/app/Http/Controllers/Api/ApiDocsController.php index bfb0c1834..84ddd5215 100644 --- a/app/Http/Controllers/Api/ApiDocsController.php +++ b/app/Http/Controllers/Api/ApiDocsController.php @@ -13,9 +13,9 @@ class ApiDocsController extends ApiController public function display() { $docs = $this->getDocs(); - dd($docs); - // TODO - Build view for API docs - return view(''); + return view('api-docs.index', [ + 'docs' => $docs, + ]); } /** diff --git a/app/Http/Controllers/Api/BooksApiController.php b/app/Http/Controllers/Api/BooksApiController.php index 8c62b7d7d..fa174dfd3 100644 --- a/app/Http/Controllers/Api/BooksApiController.php +++ b/app/Http/Controllers/Api/BooksApiController.php @@ -2,8 +2,11 @@ use BookStack\Entities\Book; use BookStack\Entities\Repos\BookRepo; +use BookStack\Exceptions\NotifyException; use BookStack\Facades\Activity; +use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Http\Request; +use Illuminate\Validation\ValidationException; class BooksApiController extends ApiController { @@ -41,8 +44,8 @@ class BooksApiController extends ApiController } /** - * Create a new book. - * @throws \Illuminate\Validation\ValidationException + * Create a new book in the system. + * @throws ValidationException */ public function create(Request $request) { @@ -66,7 +69,7 @@ class BooksApiController extends ApiController /** * Update the details of a single book. - * @throws \Illuminate\Validation\ValidationException + * @throws ValidationException */ public function update(Request $request, string $id) { @@ -81,9 +84,9 @@ class BooksApiController extends ApiController } /** - * Delete a book from the system. - * @throws \BookStack\Exceptions\NotifyException - * @throws \Illuminate\Contracts\Container\BindingResolutionException + * Delete a single book from the system. + * @throws NotifyException + * @throws BindingResolutionException */ public function delete(string $id) { diff --git a/resources/js/components/details-highlighter.js b/resources/js/components/details-highlighter.js new file mode 100644 index 000000000..18c5165fa --- /dev/null +++ b/resources/js/components/details-highlighter.js @@ -0,0 +1,18 @@ +import Code from "../services/code" +class DetailsHighlighter { + + constructor(elem) { + this.elem = elem; + this.dealtWith = false; + elem.addEventListener('toggle', this.onToggle.bind(this)); + } + + onToggle() { + if (this.dealtWith) return; + + Code.highlightWithin(this.elem); + this.dealtWith = true; + } +} + +export default DetailsHighlighter; \ No newline at end of file diff --git a/resources/js/components/index.js b/resources/js/components/index.js index bbe059898..d3ba539dd 100644 --- a/resources/js/components/index.js +++ b/resources/js/components/index.js @@ -30,6 +30,7 @@ import settingColorPicker from "./setting-color-picker"; import entityPermissionsEditor from "./entity-permissions-editor"; import templateManager from "./template-manager"; import newUserPassword from "./new-user-password"; +import detailsHighlighter from "./details-highlighter"; const componentMapping = { 'dropdown': dropdown, @@ -64,6 +65,7 @@ const componentMapping = { 'entity-permissions-editor': entityPermissionsEditor, 'template-manager': templateManager, 'new-user-password': newUserPassword, + 'details-highlighter': detailsHighlighter, }; window.components = {}; diff --git a/resources/js/services/code.js b/resources/js/services/code.js index 26dee5bfb..834a547e3 100644 --- a/resources/js/services/code.js +++ b/resources/js/services/code.js @@ -87,9 +87,20 @@ const modeMap = { * Highlight pre elements on a page */ function highlight() { - let codeBlocks = document.querySelectorAll('.page-content pre, .comment-box .content pre'); - for (let i = 0; i < codeBlocks.length; i++) { - highlightElem(codeBlocks[i]); + const codeBlocks = document.querySelectorAll('.page-content pre, .comment-box .content pre'); + for (const codeBlock of codeBlocks) { + highlightElem(codeBlock); + } +} + +/** + * Highlight all code blocks within the given parent element + * @param {HTMLElement} parent + */ +function highlightWithin(parent) { + const codeBlocks = parent.querySelectorAll('pre'); + for (const codeBlock of codeBlocks) { + highlightElem(codeBlock); } } @@ -308,6 +319,7 @@ function getMetaKey() { export default { highlight: highlight, + highlightWithin: highlightWithin, wysiwygView: wysiwygView, popupEditor: popupEditor, setMode: setMode, diff --git a/resources/sass/_blocks.scss b/resources/sass/_blocks.scss index 2cb17a18d..cc42dc736 100644 --- a/resources/sass/_blocks.scss +++ b/resources/sass/_blocks.scss @@ -236,4 +236,26 @@ .tag-list div:last-child .tag-item { margin-bottom: 0; +} + +/** + * API Docs + */ +.api-method { + font-size: 0.75rem; + background-color: #888; + padding: $-xs; + line-height: 1.3; + opacity: 0.7; + vertical-align: top; + border-radius: 3px; + color: #FFF; + display: inline-block; + min-width: 60px; + text-align: center; + font-weight: bold; + &[data-method="GET"] { background-color: #077b70 } + &[data-method="POST"] { background-color: #cf4d03 } + &[data-method="PUT"] { background-color: #0288D1 } + &[data-method="DELETE"] { background-color: #ab0f0e } } \ No newline at end of file diff --git a/resources/sass/_text.scss b/resources/sass/_text.scss index cf78c162b..77e0773eb 100644 --- a/resources/sass/_text.scss +++ b/resources/sass/_text.scss @@ -213,6 +213,18 @@ blockquote { } } +.text-mono { + font-family: $mono; +} + +.text-uppercase { + text-transform: uppercase; +} + +.text-capitals { + text-transform: capitalize; +} + .code-base { background-color: #F8F8F8; font-size: 0.80em; diff --git a/resources/views/api-docs/index.blade.php b/resources/views/api-docs/index.blade.php new file mode 100644 index 000000000..181bcd746 --- /dev/null +++ b/resources/views/api-docs/index.blade.php @@ -0,0 +1,51 @@ +@extends('simple-layout') + +@section('body') + +
+ +
+ +
+ @foreach($docs as $model => $endpoints) +

{{ $model }}

+ + @foreach($endpoints as $endpoint) + + @endforeach + @endforeach +
+ +
+ @foreach($docs as $model => $endpoints) +
+

{{ $model }}

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

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

+ @if($endpoint['example_response'] ?? false) +
+ Example Response +
{{ $endpoint['example_response'] }}
+
+
+ @endif + @endforeach +
+ @endforeach +
+ +
+ + +
+@stop \ No newline at end of file From 8016f1121ef8feef114a5f20c5dba97c8d550bea Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 18 Jan 2020 09:48:30 +0000 Subject: [PATCH 153/191] Refined docs view, Added example requests --- app/Api/ApiDocsGenerator.php | 9 +++-- dev/api/requests/books-create.json | 4 +++ dev/api/requests/books-update.json | 4 +++ resources/views/api-docs/index.blade.php | 42 +++++++++++++++++++++--- 4 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 dev/api/requests/books-create.json create mode 100644 dev/api/requests/books-update.json diff --git a/app/Api/ApiDocsGenerator.php b/app/Api/ApiDocsGenerator.php index 41decd23d..a0c45608a 100644 --- a/app/Api/ApiDocsGenerator.php +++ b/app/Api/ApiDocsGenerator.php @@ -31,9 +31,12 @@ class ApiDocsGenerator protected function loadDetailsFromFiles(Collection $routes): Collection { return $routes->map(function (array $route) { - $exampleResponseFile = base_path('dev/api/responses/' . $route['name'] . '.json'); - $exampleResponse = file_exists($exampleResponseFile) ? file_get_contents($exampleResponseFile) : null; - $route['example_response'] = $exampleResponse; + $exampleTypes = ['request', 'response']; + foreach ($exampleTypes as $exampleType) { + $exampleFile = base_path("dev/api/{$exampleType}s/{$route['name']}.json"); + $exampleContent = file_exists($exampleFile) ? file_get_contents($exampleFile) : null; + $route["example_{$exampleType}"] = $exampleContent; + } return $route; }); } diff --git a/dev/api/requests/books-create.json b/dev/api/requests/books-create.json new file mode 100644 index 000000000..4a6626619 --- /dev/null +++ b/dev/api/requests/books-create.json @@ -0,0 +1,4 @@ +{ + "name": "My own book", + "description": "This is my own little book" +} \ No newline at end of file diff --git a/dev/api/requests/books-update.json b/dev/api/requests/books-update.json new file mode 100644 index 000000000..fc67d5fcc --- /dev/null +++ b/dev/api/requests/books-update.json @@ -0,0 +1,4 @@ +{ + "name": "My updated book", + "description": "This is my book with updated details" +} \ No newline at end of file diff --git a/resources/views/api-docs/index.blade.php b/resources/views/api-docs/index.blade.php index 181bcd746..a20ba04cc 100644 --- a/resources/views/api-docs/index.blade.php +++ b/resources/views/api-docs/index.blade.php @@ -12,32 +12,64 @@ @foreach($endpoints as $endpoint) @endforeach @endforeach
-
+
@foreach($docs as $model => $endpoints)

{{ $model }}

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

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

+ @if($endpoint['body_params'] ?? false) +
+ Body Parameters + + + + + + @foreach($endpoint['body_params'] as $paramName => $rules) + + + + + @endforeach +
Param NameValue Rules
{{ $paramName }} + @foreach($rules as $rule) + {{ $rule }} + @endforeach +
+
+ @endif + @if($endpoint['example_request'] ?? false) +
+ Example Request +
{{ $endpoint['example_request'] }}
+
+ @endif @if($endpoint['example_response'] ?? false) -
+
Example Response
{{ $endpoint['example_response'] }}
-
+ @endif + @if(!$loop->last) +
@endif @endforeach
From 8ead596067af45ed3540771ad9ccd37e7143539a Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 18 Jan 2020 09:55:02 +0000 Subject: [PATCH 154/191] Updated default codemirror theme - To mdn-like theme, to have better default legibility and contrast --- resources/js/services/code.js | 2 +- resources/sass/_codemirror.scss | 70 ++++++++++++++++++--------------- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/resources/js/services/code.js b/resources/js/services/code.js index 834a547e3..0c5f75db3 100644 --- a/resources/js/services/code.js +++ b/resources/js/services/code.js @@ -185,7 +185,7 @@ function getMode(suggestion, content) { * @returns {*|string} */ function getTheme() { - return window.codeTheme || 'base16-light'; + return window.codeTheme || 'mdn-like'; } /** diff --git a/resources/sass/_codemirror.scss b/resources/sass/_codemirror.scss index 28c777608..92287c484 100644 --- a/resources/sass/_codemirror.scss +++ b/resources/sass/_codemirror.scss @@ -343,44 +343,51 @@ span.CodeMirror-selectedtext { background: none; } /* + MDN-LIKE Theme - Mozilla + Ported to CodeMirror by Peter Kroon + Report bugs/issues here: https://github.com/codemirror/CodeMirror/issues + GitHub: @peterkroon - Name: Base16 Default Light - Author: Chris Kempson (http://chriskempson.com) - - CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) - Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + The mdn-like theme is inspired on the displayed code examples at: https://developer.mozilla.org/en-US/docs/Web/CSS/animation */ +.cm-s-mdn-like.CodeMirror { color: #999; background-color: #fff; } +.cm-s-mdn-like div.CodeMirror-selected { background: #cfc; } +.cm-s-mdn-like .CodeMirror-line::selection, .cm-s-mdn-like .CodeMirror-line > span::selection, .cm-s-mdn-like .CodeMirror-line > span > span::selection { background: #cfc; } +.cm-s-mdn-like .CodeMirror-line::-moz-selection, .cm-s-mdn-like .CodeMirror-line > span::-moz-selection, .cm-s-mdn-like .CodeMirror-line > span > span::-moz-selection { background: #cfc; } -.cm-s-base16-light.CodeMirror { background: #f8f8f8; color: #444444; } -.cm-s-base16-light div.CodeMirror-selected { background: #e0e0e0; } -.cm-s-base16-light .CodeMirror-line::selection, .cm-s-base16-light .CodeMirror-line > span::selection, .cm-s-base16-light .CodeMirror-line > span > span::selection { background: #e0e0e0; } -.cm-s-base16-light .CodeMirror-line::-moz-selection, .cm-s-base16-light .CodeMirror-line > span::-moz-selection, .cm-s-base16-light .CodeMirror-line > span > span::-moz-selection { background: #e0e0e0; } -.cm-s-base16-light .CodeMirror-gutters { background: #f5f5f5; border-right: 0px; } -.cm-s-base16-light .CodeMirror-guttermarker { color: #ac4142; } -.cm-s-base16-light .CodeMirror-guttermarker-subtle { color: #b0b0b0; } -.cm-s-base16-light .CodeMirror-linenumber { color: #b0b0b0; } -.cm-s-base16-light .CodeMirror-cursor { border-left: 1px solid #505050; } +.cm-s-mdn-like .CodeMirror-gutters { background: #f8f8f8; border-left: 6px solid rgba(0,83,159,0.65); color: #333; } +.cm-s-mdn-like .CodeMirror-linenumber { color: #aaa; padding-left: 8px; } +.cm-s-mdn-like .CodeMirror-cursor { border-left: 2px solid #222; } -.cm-s-base16-light span.cm-comment { color: #8f5536; } -.cm-s-base16-light span.cm-atom { color: #aa759f; } -.cm-s-base16-light span.cm-number { color: #aa759f; } +.cm-s-mdn-like .cm-keyword { color: #6262FF; } +.cm-s-mdn-like .cm-atom { color: #F90; } +.cm-s-mdn-like .cm-number { color: #ca7841; } +.cm-s-mdn-like .cm-def { color: #8DA6CE; } +.cm-s-mdn-like span.cm-variable-2, .cm-s-mdn-like span.cm-tag { color: #690; } +.cm-s-mdn-like span.cm-variable-3, .cm-s-mdn-like span.cm-def, .cm-s-mdn-like span.cm-type { color: #07a; } -.cm-s-base16-light span.cm-property, .cm-s-base16-light span.cm-attribute { color: #678c30; } -.cm-s-base16-light span.cm-keyword { color: #ac4142; } -.cm-s-base16-light span.cm-string { color: #e09c3c; } +.cm-s-mdn-like .cm-variable { color: #07a; } +.cm-s-mdn-like .cm-property { color: #905; } +.cm-s-mdn-like .cm-qualifier { color: #690; } -.cm-s-base16-light span.cm-builtin { color: #4c7f9e; } -.cm-s-base16-light span.cm-variable { color: #90a959; } -.cm-s-base16-light span.cm-variable-2 { color: #6a9fb5; } -.cm-s-base16-light span.cm-def { color: #d28445; } -.cm-s-base16-light span.cm-bracket { color: #202020; } -.cm-s-base16-light span.cm-tag { color: #ac4142; } -.cm-s-base16-light span.cm-link { color: #aa759f; } -.cm-s-base16-light span.cm-error { background: #ac4142; color: #505050; } +.cm-s-mdn-like .cm-operator { color: #cda869; } +.cm-s-mdn-like .cm-comment { color:#777; font-weight:normal; } +.cm-s-mdn-like .cm-string { color:#07a; font-style:italic; } +.cm-s-mdn-like .cm-string-2 { color:#bd6b18; } /*?*/ +.cm-s-mdn-like .cm-meta { color: #000; } /*?*/ +.cm-s-mdn-like .cm-builtin { color: #9B7536; } /*?*/ +.cm-s-mdn-like .cm-tag { color: #997643; } +.cm-s-mdn-like .cm-attribute { color: #d6bb6d; } /*?*/ +.cm-s-mdn-like .cm-header { color: #FF6400; } +.cm-s-mdn-like .cm-hr { color: #AEAEAE; } +.cm-s-mdn-like .cm-link { color:#ad9361; font-style:italic; text-decoration:none; } +.cm-s-mdn-like .cm-error { border-bottom: 1px solid red; } -.cm-s-base16-light .CodeMirror-activeline-background { background: #DDDCDC; } -.cm-s-base16-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; } +div.cm-s-mdn-like .CodeMirror-activeline-background { background: #efefff; } +div.cm-s-mdn-like span.CodeMirror-matchingbracket { outline:1px solid grey; color: inherit; } + +.cm-s-mdn-like.CodeMirror { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFcAAAAyCAYAAAAp8UeFAAAHvklEQVR42s2b63bcNgyEQZCSHCdt2vd/0tWF7I+Q6XgMXiTtuvU5Pl57ZQKkKHzEAOtF5KeIJBGJ8uvL599FRFREZhFx8DeXv8trn68RuGaC8TRfo3SNp9dlDDHedyLyTUTeRWStXKPZrjtpZxaRw5hPqozRs1N8/enzIiQRWcCgy4MUA0f+XWliDhyL8Lfyvx7ei/Ae3iQFHyw7U/59pQVIMEEPEz0G7XiwdRjzSfC3UTtz9vchIntxvry5iMgfIhJoEflOz2CQr3F5h/HfeFe+GTdLaKcu9L8LTeQb/R/7GgbsfKedyNdoHsN31uRPWrfZ5wsj/NzzRQHuToIdU3ahwnsKPxXCjJITuOsi7XLc7SG/v5GdALs7wf8JjTFiB5+QvTEfRyGOfX3Lrx8wxyQi3sNq46O7QahQiCsRFgqddjBouVEHOKDgXAQHD9gJCr5sMKkEdjwsarG/ww3BMHBU7OBjXnzdyY7SfCxf5/z6ATccrwlKuwC/jhznnPF4CgVzhhVf4xp2EixcBActO75iZ8/fM9zAs2OMzKdslgXWJ9XG8PQoOAMA5fGcsvORgv0doBXyHrCwfLJAOwo71QLNkb8n2Pl6EWiR7OCibtkPaz4Kc/0NNAze2gju3zOwekALDaCFPI5vjPFmgGY5AZqyGEvH1x7QfIb8YtxMnA/b+QQ0aQDAwc6JMFg8CbQZ4qoYEEHbRwNojuK3EHwd7VALSgq+MNDKzfT58T8qdpADrgW0GmgcAS1lhzztJmkAzcPNOQbsWEALBDSlMKUG0Eq4CLAQWvEVQ9WU57gZJwZtgPO3r9oBTQ9WO8TjqXINx8R0EYpiZEUWOF3FxkbJkgU9B2f41YBrIj5ZfsQa0M5kTgiAAqM3ShXLgu8XMqcrQBvJ0CL5pnTsfMB13oB8athpAq2XOQmcGmoACCLydx7nToa23ATaSIY2ichfOdPTGxlasXMLaL0MLZAOwAKIM+y8CmicobGdCcbbK9DzN+yYGVoNNI5iUKTMyYOjPse4A8SM1MmcXgU0toOq1yO/v8FOxlASyc7TgeYaAMBJHcY1CcCwGI/TK4AmDbDyKYBBtFUkRwto8gygiQEaByFgJ00BH2M8JWwQS1nafDXQCidWyOI8AcjDCSjCLk8ngObuAm3JAHAdubAmOaK06V8MNEsKPJOhobSprwQa6gD7DclRQdqcwL4zxqgBrQcabUiBLclRDKAlWp+etPkBaNMA0AKlrHwTdEByZAA4GM+SNluSY6wAzcMNewxmgig5Ks0nkrSpBvSaQHMdKTBAnLojOdYyGpQ254602ZILPdTD1hdlggdIm74jbTp8vDwF5ZYUeLWGJpWsh6XNyXgcYwVoJQTEhhTYkxzZjiU5npU2TaB979TQehlaAVq4kaGpiPwwwLkYUuBbQwocyQTv1tA0+1UFWoJF3iv1oq+qoSk8EQdJmwHkziIF7oOZk14EGitibAdjLYYK78H5vZOhtWpoI0ATGHs0Q8OMb4Ey+2bU2UYztCtA0wFAs7TplGLRVQCcqaFdGSPCeTI1QNIC52iWNzof6Uib7xjEp07mNNoUYmVosVItHrHzRlLgBn9LFyRHaQCtVUMbtTNhoXWiTOO9k/V8BdAc1Oq0ArSQs6/5SU0hckNy9NnXqQY0PGYo5dWJ7nINaN6o958FWin27aBaWRka1r5myvLOAm0j30eBJqCxHLReVclxhxOEN2JfDWjxBtAC7MIH1fVaGdoOp4qJYDgKtKPSFNID2gSnGldrCqkFZ+5UeQXQBIRrSwocbdZYQT/2LwRahBPBXoHrB8nxaGROST62DKUbQOMMzZIC9abkuELfQzQALWTnDNAm8KHWFOJgJ5+SHIvTPcmx1xQyZRhNL5Qci689aXMEaN/uNIWkEwDAvFpOZmgsBaaGnbs1NPa1Jm32gBZAIh1pCtG7TSH4aE0y1uVY4uqoFPisGlpP2rSA5qTecWn5agK6BzSpgAyD+wFaqhnYoSZ1Vwr8CmlTQbrcO3ZaX0NAEyMbYaAlyquFoLKK3SPby9CeVUPThrSJmkCAE0CrKUQadi4DrdSlWhmah0YL9z9vClH59YGbHx1J8VZTyAjQepJjmXwAKTDQI3omc3p1U4gDUf6RfcdYfrUp5ClAi2J3Ba6UOXGo+K+bQrjjssitG2SJzshaLwMtXgRagUNpYYoVkMSBLM+9GGiJZMvduG6DRZ4qc04DMPtQQxOjEtACmhO7K1AbNbQDEggZyJwscFpAGwENhoBeUwh3bWolhe8BTYVKxQEWrSUn/uhcM5KhvUu/+eQu0Lzhi+VrK0PrZZNDQKs9cpYUuFYgMVpD4/NxenJTiMCNqdUEUf1qZWjppLT5qSkkUZbCwkbZMSuVnu80hfSkzRbQeqCZSAh6huR4VtoM2gHAlLf72smuWgE+VV7XpE25Ab2WFDgyhnSuKbs4GuGzCjR+tIoUuMFg3kgcWKLTwRqanJQ2W00hAsenfaApRC42hbCvK1SlE0HtE9BGgneJO+ELamitD1YjjOYnNYVcraGhtKkW0EqVVeDx733I2NH581k1NNxNLG0i0IJ8/NjVaOZ0tYZ2Vtr0Xv7tPV3hkWp9EFkgS/J0vosngTaSoaG06WHi+xObQkaAdlbanP8B2+2l0f90LmUAAAAASUVORK5CYII=); } /** * Custom BookStack overrides @@ -394,7 +401,8 @@ span.CodeMirror-selectedtext { background: none; } margin-bottom: $-l; border: 1px solid #DDD;; } -.cm-s-base16-light .CodeMirror-gutters { background: #f5f5f5; border-right: 1px solid #DDD; } + +.cm-s-mdn-like .CodeMirror-gutters { background: #f8f8f8; border-left: 0; color: #333; } .code-fill .CodeMirror { position: absolute; From 64455307b13d7eae3d40ab91a75a34ddec3ea686 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 18 Jan 2020 10:04:13 +0000 Subject: [PATCH 155/191] Added a few test to cover api docs pages --- tests/Api/ApiDocsTest.php | 42 ++++++++++++++++++++++++++++++++++++ tests/Api/ApiListingTest.php | 2 -- 2 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 tests/Api/ApiDocsTest.php diff --git a/tests/Api/ApiDocsTest.php b/tests/Api/ApiDocsTest.php new file mode 100644 index 000000000..b240c1672 --- /dev/null +++ b/tests/Api/ApiDocsTest.php @@ -0,0 +1,42 @@ +getViewer(); + $resp = $this->actingAs($viewer)->get($this->endpoint); + $resp->assertStatus(403); + + $resp = $this->actingAsApiEditor()->get($this->endpoint); + $resp->assertStatus(200); + } + + public function test_docs_page_returns_view_with_docs_content() + { + $resp = $this->actingAsApiEditor()->get($this->endpoint); + $resp->assertStatus(200); + $resp->assertSee(url('/api/docs.json')); + $resp->assertSee('Show a JSON view of the API docs data.'); + $resp->assertHeader('Content-Type', 'text/html; charset=UTF-8'); + } + + public function test_docs_json_endpoint_returns_json() + { + $resp = $this->actingAsApiEditor()->get($this->endpoint . '.json'); + $resp->assertStatus(200); + $resp->assertHeader('Content-Type', 'application/json'); + $resp->assertJson([ + 'docs' => [ [ + 'name' => 'docs-display', + 'uri' => 'api/docs' + ] ] + ]); + } +} \ No newline at end of file diff --git a/tests/Api/ApiListingTest.php b/tests/Api/ApiListingTest.php index fa28dfb36..741b9664b 100644 --- a/tests/Api/ApiListingTest.php +++ b/tests/Api/ApiListingTest.php @@ -2,9 +2,7 @@ namespace Tests; -use BookStack\Auth\Permissions\RolePermission; use BookStack\Entities\Book; -use Carbon\Carbon; class ApiListingTest extends TestCase { From b9fb655b60fd8b4ad46699d52a64bd5f29f43ddb Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 18 Jan 2020 14:03:11 +0000 Subject: [PATCH 156/191] Added "Getting Started" API docs --- .../Controllers/Api/BooksApiController.php | 2 +- .../{books-index.json => books-list.json} | 0 resources/js/components/code-highlighter.js | 10 ++ resources/js/components/index.js | 2 + resources/lang/en/settings.php | 1 + resources/views/api-docs/index.blade.php | 157 +++++++++++++++++- .../views/users/api-tokens/list.blade.php | 34 ++++ resources/views/users/edit.blade.php | 34 +--- routes/api.php | 2 +- 9 files changed, 206 insertions(+), 36 deletions(-) rename dev/api/responses/{books-index.json => books-list.json} (100%) create mode 100644 resources/js/components/code-highlighter.js create mode 100644 resources/views/users/api-tokens/list.blade.php diff --git a/app/Http/Controllers/Api/BooksApiController.php b/app/Http/Controllers/Api/BooksApiController.php index fa174dfd3..ac4ea171c 100644 --- a/app/Http/Controllers/Api/BooksApiController.php +++ b/app/Http/Controllers/Api/BooksApiController.php @@ -35,7 +35,7 @@ class BooksApiController extends ApiController /** * Get a listing of books visible to the user. */ - public function index() + public function list() { $books = Book::visible(); return $this->apiListingResponse($books, [ diff --git a/dev/api/responses/books-index.json b/dev/api/responses/books-list.json similarity index 100% rename from dev/api/responses/books-index.json rename to dev/api/responses/books-list.json diff --git a/resources/js/components/code-highlighter.js b/resources/js/components/code-highlighter.js new file mode 100644 index 000000000..db6112887 --- /dev/null +++ b/resources/js/components/code-highlighter.js @@ -0,0 +1,10 @@ +import Code from "../services/code" +class CodeHighlighter { + + constructor(elem) { + Code.highlightWithin(elem); + } + +} + +export default CodeHighlighter; \ No newline at end of file diff --git a/resources/js/components/index.js b/resources/js/components/index.js index d3ba539dd..112827330 100644 --- a/resources/js/components/index.js +++ b/resources/js/components/index.js @@ -31,6 +31,7 @@ import entityPermissionsEditor from "./entity-permissions-editor"; import templateManager from "./template-manager"; import newUserPassword from "./new-user-password"; import detailsHighlighter from "./details-highlighter"; +import codeHighlighter from "./code-highlighter"; const componentMapping = { 'dropdown': dropdown, @@ -66,6 +67,7 @@ const componentMapping = { 'template-manager': templateManager, 'new-user-password': newUserPassword, 'details-highlighter': detailsHighlighter, + 'code-highlighter': codeHighlighter, }; window.components = {}; diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index b1da5435f..fb00c3cce 100755 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -156,6 +156,7 @@ return [ 'users_api_tokens_none' => 'No API tokens have been created for this user', 'users_api_tokens_create' => 'Create Token', 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', // API Tokens 'user_api_token_create' => 'Create API Token', diff --git a/resources/views/api-docs/index.blade.php b/resources/views/api-docs/index.blade.php index a20ba04cc..e9583838c 100644 --- a/resources/views/api-docs/index.blade.php +++ b/resources/views/api-docs/index.blade.php @@ -5,8 +5,17 @@
-
+ +

Getting Started

+ + + @foreach($docs as $model => $endpoints)

{{ $model }}

@@ -24,6 +33,152 @@
+ +
+

Getting Started

+ +
Authentication
+

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

+

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

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

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

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

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

+ +
+ +
Request Format
+

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

+

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

+ +
+ +
Listing Endpoints
+

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

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

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

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

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

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

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

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

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

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

{{ $model }}

diff --git a/resources/views/users/api-tokens/list.blade.php b/resources/views/users/api-tokens/list.blade.php new file mode 100644 index 000000000..ea1893372 --- /dev/null +++ b/resources/views/users/api-tokens/list.blade.php @@ -0,0 +1,34 @@ +
+
+

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

+ +
+ @if (count($user->apiTokens) > 0) + + + + + + + @foreach($user->apiTokens as $token) + + + + + + @endforeach +
{{ trans('common.name') }}{{ trans('settings.users_api_tokens_expires') }}
+ {{ $token->name }}
+ {{ $token->token_id }} +
{{ $token->expires_at->format('Y-m-d') ?? '' }} + {{ trans('common.edit') }} +
+ @else +

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

+ @endif +
\ No newline at end of file diff --git a/resources/views/users/edit.blade.php b/resources/views/users/edit.blade.php index c69d101d4..f78c25ceb 100644 --- a/resources/views/users/edit.blade.php +++ b/resources/views/users/edit.blade.php @@ -89,39 +89,7 @@ @endif @if(($currentUser->id === $user->id && userCan('access-api')) || userCan('users-manage')) -
-
-

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

-
- @if(userCan('access-api')) - {{ trans('settings.users_api_tokens_create') }} - @endif -
-
- @if (count($user->apiTokens) > 0) - - - - - - - @foreach($user->apiTokens as $token) - - - - - - @endforeach -
{{ trans('common.name') }}{{ trans('settings.users_api_tokens_expires') }}
- {{ $token->name }}
- {{ $token->token_id }} -
{{ $token->expires_at->format('Y-m-d') ?? '' }} - {{ trans('common.edit') }} -
- @else -

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

- @endif -
+ @include('users.api-tokens.list', ['user' => $user]) @endif
diff --git a/routes/api.php b/routes/api.php index 12b327798..73f2faf79 100644 --- a/routes/api.php +++ b/routes/api.php @@ -9,7 +9,7 @@ Route::get('docs', 'ApiDocsController@display'); Route::get('docs.json', 'ApiDocsController@json'); -Route::get('books', 'BooksApiController@index'); +Route::get('books', 'BooksApiController@list'); Route::post('books', 'BooksApiController@create'); Route::get('books/{id}', 'BooksApiController@read'); Route::put('books/{id}', 'BooksApiController@update'); From 1350136ca3029b58cc6f930dbe5e5eed539234ce Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 18 Jan 2020 14:07:43 +0000 Subject: [PATCH 157/191] Fixed bad test class name --- tests/Api/BooksApiTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Api/BooksApiTest.php b/tests/Api/BooksApiTest.php index f560bfffd..813e34360 100644 --- a/tests/Api/BooksApiTest.php +++ b/tests/Api/BooksApiTest.php @@ -2,7 +2,7 @@ use BookStack\Entities\Book; -class ApiAuthTest extends TestCase +class BooksApiTest extends TestCase { use TestsApi; From be554b9c797c53a9de301dc58b9e8bc1e8b54ae6 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 18 Jan 2020 15:03:28 +0000 Subject: [PATCH 158/191] Added configurable API throttling, Handled API errors standardly --- .env.example.complete | 5 ++- app/Config/api.php | 3 ++ app/Exceptions/Handler.php | 42 +++++++++++++++++++++ app/Http/Kernel.php | 2 +- app/Http/Middleware/ThrottleApiRequests.php | 18 +++++++++ phpunit.xml | 1 + tests/Api/ApiAuthTest.php | 25 ++++++++++++ tests/Api/ApiConfigTest.php | 11 ++++++ tests/Api/BooksApiTest.php | 20 ++++++++++ 9 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 app/Http/Middleware/ThrottleApiRequests.php diff --git a/.env.example.complete b/.env.example.complete index 716d614a3..e44644f08 100644 --- a/.env.example.complete +++ b/.env.example.complete @@ -260,4 +260,7 @@ ALLOW_ROBOTS=null # The default and maximum item-counts for listing API requests. API_DEFAULT_ITEM_COUNT=100 -API_MAX_ITEM_COUNT=500 \ No newline at end of file +API_MAX_ITEM_COUNT=500 + +# The number of API requests that can be made per minute by a single user. +API_REQUESTS_PER_MIN=180 \ No newline at end of file diff --git a/app/Config/api.php b/app/Config/api.php index dd54b2906..6afea2dc8 100644 --- a/app/Config/api.php +++ b/app/Config/api.php @@ -17,4 +17,7 @@ return [ // The maximum number of items that can be returned in a listing API request. 'max_item_count' => env('API_MAX_ITEM_COUNT', 500), + // The number of API requests that can be made per minute by a single user. + 'requests_per_minute' => env('API_REQUESTS_PER_MIN', 180) + ]; diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 70a534975..284d731d7 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -7,6 +7,9 @@ use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Auth\AuthenticationException; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; +use Illuminate\Http\JsonResponse; +use Illuminate\Http\Request; +use Illuminate\Http\Response; use Illuminate\Validation\ValidationException; use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -47,6 +50,10 @@ class Handler extends ExceptionHandler */ public function render($request, Exception $e) { + if ($this->isApiRequest($request)) { + return $this->renderApiException($e); + } + // Handle notify exceptions which will redirect to the // specified location then show a notification message. if ($this->isExceptionType($e, NotifyException::class)) { @@ -70,6 +77,41 @@ class Handler extends ExceptionHandler return parent::render($request, $e); } + /** + * Check if the given request is an API request. + */ + protected function isApiRequest(Request $request): bool + { + return strpos($request->path(), 'api/') === 0; + } + + /** + * Render an exception when the API is in use. + */ + protected function renderApiException(Exception $e): JsonResponse + { + $code = $e->getCode() === 0 ? 500 : $e->getCode(); + $headers = []; + if ($e instanceof HttpException) { + $code = $e->getStatusCode(); + $headers = $e->getHeaders(); + } + + $responseData = [ + 'error' => [ + 'message' => $e->getMessage(), + ] + ]; + + if ($e instanceof ValidationException) { + $responseData['error']['validation'] = $e->errors(); + $code = $e->status; + } + + $responseData['error']['code'] = $code; + return new JsonResponse($responseData, $code, $headers); + } + /** * Check the exception chain to compare against the original exception type. * @param Exception $e diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 978583a7f..c2016281a 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -32,7 +32,7 @@ class Kernel extends HttpKernel \BookStack\Http\Middleware\GlobalViewData::class, ], 'api' => [ - 'throttle:60,1', + \BookStack\Http\Middleware\ThrottleApiRequests::class, \BookStack\Http\Middleware\EncryptCookies::class, \BookStack\Http\Middleware\StartSessionIfCookieExists::class, \BookStack\Http\Middleware\ApiAuthenticate::class, diff --git a/app/Http/Middleware/ThrottleApiRequests.php b/app/Http/Middleware/ThrottleApiRequests.php new file mode 100644 index 000000000..d08840cd1 --- /dev/null +++ b/app/Http/Middleware/ThrottleApiRequests.php @@ -0,0 +1,18 @@ + + diff --git a/tests/Api/ApiAuthTest.php b/tests/Api/ApiAuthTest.php index b6b6b72ac..2ab81814b 100644 --- a/tests/Api/ApiAuthTest.php +++ b/tests/Api/ApiAuthTest.php @@ -120,4 +120,29 @@ class ApiAuthTest extends TestCase $resp->assertJson($this->errorResponse("The email address for the account in use needs to be confirmed", 401)); } + public function test_rate_limit_headers_active_on_requests() + { + $resp = $this->actingAsApiEditor()->get($this->endpoint); + $resp->assertHeader('x-ratelimit-limit', 180); + $resp->assertHeader('x-ratelimit-remaining', 179); + $resp = $this->actingAsApiEditor()->get($this->endpoint); + $resp->assertHeader('x-ratelimit-remaining', 178); + } + + public function test_rate_limit_hit_gives_json_error() + { + config()->set(['api.requests_per_minute' => 1]); + $resp = $this->actingAsApiEditor()->get($this->endpoint); + $resp->assertStatus(200); + + $resp = $this->actingAsApiEditor()->get($this->endpoint); + $resp->assertStatus(429); + $resp->assertHeader('x-ratelimit-remaining', 0); + $resp->assertHeader('retry-after'); + $resp->assertJson([ + 'error' => [ + 'code' => 429, + ] + ]); + } } \ No newline at end of file diff --git a/tests/Api/ApiConfigTest.php b/tests/Api/ApiConfigTest.php index d9367741f..1b3da2f34 100644 --- a/tests/Api/ApiConfigTest.php +++ b/tests/Api/ApiConfigTest.php @@ -44,4 +44,15 @@ class ApiConfigTest extends TestCase $resp->assertJsonCount(2, 'data'); } + public function test_requests_per_min_alters_rate_limit() + { + $resp = $this->actingAsApiEditor()->get($this->endpoint); + $resp->assertHeader('x-ratelimit-limit', 180); + + config()->set(['api.requests_per_minute' => 10]); + + $resp = $this->actingAsApiEditor()->get($this->endpoint); + $resp->assertHeader('x-ratelimit-limit', 10); + } + } \ No newline at end of file diff --git a/tests/Api/BooksApiTest.php b/tests/Api/BooksApiTest.php index 813e34360..a40e4c93b 100644 --- a/tests/Api/BooksApiTest.php +++ b/tests/Api/BooksApiTest.php @@ -38,6 +38,26 @@ class BooksApiTest extends TestCase $this->assertActivityExists('book_create', $newItem); } + public function test_book_name_needed_to_create() + { + $this->actingAsApiEditor(); + $details = [ + 'description' => 'A book created via the API', + ]; + + $resp = $this->postJson($this->baseEndpoint, $details); + $resp->assertStatus(422); + $resp->assertJson([ + "error" => [ + "message" => "The given data was invalid.", + "validation" => [ + "name" => ["The name field is required."] + ], + "code" => 422, + ], + ]); + } + public function test_read_endpoint() { $this->actingAsApiEditor(); From 4ed23b01872b7c32f282aa68ae35fc94b534bb39 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 18 Jan 2020 15:17:21 +0000 Subject: [PATCH 159/191] Added caching to github action workflow --- .github/workflows/phpunit.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 922aa5067..9a2b03da7 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -10,17 +10,27 @@ jobs: php: [7.2, 7.3] steps: - uses: actions/checkout@v1 + + - name: Cache composer packages + uses: actions/cache@v1 + with: + path: ~/.cache/composer + key: ${{ runner.os }}-node-${{ matrix.php }} + - name: Setup Database run: | mysql -uroot -proot -e 'CREATE DATABASE IF NOT EXISTS `bookstack-test`;' mysql -uroot -proot -e "CREATE USER 'bookstack-test'@'localhost' IDENTIFIED BY 'bookstack-test';" mysql -uroot -proot -e "GRANT ALL ON \`bookstack-test\`.* TO 'bookstack-test'@'localhost';" mysql -uroot -proot -e 'FLUSH PRIVILEGES;' + - name: Install composer dependencies & Test run: composer install --prefer-dist --no-interaction --ansi + - name: Migrate and seed the database run: | php${{ matrix.php }} artisan migrate --force -n --database=mysql_testing php${{ matrix.php }} artisan db:seed --force -n --class=DummyContentSeeder --database=mysql_testing + - name: phpunit run: php${{ matrix.php }} ./vendor/bin/phpunit From 281200e2122fb6ff40a369d2d00ab0b9124925f7 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 18 Jan 2020 15:27:57 +0000 Subject: [PATCH 160/191] Further updated github actions config - Added composer caching based off github docs. - Focused when actions run so they're not running unneccessarily. --- .github/workflows/phpunit.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 9a2b03da7..4a641c56b 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -1,6 +1,15 @@ name: phpunit -on: [push, pull_request] +on: + push: + branches: + - master + - release + pull_request: + branches: + - '*' + - '*/*' + - '!l10n_master' jobs: build: @@ -12,10 +21,13 @@ jobs: - uses: actions/checkout@v1 - name: Cache composer packages + id: composer-cache + run: | + echo "::set-output name=dir::$(composer config cache-files-dir)" uses: actions/cache@v1 with: - path: ~/.cache/composer - key: ${{ runner.os }}-node-${{ matrix.php }} + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ matrix.php }} - name: Setup Database run: | From 0ba75713e1f84d93fe352938e29686ef1fca803b Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 18 Jan 2020 15:30:54 +0000 Subject: [PATCH 161/191] Fixed github action workflow --- .github/workflows/phpunit.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 4a641c56b..f6c002c05 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -20,10 +20,12 @@ jobs: steps: - uses: actions/checkout@v1 - - name: Cache composer packages + - name: Get Composer Cache Directory id: composer-cache run: | echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache composer packages uses: actions/cache@v1 with: path: ${{ steps.composer-cache.outputs.dir }} From 7a2404d5e08a6e5beb31945a809f84134b6e3135 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 18 Jan 2020 16:03:27 +0000 Subject: [PATCH 162/191] New Crowdin translations (#1825) * New translations common.php (Turkish) * New translations errors.php (Turkish) * New translations settings.php (Turkish) * New translations common.php (Italian) * New translations settings.php (Italian) * New translations auth.php (Portuguese, Brazilian) * New translations auth.php (Portuguese, Brazilian) * New translations auth.php (Portuguese, Brazilian) * New translations common.php (Portuguese, Brazilian) * New translations validation.php (Portuguese, Brazilian) * New translations activities.php (Portuguese, Brazilian) * New translations auth.php (Portuguese, Brazilian) * New translations common.php (Portuguese, Brazilian) * New translations activities.php (Portuguese, Brazilian) * New translations components.php (Portuguese, Brazilian) * New translations entities.php (Portuguese, Brazilian) * New translations entities.php (Portuguese, Brazilian) * New translations activities.php (Portuguese, Brazilian) * New translations activities.php (Portuguese, Brazilian) * New translations activities.php (Portuguese, Brazilian) * New translations common.php (Portuguese, Brazilian) * New translations components.php (Portuguese, Brazilian) * New translations passwords.php (Portuguese, Brazilian) * New translations settings.php (Portuguese, Brazilian) * New translations settings.php (Portuguese, Brazilian) * New translations settings.php (Portuguese, Brazilian) * New translations settings.php (Portuguese, Brazilian) * New translations auth.php (Dutch) * New translations auth.php (Dutch) * New translations common.php (Dutch) * New translations settings.php (Dutch) * New translations common.php (Portuguese, Brazilian) * New translations settings.php (Portuguese, Brazilian) * New translations validation.php (Dutch) * New translations settings.php (Portuguese, Brazilian) * New translations components.php (Dutch) * New translations errors.php (Dutch) * New translations settings.php (Dutch) * New translations validation.php (Dutch) * New translations settings.php (Dutch) * New translations validation.php (Dutch) * New translations entities.php (Portuguese, Brazilian) * New translations entities.php (Portuguese, Brazilian) * New translations errors.php (Portuguese, Brazilian) * New translations settings.php (Portuguese, Brazilian) * New translations auth.php (Portuguese, Brazilian) * New translations settings.php (Portuguese, Brazilian) * New translations auth.php (Portuguese, Brazilian) * New translations auth.php (Portuguese, Brazilian) * New translations components.php (Portuguese, Brazilian) * New translations settings.php (Portuguese, Brazilian) * New translations errors.php (Portuguese, Brazilian) * New translations entities.php (Portuguese, Brazilian) * New translations errors.php (Portuguese, Brazilian) * New translations entities.php (Portuguese, Brazilian) * New translations entities.php (Portuguese, Brazilian) * New translations validation.php (Portuguese, Brazilian) * New translations validation.php (Portuguese, Brazilian) * New translations validation.php (Portuguese, Brazilian) * New translations errors.php (Danish) * New translations errors.php (Danish) * New translations activities.php (Danish) * New translations common.php (Danish) * New translations auth.php (Danish) * New translations auth.php (Danish) * New translations passwords.php (Danish) * New translations common.php (Korean) * New translations settings.php (Korean) * New translations settings.php (Korean) * New translations errors.php (Korean) * New translations common.php (Chinese Simplified) * New translations entities.php (Chinese Simplified) * New translations errors.php (Chinese Simplified) * New translations errors.php (Chinese Simplified) * New translations settings.php (Chinese Simplified) * New translations settings.php (Korean) * New translations settings.php (Spanish) * New translations settings.php (Polish) * New translations errors.php (Portuguese, Brazilian) * New translations settings.php (Portuguese, Brazilian) * New translations errors.php (Russian) * New translations settings.php (Russian) * New translations errors.php (Slovak) * New translations settings.php (Slovak) * New translations errors.php (Spanish) * New translations errors.php (Spanish, Argentina) * New translations settings.php (Japanese) * New translations settings.php (Spanish, Argentina) * New translations errors.php (Swedish) * New translations settings.php (Swedish) * New translations errors.php (Turkish) * New translations settings.php (Turkish) * New translations errors.php (Ukrainian) * New translations settings.php (Ukrainian) * New translations errors.php (German Informal) * New translations errors.php (Polish) * New translations errors.php (Japanese) * New translations errors.php (Korean) * New translations errors.php (Danish) * New translations errors.php (Chinese Simplified) * New translations settings.php (Chinese Simplified) * New translations errors.php (Arabic) * New translations settings.php (Arabic) * New translations errors.php (Chinese Traditional) * New translations settings.php (Chinese Traditional) * New translations errors.php (Czech) * New translations settings.php (Czech) * New translations settings.php (Danish) * New translations settings.php (Italian) * New translations errors.php (Dutch) * New translations settings.php (Dutch) * New translations errors.php (French) * New translations settings.php (French) * New translations errors.php (German) * New translations settings.php (German) * New translations errors.php (Hungarian) * New translations settings.php (Hungarian) * New translations errors.php (Italian) * New translations settings.php (German Informal) --- resources/lang/ar/errors.php | 9 + resources/lang/ar/settings.php | 27 +++ resources/lang/cs/errors.php | 9 + resources/lang/cs/settings.php | 27 +++ resources/lang/da/activities.php | 48 ++++++ resources/lang/da/auth.php | 77 +++++++++ resources/lang/da/common.php | 77 +++++++++ resources/lang/da/errors.php | 100 +++++++++++ resources/lang/da/passwords.php | 15 ++ resources/lang/da/settings.php | 210 ++++++++++++++++++++++++ resources/lang/de/errors.php | 9 + resources/lang/de/settings.php | 27 +++ resources/lang/de_informal/errors.php | 9 + resources/lang/de_informal/settings.php | 27 +++ resources/lang/es/errors.php | 9 + resources/lang/es/settings.php | 27 +++ resources/lang/es_AR/errors.php | 9 + resources/lang/es_AR/settings.php | 27 +++ resources/lang/fr/errors.php | 9 + resources/lang/fr/settings.php | 27 +++ resources/lang/hu/errors.php | 9 + resources/lang/hu/settings.php | 27 +++ resources/lang/it/common.php | 2 +- resources/lang/it/errors.php | 9 + resources/lang/it/settings.php | 43 ++++- resources/lang/ja/errors.php | 9 + resources/lang/ja/settings.php | 27 +++ resources/lang/ko/common.php | 4 +- resources/lang/ko/errors.php | 21 ++- resources/lang/ko/settings.php | 57 +++++-- resources/lang/nl/auth.php | 26 +-- resources/lang/nl/common.php | 14 +- resources/lang/nl/components.php | 6 +- resources/lang/nl/errors.php | 39 +++-- resources/lang/nl/settings.php | 133 +++++++++------ resources/lang/nl/validation.php | 156 +++++++++--------- resources/lang/pl/errors.php | 9 + resources/lang/pl/settings.php | 27 +++ resources/lang/pt_BR/activities.php | 42 ++--- resources/lang/pt_BR/auth.php | 68 ++++---- resources/lang/pt_BR/common.php | 26 +-- resources/lang/pt_BR/components.php | 12 +- resources/lang/pt_BR/entities.php | 168 +++++++++---------- resources/lang/pt_BR/errors.php | 69 ++++---- resources/lang/pt_BR/passwords.php | 8 +- resources/lang/pt_BR/settings.php | 179 +++++++++++--------- resources/lang/pt_BR/validation.php | 86 +++++----- resources/lang/ru/errors.php | 9 + resources/lang/ru/settings.php | 27 +++ resources/lang/sk/errors.php | 9 + resources/lang/sk/settings.php | 27 +++ resources/lang/sv/errors.php | 9 + resources/lang/sv/settings.php | 27 +++ resources/lang/tr/common.php | 2 +- resources/lang/tr/errors.php | 21 ++- resources/lang/tr/settings.php | 39 ++++- resources/lang/uk/errors.php | 9 + resources/lang/uk/settings.php | 27 +++ resources/lang/zh_CN/common.php | 2 +- resources/lang/zh_CN/entities.php | 2 +- resources/lang/zh_CN/errors.php | 21 ++- resources/lang/zh_CN/settings.php | 59 +++++-- resources/lang/zh_TW/errors.php | 9 + resources/lang/zh_TW/settings.php | 27 +++ 64 files changed, 1832 insertions(+), 549 deletions(-) create mode 100644 resources/lang/da/activities.php create mode 100644 resources/lang/da/auth.php create mode 100644 resources/lang/da/common.php create mode 100644 resources/lang/da/errors.php create mode 100644 resources/lang/da/passwords.php create mode 100644 resources/lang/da/settings.php diff --git a/resources/lang/ar/errors.php b/resources/lang/ar/errors.php index 955efbd23..961ce7351 100644 --- a/resources/lang/ar/errors.php +++ b/resources/lang/ar/errors.php @@ -13,6 +13,7 @@ return [ 'email_already_confirmed' => 'تم تأكيد البريد الإلكتروني من قبل, الرجاء محاولة تسجيل الدخول.', 'email_confirmation_invalid' => 'رابط التأكيد غير صحيح أو قد تم استخدامه من قبل, الرجاء محاولة التسجيل من جديد.', 'email_confirmation_expired' => 'صلاحية رابط التأكيد انتهت, تم إرسال رسالة تأكيد جديدة لعنوان البريد الإلكتروني.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'فشل الوصول إلى LDAP باستخدام الربط المجهول', 'ldap_fail_authed' => 'فشل الوصول إلى LDAP باستخدام dn و password المعطاة', 'ldap_extension_not_installed' => 'لم يتم تثبيت إضافة LDAP PHP', @@ -88,4 +89,12 @@ return [ 'app_down' => ':appName لا يعمل حالياً', 'back_soon' => 'سيعود للعمل قريباً.', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + ]; diff --git a/resources/lang/ar/settings.php b/resources/lang/ar/settings.php index 4b12d0541..26b936254 100755 --- a/resources/lang/ar/settings.php +++ b/resources/lang/ar/settings.php @@ -103,6 +103,7 @@ return [ 'role_manage_entity_permissions' => 'إدارة جميع أذونات الكتب والفصول والصفحات', 'role_manage_own_entity_permissions' => 'إدارة الأذونات الخاصة بكتابك أو فصلك أو صفحاتك', 'role_manage_page_templates' => 'Manage page templates', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'إدارة إعدادات التطبيق', 'role_asset' => 'Asset Permissions', 'role_asset_desc' => 'These permissions control default access to the assets within the system. Permissions on Books, Chapters and Pages will override these permissions.', @@ -151,6 +152,32 @@ return [ 'users_social_disconnect' => 'فصل الحساب', 'users_social_connected' => 'تم ربط حساب :socialAccount بملفك بنجاح.', 'users_social_disconnected' => 'تم فصل حساب :socialAccount من ملفك بنجاح.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/lang/cs/errors.php b/resources/lang/cs/errors.php index 0e4757ed4..5d9a3feb9 100644 --- a/resources/lang/cs/errors.php +++ b/resources/lang/cs/errors.php @@ -13,6 +13,7 @@ return [ 'email_already_confirmed' => 'Emailová adresa již byla potvrzena. Zkuste se přihlásit.', 'email_confirmation_invalid' => 'Tento potvrzovací odkaz již neplatí nebo už byl použit. Zkuste prosím registraci znovu.', 'email_confirmation_expired' => 'Potvrzovací odkaz už neplatí, email s novým odkazem už byl poslán.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'Přístup k adresáři LDAP jako anonymní uživatel (anonymous bind) selhal', 'ldap_fail_authed' => 'Přístup k adresáři LDAP pomocí zadaného jména (dn) a hesla selhal', 'ldap_extension_not_installed' => 'Není nainstalováno rozšíření LDAP pro PHP', @@ -88,4 +89,12 @@ return [ 'app_down' => ':appName je momentálně vypnutá', 'back_soon' => 'Brzy naběhne.', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + ]; diff --git a/resources/lang/cs/settings.php b/resources/lang/cs/settings.php index 57c874a53..ca10a3318 100644 --- a/resources/lang/cs/settings.php +++ b/resources/lang/cs/settings.php @@ -103,6 +103,7 @@ return [ 'role_manage_entity_permissions' => 'Správa práv všech knih, kapitol a stránek', 'role_manage_own_entity_permissions' => 'Správa práv vlastních knih, kapitol a stránek', 'role_manage_page_templates' => 'Manage page templates', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Správa nastavení aplikace', 'role_asset' => 'Práva děl', 'role_asset_desc' => 'Tato práva řídí přístup k dílům v rámci systému. Specifická práva na knihách, kapitolách a stránkách překryjí tato nastavení.', @@ -151,6 +152,32 @@ return [ 'users_social_disconnect' => 'Zrušit přidružení', 'users_social_connected' => 'Účet :socialAccount byl úspěšně přidružen k vašemu profilu.', 'users_social_disconnected' => 'Přidružení účtu :socialAccount k vašemu profilu bylo úspěšně zrušeno.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/lang/da/activities.php b/resources/lang/da/activities.php new file mode 100644 index 000000000..a72e9210b --- /dev/null +++ b/resources/lang/da/activities.php @@ -0,0 +1,48 @@ + 'oprettede side', + 'page_create_notification' => 'Siden blev oprettet', + 'page_update' => 'opdaterede side', + 'page_update_notification' => 'Siden blev opdateret', + 'page_delete' => 'slettede side', + 'page_delete_notification' => 'Siden blev slettet', + 'page_restore' => 'gendannede side', + 'page_restore_notification' => 'Siden blev gendannet', + 'page_move' => 'flyttede side', + + // Chapters + 'chapter_create' => 'oprettede kapitel', + 'chapter_create_notification' => 'Kapitel blev oprettet', + 'chapter_update' => 'opdaterede kapitel', + 'chapter_update_notification' => 'Kapitel blev opdateret', + 'chapter_delete' => 'slettede kapitel', + 'chapter_delete_notification' => 'Kapitel blev slettet', + 'chapter_move' => 'flyttede kapitel', + + // Books + 'book_create' => 'oprettede bog', + 'book_create_notification' => 'Bogen blev oprettet', + 'book_update' => 'opdaterede bog', + 'book_update_notification' => 'Bogen blev opdateret', + 'book_delete' => 'slettede bog', + 'book_delete_notification' => 'Bogen blev slettet', + 'book_sort' => 'sorterede bogen', + 'book_sort_notification' => 'Bogen blev re-sorteret', + + // Bookshelves + 'bookshelf_create' => 'oprettede bogreol', + 'bookshelf_create_notification' => 'Bogreolen blev oprettet', + 'bookshelf_update' => 'opdaterede bogreolen', + 'bookshelf_update_notification' => 'Bogreolen blev opdateret', + 'bookshelf_delete' => 'slettede bogreol', + 'bookshelf_delete_notification' => 'Bogreolen blev opdateret', + + // Other + 'commented_on' => 'kommenterede til', +]; diff --git a/resources/lang/da/auth.php b/resources/lang/da/auth.php new file mode 100644 index 000000000..fe1b62079 --- /dev/null +++ b/resources/lang/da/auth.php @@ -0,0 +1,77 @@ + 'Det indtastede stemmer ikke overens med vores registrering.', + 'throttle' => 'For mange mislykkede loginforsøg. Prøv igen om :seconds seconds.', + + // Login & Register + 'sign_up' => 'Registrér', + 'log_in' => 'Log ind', + 'log_in_with' => 'Log ind med :socialDriver', + 'sign_up_with' => 'Registrér med :socialDriver', + 'logout' => 'Log ud', + + 'name' => 'Navn', + 'username' => 'Brugernavn', + 'email' => 'E-mail', + 'password' => 'Adgangskode', + 'password_confirm' => 'Bekræft adgangskode', + 'password_hint' => 'Skal være på mindst 8 karakterer', + 'forgot_password' => 'Glemt Adgangskode?', + 'remember_me' => 'Husk Mig', + 'ldap_email_hint' => 'Angiv venligst din kontos e-mail.', + 'create_account' => 'Opret Konto', + 'already_have_account' => 'Har du allerede en konto?', + 'dont_have_account' => 'Har du ikke en konto?', + 'social_login' => 'Social Log ind', + 'social_registration' => 'Social Registrering', + 'social_registration_text' => 'Registrér og log ind med anden service.', + + 'register_thanks' => 'Tak for registreringen!', + 'register_confirm' => 'Check venligst din e-mail og klik deri på bekræftelses knappen for at tilgå :appName.', + 'registrations_disabled' => 'Registrations are currently disabled', + 'registration_email_domain_invalid' => 'That email domain does not have access to this application', + 'register_success' => 'Thanks for signing up! You are now registered and signed in.', + + + // Password Reset + 'reset_password' => 'Reset Password', + 'reset_password_send_instructions' => 'Enter your email below and you will be sent an email with a password reset link.', + 'reset_password_send_button' => 'Send Reset Link', + 'reset_password_sent_success' => 'A password reset link has been sent to :email.', + 'reset_password_success' => 'Your password has been successfully reset.', + 'email_reset_subject' => 'Reset your :appName password', + 'email_reset_text' => 'You are receiving this email because we received a password reset request for your account.', + 'email_reset_not_requested' => 'If you did not request a password reset, no further action is required.', + + + // Email Confirmation + 'email_confirm_subject' => 'Confirm your email on :appName', + 'email_confirm_greeting' => 'Thanks for joining :appName!', + 'email_confirm_text' => 'Please confirm your email address by clicking the button below:', + 'email_confirm_action' => 'Confirm Email', + 'email_confirm_send_error' => 'Email confirmation required but the system could not send the email. Contact the admin to ensure email is set up correctly.', + 'email_confirm_success' => 'Your email has been confirmed!', + 'email_confirm_resent' => 'Confirmation email resent, Please check your inbox.', + + 'email_not_confirmed' => 'Email Address Not Confirmed', + 'email_not_confirmed_text' => 'Your email address has not yet been confirmed.', + 'email_not_confirmed_click_link' => 'Please click the link in the email that was sent shortly after you registered.', + 'email_not_confirmed_resend' => 'If you cannot find the email you can re-send the confirmation email by submitting the form below.', + 'email_not_confirmed_resend_button' => 'Resend Confirmation Email', + + // User Invite + 'user_invite_email_subject' => 'You have been invited to join :appName!', + 'user_invite_email_greeting' => 'An account has been created for you on :appName.', + 'user_invite_email_text' => 'Click the button below to set an account password and gain access:', + 'user_invite_email_action' => 'Set Account Password', + 'user_invite_page_welcome' => 'Welcome to :appName!', + 'user_invite_page_text' => 'To finalise your account and gain access you need to set a password which will be used to log-in to :appName on future visits.', + 'user_invite_page_confirm_button' => 'Confirm Password', + 'user_invite_success' => 'Password set, you now have access to :appName!' +]; \ No newline at end of file diff --git a/resources/lang/da/common.php b/resources/lang/da/common.php new file mode 100644 index 000000000..be37d11ae --- /dev/null +++ b/resources/lang/da/common.php @@ -0,0 +1,77 @@ + 'Annuller', + 'confirm' => 'Bekræft', + 'back' => 'Tilbage', + 'save' => 'Gem', + 'continue' => 'Fortsæt', + 'select' => 'Vælg', + 'toggle_all' => 'Vælg/Fravælg alle', + 'more' => 'Mere', + + // Form Labels + 'name' => 'Navn', + 'description' => 'Beskrivelse', + 'role' => 'Rolle', + 'cover_image' => 'Coverbillede', + 'cover_image_description' => 'This image should be approx 440x250px.', + + // Actions + 'actions' => 'Actions', + 'view' => 'Vis', + 'view_all' => 'Vis alle', + 'create' => 'Opret', + 'update' => 'Opdater', + 'edit' => 'Rediger', + 'sort' => 'Sorter', + 'move' => 'Flyt', + 'copy' => 'Kopier', + 'reply' => 'Besvar', + 'delete' => 'Slet', + 'search' => 'Søg', + 'search_clear' => 'Ryd søgning', + 'reset' => 'Nulstil', + 'remove' => 'Fjern', + 'add' => 'Tilføj', + 'fullscreen' => 'Fuld skærm', + + // Sort Options + 'sort_options' => 'Sorteringsindstillinger', + 'sort_direction_toggle' => 'Sort Direction Toggle', + 'sort_ascending' => 'Sort Ascending', + 'sort_descending' => 'Sort Descending', + 'sort_name' => 'Name', + 'sort_created_at' => 'Created Date', + 'sort_updated_at' => 'Updated Date', + + // Misc + 'deleted_user' => 'Deleted User', + 'no_activity' => 'No activity to show', + 'no_items' => 'No items available', + 'back_to_top' => 'Back to top', + 'toggle_details' => 'Toggle Details', + 'toggle_thumbnails' => 'Toggle Thumbnails', + 'details' => 'Details', + 'grid_view' => 'Grid View', + 'list_view' => 'List View', + 'default' => 'Default', + 'breadcrumb' => 'Breadcrumb', + + // Header + 'profile_menu' => 'Profile Menu', + 'view_profile' => 'View Profile', + 'edit_profile' => 'Edit Profile', + + // Layout tabs + 'tab_info' => 'Info', + 'tab_content' => 'Content', + + // Email Content + 'email_action_help' => 'If you’re having trouble clicking the ":actionText" button, copy and paste the URL below into your web browser:', + 'email_rights' => 'All rights reserved', +]; diff --git a/resources/lang/da/errors.php b/resources/lang/da/errors.php new file mode 100644 index 000000000..5d286b03c --- /dev/null +++ b/resources/lang/da/errors.php @@ -0,0 +1,100 @@ + 'Du har ikke tilladelse til at tilgå den efterspurgte side.', + 'permissionJson' => 'Du har ikke tilladelse til at udføre den valgte handling.', + + // Auth + 'error_user_exists_different_creds' => 'En bruger med email :email eksistere allerede, men med andre legitimationsoplysninger.', + 'email_already_confirmed' => 'Email er allerede bekræftet. Prøv at logge ind.', + 'email_confirmation_invalid' => 'Denne bekræftelsestoken er ikke gyldig eller er allerede blevet brugt. Prøv at registrere dig igen.', + 'email_confirmation_expired' => 'Bekræftelsestoken er udløbet. En ny bekræftelsesmail er blevet sendt.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', + 'ldap_fail_anonymous' => 'LDAP access failed using anonymous bind', + 'ldap_fail_authed' => 'LDAP adgang fejlede med de givne DN & kodeord oplysninger', + 'ldap_extension_not_installed' => 'LDAP PHP udvidelse er ikke installeret', + 'ldap_cannot_connect' => 'Kan ikke forbinde til ldap server. Indledende forbindelse mislykkedes', + 'saml_already_logged_in' => 'Allerede logget ind', + 'saml_user_not_registered' => 'Brugeren :name er ikke registreret, og automatisk registrering er slået fra', + 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', + 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', + 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', + 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', + 'social_no_action_defined' => 'No action defined', + 'social_login_bad_response' => "Error received during :socialAccount login: \n:error", + 'social_account_in_use' => 'This :socialAccount account is already in use, Try logging in via the :socialAccount option.', + 'social_account_email_in_use' => 'The email :email is already in use. If you already have an account you can connect your :socialAccount account from your profile settings.', + 'social_account_existing' => 'This :socialAccount is already attached to your profile.', + 'social_account_already_used_existing' => 'This :socialAccount account is already used by another user.', + 'social_account_not_used' => 'This :socialAccount account is not linked to any users. Please attach it in your profile settings. ', + 'social_account_register_instructions' => 'If you do not yet have an account, You can register an account using the :socialAccount option.', + 'social_driver_not_found' => 'Social driver not found', + 'social_driver_not_configured' => 'Your :socialAccount social settings are not configured correctly.', + 'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.', + + // System + 'path_not_writable' => 'File path :filePath could not be uploaded to. Ensure it is writable to the server.', + 'cannot_get_image_from_url' => 'Cannot get image from :url', + 'cannot_create_thumbs' => 'The server cannot create thumbnails. Please check you have the GD PHP extension installed.', + 'server_upload_limit' => 'The server does not allow uploads of this size. Please try a smaller file size.', + 'uploaded' => 'The server does not allow uploads of this size. Please try a smaller file size.', + 'image_upload_error' => 'An error occurred uploading the image', + 'image_upload_type_error' => 'The image type being uploaded is invalid', + 'file_upload_timeout' => 'The file upload has timed out.', + + // Attachments + 'attachment_page_mismatch' => 'Page mismatch during attachment update', + 'attachment_not_found' => 'Attachment not found', + + // Pages + 'page_draft_autosave_fail' => 'Failed to save draft. Ensure you have internet connection before saving this page', + 'page_custom_home_deletion' => 'Cannot delete a page while it is set as a homepage', + + // Entities + 'entity_not_found' => 'Entity not found', + 'bookshelf_not_found' => 'Bookshelf not found', + 'book_not_found' => 'Book not found', + 'page_not_found' => 'Page not found', + 'chapter_not_found' => 'Chapter not found', + 'selected_book_not_found' => 'The selected book was not found', + 'selected_book_chapter_not_found' => 'The selected Book or Chapter was not found', + 'guests_cannot_save_drafts' => 'Guests cannot save drafts', + + // Users + 'users_cannot_delete_only_admin' => 'You cannot delete the only admin', + 'users_cannot_delete_guest' => 'You cannot delete the guest user', + + // Roles + 'role_cannot_be_edited' => 'This role cannot be edited', + 'role_system_cannot_be_deleted' => 'This role is a system role and cannot be deleted', + 'role_registration_default_cannot_delete' => 'This role cannot be deleted while set as the default registration role', + 'role_cannot_remove_only_admin' => 'This user is the only user assigned to the administrator role. Assign the administrator role to another user before attempting to remove it here.', + + // Comments + 'comment_list' => 'An error occurred while fetching the comments.', + 'cannot_add_comment_to_draft' => 'You cannot add comments to a draft.', + 'comment_add' => 'An error occurred while adding / updating the comment.', + 'comment_delete' => 'An error occurred while deleting the comment.', + 'empty_comment' => 'Cannot add an empty comment.', + + // Error pages + '404_page_not_found' => 'Page Not Found', + 'sorry_page_not_found' => 'Sorry, The page you were looking for could not be found.', + 'return_home' => 'Return to home', + 'error_occurred' => 'An Error Occurred', + 'app_down' => ':appName is down right now', + 'back_soon' => 'It will be back up soon.', + + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + +]; diff --git a/resources/lang/da/passwords.php b/resources/lang/da/passwords.php new file mode 100644 index 000000000..b4ace5513 --- /dev/null +++ b/resources/lang/da/passwords.php @@ -0,0 +1,15 @@ + 'Adgangskoder skal være mindst otte tegn og svare til bekræftelsen.', + 'user' => "Vi kan ikke finde en bruger med den e-mail adresse.", + 'token' => 'Denne adgangskode nulstillingstoken er ugyldig.', + 'sent' => 'Vi har sendt dig en e-mail med et link til at nulstille adgangskoden!', + 'reset' => 'Dit kodeord er blevet nulstillet!', + +]; diff --git a/resources/lang/da/settings.php b/resources/lang/da/settings.php new file mode 100644 index 000000000..9bf384c3b --- /dev/null +++ b/resources/lang/da/settings.php @@ -0,0 +1,210 @@ + 'Indstillinger', + 'settings_save' => 'Gem indstillinger', + 'settings_save_success' => 'Indstillinger gemt', + + // App Settings + 'app_customization' => 'Customization', + 'app_features_security' => 'Features & Security', + 'app_name' => 'Application Name', + 'app_name_desc' => 'This name is shown in the header and in any system-sent emails.', + 'app_name_header' => 'Show name in header', + 'app_public_access' => 'Offentlig adgang', + 'app_public_access_desc' => 'Enabling this option will allow visitors, that are not logged-in, to access content in your BookStack instance.', + 'app_public_access_desc_guest' => 'Access for public visitors can be controlled through the "Guest" user.', + 'app_public_access_toggle' => 'Tillad offentlig adgang', + 'app_public_viewing' => 'Allow public viewing?', + 'app_secure_images' => 'Higher Security Image Uploads', + 'app_secure_images_toggle' => 'Enable higher security image uploads', + 'app_secure_images_desc' => 'For performance reasons, all images are public. This option adds a random, hard-to-guess string in front of image urls. Ensure directory indexes are not enabled to prevent easy access.', + 'app_editor' => 'Page Editor', + 'app_editor_desc' => 'Select which editor will be used by all users to edit pages.', + 'app_custom_html' => 'Custom HTML Head Content', + 'app_custom_html_desc' => 'Any content added here will be inserted into the bottom of the section of every page. This is handy for overriding styles or adding analytics code.', + 'app_custom_html_disabled_notice' => 'Custom HTML head content is disabled on this settings page to ensure any breaking changes can be reverted.', + 'app_logo' => 'Application Logo', + 'app_logo_desc' => 'This image should be 43px in height.
Large images will be scaled down.', + 'app_primary_color' => 'Application Primary Color', + 'app_primary_color_desc' => 'Sets the primary color for the application including the banner, buttons, and links.', + 'app_homepage' => 'Application Homepage', + 'app_homepage_desc' => 'Select a view to show on the homepage instead of the default view. Page permissions are ignored for selected pages.', + 'app_homepage_select' => 'Vælg en side', + 'app_disable_comments' => 'Disable Comments', + 'app_disable_comments_toggle' => 'Disable comments', + 'app_disable_comments_desc' => 'Disables comments across all pages in the application.
Existing comments are not shown.', + + // Color settings + 'content_colors' => 'Content Colors', + 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'bookshelf_color' => 'Shelf Color', + 'book_color' => 'Book Color', + 'chapter_color' => 'Chapter Color', + 'page_color' => 'Sidefarve', + 'page_draft_color' => 'Page Draft Color', + + // Registration Settings + 'reg_settings' => 'Registrering', + 'reg_enable' => 'Aktivér tilmelding', + 'reg_enable_toggle' => 'Aktivér tilmelding', + 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', + 'reg_default_role' => 'Default user role after registration', + 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', + 'reg_email_confirmation' => 'Email bekræftelse', + 'reg_email_confirmation_toggle' => 'Require email confirmation', + 'reg_confirm_email_desc' => 'If domain restriction is used then email confirmation will be required and this option will be ignored.', + 'reg_confirm_restrict_domain' => 'Domain Restriction', + 'reg_confirm_restrict_domain_desc' => 'Enter a comma separated list of email domains you would like to restrict registration to. Users will be sent an email to confirm their address before being allowed to interact with the application.
Note that users will be able to change their email addresses after successful registration.', + 'reg_confirm_restrict_domain_placeholder' => 'No restriction set', + + // Maintenance settings + 'maint' => 'Vedligeholdelse', + 'maint_image_cleanup' => 'Cleanup Images', + 'maint_image_cleanup_desc' => "Scans page & revision content to check which images and drawings are currently in use and which images are redundant. Ensure you create a full database and image backup before running this.", + 'maint_image_cleanup_ignore_revisions' => 'Ignore images in revisions', + 'maint_image_cleanup_run' => 'Run Cleanup', + 'maint_image_cleanup_warning' => ':count potentially unused images were found. Are you sure you want to delete these images?', + 'maint_image_cleanup_success' => ':count potentially unused images found and deleted!', + 'maint_image_cleanup_nothing_found' => 'No unused images found, Nothing deleted!', + 'maint_send_test_email' => 'Send a Test Email', + 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', + 'maint_send_test_email_run' => 'Send test email', + 'maint_send_test_email_success' => 'Email sent to :address', + 'maint_send_test_email_mail_subject' => 'Test Email', + 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', + 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', + + // Role Settings + 'roles' => 'Roller', + 'role_user_roles' => 'Brugerroller', + 'role_create' => 'Opret en ny rolle', + 'role_create_success' => 'Rollen blev oprette korrekt', + 'role_delete' => 'Slet rolle', + 'role_delete_confirm' => 'This will delete the role with the name \':roleName\'.', + 'role_delete_users_assigned' => 'This role has :userCount users assigned to it. If you would like to migrate the users from this role select a new role below.', + 'role_delete_no_migration' => "Don't migrate users", + 'role_delete_sure' => 'Are you sure you want to delete this role?', + 'role_delete_success' => 'Role successfully deleted', + 'role_edit' => 'Rediger rolle', + 'role_details' => 'Role Details', + 'role_name' => 'Rollenavn', + 'role_desc' => 'Short Description of Role', + 'role_external_auth_id' => 'External Authentication IDs', + 'role_system' => 'System Permissions', + 'role_manage_users' => 'Administrere brugere', + 'role_manage_roles' => 'Manage roles & role permissions', + 'role_manage_entity_permissions' => 'Manage all book, chapter & page permissions', + 'role_manage_own_entity_permissions' => 'Manage permissions on own book, chapter & pages', + 'role_manage_page_templates' => 'Manage page templates', + 'role_access_api' => 'Access system API', + 'role_manage_settings' => 'Manage app settings', + 'role_asset' => 'Asset Permissions', + 'role_asset_desc' => 'These permissions control default access to the assets within the system. Permissions on Books, Chapters and Pages will override these permissions.', + 'role_asset_admins' => 'Admins are automatically given access to all content but these options may show or hide UI options.', + 'role_all' => 'Alle', + 'role_own' => 'Eget', + 'role_controlled_by_asset' => 'Controlled by the asset they are uploaded to', + 'role_save' => 'Save Role', + 'role_update_success' => 'Role successfully updated', + 'role_users' => 'Users in this role', + 'role_users_none' => 'No users are currently assigned to this role', + + // Users + 'users' => 'Brugere', + 'user_profile' => 'Brugerprofil', + 'users_add_new' => 'Tilføj ny bruger', + 'users_search' => 'Søg efter brugere', + 'users_details' => 'Brugeroplysninger', + 'users_details_desc' => 'Set a display name and an email address for this user. The email address will be used for logging into the application.', + 'users_details_desc_no_email' => 'Set a display name for this user so others can recognise them.', + 'users_role' => 'Brugerroller', + 'users_role_desc' => 'Select which roles this user will be assigned to. If a user is assigned to multiple roles the permissions from those roles will stack and they will receive all abilities of the assigned roles.', + 'users_password' => 'User Password', + 'users_password_desc' => 'Set a password used to log-in to the application. This must be at least 6 characters long.', + 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', + 'users_send_invite_option' => 'Send user invite email', + 'users_external_auth_id' => 'Ekstern godkendelses ID', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your LDAP system.', + 'users_password_warning' => 'Only fill the below if you would like to change your password.', + 'users_system_public' => 'This user represents any guest users that visit your instance. It cannot be used to log in but is assigned automatically.', + 'users_delete' => 'Delete User', + 'users_delete_named' => 'Delete user :userName', + 'users_delete_warning' => 'This will fully delete this user with the name \':userName\' from the system.', + 'users_delete_confirm' => 'Are you sure you want to delete this user?', + 'users_delete_success' => 'Users successfully removed', + 'users_edit' => 'Edit User', + 'users_edit_profile' => 'Edit Profile', + 'users_edit_success' => 'User successfully updated', + 'users_avatar' => 'User Avatar', + 'users_avatar_desc' => 'Select an image to represent this user. This should be approx 256px square.', + 'users_preferred_language' => 'Preferred Language', + 'users_preferred_language_desc' => 'This option will change the language used for the user-interface of the application. This will not affect any user-created content.', + 'users_social_accounts' => 'Social Accounts', + 'users_social_accounts_info' => 'Here you can connect your other accounts for quicker and easier login. Disconnecting an account here does not revoke previously authorized access. Revoke access from your profile settings on the connected social account.', + 'users_social_connect' => 'Connect Account', + 'users_social_disconnect' => 'Disconnect Account', + 'users_social_connected' => ':socialAccount kontoen blev knyttet til din profil.', + 'users_social_disconnected' => ':socialAccount kontoen blev afbrudt fra din profil.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', + + //! If editing translations files directly please ignore this in all + //! languages apart from en. Content will be auto-copied from en. + //!//////////////////////////////// + 'language_select' => [ + 'en' => 'English', + 'ar' => 'العربية', + 'de' => 'Deutsch (Sie)', + 'de_informal' => 'Deutsch (Du)', + 'es' => 'Español', + 'es_AR' => 'Español Argentina', + 'fr' => 'Français', + 'nl' => 'Nederlands', + 'pt_BR' => 'Português do Brasil', + 'sk' => 'Slovensky', + 'cs' => 'Česky', + 'sv' => 'Svenska', + 'ko' => '한국어', + 'ja' => '日本語', + 'pl' => 'Polski', + 'it' => 'Italian', + 'ru' => 'Русский', + 'uk' => 'Українська', + 'zh_CN' => '简体中文', + 'zh_TW' => '繁體中文', + 'hu' => 'Magyar', + 'tr' => 'Türkçe', + ] + //!//////////////////////////////// +]; diff --git a/resources/lang/de/errors.php b/resources/lang/de/errors.php index 0ed6cea66..1912d01a0 100644 --- a/resources/lang/de/errors.php +++ b/resources/lang/de/errors.php @@ -13,6 +13,7 @@ return [ 'email_already_confirmed' => 'Die E-Mail-Adresse ist bereits bestätigt. Bitte melden Sie sich an.', 'email_confirmation_invalid' => 'Der Bestätigungslink ist nicht gültig oder wurde bereits verwendet. Bitte registrieren Sie sich erneut.', 'email_confirmation_expired' => 'Der Bestätigungslink ist abgelaufen. Es wurde eine neue Bestätigungs-E-Mail gesendet.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'Anonymer LDAP-Zugriff ist fehlgeschlafgen', 'ldap_fail_authed' => 'LDAP-Zugriff mit DN und Passwort ist fehlgeschlagen', 'ldap_extension_not_installed' => 'LDAP-PHP-Erweiterung ist nicht installiert.', @@ -88,4 +89,12 @@ return [ 'app_down' => ':appName befindet sich aktuell im Wartungsmodus.', 'back_soon' => 'Wir werden so schnell wie möglich wieder online sein.', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + ]; diff --git a/resources/lang/de/settings.php b/resources/lang/de/settings.php index 103515739..29f5d42bb 100644 --- a/resources/lang/de/settings.php +++ b/resources/lang/de/settings.php @@ -106,6 +106,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'role_manage_entity_permissions' => 'Alle Buch-, Kapitel- und Seiten-Berechtigungen verwalten', 'role_manage_own_entity_permissions' => 'Nur Berechtigungen eigener Bücher, Kapitel und Seiten verwalten', 'role_manage_page_templates' => 'Seitenvorlagen verwalten', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Globaleinstellungen verwalten', 'role_asset' => 'Berechtigungen', 'role_asset_desc' => 'Diese Berechtigungen gelten für den Standard-Zugriff innerhalb des Systems. Berechtigungen für Bücher, Kapitel und Seiten überschreiben diese Berechtigungenen.', @@ -154,6 +155,32 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'users_social_disconnect' => 'Social-Media-Konto lösen', 'users_social_connected' => ':socialAccount-Konto wurde erfolgreich mit dem Profil verknüpft.', 'users_social_disconnected' => ':socialAccount-Konto wurde erfolgreich vom Profil gelöst.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/lang/de_informal/errors.php b/resources/lang/de_informal/errors.php index dc33f4239..097c983af 100644 --- a/resources/lang/de_informal/errors.php +++ b/resources/lang/de_informal/errors.php @@ -13,6 +13,7 @@ return [ 'email_already_confirmed' => 'Die E-Mail-Adresse ist bereits bestätigt. Bitte melde dich an.', 'email_confirmation_invalid' => 'Der Bestätigungslink ist nicht gültig oder wurde bereits verwendet. Bitte registriere dich erneut.', 'email_confirmation_expired' => 'Der Bestätigungslink ist abgelaufen. Es wurde eine neue Bestätigungs-E-Mail gesendet.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'Anonymer LDAP-Zugriff ist fehlgeschlafgen', 'ldap_fail_authed' => 'LDAP-Zugriff mit DN und Passwort ist fehlgeschlagen', 'ldap_extension_not_installed' => 'LDAP-PHP-Erweiterung ist nicht installiert.', @@ -88,4 +89,12 @@ return [ 'app_down' => ':appName befindet sich aktuell im Wartungsmodus.', 'back_soon' => 'Wir werden so schnell wie möglich wieder online sein.', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + ]; diff --git a/resources/lang/de_informal/settings.php b/resources/lang/de_informal/settings.php index afc111679..260793f09 100644 --- a/resources/lang/de_informal/settings.php +++ b/resources/lang/de_informal/settings.php @@ -106,6 +106,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'role_manage_entity_permissions' => 'Alle Buch-, Kapitel- und Seiten-Berechtigungen verwalten', 'role_manage_own_entity_permissions' => 'Nur Berechtigungen eigener Bücher, Kapitel und Seiten verwalten', 'role_manage_page_templates' => 'Seitenvorlagen verwalten', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Globaleinstellungen verwalten', 'role_asset' => 'Berechtigungen', 'role_asset_desc' => 'Diese Berechtigungen gelten für den Standard-Zugriff innerhalb des Systems. Berechtigungen für Bücher, Kapitel und Seiten überschreiben diese Berechtigungenen.', @@ -154,6 +155,32 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'users_social_disconnect' => 'Social-Media-Konto lösen', 'users_social_connected' => ':socialAccount-Konto wurde erfolgreich mit dem Profil verknüpft.', 'users_social_disconnected' => ':socialAccount-Konto wurde erfolgreich vom Profil gelöst.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/lang/es/errors.php b/resources/lang/es/errors.php index 8cc80e754..ddae6ee5c 100644 --- a/resources/lang/es/errors.php +++ b/resources/lang/es/errors.php @@ -13,6 +13,7 @@ return [ 'email_already_confirmed' => 'El correo electrónico ya ha sido confirmado, intente acceder a la aplicación.', 'email_confirmation_invalid' => 'Este token de confirmación no es válido o ya ha sido usado, intente registrar uno nuevamente.', 'email_confirmation_expired' => 'El token de confirmación ha expirado, un nuevo email de confirmacón ha sido enviado.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'El acceso con LDAP ha fallado usando binding anónimo', 'ldap_fail_authed' => 'El acceso LDAP ha fallado usando el dn & contraseña enviados', 'ldap_extension_not_installed' => 'La extensión LDAP PHP no se encuentra instalada', @@ -88,4 +89,12 @@ return [ 'app_down' => 'La aplicación :appName se encuentra caída en este momento', 'back_soon' => 'Volverá a estar operativa pronto.', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + ]; diff --git a/resources/lang/es/settings.php b/resources/lang/es/settings.php index 39faff2fd..41e49fe29 100644 --- a/resources/lang/es/settings.php +++ b/resources/lang/es/settings.php @@ -103,6 +103,7 @@ return [ 'role_manage_entity_permissions' => 'Gestionar todos los permisos de libros, capítulos y páginas', 'role_manage_own_entity_permissions' => 'Gestionar permisos en libros, capítulos y páginas propias', 'role_manage_page_templates' => 'Administrar plantillas', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Gestionar ajustes de la aplicación', 'role_asset' => 'Permisos de contenido', 'role_asset_desc' => 'Estos permisos controlan el acceso por defecto a los contenidos del sistema. Los permisos de Libros, Capítulos y Páginas sobreescribiran estos permisos.', @@ -151,6 +152,32 @@ return [ 'users_social_disconnect' => 'Desconectar cuenta', 'users_social_connected' => 'La cuenta :socialAccount ha sido añadida éxitosamente a su perfil.', 'users_social_disconnected' => 'La cuenta :socialAccount ha sido desconectada éxitosamente de su perfil.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/lang/es_AR/errors.php b/resources/lang/es_AR/errors.php index 5ad6aa8d9..e14dccc22 100644 --- a/resources/lang/es_AR/errors.php +++ b/resources/lang/es_AR/errors.php @@ -13,6 +13,7 @@ return [ 'email_already_confirmed' => 'El email ya ha sido confirmado, Intente loguearse en la aplicación.', 'email_confirmation_invalid' => 'Este token de confirmación no e válido o ya ha sido usado,Intente registrar uno nuevamente.', 'email_confirmation_expired' => 'El token de confirmación ha expirado, Un nuevo email de confirmacón ha sido enviado.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'El acceso con LDAP ha fallado usando binding anónimo', 'ldap_fail_authed' => 'El acceso LDAP usando el dn & password detallados', 'ldap_extension_not_installed' => 'La extensión LDAP PHP no se encuentra instalada', @@ -88,4 +89,12 @@ return [ 'app_down' => 'La aplicación :appName se encuentra caída en este momento', 'back_soon' => 'Volverá a estar operativa en corto tiempo.', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + ]; diff --git a/resources/lang/es_AR/settings.php b/resources/lang/es_AR/settings.php index 2f40ad985..4250d7173 100644 --- a/resources/lang/es_AR/settings.php +++ b/resources/lang/es_AR/settings.php @@ -104,6 +104,7 @@ return [ 'role_manage_own_entity_permissions' => 'Gestionar permisos en libro s propios, capítulos y páginas', 'role_manage_page_templates' => 'Gestionar las plantillas de páginas', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Gestionar ajustes de activos', 'role_asset' => 'Permisos de activos', 'role_asset_desc' => 'Estos permisos controlan el acceso por defecto a los activos del sistema. Permisos a Libros, Capítulos y Páginas sobreescribiran estos permisos.', @@ -152,6 +153,32 @@ return [ 'users_social_disconnect' => 'Desconectar cuenta', 'users_social_connected' => 'La cuenta :socialAccount ha sido exitosamente añadida a su perfil.', 'users_social_disconnected' => 'La cuenta :socialAccount ha sido desconectada exitosamente de su perfil.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/lang/fr/errors.php b/resources/lang/fr/errors.php index bc5ef61d3..cd8a83ffe 100644 --- a/resources/lang/fr/errors.php +++ b/resources/lang/fr/errors.php @@ -13,6 +13,7 @@ return [ 'email_already_confirmed' => 'Cet e-mail a déjà été validé, vous pouvez vous connecter.', 'email_confirmation_invalid' => 'Cette confirmation est invalide. Veuillez essayer de vous inscrire à nouveau.', 'email_confirmation_expired' => 'Le jeton de confirmation est périmé. Un nouvel e-mail vous a été envoyé.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'L\'accès LDAP anonyme n\'a pas abouti', 'ldap_fail_authed' => 'L\'accès LDAP n\'a pas abouti avec cet utilisateur et ce mot de passe', 'ldap_extension_not_installed' => 'L\'extension LDAP PHP n\'est pas installée', @@ -88,4 +89,12 @@ return [ 'app_down' => ':appName n\'est pas en service pour le moment', 'back_soon' => 'Nous serons bientôt de retour.', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + ]; diff --git a/resources/lang/fr/settings.php b/resources/lang/fr/settings.php index 095889a6f..0ae45411c 100644 --- a/resources/lang/fr/settings.php +++ b/resources/lang/fr/settings.php @@ -103,6 +103,7 @@ return [ 'role_manage_entity_permissions' => 'Gérer les permissions sur les livres, chapitres et pages', 'role_manage_own_entity_permissions' => 'Gérer les permissions de ses propres livres, chapitres et pages', 'role_manage_page_templates' => 'Gérer les modèles de page', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Gérer les préférences de l\'application', 'role_asset' => 'Permissions des ressources', 'role_asset_desc' => 'Ces permissions contrôlent l\'accès par défaut des ressources dans le système. Les permissions dans les livres, les chapitres et les pages ignoreront ces permissions', @@ -151,6 +152,32 @@ return [ 'users_social_disconnect' => 'Déconnecter le compte', 'users_social_connected' => 'Votre compte :socialAccount a été ajouté avec succès.', 'users_social_disconnected' => 'Votre compte :socialAccount a été déconnecté avec succès', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/lang/hu/errors.php b/resources/lang/hu/errors.php index 10e560c35..a557f1a98 100644 --- a/resources/lang/hu/errors.php +++ b/resources/lang/hu/errors.php @@ -13,6 +13,7 @@ return [ 'email_already_confirmed' => 'Az email cím már meg van erősítve, meg lehet próbálni a bejelentkezést.', 'email_confirmation_invalid' => 'A megerősítő vezérjel nem érvényes vagy használva volt. Meg kell próbálni újraregisztrálni.', 'email_confirmation_expired' => 'A megerősítő vezérjel lejárt. Egy új megerősítő email lett elküldve.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'Nem sikerült az LDAP elérése névtelen csatlakozással', 'ldap_fail_authed' => 'Az LDAP hozzáférés nem sikerült a megadott DN és jelszó beállításokkal', 'ldap_extension_not_installed' => 'LDAP PHP kiterjesztés nincs telepítve', @@ -88,4 +89,12 @@ return [ 'app_down' => ':appName jelenleg nem üzemel', 'back_soon' => 'Hamarosan újra elérhető lesz.', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + ]; diff --git a/resources/lang/hu/settings.php b/resources/lang/hu/settings.php index 7059f112a..549d3bd6a 100644 --- a/resources/lang/hu/settings.php +++ b/resources/lang/hu/settings.php @@ -103,6 +103,7 @@ return [ 'role_manage_entity_permissions' => 'Minden könyv, fejezet és oldalengedély kezelése', 'role_manage_own_entity_permissions' => 'Saját könyv, fejezet és oldalak engedélyeinek kezelése', 'role_manage_page_templates' => 'Oldalsablonok kezelése', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Alkalmazás beállításainak kezelése', 'role_asset' => 'Eszköz jogosultságok', 'role_asset_desc' => 'Ezek a jogosultság vezérlik a alapértelmezés szerinti hozzáférést a rendszerben található eszközökhöz. A könyvek, fejezetek és oldalak jogosultságai felülírják ezeket a jogosultságokat.', @@ -151,6 +152,32 @@ return [ 'users_social_disconnect' => 'Fiók lecsatlakoztatása', 'users_social_connected' => ':socialAccount fiók sikeresen csatlakoztatva a profilhoz.', 'users_social_disconnected' => ':socialAccount fiók sikeresen lecsatlakoztatva a profilról.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/lang/it/common.php b/resources/lang/it/common.php index 9b10457f4..d8dbce451 100755 --- a/resources/lang/it/common.php +++ b/resources/lang/it/common.php @@ -38,7 +38,7 @@ return [ 'reset' => 'Azzera', 'remove' => 'Rimuovi', 'add' => 'Aggiungi', - 'fullscreen' => 'Fullscreen', + 'fullscreen' => 'Schermo intero', // Sort Options 'sort_options' => 'Opzioni Ordinamento', diff --git a/resources/lang/it/errors.php b/resources/lang/it/errors.php index e444f2968..f2514d0cb 100755 --- a/resources/lang/it/errors.php +++ b/resources/lang/it/errors.php @@ -13,6 +13,7 @@ return [ 'email_already_confirmed' => 'La mail è già stata confermata, esegui il login.', 'email_confirmation_invalid' => 'Questo token di conferma non è valido o già stato utilizzato, registrati nuovamente.', 'email_confirmation_expired' => 'Il token di conferma è scaduto, è stata inviata una nuova mail di conferma.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'Accesso LDAP fallito usando bind anonimo', 'ldap_fail_authed' => 'Accesso LDAP fallito usando il dn e la password inseriti', 'ldap_extension_not_installed' => 'L\'estensione PHP LDAP non è installata', @@ -88,4 +89,12 @@ return [ 'app_down' => ':appName è offline', 'back_soon' => 'Ritornerà presto.', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + ]; diff --git a/resources/lang/it/settings.php b/resources/lang/it/settings.php index ac66446e1..8cdd4f758 100755 --- a/resources/lang/it/settings.php +++ b/resources/lang/it/settings.php @@ -42,13 +42,13 @@ return [ 'app_disable_comments_desc' => 'Disabilita i commenti su tutte le pagine nell\'applicazione. I commenti esistenti non sono mostrati. ', // Color settings - 'content_colors' => 'Content Colors', - 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', - 'bookshelf_color' => 'Shelf Color', - 'book_color' => 'Book Color', - 'chapter_color' => 'Chapter Color', - 'page_color' => 'Page Color', - 'page_draft_color' => 'Page Draft Color', + 'content_colors' => 'Colori del contenuto', + 'content_colors_desc' => 'Imposta i colori per tutti gli elementi nella gerarchia della pagina. È raccomandato scegliere colori con una luminosità simile a quelli di default per una maggiore leggibilità.', + 'bookshelf_color' => 'Colore delle libreria', + 'book_color' => 'Colore del libro', + 'chapter_color' => 'Colore del capitolo', + 'page_color' => 'Colore della Pagina', + 'page_draft_color' => 'Colore della bozza', // Registration Settings 'reg_settings' => 'Impostazioni Registrazione', @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => 'Abilita registrazione', 'reg_enable_desc' => 'Quando la registrazione è abilitata, l\utente sarà in grado di registrarsi all\'applicazione. Al momento della registrazione gli verrà associato un ruolo utente predefinito.', 'reg_default_role' => 'Ruolo predefinito dopo la registrazione', - 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', + 'reg_enable_ldap_warning' => 'L\'opzione qui sopra non è usata mentre l\'autenticazione LDAP è attiva. Gli account per i membri non esistenti verranno creati automaticamente se l\'autenticazione, attraverso LDAP, avviene correttamente.', 'reg_email_confirmation' => 'Conferma Email', 'reg_email_confirmation_toggle' => 'Richiedi conferma email', 'reg_confirm_email_desc' => 'Se la restrizione per dominio è usata la conferma della mail sarà richiesta e la scelta ignorata.', @@ -103,6 +103,7 @@ return [ 'role_manage_entity_permissions' => 'Gestire tutti i permessi di libri, capitoli e pagine', 'role_manage_own_entity_permissions' => 'Gestire i permessi sui propri libri, capitoli e pagine', 'role_manage_page_templates' => 'Gestisci template pagine', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Gestire impostazioni app', 'role_asset' => 'Permessi Entità', 'role_asset_desc' => 'Questi permessi controllano l\'accesso di default alle entità. I permessi nei Libri, Capitoli e Pagine sovrascriveranno questi.', @@ -151,6 +152,32 @@ return [ 'users_social_disconnect' => 'Disconnetti Account', 'users_social_connected' => 'L\'account :socialAccount è stato connesso correttamente al tuo profilo.', 'users_social_disconnected' => 'L\'account :socialAccount è stato disconnesso correttamente dal tuo profilo.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/lang/ja/errors.php b/resources/lang/ja/errors.php index d02679f72..47932ca00 100644 --- a/resources/lang/ja/errors.php +++ b/resources/lang/ja/errors.php @@ -13,6 +13,7 @@ return [ 'email_already_confirmed' => 'Eメールは既に確認済みです。ログインしてください。', 'email_confirmation_invalid' => 'この確認トークンは無効か、または既に使用済みです。登録を再試行してください。', 'email_confirmation_expired' => '確認トークンは有効期限切れです。確認メールを再送しました。', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => '匿名バインドを用いたLDAPアクセスに失敗しました', 'ldap_fail_authed' => '識別名, パスワードを用いたLDAPアクセスに失敗しました', 'ldap_extension_not_installed' => 'LDAP PHP extensionがインストールされていません', @@ -88,4 +89,12 @@ return [ 'app_down' => ':appNameは現在停止しています', 'back_soon' => '回復までしばらくお待ちください。', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + ]; diff --git a/resources/lang/ja/settings.php b/resources/lang/ja/settings.php index b69845d0e..1030499f7 100644 --- a/resources/lang/ja/settings.php +++ b/resources/lang/ja/settings.php @@ -103,6 +103,7 @@ return [ 'role_manage_entity_permissions' => '全てのブック, チャプター, ページに対する権限の管理', 'role_manage_own_entity_permissions' => '自身のブック, チャプター, ページに対する権限の管理', 'role_manage_page_templates' => 'Manage page templates', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'アプリケーション設定の管理', 'role_asset' => 'アセット権限', 'role_asset_desc' => '各アセットに対するデフォルトの権限を設定します。ここで設定した権限が優先されます。', @@ -151,6 +152,32 @@ return [ 'users_social_disconnect' => 'アカウントを接続解除', 'users_social_connected' => '「:socialAccount」がプロフィールに接続されました。', 'users_social_disconnected' => '「:socialAccount」がプロフィールから接続解除されました。', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/lang/ko/common.php b/resources/lang/ko/common.php index d50965752..c2b09080c 100644 --- a/resources/lang/ko/common.php +++ b/resources/lang/ko/common.php @@ -38,7 +38,7 @@ return [ 'reset' => '리셋', 'remove' => '제거', 'add' => '추가', - 'fullscreen' => 'Fullscreen', + 'fullscreen' => '전체화면', // Sort Options 'sort_options' => '정렬 기준', @@ -73,5 +73,5 @@ return [ // Email Content 'email_action_help' => ':actionText를 클릭할 수 없을 때는 웹 브라우저에서 다음 링크로 접속할 수 있습니다.', - 'email_rights' => 'All rights reserved', + 'email_rights' => '모든 권리 소유', ]; diff --git a/resources/lang/ko/errors.php b/resources/lang/ko/errors.php index d054a620f..d3563fd83 100644 --- a/resources/lang/ko/errors.php +++ b/resources/lang/ko/errors.php @@ -13,16 +13,17 @@ return [ 'email_already_confirmed' => '확인이 끝난 메일 주소입니다. 로그인하세요.', 'email_confirmation_invalid' => '이 링크는 더 이상 유효하지 않습니다. 다시 가입하세요.', 'email_confirmation_expired' => '이 링크는 더 이상 유효하지 않습니다. 메일을 다시 보냈습니다.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => '익명 정보로 LDAP 서버에 접근할 수 없습니다.', 'ldap_fail_authed' => '이 정보로 LDAP 서버에 접근할 수 없습니다.', 'ldap_extension_not_installed' => 'PHP에 LDAP 확장 도구를 설치하세요.', 'ldap_cannot_connect' => 'LDAP 서버에 연결할 수 없습니다.', - 'saml_already_logged_in' => 'Already logged in', - 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', - 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', - 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', - 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', - 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', + 'saml_already_logged_in' => '이미 로그인되어있습니다.', + 'saml_user_not_registered' => '사용자 이름이 등록되지 않았으며 자동 계정 등록이 활성화되지 않았습니다.', + 'saml_no_email_address' => '이 사용자에 대하여 외부 인증시스템에 의해 제공된 데이타 중 이메일 주소를 찾을 수 없습니다.', + 'saml_invalid_response_id' => '이 응용프로그램에 의해 시작된 프로세스에 의하면 외부 인증시스템으로 온 요청이 인식되지 않습니다. 인증 후에 뒤로가기 기능을 사용했을 경우 이런 현상이 발생할 수 있습니다.', + 'saml_fail_authed' => '시스템 로그인에 실패하였습니다. ( 해당 시스템이 인증성공값을 제공하지 않았습니다. )', + 'saml_email_exists' => '해당 사용자가 이미 존재하는 이메일주소를 입력하였기에 사용자 등록에 실패하였습니다.', 'social_no_action_defined' => '무슨 활동인지 알 수 없습니다.', 'social_login_bad_response' => ":socialAccount에 로그인할 수 없습니다. : \\n:error", 'social_account_in_use' => ':socialAccount(을)를 가진 사용자가 있습니다. :socialAccount로 로그인하세요.', @@ -88,4 +89,12 @@ return [ 'app_down' => ':appName에 문제가 있는 것 같습니다', 'back_soon' => '곧 되돌아갑니다.', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + ]; diff --git a/resources/lang/ko/settings.php b/resources/lang/ko/settings.php index be1747040..544346dcd 100755 --- a/resources/lang/ko/settings.php +++ b/resources/lang/ko/settings.php @@ -42,13 +42,13 @@ return [ 'app_disable_comments_desc' => '모든 페이지에서 댓글을 숨깁니다.', // Color settings - 'content_colors' => 'Content Colors', - 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', - 'bookshelf_color' => 'Shelf Color', - 'book_color' => 'Book Color', - 'chapter_color' => 'Chapter Color', - 'page_color' => 'Page Color', - 'page_draft_color' => 'Page Draft Color', + 'content_colors' => '본문 색상', + 'content_colors_desc' => '페이지에 있는 모든 요소에 대한 색상 지정하세요. 가독성을 위해 기본 색상과 유사한 밝기를 가진 색상으로 추천됩니다.', + 'bookshelf_color' => '책선반 색상', + 'book_color' => '책 색상', + 'chapter_color' => '챕터 색상', + 'page_color' => '페이지 색상', + 'page_draft_color' => '드래프트 페이지 색상', // Registration Settings 'reg_settings' => '가입', @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => '사이트 가입 허용', 'reg_enable_desc' => '가입한 사용자는 단일한 권한을 가집니다.', 'reg_default_role' => '가입한 사용자의 기본 권한', - 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', + 'reg_enable_ldap_warning' => 'LDAP 인증이 활성화되었다면 위 옵션은 사용되지 않습니다. LDAP 시스템 인증 사용시 존재하지 않은 멤버 계정은 자동으로 생성됩니다.', 'reg_email_confirmation' => '메일 주소 확인', 'reg_email_confirmation_toggle' => '주소 확인 요구', 'reg_confirm_email_desc' => '도메인 차단을 쓰고 있으면 메일 주소를 확인해야 하고, 이 설정은 무시합니다.', @@ -73,13 +73,13 @@ return [ 'maint_image_cleanup_warning' => '이미지 :count개를 지울 건가요?', 'maint_image_cleanup_success' => '이미지 :count개 삭제함', 'maint_image_cleanup_nothing_found' => '삭제한 것 없음', - 'maint_send_test_email' => 'Send a Test Email', - 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', - 'maint_send_test_email_run' => 'Send test email', - 'maint_send_test_email_success' => 'Email sent to :address', - 'maint_send_test_email_mail_subject' => 'Test Email', - 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', - 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', + 'maint_send_test_email' => '테스트 메일 보내기', + 'maint_send_test_email_desc' => '프로필에 명시된 이메일주소로 테스트 메일이 전송됩니다.', + 'maint_send_test_email_run' => '테스트 메일 보내기', + 'maint_send_test_email_success' => '보낼 이메일 주소', + 'maint_send_test_email_mail_subject' => '테스트 메일', + 'maint_send_test_email_mail_greeting' => '이메일 전송이 성공하였습니다.', + 'maint_send_test_email_mail_text' => '축하합니다! 이 메일을 받음으로 이메일 설정이 정상적으로 되었음을 확인하였습니다.', // Role Settings 'roles' => '권한', @@ -103,6 +103,7 @@ return [ 'role_manage_entity_permissions' => '문서별 권한 관리', 'role_manage_own_entity_permissions' => '직접 만든 문서별 권한 관리', 'role_manage_page_templates' => '템플릿 관리', + 'role_access_api' => 'Access system API', 'role_manage_settings' => '사이트 설정 관리', 'role_asset' => '권한 항목', 'role_asset_desc' => '책자, 챕터, 문서별 권한은 이 설정에 우선합니다.', @@ -151,6 +152,32 @@ return [ 'users_social_disconnect' => '계정 연결 끊기', 'users_social_connected' => ':socialAccount(와)과 연결했습니다.', 'users_social_disconnected' => ':socialAccount(와)과의 연결을 끊었습니다.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/lang/nl/auth.php b/resources/lang/nl/auth.php index 059214bb4..c691bf6b5 100644 --- a/resources/lang/nl/auth.php +++ b/resources/lang/nl/auth.php @@ -11,14 +11,14 @@ return [ // Login & Register 'sign_up' => 'Registreren', - 'log_in' => 'Log in', + 'log_in' => 'Inloggen', 'log_in_with' => 'Login met :socialDriver', 'sign_up_with' => 'Registreer met :socialDriver', 'logout' => 'Uitloggen', 'name' => 'Naam', 'username' => 'Gebruikersnaam', - 'email' => 'Email', + 'email' => 'E-mail', 'password' => 'Wachtwoord', 'password_confirm' => 'Wachtwoord Bevestigen', 'password_hint' => 'Minimaal 8 tekens', @@ -26,9 +26,9 @@ return [ 'remember_me' => 'Mij onthouden', 'ldap_email_hint' => 'Geef een email op waarmee je dit account wilt gebruiken.', 'create_account' => 'Account Aanmaken', - 'already_have_account' => 'Already have an account?', - 'dont_have_account' => 'Don\'t have an account?', - 'social_login' => 'Social Login', + 'already_have_account' => 'Heb je al een account?', + 'dont_have_account' => 'Nog geen account?', + 'social_login' => 'Aanmelden via een sociaal netwerk', 'social_registration' => 'Social Registratie', 'social_registration_text' => 'Registreer en log in met een andere dienst.', @@ -66,12 +66,12 @@ return [ 'email_not_confirmed_resend_button' => 'Bevestigingsmail Opnieuw Verzenden', // User Invite - 'user_invite_email_subject' => 'You have been invited to join :appName!', - 'user_invite_email_greeting' => 'An account has been created for you on :appName.', - 'user_invite_email_text' => 'Click the button below to set an account password and gain access:', - 'user_invite_email_action' => 'Set Account Password', - 'user_invite_page_welcome' => 'Welcome to :appName!', - 'user_invite_page_text' => 'To finalise your account and gain access you need to set a password which will be used to log-in to :appName on future visits.', - 'user_invite_page_confirm_button' => 'Confirm Password', - 'user_invite_success' => 'Password set, you now have access to :appName!' + 'user_invite_email_subject' => 'Je bent uitgenodigd voor :appName!', + 'user_invite_email_greeting' => 'Er is een account voor je aangemaakt op :appName.', + 'user_invite_email_text' => 'Klik op de onderstaande knop om een account wachtwoord in te stellen en toegang te krijgen:', + 'user_invite_email_action' => 'Account wachtwoord instellen', + 'user_invite_page_welcome' => 'Welkom bij :appName!', + 'user_invite_page_text' => 'Om je account af te ronden en toegang te krijgen moet je een wachtwoord instellen dat gebruikt wordt om in te loggen op :appName bij toekomstige bezoeken.', + 'user_invite_page_confirm_button' => 'Bevestig wachtwoord', + 'user_invite_success' => 'Wachtwoord ingesteld, je hebt nu toegang tot :appName!' ]; \ No newline at end of file diff --git a/resources/lang/nl/common.php b/resources/lang/nl/common.php index 9e7d53fa7..93de8a11d 100644 --- a/resources/lang/nl/common.php +++ b/resources/lang/nl/common.php @@ -38,13 +38,13 @@ return [ 'reset' => 'Reset', 'remove' => 'Verwijderen', 'add' => 'Toevoegen', - 'fullscreen' => 'Fullscreen', + 'fullscreen' => 'Volledig scherm', // Sort Options - 'sort_options' => 'Sort Options', - 'sort_direction_toggle' => 'Sort Direction Toggle', - 'sort_ascending' => 'Sort Ascending', - 'sort_descending' => 'Sort Descending', + 'sort_options' => 'Sorteeropties', + 'sort_direction_toggle' => 'Sorteer richting', + 'sort_ascending' => 'Sorteer oplopend', + 'sort_descending' => 'Sorteer teruglopend', 'sort_name' => 'Naam', 'sort_created_at' => 'Aanmaakdatum', 'sort_updated_at' => 'Gewijzigd op', @@ -60,10 +60,10 @@ return [ 'grid_view' => 'Grid weergave', 'list_view' => 'Lijst weergave', 'default' => 'Standaard', - 'breadcrumb' => 'Breadcrumb', + 'breadcrumb' => 'Kruimelpad', // Header - 'profile_menu' => 'Profile Menu', + 'profile_menu' => 'Profiel menu', 'view_profile' => 'Profiel Weergeven', 'edit_profile' => 'Profiel Bewerken', diff --git a/resources/lang/nl/components.php b/resources/lang/nl/components.php index ffff70b08..4083b57be 100644 --- a/resources/lang/nl/components.php +++ b/resources/lang/nl/components.php @@ -5,13 +5,13 @@ return [ // Image Manager - 'image_select' => 'Selecteer Afbeelding', + 'image_select' => 'Afbeelding selecteren', 'image_all' => 'Alles', 'image_all_title' => 'Alle afbeeldingen weergeven', 'image_book_title' => 'Afbeeldingen van dit boek weergeven', 'image_page_title' => 'Afbeeldingen van deze pagina weergeven', 'image_search_hint' => 'Zoek op afbeeldingsnaam', - 'image_uploaded' => 'Uploaded :uploadedDate', + 'image_uploaded' => 'Geüpload :uploadedDate', 'image_load_more' => 'Meer Laden', 'image_image_name' => 'Afbeeldingsnaam', 'image_delete_used' => 'Deze afbeeldingen is op onderstaande pagina\'s in gebruik.', @@ -23,7 +23,7 @@ return [ 'image_upload_success' => 'Afbeelding succesvol geüpload', 'image_update_success' => 'Afbeeldingsdetails succesvol verwijderd', 'image_delete_success' => 'Afbeelding succesvol verwijderd', - 'image_upload_remove' => 'Remove', + 'image_upload_remove' => 'Verwijderen', // Code Editor 'code_editor' => 'Code invoegen', diff --git a/resources/lang/nl/errors.php b/resources/lang/nl/errors.php index a6cdbf8f7..f9c57b012 100644 --- a/resources/lang/nl/errors.php +++ b/resources/lang/nl/errors.php @@ -13,18 +13,19 @@ return [ 'email_already_confirmed' => 'Het e-mailadres is al bevestigd. Probeer in te loggen.', 'email_confirmation_invalid' => 'Deze bevestigingstoken is ongeldig, Probeer opnieuw te registreren.', 'email_confirmation_expired' => 'De bevestigingstoken is verlopen, Een nieuwe bevestigingsmail is verzonden.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'LDAP toegang kon geen \'anonymous bind\' uitvoeren', 'ldap_fail_authed' => 'LDAP toegang was niet mogelijk met de opgegeven dn & wachtwoord', - 'ldap_extension_not_installed' => 'LDAP PHP extension not installed', + 'ldap_extension_not_installed' => 'LDAP PHP-extensie is niet geïnstalleerd', 'ldap_cannot_connect' => 'Kon niet met de LDAP server verbinden', - 'saml_already_logged_in' => 'Already logged in', - 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', - 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', - 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', - 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', - 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', + 'saml_already_logged_in' => 'Al ingelogd', + 'saml_user_not_registered' => 'De gebruiker: naam is niet geregistreerd en automatische registratie is uitgeschakeld', + 'saml_no_email_address' => 'Kan geen e-mailadres voor deze gebruiker vinden in de gegevens die door het externe verificatiesysteem worden verstrekt', + 'saml_invalid_response_id' => 'Het verzoek van het externe verificatiesysteem is niet herkend door een door deze applicatie gestart proces. Het terug navigeren na een login kan dit probleem veroorzaken.', + 'saml_fail_authed' => 'Inloggen met :system mislukt, het systeem gaf geen succesvolle autorisatie', + 'saml_email_exists' => 'Registratie is mislukt omdat een gebruiker al bestaat met e-mailadres ":email"', 'social_no_action_defined' => 'Geen actie gedefineerd', - 'social_login_bad_response' => "Error received during :socialAccount login: \n:error", + 'social_login_bad_response' => "Fout ontvangen tijdens :socialAccount login: \n:error", 'social_account_in_use' => 'Dit :socialAccount account is al in gebruik, Probeer in te loggen met de :socialAccount optie.', 'social_account_email_in_use' => 'Het e-mailadres :email is al in gebruik. Als je al een account hebt kun je een :socialAccount account verbinden met je profielinstellingen.', 'social_account_existing' => 'Dit :socialAccount is al gekoppeld aan een profiel.', @@ -33,29 +34,29 @@ return [ 'social_account_register_instructions' => 'Als je nog geen account hebt kun je je registreren met de :socialAccount optie.', 'social_driver_not_found' => 'Social driver niet gevonden', 'social_driver_not_configured' => 'Je :socialAccount instellingen zijn correct geconfigureerd.', - 'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.', + 'invite_token_expired' => 'Deze uitnodigingslink is verlopen. U kunt in plaats daarvan proberen uw wachtwoord opnieuw in te stellen.', // System 'path_not_writable' => 'Bestand :filePath kon niet geupload worden. Zorg dat je schrijfrechten op de server hebt.', 'cannot_get_image_from_url' => 'Kon geen afbeelding genereren van :url', 'cannot_create_thumbs' => 'De server kon geen thumbnails maken. Controleer of je de GD PHP extensie geïnstalleerd hebt.', 'server_upload_limit' => 'Het afbeeldingsformaat is te groot. Probeer een kleinere bestandsgrootte.', - 'uploaded' => 'The server does not allow uploads of this size. Please try a smaller file size.', + 'uploaded' => 'Server staat geen uploads van deze grootte toe. Probeer een kleinere grootte van het bestand.', 'image_upload_error' => 'Er ging iets fout bij het uploaden van de afbeelding', - 'image_upload_type_error' => 'The image type being uploaded is invalid', + 'image_upload_type_error' => 'Het afbeeldingstype dat wordt geüpload is ongeldig', 'file_upload_timeout' => 'Het uploaden van het bestand is verlopen.', // Attachments 'attachment_page_mismatch' => 'Bij het bijwerken van de bijlage bleek de pagina onjuist', - 'attachment_not_found' => 'Attachment not found', + 'attachment_not_found' => 'Bijlage niet gevonden', // Pages 'page_draft_autosave_fail' => 'Kon het concept niet opslaan. Zorg ervoor dat je een werkende internetverbinding hebt.', - 'page_custom_home_deletion' => 'Cannot delete a page while it is set as a homepage', + 'page_custom_home_deletion' => 'Kan geen pagina verwijderen terwijl deze is ingesteld als een homepage', // Entities 'entity_not_found' => 'Entiteit niet gevonden', - 'bookshelf_not_found' => 'Bookshelf not found', + 'bookshelf_not_found' => 'Boekenplank niet gevonden', 'book_not_found' => 'Boek niet gevonden', 'page_not_found' => 'Pagina niet gevonden', 'chapter_not_found' => 'Hoofdstuk niet gevonden', @@ -71,7 +72,7 @@ return [ 'role_cannot_be_edited' => 'Deze rol kan niet bewerkt worden', 'role_system_cannot_be_deleted' => 'Dit is een systeemrol en kan niet verwijderd worden', 'role_registration_default_cannot_delete' => 'Deze rol kan niet verwijerd worden zolang dit de standaardrol na registratie is.', - 'role_cannot_remove_only_admin' => 'This user is the only user assigned to the administrator role. Assign the administrator role to another user before attempting to remove it here.', + 'role_cannot_remove_only_admin' => 'Deze gebruiker is de enige gebruiker die is toegewezen aan de beheerdersrol. Wijs de beheerdersrol toe aan een andere gebruiker voordat u probeert deze hier te verwijderen.', // Comments 'comment_list' => 'Er is een fout opgetreden tijdens het ophalen van de reacties.', @@ -88,4 +89,12 @@ return [ 'app_down' => ':appName is nu niet beschikbaar', 'back_soon' => 'Komt snel weer online.', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + ]; diff --git a/resources/lang/nl/settings.php b/resources/lang/nl/settings.php index 2240d7198..2fd7c4586 100644 --- a/resources/lang/nl/settings.php +++ b/resources/lang/nl/settings.php @@ -8,78 +8,78 @@ return [ // Common Messages 'settings' => 'Instellingen', - 'settings_save' => 'Instellingen Opslaan', + 'settings_save' => 'Instellingen opslaan', 'settings_save_success' => 'Instellingen Opgeslagen', // App Settings - 'app_customization' => 'Customization', - 'app_features_security' => 'Features & Security', + 'app_customization' => 'Aanpassingen', + 'app_features_security' => 'Functies en beveiliging', 'app_name' => 'Applicatienaam', 'app_name_desc' => 'De applicatienaam wordt in e-mails in in de header weergegeven.', 'app_name_header' => 'Applicatienaam in de header weergeven?', - 'app_public_access' => 'Public Access', - 'app_public_access_desc' => 'Enabling this option will allow visitors, that are not logged-in, to access content in your BookStack instance.', - 'app_public_access_desc_guest' => 'Access for public visitors can be controlled through the "Guest" user.', - 'app_public_access_toggle' => 'Allow public access', + 'app_public_access' => 'Openbare toegang', + 'app_public_access_desc' => 'Door deze optie in te schakelen, krijgen bezoekers die niet zijn ingelogd, toegang tot content in je BookStack.', + 'app_public_access_desc_guest' => 'Toegang voor openbare bezoekers kan worden gecontroleerd via de "Guest" gebruiker.', + 'app_public_access_toggle' => 'Openbare toegang toestaan', 'app_public_viewing' => 'Publieke bewerkingen toestaan?', 'app_secure_images' => 'Beter beveiligide afbeeldingen gebruiken?', - 'app_secure_images_toggle' => 'Enable higher security image uploads', + 'app_secure_images_toggle' => 'Hogere beveiliging geuploade afbeeldingen inschakelen', 'app_secure_images_desc' => 'Omwille van de performance zijn alle afbeeldingen publiek toegankelijk. Zorg ervoor dat je de \'directory index\' niet hebt ingeschakeld.', 'app_editor' => 'Pagina Bewerken', 'app_editor_desc' => 'Selecteer welke tekstverwerker je wilt gebruiken.', 'app_custom_html' => 'Speciale HTML toevoegen', 'app_custom_html_desc' => 'Alles wat je hier toevoegd wordt in de sectie van elke pagina meengenomen. Dit kun je bijvoorbeeld voor analytics gebruiken.', - 'app_custom_html_disabled_notice' => 'Custom HTML head content is disabled on this settings page to ensure any breaking changes can be reverted.', + 'app_custom_html_disabled_notice' => 'Aangepaste HTML-hoofd-inhoud is uitgeschakeld op deze instellingenpagina om ervoor te zorgen dat breekbare wijzigingen ongedaan gemaakt kunnen worden.', 'app_logo' => 'Applicatielogo', 'app_logo_desc' => 'De afbeelding moet 43px hoog zijn.
Grotere afbeeldingen worden geschaald.', 'app_primary_color' => 'Applicatie hoofdkleur', 'app_primary_color_desc' => 'Geef een hexadecimale waarde.
Als je niks invult wordt de standaardkleur gebruikt.', - 'app_homepage' => 'Application Homepage', - 'app_homepage_desc' => 'Select a view to show on the homepage instead of the default view. Page permissions are ignored for selected pages.', - 'app_homepage_select' => 'Select a page', + 'app_homepage' => 'Applicatie Homepagina', + 'app_homepage_desc' => 'Selecteer een weergave om weer te geven op de homepage in plaats van de standaard weergave. Paginarechten worden genegeerd voor geselecteerde pagina\'s.', + 'app_homepage_select' => 'Selecteer een pagina', 'app_disable_comments' => 'Reacties uitschakelen', - 'app_disable_comments_toggle' => 'Disable comments', + 'app_disable_comments_toggle' => 'Opmerkingen uitschakelen', 'app_disable_comments_desc' => 'Schakel opmerkingen uit op alle pagina\'s in de applicatie. Bestaande opmerkingen worden niet getoond.', // Color settings - 'content_colors' => 'Content Colors', - 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'content_colors' => 'Kleuren inhoud', + 'content_colors_desc' => 'Stelt de kleuren in voor alle elementen in de pagina-organisatieleiding. Het kiezen van kleuren met dezelfde helderheid als de standaard kleuren wordt aanbevolen voor de leesbaarheid.', 'bookshelf_color' => 'Shelf Color', 'book_color' => 'Book Color', 'chapter_color' => 'Chapter Color', - 'page_color' => 'Page Color', - 'page_draft_color' => 'Page Draft Color', + 'page_color' => 'Pagina kleur', + 'page_draft_color' => 'Klad pagina kleur', // Registration Settings 'reg_settings' => 'Registratieinstellingen', - 'reg_enable' => 'Enable Registration', - 'reg_enable_toggle' => 'Enable registration', - 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', + 'reg_enable' => 'Registratie inschakelen', + 'reg_enable_toggle' => 'Registratie inschakelen', + 'reg_enable_desc' => 'Wanneer registratie is ingeschakeld, kan de gebruiker zich aanmelden als een gebruiker. Na registratie krijgen ze een enkele, standaard gebruikersrol.', 'reg_default_role' => 'Standaard rol na registratie', - 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', - 'reg_email_confirmation' => 'Email Confirmation', - 'reg_email_confirmation_toggle' => 'Require email confirmation', + 'reg_enable_ldap_warning' => 'De optie hierboven wordt niet gebruikt terwijl LDAP authenticatie actief is. Gebruikersaccounts voor niet-bestaande leden zullen automatisch worden gecreëerd als authenticatie tegen het gebruikte LDAP-systeem succesvol is.', + 'reg_email_confirmation' => 'E-mail bevestiging', + 'reg_email_confirmation_toggle' => 'E-mailbevestiging verplichten', 'reg_confirm_email_desc' => 'Als domeinrestricties aan staan dan is altijd e-maibevestiging nodig. Onderstaande instelling wordt dan genegeerd.', 'reg_confirm_restrict_domain' => 'Beperk registratie tot een maildomein', 'reg_confirm_restrict_domain_desc' => 'Geen een komma-gescheiden lijst van domeinnamen die gebruikt mogen worden bij registratie.
Let op: na registratie kunnen gebruikers hun e-mailadres nog steeds wijzigen.', 'reg_confirm_restrict_domain_placeholder' => 'Geen beperkingen ingesteld', // Maintenance settings - 'maint' => 'Maintenance', - 'maint_image_cleanup' => 'Cleanup Images', - 'maint_image_cleanup_desc' => "Scans page & revision content to check which images and drawings are currently in use and which images are redundant. Ensure you create a full database and image backup before running this.", - 'maint_image_cleanup_ignore_revisions' => 'Ignore images in revisions', - 'maint_image_cleanup_run' => 'Run Cleanup', - 'maint_image_cleanup_warning' => ':count potentially unused images were found. Are you sure you want to delete these images?', - 'maint_image_cleanup_success' => ':count potentially unused images found and deleted!', - 'maint_image_cleanup_nothing_found' => 'No unused images found, Nothing deleted!', - 'maint_send_test_email' => 'Send a Test Email', - 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', - 'maint_send_test_email_run' => 'Send test email', - 'maint_send_test_email_success' => 'Email sent to :address', - 'maint_send_test_email_mail_subject' => 'Test Email', - 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', - 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', + 'maint' => 'Onderhoud', + 'maint_image_cleanup' => 'Afbeeldingen opschonen', + 'maint_image_cleanup_desc' => "Scant pagina- en revisie inhoud om te controleren welke afbeeldingen en tekeningen momenteel worden gebruikt en welke afbeeldingen overbodig zijn. Zorg ervoor dat je een volledige database en afbeelding backup maakt voordat je dit uitvoert.", + 'maint_image_cleanup_ignore_revisions' => 'Afbeeldingen in revisies negeren', + 'maint_image_cleanup_run' => 'Opschonen uitvoeren', + 'maint_image_cleanup_warning' => ':count potentieel ongebruikte afbeeldingen gevonden. Weet u zeker dat u deze afbeeldingen wilt verwijderen?', + 'maint_image_cleanup_success' => ':count potentieel ongebruikte afbeeldingen gevonden en verwijderd!', + 'maint_image_cleanup_nothing_found' => 'Geen ongebruikte afbeeldingen gevonden, niets verwijderd!', + 'maint_send_test_email' => 'Stuur een test e-mail', + 'maint_send_test_email_desc' => 'Dit verstuurt een test e-mail naar het e-mailadres dat je in je profiel hebt opgegeven.', + 'maint_send_test_email_run' => 'Test e-mail verzenden', + 'maint_send_test_email_success' => 'E-mail verzonden naar :address', + 'maint_send_test_email_mail_subject' => 'Test E-mail', + 'maint_send_test_email_mail_greeting' => 'E-mailbezorging lijkt te werken!', + 'maint_send_test_email_mail_text' => 'Gefeliciteerd! Nu je deze e-mailmelding hebt ontvangen, lijken je e-mailinstellingen correct te zijn geconfigureerd.', // Role Settings 'roles' => 'Rollen', @@ -96,17 +96,18 @@ return [ 'role_details' => 'Rol Details', 'role_name' => 'Rolnaam', 'role_desc' => 'Korte beschrijving van de rol', - 'role_external_auth_id' => 'External Authentication IDs', + 'role_external_auth_id' => 'Externe authenticatie ID\'s', 'role_system' => 'Systeem Permissies', 'role_manage_users' => 'Gebruikers beheren', 'role_manage_roles' => 'Rollen en rechten beheren', 'role_manage_entity_permissions' => 'Beheer alle boeken-, hoofdstukken- en paginaresitrcties', 'role_manage_own_entity_permissions' => 'Beheer restricties van je eigen boeken, hoofdstukken en pagina\'s', - 'role_manage_page_templates' => 'Manage page templates', + 'role_manage_page_templates' => 'Paginasjablonen beheren', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Beheer app instellingen', 'role_asset' => 'Asset Permissies', 'role_asset_desc' => 'Deze permissies bepalen de standaardtoegangsrechten. Permissies op boeken, hoofdstukken en pagina\'s overschrijven deze instelling.', - 'role_asset_admins' => 'Admins are automatically given access to all content but these options may show or hide UI options.', + 'role_asset_admins' => 'Beheerders krijgen automatisch toegang tot alle inhoud, maar deze opties kunnen interface opties tonen of verbergen.', 'role_all' => 'Alles', 'role_own' => 'Eigen', 'role_controlled_by_asset' => 'Gecontroleerd door de asset waar deze is geüpload', @@ -120,17 +121,17 @@ return [ 'user_profile' => 'Gebruikersprofiel', 'users_add_new' => 'Gebruiker toevoegen', 'users_search' => 'Gebruiker zoeken', - 'users_details' => 'User Details', - 'users_details_desc' => 'Set a display name and an email address for this user. The email address will be used for logging into the application.', - 'users_details_desc_no_email' => 'Set a display name for this user so others can recognise them.', + 'users_details' => 'Gebruiker details', + 'users_details_desc' => 'Stel een weergavenaam en e-mailadres in voor deze gebruiker. Het e-mailadres zal worden gebruikt om in te loggen.', + 'users_details_desc_no_email' => 'Stel een weergavenaam in voor deze gebruiker zodat anderen deze kunnen herkennen.', 'users_role' => 'Gebruikersrollen', - 'users_role_desc' => 'Select which roles this user will be assigned to. If a user is assigned to multiple roles the permissions from those roles will stack and they will receive all abilities of the assigned roles.', - 'users_password' => 'User Password', - 'users_password_desc' => 'Set a password used to log-in to the application. This must be at least 6 characters long.', - 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', - 'users_send_invite_option' => 'Send user invite email', - 'users_external_auth_id' => 'External Authentication ID', - 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your LDAP system.', + 'users_role_desc' => 'Selecteer aan welke rollen deze gebruiker zal worden toegewezen. Als een gebruiker aan meerdere rollen wordt toegewezen worden de machtigingen van deze rollen samengevoegd en krijgen ze alle machtigingen van de toegewezen rollen.', + 'users_password' => 'Wachtwoord gebruiker', + 'users_password_desc' => 'Stel een wachtwoord in dat gebruikt wordt om in te loggen op de applicatie. Dit moet minstens 6 tekens lang zijn.', + 'users_send_invite_text' => 'U kunt ervoor kiezen om deze gebruiker een uitnodigingsmail te sturen waarmee hij zijn eigen wachtwoord kan instellen, anders kunt u zelf zijn wachtwoord instellen.', + 'users_send_invite_option' => 'Stuur gebruiker uitnodigings e-mail', + 'users_external_auth_id' => 'Externe authenticatie ID', + 'users_external_auth_id_desc' => 'Dit is het ID dat gebruikt wordt om deze gebruiker te vergelijken wanneer hij communiceert met uw LDAP-systeem.', 'users_password_warning' => 'Vul onderstaande formulier alleen in als je het wachtwoord wilt aanpassen:', 'users_system_public' => 'De eigenschappen van deze gebruiker worden voor elke gastbezoeker gebruikt. Er kan niet mee ingelogd worden en wordt automatisch toegewezen.', 'users_delete' => 'Verwijder gebruiker', @@ -144,13 +145,39 @@ return [ 'users_avatar' => 'Avatar', 'users_avatar_desc' => 'De afbeelding moet vierkant zijn en ongeveer 256px breed.', 'users_preferred_language' => 'Voorkeurstaal', - 'users_preferred_language_desc' => 'This option will change the language used for the user-interface of the application. This will not affect any user-created content.', - 'users_social_accounts' => 'Social Accounts', + 'users_preferred_language_desc' => 'Deze optie wijzigt de taal die gebruikt wordt voor de gebruikersinterface. Dit heeft geen invloed op de door de gebruiker gemaakte inhoud.', + 'users_social_accounts' => 'Sociale accounts', 'users_social_accounts_info' => 'Hier kun je accounts verbinden om makkelijker in te loggen. Via je profiel kun je ook weer rechten intrekken die bij deze social accountsh horen.', 'users_social_connect' => 'Account Verbinden', 'users_social_disconnect' => 'Account Ontkoppelen', 'users_social_connected' => ':socialAccount account is succesvol aan je profiel gekoppeld.', 'users_social_disconnected' => ':socialAccount account is succesvol ontkoppeld van je profiel.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/lang/nl/validation.php b/resources/lang/nl/validation.php index 05e09d8a1..f85e5786f 100644 --- a/resources/lang/nl/validation.php +++ b/resources/lang/nl/validation.php @@ -8,104 +8,104 @@ return [ // Standard laravel validation lines - 'accepted' => 'The :attribute must be accepted.', - 'active_url' => 'The :attribute is not a valid URL.', - 'after' => 'The :attribute must be a date after :date.', - 'alpha' => 'The :attribute may only contain letters.', - 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', - 'alpha_num' => 'The :attribute may only contain letters and numbers.', - 'array' => 'The :attribute must be an array.', - 'before' => 'The :attribute must be a date before :date.', + 'accepted' => ':attribute moet geaccepteerd worden.', + 'active_url' => ':attribute is geen geldige URL.', + 'after' => ':attribute moet een datum zijn later dan :date.', + 'alpha' => ':attribute mag alleen letters bevatten.', + 'alpha_dash' => ':attribute mag alleen letters, cijfers, streepjes en liggende streepjes bevatten.', + 'alpha_num' => ':attribute mag alleen letters en nummers bevatten.', + 'array' => ':attribute moet een reeks zijn.', + 'before' => ':attribute moet een datum zijn voor :date.', 'between' => [ - 'numeric' => 'The :attribute must be between :min and :max.', - 'file' => 'The :attribute must be between :min and :max kilobytes.', - 'string' => 'The :attribute must be between :min and :max characters.', - 'array' => 'The :attribute must have between :min and :max items.', + 'numeric' => ':attribute moet tussen de :min en :max zijn.', + 'file' => ':attribute moet tussen de :min en :max kilobytes zijn.', + 'string' => ':attribute moet tussen de :min en :max tekens zijn.', + 'array' => ':attribute moet tussen de :min en :max items bevatten.', ], - 'boolean' => 'The :attribute field must be true or false.', - 'confirmed' => 'The :attribute confirmation does not match.', - 'date' => 'The :attribute is not a valid date.', - 'date_format' => 'The :attribute does not match the format :format.', - 'different' => 'The :attribute and :other must be different.', - 'digits' => 'The :attribute must be :digits digits.', - 'digits_between' => 'The :attribute must be between :min and :max digits.', - 'email' => 'The :attribute must be a valid email address.', - 'ends_with' => 'The :attribute must end with one of the following: :values', - 'filled' => 'The :attribute field is required.', + 'boolean' => ':attribute moet ja of nee zijn.', + 'confirmed' => ':attribute bevestiging komt niet overeen.', + 'date' => ':attribute is geen geldige datum.', + 'date_format' => ':attribute komt niet overeen met het formaat :format.', + 'different' => ':attribute en :other moeten verschillend zijn.', + 'digits' => ':attribute moet bestaan uit :digits cijfers.', + 'digits_between' => ':attribute moet tussen de :min en :max cijfers zijn.', + 'email' => ':attribute is geen geldig e-mailadres.', + 'ends_with' => ':attribute moet eindigen met een van de volgende: :values', + 'filled' => ':attribute is verplicht.', 'gt' => [ - 'numeric' => 'The :attribute must be greater than :value.', - 'file' => 'The :attribute must be greater than :value kilobytes.', - 'string' => 'The :attribute must be greater than :value characters.', - 'array' => 'The :attribute must have more than :value items.', + 'numeric' => ':attribute moet groter zijn dan :value.', + 'file' => ':attribute moet groter zijn dan :value kilobytes.', + 'string' => ':attribute moet meer dan :value tekens bevatten.', + 'array' => ':attribute moet meer dan :value items bevatten.', ], 'gte' => [ - 'numeric' => 'The :attribute must be greater than or equal :value.', - 'file' => 'The :attribute must be greater than or equal :value kilobytes.', - 'string' => 'The :attribute must be greater than or equal :value characters.', - 'array' => 'The :attribute must have :value items or more.', + 'numeric' => ':attribute moet groter of gelijk zijn aan :value.', + 'file' => ':attribute moet groter of gelijk zijn aan :value kilobytes.', + 'string' => ':attribute moet :value of meer tekens bevatten.', + 'array' => ':attribute moet :value items of meer bevatten.', ], - 'exists' => 'The selected :attribute is invalid.', - 'image' => 'The :attribute must be an image.', - 'image_extension' => 'The :attribute must have a valid & supported image extension.', - 'in' => 'The selected :attribute is invalid.', - 'integer' => 'The :attribute must be an integer.', - 'ip' => 'The :attribute must be a valid IP address.', - 'ipv4' => 'The :attribute must be a valid IPv4 address.', - 'ipv6' => 'The :attribute must be a valid IPv6 address.', - 'json' => 'The :attribute must be a valid JSON string.', + 'exists' => ':attribute is ongeldig.', + 'image' => ':attribute moet een afbeelding zijn.', + 'image_extension' => ':attribute moet een geldige en ondersteunde afbeeldings-extensie hebben.', + 'in' => ':attribute is ongeldig.', + 'integer' => ':attribute moet een getal zijn.', + 'ip' => ':attribute moet een geldig IP-adres zijn.', + 'ipv4' => ':attribute moet een geldig IPv4-adres zijn.', + 'ipv6' => ':attribute moet een geldig IPv6-adres zijn.', + 'json' => ':attribute moet een geldige JSON-string zijn.', 'lt' => [ - 'numeric' => 'The :attribute must be less than :value.', - 'file' => 'The :attribute must be less than :value kilobytes.', - 'string' => 'The :attribute must be less than :value characters.', - 'array' => 'The :attribute must have less than :value items.', + 'numeric' => ':attribute moet kleiner zijn dan :value.', + 'file' => ':attribute moet kleiner zijn dan :value kilobytes.', + 'string' => ':attribute moet minder dan :value tekens bevatten.', + 'array' => ':attribute moet minder dan :value items bevatten.', ], 'lte' => [ - 'numeric' => 'The :attribute must be less than or equal :value.', - 'file' => 'The :attribute must be less than or equal :value kilobytes.', - 'string' => 'The :attribute must be less than or equal :value characters.', - 'array' => 'The :attribute must not have more than :value items.', + 'numeric' => ':attribute moet kleiner of gelijk zijn aan :value.', + 'file' => ':attribute moet kleiner of gelijk zijn aan :value kilobytes.', + 'string' => ':attribute moet :value tekens of minder bevatten.', + 'array' => ':attribute mag niet meer dan :value items bevatten.', ], 'max' => [ - 'numeric' => 'The :attribute may not be greater than :max.', - 'file' => 'The :attribute may not be greater than :max kilobytes.', - 'string' => 'The :attribute may not be greater than :max characters.', - 'array' => 'The :attribute may not have more than :max items.', + 'numeric' => ':attribute mag niet groter zijn dan :max.', + 'file' => ':attribute mag niet groter zijn dan :max kilobytes.', + 'string' => ':attribute mag niet groter zijn dan :max tekens.', + 'array' => ':attribute mag niet meer dan :max items bevatten.', ], - 'mimes' => 'The :attribute must be a file of type: :values.', + 'mimes' => ':attribute moet een bestand zijn van het type: :values.', 'min' => [ - 'numeric' => 'The :attribute must be at least :min.', - 'file' => 'The :attribute must be at least :min kilobytes.', - 'string' => 'The :attribute must be at least :min characters.', - 'array' => 'The :attribute must have at least :min items.', + 'numeric' => ':attribute moet minstens :min zijn.', + 'file' => ':attribute moet minstens :min kilobytes zijn.', + 'string' => ':attribute moet minstens :min karakters bevatten.', + 'array' => ':attribute moet minstens :min items bevatten.', ], - 'no_double_extension' => 'The :attribute must only have a single file extension.', - 'not_in' => 'The selected :attribute is invalid.', - 'not_regex' => 'The :attribute format is invalid.', - 'numeric' => 'The :attribute must be a number.', - 'regex' => 'The :attribute format is invalid.', - 'required' => 'The :attribute field is required.', - 'required_if' => 'The :attribute field is required when :other is :value.', - 'required_with' => 'The :attribute field is required when :values is present.', - 'required_with_all' => 'The :attribute field is required when :values is present.', - 'required_without' => 'The :attribute field is required when :values is not present.', - 'required_without_all' => 'The :attribute field is required when none of :values are present.', - 'same' => 'The :attribute and :other must match.', + 'no_double_extension' => ':attribute mag maar een enkele bestandsextensie hebben.', + 'not_in' => ':attribute is ongeldig.', + 'not_regex' => ':attribute formaat is ongeldig.', + 'numeric' => ':attribute moet een getal zijn.', + 'regex' => ':attribute formaat is ongeldig.', + 'required' => ':attribute veld is verplicht.', + 'required_if' => ':attribute veld is verplicht als :other gelijk is aan :value.', + 'required_with' => ':attribute veld is verplicht wanneer :values ingesteld is.', + 'required_with_all' => ':attribute veld is verplicht wanneer :values ingesteld is.', + 'required_without' => ':attribute veld is verplicht wanneer :values niet ingesteld is.', + 'required_without_all' => ':attribute veld is verplicht wanneer geen van :values ingesteld zijn.', + 'same' => ':attribute en :other moeten overeenkomen.', 'size' => [ - 'numeric' => 'The :attribute must be :size.', - 'file' => 'The :attribute must be :size kilobytes.', - 'string' => 'The :attribute must be :size characters.', - 'array' => 'The :attribute must contain :size items.', + 'numeric' => ':attribute moet :size zijn.', + 'file' => ':attribute moet :size kilobytes zijn.', + 'string' => ':attribute moet :size tekens bevatten.', + 'array' => ':attribute moet :size items bevatten.', ], - 'string' => 'The :attribute must be a string.', - 'timezone' => 'The :attribute must be a valid zone.', - 'unique' => 'The :attribute has already been taken.', - 'url' => 'The :attribute format is invalid.', - 'uploaded' => 'The file could not be uploaded. The server may not accept files of this size.', + 'string' => ':attribute moet tekst zijn.', + 'timezone' => ':attribute moet een geldige zone zijn.', + 'unique' => ':attribute is al in gebruik.', + 'url' => ':attribute formaat is ongeldig.', + 'uploaded' => 'Het bestand kon niet worden geüpload. De server accepteert mogelijk geen bestanden van deze grootte.', // Custom validation lines 'custom' => [ 'password-confirm' => [ - 'required_with' => 'Password confirmation required', + 'required_with' => 'Wachtwoord bevestiging verplicht', ], ], diff --git a/resources/lang/pl/errors.php b/resources/lang/pl/errors.php index fd378214a..410e67a36 100644 --- a/resources/lang/pl/errors.php +++ b/resources/lang/pl/errors.php @@ -13,6 +13,7 @@ return [ 'email_already_confirmed' => 'E-mail został potwierdzony, spróbuj się zalogować.', 'email_confirmation_invalid' => 'Ten token jest nieprawidłowy lub został już wykorzystany. Spróbuj zarejestrować się ponownie.', 'email_confirmation_expired' => 'Ten token potwierdzający wygasł. Wysłaliśmy Ci kolejny.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'Dostęp LDAP przy użyciu anonimowego powiązania nie powiódł się', 'ldap_fail_authed' => 'Dostęp LDAP przy użyciu tego DN i hasła nie powiódł się', 'ldap_extension_not_installed' => 'Rozszerzenie LDAP PHP nie zostało zainstalowane', @@ -88,4 +89,12 @@ return [ 'app_down' => ':appName jest aktualnie wyłączona', 'back_soon' => 'Niedługo zostanie uruchomiona ponownie.', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + ]; diff --git a/resources/lang/pl/settings.php b/resources/lang/pl/settings.php index a9ec17cd9..868ac5694 100644 --- a/resources/lang/pl/settings.php +++ b/resources/lang/pl/settings.php @@ -103,6 +103,7 @@ return [ 'role_manage_entity_permissions' => 'Zarządzanie uprawnieniami książek, rozdziałów i stron', 'role_manage_own_entity_permissions' => 'Zarządzanie uprawnieniami własnych książek, rozdziałów i stron', 'role_manage_page_templates' => 'Zarządzaj szablonami stron', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Zarządzanie ustawieniami aplikacji', 'role_asset' => 'Zarządzanie zasobami', 'role_asset_desc' => 'Te ustawienia kontrolują zarządzanie zasobami systemu. Uprawnienia książek, rozdziałów i stron nadpisują te ustawienia.', @@ -151,6 +152,32 @@ return [ 'users_social_disconnect' => 'Odłącz konto', 'users_social_connected' => ':socialAccount zostało dodane do Twojego profilu.', 'users_social_disconnected' => ':socialAccount zostało odłączone od Twojego profilu.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/lang/pt_BR/activities.php b/resources/lang/pt_BR/activities.php index 5a4088600..9789fe3be 100644 --- a/resources/lang/pt_BR/activities.php +++ b/resources/lang/pt_BR/activities.php @@ -6,42 +6,42 @@ return [ // Pages - 'page_create' => 'página criada', + 'page_create' => 'criou a página', 'page_create_notification' => 'Página criada com sucesso', - 'page_update' => 'página atualizada', + 'page_update' => 'atualizou a página', 'page_update_notification' => 'Página atualizada com sucesso', - 'page_delete' => 'página excluída', + 'page_delete' => 'excluiu a página', 'page_delete_notification' => 'Página excluída com sucesso', - 'page_restore' => 'página restaurada', + 'page_restore' => 'restaurou a página', 'page_restore_notification' => 'Página restaurada com sucesso', - 'page_move' => 'página movida', + 'page_move' => 'moveu a página', // Chapters - 'chapter_create' => 'capítulo criado', + 'chapter_create' => 'criou o capítulo', 'chapter_create_notification' => 'Capítulo criado com sucesso', - 'chapter_update' => 'capítulo atualizado', - 'chapter_update_notification' => 'capítulo atualizado com sucesso', - 'chapter_delete' => 'capítulo excluído', + 'chapter_update' => 'atualizou o capítulo', + 'chapter_update_notification' => 'Capítulo atualizado com sucesso', + 'chapter_delete' => 'excluiu o capítulo', 'chapter_delete_notification' => 'Capítulo excluído com sucesso', - 'chapter_move' => 'capitulo movido', + 'chapter_move' => 'moveu o capítulo', // Books - 'book_create' => 'livro criado', + 'book_create' => 'criou o livro', 'book_create_notification' => 'Livro criado com sucesso', - 'book_update' => 'livro atualizado', + 'book_update' => 'atualizou o livro', 'book_update_notification' => 'Livro atualizado com sucesso', - 'book_delete' => 'livro excluído', + 'book_delete' => 'excluiu o livro', 'book_delete_notification' => 'Livro excluído com sucesso', - 'book_sort' => 'livro classificado', - 'book_sort_notification' => 'Livro reclassificado com sucesso', + 'book_sort' => 'ordenou o livro', + 'book_sort_notification' => 'Livro reordenado com sucesso', // Bookshelves - 'bookshelf_create' => 'prateleira de livros criada', - 'bookshelf_create_notification' => 'Prateleira de Livros criada com sucesso', - 'bookshelf_update' => 'prateleira de livros atualizada', - 'bookshelf_update_notification' => 'Prateleira de Livros atualizada com sucesso', - 'bookshelf_delete' => 'prateleira de livros excluída', - 'bookshelf_delete_notification' => 'Prateleira de Livros excluída com sucesso', + 'bookshelf_create' => 'criou a prateleira', + 'bookshelf_create_notification' => 'Prateleira criada com sucesso', + 'bookshelf_update' => 'atualizou a prateleira', + 'bookshelf_update_notification' => 'Prateleira atualizada com sucesso', + 'bookshelf_delete' => 'excluiu a prateleira', + 'bookshelf_delete_notification' => 'Prateleira excluída com sucesso', // Other 'commented_on' => 'comentou em', diff --git a/resources/lang/pt_BR/auth.php b/resources/lang/pt_BR/auth.php index 21c16699c..fd0cf823d 100644 --- a/resources/lang/pt_BR/auth.php +++ b/resources/lang/pt_BR/auth.php @@ -6,14 +6,14 @@ */ return [ - 'failed' => 'As credenciais fornecidas não puderam ser validadas em nossos registros..', + 'failed' => 'As credenciais fornecidas não puderam ser validadas em nossos registros.', 'throttle' => 'Muitas tentativas de login. Por favor, tente novamente em :seconds segundos.', // Login & Register - 'sign_up' => 'Registrar-se', + 'sign_up' => 'Criar Conta', 'log_in' => 'Entrar', 'log_in_with' => 'Entrar com :socialDriver', - 'sign_up_with' => 'Registrar com :socialDriver', + 'sign_up_with' => 'Cadastre-se com :socialDriver', 'logout' => 'Sair', 'name' => 'Nome', @@ -21,57 +21,57 @@ return [ 'email' => 'E-mail', 'password' => 'Senha', 'password_confirm' => 'Confirmar Senha', - 'password_hint' => 'Senha deverá ser maior que 7 caracteres', + 'password_hint' => 'Deve ser maior que 7 caracteres', 'forgot_password' => 'Esqueceu a senha?', 'remember_me' => 'Lembrar de mim', 'ldap_email_hint' => 'Por favor, digite um e-mail para essa conta.', - 'create_account' => 'Criar conta', - 'already_have_account' => 'Você já possui uma conta?', + 'create_account' => 'Criar Conta', + 'already_have_account' => 'Já possui uma conta?', 'dont_have_account' => 'Não possui uma conta?', - 'social_login' => 'Login social', - 'social_registration' => 'Registro social', - 'social_registration_text' => 'Registre e entre usando outro serviço.', + 'social_login' => 'Login Social', + 'social_registration' => 'Cadastro Social', + 'social_registration_text' => 'Cadastre-se e entre utilizando outro serviço.', - 'register_thanks' => 'Obrigado por efetuar o registro!', + 'register_thanks' => 'Obrigado por se cadastrar!', 'register_confirm' => 'Por favor, verifique seu e-mail e clique no botão de confirmação para acessar :appName.', - 'registrations_disabled' => 'Registros estão temporariamente desabilitados', + 'registrations_disabled' => 'Cadastros estão temporariamente desabilitados', 'registration_email_domain_invalid' => 'O domínio de e-mail usado não tem acesso permitido a essa aplicação', - 'register_success' => 'Obrigado por se registrar! Você agora encontra-se registrado e logado..', + 'register_success' => 'Obrigado por se cadastrar! Você agora encontra-se cadastrado(a) e logado(a).', // Password Reset - 'reset_password' => 'Resetar senha', - 'reset_password_send_instructions' => 'Digite seu e-mail abaixo e o sistema enviará uma mensagem com o link de reset de senha.', - 'reset_password_send_button' => 'Enviar o link de reset de senha', - 'reset_password_sent_success' => 'Um link de reset de senha foi enviado para :email.', - 'reset_password_success' => 'Sua senha foi resetada com sucesso.', - 'email_reset_subject' => 'Resetar a senha de :appName', - 'email_reset_text' => 'Você recebeu esse e-mail pois recebemos uma solicitação de reset de senha para sua conta.', - 'email_reset_not_requested' => 'Caso não tenha sido você a solicitar o reset de senha, ignore esse e-mail.', + 'reset_password' => 'Redefinir Senha', + 'reset_password_send_instructions' => 'Insira seu e-mail abaixo e uma mensagem com o link de redefinição de senha lhe será enviada.', + 'reset_password_send_button' => 'Enviar o Link de Redefinição', + 'reset_password_sent_success' => 'Um link de redefinição de senha foi enviado para :email.', + 'reset_password_success' => 'Sua senha foi redefinida com sucesso.', + 'email_reset_subject' => 'Redefina a senha de :appName', + 'email_reset_text' => 'Você recebeu esse e-mail pois recebemos uma solicitação de redefinição de senha para a sua conta.', + 'email_reset_not_requested' => 'Caso não tenha sido você a solicitar a redefinição de senha, ignore esse e-mail.', // Email Confirmation 'email_confirm_subject' => 'Confirme seu e-mail para :appName', - 'email_confirm_greeting' => 'Obrigado por se registrar em :appName!', + 'email_confirm_greeting' => 'Obrigado por se cadastrar em :appName!', 'email_confirm_text' => 'Por favor, confirme seu endereço de e-mail clicando no botão abaixo:', 'email_confirm_action' => 'Confirmar E-mail', - 'email_confirm_send_error' => 'E-mail de confirmação é requerido, mas o sistema não pôde enviar a mensagem. Por favor, entre em contato com o admin para se certificar que o serviço de envio de e-mails está corretamente configurado.', + 'email_confirm_send_error' => 'A confirmação de e-mail é requerida, mas o sistema não pôde enviar a mensagem. Por favor, entre em contato com o administrador para se certificar que o serviço de envio de e-mails está corretamente configurado.', 'email_confirm_success' => 'Seu e-mail foi confirmado!', - 'email_confirm_resent' => 'E-mail de confirmação reenviado. Por favor, cheque sua caixa postal.', + 'email_confirm_resent' => 'E-mail de confirmação reenviado. Por favor, verifique sua caixa de entrada.', - 'email_not_confirmed' => 'Endereço de e-mail não foi confirmado', + 'email_not_confirmed' => 'Endereço de E-mail Não Confirmado', 'email_not_confirmed_text' => 'Seu endereço de e-mail ainda não foi confirmado.', - 'email_not_confirmed_click_link' => 'Por favor, clique no link no e-mail que foi enviado após o registro.', + 'email_not_confirmed_click_link' => 'Por favor, clique no link no e-mail que foi enviado após o cadastro.', 'email_not_confirmed_resend' => 'Caso não encontre o e-mail você poderá reenviar a confirmação usando o formulário abaixo.', - 'email_not_confirmed_resend_button' => 'Reenviar o e-mail de confirmação', + 'email_not_confirmed_resend_button' => 'Reenviar o E-mail de Confirmação', // User Invite - 'user_invite_email_subject' => 'You have been invited to join :appName!', - 'user_invite_email_greeting' => 'An account has been created for you on :appName.', - 'user_invite_email_text' => 'Click the button below to set an account password and gain access:', - 'user_invite_email_action' => 'Set Account Password', - 'user_invite_page_welcome' => 'Welcome to :appName!', - 'user_invite_page_text' => 'To finalise your account and gain access you need to set a password which will be used to log-in to :appName on future visits.', - 'user_invite_page_confirm_button' => 'Confirm Password', - 'user_invite_success' => 'Password set, you now have access to :appName!' + 'user_invite_email_subject' => 'Você recebeu um convite para :appName!', + 'user_invite_email_greeting' => 'Uma conta foi criada para você em :appName.', + 'user_invite_email_text' => 'Clique no botão abaixo para definir uma senha de conta e obter acesso:', + 'user_invite_email_action' => 'Defina a Senha da Conta', + 'user_invite_page_welcome' => 'Bem-vindo(a) a :appName!', + 'user_invite_page_text' => 'Para finalizar sua conta e obter acesso, você precisa definir uma senha que será usada para efetuar login em :appName em futuras visitas.', + 'user_invite_page_confirm_button' => 'Confirmar Senha', + 'user_invite_success' => 'Senha definida, você agora tem acesso a :appName!' ]; \ No newline at end of file diff --git a/resources/lang/pt_BR/common.php b/resources/lang/pt_BR/common.php index 811446444..f32774014 100644 --- a/resources/lang/pt_BR/common.php +++ b/resources/lang/pt_BR/common.php @@ -11,20 +11,20 @@ return [ 'save' => 'Salvar', 'continue' => 'Continuar', 'select' => 'Selecionar', - 'toggle_all' => 'Alternar Tudo', + 'toggle_all' => 'Alternar Todos', 'more' => 'Mais', // Form Labels 'name' => 'Nome', 'description' => 'Descrição', - 'role' => 'Regra', + 'role' => 'Cargo', 'cover_image' => 'Imagem de capa', - 'cover_image_description' => 'Esta imagem deve ser aproximadamente 300x170px.', + 'cover_image_description' => 'Esta imagem deve ser aproximadamente 440x250px.', // Actions 'actions' => 'Ações', 'view' => 'Visualizar', - 'view_all' => 'Ver Tudo', + 'view_all' => 'Visualizar Tudo', 'create' => 'Criar', 'update' => 'Atualizar', 'edit' => 'Editar', @@ -35,16 +35,16 @@ return [ 'delete' => 'Excluir', 'search' => 'Pesquisar', 'search_clear' => 'Limpar Pesquisa', - 'reset' => 'Resetar', + 'reset' => 'Redefinir', 'remove' => 'Remover', 'add' => 'Adicionar', - 'fullscreen' => 'Fullscreen', + 'fullscreen' => 'Tela cheia', // Sort Options - 'sort_options' => 'Sort Options', - 'sort_direction_toggle' => 'Sort Direction Toggle', - 'sort_ascending' => 'Sort Ascending', - 'sort_descending' => 'Sort Descending', + 'sort_options' => 'Opções de Ordenação', + 'sort_direction_toggle' => 'Alternar Direção de Ordenação', + 'sort_ascending' => 'Ordenação Crescente', + 'sort_descending' => 'Ordenação Decrescente', 'sort_name' => 'Nome', 'sort_created_at' => 'Data de Criação', 'sort_updated_at' => 'Data de Atualização', @@ -60,15 +60,15 @@ return [ 'grid_view' => 'Visualização em Grade', 'list_view' => 'Visualização em Lista', 'default' => 'Padrão', - 'breadcrumb' => 'Breadcrumb', + 'breadcrumb' => 'Caminho', // Header - 'profile_menu' => 'Profile Menu', + 'profile_menu' => 'Menu de Perfil', 'view_profile' => 'Visualizar Perfil', 'edit_profile' => 'Editar Perfil', // Layout tabs - 'tab_info' => 'Info', + 'tab_info' => 'Informações', 'tab_content' => 'Conteúdo', // Email Content diff --git a/resources/lang/pt_BR/components.php b/resources/lang/pt_BR/components.php index e983e9f8d..e45101452 100644 --- a/resources/lang/pt_BR/components.php +++ b/resources/lang/pt_BR/components.php @@ -5,23 +5,23 @@ return [ // Image Manager - 'image_select' => 'Selecionar imagem', - 'image_all' => 'Todos', + 'image_select' => 'Selecionar Imagem', + 'image_all' => 'Todas', 'image_all_title' => 'Visualizar todas as imagens', 'image_book_title' => 'Visualizar imagens relacionadas a esse livro', 'image_page_title' => 'visualizar imagens relacionadas a essa página', 'image_search_hint' => 'Pesquisar imagem por nome', - 'image_uploaded' => 'Carregado :uploadedDate', + 'image_uploaded' => 'Adicionada em :uploadedDate', 'image_load_more' => 'Carregar Mais', 'image_image_name' => 'Nome da Imagem', 'image_delete_used' => 'Essa imagem é usada nas páginas abaixo.', 'image_delete_confirm' => 'Clique em Excluir novamente para confirmar que você deseja mesmo eliminar a imagem.', 'image_select_image' => 'Selecionar Imagem', 'image_dropzone' => 'Arraste imagens ou clique aqui para fazer upload', - 'images_deleted' => 'Imagens excluídas', - 'image_preview' => 'Virtualização de Imagem', + 'images_deleted' => 'Imagens Excluídas', + 'image_preview' => 'Pré-Visualização de Imagem', 'image_upload_success' => 'Upload de imagem efetuado com sucesso', - 'image_update_success' => 'Upload de detalhes da imagem efetuado com sucesso', + 'image_update_success' => 'Detalhes da imagem atualizados com sucesso', 'image_delete_success' => 'Imagem excluída com sucesso', 'image_upload_remove' => 'Remover', diff --git a/resources/lang/pt_BR/entities.php b/resources/lang/pt_BR/entities.php index c0e2c5ee9..323ce083f 100644 --- a/resources/lang/pt_BR/entities.php +++ b/resources/lang/pt_BR/entities.php @@ -6,29 +6,29 @@ return [ // Shared - 'recently_created' => 'Recentemente Criado', - 'recently_created_pages' => 'Páginas Recentemente Criadas', - 'recently_updated_pages' => 'Páginas Recentemente Atualizadas', - 'recently_created_chapters' => 'Capítulos Recentemente Criados', - 'recently_created_books' => 'Livros Recentemente Criados', - 'recently_created_shelves' => 'Prateleiras Recentemente Criadas', - 'recently_update' => 'Recentemente Atualizado', - 'recently_viewed' => 'Recentemente Visualizado', + 'recently_created' => 'Criados Recentemente', + 'recently_created_pages' => 'Páginas Criadas Recentemente', + 'recently_updated_pages' => 'Páginas Atualizadas Recentemente', + 'recently_created_chapters' => 'Capítulos Criados Recentemente', + 'recently_created_books' => 'Livros Criados Recentemente', + 'recently_created_shelves' => 'Prateleiras Criadas Recentemente', + 'recently_update' => 'Atualizados Recentemente', + 'recently_viewed' => 'Visualizados Recentemente', 'recent_activity' => 'Atividade Recente', 'create_now' => 'Criar um agora', 'revisions' => 'Revisões', 'meta_revision' => 'Revisão #:revisionCount', - 'meta_created' => 'Criado em :timeLength', - 'meta_created_name' => 'Criado em :timeLength por :user', - 'meta_updated' => 'Atualizado em :timeLength', - 'meta_updated_name' => 'Atualizado em :timeLength por :user', + 'meta_created' => 'Criado :timeLength', + 'meta_created_name' => 'Criado :timeLength por :user', + 'meta_updated' => 'Atualizado :timeLength', + 'meta_updated_name' => 'Atualizado :timeLength por :user', 'entity_select' => 'Seleção de Entidade', 'images' => 'Imagens', - 'my_recent_drafts' => 'Meus rascunhos recentes', - 'my_recently_viewed' => 'Meus itens recentemente visto', + 'my_recent_drafts' => 'Meus Rascunhos Recentes', + 'my_recently_viewed' => 'Visualizados por mim Recentemente', 'no_pages_viewed' => 'Você não visualizou nenhuma página', - 'no_pages_recently_created' => 'Nenhuma página recentemente criada', - 'no_pages_recently_updated' => 'Nenhuma página recentemente atualizada', + 'no_pages_recently_created' => 'Nenhuma página criada recentemente', + 'no_pages_recently_updated' => 'Nenhuma página atualizada recentemente', 'export' => 'Exportar', 'export_html' => 'Arquivo Web Contained', 'export_pdf' => 'Arquivo PDF', @@ -36,7 +36,7 @@ return [ // Permissions and restrictions 'permissions' => 'Permissões', - 'permissions_intro' => 'Uma vez habilitado, as permissões terão prioridade sobre outro conjunto de permissões.', + 'permissions_intro' => 'Uma vez habilitadas, estas permissões terão prioridade sobre outro conjunto de permissões.', 'permissions_enable' => 'Habilitar Permissões Customizadas', 'permissions_save' => 'Salvar Permissões', @@ -50,10 +50,10 @@ return [ 'search_filters' => 'Filtros de Pesquisa', 'search_content_type' => 'Tipo de Conteúdo', 'search_exact_matches' => 'Correspondências Exatas', - 'search_tags' => 'Tags', + 'search_tags' => 'Persquisar Tags', 'search_options' => 'Opções', - 'search_viewed_by_me' => 'Visto por mim', - 'search_not_viewed_by_me' => 'Não visto por mim', + 'search_viewed_by_me' => 'Visualizado por mim', + 'search_not_viewed_by_me' => 'Não visualizado por mim', 'search_permissions_set' => 'Permissão definida', 'search_created_by_me' => 'Criado por mim', 'search_updated_by_me' => 'Atualizado por mim', @@ -62,7 +62,7 @@ return [ 'search_updated_after' => 'Atualizado depois de', 'search_created_before' => 'Criado antes de', 'search_created_after' => 'Criado depois de', - 'search_set_date' => 'Definir data', + 'search_set_date' => 'Definir Data', 'search_update' => 'Refazer Pesquisa', // Shelves @@ -82,20 +82,20 @@ return [ 'shelves_add_books' => 'Adicionar livros a esta prateleira', 'shelves_drag_books' => 'Arraste livros aqui para adicioná-los a esta prateleira', 'shelves_empty_contents' => 'Esta prateleira não possui livros atribuídos a ela', - 'shelves_edit_and_assign' => 'Edit shelf to assign books', + 'shelves_edit_and_assign' => 'Editar prateleira para atribuir livros', 'shelves_edit_named' => 'Editar Prateleira de Livros :name', 'shelves_edit' => 'Edit Prateleira de Livros', 'shelves_delete' => 'Excluir Prateleira de Livros', 'shelves_delete_named' => 'Excluir Prateleira de Livros :name', - 'shelves_delete_explain' => "A ação vai excluír a prateleira de livros com o nome ':name'. Livros contidos não serão excluídos", + 'shelves_delete_explain' => "A ação vai excluír a prateleira com o nome ':name'. Livros contidos não serão excluídos.", 'shelves_delete_confirmation' => 'Você tem certeza que quer excluir esta prateleira de livros?', - 'shelves_permissions' => 'Permissões da Prateleira de Livros', - 'shelves_permissions_updated' => 'Permissões da Prateleira de Livros Atualizada', - 'shelves_permissions_active' => 'Permissões da Prateleira de Livros Ativadas', + 'shelves_permissions' => 'Permissões da Prateleira', + 'shelves_permissions_updated' => 'Permissões da Prateleira Atualizadas', + 'shelves_permissions_active' => 'Permissões da Prateleira Ativas', 'shelves_copy_permissions_to_books' => 'Copiar Permissões para Livros', 'shelves_copy_permissions' => 'Copiar Permissões', - 'shelves_copy_permissions_explain' => 'Isto aplicará as configurações de permissões atuais desta prateleira de livros a todos os livros contidos nela. Antes de ativar, assegure-se de que quaisquer alterações nas permissões desta prateleira de livros tenham sido salvas.', - 'shelves_copy_permission_success' => 'Permissões da prateleira de livros copiada para :count livros', + 'shelves_copy_permissions_explain' => 'Isto aplicará as configurações de permissões atuais desta prateleira a todos os livros contidos nela. Antes de ativar, assegure-se de que quaisquer alterações nas permissões desta prateleira tenham sido salvas.', + 'shelves_copy_permission_success' => 'Permissões da prateleira copiadas para :count livros', // Books 'book' => 'Livro', @@ -108,23 +108,23 @@ return [ 'books_new_action' => 'Novo Livro', 'books_popular_empty' => 'Os livros mais populares aparecerão aqui.', 'books_new_empty' => 'Os livros criados mais recentemente aparecerão aqui.', - 'books_create' => 'Criar novo Livro', + 'books_create' => 'Criar Novo Livro', 'books_delete' => 'Excluir Livro', 'books_delete_named' => 'Excluir Livro :bookName', - 'books_delete_explain' => 'A ação vai excluír o livro com o nome \':bookName\'. Todas as páginas e capítulos serão removidos.', - 'books_delete_confirmation' => 'Você tem certeza que quer excluír o Livro?', + 'books_delete_explain' => 'A ação vai excluir o livro com o nome \':bookName\'. Todas as páginas e capítulos serão removidos.', + 'books_delete_confirmation' => 'Você tem certeza que quer excluir o Livro?', 'books_edit' => 'Editar Livro', 'books_edit_named' => 'Editar Livro :bookName', 'books_form_book_name' => 'Nome do Livro', 'books_save' => 'Salvar Livro', 'books_permissions' => 'Permissões do Livro', 'books_permissions_updated' => 'Permissões do Livro Atualizadas', - 'books_empty_contents' => 'Nenhuma página ou capítulo criado para esse livro.', + 'books_empty_contents' => 'Nenhuma página ou capítulo foram criados para este livro.', 'books_empty_create_page' => 'Criar uma nova página', 'books_empty_sort_current_book' => 'Ordenar o livro atual', 'books_empty_add_chapter' => 'Adicionar um capítulo', - 'books_permissions_active' => 'Permissões do Livro Ativadas', - 'books_search_this' => 'Pesquisar esse livro', + 'books_permissions_active' => 'Permissões do Livro Ativas', + 'books_search_this' => 'Pesquisar neste livro', 'books_navigation' => 'Navegação do Livro', 'books_sort' => 'Ordenar Conteúdos do Livro', 'books_sort_named' => 'Ordenar Livro :bookName', @@ -143,10 +143,10 @@ return [ 'chapters_popular' => 'Capítulos Populares', 'chapters_new' => 'Novo Capítulo', 'chapters_create' => 'Criar Novo Capítulo', - 'chapters_delete' => 'Excluír Capítulo', + 'chapters_delete' => 'Excluir Capítulo', 'chapters_delete_named' => 'Excluir Capítulo :chapterName', - 'chapters_delete_explain' => 'A ação vai excluír o capítulo de nome \':chapterName\'. Todas as páginas do capítulo serão removidas e adicionadas diretamente ao livro pai.', - 'chapters_delete_confirm' => 'Tem certeza que deseja excluír o capítulo?', + 'chapters_delete_explain' => 'A ação vai excluir o capítulo de nome \':chapterName\'. Todas as páginas do capítulo serão removidas e adicionadas diretamente ao livro pai.', + 'chapters_delete_confirm' => 'Tem certeza que deseja excluir o capítulo?', 'chapters_edit' => 'Editar Capítulo', 'chapters_edit_named' => 'Editar Capítulo :chapterName', 'chapters_save' => 'Salvar Capítulo', @@ -155,86 +155,86 @@ return [ 'chapter_move_success' => 'Capítulo movido para :bookName', 'chapters_permissions' => 'Permissões do Capítulo', 'chapters_empty' => 'Nenhuma página existente nesse capítulo.', - 'chapters_permissions_active' => 'Permissões de Capítulo Ativadas', + 'chapters_permissions_active' => 'Permissões de Capítulo Ativas', 'chapters_permissions_success' => 'Permissões de Capítulo Atualizadas', - 'chapters_search_this' => 'Pesquisar este Capítulo', + 'chapters_search_this' => 'Pesquisar neste Capítulo', // Pages 'page' => 'Página', 'pages' => 'Páginas', 'x_pages' => ':count Página|:count Páginas', - 'pages_popular' => 'Páginas Popular', + 'pages_popular' => 'Páginas Populares', 'pages_new' => 'Nova Página', 'pages_attachments' => 'Anexos', - 'pages_navigation' => 'Página de Navegação', - 'pages_delete' => 'Excluír Página', - 'pages_delete_named' => 'Excluír Página :pageName', - 'pages_delete_draft_named' => 'Excluir rascunho de Página de nome :pageName', - 'pages_delete_draft' => 'Excluir rascunho de Página', + 'pages_navigation' => 'Navegação da Página', + 'pages_delete' => 'Excluir Página', + 'pages_delete_named' => 'Excluir Página :pageName', + 'pages_delete_draft_named' => 'Excluir Rascunho de Página de nome :pageName', + 'pages_delete_draft' => 'Excluir Rascunho de Página', 'pages_delete_success' => 'Página excluída', - 'pages_delete_draft_success' => 'Página de rascunho excluída', + 'pages_delete_draft_success' => 'Rascunho de página excluído', 'pages_delete_confirm' => 'Tem certeza que deseja excluir a página?', 'pages_delete_draft_confirm' => 'Tem certeza que deseja excluir o rascunho de página?', 'pages_editing_named' => 'Editando a Página :pageName', - 'pages_edit_draft_options' => 'Draft Options', + 'pages_edit_draft_options' => 'Opções de Rascunho', 'pages_edit_save_draft' => 'Salvar Rascunho', - 'pages_edit_draft' => 'Editar rascunho de Página', + 'pages_edit_draft' => 'Editar Rascunho de Página', 'pages_editing_draft' => 'Editando Rascunho', 'pages_editing_page' => 'Editando Página', 'pages_edit_draft_save_at' => 'Rascunho salvo em ', - 'pages_edit_delete_draft' => 'Excluir rascunho', - 'pages_edit_discard_draft' => 'Descartar rascunho', - 'pages_edit_set_changelog' => 'Definir Changelog', - 'pages_edit_enter_changelog_desc' => 'Digite uma breve descrição das mudanças efetuadas por você', - 'pages_edit_enter_changelog' => 'Entrar no Changelog', + 'pages_edit_delete_draft' => 'Excluir Rascunho', + 'pages_edit_discard_draft' => 'Descartar Rascunho', + 'pages_edit_set_changelog' => 'Relatar Alterações', + 'pages_edit_enter_changelog_desc' => 'Digite uma breve descrição das alterações efetuadas por você', + 'pages_edit_enter_changelog' => 'Insira Alterações', 'pages_save' => 'Salvar Página', - 'pages_title' => 'Título de Página', + 'pages_title' => 'Título da Página', 'pages_name' => 'Nome da Página', 'pages_md_editor' => 'Editor', - 'pages_md_preview' => 'Preview', + 'pages_md_preview' => 'Pré-Visualização', 'pages_md_insert_image' => 'Inserir Imagem', 'pages_md_insert_link' => 'Inserir Link para Entidade', 'pages_md_insert_drawing' => 'Inserir Desenho', - 'pages_not_in_chapter' => 'Página não está dentro de um Capítulo', + 'pages_not_in_chapter' => 'Página não está dentro de um capítulo', 'pages_move' => 'Mover Página', 'pages_move_success' => 'Pagina movida para ":parentName"', 'pages_copy' => 'Copiar Página', 'pages_copy_desination' => 'Destino da Cópia', 'pages_copy_success' => 'Página copiada com sucesso', - 'pages_permissions' => 'Permissões de Página', - 'pages_permissions_success' => 'Permissões de Página atualizadas', + 'pages_permissions' => 'Permissões da Página', + 'pages_permissions_success' => 'Permissões da Página atualizadas', 'pages_revision' => 'Revisão', - 'pages_revisions' => 'Revisões de Página', + 'pages_revisions' => 'Revisões da Página', 'pages_revisions_named' => 'Revisões de Página para :pageName', 'pages_revision_named' => 'Revisão de Página para :pageName', - 'pages_revisions_created_by' => 'Criado por', + 'pages_revisions_created_by' => 'Criada por', 'pages_revisions_date' => 'Data da Revisão', 'pages_revisions_number' => '#', 'pages_revisions_numbered' => 'Revisão #:id', 'pages_revisions_numbered_changes' => 'Alterações da Revisão #:id', - 'pages_revisions_changelog' => 'Changelog', - 'pages_revisions_changes' => 'Mudanças', - 'pages_revisions_current' => 'Versão atual', - 'pages_revisions_preview' => 'Preview', + 'pages_revisions_changelog' => 'Relatório de Alterações', + 'pages_revisions_changes' => 'Alterações', + 'pages_revisions_current' => 'Versão Atual', + 'pages_revisions_preview' => 'Pré-Visualização', 'pages_revisions_restore' => 'Restaurar', 'pages_revisions_none' => 'Essa página não tem revisões', - 'pages_copy_link' => 'Copia Link', - 'pages_edit_content_link' => 'Editar conteúdo', + 'pages_copy_link' => 'Copiar Link', + 'pages_edit_content_link' => 'Editar Conteúdo', 'pages_permissions_active' => 'Permissões de Página Ativas', 'pages_initial_revision' => 'Publicação Inicial', 'pages_initial_name' => 'Nova Página', 'pages_editing_draft_notification' => 'Você está atualmente editando um rascunho que foi salvo da última vez em :timeDiff.', 'pages_draft_edited_notification' => 'Essa página foi atualizada desde então. É recomendado que você descarte esse rascunho.', 'pages_draft_edit_active' => [ - 'start_a' => ':count usuários que iniciaram edição dessa página', + 'start_a' => ':count usuários iniciaram a edição dessa página', 'start_b' => ':userName iniciou a edição dessa página', 'time_a' => 'desde que a página foi atualizada pela última vez', 'time_b' => 'nos últimos :minCount minutos', 'message' => ':start :time. Tome cuidado para não sobrescrever atualizações de outras pessoas!', ], - 'pages_draft_discarded' => 'Rascunho descartado. O editor foi atualizado com a página atualizada', + 'pages_draft_discarded' => 'Rascunho descartado. O editor foi atualizado com o conteúdo atual da página', 'pages_specific' => 'Página Específica', - 'pages_is_template' => 'Page Template', + 'pages_is_template' => 'Modelo de Página', // Editor Sidebar 'page_tags' => 'Tags de Página', @@ -243,22 +243,22 @@ return [ 'shelf_tags' => 'Tags de Prateleira', 'tag' => 'Tag', 'tags' => 'Tags', - 'tag_name' => 'Tag Name', + 'tag_name' => 'Nome da Tag', 'tag_value' => 'Valor da Tag (Opcional)', - 'tags_explain' => "Adicione algumas tags para melhor categorizar seu conteúdo. \n Você pode atrelar um valor para uma tag para uma organização mais consistente.", + 'tags_explain' => "Adicione algumas tags para melhor categorizar seu conteúdo. \n Você pode atribuir valores às tags para uma organização mais complexa.", 'tags_add' => 'Adicionar outra tag', - 'tags_remove' => 'Remove this tag', + 'tags_remove' => 'Remover essa tag', 'attachments' => 'Anexos', - 'attachments_explain' => 'Faça o Upload de alguns arquivos ou anexo algum link para ser mostrado na sua página. Eles estarão visíveis na barra lateral à direita da página.', + 'attachments_explain' => 'Faça o upload de alguns arquivos ou anexe links para serem exibidos na sua página. Eles estarão visíveis na barra lateral à direita.', 'attachments_explain_instant_save' => 'Mudanças são salvas instantaneamente.', 'attachments_items' => 'Itens Anexados', - 'attachments_upload' => 'Upload de arquivos', + 'attachments_upload' => 'Upload de Arquivos', 'attachments_link' => 'Links Anexados', 'attachments_set_link' => 'Definir Link', 'attachments_delete_confirm' => 'Clique novamente em Excluir para confirmar a exclusão desse anexo.', 'attachments_dropzone' => 'Arraste arquivos para cá ou clique para anexar arquivos', 'attachments_no_files' => 'Nenhum arquivo foi enviado', - 'attachments_explain_link' => 'Você pode anexar um link se preferir não fazer o upload do arquivo. O link poderá ser para uma outra página ou link para um arquivo na nuvem.', + 'attachments_explain_link' => 'Você pode anexar um link se preferir não fazer o upload do arquivo. O link poderá ser para uma outra página ou para um arquivo na nuvem.', 'attachments_link_name' => 'Nome do Link', 'attachment_link' => 'Link para o Anexo', 'attachments_link_url' => 'Link para o Arquivo', @@ -266,19 +266,19 @@ return [ 'attach' => 'Anexar', 'attachments_edit_file' => 'Editar Arquivo', 'attachments_edit_file_name' => 'Nome do Arquivo', - 'attachments_edit_drop_upload' => 'Arraste arquivos para cá ou clique para anexar arquivos e sobrescreve-lo', + 'attachments_edit_drop_upload' => 'Arraste arquivos para cá ou clique para anexar arquivos e sobrescreve-los', 'attachments_order_updated' => 'Ordem dos anexos atualizada', 'attachments_updated_success' => 'Detalhes dos anexos atualizados', 'attachments_deleted' => 'Anexo excluído', 'attachments_file_uploaded' => 'Upload de arquivo efetuado com sucesso', 'attachments_file_updated' => 'Arquivo atualizado com sucesso', 'attachments_link_attached' => 'Link anexado com sucesso à página', - 'templates' => 'Templates', - 'templates_set_as_template' => 'Page is a template', - 'templates_explain_set_as_template' => 'You can set this page as a template so its contents be utilized when creating other pages. Other users will be able to use this template if they have view permissions for this page.', - 'templates_replace_content' => 'Replace page content', - 'templates_append_content' => 'Append to page content', - 'templates_prepend_content' => 'Prepend to page content', + 'templates' => 'Modelos', + 'templates_set_as_template' => 'A Página é um Modelo', + 'templates_explain_set_as_template' => 'Você pode definir esta página como um modelo para que seu conteúdo possa ser utilizado para criar outras páginas. Outros usuários poderão utilizar esta página como modelo se tiverem permissão para visualiza-la.', + 'templates_replace_content' => 'Substituir conteúdo da página', + 'templates_append_content' => 'Adicionar ao fim do conteúdo da página', + 'templates_prepend_content' => 'Adicionar ao início do conteúdo da página', // Profile View 'profile_user_for_x' => 'Usuário por :time', @@ -297,13 +297,13 @@ return [ 'comment_save' => 'Salvar comentário', 'comment_saving' => 'Salvando comentário...', 'comment_deleting' => 'Removendo comentário...', - 'comment_new' => 'Novo comentário', + 'comment_new' => 'Novo Comentário', 'comment_created' => 'comentado :createDiff', 'comment_updated' => 'Editado :updateDiff por :username', 'comment_deleted_success' => 'Comentário removido', 'comment_created_success' => 'Comentário adicionado', 'comment_updated_success' => 'Comentário editado', - 'comment_delete_confirm' => 'Você tem certeza de que quer deletar este comentário?', + 'comment_delete_confirm' => 'Você tem certeza de que deseja excluir este comentário?', 'comment_in_reply_to' => 'Em resposta à :commentId', // Revision diff --git a/resources/lang/pt_BR/errors.php b/resources/lang/pt_BR/errors.php index fb254bc13..0b7c75839 100644 --- a/resources/lang/pt_BR/errors.php +++ b/resources/lang/pt_BR/errors.php @@ -5,44 +5,45 @@ return [ // Permissions - 'permission' => 'Você não tem permissões para acessar a página requerida.', + 'permission' => 'Você não tem permissão para acessar a página requerida.', 'permissionJson' => 'Você não tem permissão para realizar a ação requerida.', // Auth 'error_user_exists_different_creds' => 'Um usuário com o e-mail :email já existe mas com credenciais diferentes.', 'email_already_confirmed' => 'E-mail já foi confirmado. Tente efetuar o login.', - 'email_confirmation_invalid' => 'Esse token de confirmação não é válido ou já foi utilizado. Por favor, tente efetuar o registro novamente.', + 'email_confirmation_invalid' => 'Esse token de confirmação não é válido ou já foi utilizado. Por favor, tente cadastrar-se novamente.', 'email_confirmation_expired' => 'O token de confirmação já expirou. Um novo e-mail foi enviado.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'O acesso LDAP falhou ao tentar usar o anonymous bind', 'ldap_fail_authed' => 'O acesso LDAP falhou ao tentar os detalhes do dn e senha fornecidos', - 'ldap_extension_not_installed' => 'As extensões LDAP PHP não estão instaladas', + 'ldap_extension_not_installed' => 'A extensão LDAP PHP não está instalada', 'ldap_cannot_connect' => 'Não foi possível conectar ao servidor LDAP. Conexão inicial falhou', - 'saml_already_logged_in' => 'Already logged in', - 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', - 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', - 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', - 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', - 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', + 'saml_already_logged_in' => 'Login já efetuado', + 'saml_user_not_registered' => 'O usuário :name não está cadastrado e o cadastro automático está desativado', + 'saml_no_email_address' => 'Não foi possível encontrar um endereço de e-mail para este usuário nos dados providos pelo sistema de autenticação externa', + 'saml_invalid_response_id' => 'A requisição do sistema de autenticação externa não foi reconhecia por um processo iniciado por esta aplicação. Após o login, navegar para o caminho anterior pode causar um problema.', + 'saml_fail_authed' => 'Login utilizando :system falhou. Sistema não forneceu autorização bem sucedida', + 'saml_email_exists' => 'Registro malsucedido pois um usuário já existe com este endereço de e-mail ":email"', 'social_no_action_defined' => 'Nenhuma ação definida', 'social_login_bad_response' => "Erro recebido durante o login :socialAccount: \n:error", - 'social_account_in_use' => 'Essa conta :socialAccount já está em uso. Por favor, tente se logar usando a opção :socialAccount', - 'social_account_email_in_use' => 'O e-mail :email já está e muso. Se você já tem uma conta você poderá se conectar a conta :socialAccount a partir das configurações de seu perfil.', - 'social_account_existing' => 'Essa conta :socialAccount já está atrelada a esse perfil.', - 'social_account_already_used_existing' => 'Essa conta :socialAccount já está sendo usada por outro usuário.', - 'social_account_not_used' => 'Essa conta :socialAccount não está atrelada a nenhum usuário. Por favor, faça o link da conta com suas configurações de perfil. ', - 'social_account_register_instructions' => 'Se você não tem uma conta, você poderá fazer o registro usando a opção :socialAccount', + 'social_account_in_use' => 'Essa conta :socialAccount já está em uso. Por favor, tente entrar utilizando a opção :socialAccount.', + 'social_account_email_in_use' => 'O e-mail :email já está em uso. Se você já tem uma conta você poderá se conectar a conta :socialAccount a partir das configurações de seu perfil.', + 'social_account_existing' => 'Essa conta :socialAccount já está vinculada a esse perfil.', + 'social_account_already_used_existing' => 'Essa conta :socialAccount já está sendo utilizada por outro usuário.', + 'social_account_not_used' => 'Essa conta :socialAccount não está vinculada a nenhum usuário. Por favor vincule a conta nas suas configurações de perfil. ', + 'social_account_register_instructions' => 'Se você não tem uma conta, você poderá se cadastrar usando a opção :socialAccount.', 'social_driver_not_found' => 'Social driver não encontrado', 'social_driver_not_configured' => 'Seus parâmetros socials de :socialAccount não estão configurados corretamente.', - 'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.', + 'invite_token_expired' => 'Esse link de convite expirou. Alternativamente, você pode tentar redefinir a senha da sua conta.', // System 'path_not_writable' => 'O caminho de destino (:filePath) de upload de arquivo não possui permissão de escrita. Certifique-se que ele possui direitos de escrita no servidor.', - 'cannot_get_image_from_url' => 'Não foi possivel capturar a imagem a partir de :url', + 'cannot_get_image_from_url' => 'Não foi possível obter a imagem a partir de :url', 'cannot_create_thumbs' => 'O servidor não pôde criar as miniaturas de imagem. Por favor, verifique se a extensão GD PHP está instalada.', 'server_upload_limit' => 'O servidor não permite o upload de arquivos com esse tamanho. Por favor, tente fazer o upload de arquivos de menor tamanho.', 'uploaded' => 'O servidor não permite o upload de arquivos com esse tamanho. Por favor, tente fazer o upload de arquivos de menor tamanho.', 'image_upload_error' => 'Um erro aconteceu enquanto o servidor tentava efetuar o upload da imagem', - 'image_upload_type_error' => 'O tipo de imagem que está sendo feito upload é inválido', + 'image_upload_type_error' => 'O tipo de imagem que está sendo enviada é inválido', 'file_upload_timeout' => 'O upload do arquivo expirou.', // Attachments @@ -50,8 +51,8 @@ return [ 'attachment_not_found' => 'Anexo não encontrado', // Pages - 'page_draft_autosave_fail' => 'Falhou ao tentar salvar o rascunho. Certifique-se que a conexão de internet está funcional antes de tentar salvar essa página', - 'page_custom_home_deletion' => 'Não pode deletar uma página que está definida como página inicial', + 'page_draft_autosave_fail' => 'Falha ao tentar salvar o rascunho. Certifique-se que a conexão de internet está funcional antes de tentar salvar essa página', + 'page_custom_home_deletion' => 'Não é possível excluir uma página que está definida como página inicial', // Entities 'entity_not_found' => 'Entidade não encontrada', @@ -60,18 +61,18 @@ return [ 'page_not_found' => 'Página não encontrada', 'chapter_not_found' => 'Capítulo não encontrado', 'selected_book_not_found' => 'O livro selecionado não foi encontrado', - 'selected_book_chapter_not_found' => 'O Livro selecionado ou Capítulo não foi encontrado', + 'selected_book_chapter_not_found' => 'O Livro ou Capítulo selecionado não foi encontrado', 'guests_cannot_save_drafts' => 'Convidados não podem salvar rascunhos', // Users - 'users_cannot_delete_only_admin' => 'Você não pode excluir o conteúdo, apenas o admin.', + 'users_cannot_delete_only_admin' => 'Você não pode excluir o único admin', 'users_cannot_delete_guest' => 'Você não pode excluir o usuário convidado', // Roles - 'role_cannot_be_edited' => 'Esse perfil não pode ser editado', - 'role_system_cannot_be_deleted' => 'Esse perfil é um perfil de sistema e não pode ser excluído', - 'role_registration_default_cannot_delete' => 'Esse perfil não poderá se excluído enquando estiver registrado como o perfil padrão', - 'role_cannot_remove_only_admin' => 'Este usuário é o único usuário atribuído ao perfil de administrador. Atribua o perfil de administrador a outro usuário antes de tentar removê-lo aqui.', + 'role_cannot_be_edited' => 'Esse cargo não pode ser editado', + 'role_system_cannot_be_deleted' => 'Esse cargo é um cargo do sistema e não pode ser excluído', + 'role_registration_default_cannot_delete' => 'Esse cargo não poderá se excluído enquanto estiver registrado como o cargo padrão', + 'role_cannot_remove_only_admin' => 'Este usuário é o único usuário vinculado ao cargo de administrador. Atribua o cargo de administrador a outro usuário antes de tentar removê-lo aqui.', // Comments 'comment_list' => 'Ocorreu um erro ao buscar os comentários.', @@ -81,11 +82,19 @@ return [ 'empty_comment' => 'Não é possível adicionar um comentário vazio.', // Error pages - '404_page_not_found' => 'Página não encontrada', + '404_page_not_found' => 'Página Não Encontrada', 'sorry_page_not_found' => 'Desculpe, a página que você está procurando não pôde ser encontrada.', - 'return_home' => 'Retornar à página principal', - 'error_occurred' => 'Um erro ocorreu', + 'return_home' => 'Retornar à página inicial', + 'error_occurred' => 'Ocorreu um Erro', 'app_down' => ':appName está fora do ar no momento', - 'back_soon' => 'Voltaremos em seguida.', + 'back_soon' => 'Voltaremos em breve.', + + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', ]; diff --git a/resources/lang/pt_BR/passwords.php b/resources/lang/pt_BR/passwords.php index 61a49f57a..0d452c361 100644 --- a/resources/lang/pt_BR/passwords.php +++ b/resources/lang/pt_BR/passwords.php @@ -6,10 +6,10 @@ */ return [ - 'password' => 'Senhas devem ter ao menos 6 caraceres e combinar com os atributos mínimos para a senha.', + 'password' => 'Senhas devem ter ao menos oito caracteres e ser iguais à confirmação.', 'user' => "Não pudemos encontrar um usuário com o e-mail fornecido.", - 'token' => 'O token de reset de senha é inválido.', - 'sent' => 'Enviamos para seu e-mail o link de reset de senha!', - 'reset' => 'Sua senha foi resetada com sucesso!', + 'token' => 'O token de redefinição de senha é inválido.', + 'sent' => 'Enviamos o link de redefinição de senha para o seu e-mail!', + 'reset' => 'Sua senha foi redefinida com sucesso!', ]; diff --git a/resources/lang/pt_BR/settings.php b/resources/lang/pt_BR/settings.php index f15b724c4..5376ab9c0 100644 --- a/resources/lang/pt_BR/settings.php +++ b/resources/lang/pt_BR/settings.php @@ -9,111 +9,112 @@ return [ // Common Messages 'settings' => 'Configurações', 'settings_save' => 'Salvar Configurações', - 'settings_save_success' => 'Configurações Salvas', + 'settings_save_success' => 'Configurações salvas', // App Settings 'app_customization' => 'Customização', 'app_features_security' => 'Recursos & Segurança', 'app_name' => 'Nome da Aplicação', 'app_name_desc' => 'Esse nome será mostrado no cabeçalho e em e-mails.', - 'app_name_header' => 'Mostrar o nome da Aplicação no cabeçalho?', + 'app_name_header' => 'Mostrar o nome no cabeçalho', 'app_public_access' => 'Acesso Público', 'app_public_access_desc' => 'Habilitar esta opção irá permitir que visitantes, que não estão logados, acessem o conteúdo em sua instância do BookStack.', 'app_public_access_desc_guest' => 'O acesso de visitantes públicos pode ser controlado através do usuário "Convidado".', 'app_public_access_toggle' => 'Permitir acesso público', 'app_public_viewing' => 'Permitir visualização pública?', - 'app_secure_images' => 'Permitir upload de imagens com maior segurança?', - 'app_secure_images_toggle' => 'Habilitar uploads de imagem de maior segurança', - 'app_secure_images_desc' => 'Por questões de performance, todas as imagens são públicas. Essa opção adiciona uma string randômica na frente da imagem. Certifique-se de que os índices do diretórios permitem o acesso fácil.', + 'app_secure_images' => 'Upload de Imagens mais Seguro', + 'app_secure_images_toggle' => 'Habilitar uploads de imagem mais seguro', + 'app_secure_images_desc' => 'Por razões de performance, todas as imagens são públicas. Esta opção adiciona uma string randômica na frente das URLs de imagens. Certifique-se de que os diretórios não possam ser indexados para prevenir acesso indesejado.', 'app_editor' => 'Editor de Página', - 'app_editor_desc' => 'Selecione qual editor a ser usado pelos usuários para editar páginas.', - 'app_custom_html' => 'Conteúdo para tag HTML HEAD customizado', - 'app_custom_html_desc' => 'Quaisquer conteúdos aqui inseridos serão inseridos no final da seção do HTML de cada página. Essa é uma maneira útil de sobrescrever estilos e adicionar códigos de análise de site.', - 'app_custom_html_disabled_notice' => 'O conteúdo personalizado do head do HTML está desabilitado nesta página de configurações para garantir que quaisquer alterações significativas possam ser revertidas.', + 'app_editor_desc' => 'Selecione qual editor será utilizado pelos usuários ao editar páginas.', + 'app_custom_html' => 'Conteúdo customizado para HTML', + 'app_custom_html_desc' => 'Quaisquer conteúdos aqui adicionados serão inseridos no final da seção de cada página. Essa é uma maneira útil de sobrescrever estilos e adicionar códigos de análise de site.', + 'app_custom_html_disabled_notice' => 'O conteúdo customizado do HTML está desabilitado nesta página de configurações, para garantir que quaisquer alterações danosas possam ser revertidas.', 'app_logo' => 'Logo da Aplicação', - 'app_logo_desc' => 'A imagem deve ter 43px de altura.
Imagens mais largas devem ser reduzidas.', - 'app_primary_color' => 'Cor primária da Aplicação', - 'app_primary_color_desc' => 'Esse valor deverá ser Hexadecimal.
Deixe em branco para que o Bookstack assuma a cor padrão.', - 'app_homepage' => 'Página incial', - 'app_homepage_desc' => 'Selecione a página para ser usada como página inicial em vez da padrão. Permissões da página serão ignoradas.', + 'app_logo_desc' => 'A imagem deve ter 43px de altura.
Imagens maiores serão reduzidas.', + 'app_primary_color' => 'Cor Primária da Aplicação', + 'app_primary_color_desc' => 'Define a cor primária para a aplicação, incluindo o banner, botões e links.', + 'app_homepage' => 'Página Inicial', + 'app_homepage_desc' => 'Selecione uma opção para ser exibida como página inicial em vez da padrão. Permissões de página serão ignoradas para as páginas selecionadas.', 'app_homepage_select' => 'Selecione uma página', 'app_disable_comments' => 'Desativar Comentários', 'app_disable_comments_toggle' => 'Desativar comentários', - 'app_disable_comments_desc' => 'Desativar comentários em todas as páginas no aplicativo. Os comentários existentes não são exibidos.', + 'app_disable_comments_desc' => 'Desativar comentários em todas as páginas no aplicativo.
Comentários existentes não serão exibidos.', // Color settings - 'content_colors' => 'Content Colors', - 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', - 'bookshelf_color' => 'Shelf Color', - 'book_color' => 'Book Color', - 'chapter_color' => 'Chapter Color', - 'page_color' => 'Page Color', - 'page_draft_color' => 'Page Draft Color', + 'content_colors' => 'Cores do Conteúdo', + 'content_colors_desc' => 'Define as cores para todos os elementos da hierarquia de organização de páginas. Escolher cores com brilho similar ao das cores padrão é aconselhável para a legibilidade.', + 'bookshelf_color' => 'Cor da Prateleira', + 'book_color' => 'Cor do Livro', + 'chapter_color' => 'Cor do Capítulo', + 'page_color' => 'Cor da Página', + 'page_draft_color' => 'Cor do Rascunho', // Registration Settings - 'reg_settings' => 'Registro', - 'reg_enable' => 'Habilitar Registro', - 'reg_enable_toggle' => 'Habilitar registro', - 'reg_enable_desc' => 'Quando o registro é habilitado, o usuário poderá se registrar como usuário do aplicativo. No registro, eles recebem um único perfil padrão.', - 'reg_default_role' => 'Perfil padrão para usuários após o registro', - 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', + 'reg_settings' => 'Cadastro', + 'reg_enable' => 'Habilitar Cadastro', + 'reg_enable_toggle' => 'Habilitar cadastro', + 'reg_enable_desc' => 'Quando o cadastro é habilitado, visitantes poderão cadastrar-se como usuários do aplicativo. Realizado o cadastro, recebem um único cargo padrão.', + 'reg_default_role' => 'Cargo padrão para usuários após o cadastro', + 'reg_enable_ldap_warning' => 'A opção acima não é usada enquanto a autenticação por LDAP está ativa. Contas de usuário para membros não existentes serão criadas automaticamente se a autenticação contrária ao sistema LDAP em uso é bem sucedida.', 'reg_email_confirmation' => 'Confirmação de E-mail', - 'reg_email_confirmation_toggle' => 'Requer confirmação de e-mail', - 'reg_confirm_email_desc' => 'Se restrições de domínio são usadas a confirmação por e-mail será requerida e o valor abaixo será ignorado.', - 'reg_confirm_restrict_domain' => 'Restringir registro ao domínio', - 'reg_confirm_restrict_domain_desc' => 'Entre com uma lista de domínios de e-mails separados por vírgula para os quais você deseja restringir os registros. Será enviado um e-mail de confirmação para o usuário validar o e-mail antes de ser permitido interação com a aplicação.
Note que os usuários serão capazes de alterar o e-mail cadastrado após o sucesso na confirmação do registro.', - 'reg_confirm_restrict_domain_placeholder' => 'Nenhuma restrição configurada', + 'reg_email_confirmation_toggle' => 'Requerer confirmação de e-mail', + 'reg_confirm_email_desc' => 'Em caso da restrição de domínios estar em uso, a confirmação de e-mail será requerida e essa opção será ignorada.', + 'reg_confirm_restrict_domain' => 'Restrição de Domínios', + 'reg_confirm_restrict_domain_desc' => 'Entre com uma lista separada por vírgulas de domínios de e-mails aos quais você deseja restringir o cadastro. Um e-mail de confirmação será enviado para o usuário validar seu endereço de e-mail antes de ser permitido a interagir com a aplicação.
Note que os usuários serão capazes de alterar o seus endereços de e-mail após o sucesso na confirmação do cadastro.', + 'reg_confirm_restrict_domain_placeholder' => 'Nenhuma restrição definida', // Maintenance settings 'maint' => 'Manutenção', 'maint_image_cleanup' => 'Limpeza de Imagens', - 'maint_image_cleanup_desc' => "Examina páginas & revisa o conteúdo para verificar quais imagens e desenhos estão atualmente em uso e quais imagens são redundantes. Certifique-se de criar um backup completo do banco de dados e imagens antes de executar isso.", + 'maint_image_cleanup_desc' => "Examina páginas e revisa seus conteúdos para verificar quais imagens e desenhos estão atualmente em uso e quais são redundantes. Certifique-se de criar um backup completo do banco de dados e imagens antes de executar esta ação.", 'maint_image_cleanup_ignore_revisions' => 'Ignorar imagens em revisões', 'maint_image_cleanup_run' => 'Executar Limpeza', 'maint_image_cleanup_warning' => ':count imagens potencialmente não utilizadas foram encontradas. Tem certeza de que deseja excluir estas imagens?', 'maint_image_cleanup_success' => ':count imagens potencialmente não utilizadas foram encontradas e excluídas!', 'maint_image_cleanup_nothing_found' => 'Nenhuma imagem não utilizada foi encontrada, nada foi excluído!', - 'maint_send_test_email' => 'Send a Test Email', - 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', - 'maint_send_test_email_run' => 'Send test email', - 'maint_send_test_email_success' => 'Email sent to :address', - 'maint_send_test_email_mail_subject' => 'Test Email', - 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', - 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', + 'maint_send_test_email' => 'Enviar um E-mail de Teste', + 'maint_send_test_email_desc' => 'Esta opção envia um e-mail de teste para o endereço especificado no seu perfil.', + 'maint_send_test_email_run' => 'Enviar e-mail de teste', + 'maint_send_test_email_success' => 'E-mail enviado para :address', + 'maint_send_test_email_mail_subject' => 'E-mail de Teste', + 'maint_send_test_email_mail_greeting' => 'O envio de e-mails parece funcionar!', + 'maint_send_test_email_mail_text' => 'Parabéns! Já que você recebeu esta notificação, suas opções de e-mail parecem estar configuradas corretamente.', // Role Settings - 'roles' => 'Perfis', - 'role_user_roles' => 'Perfis de Usuário', - 'role_create' => 'Criar novo Perfil', - 'role_create_success' => 'Perfil criado com sucesso', - 'role_delete' => 'Excluir Perfil', - 'role_delete_confirm' => 'A ação vai excluír o Perfil de nome \':roleName\'.', - 'role_delete_users_assigned' => 'Esse Perfil tem :userCount usuários assinalados a ele. Se quiser migrar usuários desse Perfil para outro, selecione um novo Perfil.', + 'roles' => 'Cargos', + 'role_user_roles' => 'Cargos de Usuário', + 'role_create' => 'Criar novo Cargo', + 'role_create_success' => 'Cargo criado com sucesso', + 'role_delete' => 'Excluir Cargo', + 'role_delete_confirm' => 'A ação vai excluír o cargo de nome \':roleName\'.', + 'role_delete_users_assigned' => 'Esse cargo tem :userCount usuários vinculados a ele. Se quiser migrar usuários desse cargo para outro, selecione um novo cargo.', 'role_delete_no_migration' => "Não migre os usuários", - 'role_delete_sure' => 'Tem certeza que deseja excluir esse Perfil?', - 'role_delete_success' => 'Perfil excluído com sucesso', - 'role_edit' => 'Editar Perfil', - 'role_details' => 'Detalhes do Perfil', - 'role_name' => 'Nome do Perfil', - 'role_desc' => 'Descrição Curta do Perfil', + 'role_delete_sure' => 'Tem certeza que deseja excluir esse cargo?', + 'role_delete_success' => 'Cargo excluído com sucesso', + 'role_edit' => 'Editar Cargo', + 'role_details' => 'Detalhes do Cargo', + 'role_name' => 'Nome do Cargo', + 'role_desc' => 'Breve Descrição do Cargo', 'role_external_auth_id' => 'IDs de Autenticação Externa', 'role_system' => 'Permissões do Sistema', - 'role_manage_users' => 'Gerenciar Usuários', - 'role_manage_roles' => 'Gerenciar Perfis & Permissões de Perfis', + 'role_manage_users' => 'Gerenciar usuários', + 'role_manage_roles' => 'Gerenciar cargos e permissões de cargos', 'role_manage_entity_permissions' => 'Gerenciar todos os livros, capítulos e permissões de páginas', 'role_manage_own_entity_permissions' => 'Gerenciar permissões de seu próprio livro, capítulo e paginas', - 'role_manage_page_templates' => 'Manage page templates', - 'role_manage_settings' => 'Gerenciar configurações de app', + 'role_manage_page_templates' => 'Gerenciar modelos de página', + 'role_access_api' => 'Access system API', + 'role_manage_settings' => 'Gerenciar configurações da aplicação', 'role_asset' => 'Permissões de Ativos', 'role_asset_desc' => 'Essas permissões controlam o acesso padrão para os ativos dentro do sistema. Permissões em Livros, Capítulos e Páginas serão sobrescritas por essas permissões.', - 'role_asset_admins' => 'Administradores recebem automaticamente acesso a todo o conteúdo, mas essas opções podem mostrar ou ocultar as opções da UI.', + 'role_asset_admins' => 'Administradores recebem automaticamente acesso a todo o conteúdo, mas essas opções podem mostrar ou ocultar as opções da Interface de Usuário.', 'role_all' => 'Todos', 'role_own' => 'Próprio', - 'role_controlled_by_asset' => 'Controlado pelos ativos que você fez upload', - 'role_save' => 'Salvar Perfil', - 'role_update_success' => 'Perfil atualizado com sucesso', - 'role_users' => 'Usuários neste Perfil', - 'role_users_none' => 'Nenhum usuário está atualmente atrelado a esse Perfil', + 'role_controlled_by_asset' => 'Controlado pelos ativos nos quais o upload foi realizado', + 'role_save' => 'Salvar Cargo', + 'role_update_success' => 'Cargo atualizado com sucesso', + 'role_users' => 'Usuários com este cargo', + 'role_users_none' => 'Nenhum usuário está atualmente vinculado a este cargo', // Users 'users' => 'Usuários', @@ -123,34 +124,60 @@ return [ 'users_details' => 'Detalhes do Usuário', 'users_details_desc' => 'Defina um nome de exibição e um endereço de e-mail para este usuário. O endereço de e-mail será usado para fazer login na aplicação.', 'users_details_desc_no_email' => 'Defina um nome de exibição para este usuário para que outros usuários possam reconhecê-lo', - 'users_role' => 'Perfis do Usuário', - 'users_role_desc' => 'Selecione os perfis para os quais este usuário será atribuído. Se um usuário for atribuído a multiplos perfis, as permissões destes perfis serão empilhadas e eles receberão todas as habilidades dos perfis atribuídos.', + 'users_role' => 'Cargos do Usuário', + 'users_role_desc' => 'Selecione os cargos aos quais este usuário será vinculado. Se um usuário for vinculado a múltiplos cargos, suas permissões serão empilhadas e ele receberá todas as habilidades dos cargos atribuídos.', 'users_password' => 'Senha do Usuário', - 'users_password_desc' => 'Defina uma senha usada para fazer login na aplicação. Esta deve ter pelo menos 5 caracteres.', - 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', - 'users_send_invite_option' => 'Send user invite email', + 'users_password_desc' => 'Defina uma senha usada para fazer login na aplicação. Esta deve ter pelo menos 6 caracteres.', + 'users_send_invite_text' => 'Você pode escolher enviar a este usuário um convite por e-mail que o possibilitará definir sua própria senha, ou defina você uma senha.', + 'users_send_invite_option' => 'Enviar convite por e-mail', 'users_external_auth_id' => 'ID de Autenticação Externa', - 'users_external_auth_id_desc' => 'Este é o ID usado para corresponder a este usuário ao se comunicar com seu sistema LDAP.', - 'users_password_warning' => 'Preencha os dados abaixo caso queira modificar a sua senha:', - 'users_system_public' => 'Esse usuário representa quaisquer convidados que visitam o aplicativo. Ele não pode ser usado para login.', + 'users_external_auth_id_desc' => 'Este é o ID usado para identificar este usuário quando se comunicando com seu sistema LDAP.', + 'users_password_warning' => 'Apenas preencha os dados abaixo caso queira modificar a sua senha.', + 'users_system_public' => 'Esse usuário representa quaisquer convidados que visitam o aplicativo. Ele não pode ser usado para login mas é automaticamente atribuído.', 'users_delete' => 'Excluir Usuário', 'users_delete_named' => 'Excluir :userName', 'users_delete_warning' => 'A ação vai excluir completamente o usuário de nome \':userName\' do sistema.', 'users_delete_confirm' => 'Tem certeza que deseja excluir esse usuário?', 'users_delete_success' => 'Usuários excluídos com sucesso', - 'users_edit' => 'Editar usuário', + 'users_edit' => 'Editar Usuário', 'users_edit_profile' => 'Editar Perfil', 'users_edit_success' => 'Usuário atualizado com sucesso', 'users_avatar' => 'Imagem de Usuário', - 'users_avatar_desc' => 'Essa imagem deve ser um quadrado com aproximadamente 256px de altura e largura.', + 'users_avatar_desc' => 'Defina uma imagem para representar este usuário. Essa imagem deve ser um quadrado com aproximadamente 256px de altura e largura.', 'users_preferred_language' => 'Linguagem de Preferência', - 'users_preferred_language_desc' => 'Esta opção irá alterar o idioma usado para a interface de usuário da aplicação. Isto não afetará nenhum conteúdo criado pelo usuário.', + 'users_preferred_language_desc' => 'Esta opção irá alterar o idioma utilizado para a interface de usuário da aplicação. Isto não afetará nenhum conteúdo criado por usuários.', 'users_social_accounts' => 'Contas Sociais', 'users_social_accounts_info' => 'Aqui você pode conectar outras contas para acesso mais rápido. Desconectar uma conta não retira a possibilidade de acesso usando-a. Para revogar o acesso ao perfil através da conta social, você deverá fazê-lo na sua conta social.', - 'users_social_connect' => 'Contas conectadas', + 'users_social_connect' => 'Contas Conectadas', 'users_social_disconnect' => 'Desconectar Conta', 'users_social_connected' => 'Conta :socialAccount foi conectada com sucesso ao seu perfil.', 'users_social_disconnected' => 'Conta :socialAccount foi desconectada com sucesso de seu perfil.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/lang/pt_BR/validation.php b/resources/lang/pt_BR/validation.php index c087fd0ab..718fca6b9 100644 --- a/resources/lang/pt_BR/validation.php +++ b/resources/lang/pt_BR/validation.php @@ -8,62 +8,62 @@ return [ // Standard laravel validation lines - 'accepted' => 'O :attribute deve ser aceito.', - 'active_url' => 'O :attribute não é uma URL válida.', - 'after' => 'O :attribute deve ser uma data posterior à data :date.', - 'alpha' => 'O :attribute deve conter apenas letras.', - 'alpha_dash' => 'O :attribute deve conter apenas letras, números e traços.', - 'alpha_num' => 'O :attribute deve conter apenas letras e números.', - 'array' => 'O :attribute deve ser uma array.', - 'before' => 'O :attribute deve ser uma data anterior à data :date.', + 'accepted' => 'O campo :attribute deve ser aceito.', + 'active_url' => 'O campo :attribute não é uma URL válida.', + 'after' => 'O campo :attribute deve ser uma data posterior à data :date.', + 'alpha' => 'O campo :attribute deve conter apenas letras.', + 'alpha_dash' => 'O campo :attribute deve conter apenas letras, números, traços e underlines.', + 'alpha_num' => 'O campo :attribute deve conter apenas letras e números.', + 'array' => 'O campo :attribute deve ser uma array.', + 'before' => 'O campo :attribute deve ser uma data anterior à data :date.', 'between' => [ - 'numeric' => 'O :attribute deve ter tamanho entre :min e :max.', - 'file' => 'O :attribute deve ter entre :min e :max kilobytes.', - 'string' => 'O :attribute deve ter entre :min e :max caracteres.', - 'array' => 'O :attribute deve ter entre :min e :max itens.', + 'numeric' => 'O campo :attribute deve estar entre :min e :max.', + 'file' => 'O campo :attribute deve ter entre :min e :max kilobytes.', + 'string' => 'O campo :attribute deve ter entre :min e :max caracteres.', + 'array' => 'O campo :attribute deve ter entre :min e :max itens.', ], 'boolean' => 'O campo :attribute deve ser verdadeiro ou falso.', - 'confirmed' => 'O campo :attribute de confirmação não é igual.', + 'confirmed' => 'O campo :attribute não é igual à sua confirmação.', 'date' => 'O campo :attribute não está em um formato de data válido.', 'date_format' => 'O campo :attribute não tem a formatação :format.', 'different' => 'O campo :attribute e o campo :other devem ser diferentes.', 'digits' => 'O campo :attribute deve ter :digits dígitos.', 'digits_between' => 'O campo :attribute deve ter entre :min e :max dígitos.', 'email' => 'O campo :attribute deve ser um e-mail válido.', - 'ends_with' => 'The :attribute must end with one of the following: :values', + 'ends_with' => 'O campo :attribute deve terminar com um dos seguintes: :values', 'filled' => 'O campo :attribute é requerido.', 'gt' => [ - 'numeric' => 'The :attribute must be greater than :value.', - 'file' => 'The :attribute must be greater than :value kilobytes.', - 'string' => 'The :attribute must be greater than :value characters.', - 'array' => 'The :attribute must have more than :value items.', + 'numeric' => 'O campo :attribute deve ser maior que :value.', + 'file' => 'O campo :attribute deve ser maior que :value kilobytes.', + 'string' => 'O campo :attribute deve ser maior que :value caracteres.', + 'array' => 'O campo :attribute deve ter mais que :value itens.', ], 'gte' => [ - 'numeric' => 'The :attribute must be greater than or equal :value.', - 'file' => 'The :attribute must be greater than or equal :value kilobytes.', - 'string' => 'The :attribute must be greater than or equal :value characters.', - 'array' => 'The :attribute must have :value items or more.', + 'numeric' => 'O campo :attribute deve ser maior ou igual a :value.', + 'file' => 'O campo :attribute deve ser maior ou igual a :value kilobytes.', + 'string' => 'O campo :attribute deve ser maior ou igual a :value caracteres.', + 'array' => 'O campo :attribute deve ter :value itens ou mais.', ], - 'exists' => 'O atributo :attribute selecionado não é válido.', + 'exists' => 'O campo :attribute selecionado não é válido.', 'image' => 'O campo :attribute deve ser uma imagem.', - 'image_extension' => 'O campo :attribute deve ter uma extensão de imagem válida & suportada.', - 'in' => 'The selected :attribute is invalid.', + 'image_extension' => 'O campo :attribute deve ter uma extensão de imagem válida e suportada.', + 'in' => 'O campo :attribute selecionado não é válido.', 'integer' => 'O campo :attribute deve ser um número inteiro.', - 'ip' => 'O campo :attribute deve ser um IP válido.', - 'ipv4' => 'The :attribute must be a valid IPv4 address.', - 'ipv6' => 'The :attribute must be a valid IPv6 address.', - 'json' => 'The :attribute must be a valid JSON string.', + 'ip' => 'O campo :attribute deve ser um endereço IP válido.', + 'ipv4' => 'O campo :attribute deve ser um endereço IPv4 válido.', + 'ipv6' => 'O campo :attribute deve ser um endereço IPv6 válido.', + 'json' => 'O campo :attribute deve ser uma string JSON válida.', 'lt' => [ - 'numeric' => 'The :attribute must be less than :value.', - 'file' => 'The :attribute must be less than :value kilobytes.', - 'string' => 'The :attribute must be less than :value characters.', - 'array' => 'The :attribute must have less than :value items.', + 'numeric' => 'O campo :attribute deve ser menor que :value.', + 'file' => 'O campo :attribute deve ser menor que :value kilobytes.', + 'string' => 'O campo :attribute deve ser menor que :value caracteres.', + 'array' => 'O campo :attribute deve conter menos que :value itens.', ], 'lte' => [ - 'numeric' => 'The :attribute must be less than or equal :value.', - 'file' => 'The :attribute must be less than or equal :value kilobytes.', - 'string' => 'The :attribute must be less than or equal :value characters.', - 'array' => 'The :attribute must not have more than :value items.', + 'numeric' => 'O campo :attribute deve ser menor ou igual a :value.', + 'file' => 'O campo :attribute deve ser menor ou igual a :value kilobytes.', + 'string' => 'O campo :attribute deve ser menor ou igual a :value caracteres.', + 'array' => 'O campo :attribute não deve conter mais que :value itens.', ], 'max' => [ 'numeric' => 'O valor para o campo :attribute não deve ser maior que :max.', @@ -71,16 +71,16 @@ return [ 'string' => 'O valor para o campo :attribute não deve ter mais que :max caracteres.', 'array' => 'O valor para o campo :attribute não deve ter mais que :max itens.', ], - 'mimes' => 'O :attribute deve ser do tipo type: :values.', + 'mimes' => 'O campo :attribute deve ser do tipo type: :values.', 'min' => [ - 'numeric' => 'O valor para o campo :attribute não deve ser menor que :min.', - 'file' => 'O valor para o campo :attribute não deve ter tamanho menor que :min kilobytes.', - 'string' => 'O valor para o campo :attribute não deve ter menos que :min caracteres.', - 'array' => 'O valor para o campo :attribute não deve ter menos que :min itens.', + 'numeric' => 'O campo :attribute não deve ser menor que :min.', + 'file' => 'O campo :attribute não deve ter tamanho menor que :min kilobytes.', + 'string' => 'O campo :attribute não deve ter menos que :min caracteres.', + 'array' => 'O campo :attribute não deve ter menos que :min itens.', ], 'no_double_extension' => 'O campo :attribute deve ter apenas uma extensão de arquivo.', 'not_in' => 'O campo selecionado :attribute é inválido.', - 'not_regex' => 'The :attribute format is invalid.', + 'not_regex' => 'O formato do campo :attribute é inválido.', 'numeric' => 'O campo :attribute deve ser um número.', 'regex' => 'O formato do campo :attribute é inválido.', 'required' => 'O campo :attribute é requerido.', diff --git a/resources/lang/ru/errors.php b/resources/lang/ru/errors.php index a812af677..1362fbb61 100644 --- a/resources/lang/ru/errors.php +++ b/resources/lang/ru/errors.php @@ -13,6 +13,7 @@ return [ 'email_already_confirmed' => 'Электронная почта уже подтверждена, попробуйте войти в систему.', 'email_confirmation_invalid' => 'Этот токен подтверждения недействителен или уже используется. Повторите попытку регистрации.', 'email_confirmation_expired' => 'Истек срок действия токена. Отправлено новое письмо с подтверждением.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'Недопустимый доступ LDAP с использованием анонимной привязки', 'ldap_fail_authed' => 'Не удалось получить доступ к LDAP, используя данные dn & password', 'ldap_extension_not_installed' => 'LDAP расширения для PHP не установлено', @@ -88,4 +89,12 @@ return [ 'app_down' => ':appName в данный момент не достпуно', 'back_soon' => 'Скоро восстановится.', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + ]; diff --git a/resources/lang/ru/settings.php b/resources/lang/ru/settings.php index 0dd3b97be..429fe037b 100755 --- a/resources/lang/ru/settings.php +++ b/resources/lang/ru/settings.php @@ -103,6 +103,7 @@ return [ 'role_manage_entity_permissions' => 'Управление правами на все книги, главы и страницы', 'role_manage_own_entity_permissions' => 'Управление разрешениями для собственных книг, разделов и страниц', 'role_manage_page_templates' => 'Управление шаблонами страниц', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Управление настройками приложения', 'role_asset' => 'Разрешение для активации', 'role_asset_desc' => 'Эти разрешения контролируют доступ по умолчанию к параметрам внутри системы. Разрешения на книги, главы и страницы перезапишут эти разрешения.', @@ -151,6 +152,32 @@ return [ 'users_social_disconnect' => 'Отключить аккаунт', 'users_social_connected' => ':socialAccount аккаунт упешно подключен к вашему профилю.', 'users_social_disconnected' => ':socialAccount аккаунт успешно отключен от вашего профиля.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/lang/sk/errors.php b/resources/lang/sk/errors.php index ab2ec88a2..6dac83fab 100644 --- a/resources/lang/sk/errors.php +++ b/resources/lang/sk/errors.php @@ -13,6 +13,7 @@ return [ 'email_already_confirmed' => 'Email bol už overený, skúste sa prihlásiť.', 'email_confirmation_invalid' => 'Tento potvrdzujúci token nie je platný alebo už bol použitý, skúste sa prosím registrovať znova.', 'email_confirmation_expired' => 'Potvrdzujúci token expiroval, bol odoslaný nový potvrdzujúci email.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'LDAP access failed using anonymous bind', 'ldap_fail_authed' => 'LDAP access failed using given dn & password details', 'ldap_extension_not_installed' => 'LDAP PHP extension not installed', @@ -88,4 +89,12 @@ return [ 'app_down' => ':appName je momentálne nedostupná', 'back_soon' => 'Čoskoro bude opäť dostupná.', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + ]; diff --git a/resources/lang/sk/settings.php b/resources/lang/sk/settings.php index c83d0fdb1..5ba754b5c 100644 --- a/resources/lang/sk/settings.php +++ b/resources/lang/sk/settings.php @@ -103,6 +103,7 @@ return [ 'role_manage_entity_permissions' => 'Spravovať všetky oprávnenia kníh, kapitol a stránok', 'role_manage_own_entity_permissions' => 'Spravovať oprávnenia vlastných kníh, kapitol a stránok', 'role_manage_page_templates' => 'Manage page templates', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Spravovať nastavenia aplikácie', 'role_asset' => 'Oprávnenia majetku', 'role_asset_desc' => 'Tieto oprávnenia regulujú prednastavený prístup k zdroju v systéme. Oprávnenia pre knihy, kapitoly a stránky majú vyššiu prioritu.', @@ -151,6 +152,32 @@ return [ 'users_social_disconnect' => 'Odpojiť účet', 'users_social_connected' => ':socialAccount účet bol úspešne pripojený k Vášmu profilu.', 'users_social_disconnected' => ':socialAccount účet bol úspešne odpojený od Vášho profilu.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/lang/sv/errors.php b/resources/lang/sv/errors.php index ac7d117ae..1149867ff 100644 --- a/resources/lang/sv/errors.php +++ b/resources/lang/sv/errors.php @@ -13,6 +13,7 @@ return [ 'email_already_confirmed' => 'E-posten har redan bekräftats, prova att logga in.', 'email_confirmation_invalid' => 'Denna bekräftelsekod är inte giltig eller har redan använts. Vänligen prova att registera dig på nytt', 'email_confirmation_expired' => 'Denna bekräftelsekod har gått ut. Vi har skickat dig en ny.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'LDAP-inloggning misslyckades med anonym bindning', 'ldap_fail_authed' => 'LDAP-inloggning misslyckades med angivna dn- och lösenordsuppgifter', 'ldap_extension_not_installed' => 'LDAP PHP-tillägg inte installerat', @@ -88,4 +89,12 @@ return [ 'app_down' => ':appName är nere just nu', 'back_soon' => 'Vi är snart tillbaka.', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + ]; diff --git a/resources/lang/sv/settings.php b/resources/lang/sv/settings.php index 5dd472e1a..38ac8a664 100644 --- a/resources/lang/sv/settings.php +++ b/resources/lang/sv/settings.php @@ -103,6 +103,7 @@ return [ 'role_manage_entity_permissions' => 'Hantera rättigheter för alla böcker, kapitel och sidor', 'role_manage_own_entity_permissions' => 'Hantera rättigheter för egna böcker, kapitel och sidor', 'role_manage_page_templates' => 'Manage page templates', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Hantera appinställningar', 'role_asset' => 'Tillgång till innehåll', 'role_asset_desc' => 'Det här är standardinställningarna för allt innehåll i systemet. Eventuella anpassade rättigheter på böcker, kapitel och sidor skriver över dessa inställningar.', @@ -151,6 +152,32 @@ return [ 'users_social_disconnect' => 'Koppla från konto', 'users_social_connected' => ':socialAccount har kopplats till ditt konto.', 'users_social_disconnected' => ':socialAccount har kopplats bort från ditt konto.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/lang/tr/common.php b/resources/lang/tr/common.php index c17c1cd8b..740757671 100644 --- a/resources/lang/tr/common.php +++ b/resources/lang/tr/common.php @@ -38,7 +38,7 @@ return [ 'reset' => 'Sıfırla', 'remove' => 'Kaldır', 'add' => 'Ekle', - 'fullscreen' => 'Fullscreen', + 'fullscreen' => 'Tam Ekran', // Sort Options 'sort_options' => 'Sıralama Seçenekleri', diff --git a/resources/lang/tr/errors.php b/resources/lang/tr/errors.php index 4b14edb4c..aef44c2b5 100644 --- a/resources/lang/tr/errors.php +++ b/resources/lang/tr/errors.php @@ -13,16 +13,17 @@ return [ 'email_already_confirmed' => 'E-mail halihazırda onaylanmış, giriş yapmayı dene.', 'email_confirmation_invalid' => 'Bu doğrulama tokenı daha önce kullanılmış veya geçerli değil, lütfen tekrar kayıt olmayı deneyin.', 'email_confirmation_expired' => 'Doğrulama token\'ının süresi geçmiş, yeni bir mail gönderildi.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'Anonim LDAP girişi başarısız oldu', 'ldap_fail_authed' => 'Verdiğiniz bilgiler ile LDAP girişi başarısız oldu.', 'ldap_extension_not_installed' => 'LDAP PHP eklentisi yüklenmedi', 'ldap_cannot_connect' => 'LDAP sunucusuna bağlanılamadı, ilk bağlantı başarısız oldu', - 'saml_already_logged_in' => 'Already logged in', - 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', - 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', - 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', - 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', - 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', + 'saml_already_logged_in' => 'Zaten giriş yapıldı', + 'saml_user_not_registered' => ':name adlı kullanıcı kayıtlı değil ve otomatik kaydolma devre dışı', + 'saml_no_email_address' => 'Bu kullanıcı için, harici bir doğrulama siteminden elde edilen verilerde, bir e-posta adresi bulunamadı', + 'saml_invalid_response_id' => 'Harici doğrulama sistemi tarafından sağlanan bir veri talebi, bu uygulama tarafından başlatılan bir işlem tarafından tanınamadı. Giriş yaptıktan sonra geri dönmek bu soruna yol açabilir.', + 'saml_fail_authed' => ':system kullanarak giriş yapma başarısız, sistem başarılı bir doğrulama sağlamadı', + 'saml_email_exists' => '":email" adresiyle halihazırda kayıtlı bir kullanıcı olduğu için kayıt başarısız', 'social_no_action_defined' => 'Bir aksiyon tanımlanmadı', 'social_login_bad_response' => ":socialAccount girişi sırasında hata oluştu: \n:error", 'social_account_in_use' => 'Bu :socialAccount zaten kullanımda, :socialAccount hesabıyla giriş yapmayı deneyin.', @@ -88,4 +89,12 @@ return [ 'app_down' => ':appName şu anda inaktif', 'back_soon' => 'En kısa zamanda aktif hale gelecek.', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + ]; diff --git a/resources/lang/tr/settings.php b/resources/lang/tr/settings.php index 7d5db1f2a..6c8e9c96f 100755 --- a/resources/lang/tr/settings.php +++ b/resources/lang/tr/settings.php @@ -42,13 +42,13 @@ return [ 'app_disable_comments_desc' => 'Yorumları uygulamadaki bütün sayfalar için engelle.
Mevcut yorumlar gösterilmeyecektir.', // Color settings - 'content_colors' => 'Content Colors', + 'content_colors' => 'İçerik Renkleri', 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', - 'bookshelf_color' => 'Shelf Color', - 'book_color' => 'Book Color', - 'chapter_color' => 'Chapter Color', - 'page_color' => 'Page Color', - 'page_draft_color' => 'Page Draft Color', + 'bookshelf_color' => 'Raf Rengi', + 'book_color' => 'Kitap Rengi', + 'chapter_color' => 'Kısım Rengi', + 'page_color' => 'Sayfa Rengi', + 'page_draft_color' => 'Sayfa Taslağı Rengi', // Registration Settings 'reg_settings' => 'Kayıt', @@ -103,6 +103,7 @@ return [ 'role_manage_entity_permissions' => 'Bütün kitap, bölüm ve sayfa izinlerini yönet', 'role_manage_own_entity_permissions' => 'Sahip olunan kitap, bölüm ve sayfaların izinlerini yönet', 'role_manage_page_templates' => 'Sayfa şablonlarını yönet', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Uygulama ayarlarını yönet', 'role_asset' => 'Asset Yetkileri', 'role_asset_desc' => 'Bu izinleri assetlere sistem içinden varsayılan erişimi kontrol eder. Kitaplar, bölümler ve sayfaların izinleri bu izinleri override eder.', @@ -151,6 +152,32 @@ return [ 'users_social_disconnect' => 'Hesabın Bağlantısını Kes', 'users_social_connected' => ':socialAccount hesabı profilinize başarıyla bağlandı.', 'users_social_disconnected' => ':socialAccount hesabınızın profilinizle ilişiği başarıyla kesildi.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/lang/uk/errors.php b/resources/lang/uk/errors.php index 461874573..8cf8ff936 100644 --- a/resources/lang/uk/errors.php +++ b/resources/lang/uk/errors.php @@ -13,6 +13,7 @@ return [ 'email_already_confirmed' => 'Електронна пошта вже підтверджена, спробуйте увійти.', 'email_confirmation_invalid' => 'Цей токен підтвердження недійсний або вже був використаний, будь ласка, спробуйте знову зареєструватися.', 'email_confirmation_expired' => 'Термін дії токена підтвердження минув, новий електронний лист підтвердження був відправлений.', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => 'LDAP-доступ невдалий, з використання анонімного зв\'язку', 'ldap_fail_authed' => 'LDAP-доступ невдалий, використовуючи задані параметри dn та password', 'ldap_extension_not_installed' => 'Розширення PHP LDAP не встановлено', @@ -88,4 +89,12 @@ return [ 'app_down' => ':appName зараз недоступний', 'back_soon' => 'Він повернеться найближчим часом.', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + ]; diff --git a/resources/lang/uk/settings.php b/resources/lang/uk/settings.php index d15e85fa8..0f3986328 100644 --- a/resources/lang/uk/settings.php +++ b/resources/lang/uk/settings.php @@ -103,6 +103,7 @@ return [ 'role_manage_entity_permissions' => 'Керування всіма правами на книги, розділи та сторінки', 'role_manage_own_entity_permissions' => 'Керування дозволами на власну книгу, розділ та сторінки', 'role_manage_page_templates' => 'Управління шаблонами сторінок', + 'role_access_api' => 'Access system API', 'role_manage_settings' => 'Керування налаштуваннями програми', 'role_asset' => 'Дозволи', 'role_asset_desc' => 'Ці дозволи контролюють стандартні доступи всередині системи. Права на книги, розділи та сторінки перевизначать ці дозволи.', @@ -151,6 +152,32 @@ return [ 'users_social_disconnect' => 'Від\'єднати обліковий запис', 'users_social_connected' => 'Обліковий запис :socialAccount успішно додано до вашого профілю.', 'users_social_disconnected' => 'Обліковий запис :socialAccount був успішно відключений від вашого профілю.', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/lang/zh_CN/common.php b/resources/lang/zh_CN/common.php index 4e257a2b6..c21e8029d 100644 --- a/resources/lang/zh_CN/common.php +++ b/resources/lang/zh_CN/common.php @@ -38,7 +38,7 @@ return [ 'reset' => '重置', 'remove' => '删除', 'add' => '添加', - 'fullscreen' => 'Fullscreen', + 'fullscreen' => '全屏', // Sort Options 'sort_options' => '排序选项', diff --git a/resources/lang/zh_CN/entities.php b/resources/lang/zh_CN/entities.php index d391856b8..5c614b079 100644 --- a/resources/lang/zh_CN/entities.php +++ b/resources/lang/zh_CN/entities.php @@ -247,7 +247,7 @@ return [ 'tag_value' => '标签值 (Optional)', 'tags_explain' => "添加一些标签以更好地对您的内容进行分类。\n您可以为标签分配一个值,以进行更深入的组织。", 'tags_add' => '添加另一个标签', - 'tags_remove' => 'Remove this tag', + 'tags_remove' => '删除此标签', 'attachments' => '附件', 'attachments_explain' => '上传一些文件或附加一些链接显示在您的网页上。这些在页面的侧边栏中可见。', 'attachments_explain_instant_save' => '这里的更改将立即保存。', diff --git a/resources/lang/zh_CN/errors.php b/resources/lang/zh_CN/errors.php index fcce87dcc..46a0a6880 100644 --- a/resources/lang/zh_CN/errors.php +++ b/resources/lang/zh_CN/errors.php @@ -13,16 +13,17 @@ return [ 'email_already_confirmed' => 'Email已被确认,请尝试登录。', 'email_confirmation_invalid' => '此确认令牌无效或已被使用,请重新注册。', 'email_confirmation_expired' => '确认令牌已过期,已发送新的确认电子邮件。', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => '使用匿名绑定的LDAP访问失败。', 'ldap_fail_authed' => '带有标识名称和密码的LDAP访问失败。', 'ldap_extension_not_installed' => '未安装LDAP PHP扩展程序', 'ldap_cannot_connect' => '无法连接到ldap服务器,初始连接失败', - 'saml_already_logged_in' => 'Already logged in', - 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', - 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', - 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', - 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', - 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', + 'saml_already_logged_in' => '您已经登陆了', + 'saml_user_not_registered' => '用户 :name 未注册且自动注册功能已被禁用', + 'saml_no_email_address' => '无法找到有效Email地址,此用户数据由外部身份验证系统托管', + 'saml_invalid_response_id' => '来自外部身份验证系统的请求没有被本应用程序认证,在登录后返回上一页可能会导致此问题。', + 'saml_fail_authed' => '使用 :system 登录失败,登录系统未返回成功登录授权信息。', + 'saml_email_exists' => '注册失败,因此已经有用户使用了 ":email" 此Email地址了', 'social_no_action_defined' => '没有定义行为', 'social_login_bad_response' => "在 :socialAccount 登录时遇到错误:\n:error", 'social_account_in_use' => ':socialAccount 账户已被使用,请尝试通过 :socialAccount 选项登录。', @@ -88,4 +89,12 @@ return [ 'app_down' => ':appName现在正在关闭', 'back_soon' => '请耐心等待网站的恢复。', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + ]; diff --git a/resources/lang/zh_CN/settings.php b/resources/lang/zh_CN/settings.php index 9fd6532fc..9b534374d 100755 --- a/resources/lang/zh_CN/settings.php +++ b/resources/lang/zh_CN/settings.php @@ -42,13 +42,13 @@ return [ 'app_disable_comments_desc' => '在站点的所有页面上禁用评论,现有评论也不会显示出来。', // Color settings - 'content_colors' => 'Content Colors', - 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', - 'bookshelf_color' => 'Shelf Color', - 'book_color' => 'Book Color', - 'chapter_color' => 'Chapter Color', - 'page_color' => 'Page Color', - 'page_draft_color' => 'Page Draft Color', + 'content_colors' => '内容颜色', + 'content_colors_desc' => '设置页面组织层次中所有元素的颜色。建议选择与默认颜色相似的亮度的颜色。', + 'bookshelf_color' => '书架颜色', + 'book_color' => '图书颜色', + 'chapter_color' => '章节颜色', + 'page_color' => '页面颜色', + 'page_draft_color' => '页面草稿颜色', // Registration Settings 'reg_settings' => '注册设置', @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => '启用注册', 'reg_enable_desc' => '启用注册后,用户将可以自己注册为站点用户。 注册后,他们将获得一个默认的单一用户角色。', 'reg_default_role' => '注册后的默认用户角色', - 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', + 'reg_enable_ldap_warning' => 'LDAP 身份验证处于活动状态时不使用上面的选项。 如果使用的 LDAP 系统验证成功,将自动创建非现有会员的用户帐户。', 'reg_email_confirmation' => '邮箱确认n', 'reg_email_confirmation_toggle' => '需要电子邮件确认', 'reg_confirm_email_desc' => '如果使用域名限制,则需要Email验证,并且该值将被忽略。', @@ -73,13 +73,13 @@ return [ 'maint_image_cleanup_warning' => '发现了 :count 张可能未使用的图像。您确定要删除这些图像吗?', 'maint_image_cleanup_success' => '找到并删除了 :count 张可能未使用的图像!', 'maint_image_cleanup_nothing_found' => '找不到未使用的图像,没有删除!', - 'maint_send_test_email' => 'Send a Test Email', - 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', - 'maint_send_test_email_run' => 'Send test email', - 'maint_send_test_email_success' => 'Email sent to :address', - 'maint_send_test_email_mail_subject' => 'Test Email', - 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', - 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', + 'maint_send_test_email' => '发送测试电子邮件', + 'maint_send_test_email_desc' => '这将发送测试邮件到您的个人资料中指定的电子邮件地址。', + 'maint_send_test_email_run' => '发送测试邮件', + 'maint_send_test_email_success' => '电子邮件已发送至 :address', + 'maint_send_test_email_mail_subject' => '测试电子邮件', + 'maint_send_test_email_mail_greeting' => '邮件发送功能看起来工作正常!', + 'maint_send_test_email_mail_text' => '恭喜!您收到了此邮件通知,你的电子邮件设置看起来配置正确。', // Role Settings 'roles' => '角色', @@ -102,7 +102,8 @@ return [ 'role_manage_roles' => '管理角色与角色权限', 'role_manage_entity_permissions' => '管理所有图书,章节和页面的权限', 'role_manage_own_entity_permissions' => '管理自己的图书,章节和页面的权限', - 'role_manage_page_templates' => 'Manage page templates', + 'role_manage_page_templates' => '管理页面模板', + 'role_access_api' => 'Access system API', 'role_manage_settings' => '管理App设置', 'role_asset' => '资源许可', 'role_asset_desc' => '对系统内资源的默认访问许可将由这些权限控制。单独设置在书籍,章节和页面上的权限将覆盖这里的权限设定。', @@ -151,6 +152,32 @@ return [ 'users_social_disconnect' => '解除绑定账户', 'users_social_connected' => ':socialAccount 账户已经成功绑定到您的资料。', 'users_social_disconnected' => ':socialAccount 账户已经成功解除绑定。', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. diff --git a/resources/lang/zh_TW/errors.php b/resources/lang/zh_TW/errors.php index 3042364b0..7cbff8891 100644 --- a/resources/lang/zh_TW/errors.php +++ b/resources/lang/zh_TW/errors.php @@ -13,6 +13,7 @@ return [ 'email_already_confirmed' => 'Email已被確認,請嘗試登錄。', 'email_confirmation_invalid' => '此確認 Session 無效或已被使用,請重新註冊。', 'email_confirmation_expired' => '確認 Session 已過期,已發送新的確認電子郵件。', + 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', 'ldap_fail_anonymous' => '使用匿名綁定的LDAP進入失敗。', 'ldap_fail_authed' => '帶有標識名稱和密碼的LDAP進入失敗。', 'ldap_extension_not_installed' => '未安裝LDAP PHP外掛程式', @@ -88,4 +89,12 @@ return [ 'app_down' => ':appName現在正在關閉', 'back_soon' => '請耐心等待網站的恢複。', + // API errors + 'api_no_authorization_found' => 'No authorization token found on the request', + 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', + 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', + 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', + 'api_user_token_expired' => 'The authorization token used has expired', + ]; diff --git a/resources/lang/zh_TW/settings.php b/resources/lang/zh_TW/settings.php index cd887c7be..052bd5394 100644 --- a/resources/lang/zh_TW/settings.php +++ b/resources/lang/zh_TW/settings.php @@ -103,6 +103,7 @@ return [ 'role_manage_entity_permissions' => '管理所有圖書,章節和頁面的權限', 'role_manage_own_entity_permissions' => '管理自己的圖書,章節和頁面的權限', 'role_manage_page_templates' => 'Manage page templates', + 'role_access_api' => 'Access system API', 'role_manage_settings' => '管理App設定', 'role_asset' => '資源項目', 'role_asset_desc' => '對系統內資源的預設權限將由這裡的權限控制。若有單獨設定在書本、章節和頁面上的權限,將會覆蓋這裡的權限設定。', @@ -151,6 +152,32 @@ return [ 'users_social_disconnect' => '解除連結帳號', 'users_social_connected' => ':socialAccount 帳號已經成功連結到您的資料。', 'users_social_disconnected' => ':socialAccount 帳號已經成功解除連結。', + 'users_api_tokens' => 'API Tokens', + 'users_api_tokens_none' => 'No API tokens have been created for this user', + 'users_api_tokens_create' => 'Create Token', + 'users_api_tokens_expires' => 'Expires', + 'users_api_tokens_docs' => 'API Documentation', + + // API Tokens + 'user_api_token_create' => 'Create API Token', + 'user_api_token_name' => 'Name', + 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', + 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', + 'user_api_token_create_success' => 'API token successfully created', + 'user_api_token_update_success' => 'API token successfully updated', + 'user_api_token' => 'API Token', + 'user_api_token_id' => 'Token ID', + 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_secret' => 'Token Secret', + 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', + 'user_api_token_created' => 'Token Created :timeAgo', + 'user_api_token_updated' => 'Token Updated :timeAgo', + 'user_api_token_delete' => 'Delete Token', + 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', + 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', + 'user_api_token_delete_success' => 'API token successfully deleted', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. From 5ff89a1abbdd4063282898127ac5582c8695e7a9 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 18 Jan 2020 16:07:36 +0000 Subject: [PATCH 163/191] Added danish to language arrays --- app/Config/app.php | 2 +- app/Http/Middleware/Localization.php | 1 + resources/lang/en/settings.php | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Config/app.php b/app/Config/app.php index 0d06a9b21..3b7216b3d 100755 --- a/app/Config/app.php +++ b/app/Config/app.php @@ -52,7 +52,7 @@ return [ 'locale' => env('APP_LANG', 'en'), // Locales available - 'locales' => ['en', 'ar', 'de', 'de_informal', 'es', 'es_AR', 'fr', 'hu', 'nl', 'pt_BR', 'sk', 'cs', 'sv', 'ko', 'ja', 'pl', 'it', 'ru', 'uk', 'zh_CN', 'zh_TW', 'tr'], + 'locales' => ['en', 'ar', 'da', 'de', 'de_informal', 'es', 'es_AR', 'fr', 'hu', 'nl', 'pt_BR', 'sk', 'cs', 'sv', 'ko', 'ja', 'pl', 'it', 'ru', 'uk', 'zh_CN', 'zh_TW', 'tr'], // Application Fallback Locale 'fallback_locale' => 'en', diff --git a/app/Http/Middleware/Localization.php b/app/Http/Middleware/Localization.php index de48cb196..f36d72725 100644 --- a/app/Http/Middleware/Localization.php +++ b/app/Http/Middleware/Localization.php @@ -19,6 +19,7 @@ class Localization */ protected $localeMap = [ 'ar' => 'ar', + 'da' => 'da_DK', 'de' => 'de_DE', 'de_informal' => 'de_DE', 'en' => 'en_GB', diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index fb00c3cce..b36fdda7a 100755 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -185,6 +185,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', From fb5df49fd4459ed0096426077692fbd58e972e0f Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 26 Jan 2020 13:26:37 +0000 Subject: [PATCH 164/191] Updated laravel version and moved flare to non-dev --- composer.json | 8 +- composer.lock | 1431 ++++++++++++++++++++++++++----------------------- 2 files changed, 768 insertions(+), 671 deletions(-) diff --git a/composer.json b/composer.json index ccfffb569..0edf7bae8 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,7 @@ "fideloper/proxy": "^4.0", "gathercontent/htmldiff": "^0.2.1", "intervention/image": "^2.5", - "laravel/framework": "^6.9", + "laravel/framework": "^6.12", "laravel/socialite": "^4.2", "league/flysystem-aws-s3-v3": "^1.0", "onelogin/php-saml": "^3.3", @@ -29,16 +29,16 @@ "socialiteproviders/microsoft-azure": "^3.0", "socialiteproviders/okta": "^1.0", "socialiteproviders/slack": "^3.0", - "socialiteproviders/twitch": "^5.0" + "socialiteproviders/twitch": "^5.0", + "facade/ignition": "^1.4", + "nunomaduro/collision": "^3.0" }, "require-dev": { "barryvdh/laravel-debugbar": "^3.2.8", "barryvdh/laravel-ide-helper": "^2.6.4", - "facade/ignition": "^1.4", "fzaninotto/faker": "^1.4", "laravel/browser-kit-testing": "^5.1", "mockery/mockery": "^1.0", - "nunomaduro/collision": "^3.0", "phpunit/phpunit": "^8.0", "squizlabs/php_codesniffer": "^3.4", "wnx/laravel-stats": "^2.0" diff --git a/composer.lock b/composer.lock index b44554ac9..c35b3f962 100644 --- a/composer.lock +++ b/composer.lock @@ -4,30 +4,30 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e9b29fe5292928c55110f71cd2181afe", + "content-hash": "309610dc13c0d46ca7553ee264a88d29", "packages": [ { "name": "aws/aws-sdk-php", - "version": "3.130.2", + "version": "3.133.6", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "35289d9dd5184dd1106e49f99ef5074a84635b5c" + "reference": "cd7bd2fdd159146ef6c7eeb90b73fae4fd11da57" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/35289d9dd5184dd1106e49f99ef5074a84635b5c", - "reference": "35289d9dd5184dd1106e49f99ef5074a84635b5c", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/cd7bd2fdd159146ef6c7eeb90b73fae4fd11da57", + "reference": "cd7bd2fdd159146ef6c7eeb90b73fae4fd11da57", "shasum": "" }, "require": { "ext-json": "*", "ext-pcre": "*", "ext-simplexml": "*", - "guzzlehttp/guzzle": "^5.3.3|^6.2.1", - "guzzlehttp/promises": "~1.0", + "guzzlehttp/guzzle": "^5.3.3|^6.2.1|^7.0", + "guzzlehttp/promises": "^1.0", "guzzlehttp/psr7": "^1.4.1", - "mtdowling/jmespath.php": "~2.2", + "mtdowling/jmespath.php": "^2.5", "php": ">=5.5" }, "require-dev": { @@ -88,7 +88,7 @@ "s3", "sdk" ], - "time": "2019-12-23T19:12:28+00:00" + "time": "2020-01-24T19:11:35+00:00" }, { "name": "barryvdh/laravel-dompdf", @@ -342,16 +342,16 @@ }, { "name": "doctrine/dbal", - "version": "v2.10.0", + "version": "v2.10.1", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "0c9a646775ef549eb0a213a4f9bd4381d9b4d934" + "reference": "c2b8e6e82732a64ecde1cddf9e1e06cb8556e3d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/0c9a646775ef549eb0a213a4f9bd4381d9b4d934", - "reference": "0c9a646775ef549eb0a213a4f9bd4381d9b4d934", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/c2b8e6e82732a64ecde1cddf9e1e06cb8556e3d8", + "reference": "c2b8e6e82732a64ecde1cddf9e1e06cb8556e3d8", "shasum": "" }, "require": { @@ -430,7 +430,7 @@ "sqlserver", "sqlsrv" ], - "time": "2019-11-03T16:50:43+00:00" + "time": "2020-01-04T12:56:21+00:00" }, { "name": "doctrine/event-manager", @@ -639,28 +639,28 @@ }, { "name": "dompdf/dompdf", - "version": "v0.8.3", + "version": "v0.8.4", "source": { "type": "git", "url": "https://github.com/dompdf/dompdf.git", - "reference": "75f13c700009be21a1965dc2c5b68a8708c22ba2" + "reference": "8f49b3b01693f51037dd50da81090beba1b5c005" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/dompdf/zipball/75f13c700009be21a1965dc2c5b68a8708c22ba2", - "reference": "75f13c700009be21a1965dc2c5b68a8708c22ba2", + "url": "https://api.github.com/repos/dompdf/dompdf/zipball/8f49b3b01693f51037dd50da81090beba1b5c005", + "reference": "8f49b3b01693f51037dd50da81090beba1b5c005", "shasum": "" }, "require": { "ext-dom": "*", "ext-mbstring": "*", - "phenx/php-font-lib": "0.5.*", - "phenx/php-svg-lib": "0.3.*", - "php": ">=5.4.0" + "phenx/php-font-lib": "^0.5.1", + "phenx/php-svg-lib": "^0.3.3", + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^4.8|^5.5|^6.5", - "squizlabs/php_codesniffer": "2.*" + "phpunit/phpunit": "^7.5", + "squizlabs/php_codesniffer": "^3.5" }, "suggest": { "ext-gd": "Needed to process images", @@ -701,7 +701,7 @@ ], "description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter", "homepage": "https://github.com/dompdf/dompdf", - "time": "2018-12-14T02:40:31+00:00" + "time": "2020-01-20T17:00:46+00:00" }, { "name": "dragonmantank/cron-expression", @@ -759,27 +759,27 @@ }, { "name": "egulias/email-validator", - "version": "2.1.12", + "version": "2.1.15", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "a6255605af39f2db7f5cb62e672bd8a7bad8d208" + "reference": "e834eea5306d85d67de5a05db5882911d5b29357" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/a6255605af39f2db7f5cb62e672bd8a7bad8d208", - "reference": "a6255605af39f2db7f5cb62e672bd8a7bad8d208", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/e834eea5306d85d67de5a05db5882911d5b29357", + "reference": "e834eea5306d85d67de5a05db5882911d5b29357", "shasum": "" }, "require": { "doctrine/lexer": "^1.0.1", - "php": ">= 5.5" + "php": ">=5.5", + "symfony/polyfill-intl-idn": "^1.10" }, "require-dev": { - "dominicsayers/isemail": "dev-master", - "phpunit/phpunit": "^4.8.35||^5.7||^6.0", - "satooshi/php-coveralls": "^1.0.1", - "symfony/phpunit-bridge": "^4.4@dev" + "dominicsayers/isemail": "^3.0.7", + "phpunit/phpunit": "^4.8.36|^7.5.15", + "satooshi/php-coveralls": "^1.0.1" }, "suggest": { "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" @@ -813,33 +813,154 @@ "validation", "validator" ], - "time": "2019-12-20T12:49:39+00:00" + "time": "2020-01-20T21:40:59+00:00" }, { - "name": "erusev/parsedown", - "version": "1.7.3", + "name": "facade/flare-client-php", + "version": "1.3.1", "source": { "type": "git", - "url": "https://github.com/erusev/parsedown.git", - "reference": "6d893938171a817f4e9bc9e86f2da1e370b7bcd7" + "url": "https://github.com/facade/flare-client-php.git", + "reference": "24444ea0e1556f0a4b5fc8e61802caf72ae9a408" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/erusev/parsedown/zipball/6d893938171a817f4e9bc9e86f2da1e370b7bcd7", - "reference": "6d893938171a817f4e9bc9e86f2da1e370b7bcd7", + "url": "https://api.github.com/repos/facade/flare-client-php/zipball/24444ea0e1556f0a4b5fc8e61802caf72ae9a408", + "reference": "24444ea0e1556f0a4b5fc8e61802caf72ae9a408", "shasum": "" }, "require": { - "ext-mbstring": "*", - "php": ">=5.3.0" + "facade/ignition-contracts": "~1.0", + "illuminate/pipeline": "~5.5|~5.6|~5.7|~5.8|^6.0", + "php": "^7.1", + "symfony/http-foundation": "~3.3|~4.1", + "symfony/var-dumper": "^3.4|^4.0|^5.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35" + "larapack/dd": "^1.1", + "phpunit/phpunit": "^7.5.16", + "spatie/phpunit-snapshot-assertions": "^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Facade\\FlareClient\\": "src" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Send PHP errors to Flare", + "homepage": "https://github.com/facade/flare-client-php", + "keywords": [ + "exception", + "facade", + "flare", + "reporting" + ], + "time": "2019-12-15T18:28:38+00:00" + }, + { + "name": "facade/ignition", + "version": "1.16.0", + "source": { + "type": "git", + "url": "https://github.com/facade/ignition.git", + "reference": "37f094775814b68d0c6cc8b8ff3c3be243f20725" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facade/ignition/zipball/37f094775814b68d0c6cc8b8ff3c3be243f20725", + "reference": "37f094775814b68d0c6cc8b8ff3c3be243f20725", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "facade/flare-client-php": "^1.3", + "facade/ignition-contracts": "^1.0", + "filp/whoops": "^2.4", + "illuminate/support": "~5.5.0 || ~5.6.0 || ~5.7.0 || ~5.8.0 || ^6.0", + "monolog/monolog": "^1.12 || ^2.0", + "php": "^7.1", + "scrivo/highlight.php": "^9.15", + "symfony/console": "^3.4 || ^4.0", + "symfony/var-dumper": "^3.4 || ^4.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.14", + "mockery/mockery": "^1.2", + "orchestra/testbench": "^3.5 || ^3.6 || ^3.7 || ^3.8 || ^4.0" + }, + "suggest": { + "laravel/telescope": "^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "v2.x-dev" + }, + "laravel": { + "providers": [ + "Facade\\Ignition\\IgnitionServiceProvider" + ], + "aliases": { + "Flare": "Facade\\Ignition\\Facades\\Flare" + } + } + }, + "autoload": { + "psr-4": { + "Facade\\Ignition\\": "src" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A beautiful error page for Laravel applications.", + "homepage": "https://github.com/facade/ignition", + "keywords": [ + "error", + "flare", + "laravel", + "page" + ], + "time": "2020-01-21T17:46:02+00:00" + }, + { + "name": "facade/ignition-contracts", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/facade/ignition-contracts.git", + "reference": "f445db0fb86f48e205787b2592840dd9c80ded28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facade/ignition-contracts/zipball/f445db0fb86f48e205787b2592840dd9c80ded28", + "reference": "f445db0fb86f48e205787b2592840dd9c80ded28", + "shasum": "" + }, + "require": { + "php": "^7.1" }, "type": "library", "autoload": { - "psr-0": { - "Parsedown": "" + "psr-4": { + "Facade\\IgnitionContracts\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -848,18 +969,20 @@ ], "authors": [ { - "name": "Emanuil Rusev", - "email": "hello@erusev.com", - "homepage": "http://erusev.com" + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://flareapp.io", + "role": "Developer" } ], - "description": "Parser for Markdown.", - "homepage": "http://parsedown.org", + "description": "Solution contracts for Ignition", + "homepage": "https://github.com/facade/ignition-contracts", "keywords": [ - "markdown", - "parser" + "contracts", + "flare", + "ignition" ], - "time": "2019-03-17T18:48:37+00:00" + "time": "2019-08-30T14:06:08+00:00" }, { "name": "fideloper/proxy", @@ -915,6 +1038,67 @@ ], "time": "2019-12-20T13:11:11+00:00" }, + { + "name": "filp/whoops", + "version": "2.7.1", + "source": { + "type": "git", + "url": "https://github.com/filp/whoops.git", + "reference": "fff6f1e4f36be0e0d0b84d66b413d9dcb0c49130" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filp/whoops/zipball/fff6f1e4f36be0e0d0b84d66b413d9dcb0c49130", + "reference": "fff6f1e4f36be0e0d0b84d66b413d9dcb0c49130", + "shasum": "" + }, + "require": { + "php": "^5.5.9 || ^7.0", + "psr/log": "^1.0.1" + }, + "require-dev": { + "mockery/mockery": "^0.9 || ^1.0", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0", + "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0 || ^5.0" + }, + "suggest": { + "symfony/var-dumper": "Pretty print complex values better with var-dumper available", + "whoops/soap": "Formats errors as SOAP responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-4": { + "Whoops\\": "src/Whoops/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Filipe Dobreira", + "homepage": "https://github.com/filp", + "role": "Developer" + } + ], + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", + "keywords": [ + "error", + "exception", + "handling", + "library", + "throwable", + "whoops" + ], + "time": "2020-01-15T10:00:00+00:00" + }, { "name": "gathercontent/htmldiff", "version": "0.2.1", @@ -1224,17 +1408,105 @@ "time": "2019-11-02T09:15:47+00:00" }, { - "name": "knplabs/knp-snappy", - "version": "v1.2.0", + "name": "jakub-onderka/php-console-color", + "version": "v0.2", "source": { "type": "git", - "url": "https://github.com/KnpLabs/snappy.git", - "reference": "162633e3143f7f03b395e1dbd53df25e1e87d2f5" + "url": "https://github.com/JakubOnderka/PHP-Console-Color.git", + "reference": "d5deaecff52a0d61ccb613bb3804088da0307191" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/KnpLabs/snappy/zipball/162633e3143f7f03b395e1dbd53df25e1e87d2f5", - "reference": "162633e3143f7f03b395e1dbd53df25e1e87d2f5", + "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/d5deaecff52a0d61ccb613bb3804088da0307191", + "reference": "d5deaecff52a0d61ccb613bb3804088da0307191", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "jakub-onderka/php-code-style": "1.0", + "jakub-onderka/php-parallel-lint": "1.0", + "jakub-onderka/php-var-dump-check": "0.*", + "phpunit/phpunit": "~4.3", + "squizlabs/php_codesniffer": "1.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "JakubOnderka\\PhpConsoleColor\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Jakub Onderka", + "email": "jakub.onderka@gmail.com" + } + ], + "time": "2018-09-29T17:23:10+00:00" + }, + { + "name": "jakub-onderka/php-console-highlighter", + "version": "v0.4", + "source": { + "type": "git", + "url": "https://github.com/JakubOnderka/PHP-Console-Highlighter.git", + "reference": "9f7a229a69d52506914b4bc61bfdb199d90c5547" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Highlighter/zipball/9f7a229a69d52506914b4bc61bfdb199d90c5547", + "reference": "9f7a229a69d52506914b4bc61bfdb199d90c5547", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "jakub-onderka/php-console-color": "~0.2", + "php": ">=5.4.0" + }, + "require-dev": { + "jakub-onderka/php-code-style": "~1.0", + "jakub-onderka/php-parallel-lint": "~1.0", + "jakub-onderka/php-var-dump-check": "~0.1", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "JakubOnderka\\PhpConsoleHighlighter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jakub Onderka", + "email": "acci@acci.cz", + "homepage": "http://www.acci.cz/" + } + ], + "description": "Highlight PHP code in terminal", + "time": "2018-09-29T18:48:56+00:00" + }, + { + "name": "knplabs/knp-snappy", + "version": "v1.2.1", + "source": { + "type": "git", + "url": "https://github.com/KnpLabs/snappy.git", + "reference": "7bac60fb729147b7ccd8532c07df3f52a4afa8a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/KnpLabs/snappy/zipball/7bac60fb729147b7ccd8532c07df3f52a4afa8a4", + "reference": "7bac60fb729147b7ccd8532c07df3f52a4afa8a4", "shasum": "" }, "require": { @@ -1287,30 +1559,31 @@ "thumbnail", "wkhtmltopdf" ], - "time": "2019-12-02T16:06:55+00:00" + "time": "2020-01-20T08:30:30+00:00" }, { "name": "laravel/framework", - "version": "v6.9.0", + "version": "v6.12.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "60610be97ca389fa4b959d4d13fb3690970d9fb7" + "reference": "8e189a8dee7ff76bf50acb7e80aa1a36afaf54d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/60610be97ca389fa4b959d4d13fb3690970d9fb7", - "reference": "60610be97ca389fa4b959d4d13fb3690970d9fb7", + "url": "https://api.github.com/repos/laravel/framework/zipball/8e189a8dee7ff76bf50acb7e80aa1a36afaf54d4", + "reference": "8e189a8dee7ff76bf50acb7e80aa1a36afaf54d4", "shasum": "" }, "require": { "doctrine/inflector": "^1.1", "dragonmantank/cron-expression": "^2.0", "egulias/email-validator": "^2.1.10", - "erusev/parsedown": "^1.7", "ext-json": "*", "ext-mbstring": "*", "ext-openssl": "*", + "league/commonmark": "^1.1", + "league/commonmark-ext-table": "^2.1", "league/flysystem": "^1.0.8", "monolog/monolog": "^1.12|^2.0", "nesbot/carbon": "^2.0", @@ -1370,14 +1643,13 @@ "filp/whoops": "^2.4", "guzzlehttp/guzzle": "^6.3", "league/flysystem-cached-adapter": "^1.0", - "mockery/mockery": "^1.2.3", + "mockery/mockery": "^1.3.1", "moontoast/math": "^1.1", "orchestra/testbench-core": "^4.0", "pda/pheanstalk": "^4.0", - "phpunit/phpunit": "^8.3", + "phpunit/phpunit": "^7.5.15|^8.4|^9.0", "predis/predis": "^1.1.1", - "symfony/cache": "^4.3", - "true/punycode": "^2.1" + "symfony/cache": "^4.3.4" }, "suggest": { "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.0).", @@ -1395,6 +1667,7 @@ "league/flysystem-cached-adapter": "Required to use the Flysystem cache (^1.0).", "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (^1.0).", "moontoast/math": "Required to use ordered UUIDs (^1.1).", + "nyholm/psr7": "Required to use PSR-7 bridging features (^1.2).", "pda/pheanstalk": "Required to use the beanstalk queue driver (^4.0).", "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^4.0).", @@ -1433,7 +1706,7 @@ "framework", "laravel" ], - "time": "2019-12-19T18:16:22+00:00" + "time": "2020-01-21T15:10:03+00:00" }, { "name": "laravel/socialite", @@ -1500,17 +1773,153 @@ "time": "2019-11-26T17:39:15+00:00" }, { - "name": "league/flysystem", - "version": "1.0.61", + "name": "league/commonmark", + "version": "1.2.2", "source": { "type": "git", - "url": "https://github.com/thephpleague/flysystem.git", - "reference": "4fb13c01784a6c9f165a351e996871488ca2d8c9" + "url": "https://github.com/thephpleague/commonmark.git", + "reference": "34cf4ddb3892c715ae785c880e6691d839cff88d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/4fb13c01784a6c9f165a351e996871488ca2d8c9", - "reference": "4fb13c01784a6c9f165a351e996871488ca2d8c9", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/34cf4ddb3892c715ae785c880e6691d839cff88d", + "reference": "34cf4ddb3892c715ae785c880e6691d839cff88d", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1" + }, + "replace": { + "colinodell/commonmark-php": "*" + }, + "require-dev": { + "cebe/markdown": "~1.0", + "commonmark/commonmark.js": "0.29.1", + "erusev/parsedown": "~1.0", + "ext-json": "*", + "michelf/php-markdown": "~1.4", + "mikehaertl/php-shellcommand": "^1.4", + "phpstan/phpstan-shim": "^0.11.5", + "phpunit/phpunit": "^7.5", + "scrutinizer/ocular": "^1.5", + "symfony/finder": "^4.2" + }, + "suggest": { + "league/commonmark-extras": "Library of useful extensions including smart punctuation" + }, + "bin": [ + "bin/commonmark" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "League\\CommonMark\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "PHP Markdown parser based on the CommonMark spec", + "homepage": "https://commonmark.thephpleague.com", + "keywords": [ + "commonmark", + "markdown", + "parser" + ], + "time": "2020-01-16T01:18:13+00:00" + }, + { + "name": "league/commonmark-ext-table", + "version": "v2.1.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/commonmark-ext-table.git", + "reference": "3228888ea69636e855efcf6636ff8e6316933fe7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/commonmark-ext-table/zipball/3228888ea69636e855efcf6636ff8e6316933fe7", + "reference": "3228888ea69636e855efcf6636ff8e6316933fe7", + "shasum": "" + }, + "require": { + "league/commonmark": "~0.19.3|^1.0", + "php": "^7.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.14", + "phpstan/phpstan": "~0.11", + "phpunit/phpunit": "^7.0|^8.0", + "symfony/var-dumper": "^4.0", + "vimeo/psalm": "^3.0" + }, + "type": "commonmark-extension", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-4": { + "League\\CommonMark\\Ext\\Table\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Martin Hasoň", + "email": "martin.hason@gmail.com" + }, + { + "name": "Webuni s.r.o.", + "homepage": "https://www.webuni.cz" + }, + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com" + } + ], + "description": "Table extension for league/commonmark", + "homepage": "https://github.com/thephpleague/commonmark-ext-table", + "keywords": [ + "commonmark", + "extension", + "markdown", + "table" + ], + "time": "2019-09-26T13:28:33+00:00" + }, + { + "name": "league/flysystem", + "version": "1.0.63", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "8132daec326565036bc8e8d1876f77ec183a7bd6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/8132daec326565036bc8e8d1876f77ec183a7bd6", + "reference": "8132daec326565036bc8e8d1876f77ec183a7bd6", "shasum": "" }, "require": { @@ -1581,7 +1990,7 @@ "sftp", "storage" ], - "time": "2019-12-08T21:46:50+00:00" + "time": "2020-01-04T16:30:31+00:00" }, { "name": "league/flysystem-aws-s3-v3", @@ -1776,23 +2185,25 @@ }, { "name": "mtdowling/jmespath.php", - "version": "2.4.0", + "version": "2.5.0", "source": { "type": "git", "url": "https://github.com/jmespath/jmespath.php.git", - "reference": "adcc9531682cf87dfda21e1fd5d0e7a41d292fac" + "reference": "52168cb9472de06979613d365c7f1ab8798be895" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/adcc9531682cf87dfda21e1fd5d0e7a41d292fac", - "reference": "adcc9531682cf87dfda21e1fd5d0e7a41d292fac", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/52168cb9472de06979613d365c7f1ab8798be895", + "reference": "52168cb9472de06979613d365c7f1ab8798be895", "shasum": "" }, "require": { - "php": ">=5.4.0" + "php": ">=5.4.0", + "symfony/polyfill-mbstring": "^1.4" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "composer/xdebug-handler": "^1.2", + "phpunit/phpunit": "^4.8.36|^7.5.15" }, "bin": [ "bin/jp.php" @@ -1800,7 +2211,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "2.5-dev" } }, "autoload": { @@ -1827,20 +2238,20 @@ "json", "jsonpath" ], - "time": "2016-12-03T22:08:25+00:00" + "time": "2019-12-30T18:03:34+00:00" }, { "name": "nesbot/carbon", - "version": "2.28.0", + "version": "2.29.1", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "e2bcbcd43e67ee6101d321d5de916251d2870ca8" + "reference": "e509be5bf2d703390e69e14496d9a1168452b0a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/e2bcbcd43e67ee6101d321d5de916251d2870ca8", - "reference": "e2bcbcd43e67ee6101d321d5de916251d2870ca8", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/e509be5bf2d703390e69e14496d9a1168452b0a2", + "reference": "e509be5bf2d703390e69e14496d9a1168452b0a2", "shasum": "" }, "require": { @@ -1851,7 +2262,7 @@ "require-dev": { "friendsofphp/php-cs-fixer": "^2.14 || ^3.0", "kylekatarnls/multi-tester": "^1.1", - "phpmd/phpmd": "dev-php-7.1-compatibility", + "phpmd/phpmd": "^2.8", "phpstan/phpstan": "^0.11", "phpunit/phpunit": "^7.5 || ^8.0", "squizlabs/php_codesniffer": "^3.4" @@ -1897,7 +2308,71 @@ "datetime", "time" ], - "time": "2019-12-16T16:30:25+00:00" + "time": "2020-01-21T09:36:43+00:00" + }, + { + "name": "nunomaduro/collision", + "version": "v3.0.1", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/collision.git", + "reference": "af42d339fe2742295a54f6fdd42aaa6f8c4aca68" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/af42d339fe2742295a54f6fdd42aaa6f8c4aca68", + "reference": "af42d339fe2742295a54f6fdd42aaa6f8c4aca68", + "shasum": "" + }, + "require": { + "filp/whoops": "^2.1.4", + "jakub-onderka/php-console-highlighter": "0.3.*|0.4.*", + "php": "^7.1", + "symfony/console": "~2.8|~3.3|~4.0" + }, + "require-dev": { + "laravel/framework": "5.8.*", + "nunomaduro/larastan": "^0.3.0", + "phpstan/phpstan": "^0.11", + "phpunit/phpunit": "~8.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "NunoMaduro\\Collision\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Cli error handling for console/command-line PHP applications.", + "keywords": [ + "artisan", + "cli", + "command-line", + "console", + "error", + "handling", + "laravel", + "laravel-zero", + "php", + "symfony" + ], + "time": "2019-03-07T21:35:13+00:00" }, { "name": "onelogin/php-saml", @@ -2641,6 +3116,74 @@ ], "time": "2019-02-22T07:42:52+00:00" }, + { + "name": "scrivo/highlight.php", + "version": "v9.17.1.0", + "source": { + "type": "git", + "url": "https://github.com/scrivo/highlight.php.git", + "reference": "5451a9ad6d638559cf2a092880f935c39776134e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/scrivo/highlight.php/zipball/5451a9ad6d638559cf2a092880f935c39776134e", + "reference": "5451a9ad6d638559cf2a092880f935c39776134e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "php": ">=5.4" + }, + "require-dev": { + "phpunit/phpunit": "^4.8|^5.7", + "symfony/finder": "^3.4", + "symfony/var-dumper": "^3.4" + }, + "suggest": { + "ext-dom": "Needed to make use of the features in the utilities namespace" + }, + "type": "library", + "autoload": { + "psr-0": { + "Highlight\\": "", + "HighlightUtilities\\": "" + }, + "files": [ + "HighlightUtilities/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Geert Bergman", + "homepage": "http://www.scrivo.org/", + "role": "Project Author" + }, + { + "name": "Vladimir Jimenez", + "homepage": "https://allejo.io", + "role": "Maintainer" + }, + { + "name": "Martin Folkers", + "homepage": "https://twobrain.io", + "role": "Contributor" + } + ], + "description": "Server side syntax highlighter that supports 185 languages. It's a PHP port of highlight.js", + "keywords": [ + "code", + "highlight", + "highlight.js", + "highlight.php", + "syntax" + ], + "time": "2019-12-13T21:54:06+00:00" + }, { "name": "socialiteproviders/discord", "version": "v2.0.2", @@ -2984,16 +3527,16 @@ }, { "name": "symfony/console", - "version": "v4.4.2", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "82437719dab1e6bdd28726af14cb345c2ec816d0" + "reference": "e9ee09d087e2c88eaf6e5fc0f5c574f64d100e4f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/82437719dab1e6bdd28726af14cb345c2ec816d0", - "reference": "82437719dab1e6bdd28726af14cb345c2ec816d0", + "url": "https://api.github.com/repos/symfony/console/zipball/e9ee09d087e2c88eaf6e5fc0f5c574f64d100e4f", + "reference": "e9ee09d087e2c88eaf6e5fc0f5c574f64d100e4f", "shasum": "" }, "require": { @@ -3056,20 +3599,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2019-12-17T10:32:23+00:00" + "time": "2020-01-10T21:54:01+00:00" }, { "name": "symfony/css-selector", - "version": "v4.4.2", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "64acec7e0d67125e9f4656c68d4a38a42ab5a0b7" + "reference": "a167b1860995b926d279f9bb538f873e3bfa3465" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/64acec7e0d67125e9f4656c68d4a38a42ab5a0b7", - "reference": "64acec7e0d67125e9f4656c68d4a38a42ab5a0b7", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/a167b1860995b926d279f9bb538f873e3bfa3465", + "reference": "a167b1860995b926d279f9bb538f873e3bfa3465", "shasum": "" }, "require": { @@ -3109,20 +3652,20 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2019-10-12T00:35:04+00:00" + "time": "2020-01-04T13:00:46+00:00" }, { "name": "symfony/debug", - "version": "v4.4.2", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "5c4c1db977dc70bb3250e1308d3e8c6341aa38f5" + "reference": "89c3fd5c299b940333bc6fe9f1b8db1b0912c759" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/5c4c1db977dc70bb3250e1308d3e8c6341aa38f5", - "reference": "5c4c1db977dc70bb3250e1308d3e8c6341aa38f5", + "url": "https://api.github.com/repos/symfony/debug/zipball/89c3fd5c299b940333bc6fe9f1b8db1b0912c759", + "reference": "89c3fd5c299b940333bc6fe9f1b8db1b0912c759", "shasum": "" }, "require": { @@ -3165,20 +3708,20 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2019-12-16T14:46:54+00:00" + "time": "2020-01-08T17:29:02+00:00" }, { "name": "symfony/error-handler", - "version": "v4.4.2", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "6d7d7712a6ff5215ec26215672293b154f1db8c1" + "reference": "a59789092e40ad08465dc2cdc55651be503d0d5a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/6d7d7712a6ff5215ec26215672293b154f1db8c1", - "reference": "6d7d7712a6ff5215ec26215672293b154f1db8c1", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/a59789092e40ad08465dc2cdc55651be503d0d5a", + "reference": "a59789092e40ad08465dc2cdc55651be503d0d5a", "shasum": "" }, "require": { @@ -3221,20 +3764,20 @@ ], "description": "Symfony ErrorHandler Component", "homepage": "https://symfony.com", - "time": "2019-12-16T14:46:54+00:00" + "time": "2020-01-08T17:29:02+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v4.4.2", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "b3c3068a72623287550fe20b84a2b01dcba2686f" + "reference": "9e3de195e5bc301704dd6915df55892f6dfc208b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b3c3068a72623287550fe20b84a2b01dcba2686f", - "reference": "b3c3068a72623287550fe20b84a2b01dcba2686f", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/9e3de195e5bc301704dd6915df55892f6dfc208b", + "reference": "9e3de195e5bc301704dd6915df55892f6dfc208b", "shasum": "" }, "require": { @@ -3291,7 +3834,7 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2019-11-28T13:33:56+00:00" + "time": "2020-01-10T21:54:01+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -3353,16 +3896,16 @@ }, { "name": "symfony/finder", - "version": "v4.4.2", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "ce8743441da64c41e2a667b8eb66070444ed911e" + "reference": "3a50be43515590faf812fbd7708200aabc327ec3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/ce8743441da64c41e2a667b8eb66070444ed911e", - "reference": "ce8743441da64c41e2a667b8eb66070444ed911e", + "url": "https://api.github.com/repos/symfony/finder/zipball/3a50be43515590faf812fbd7708200aabc327ec3", + "reference": "3a50be43515590faf812fbd7708200aabc327ec3", "shasum": "" }, "require": { @@ -3398,20 +3941,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2019-11-17T21:56:56+00:00" + "time": "2020-01-04T13:00:46+00:00" }, { "name": "symfony/http-foundation", - "version": "v4.4.2", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "fcae1cff5b57b2a9c3aabefeb1527678705ddb62" + "reference": "c33998709f3fe9b8e27e0277535b07fbf6fde37a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/fcae1cff5b57b2a9c3aabefeb1527678705ddb62", - "reference": "fcae1cff5b57b2a9c3aabefeb1527678705ddb62", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/c33998709f3fe9b8e27e0277535b07fbf6fde37a", + "reference": "c33998709f3fe9b8e27e0277535b07fbf6fde37a", "shasum": "" }, "require": { @@ -3453,20 +3996,20 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2019-12-19T15:57:49+00:00" + "time": "2020-01-04T13:00:46+00:00" }, { "name": "symfony/http-kernel", - "version": "v4.4.2", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "fe310d2e95cd4c356836c8ecb0895a46d97fede2" + "reference": "16f2aa3c54b08483fba5375938f60b1ff83b6bd2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/fe310d2e95cd4c356836c8ecb0895a46d97fede2", - "reference": "fe310d2e95cd4c356836c8ecb0895a46d97fede2", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/16f2aa3c54b08483fba5375938f60b1ff83b6bd2", + "reference": "16f2aa3c54b08483fba5375938f60b1ff83b6bd2", "shasum": "" }, "require": { @@ -3543,20 +4086,20 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", - "time": "2019-12-19T16:23:40+00:00" + "time": "2020-01-21T13:23:17+00:00" }, { "name": "symfony/mime", - "version": "v4.4.2", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "010cc488e56cafe5f7494dea70aea93100c234df" + "reference": "225034620ecd4b34fd826e9983d85e2b7a359094" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/010cc488e56cafe5f7494dea70aea93100c234df", - "reference": "010cc488e56cafe5f7494dea70aea93100c234df", + "url": "https://api.github.com/repos/symfony/mime/zipball/225034620ecd4b34fd826e9983d85e2b7a359094", + "reference": "225034620ecd4b34fd826e9983d85e2b7a359094", "shasum": "" }, "require": { @@ -3605,7 +4148,7 @@ "mime", "mime-type" ], - "time": "2019-11-30T08:27:26+00:00" + "time": "2020-01-04T13:00:46+00:00" }, { "name": "symfony/polyfill-ctype", @@ -3960,16 +4503,16 @@ }, { "name": "symfony/process", - "version": "v4.4.2", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "b84501ad50adb72a94fb460a5b5c91f693e99c9b" + "reference": "f5697ab4cb14a5deed7473819e63141bf5352c36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/b84501ad50adb72a94fb460a5b5c91f693e99c9b", - "reference": "b84501ad50adb72a94fb460a5b5c91f693e99c9b", + "url": "https://api.github.com/repos/symfony/process/zipball/f5697ab4cb14a5deed7473819e63141bf5352c36", + "reference": "f5697ab4cb14a5deed7473819e63141bf5352c36", "shasum": "" }, "require": { @@ -4005,20 +4548,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2019-12-06T10:06:46+00:00" + "time": "2020-01-09T09:50:08+00:00" }, { "name": "symfony/routing", - "version": "v4.4.2", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "628bcafae1b2043969378dcfbf9c196539a38722" + "reference": "7bf4e38573728e317b926ca4482ad30470d0e86a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/628bcafae1b2043969378dcfbf9c196539a38722", - "reference": "628bcafae1b2043969378dcfbf9c196539a38722", + "url": "https://api.github.com/repos/symfony/routing/zipball/7bf4e38573728e317b926ca4482ad30470d0e86a", + "reference": "7bf4e38573728e317b926ca4482ad30470d0e86a", "shasum": "" }, "require": { @@ -4081,7 +4624,7 @@ "uri", "url" ], - "time": "2019-12-12T12:53:52+00:00" + "time": "2020-01-08T17:29:02+00:00" }, { "name": "symfony/service-contracts", @@ -4143,16 +4686,16 @@ }, { "name": "symfony/translation", - "version": "v4.4.2", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "f7669f48a9633bf8139bc026c755e894b7206677" + "reference": "f5d2ac46930238b30a9c2f1b17c905f3697d808c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/f7669f48a9633bf8139bc026c755e894b7206677", - "reference": "f7669f48a9633bf8139bc026c755e894b7206677", + "url": "https://api.github.com/repos/symfony/translation/zipball/f5d2ac46930238b30a9c2f1b17c905f3697d808c", + "reference": "f5d2ac46930238b30a9c2f1b17c905f3697d808c", "shasum": "" }, "require": { @@ -4215,7 +4758,7 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2019-12-12T12:53:52+00:00" + "time": "2020-01-15T13:29:06+00:00" }, { "name": "symfony/translation-contracts", @@ -4276,16 +4819,16 @@ }, { "name": "symfony/var-dumper", - "version": "v4.4.2", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "be330f919bdb395d1e0c3f2bfb8948512d6bdd99" + "reference": "7cfa470bc3b1887a7b2a47c0a702a84ad614fa92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/be330f919bdb395d1e0c3f2bfb8948512d6bdd99", - "reference": "be330f919bdb395d1e0c3f2bfb8948512d6bdd99", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/7cfa470bc3b1887a7b2a47c0a702a84ad614fa92", + "reference": "7cfa470bc3b1887a7b2a47c0a702a84ad614fa92", "shasum": "" }, "require": { @@ -4348,7 +4891,7 @@ "debug", "dump" ], - "time": "2019-12-18T13:41:29+00:00" + "time": "2020-01-04T13:00:46+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -4648,16 +5191,16 @@ }, { "name": "composer/ca-bundle", - "version": "1.2.5", + "version": "1.2.6", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "62e8fc2dc550e5d6d8c9360c7721662670f58149" + "reference": "47fe531de31fca4a1b997f87308e7d7804348f7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/62e8fc2dc550e5d6d8c9360c7721662670f58149", - "reference": "62e8fc2dc550e5d6d8c9360c7721662670f58149", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/47fe531de31fca4a1b997f87308e7d7804348f7e", + "reference": "47fe531de31fca4a1b997f87308e7d7804348f7e", "shasum": "" }, "require": { @@ -4700,20 +5243,20 @@ "ssl", "tls" ], - "time": "2019-12-11T14:44:42+00:00" + "time": "2020-01-13T10:02:55+00:00" }, { "name": "composer/composer", - "version": "1.9.1", + "version": "1.9.2", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "bb01f2180df87ce7992b8331a68904f80439dd2f" + "reference": "7a04aa0201ddaa0b3cf64d41022bd8cdcd7fafeb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/bb01f2180df87ce7992b8331a68904f80439dd2f", - "reference": "bb01f2180df87ce7992b8331a68904f80439dd2f", + "url": "https://api.github.com/repos/composer/composer/zipball/7a04aa0201ddaa0b3cf64d41022bd8cdcd7fafeb", + "reference": "7a04aa0201ddaa0b3cf64d41022bd8cdcd7fafeb", "shasum": "" }, "require": { @@ -4780,28 +5323,27 @@ "dependency", "package" ], - "time": "2019-11-01T16:20:17+00:00" + "time": "2020-01-14T15:30:32+00:00" }, { "name": "composer/semver", - "version": "1.5.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "46d9139568ccb8d9e7cdd4539cab7347568a5e2e" + "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/46d9139568ccb8d9e7cdd4539cab7347568a5e2e", - "reference": "46d9139568ccb8d9e7cdd4539cab7347568a5e2e", + "url": "https://api.github.com/repos/composer/semver/zipball/c6bea70230ef4dd483e6bbcab6005f682ed3a8de", + "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "^4.5 || ^5.0.5", - "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" + "phpunit/phpunit": "^4.5 || ^5.0.5" }, "type": "library", "extra": { @@ -4842,7 +5384,7 @@ "validation", "versioning" ], - "time": "2019-03-19T17:25:45+00:00" + "time": "2020-01-13T12:06:48+00:00" }, { "name": "composer/spdx-licenses", @@ -5004,236 +5546,6 @@ ], "time": "2019-10-21T16:45:58+00:00" }, - { - "name": "facade/flare-client-php", - "version": "1.3.1", - "source": { - "type": "git", - "url": "https://github.com/facade/flare-client-php.git", - "reference": "24444ea0e1556f0a4b5fc8e61802caf72ae9a408" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/facade/flare-client-php/zipball/24444ea0e1556f0a4b5fc8e61802caf72ae9a408", - "reference": "24444ea0e1556f0a4b5fc8e61802caf72ae9a408", - "shasum": "" - }, - "require": { - "facade/ignition-contracts": "~1.0", - "illuminate/pipeline": "~5.5|~5.6|~5.7|~5.8|^6.0", - "php": "^7.1", - "symfony/http-foundation": "~3.3|~4.1", - "symfony/var-dumper": "^3.4|^4.0|^5.0" - }, - "require-dev": { - "larapack/dd": "^1.1", - "phpunit/phpunit": "^7.5.16", - "spatie/phpunit-snapshot-assertions": "^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-4": { - "Facade\\FlareClient\\": "src" - }, - "files": [ - "src/helpers.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Send PHP errors to Flare", - "homepage": "https://github.com/facade/flare-client-php", - "keywords": [ - "exception", - "facade", - "flare", - "reporting" - ], - "time": "2019-12-15T18:28:38+00:00" - }, - { - "name": "facade/ignition", - "version": "1.13.0", - "source": { - "type": "git", - "url": "https://github.com/facade/ignition.git", - "reference": "1d2103aefecc9c4e6975bcc77fc5eceb330adb33" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/facade/ignition/zipball/1d2103aefecc9c4e6975bcc77fc5eceb330adb33", - "reference": "1d2103aefecc9c4e6975bcc77fc5eceb330adb33", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-mbstring": "*", - "facade/flare-client-php": "^1.3", - "facade/ignition-contracts": "^1.0", - "filp/whoops": "^2.4", - "illuminate/support": "~5.5.0 || ~5.6.0 || ~5.7.0 || ~5.8.0 || ^6.0", - "monolog/monolog": "^1.12 || ^2.0", - "php": "^7.1", - "scrivo/highlight.php": "^9.15", - "symfony/console": "^3.4 || ^4.0", - "symfony/var-dumper": "^3.4 || ^4.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.14", - "mockery/mockery": "^1.2", - "orchestra/testbench": "^3.5 || ^3.6 || ^3.7 || ^3.8 || ^4.0" - }, - "suggest": { - "laravel/telescope": "^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - }, - "laravel": { - "providers": [ - "Facade\\Ignition\\IgnitionServiceProvider" - ], - "aliases": { - "Flare": "Facade\\Ignition\\Facades\\Flare" - } - } - }, - "autoload": { - "psr-4": { - "Facade\\Ignition\\": "src" - }, - "files": [ - "src/helpers.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A beautiful error page for Laravel applications.", - "homepage": "https://github.com/facade/ignition", - "keywords": [ - "error", - "flare", - "laravel", - "page" - ], - "time": "2019-11-27T11:17:18+00:00" - }, - { - "name": "facade/ignition-contracts", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/facade/ignition-contracts.git", - "reference": "f445db0fb86f48e205787b2592840dd9c80ded28" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/facade/ignition-contracts/zipball/f445db0fb86f48e205787b2592840dd9c80ded28", - "reference": "f445db0fb86f48e205787b2592840dd9c80ded28", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "Facade\\IgnitionContracts\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Freek Van der Herten", - "email": "freek@spatie.be", - "homepage": "https://flareapp.io", - "role": "Developer" - } - ], - "description": "Solution contracts for Ignition", - "homepage": "https://github.com/facade/ignition-contracts", - "keywords": [ - "contracts", - "flare", - "ignition" - ], - "time": "2019-08-30T14:06:08+00:00" - }, - { - "name": "filp/whoops", - "version": "2.6.0", - "source": { - "type": "git", - "url": "https://github.com/filp/whoops.git", - "reference": "ecbc8f3ed2cafca3cfca3d5febaae5a9d2899508" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/ecbc8f3ed2cafca3cfca3d5febaae5a9d2899508", - "reference": "ecbc8f3ed2cafca3cfca3d5febaae5a9d2899508", - "shasum": "" - }, - "require": { - "php": "^5.5.9 || ^7.0", - "psr/log": "^1.0.1" - }, - "require-dev": { - "mockery/mockery": "^0.9 || ^1.0", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0", - "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0 || ^5.0" - }, - "suggest": { - "symfony/var-dumper": "Pretty print complex values better with var-dumper available", - "whoops/soap": "Formats errors as SOAP responses" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.5-dev" - } - }, - "autoload": { - "psr-4": { - "Whoops\\": "src/Whoops/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Filipe Dobreira", - "homepage": "https://github.com/filp", - "role": "Developer" - } - ], - "description": "php error handling for cool kids", - "homepage": "https://filp.github.io/whoops/", - "keywords": [ - "error", - "exception", - "handling", - "library", - "throwable", - "whoops" - ], - "time": "2019-12-25T10:00:00+00:00" - }, { "name": "fzaninotto/faker", "version": "v1.9.1", @@ -5332,94 +5644,6 @@ ], "time": "2016-01-20T08:20:44+00:00" }, - { - "name": "jakub-onderka/php-console-color", - "version": "v0.2", - "source": { - "type": "git", - "url": "https://github.com/JakubOnderka/PHP-Console-Color.git", - "reference": "d5deaecff52a0d61ccb613bb3804088da0307191" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/d5deaecff52a0d61ccb613bb3804088da0307191", - "reference": "d5deaecff52a0d61ccb613bb3804088da0307191", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "jakub-onderka/php-code-style": "1.0", - "jakub-onderka/php-parallel-lint": "1.0", - "jakub-onderka/php-var-dump-check": "0.*", - "phpunit/phpunit": "~4.3", - "squizlabs/php_codesniffer": "1.*" - }, - "type": "library", - "autoload": { - "psr-4": { - "JakubOnderka\\PhpConsoleColor\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-2-Clause" - ], - "authors": [ - { - "name": "Jakub Onderka", - "email": "jakub.onderka@gmail.com" - } - ], - "time": "2018-09-29T17:23:10+00:00" - }, - { - "name": "jakub-onderka/php-console-highlighter", - "version": "v0.4", - "source": { - "type": "git", - "url": "https://github.com/JakubOnderka/PHP-Console-Highlighter.git", - "reference": "9f7a229a69d52506914b4bc61bfdb199d90c5547" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Highlighter/zipball/9f7a229a69d52506914b4bc61bfdb199d90c5547", - "reference": "9f7a229a69d52506914b4bc61bfdb199d90c5547", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "jakub-onderka/php-console-color": "~0.2", - "php": ">=5.4.0" - }, - "require-dev": { - "jakub-onderka/php-code-style": "~1.0", - "jakub-onderka/php-parallel-lint": "~1.0", - "jakub-onderka/php-var-dump-check": "~0.1", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~1.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "JakubOnderka\\PhpConsoleHighlighter\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jakub Onderka", - "email": "acci@acci.cz", - "homepage": "http://www.acci.cz/" - } - ], - "description": "Highlight PHP code in terminal", - "time": "2018-09-29T18:48:56+00:00" - }, { "name": "justinrainbow/json-schema", "version": "5.2.9", @@ -5675,16 +5899,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.9.4", + "version": "1.9.5", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "579bb7356d91f9456ccd505f24ca8b667966a0a7" + "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/579bb7356d91f9456ccd505f24ca8b667966a0a7", - "reference": "579bb7356d91f9456ccd505f24ca8b667966a0a7", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/b2c28789e80a97badd14145fda39b545d83ca3ef", + "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef", "shasum": "" }, "require": { @@ -5719,71 +5943,7 @@ "object", "object graph" ], - "time": "2019-12-15T19:12:40+00:00" - }, - { - "name": "nunomaduro/collision", - "version": "v3.0.1", - "source": { - "type": "git", - "url": "https://github.com/nunomaduro/collision.git", - "reference": "af42d339fe2742295a54f6fdd42aaa6f8c4aca68" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/af42d339fe2742295a54f6fdd42aaa6f8c4aca68", - "reference": "af42d339fe2742295a54f6fdd42aaa6f8c4aca68", - "shasum": "" - }, - "require": { - "filp/whoops": "^2.1.4", - "jakub-onderka/php-console-highlighter": "0.3.*|0.4.*", - "php": "^7.1", - "symfony/console": "~2.8|~3.3|~4.0" - }, - "require-dev": { - "laravel/framework": "5.8.*", - "nunomaduro/larastan": "^0.3.0", - "phpstan/phpstan": "^0.11", - "phpunit/phpunit": "~8.0" - }, - "type": "library", - "extra": { - "laravel": { - "providers": [ - "NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "NunoMaduro\\Collision\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nuno Maduro", - "email": "enunomaduro@gmail.com" - } - ], - "description": "Cli error handling for console/command-line PHP applications.", - "keywords": [ - "artisan", - "cli", - "command-line", - "console", - "error", - "handling", - "laravel", - "laravel-zero", - "php", - "symfony" - ], - "time": "2019-03-07T21:35:13+00:00" + "time": "2020-01-17T21:11:47+00:00" }, { "name": "phar-io/manifest", @@ -5941,16 +6101,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.3.3", + "version": "4.3.4", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "2ecaa9fef01634c83bfa8dc1fe35fb5cef223a62" + "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/2ecaa9fef01634c83bfa8dc1fe35fb5cef223a62", - "reference": "2ecaa9fef01634c83bfa8dc1fe35fb5cef223a62", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/da3fd972d6bafd628114f7e7e036f45944b62e9c", + "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c", "shasum": "" }, "require": { @@ -5962,6 +6122,7 @@ "require-dev": { "doctrine/instantiator": "^1.0.5", "mockery/mockery": "^1.0", + "phpdocumentor/type-resolver": "0.4.*", "phpunit/phpunit": "^6.4" }, "type": "library", @@ -5988,7 +6149,7 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2019-12-20T13:40:23+00:00" + "time": "2019-12-28T18:55:12+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -6088,24 +6249,24 @@ }, { "name": "phpspec/prophecy", - "version": "1.10.1", + "version": "v1.10.2", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "cbe1df668b3fe136bcc909126a0f529a78d4cbbc" + "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/cbe1df668b3fe136bcc909126a0f529a78d4cbbc", - "reference": "cbe1df668b3fe136bcc909126a0f529a78d4cbbc", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/b4400efc9d206e83138e2bb97ed7f5b14b831cd9", + "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", - "sebastian/comparator": "^1.2.3|^2.0|^3.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0" + "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0" }, "require-dev": { "phpspec/phpspec": "^2.5 || ^3.2", @@ -6147,7 +6308,7 @@ "spy", "stub" ], - "time": "2019-12-22T21:05:45+00:00" + "time": "2020-01-20T15:57:02+00:00" }, { "name": "phpunit/php-code-coverage", @@ -6403,16 +6564,16 @@ }, { "name": "phpunit/phpunit", - "version": "8.5.1", + "version": "8.5.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "7870c78da3c5e4883eaef36ae47853ebb3cb86f2" + "reference": "018b6ac3c8ab20916db85fa91bf6465acb64d1e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7870c78da3c5e4883eaef36ae47853ebb3cb86f2", - "reference": "7870c78da3c5e4883eaef36ae47853ebb3cb86f2", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/018b6ac3c8ab20916db85fa91bf6465acb64d1e0", + "reference": "018b6ac3c8ab20916db85fa91bf6465acb64d1e0", "shasum": "" }, "require": { @@ -6482,75 +6643,7 @@ "testing", "xunit" ], - "time": "2019-12-25T14:49:39+00:00" - }, - { - "name": "scrivo/highlight.php", - "version": "v9.17.1.0", - "source": { - "type": "git", - "url": "https://github.com/scrivo/highlight.php.git", - "reference": "5451a9ad6d638559cf2a092880f935c39776134e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/scrivo/highlight.php/zipball/5451a9ad6d638559cf2a092880f935c39776134e", - "reference": "5451a9ad6d638559cf2a092880f935c39776134e", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-mbstring": "*", - "php": ">=5.4" - }, - "require-dev": { - "phpunit/phpunit": "^4.8|^5.7", - "symfony/finder": "^3.4", - "symfony/var-dumper": "^3.4" - }, - "suggest": { - "ext-dom": "Needed to make use of the features in the utilities namespace" - }, - "type": "library", - "autoload": { - "psr-0": { - "Highlight\\": "", - "HighlightUtilities\\": "" - }, - "files": [ - "HighlightUtilities/functions.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Geert Bergman", - "homepage": "http://www.scrivo.org/", - "role": "Project Author" - }, - { - "name": "Vladimir Jimenez", - "homepage": "https://allejo.io", - "role": "Maintainer" - }, - { - "name": "Martin Folkers", - "homepage": "https://twobrain.io", - "role": "Contributor" - } - ], - "description": "Server side syntax highlighter that supports 185 languages. It's a PHP port of highlight.js", - "keywords": [ - "code", - "highlight", - "highlight.js", - "highlight.php", - "syntax" - ], - "time": "2019-12-13T21:54:06+00:00" + "time": "2020-01-08T08:49:49+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -6839,23 +6932,27 @@ }, { "name": "sebastian/finder-facade", - "version": "1.2.2", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/finder-facade.git", - "reference": "4a3174709c2dc565fe5fb26fcf827f6a1fc7b09f" + "reference": "167c45d131f7fc3d159f56f191a0a22228765e16" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/finder-facade/zipball/4a3174709c2dc565fe5fb26fcf827f6a1fc7b09f", - "reference": "4a3174709c2dc565fe5fb26fcf827f6a1fc7b09f", + "url": "https://api.github.com/repos/sebastianbergmann/finder-facade/zipball/167c45d131f7fc3d159f56f191a0a22228765e16", + "reference": "167c45d131f7fc3d159f56f191a0a22228765e16", "shasum": "" }, "require": { - "symfony/finder": "~2.3|~3.0|~4.0", - "theseer/fdomdocument": "~1.3" + "php": "^7.1", + "symfony/finder": "^2.3|^3.0|^4.0|^5.0", + "theseer/fdomdocument": "^1.6" }, "type": "library", + "extra": { + "branch-alias": [] + }, "autoload": { "classmap": [ "src/" @@ -6874,7 +6971,7 @@ ], "description": "FinderFacade is a convenience wrapper for Symfony's Finder component.", "homepage": "https://github.com/sebastianbergmann/finder-facade", - "time": "2017-11-18T17:31:49+00:00" + "time": "2020-01-16T08:08:45+00:00" }, { "name": "sebastian/global-state", @@ -7257,16 +7354,16 @@ }, { "name": "seld/phar-utils", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/Seldaek/phar-utils.git", - "reference": "7009b5139491975ef6486545a39f3e6dad5ac30a" + "reference": "84715761c35808076b00908a20317a3a8a67d17e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/7009b5139491975ef6486545a39f3e6dad5ac30a", - "reference": "7009b5139491975ef6486545a39f3e6dad5ac30a", + "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/84715761c35808076b00908a20317a3a8a67d17e", + "reference": "84715761c35808076b00908a20317a3a8a67d17e", "shasum": "" }, "require": { @@ -7297,7 +7394,7 @@ "keywords": [ "phra" ], - "time": "2015-10-13T18:44:15+00:00" + "time": "2020-01-13T10:41:09+00:00" }, { "name": "squizlabs/php_codesniffer", @@ -7352,16 +7449,16 @@ }, { "name": "symfony/dom-crawler", - "version": "v4.4.2", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "36bbcab9369fc2f583220890efd43bf262d563fd" + "reference": "b66fe8ccc850ea11c4cd31677706c1219768bea1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/36bbcab9369fc2f583220890efd43bf262d563fd", - "reference": "36bbcab9369fc2f583220890efd43bf262d563fd", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/b66fe8ccc850ea11c4cd31677706c1219768bea1", + "reference": "b66fe8ccc850ea11c4cd31677706c1219768bea1", "shasum": "" }, "require": { @@ -7409,20 +7506,20 @@ ], "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", - "time": "2019-10-29T11:38:30+00:00" + "time": "2020-01-04T13:00:46+00:00" }, { "name": "symfony/filesystem", - "version": "v4.4.2", + "version": "v4.4.3", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "40c2606131d56eff6f193b6e2ceb92414653b591" + "reference": "266c9540b475f26122b61ef8b23dd9198f5d1cfd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/40c2606131d56eff6f193b6e2ceb92414653b591", - "reference": "40c2606131d56eff6f193b6e2ceb92414653b591", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/266c9540b475f26122b61ef8b23dd9198f5d1cfd", + "reference": "266c9540b475f26122b61ef8b23dd9198f5d1cfd", "shasum": "" }, "require": { @@ -7459,7 +7556,7 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2019-11-26T23:16:41+00:00" + "time": "2020-01-21T08:20:44+00:00" }, { "name": "theseer/fdomdocument", From 92690d1ae92363467c6a49664a558320b8b5771b Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 26 Jan 2020 14:42:50 +0000 Subject: [PATCH 165/191] Moved socal auth routes to their own controller Also cleaned some phpdocs and extracted register actions to their own service. --- app/Auth/Access/RegistrationService.php | 73 +++++++ app/Auth/Access/SocialAuthService.php | 69 ++----- app/Http/Controllers/Auth/LoginController.php | 21 -- .../Controllers/Auth/RegisterController.php | 194 ++---------------- .../Controllers/Auth/SocialController.php | 139 +++++++++++++ routes/web.php | 8 +- 6 files changed, 257 insertions(+), 247 deletions(-) create mode 100644 app/Auth/Access/RegistrationService.php create mode 100644 app/Http/Controllers/Auth/SocialController.php diff --git a/app/Auth/Access/RegistrationService.php b/app/Auth/Access/RegistrationService.php new file mode 100644 index 000000000..7e8c7d5f5 --- /dev/null +++ b/app/Auth/Access/RegistrationService.php @@ -0,0 +1,73 @@ +userRepo = $userRepo; + $this->emailConfirmationService = $emailConfirmationService; + } + + + /** + * Check whether or not registrations are allowed in the app settings. + * @throws UserRegistrationException + */ + public function checkRegistrationAllowed() + { + if (!setting('registration-enabled') || config('auth.method') === 'ldap') { + throw new UserRegistrationException(trans('auth.registrations_disabled'), '/login'); + } + } + + /** + * The registrations flow for all users. + * @throws UserRegistrationException + */ + public function registerUser(array $userData, ?SocialAccount $socialAccount = null, bool $emailVerified = false) + { + $registrationRestrict = setting('registration-restrict'); + + if ($registrationRestrict) { + $restrictedEmailDomains = explode(',', str_replace(' ', '', $registrationRestrict)); + $userEmailDomain = $domain = mb_substr(mb_strrchr($userData['email'], "@"), 1); + if (!in_array($userEmailDomain, $restrictedEmailDomains)) { + throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), '/register'); + } + } + + $newUser = $this->userRepo->registerNew($userData, $emailVerified); + + if ($socialAccount) { + $newUser->socialAccounts()->save($socialAccount); + } + + if ($this->emailConfirmationService->confirmationRequired() && !$emailVerified) { + $newUser->save(); + $message = ''; + + try { + $this->emailConfirmationService->sendConfirmation($newUser); + } catch (Exception $e) { + $message = trans('auth.email_confirm_send_error'); + } + + throw new UserRegistrationException($message, '/register/confirm'); + } + + auth()->login($newUser); + } + +} \ No newline at end of file diff --git a/app/Auth/Access/SocialAuthService.php b/app/Auth/Access/SocialAuthService.php index bc5b7a4d5..cf836618a 100644 --- a/app/Auth/Access/SocialAuthService.php +++ b/app/Auth/Access/SocialAuthService.php @@ -7,7 +7,9 @@ use BookStack\Exceptions\SocialSignInAccountNotUsed; use BookStack\Exceptions\UserRegistrationException; use Illuminate\Support\Str; use Laravel\Socialite\Contracts\Factory as Socialite; +use Laravel\Socialite\Contracts\Provider; use Laravel\Socialite\Contracts\User as SocialUser; +use Symfony\Component\HttpFoundation\RedirectResponse; class SocialAuthService { @@ -20,9 +22,6 @@ class SocialAuthService /** * SocialAuthService constructor. - * @param \BookStack\Auth\UserRepo $userRepo - * @param Socialite $socialite - * @param SocialAccount $socialAccount */ public function __construct(UserRepo $userRepo, Socialite $socialite, SocialAccount $socialAccount) { @@ -34,11 +33,9 @@ class SocialAuthService /** * Start the social login path. - * @param string $socialDriver - * @return \Symfony\Component\HttpFoundation\RedirectResponse * @throws SocialDriverNotConfigured */ - public function startLogIn($socialDriver) + public function startLogIn(string $socialDriver): RedirectResponse { $driver = $this->validateDriver($socialDriver); return $this->getSocialDriver($driver)->redirect(); @@ -46,11 +43,9 @@ class SocialAuthService /** * Start the social registration process - * @param string $socialDriver - * @return \Symfony\Component\HttpFoundation\RedirectResponse * @throws SocialDriverNotConfigured */ - public function startRegister($socialDriver) + public function startRegister(string $socialDriver): RedirectResponse { $driver = $this->validateDriver($socialDriver); return $this->getSocialDriver($driver)->redirect(); @@ -58,12 +53,9 @@ class SocialAuthService /** * Handle the social registration process on callback. - * @param string $socialDriver - * @param SocialUser $socialUser - * @return SocialUser * @throws UserRegistrationException */ - public function handleRegistrationCallback(string $socialDriver, SocialUser $socialUser) + public function handleRegistrationCallback(string $socialDriver, SocialUser $socialUser): SocialUser { // Check social account has not already been used if ($this->socialAccount->where('driver_id', '=', $socialUser->getId())->exists()) { @@ -80,11 +72,9 @@ class SocialAuthService /** * Get the social user details via the social driver. - * @param string $socialDriver - * @return SocialUser * @throws SocialDriverNotConfigured */ - public function getSocialUser(string $socialDriver) + public function getSocialUser(string $socialDriver): SocialUser { $driver = $this->validateDriver($socialDriver); return $this->socialite->driver($driver)->user(); @@ -92,12 +82,9 @@ class SocialAuthService /** * Handle the login process on a oAuth callback. - * @param $socialDriver - * @param SocialUser $socialUser - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector * @throws SocialSignInAccountNotUsed */ - public function handleLoginCallback($socialDriver, SocialUser $socialUser) + public function handleLoginCallback(string $socialDriver, SocialUser $socialUser) { $socialId = $socialUser->getId(); @@ -146,18 +133,16 @@ class SocialAuthService /** * Ensure the social driver is correct and supported. - * - * @param $socialDriver - * @return string * @throws SocialDriverNotConfigured */ - private function validateDriver($socialDriver) + protected function validateDriver(string $socialDriver): string { $driver = trim(strtolower($socialDriver)); if (!in_array($driver, $this->validSocialDrivers)) { abort(404, trans('errors.social_driver_not_found')); } + if (!$this->checkDriverConfigured($driver)) { throw new SocialDriverNotConfigured(trans('errors.social_driver_not_configured', ['socialAccount' => Str::title($socialDriver)])); } @@ -167,10 +152,8 @@ class SocialAuthService /** * Check a social driver has been configured correctly. - * @param $driver - * @return bool */ - private function checkDriverConfigured($driver) + protected function checkDriverConfigured(string $driver): bool { $lowerName = strtolower($driver); $configPrefix = 'services.' . $lowerName . '.'; @@ -180,55 +163,48 @@ class SocialAuthService /** * Gets the names of the active social drivers. - * @return array */ - public function getActiveDrivers() + public function getActiveDrivers(): array { $activeDrivers = []; + foreach ($this->validSocialDrivers as $driverKey) { if ($this->checkDriverConfigured($driverKey)) { $activeDrivers[$driverKey] = $this->getDriverName($driverKey); } } + return $activeDrivers; } /** * Get the presentational name for a driver. - * @param $driver - * @return mixed */ - public function getDriverName($driver) + public function getDriverName(string $driver): string { return config('services.' . strtolower($driver) . '.name'); } /** * Check if the current config for the given driver allows auto-registration. - * @param string $driver - * @return bool */ - public function driverAutoRegisterEnabled(string $driver) + public function driverAutoRegisterEnabled(string $driver): bool { return config('services.' . strtolower($driver) . '.auto_register') === true; } /** * Check if the current config for the given driver allow email address auto-confirmation. - * @param string $driver - * @return bool */ - public function driverAutoConfirmEmailEnabled(string $driver) + public function driverAutoConfirmEmailEnabled(string $driver): bool { return config('services.' . strtolower($driver) . '.auto_confirm') === true; } /** - * @param string $socialDriver - * @param SocialUser $socialUser - * @return SocialAccount + * Fill and return a SocialAccount from the given driver name and SocialUser. */ - public function fillSocialAccount($socialDriver, $socialUser) + public function fillSocialAccount(string $socialDriver, SocialUser $socialUser): SocialAccount { $this->socialAccount->fill([ 'driver' => $socialDriver, @@ -240,22 +216,17 @@ class SocialAuthService /** * Detach a social account from a user. - * @param $socialDriver * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ - public function detachSocialAccount($socialDriver) + public function detachSocialAccount(string $socialDriver) { user()->socialAccounts()->where('driver', '=', $socialDriver)->delete(); - session()->flash('success', trans('settings.users_social_disconnected', ['socialAccount' => Str::title($socialDriver)])); - return redirect(user()->getEditUrl()); } /** * Provide redirect options per service for the Laravel Socialite driver - * @param $driverName - * @return \Laravel\Socialite\Contracts\Provider */ - public function getSocialDriver(string $driverName) + public function getSocialDriver(string $driverName): Provider { $driver = $this->socialite->driver($driverName); diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index b1d22d57e..a74e53617 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -66,9 +66,6 @@ class LoginController extends Controller /** * Overrides the action when a user is authenticated. * If the user authenticated but does not exist in the user table we create them. - * @param Request $request - * @param Authenticatable $user - * @return \Illuminate\Http\RedirectResponse * @throws AuthException * @throws \BookStack\Exceptions\LdapException */ @@ -112,8 +109,6 @@ class LoginController extends Controller /** * Show the application login form. - * @param Request $request - * @return \Illuminate\Http\Response */ public function getLogin(Request $request) { @@ -135,23 +130,8 @@ class LoginController extends Controller ]); } - /** - * Redirect to the relevant social site. - * @param $socialDriver - * @return \Symfony\Component\HttpFoundation\RedirectResponse - * @throws \BookStack\Exceptions\SocialDriverNotConfigured - */ - public function getSocialLogin($socialDriver) - { - session()->put('social-callback', 'login'); - return $this->socialAuthService->startLogIn($socialDriver); - } - /** * Log the user out of the application. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response */ public function logout(Request $request) { @@ -160,7 +140,6 @@ class LoginController extends Controller } $this->guard()->logout(); - $request->session()->invalidate(); return $this->loggedOut($request) ?: redirect('/'); diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 8e4dd57c3..c9c0c3ec5 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -2,25 +2,14 @@ namespace BookStack\Http\Controllers\Auth; -use BookStack\Auth\Access\EmailConfirmationService; +use BookStack\Auth\Access\RegistrationService; use BookStack\Auth\Access\SocialAuthService; -use BookStack\Auth\SocialAccount; use BookStack\Auth\User; -use BookStack\Auth\UserRepo; -use BookStack\Exceptions\SocialDriverNotConfigured; -use BookStack\Exceptions\SocialSignInAccountNotUsed; -use BookStack\Exceptions\SocialSignInException; use BookStack\Exceptions\UserRegistrationException; use BookStack\Http\Controllers\Controller; -use Exception; use Illuminate\Foundation\Auth\RegistersUsers; -use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; -use Illuminate\Http\Response; -use Illuminate\Routing\Redirector; use Illuminate\Support\Facades\Hash; -use Illuminate\Support\Str; -use Laravel\Socialite\Contracts\User as SocialUser; use Validator; class RegisterController extends Controller @@ -39,8 +28,7 @@ class RegisterController extends Controller use RegistersUsers; protected $socialAuthService; - protected $emailConfirmationService; - protected $userRepo; + protected $registrationService; /** * Where to redirect users after login / registration. @@ -52,17 +40,14 @@ class RegisterController extends Controller /** * Create a new controller instance. - * - * @param SocialAuthService $socialAuthService - * @param EmailConfirmationService $emailConfirmationService - * @param UserRepo $userRepo */ - public function __construct(SocialAuthService $socialAuthService, EmailConfirmationService $emailConfirmationService, UserRepo $userRepo) + public function __construct(SocialAuthService $socialAuthService, RegistrationService $registrationService) { - $this->middleware('guest')->only(['getRegister', 'postRegister', 'socialRegister']); + $this->middleware('guest')->only(['getRegister', 'postRegister']); + $this->socialAuthService = $socialAuthService; - $this->emailConfirmationService = $emailConfirmationService; - $this->userRepo = $userRepo; + $this->registrationService = $registrationService; + $this->redirectTo = url('/'); $this->redirectPath = url('/'); parent::__construct(); @@ -71,7 +56,6 @@ class RegisterController extends Controller /** * Get a validator for an incoming registration request. * - * @param array $data * @return \Illuminate\Contracts\Validation\Validator */ protected function validator(array $data) @@ -83,25 +67,13 @@ class RegisterController extends Controller ]); } - /** - * Check whether or not registrations are allowed in the app settings. - * @throws UserRegistrationException - */ - protected function checkRegistrationAllowed() - { - if (!setting('registration-enabled') || config('auth.method') === 'ldap') { - throw new UserRegistrationException(trans('auth.registrations_disabled'), '/login'); - } - } - /** * Show the application registration form. - * @return Response * @throws UserRegistrationException */ public function getRegister() { - $this->checkRegistrationAllowed(); + $this->registrationService->checkRegistrationAllowed(); $socialDrivers = $this->socialAuthService->getActiveDrivers(); $samlEnabled = (config('saml2.enabled') === true) && (config('saml2.auto_register') === true); return view('auth.register', [ @@ -112,17 +84,25 @@ class RegisterController extends Controller /** * Handle a registration request for the application. - * @param Request|Request $request - * @return RedirectResponse|Redirector * @throws UserRegistrationException */ public function postRegister(Request $request) { - $this->checkRegistrationAllowed(); + $this->registrationService->checkRegistrationAllowed(); $this->validator($request->all())->validate(); - $userData = $request->all(); - return $this->registerUser($userData); + + try { + $this->registrationService->registerUser($userData); + } catch (UserRegistrationException $exception) { + if ($exception->getMessage()) { + $this->showErrorNotification($exception->getMessage()); + } + return redirect($exception->redirectLocation); + } + + $this->showSuccessNotification(trans('auth.register_success')); + return redirect($this->redirectPath()); } /** @@ -139,136 +119,4 @@ class RegisterController extends Controller ]); } - /** - * The registrations flow for all users. - * @param array $userData - * @param bool|false|SocialAccount $socialAccount - * @param bool $emailVerified - * @return RedirectResponse|Redirector - * @throws UserRegistrationException - */ - protected function registerUser(array $userData, $socialAccount = false, $emailVerified = false) - { - $registrationRestrict = setting('registration-restrict'); - - if ($registrationRestrict) { - $restrictedEmailDomains = explode(',', str_replace(' ', '', $registrationRestrict)); - $userEmailDomain = $domain = mb_substr(mb_strrchr($userData['email'], "@"), 1); - if (!in_array($userEmailDomain, $restrictedEmailDomains)) { - throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), '/register'); - } - } - - $newUser = $this->userRepo->registerNew($userData, $emailVerified); - if ($socialAccount) { - $newUser->socialAccounts()->save($socialAccount); - } - - if ($this->emailConfirmationService->confirmationRequired() && !$emailVerified) { - $newUser->save(); - - try { - $this->emailConfirmationService->sendConfirmation($newUser); - } catch (Exception $e) { - $this->showErrorNotification(trans('auth.email_confirm_send_error')); - } - - return redirect('/register/confirm'); - } - - auth()->login($newUser); - $this->showSuccessNotification(trans('auth.register_success')); - return redirect($this->redirectPath()); - } - - /** - * Redirect to the social site for authentication intended to register. - * @param $socialDriver - * @return mixed - * @throws UserRegistrationException - * @throws SocialDriverNotConfigured - */ - public function socialRegister($socialDriver) - { - $this->checkRegistrationAllowed(); - session()->put('social-callback', 'register'); - return $this->socialAuthService->startRegister($socialDriver); - } - - /** - * The callback for social login services. - * @param Request $request - * @param string $socialDriver - * @return RedirectResponse|Redirector - * @throws SocialSignInException - * @throws UserRegistrationException - * @throws SocialDriverNotConfigured - */ - public function socialCallback(Request $request, string $socialDriver) - { - if (!session()->has('social-callback')) { - throw new SocialSignInException(trans('errors.social_no_action_defined'), '/login'); - } - - // Check request for error information - if ($request->has('error') && $request->has('error_description')) { - throw new SocialSignInException(trans('errors.social_login_bad_response', [ - 'socialAccount' => $socialDriver, - 'error' => $request->get('error_description'), - ]), '/login'); - } - - $action = session()->pull('social-callback'); - - // Attempt login or fall-back to register if allowed. - $socialUser = $this->socialAuthService->getSocialUser($socialDriver); - if ($action == 'login') { - try { - return $this->socialAuthService->handleLoginCallback($socialDriver, $socialUser); - } catch (SocialSignInAccountNotUsed $exception) { - if ($this->socialAuthService->driverAutoRegisterEnabled($socialDriver)) { - return $this->socialRegisterCallback($socialDriver, $socialUser); - } - throw $exception; - } - } - - if ($action == 'register') { - return $this->socialRegisterCallback($socialDriver, $socialUser); - } - - return redirect()->back(); - } - - /** - * Detach a social account from a user. - * @param $socialDriver - * @return RedirectResponse|Redirector - */ - public function detachSocialAccount($socialDriver) - { - return $this->socialAuthService->detachSocialAccount($socialDriver); - } - - /** - * Register a new user after a registration callback. - * @param string $socialDriver - * @param SocialUser $socialUser - * @return RedirectResponse|Redirector - * @throws UserRegistrationException - */ - protected function socialRegisterCallback(string $socialDriver, SocialUser $socialUser) - { - $socialUser = $this->socialAuthService->handleRegistrationCallback($socialDriver, $socialUser); - $socialAccount = $this->socialAuthService->fillSocialAccount($socialDriver, $socialUser); - $emailVerified = $this->socialAuthService->driverAutoConfirmEmailEnabled($socialDriver); - - // Create an array of the user data to create a new user instance - $userData = [ - 'name' => $socialUser->getName(), - 'email' => $socialUser->getEmail(), - 'password' => Str::random(30) - ]; - return $this->registerUser($userData, $socialAccount, $emailVerified); - } } diff --git a/app/Http/Controllers/Auth/SocialController.php b/app/Http/Controllers/Auth/SocialController.php new file mode 100644 index 000000000..bcd82a9c0 --- /dev/null +++ b/app/Http/Controllers/Auth/SocialController.php @@ -0,0 +1,139 @@ +middleware('guest')->only(['getRegister', 'postRegister']); + $this->socialAuthService = $socialAuthService; + $this->registrationService = $registrationService; + } + + + /** + * Redirect to the relevant social site. + * @throws \BookStack\Exceptions\SocialDriverNotConfigured + */ + public function getSocialLogin(string $socialDriver) + { + session()->put('social-callback', 'login'); + return $this->socialAuthService->startLogIn($socialDriver); + } + + /** + * Redirect to the social site for authentication intended to register. + * @throws SocialDriverNotConfigured + * @throws UserRegistrationException + */ + public function socialRegister(string $socialDriver) + { + $this->registrationService->checkRegistrationAllowed(); + session()->put('social-callback', 'register'); + return $this->socialAuthService->startRegister($socialDriver); + } + + /** + * The callback for social login services. + * @throws SocialSignInException + * @throws SocialDriverNotConfigured + * @throws UserRegistrationException + */ + public function socialCallback(Request $request, string $socialDriver) + { + if (!session()->has('social-callback')) { + throw new SocialSignInException(trans('errors.social_no_action_defined'), '/login'); + } + + // Check request for error information + if ($request->has('error') && $request->has('error_description')) { + throw new SocialSignInException(trans('errors.social_login_bad_response', [ + 'socialAccount' => $socialDriver, + 'error' => $request->get('error_description'), + ]), '/login'); + } + + $action = session()->pull('social-callback'); + + // Attempt login or fall-back to register if allowed. + $socialUser = $this->socialAuthService->getSocialUser($socialDriver); + if ($action == 'login') { + try { + return $this->socialAuthService->handleLoginCallback($socialDriver, $socialUser); + } catch (SocialSignInAccountNotUsed $exception) { + if ($this->socialAuthService->driverAutoRegisterEnabled($socialDriver)) { + return $this->socialRegisterCallback($socialDriver, $socialUser); + } + throw $exception; + } + } + + if ($action == 'register') { + return $this->socialRegisterCallback($socialDriver, $socialUser); + } + + return redirect()->back(); + } + + /** + * Detach a social account from a user. + */ + public function detachSocialAccount(string $socialDriver) + { + $this->socialAuthService->detachSocialAccount($socialDriver); + session()->flash('success', trans('settings.users_social_disconnected', ['socialAccount' => Str::title($socialDriver)])); + return redirect(user()->getEditUrl()); + } + + /** + * Register a new user after a registration callback. + * @return RedirectResponse|Redirector + * @throws UserRegistrationException + */ + protected function socialRegisterCallback(string $socialDriver, SocialUser $socialUser) + { + $socialUser = $this->socialAuthService->handleRegistrationCallback($socialDriver, $socialUser); + $socialAccount = $this->socialAuthService->fillSocialAccount($socialDriver, $socialUser); + $emailVerified = $this->socialAuthService->driverAutoConfirmEmailEnabled($socialDriver); + + // Create an array of the user data to create a new user instance + $userData = [ + 'name' => $socialUser->getName(), + 'email' => $socialUser->getEmail(), + 'password' => Str::random(30) + ]; + + try { + $this->registrationService->registerUser($userData, $socialAccount, $emailVerified); + } catch (UserRegistrationException $exception) { + if ($exception->getMessage()) { + $this->showErrorNotification($exception->getMessage()); + } + return redirect($exception->redirectLocation); + } + + $this->showSuccessNotification(trans('auth.register_success')); + return redirect('/'); + } +} diff --git a/routes/web.php b/routes/web.php index f38575b79..eafad6489 100644 --- a/routes/web.php +++ b/routes/web.php @@ -208,10 +208,10 @@ Route::group(['middleware' => 'auth'], function () { }); // Social auth routes -Route::get('/login/service/{socialDriver}', 'Auth\LoginController@getSocialLogin'); -Route::get('/login/service/{socialDriver}/callback', 'Auth\RegisterController@socialCallback'); -Route::get('/login/service/{socialDriver}/detach', 'Auth\RegisterController@detachSocialAccount'); -Route::get('/register/service/{socialDriver}', 'Auth\RegisterController@socialRegister'); +Route::get('/login/service/{socialDriver}', 'Auth\SocialController@getSocialLogin'); +Route::get('/login/service/{socialDriver}/callback', 'Auth\SocialController@socialCallback'); +Route::get('/login/service/{socialDriver}/detach', 'Auth\SocialController@detachSocialAccount'); +Route::get('/register/service/{socialDriver}', 'Auth\SocialController@socialRegister'); // Login/Logout routes Route::get('/login', 'Auth\LoginController@getLogin'); From 575b85021d4f6d9507816710a5b96f6a9742d6bf Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 1 Feb 2020 11:42:22 +0000 Subject: [PATCH 166/191] Started alignment of auth services - Removed LDAP specific logic from login controller, placed in Guard. - Created safer base user provider for ldap login, to be used for SAML soon. - Moved LDAP auth work from user provider to guard. --- .../Access/ExternalBaseUserProvider.php} | 51 +-- .../Guards/ExternalBaseSessionGuard.php | 301 ++++++++++++++++++ app/Auth/Access/Guards/LdapSessionGuard.php | 126 ++++++++ app/Auth/Access/LdapService.php | 11 +- app/Config/auth.php | 19 +- app/Exceptions/AuthException.php | 6 - .../LoginAttemptEmailNeededException.php | 6 + app/Exceptions/LoginAttemptException.php | 6 + app/Http/Controllers/Auth/LoginController.php | 118 +++---- app/Providers/AuthServiceProvider.php | 18 +- 10 files changed, 539 insertions(+), 123 deletions(-) rename app/{Providers/LdapUserProvider.php => Auth/Access/ExternalBaseUserProvider.php} (61%) create mode 100644 app/Auth/Access/Guards/ExternalBaseSessionGuard.php create mode 100644 app/Auth/Access/Guards/LdapSessionGuard.php delete mode 100644 app/Exceptions/AuthException.php create mode 100644 app/Exceptions/LoginAttemptEmailNeededException.php create mode 100644 app/Exceptions/LoginAttemptException.php diff --git a/app/Providers/LdapUserProvider.php b/app/Auth/Access/ExternalBaseUserProvider.php similarity index 61% rename from app/Providers/LdapUserProvider.php rename to app/Auth/Access/ExternalBaseUserProvider.php index 9c91def2f..69295ee4e 100644 --- a/app/Providers/LdapUserProvider.php +++ b/app/Auth/Access/ExternalBaseUserProvider.php @@ -1,12 +1,11 @@ model = $model; - $this->ldapService = $ldapService; } /** @@ -44,7 +35,6 @@ class LdapUserProvider implements UserProvider return new $class; } - /** * Retrieve a user by their unique identifier. * @@ -65,12 +55,7 @@ class LdapUserProvider implements UserProvider */ public function retrieveByToken($identifier, $token) { - $model = $this->createModel(); - - return $model->newQuery() - ->where($model->getAuthIdentifierName(), $identifier) - ->where($model->getRememberTokenName(), $token) - ->first(); + return null; } @@ -83,10 +68,7 @@ class LdapUserProvider implements UserProvider */ public function updateRememberToken(Authenticatable $user, $token) { - if ($user->exists) { - $user->setRememberToken($token); - $user->save(); - } + // } /** @@ -97,27 +79,11 @@ class LdapUserProvider implements UserProvider */ public function retrieveByCredentials(array $credentials) { - // Get user via LDAP - $userDetails = $this->ldapService->getUserDetails($credentials['username']); - if ($userDetails === null) { - return null; - } - // Search current user base by looking up a uid $model = $this->createModel(); - $currentUser = $model->newQuery() - ->where('external_auth_id', $userDetails['uid']) + return $model->newQuery() + ->where('external_auth_id', $credentials['external_auth_id']) ->first(); - - if ($currentUser !== null) { - return $currentUser; - } - - $model->name = $userDetails['name']; - $model->external_auth_id = $userDetails['uid']; - $model->email = $userDetails['email']; - $model->email_confirmed = false; - return $model; } /** @@ -129,6 +95,7 @@ class LdapUserProvider implements UserProvider */ public function validateCredentials(Authenticatable $user, array $credentials) { - return $this->ldapService->validateUserCredentials($user, $credentials['username'], $credentials['password']); + // Should be done in the guard. + return false; } } diff --git a/app/Auth/Access/Guards/ExternalBaseSessionGuard.php b/app/Auth/Access/Guards/ExternalBaseSessionGuard.php new file mode 100644 index 000000000..3022b7f8e --- /dev/null +++ b/app/Auth/Access/Guards/ExternalBaseSessionGuard.php @@ -0,0 +1,301 @@ +name = $name; + $this->session = $session; + $this->provider = $provider; + } + + /** + * Get the currently authenticated user. + * + * @return \Illuminate\Contracts\Auth\Authenticatable|null + */ + public function user() + { + if ($this->loggedOut) { + return; + } + + // If we've already retrieved the user for the current request we can just + // return it back immediately. We do not want to fetch the user data on + // every call to this method because that would be tremendously slow. + if (! is_null($this->user)) { + return $this->user; + } + + $id = $this->session->get($this->getName()); + + // First we will try to load the user using the + // identifier in the session if one exists. + if (! is_null($id)) { + $this->user = $this->provider->retrieveById($id); + } + + return $this->user; + } + + /** + * Get the ID for the currently authenticated user. + * + * @return int|null + */ + public function id() + { + if ($this->loggedOut) { + return; + } + + return $this->user() + ? $this->user()->getAuthIdentifier() + : $this->session->get($this->getName()); + } + + /** + * Log a user into the application without sessions or cookies. + * + * @param array $credentials + * @return bool + */ + public function once(array $credentials = []) + { + if ($this->validate($credentials)) { + $this->setUser($this->lastAttempted); + + return true; + } + + return false; + } + + /** + * Log the given user ID into the application without sessions or cookies. + * + * @param mixed $id + * @return \Illuminate\Contracts\Auth\Authenticatable|false + */ + public function onceUsingId($id) + { + if (! is_null($user = $this->provider->retrieveById($id))) { + $this->setUser($user); + + return $user; + } + + return false; + } + + /** + * Validate a user's credentials. + * + * @param array $credentials + * @return bool + */ + public function validate(array $credentials = []) + { + return false; + } + + + /** + * Attempt to authenticate a user using the given credentials. + * + * @param array $credentials + * @param bool $remember + * @return bool + */ + public function attempt(array $credentials = [], $remember = false) + { + return false; + } + + /** + * Log the given user ID into the application. + * + * @param mixed $id + * @param bool $remember + * @return \Illuminate\Contracts\Auth\Authenticatable|false + */ + public function loginUsingId($id, $remember = false) + { + if (! is_null($user = $this->provider->retrieveById($id))) { + $this->login($user, $remember); + + return $user; + } + + return false; + } + + /** + * Log a user into the application. + * + * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param bool $remember + * @return void + */ + public function login(AuthenticatableContract $user, $remember = false) + { + $this->updateSession($user->getAuthIdentifier()); + + $this->setUser($user); + } + + /** + * Update the session with the given ID. + * + * @param string $id + * @return void + */ + protected function updateSession($id) + { + $this->session->put($this->getName(), $id); + + $this->session->migrate(true); + } + + /** + * Log the user out of the application. + * + * @return void + */ + public function logout() + { + $this->clearUserDataFromStorage(); + + // Now we will clear the users out of memory so they are no longer available + // as the user is no longer considered as being signed into this + // application and should not be available here. + $this->user = null; + + $this->loggedOut = true; + } + + /** + * Remove the user data from the session and cookies. + * + * @return void + */ + protected function clearUserDataFromStorage() + { + $this->session->remove($this->getName()); + } + + /** + * Get the last user we attempted to authenticate. + * + * @return \Illuminate\Contracts\Auth\Authenticatable + */ + public function getLastAttempted() + { + return $this->lastAttempted; + } + + /** + * Get a unique identifier for the auth session value. + * + * @return string + */ + public function getName() + { + return 'login_'.$this->name.'_'.sha1(static::class); + } + + /** + * Determine if the user was authenticated via "remember me" cookie. + * + * @return bool + */ + public function viaRemember() + { + return false; + } + + /** + * Return the currently cached user. + * + * @return \Illuminate\Contracts\Auth\Authenticatable|null + */ + public function getUser() + { + return $this->user; + } + + /** + * Set the current user. + * + * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @return $this + */ + public function setUser(AuthenticatableContract $user) + { + $this->user = $user; + + $this->loggedOut = false; + + return $this; + } + +} diff --git a/app/Auth/Access/Guards/LdapSessionGuard.php b/app/Auth/Access/Guards/LdapSessionGuard.php new file mode 100644 index 000000000..ad173cf73 --- /dev/null +++ b/app/Auth/Access/Guards/LdapSessionGuard.php @@ -0,0 +1,126 @@ +ldapService = $ldapService; + $this->userRepo = $userRepo; + parent::__construct($name, $provider, $session); + } + + /** + * Validate a user's credentials. + * + * @param array $credentials + * @return bool + * @throws LdapException + */ + public function validate(array $credentials = []) + { + $userDetails = $this->ldapService->getUserDetails($credentials['username']); + $this->lastAttempted = $this->provider->retrieveByCredentials([ + 'external_auth_id' => $userDetails['uid'] + ]); + + return $this->ldapService->validateUserCredentials($userDetails, $credentials['username'], $credentials['password']); + } + + /** + * Attempt to authenticate a user using the given credentials. + * + * @param array $credentials + * @param bool $remember + * @return bool + * @throws LoginAttemptEmailNeededException + * @throws LoginAttemptException + * @throws LdapException + */ + public function attempt(array $credentials = [], $remember = false) + { + $username = $credentials['username']; + $userDetails = $this->ldapService->getUserDetails($username); + $this->lastAttempted = $user = $this->provider->retrieveByCredentials([ + 'external_auth_id' => $userDetails['uid'] + ]); + + if (!$this->ldapService->validateUserCredentials($userDetails, $username, $credentials['password'])) { + return false; + } + + if (is_null($user)) { + $user = $this->freshUserInstanceFromLdapUserDetails($userDetails); + } + + $providedEmail = ($credentials['email'] ?? false); + + // Request email if missing from LDAP and model and missing from request + if (is_null($user->email) && !$providedEmail) { + throw new LoginAttemptEmailNeededException(); + } + + // Add email to model if non-existing and email provided in request + if (!$user->exists && $user->email === null && $providedEmail) { + $user->email = $providedEmail; + } + + if (!$user->exists) { + // Check for existing users with same email + $alreadyUser = $user->newQuery()->where('email', '=', $user->email)->count() > 0; + if ($alreadyUser) { + throw new LoginAttemptException(trans('errors.error_user_exists_different_creds', ['email' => $user->email])); + } + + $user->save(); + $this->userRepo->attachDefaultRole($user); + $this->userRepo->downloadAndAssignUserAvatar($user); + } + + // Sync LDAP groups if required + if ($this->ldapService->shouldSyncGroups()) { + $this->ldapService->syncGroups($user, $username); + } + + $this->login($user, $remember); + return true; + } + + /** + * Create a fresh user instance from details provided by a LDAP lookup. + */ + protected function freshUserInstanceFromLdapUserDetails(array $ldapUserDetails): User + { + $user = new User(); + + $user->name = $ldapUserDetails['name']; + $user->external_auth_id = $ldapUserDetails['uid']; + $user->email = $ldapUserDetails['email']; + $user->email_confirmed = false; + + return $user; + } + +} diff --git a/app/Auth/Access/LdapService.php b/app/Auth/Access/LdapService.php index 554bc4b48..cc2890817 100644 --- a/app/Auth/Access/LdapService.php +++ b/app/Auth/Access/LdapService.php @@ -106,20 +106,15 @@ class LdapService extends ExternalAuthService * Check if the given credentials are valid for the given user. * @throws LdapException */ - public function validateUserCredentials(Authenticatable $user, string $username, string $password): bool + public function validateUserCredentials(array $ldapUserDetails, string $username, string $password): bool { - $ldapUser = $this->getUserDetails($username); - if ($ldapUser === null) { - return false; - } - - if ($ldapUser['uid'] !== $user->external_auth_id) { + if ($ldapUserDetails === null) { return false; } $ldapConnection = $this->getConnection(); try { - $ldapBind = $this->ldap->bind($ldapConnection, $ldapUser['dn'], $password); + $ldapBind = $this->ldap->bind($ldapConnection, $ldapUserDetails['dn'], $password); } catch (ErrorException $e) { $ldapBind = false; } diff --git a/app/Config/auth.php b/app/Config/auth.php index b3e22c7e1..0be5aeee8 100644 --- a/app/Config/auth.php +++ b/app/Config/auth.php @@ -18,7 +18,7 @@ return [ // This option controls the default authentication "guard" and password // reset options for your application. 'defaults' => [ - 'guard' => 'web', + 'guard' => env('AUTH_METHOD', 'standard') === 'standard' ? 'web' : env('AUTH_METHOD'), 'passwords' => 'users', ], @@ -26,13 +26,16 @@ return [ // All authentication drivers have a user provider. This defines how the // users are actually retrieved out of your database or other storage // mechanisms used by this application to persist your user's data. - // Supported: "session", "token" + // Supported drivers: "session", "api-token", "ldap-session" 'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], - + 'ldap' => [ + 'driver' => 'ldap-session', + 'provider' => 'external' + ], 'api' => [ 'driver' => 'api-token', ], @@ -42,17 +45,15 @@ return [ // All authentication drivers have a user provider. This defines how the // users are actually retrieved out of your database or other storage // mechanisms used by this application to persist your user's data. - // Supported: database, eloquent, ldap 'providers' => [ 'users' => [ 'driver' => env('AUTH_METHOD', 'standard') === 'standard' ? 'eloquent' : env('AUTH_METHOD'), 'model' => \BookStack\Auth\User::class, ], - - // 'users' => [ - // 'driver' => 'database', - // 'table' => 'users', - // ], + 'external' => [ + 'driver' => 'external-users', + 'model' => \BookStack\Auth\User::class, + ], ], // Resetting Passwords diff --git a/app/Exceptions/AuthException.php b/app/Exceptions/AuthException.php deleted file mode 100644 index 2ab7d4616..000000000 --- a/app/Exceptions/AuthException.php +++ /dev/null @@ -1,6 +0,0 @@ -middleware('guest', ['only' => ['getLogin', 'postLogin']]); $this->socialAuthService = $socialAuthService; - $this->ldapService = $ldapService; - $this->userRepo = $userRepo; $this->redirectPath = url('/'); $this->redirectAfterLogout = url('/login'); parent::__construct(); @@ -64,47 +51,11 @@ class LoginController extends Controller } /** - * Overrides the action when a user is authenticated. - * If the user authenticated but does not exist in the user table we create them. - * @throws AuthException - * @throws \BookStack\Exceptions\LdapException + * Get the needed authorization credentials from the request. */ - protected function authenticated(Request $request, Authenticatable $user) + protected function credentials(Request $request) { - // Explicitly log them out for now if they do no exist. - if (!$user->exists) { - auth()->logout($user); - } - - if (!$user->exists && $user->email === null && !$request->filled('email')) { - $request->flash(); - session()->flash('request-email', true); - return redirect('/login'); - } - - if (!$user->exists && $user->email === null && $request->filled('email')) { - $user->email = $request->get('email'); - } - - if (!$user->exists) { - // Check for users with same email already - $alreadyUser = $user->newQuery()->where('email', '=', $user->email)->count() > 0; - if ($alreadyUser) { - throw new AuthException(trans('errors.error_user_exists_different_creds', ['email' => $user->email])); - } - - $user->save(); - $this->userRepo->attachDefaultRole($user); - $this->userRepo->downloadAndAssignUserAvatar($user); - auth()->login($user); - } - - // Sync LDAP groups if required - if ($this->ldapService->shouldSyncGroups()) { - $this->ldapService->syncGroups($user, $request->get($this->username())); - } - - return redirect()->intended('/'); + return $request->only('username', 'email', 'password'); } /** @@ -130,6 +81,61 @@ class LoginController extends Controller ]); } + /** + * Handle a login request to the application. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse + * + * @throws \Illuminate\Validation\ValidationException + */ + public function login(Request $request) + { + $this->validateLogin($request); + + // If the class is using the ThrottlesLogins trait, we can automatically throttle + // the login attempts for this application. We'll key this by the username and + // the IP address of the client making these requests into this application. + if (method_exists($this, 'hasTooManyLoginAttempts') && + $this->hasTooManyLoginAttempts($request)) { + $this->fireLockoutEvent($request); + + return $this->sendLockoutResponse($request); + } + + try { + if ($this->attemptLogin($request)) { + return $this->sendLoginResponse($request); + } + } catch (LoginAttemptException $exception) { + return $this->sendLoginAttemptExceptionResponse($exception, $request); + } + + // If the login attempt was unsuccessful we will increment the number of attempts + // to login and redirect the user back to the login form. Of course, when this + // user surpasses their maximum number of attempts they will get locked out. + $this->incrementLoginAttempts($request); + + return $this->sendFailedLoginResponse($request); + } + + /** + * Send a response when a login attempt exception occurs. + */ + protected function sendLoginAttemptExceptionResponse(LoginAttemptException $exception, Request $request) + { + if ($exception instanceof LoginAttemptEmailNeededException) { + $request->flash(); + session()->flash('request-email', true); + } + + if ($message = $exception->getMessage()) { + $this->showWarningNotification($message); + } + + return redirect('/login'); + } + /** * Log the user out of the application. */ diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index ab7dd5195..0b299551a 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -4,7 +4,10 @@ namespace BookStack\Providers; use Auth; use BookStack\Api\ApiTokenGuard; +use BookStack\Auth\Access\ExternalBaseUserProvider; +use BookStack\Auth\Access\Guards\LdapSessionGuard; use BookStack\Auth\Access\LdapService; +use BookStack\Auth\UserRepo; use Illuminate\Support\ServiceProvider; class AuthServiceProvider extends ServiceProvider @@ -19,6 +22,17 @@ class AuthServiceProvider extends ServiceProvider Auth::extend('api-token', function ($app, $name, array $config) { return new ApiTokenGuard($app['request']); }); + + Auth::extend('ldap-session', function ($app, $name, array $config) { + $provider = Auth::createUserProvider($config['provider']); + return new LdapSessionGuard( + $name, + $provider, + $this->app['session.store'], + $app[LdapService::class], + $app[UserRepo::class] + ); + }); } /** @@ -28,8 +42,8 @@ class AuthServiceProvider extends ServiceProvider */ public function register() { - Auth::provider('ldap', function ($app, array $config) { - return new LdapUserProvider($config['model'], $app[LdapService::class]); + Auth::provider('external-users', function ($app, array $config) { + return new ExternalBaseUserProvider($config['model']); }); } } From 7728931f150cb9f80a98cf6a2f947d7f25532cc4 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 1 Feb 2020 14:30:23 +0000 Subject: [PATCH 167/191] Set more appropriate login validation and broken up LDAP guide a bit --- app/Auth/Access/Guards/LdapSessionGuard.php | 65 ++++++++++++------- app/Http/Controllers/Auth/LoginController.php | 37 +++++++++++ 2 files changed, 79 insertions(+), 23 deletions(-) diff --git a/app/Auth/Access/Guards/LdapSessionGuard.php b/app/Auth/Access/Guards/LdapSessionGuard.php index ad173cf73..223088d05 100644 --- a/app/Auth/Access/Guards/LdapSessionGuard.php +++ b/app/Auth/Access/Guards/LdapSessionGuard.php @@ -75,29 +75,8 @@ class LdapSessionGuard extends ExternalBaseSessionGuard $user = $this->freshUserInstanceFromLdapUserDetails($userDetails); } - $providedEmail = ($credentials['email'] ?? false); - - // Request email if missing from LDAP and model and missing from request - if (is_null($user->email) && !$providedEmail) { - throw new LoginAttemptEmailNeededException(); - } - - // Add email to model if non-existing and email provided in request - if (!$user->exists && $user->email === null && $providedEmail) { - $user->email = $providedEmail; - } - - if (!$user->exists) { - // Check for existing users with same email - $alreadyUser = $user->newQuery()->where('email', '=', $user->email)->count() > 0; - if ($alreadyUser) { - throw new LoginAttemptException(trans('errors.error_user_exists_different_creds', ['email' => $user->email])); - } - - $user->save(); - $this->userRepo->attachDefaultRole($user); - $this->userRepo->downloadAndAssignUserAvatar($user); - } + $this->checkForUserEmail($user, $credentials['email'] ?? ''); + $this->saveIfNew($user); // Sync LDAP groups if required if ($this->ldapService->shouldSyncGroups()) { @@ -108,6 +87,46 @@ class LdapSessionGuard extends ExternalBaseSessionGuard return true; } + /** + * Save the give user if they don't yet existing in the system. + * @throws LoginAttemptException + */ + protected function saveIfNew(User $user) + { + if ($user->exists) { + return; + } + + // Check for existing users with same email + $alreadyUser = $user->newQuery()->where('email', '=', $user->email)->count() > 0; + if ($alreadyUser) { + throw new LoginAttemptException(trans('errors.error_user_exists_different_creds', ['email' => $user->email])); + } + + $user->save(); + $this->userRepo->attachDefaultRole($user); + $this->userRepo->downloadAndAssignUserAvatar($user); + } + + /** + * Ensure the given user has an email. + * Takes the provided email in the request if a value is provided + * and the user does not have an existing email. + * @throws LoginAttemptEmailNeededException + */ + protected function checkForUserEmail(User $user, string $providedEmail) + { + // Request email if missing from user and missing from request + if (is_null($user->email) && !$providedEmail) { + throw new LoginAttemptEmailNeededException(); + } + + // Add email to model if non-existing and email provided in request + if (!$user->exists && is_null($user->email) && $providedEmail) { + $user->email = $providedEmail; + } + } + /** * Create a fresh user instance from details provided by a LDAP lookup. */ diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 1ff86fff6..2302937cb 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -119,6 +119,43 @@ class LoginController extends Controller return $this->sendFailedLoginResponse($request); } + /** + * Validate the user login request. + * + * @param \Illuminate\Http\Request $request + * @return void + * + * @throws \Illuminate\Validation\ValidationException + */ + protected function validateLogin(Request $request) + { + $rules = []; + $authMethod = config('auth.method'); + + if ($authMethod === 'standard') { + $rules = [ + 'email' => 'required|string|email', + 'password' => 'required|string' + ]; + } + + if ($authMethod === 'ldap') { + $rules = [ + 'username' => 'required|string', + 'password' => 'required|string', + 'email' => 'email', + ]; + } + + if ($authMethod === 'saml2') { + $rules = [ + 'email' => 'email', + ]; + } + + $request->validate($rules); + } + /** * Send a response when a login attempt exception occurs. */ From 3470a6a140e7e87cbb53332d9a8b50e5693603ef Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 1 Feb 2020 16:11:56 +0000 Subject: [PATCH 168/191] Aligned SAML2 system with LDAP implementation in terms of guards and UI --- app/Auth/Access/Guards/Saml2SessionGuard.php | 103 ++++++++++++++++++ .../views/auth/forms/login/saml2.blade.php | 30 +++++ 2 files changed, 133 insertions(+) create mode 100644 app/Auth/Access/Guards/Saml2SessionGuard.php create mode 100644 resources/views/auth/forms/login/saml2.blade.php diff --git a/app/Auth/Access/Guards/Saml2SessionGuard.php b/app/Auth/Access/Guards/Saml2SessionGuard.php new file mode 100644 index 000000000..1bdb59d51 --- /dev/null +++ b/app/Auth/Access/Guards/Saml2SessionGuard.php @@ -0,0 +1,103 @@ +ldapService = $ldapService; + parent::__construct($name, $provider, $session, $userRepo); + } + + /** + * Validate a user's credentials. + * + * @param array $credentials + * @return bool + * @throws LdapException + */ + public function validate(array $credentials = []) + { + $userDetails = $this->ldapService->getUserDetails($credentials['username']); + $this->lastAttempted = $this->provider->retrieveByCredentials([ + 'external_auth_id' => $userDetails['uid'] + ]); + + return $this->ldapService->validateUserCredentials($userDetails, $credentials['username'], $credentials['password']); + } + + /** + * Attempt to authenticate a user using the given credentials. + * + * @param array $credentials + * @param bool $remember + * @return bool + * @throws LoginAttemptEmailNeededException + * @throws LoginAttemptException + * @throws LdapException + */ + public function attempt(array $credentials = [], $remember = false) + { + $username = $credentials['username']; + $userDetails = $this->ldapService->getUserDetails($username); + $this->lastAttempted = $user = $this->provider->retrieveByCredentials([ + 'external_auth_id' => $userDetails['uid'] + ]); + + if (!$this->ldapService->validateUserCredentials($userDetails, $username, $credentials['password'])) { + return false; + } + + if (is_null($user)) { + $user = $this->freshUserInstanceFromLdapUserDetails($userDetails); + } + + $this->checkForUserEmail($user, $credentials['email'] ?? ''); + $this->saveIfNew($user); + + // Sync LDAP groups if required + if ($this->ldapService->shouldSyncGroups()) { + $this->ldapService->syncGroups($user, $username); + } + + $this->login($user, $remember); + return true; + } + + /** + * Create a fresh user instance from details provided by a LDAP lookup. + */ + protected function freshUserInstanceFromLdapUserDetails(array $ldapUserDetails): User + { + $user = new User(); + + $user->name = $ldapUserDetails['name']; + $user->external_auth_id = $ldapUserDetails['uid']; + $user->email = $ldapUserDetails['email']; + $user->email_confirmed = false; + + return $user; + } + +} diff --git a/resources/views/auth/forms/login/saml2.blade.php b/resources/views/auth/forms/login/saml2.blade.php new file mode 100644 index 000000000..12592d492 --- /dev/null +++ b/resources/views/auth/forms/login/saml2.blade.php @@ -0,0 +1,30 @@ +
+ {!! csrf_field() !!} + +
+
+ + @include('form.text', ['name' => 'username', 'autofocus' => true]) +
+ + @if(session('request-email', false) === true) +
+ + @include('form.text', ['name' => 'email']) + {{ trans('auth.ldap_email_hint') }} +
+ @endif + +
+ + @include('form.password', ['name' => 'password']) +
+
+ +
+
+ +
+
+ +
\ No newline at end of file From e743cd3f606fb8a2e432813f7c84fed1093f68c4 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 2 Feb 2020 10:59:03 +0000 Subject: [PATCH 169/191] Added files missed in previous commit --- .env.example.complete | 4 +- .../Guards/ExternalBaseSessionGuard.php | 19 ++-- app/Auth/Access/Guards/LdapSessionGuard.php | 4 +- app/Auth/Access/Guards/Saml2SessionGuard.php | 89 +++---------------- app/Auth/Access/RegistrationService.php | 5 +- app/Auth/Access/Saml2Service.php | 16 ++-- app/Config/auth.php | 6 +- app/Config/saml2.php | 4 - app/Http/Controllers/Auth/LoginController.php | 26 +----- .../Controllers/Auth/RegisterController.php | 2 - app/Http/Controllers/Auth/Saml2Controller.php | 3 +- app/Providers/AuthServiceProvider.php | 11 +++ .../views/auth/forms/login/ldap.blade.php | 43 +++++---- .../views/auth/forms/login/saml2.blade.php | 31 ++----- .../views/auth/forms/login/standard.blade.php | 46 +++++++--- resources/views/auth/login.blade.php | 36 +------- resources/views/auth/register.blade.php | 9 -- resources/views/common/header.blade.php | 8 +- resources/views/settings/roles/form.blade.php | 2 +- resources/views/users/form.blade.php | 2 +- routes/web.php | 2 +- 21 files changed, 139 insertions(+), 229 deletions(-) diff --git a/.env.example.complete b/.env.example.complete index e44644f08..bc6b644aa 100644 --- a/.env.example.complete +++ b/.env.example.complete @@ -121,7 +121,7 @@ STORAGE_S3_ENDPOINT=https://my-custom-s3-compatible.service.com:8001 STORAGE_URL=false # Authentication method to use -# Can be 'standard' or 'ldap' +# Can be 'standard', 'ldap' or 'saml2' AUTH_METHOD=standard # Social authentication configuration @@ -205,8 +205,6 @@ LDAP_REMOVE_FROM_GROUPS=false # SAML authentication configuration # Refer to https://www.bookstackapp.com/docs/admin/saml2-auth/ SAML2_NAME=SSO -SAML2_ENABLED=false -SAML2_AUTO_REGISTER=true SAML2_EMAIL_ATTRIBUTE=email SAML2_DISPLAY_NAME_ATTRIBUTES=username SAML2_EXTERNAL_ID_ATTRIBUTE=null diff --git a/app/Auth/Access/Guards/ExternalBaseSessionGuard.php b/app/Auth/Access/Guards/ExternalBaseSessionGuard.php index 3022b7f8e..d1fb0b606 100644 --- a/app/Auth/Access/Guards/ExternalBaseSessionGuard.php +++ b/app/Auth/Access/Guards/ExternalBaseSessionGuard.php @@ -2,6 +2,10 @@ namespace BookStack\Auth\Access\Guards; +use BookStack\Auth\User; +use BookStack\Auth\UserRepo; +use BookStack\Exceptions\LoginAttemptEmailNeededException; +use BookStack\Exceptions\LoginAttemptException; use Illuminate\Auth\GuardHelpers; use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; use Illuminate\Contracts\Auth\StatefulGuard; @@ -51,21 +55,24 @@ class ExternalBaseSessionGuard implements StatefulGuard */ protected $loggedOut = false; + /** + * Repository to perform user-specific actions. + * + * @var UserRepo + */ + protected $userRepo; + /** * Create a new authentication guard. * - * @param string $name - * @param \Illuminate\Contracts\Auth\UserProvider $provider - * @param \Illuminate\Contracts\Session\Session $session * @return void */ - public function __construct($name, - UserProvider $provider, - Session $session) + public function __construct(string $name, UserProvider $provider, Session $session, UserRepo $userRepo) { $this->name = $name; $this->session = $session; $this->provider = $provider; + $this->userRepo = $userRepo; } /** diff --git a/app/Auth/Access/Guards/LdapSessionGuard.php b/app/Auth/Access/Guards/LdapSessionGuard.php index 223088d05..6c416bf30 100644 --- a/app/Auth/Access/Guards/LdapSessionGuard.php +++ b/app/Auth/Access/Guards/LdapSessionGuard.php @@ -15,7 +15,6 @@ class LdapSessionGuard extends ExternalBaseSessionGuard { protected $ldapService; - protected $userRepo; /** * LdapSessionGuard constructor. @@ -28,8 +27,7 @@ class LdapSessionGuard extends ExternalBaseSessionGuard ) { $this->ldapService = $ldapService; - $this->userRepo = $userRepo; - parent::__construct($name, $provider, $session); + parent::__construct($name, $provider, $session, $userRepo); } /** diff --git a/app/Auth/Access/Guards/Saml2SessionGuard.php b/app/Auth/Access/Guards/Saml2SessionGuard.php index 1bdb59d51..4023913ed 100644 --- a/app/Auth/Access/Guards/Saml2SessionGuard.php +++ b/app/Auth/Access/Guards/Saml2SessionGuard.php @@ -2,49 +2,27 @@ namespace BookStack\Auth\Access\Guards; -use BookStack\Auth\Access\LdapService; -use BookStack\Auth\User; -use BookStack\Auth\UserRepo; -use BookStack\Exceptions\LdapException; -use BookStack\Exceptions\LoginAttemptException; -use BookStack\Exceptions\LoginAttemptEmailNeededException; -use Illuminate\Contracts\Auth\UserProvider; -use Illuminate\Contracts\Session\Session; - -class LdapSessionGuard extends ExternalBaseSessionGuard +/** + * Saml2 Session Guard + * + * The saml2 login process is async in nature meaning it does not fit very well + * into the default laravel 'Guard' auth flow. Instead most of the logic is done + * via the Saml2 controller & Saml2Service. This class provides a safer, thin + * version of SessionGuard. + * + * @package BookStack\Auth\Access\Guards + */ +class Saml2SessionGuard extends ExternalBaseSessionGuard { - - protected $ldapService; - - /** - * LdapSessionGuard constructor. - */ - public function __construct($name, - UserProvider $provider, - Session $session, - LdapService $ldapService, - UserRepo $userRepo - ) - { - $this->ldapService = $ldapService; - parent::__construct($name, $provider, $session, $userRepo); - } - /** * Validate a user's credentials. * * @param array $credentials * @return bool - * @throws LdapException */ public function validate(array $credentials = []) { - $userDetails = $this->ldapService->getUserDetails($credentials['username']); - $this->lastAttempted = $this->provider->retrieveByCredentials([ - 'external_auth_id' => $userDetails['uid'] - ]); - - return $this->ldapService->validateUserCredentials($userDetails, $credentials['username'], $credentials['password']); + return false; } /** @@ -53,51 +31,10 @@ class LdapSessionGuard extends ExternalBaseSessionGuard * @param array $credentials * @param bool $remember * @return bool - * @throws LoginAttemptEmailNeededException - * @throws LoginAttemptException - * @throws LdapException */ public function attempt(array $credentials = [], $remember = false) { - $username = $credentials['username']; - $userDetails = $this->ldapService->getUserDetails($username); - $this->lastAttempted = $user = $this->provider->retrieveByCredentials([ - 'external_auth_id' => $userDetails['uid'] - ]); - - if (!$this->ldapService->validateUserCredentials($userDetails, $username, $credentials['password'])) { - return false; - } - - if (is_null($user)) { - $user = $this->freshUserInstanceFromLdapUserDetails($userDetails); - } - - $this->checkForUserEmail($user, $credentials['email'] ?? ''); - $this->saveIfNew($user); - - // Sync LDAP groups if required - if ($this->ldapService->shouldSyncGroups()) { - $this->ldapService->syncGroups($user, $username); - } - - $this->login($user, $remember); - return true; - } - - /** - * Create a fresh user instance from details provided by a LDAP lookup. - */ - protected function freshUserInstanceFromLdapUserDetails(array $ldapUserDetails): User - { - $user = new User(); - - $user->name = $ldapUserDetails['name']; - $user->external_auth_id = $ldapUserDetails['uid']; - $user->email = $ldapUserDetails['email']; - $user->email_confirmed = false; - - return $user; + return false; } } diff --git a/app/Auth/Access/RegistrationService.php b/app/Auth/Access/RegistrationService.php index 7e8c7d5f5..74142301a 100644 --- a/app/Auth/Access/RegistrationService.php +++ b/app/Auth/Access/RegistrationService.php @@ -20,14 +20,15 @@ class RegistrationService $this->emailConfirmationService = $emailConfirmationService; } - /** * Check whether or not registrations are allowed in the app settings. * @throws UserRegistrationException */ public function checkRegistrationAllowed() { - if (!setting('registration-enabled') || config('auth.method') === 'ldap') { + $authMethod = config('auth.method'); + $authMethodsWithRegistration = ['standard']; + if (!setting('registration-enabled') || !in_array($authMethod, $authMethodsWithRegistration)) { throw new UserRegistrationException(trans('auth.registrations_disabled'), '/login'); } } diff --git a/app/Auth/Access/Saml2Service.php b/app/Auth/Access/Saml2Service.php index c1038e730..c52dc3a39 100644 --- a/app/Auth/Access/Saml2Service.php +++ b/app/Auth/Access/Saml2Service.php @@ -20,7 +20,6 @@ class Saml2Service extends ExternalAuthService protected $config; protected $userRepo; protected $user; - protected $enabled; /** * Saml2Service constructor. @@ -30,7 +29,6 @@ class Saml2Service extends ExternalAuthService $this->config = config('saml2'); $this->userRepo = $userRepo; $this->user = $user; - $this->enabled = config('saml2.enabled') === true; } /** @@ -204,7 +202,7 @@ class Saml2Service extends ExternalAuthService */ protected function shouldSyncGroups(): bool { - return $this->enabled && $this->config['user_to_groups'] !== false; + return $this->config['user_to_groups'] !== false; } /** @@ -248,7 +246,7 @@ class Saml2Service extends ExternalAuthService /** * Extract the details of a user from a SAML response. */ - public function getUserDetails(string $samlID, $samlAttributes): array + protected function getUserDetails(string $samlID, $samlAttributes): array { $emailAttr = $this->config['email_attribute']; $externalId = $this->getExternalId($samlAttributes, $samlID); @@ -329,7 +327,7 @@ class Saml2Service extends ExternalAuthService throw new SamlException(trans('errors.saml_email_exists', ['email' => $userDetails['email']])); } - $user = $this->user->forceCreate($userData); + $user = $this->user->newQuery()->forceCreate($userData); $this->userRepo->attachDefaultRole($user); $this->userRepo->downloadAndAssignUserAvatar($user); return $user; @@ -337,15 +335,15 @@ class Saml2Service extends ExternalAuthService /** * Get the user from the database for the specified details. + * @throws SamlException */ protected function getOrRegisterUser(array $userDetails): ?User { - $isRegisterEnabled = $this->config['auto_register'] === true; - $user = $this->user - ->where('external_auth_id', $userDetails['external_id']) + $user = $this->user->newQuery() + ->where('external_auth_id', '=', $userDetails['external_id']) ->first(); - if ($user === null && $isRegisterEnabled) { + if (is_null($user)) { $user = $this->registerUser($userDetails); } diff --git a/app/Config/auth.php b/app/Config/auth.php index 0be5aeee8..2afb10ec2 100644 --- a/app/Config/auth.php +++ b/app/Config/auth.php @@ -34,7 +34,11 @@ return [ ], 'ldap' => [ 'driver' => 'ldap-session', - 'provider' => 'external' + 'provider' => 'external', + ], + 'saml2' => [ + 'driver' => 'saml2-session', + 'provider' => 'external', ], 'api' => [ 'driver' => 'api-token', diff --git a/app/Config/saml2.php b/app/Config/saml2.php index 2f2ad14f1..5f2c1395b 100644 --- a/app/Config/saml2.php +++ b/app/Config/saml2.php @@ -4,10 +4,6 @@ return [ // Display name, shown to users, for SAML2 option 'name' => env('SAML2_NAME', 'SSO'), - // Toggle whether the SAML2 option is active - 'enabled' => env('SAML2_ENABLED', false), - // Enable registration via SAML2 authentication - 'auto_register' => env('SAML2_AUTO_REGISTER', true), // Dump user details after a login request for debugging purposes 'dump_user_details' => env('SAML2_DUMP_USER_DETAILS', false), diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 2302937cb..8116288ad 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -65,7 +65,6 @@ class LoginController extends Controller { $socialDrivers = $this->socialAuthService->getActiveDrivers(); $authMethod = config('auth.method'); - $samlEnabled = config('saml2.enabled') === true; if ($request->has('email')) { session()->flashInput([ @@ -77,7 +76,6 @@ class LoginController extends Controller return view('auth.login', [ 'socialDrivers' => $socialDrivers, 'authMethod' => $authMethod, - 'samlEnabled' => $samlEnabled, ]); } @@ -129,28 +127,16 @@ class LoginController extends Controller */ protected function validateLogin(Request $request) { - $rules = []; + $rules = ['password' => 'required|string']; $authMethod = config('auth.method'); if ($authMethod === 'standard') { - $rules = [ - 'email' => 'required|string|email', - 'password' => 'required|string' - ]; + $rules['email'] = 'required|email'; } if ($authMethod === 'ldap') { - $rules = [ - 'username' => 'required|string', - 'password' => 'required|string', - 'email' => 'email', - ]; - } - - if ($authMethod === 'saml2') { - $rules = [ - 'email' => 'email', - ]; + $rules['username'] = 'required|string'; + $rules['email'] = 'email'; } $request->validate($rules); @@ -178,10 +164,6 @@ class LoginController extends Controller */ public function logout(Request $request) { - if (config('saml2.enabled') && session()->get('last_login_type') === 'saml2') { - return redirect('/saml2/logout'); - } - $this->guard()->logout(); $request->session()->invalidate(); diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index c9c0c3ec5..8fb13d536 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -75,10 +75,8 @@ class RegisterController extends Controller { $this->registrationService->checkRegistrationAllowed(); $socialDrivers = $this->socialAuthService->getActiveDrivers(); - $samlEnabled = (config('saml2.enabled') === true) && (config('saml2.auto_register') === true); return view('auth.register', [ 'socialDrivers' => $socialDrivers, - 'samlEnabled' => $samlEnabled, ]); } diff --git a/app/Http/Controllers/Auth/Saml2Controller.php b/app/Http/Controllers/Auth/Saml2Controller.php index 863894128..72cf0e019 100644 --- a/app/Http/Controllers/Auth/Saml2Controller.php +++ b/app/Http/Controllers/Auth/Saml2Controller.php @@ -20,7 +20,8 @@ class Saml2Controller extends Controller // SAML2 access middleware $this->middleware(function ($request, $next) { - if (!config('saml2.enabled')) { + + if (config('auth.method') !== 'saml2') { $this->showPermissionError(); } diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index 0b299551a..a885628f3 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -6,6 +6,7 @@ use Auth; use BookStack\Api\ApiTokenGuard; use BookStack\Auth\Access\ExternalBaseUserProvider; use BookStack\Auth\Access\Guards\LdapSessionGuard; +use BookStack\Auth\Access\Guards\Saml2SessionGuard; use BookStack\Auth\Access\LdapService; use BookStack\Auth\UserRepo; use Illuminate\Support\ServiceProvider; @@ -33,6 +34,16 @@ class AuthServiceProvider extends ServiceProvider $app[UserRepo::class] ); }); + + Auth::extend('saml2-session', function ($app, $name, array $config) { + $provider = Auth::createUserProvider($config['provider']); + return new Saml2SessionGuard( + $name, + $provider, + $this->app['session.store'], + $app[UserRepo::class] + ); + }); } /** diff --git a/resources/views/auth/forms/login/ldap.blade.php b/resources/views/auth/forms/login/ldap.blade.php index 2699fda00..12592d492 100644 --- a/resources/views/auth/forms/login/ldap.blade.php +++ b/resources/views/auth/forms/login/ldap.blade.php @@ -1,19 +1,30 @@ -
- - @include('form.text', ['name' => 'username', 'autofocus' => true]) -
+
+ {!! csrf_field() !!} -@if(session('request-email', false) === true) -
- - @include('form.text', ['name' => 'email']) - - {{ trans('auth.ldap_email_hint') }} - +
+
+ + @include('form.text', ['name' => 'username', 'autofocus' => true]) +
+ + @if(session('request-email', false) === true) +
+ + @include('form.text', ['name' => 'email']) + {{ trans('auth.ldap_email_hint') }} +
+ @endif + +
+ + @include('form.password', ['name' => 'password']) +
-@endif -
- - @include('form.password', ['name' => 'password']) -
\ No newline at end of file +
+
+ +
+
+ + \ No newline at end of file diff --git a/resources/views/auth/forms/login/saml2.blade.php b/resources/views/auth/forms/login/saml2.blade.php index 12592d492..aa1913e31 100644 --- a/resources/views/auth/forms/login/saml2.blade.php +++ b/resources/views/auth/forms/login/saml2.blade.php @@ -1,30 +1,11 @@ -
+ {!! csrf_field() !!} -
-
- - @include('form.text', ['name' => 'username', 'autofocus' => true]) -
- - @if(session('request-email', false) === true) -
- - @include('form.text', ['name' => 'email']) - {{ trans('auth.ldap_email_hint') }} -
- @endif - -
- - @include('form.password', ['name' => 'password']) -
-
- -
-
- -
+
+
\ 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 52fae3750..87603e2cb 100644 --- a/resources/views/auth/forms/login/standard.blade.php +++ b/resources/views/auth/forms/login/standard.blade.php @@ -1,12 +1,36 @@ -
- - @include('form.text', ['name' => 'email', 'autofocus' => true]) -
+
+ {!! csrf_field() !!} + +
+
+ + @include('form.text', ['name' => 'email', 'autofocus' => true]) +
+ +
+ + @include('form.password', ['name' => 'password']) + +
+
+ +
+
+ @include('components.custom-checkbox', [ + 'name' => 'remember', + 'checked' => false, + 'value' => 'on', + 'label' => trans('auth.remember_me'), + ]) +
+ +
+ +
+
+ +
+ -
- - @include('form.password', ['name' => 'password']) - - {{ trans('auth.forgot_password') }} - -
diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index 098ce2100..0a21a0f62 100644 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -9,29 +9,7 @@

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

-
- {!! csrf_field() !!} - -
- @include('auth.forms.login.' . $authMethod) -
- -
-
- @include('components.custom-checkbox', [ - 'name' => 'remember', - 'checked' => false, - 'value' => 'on', - 'label' => trans('auth.remember_me'), - ]) -
- -
- -
-
- -
+ @include('auth.forms.login.' . $authMethod) @if(count($socialDrivers) > 0)
@@ -45,17 +23,7 @@ @endforeach @endif - @if($samlEnabled) -
- - @endif - - @if(setting('registration-enabled') && config('auth.method') !== 'ldap') + @if(setting('registration-enabled') && config('auth.method') === 'standard')

{{ trans('auth.dont_have_account') }} diff --git a/resources/views/auth/register.blade.php b/resources/views/auth/register.blade.php index 8dd6592c1..1625ebc4c 100644 --- a/resources/views/auth/register.blade.php +++ b/resources/views/auth/register.blade.php @@ -50,15 +50,6 @@ @endforeach @endif - @if($samlEnabled) -
- - @endif
@stop diff --git a/resources/views/common/header.blade.php b/resources/views/common/header.blade.php index b06036031..7c837ec29 100644 --- a/resources/views/common/header.blade.php +++ b/resources/views/common/header.blade.php @@ -42,7 +42,7 @@ @endif @if(!signedInUser()) - @if(setting('registration-enabled') && config('auth.method') !== 'ldap') + @if(setting('registration-enabled') && config('auth.method') === 'standard') @icon('new-user') {{ trans('auth.sign_up') }} @endif @icon('login') {{ trans('auth.log_in') }} @@ -64,7 +64,11 @@ id}") }}">@icon('edit'){{ trans('common.edit_profile') }}
  • - @icon('logout'){{ trans('auth.logout') }} + @if(config('auth.method') === 'saml2') + @icon('logout'){{ trans('auth.logout') }} + @else + @icon('logout'){{ trans('auth.logout') }} + @endif
  • diff --git a/resources/views/settings/roles/form.blade.php b/resources/views/settings/roles/form.blade.php index 1fbc80b1f..ed57ad944 100644 --- a/resources/views/settings/roles/form.blade.php +++ b/resources/views/settings/roles/form.blade.php @@ -19,7 +19,7 @@ @include('form.text', ['name' => 'description'])
    - @if(config('auth.method') === 'ldap' || config('saml2.enabled') === true) + @if(config('auth.method') === 'ldap' || config('auth.method') === 'saml2')
    @include('form.text', ['name' => 'external_auth_id']) diff --git a/resources/views/users/form.blade.php b/resources/views/users/form.blade.php index 6eafd43bc..df3d06c2f 100644 --- a/resources/views/users/form.blade.php +++ b/resources/views/users/form.blade.php @@ -25,7 +25,7 @@
    -@if(($authMethod === 'ldap' || config('saml2.enabled') === true) && userCan('users-manage')) +@if(($authMethod === 'ldap' || $authMethod === 'saml2') && userCan('users-manage'))
    diff --git a/routes/web.php b/routes/web.php index eafad6489..3aa95dd68 100644 --- a/routes/web.php +++ b/routes/web.php @@ -225,7 +225,7 @@ Route::get('/register/confirm/{token}', 'Auth\ConfirmEmailController@confirm'); Route::post('/register', 'Auth\RegisterController@postRegister'); // SAML routes -Route::get('/saml2/login', 'Auth\Saml2Controller@login'); +Route::post('/saml2/login', 'Auth\Saml2Controller@login'); Route::get('/saml2/logout', 'Auth\Saml2Controller@logout'); Route::get('/saml2/metadata', 'Auth\Saml2Controller@metadata'); Route::get('/saml2/sls', 'Auth\Saml2Controller@sls'); From 5d08ec3cef1d9a2a1c96f47371f94f0762a49075 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 2 Feb 2020 12:00:41 +0000 Subject: [PATCH 170/191] Fixed failing tests caused by auth changes --- app/Config/auth.php | 2 +- .../views/auth/forms/login/ldap.blade.php | 4 +- tests/Auth/LdapTest.php | 111 +++++++++--------- tests/Auth/Saml2Test.php | 42 ++----- 4 files changed, 71 insertions(+), 88 deletions(-) diff --git a/app/Config/auth.php b/app/Config/auth.php index 2afb10ec2..66793308b 100644 --- a/app/Config/auth.php +++ b/app/Config/auth.php @@ -51,7 +51,7 @@ return [ // mechanisms used by this application to persist your user's data. 'providers' => [ 'users' => [ - 'driver' => env('AUTH_METHOD', 'standard') === 'standard' ? 'eloquent' : env('AUTH_METHOD'), + 'driver' => 'eloquent', 'model' => \BookStack\Auth\User::class, ], 'external' => [ diff --git a/resources/views/auth/forms/login/ldap.blade.php b/resources/views/auth/forms/login/ldap.blade.php index 12592d492..92eba80e8 100644 --- a/resources/views/auth/forms/login/ldap.blade.php +++ b/resources/views/auth/forms/login/ldap.blade.php @@ -19,10 +19,8 @@ @include('form.password', ['name' => 'password'])
    -
    -
    -
    +
    diff --git a/tests/Auth/LdapTest.php b/tests/Auth/LdapTest.php index 5d7bbfb1e..8bf9475cc 100644 --- a/tests/Auth/LdapTest.php +++ b/tests/Auth/LdapTest.php @@ -1,4 +1,5 @@ set([ 'auth.method' => 'ldap', + 'auth.defaults.guard' => 'ldap', 'services.ldap.base_dn' => 'dc=ldap,dc=local', 'services.ldap.email_attribute' => 'mail', 'services.ldap.display_name_attribute' => 'cn', 'services.ldap.id_attribute' => 'uid', 'services.ldap.user_to_groups' => false, - 'auth.providers.users.driver' => 'ldap', + 'services.ldap.version' => '3', + 'services.ldap.user_filter' => '(&(uid=${user}))', + 'services.ldap.follow_referrals' => false, + 'services.ldap.tls_insecure' => false, ]); $this->mockLdap = \Mockery::mock(Ldap::class); $this->app[Ldap::class] = $this->mockLdap; @@ -60,16 +65,16 @@ class LdapTest extends BrowserKitTest { $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId); $this->mockLdap->shouldReceive('setVersion')->once(); - $this->mockLdap->shouldReceive('setOption')->times(4); - $this->mockLdap->shouldReceive('searchAndGetEntries')->times(4) + $this->mockLdap->shouldReceive('setOption')->times(2); + $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2) ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) ->andReturn(['count' => 1, 0 => [ 'uid' => [$this->mockUser->name], 'cn' => [$this->mockUser->name], 'dn' => ['dc=test' . config('services.ldap.base_dn')] ]]); - $this->mockLdap->shouldReceive('bind')->times(6)->andReturn(true); - $this->mockEscapes(4); + $this->mockLdap->shouldReceive('bind')->times(4)->andReturn(true); + $this->mockEscapes(2); $this->mockUserLogin() ->seePageIs('/login')->see('Please enter an email to use for this account.'); @@ -86,16 +91,16 @@ class LdapTest extends BrowserKitTest $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId); $this->mockLdap->shouldReceive('setVersion')->once(); $ldapDn = 'cn=test-user,dc=test' . config('services.ldap.base_dn'); - $this->mockLdap->shouldReceive('setOption')->times(2); - $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2) + $this->mockLdap->shouldReceive('setOption')->times(1); + $this->mockLdap->shouldReceive('searchAndGetEntries')->times(1) ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) ->andReturn(['count' => 1, 0 => [ 'cn' => [$this->mockUser->name], 'dn' => $ldapDn, 'mail' => [$this->mockUser->email] ]]); - $this->mockLdap->shouldReceive('bind')->times(3)->andReturn(true); - $this->mockEscapes(2); + $this->mockLdap->shouldReceive('bind')->times(2)->andReturn(true); + $this->mockEscapes(1); $this->mockUserLogin() ->seePageIs('/') @@ -109,8 +114,8 @@ class LdapTest extends BrowserKitTest $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId); $this->mockLdap->shouldReceive('setVersion')->once(); $ldapDn = 'cn=test-user,dc=test' . config('services.ldap.base_dn'); - $this->mockLdap->shouldReceive('setOption')->times(2); - $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2) + $this->mockLdap->shouldReceive('setOption')->times(1); + $this->mockLdap->shouldReceive('searchAndGetEntries')->times(1) ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) ->andReturn(['count' => 1, 0 => [ 'cn' => [$this->mockUser->name], @@ -120,8 +125,8 @@ class LdapTest extends BrowserKitTest ]]); - $this->mockLdap->shouldReceive('bind')->times(3)->andReturn(true); - $this->mockEscapes(2); + $this->mockLdap->shouldReceive('bind')->times(2)->andReturn(true); + $this->mockEscapes(1); $this->mockUserLogin() ->seePageIs('/') @@ -133,16 +138,16 @@ class LdapTest extends BrowserKitTest { $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId); $this->mockLdap->shouldReceive('setVersion')->once(); - $this->mockLdap->shouldReceive('setOption')->times(2); - $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2) + $this->mockLdap->shouldReceive('setOption')->times(1); + $this->mockLdap->shouldReceive('searchAndGetEntries')->times(1) ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) ->andReturn(['count' => 1, 0 => [ 'uid' => [$this->mockUser->name], 'cn' => [$this->mockUser->name], 'dn' => ['dc=test' . config('services.ldap.base_dn')] ]]); - $this->mockLdap->shouldReceive('bind')->times(3)->andReturn(true, true, false); - $this->mockEscapes(2); + $this->mockLdap->shouldReceive('bind')->times(2)->andReturn(true, false); + $this->mockEscapes(1); $this->mockUserLogin() ->seePageIs('/login')->see('These credentials do not match our records.') @@ -201,10 +206,10 @@ class LdapTest extends BrowserKitTest 'services.ldap.group_attribute' => 'memberOf', 'services.ldap.remove_from_groups' => false, ]); - $this->mockLdap->shouldReceive('connect')->times(2)->andReturn($this->resourceId); - $this->mockLdap->shouldReceive('setVersion')->times(2); - $this->mockLdap->shouldReceive('setOption')->times(5); - $this->mockLdap->shouldReceive('searchAndGetEntries')->times(5) + $this->mockLdap->shouldReceive('connect')->times(1)->andReturn($this->resourceId); + $this->mockLdap->shouldReceive('setVersion')->times(1); + $this->mockLdap->shouldReceive('setOption')->times(4); + $this->mockLdap->shouldReceive('searchAndGetEntries')->times(4) ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) ->andReturn(['count' => 1, 0 => [ 'uid' => [$this->mockUser->name], @@ -217,8 +222,8 @@ class LdapTest extends BrowserKitTest 1 => "cn=ldaptester-second,ou=groups,dc=example,dc=com", ] ]]); - $this->mockLdap->shouldReceive('bind')->times(6)->andReturn(true); - $this->mockEscapes(5); + $this->mockLdap->shouldReceive('bind')->times(5)->andReturn(true); + $this->mockEscapes(4); $this->mockExplodes(6); $this->mockUserLogin()->seePageIs('/'); @@ -250,10 +255,10 @@ class LdapTest extends BrowserKitTest 'services.ldap.group_attribute' => 'memberOf', 'services.ldap.remove_from_groups' => true, ]); - $this->mockLdap->shouldReceive('connect')->times(2)->andReturn($this->resourceId); - $this->mockLdap->shouldReceive('setVersion')->times(2); - $this->mockLdap->shouldReceive('setOption')->times(4); - $this->mockLdap->shouldReceive('searchAndGetEntries')->times(4) + $this->mockLdap->shouldReceive('connect')->times(1)->andReturn($this->resourceId); + $this->mockLdap->shouldReceive('setVersion')->times(1); + $this->mockLdap->shouldReceive('setOption')->times(3); + $this->mockLdap->shouldReceive('searchAndGetEntries')->times(3) ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) ->andReturn(['count' => 1, 0 => [ 'uid' => [$this->mockUser->name], @@ -265,8 +270,8 @@ class LdapTest extends BrowserKitTest 0 => "cn=ldaptester,ou=groups,dc=example,dc=com", ] ]]); - $this->mockLdap->shouldReceive('bind')->times(5)->andReturn(true); - $this->mockEscapes(4); + $this->mockLdap->shouldReceive('bind')->times(4)->andReturn(true); + $this->mockEscapes(3); $this->mockExplodes(2); $this->mockUserLogin()->seePageIs('/'); @@ -299,10 +304,10 @@ class LdapTest extends BrowserKitTest 'services.ldap.group_attribute' => 'memberOf', 'services.ldap.remove_from_groups' => true, ]); - $this->mockLdap->shouldReceive('connect')->times(2)->andReturn($this->resourceId); - $this->mockLdap->shouldReceive('setVersion')->times(2); - $this->mockLdap->shouldReceive('setOption')->times(4); - $this->mockLdap->shouldReceive('searchAndGetEntries')->times(4) + $this->mockLdap->shouldReceive('connect')->times(1)->andReturn($this->resourceId); + $this->mockLdap->shouldReceive('setVersion')->times(1); + $this->mockLdap->shouldReceive('setOption')->times(3); + $this->mockLdap->shouldReceive('searchAndGetEntries')->times(3) ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) ->andReturn(['count' => 1, 0 => [ 'uid' => [$this->mockUser->name], @@ -314,8 +319,8 @@ class LdapTest extends BrowserKitTest 0 => "cn=ex-auth-a,ou=groups,dc=example,dc=com", ] ]]); - $this->mockLdap->shouldReceive('bind')->times(5)->andReturn(true); - $this->mockEscapes(4); + $this->mockLdap->shouldReceive('bind')->times(4)->andReturn(true); + $this->mockEscapes(3); $this->mockExplodes(2); $this->mockUserLogin()->seePageIs('/'); @@ -344,10 +349,10 @@ class LdapTest extends BrowserKitTest 'services.ldap.group_attribute' => 'memberOf', 'services.ldap.remove_from_groups' => true, ]); - $this->mockLdap->shouldReceive('connect')->times(2)->andReturn($this->resourceId); - $this->mockLdap->shouldReceive('setVersion')->times(2); - $this->mockLdap->shouldReceive('setOption')->times(5); - $this->mockLdap->shouldReceive('searchAndGetEntries')->times(5) + $this->mockLdap->shouldReceive('connect')->times(1)->andReturn($this->resourceId); + $this->mockLdap->shouldReceive('setVersion')->times(1); + $this->mockLdap->shouldReceive('setOption')->times(4); + $this->mockLdap->shouldReceive('searchAndGetEntries')->times(4) ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) ->andReturn(['count' => 1, 0 => [ 'uid' => [$this->mockUser->name], @@ -360,8 +365,8 @@ class LdapTest extends BrowserKitTest 1 => "cn=ldaptester-second,ou=groups,dc=example,dc=com", ] ]]); - $this->mockLdap->shouldReceive('bind')->times(6)->andReturn(true); - $this->mockEscapes(5); + $this->mockLdap->shouldReceive('bind')->times(5)->andReturn(true); + $this->mockEscapes(4); $this->mockExplodes(6); $this->mockUserLogin()->seePageIs('/'); @@ -385,8 +390,8 @@ class LdapTest extends BrowserKitTest $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId); $this->mockLdap->shouldReceive('setVersion')->once(); - $this->mockLdap->shouldReceive('setOption')->times(4); - $this->mockLdap->shouldReceive('searchAndGetEntries')->times(4) + $this->mockLdap->shouldReceive('setOption')->times(2); + $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2) ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) ->andReturn(['count' => 1, 0 => [ 'uid' => [$this->mockUser->name], @@ -394,8 +399,8 @@ class LdapTest extends BrowserKitTest 'dn' => ['dc=test' . config('services.ldap.base_dn')], 'displayname' => 'displayNameAttribute' ]]); - $this->mockLdap->shouldReceive('bind')->times(6)->andReturn(true); - $this->mockEscapes(4); + $this->mockLdap->shouldReceive('bind')->times(4)->andReturn(true); + $this->mockEscapes(2); $this->mockUserLogin() ->seePageIs('/login')->see('Please enter an email to use for this account.'); @@ -415,16 +420,16 @@ class LdapTest extends BrowserKitTest $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId); $this->mockLdap->shouldReceive('setVersion')->once(); - $this->mockLdap->shouldReceive('setOption')->times(4); - $this->mockLdap->shouldReceive('searchAndGetEntries')->times(4) + $this->mockLdap->shouldReceive('setOption')->times(2); + $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2) ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) ->andReturn(['count' => 1, 0 => [ 'uid' => [$this->mockUser->name], 'cn' => [$this->mockUser->name], 'dn' => ['dc=test' . config('services.ldap.base_dn')] ]]); - $this->mockLdap->shouldReceive('bind')->times(6)->andReturn(true); - $this->mockEscapes(4); + $this->mockLdap->shouldReceive('bind')->times(4)->andReturn(true); + $this->mockEscapes(2); $this->mockUserLogin() ->seePageIs('/login')->see('Please enter an email to use for this account.'); @@ -444,14 +449,14 @@ class LdapTest extends BrowserKitTest // Standard mocks $this->mockLdap->shouldReceive('setVersion')->once(); - $this->mockLdap->shouldReceive('setOption')->times(2); - $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2)->andReturn(['count' => 1, 0 => [ + $this->mockLdap->shouldReceive('setOption')->times(1); + $this->mockLdap->shouldReceive('searchAndGetEntries')->times(1)->andReturn(['count' => 1, 0 => [ 'uid' => [$this->mockUser->name], 'cn' => [$this->mockUser->name], 'dn' => ['dc=test' . config('services.ldap.base_dn')] ]]); - $this->mockLdap->shouldReceive('bind')->times(3)->andReturn(true); - $this->mockEscapes(2); + $this->mockLdap->shouldReceive('bind')->times(2)->andReturn(true); + $this->mockEscapes(1); $this->mockLdap->shouldReceive('connect')->once() ->with($expectedHost, $expectedPort)->andReturn($this->resourceId); diff --git a/tests/Auth/Saml2Test.php b/tests/Auth/Saml2Test.php index 45b6efa07..2cecad8bf 100644 --- a/tests/Auth/Saml2Test.php +++ b/tests/Auth/Saml2Test.php @@ -11,9 +11,9 @@ class Saml2Test extends TestCase parent::setUp(); // Set default config for SAML2 config()->set([ + 'auth.method' => 'saml2', + 'auth.defaults.guard' => 'saml2', 'saml2.name' => 'SingleSignOn-Testing', - 'saml2.enabled' => true, - 'saml2.auto_register' => true, 'saml2.email_attribute' => 'email', 'saml2.display_name_attributes' => ['first_name', 'last_name'], 'saml2.external_id_attribute' => 'uid', @@ -53,27 +53,12 @@ class Saml2Test extends TestCase { $req = $this->get('/login'); $req->assertSeeText('SingleSignOn-Testing'); - $req->assertElementExists('a[href$="/saml2/login"]'); - } - - public function test_login_option_shows_on_register_page_only_when_auto_register_enabled() - { - $this->setSettings(['app-public' => 'true', 'registration-enabled' => 'true']); - - $req = $this->get('/register'); - $req->assertSeeText('SingleSignOn-Testing'); - $req->assertElementExists('a[href$="/saml2/login"]'); - - config()->set(['saml2.auto_register' => false]); - - $req = $this->get('/register'); - $req->assertDontSeeText('SingleSignOn-Testing'); - $req->assertElementNotExists('a[href$="/saml2/login"]'); + $req->assertElementExists('form[action$="/saml2/login"][method=POST] button'); } public function test_login() { - $req = $this->get('/saml2/login'); + $req = $this->post('/saml2/login'); $redirect = $req->headers->get('location'); $this->assertStringStartsWith('http://saml.local/saml2/idp/SSOService.php', $redirect, 'Login redirects to SSO location'); @@ -138,20 +123,15 @@ class Saml2Test extends TestCase }); } - public function test_logout_redirects_to_saml_logout_when_active_saml_session() + public function test_logout_link_directs_to_saml_path() { config()->set([ 'saml2.onelogin.strict' => false, ]); - $this->withPost(['SAMLResponse' => $this->acsPostData], function () { - $acsPost = $this->post('/saml2/acs'); - $lastLoginType = session()->get('last_login_type'); - $this->assertEquals('saml2', $lastLoginType); - - $req = $this->get('/logout'); - $req->assertRedirect('/saml2/logout'); - }); + $resp = $this->actingAs($this->getEditor())->get('/'); + $resp->assertElementExists('a[href$="/saml2/logout"]'); + $resp->assertElementContains('a[href$="/saml2/logout"]', 'Logout'); } public function test_logout_sls_flow() @@ -235,8 +215,8 @@ class Saml2Test extends TestCase public function test_saml_routes_are_only_active_if_saml_enabled() { - config()->set(['saml2.enabled' => false]); - $getRoutes = ['/login', '/logout', '/metadata', '/sls']; + config()->set(['auth.method' => 'standard']); + $getRoutes = ['/logout', '/metadata', '/sls']; foreach ($getRoutes as $route) { $req = $this->get('/saml2' . $route); $req->assertRedirect('/'); @@ -245,7 +225,7 @@ class Saml2Test extends TestCase session()->flush(); } - $postRoutes = ['/acs']; + $postRoutes = ['/login', '/acs']; foreach ($postRoutes as $route) { $req = $this->post('/saml2' . $route); $req->assertRedirect('/'); From e6c6de0848caab863f410bbf9a74312392db9dcd Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 2 Feb 2020 13:10:21 +0000 Subject: [PATCH 171/191] Simplified guard names and rolled out guard route checks - Included tests to cover for LDAP and SAML - Updated wording for external auth id option. - Updated 'assertPermissionError' test case to be usable in BrowserKitTests --- app/Config/auth.php | 6 +-- .../Auth/ForgotPasswordController.php | 1 + app/Http/Controllers/Auth/LoginController.php | 14 ++--- .../Controllers/Auth/RegisterController.php | 3 +- .../Auth/ResetPasswordController.php | 1 + app/Http/Controllers/Auth/Saml2Controller.php | 11 +--- .../Controllers/Auth/UserInviteController.php | 16 ++---- app/Http/Kernel.php | 5 +- app/Http/Middleware/CheckGuard.php | 27 ++++++++++ app/Http/Middleware/PermissionMiddleware.php | 2 +- resources/lang/en/settings.php | 2 +- routes/web.php | 4 +- tests/Api/ApiAuthTest.php | 8 +-- tests/Auth/LdapTest.php | 33 ++++++++++++ tests/Auth/Saml2Test.php | 52 ++++++++++++++++--- tests/SharedTestHelpers.php | 15 ++++++ tests/TestCase.php | 13 ----- 17 files changed, 146 insertions(+), 67 deletions(-) create mode 100644 app/Http/Middleware/CheckGuard.php diff --git a/app/Config/auth.php b/app/Config/auth.php index 66793308b..51b152ff1 100644 --- a/app/Config/auth.php +++ b/app/Config/auth.php @@ -11,14 +11,14 @@ return [ // Method of authentication to use - // Options: standard, ldap + // Options: standard, ldap, saml2 'method' => env('AUTH_METHOD', 'standard'), // Authentication Defaults // This option controls the default authentication "guard" and password // reset options for your application. 'defaults' => [ - 'guard' => env('AUTH_METHOD', 'standard') === 'standard' ? 'web' : env('AUTH_METHOD'), + 'guard' => env('AUTH_METHOD', 'standard'), 'passwords' => 'users', ], @@ -28,7 +28,7 @@ return [ // mechanisms used by this application to persist your user's data. // Supported drivers: "session", "api-token", "ldap-session" 'guards' => [ - 'web' => [ + 'standard' => [ 'driver' => 'session', 'provider' => 'users', ], diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php index a3c0433a5..a60fcc1c9 100644 --- a/app/Http/Controllers/Auth/ForgotPasswordController.php +++ b/app/Http/Controllers/Auth/ForgotPasswordController.php @@ -30,6 +30,7 @@ class ForgotPasswordController extends Controller public function __construct() { $this->middleware('guest'); + $this->middleware('guard:standard'); parent::__construct(); } diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 8116288ad..4292ad6dd 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -38,7 +38,9 @@ class LoginController extends Controller */ public function __construct(SocialAuthService $socialAuthService) { - $this->middleware('guest', ['only' => ['getLogin', 'postLogin']]); + $this->middleware('guest', ['only' => ['getLogin', 'login']]); + $this->middleware('guard:standard,ldap', ['only' => ['login', 'logout']]); + $this->socialAuthService = $socialAuthService; $this->redirectPath = url('/'); $this->redirectAfterLogout = url('/login'); @@ -159,14 +161,4 @@ class LoginController extends Controller return redirect('/login'); } - /** - * Log the user out of the application. - */ - public function logout(Request $request) - { - $this->guard()->logout(); - $request->session()->invalidate(); - - return $this->loggedOut($request) ?: redirect('/'); - } } diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 8fb13d536..56ec66bff 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -43,7 +43,8 @@ class RegisterController extends Controller */ public function __construct(SocialAuthService $socialAuthService, RegistrationService $registrationService) { - $this->middleware('guest')->only(['getRegister', 'postRegister']); + $this->middleware('guest'); + $this->middleware('guard:standard'); $this->socialAuthService = $socialAuthService; $this->registrationService = $registrationService; diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php index 4d98eca59..214647cd5 100644 --- a/app/Http/Controllers/Auth/ResetPasswordController.php +++ b/app/Http/Controllers/Auth/ResetPasswordController.php @@ -31,6 +31,7 @@ class ResetPasswordController extends Controller public function __construct() { $this->middleware('guest'); + $this->middleware('guard:standard'); parent::__construct(); } diff --git a/app/Http/Controllers/Auth/Saml2Controller.php b/app/Http/Controllers/Auth/Saml2Controller.php index 72cf0e019..8c0cb21d2 100644 --- a/app/Http/Controllers/Auth/Saml2Controller.php +++ b/app/Http/Controllers/Auth/Saml2Controller.php @@ -17,16 +17,7 @@ class Saml2Controller extends Controller { parent::__construct(); $this->samlService = $samlService; - - // SAML2 access middleware - $this->middleware(function ($request, $next) { - - if (config('auth.method') !== 'saml2') { - $this->showPermissionError(); - } - - return $next($request); - }); + $this->middleware('guard:saml2'); } /** diff --git a/app/Http/Controllers/Auth/UserInviteController.php b/app/Http/Controllers/Auth/UserInviteController.php index c361b0a9b..c61b1c42b 100644 --- a/app/Http/Controllers/Auth/UserInviteController.php +++ b/app/Http/Controllers/Auth/UserInviteController.php @@ -8,11 +8,9 @@ use BookStack\Exceptions\UserTokenExpiredException; use BookStack\Exceptions\UserTokenNotFoundException; use BookStack\Http\Controllers\Controller; use Exception; -use Illuminate\Contracts\View\Factory; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Routing\Redirector; -use Illuminate\View\View; class UserInviteController extends Controller { @@ -21,22 +19,20 @@ class UserInviteController extends Controller /** * Create a new controller instance. - * - * @param UserInviteService $inviteService - * @param UserRepo $userRepo */ public function __construct(UserInviteService $inviteService, UserRepo $userRepo) { + $this->middleware('guest'); + $this->middleware('guard:standard'); + $this->inviteService = $inviteService; $this->userRepo = $userRepo; - $this->middleware('guest'); + parent::__construct(); } /** * Show the page for the user to set the password for their account. - * @param string $token - * @return Factory|View|RedirectResponse * @throws Exception */ public function showSetPassword(string $token) @@ -54,9 +50,6 @@ class UserInviteController extends Controller /** * Sets the password for an invited user and then grants them access. - * @param Request $request - * @param string $token - * @return RedirectResponse|Redirector * @throws Exception */ public function setPassword(Request $request, string $token) @@ -85,7 +78,6 @@ class UserInviteController extends Controller /** * Check and validate the exception thrown when checking an invite token. - * @param Exception $exception * @return RedirectResponse|Redirector * @throws Exception */ diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index c2016281a..4517deb90 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -48,7 +48,8 @@ class Kernel extends HttpKernel 'auth' => \BookStack\Http\Middleware\Authenticate::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \BookStack\Http\Middleware\RedirectIfAuthenticated::class, - 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, - 'perm' => \BookStack\Http\Middleware\PermissionMiddleware::class + 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, + 'perm' => \BookStack\Http\Middleware\PermissionMiddleware::class, + 'guard' => \BookStack\Http\Middleware\CheckGuard::class, ]; } diff --git a/app/Http/Middleware/CheckGuard.php b/app/Http/Middleware/CheckGuard.php new file mode 100644 index 000000000..cc73ea68d --- /dev/null +++ b/app/Http/Middleware/CheckGuard.php @@ -0,0 +1,27 @@ +flash('error', trans('errors.permission')); + return redirect('/'); + } + + return $next($request); + } +} diff --git a/app/Http/Middleware/PermissionMiddleware.php b/app/Http/Middleware/PermissionMiddleware.php index 28ffff643..d0bb4f79e 100644 --- a/app/Http/Middleware/PermissionMiddleware.php +++ b/app/Http/Middleware/PermissionMiddleware.php @@ -19,7 +19,7 @@ class PermissionMiddleware { if (!$request->user() || !$request->user()->can($permission)) { - Session::flash('error', trans('errors.permission')); + session()->flash('error', trans('errors.permission')); return redirect()->back(); } diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index b36fdda7a..8c9675f09 100755 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -131,7 +131,7 @@ return [ 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', 'users_send_invite_option' => 'Send user invite email', 'users_external_auth_id' => 'External Authentication ID', - 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your LDAP system.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Only fill the below if you would like to change your password.', 'users_system_public' => 'This user represents any guest users that visit your instance. It cannot be used to log in but is assigned automatically.', 'users_delete' => 'Delete User', diff --git a/routes/web.php b/routes/web.php index 3aa95dd68..90261e1ac 100644 --- a/routes/web.php +++ b/routes/web.php @@ -210,7 +210,9 @@ Route::group(['middleware' => 'auth'], function () { // Social auth routes Route::get('/login/service/{socialDriver}', 'Auth\SocialController@getSocialLogin'); Route::get('/login/service/{socialDriver}/callback', 'Auth\SocialController@socialCallback'); -Route::get('/login/service/{socialDriver}/detach', 'Auth\SocialController@detachSocialAccount'); +Route::group(['middleware' => 'auth'], function () { + Route::get('/login/service/{socialDriver}/detach', 'Auth\SocialController@detachSocialAccount'); +}); Route::get('/register/service/{socialDriver}', 'Auth\SocialController@socialRegister'); // Login/Logout routes diff --git a/tests/Api/ApiAuthTest.php b/tests/Api/ApiAuthTest.php index 2ab81814b..1f283753a 100644 --- a/tests/Api/ApiAuthTest.php +++ b/tests/Api/ApiAuthTest.php @@ -20,7 +20,7 @@ class ApiAuthTest extends TestCase $resp = $this->get($this->endpoint); $resp->assertStatus(401); - $this->actingAs($viewer, 'web'); + $this->actingAs($viewer, 'standard'); $resp = $this->get($this->endpoint); $resp->assertStatus(200); @@ -72,11 +72,11 @@ class ApiAuthTest extends TestCase public function test_api_access_permission_required_to_access_api_with_session_auth() { $editor = $this->getEditor(); - $this->actingAs($editor, 'web'); + $this->actingAs($editor, 'standard'); $resp = $this->get($this->endpoint); $resp->assertStatus(200); - auth('web')->logout(); + auth('standard')->logout(); $accessApiPermission = RolePermission::getByName('access-api'); $editorRole = $this->getEditor()->roles()->first(); @@ -84,7 +84,7 @@ class ApiAuthTest extends TestCase $editor = User::query()->where('id', '=', $editor->id)->first(); - $this->actingAs($editor, 'web'); + $this->actingAs($editor, 'standard'); $resp = $this->get($this->endpoint); $resp->assertStatus(403); $resp->assertJson($this->errorResponse("The owner of the used API token does not have permission to make API calls", 403)); diff --git a/tests/Auth/LdapTest.php b/tests/Auth/LdapTest.php index 8bf9475cc..92ff4a829 100644 --- a/tests/Auth/LdapTest.php +++ b/tests/Auth/LdapTest.php @@ -478,4 +478,37 @@ class LdapTest extends BrowserKitTest { $this->checkLdapReceivesCorrectDetails('ldap.bookstack.com', 'ldap.bookstack.com', 389); } + + public function test_forgot_password_routes_inaccessible() + { + $resp = $this->get('/password/email'); + $this->assertPermissionError($resp); + + $resp = $this->post('/password/email'); + $this->assertPermissionError($resp); + + $resp = $this->get('/password/reset/abc123'); + $this->assertPermissionError($resp); + + $resp = $this->post('/password/reset'); + $this->assertPermissionError($resp); + } + + public function test_user_invite_routes_inaccessible() + { + $resp = $this->get('/register/invite/abc123'); + $this->assertPermissionError($resp); + + $resp = $this->post('/register/invite/abc123'); + $this->assertPermissionError($resp); + } + + public function test_user_register_routes_inaccessible() + { + $resp = $this->get('/register'); + $this->assertPermissionError($resp); + + $resp = $this->post('/register'); + $this->assertPermissionError($resp); + } } diff --git a/tests/Auth/Saml2Test.php b/tests/Auth/Saml2Test.php index 2cecad8bf..b3e6bd41b 100644 --- a/tests/Auth/Saml2Test.php +++ b/tests/Auth/Saml2Test.php @@ -219,22 +219,58 @@ class Saml2Test extends TestCase $getRoutes = ['/logout', '/metadata', '/sls']; foreach ($getRoutes as $route) { $req = $this->get('/saml2' . $route); - $req->assertRedirect('/'); - $error = session()->get('error'); - $this->assertStringStartsWith('You do not have permission to access', $error); - session()->flush(); + $this->assertPermissionError($req); } $postRoutes = ['/login', '/acs']; foreach ($postRoutes as $route) { $req = $this->post('/saml2' . $route); - $req->assertRedirect('/'); - $error = session()->get('error'); - $this->assertStringStartsWith('You do not have permission to access', $error); - session()->flush(); + $this->assertPermissionError($req); } } + public function test_forgot_password_routes_inaccessible() + { + $resp = $this->get('/password/email'); + $this->assertPermissionError($resp); + + $resp = $this->post('/password/email'); + $this->assertPermissionError($resp); + + $resp = $this->get('/password/reset/abc123'); + $this->assertPermissionError($resp); + + $resp = $this->post('/password/reset'); + $this->assertPermissionError($resp); + } + + public function test_standard_login_routes_inaccessible() + { + $resp = $this->post('/login'); + $this->assertPermissionError($resp); + + $resp = $this->get('/logout'); + $this->assertPermissionError($resp); + } + + public function test_user_invite_routes_inaccessible() + { + $resp = $this->get('/register/invite/abc123'); + $this->assertPermissionError($resp); + + $resp = $this->post('/register/invite/abc123'); + $this->assertPermissionError($resp); + } + + public function test_user_register_routes_inaccessible() + { + $resp = $this->get('/register'); + $this->assertPermissionError($resp); + + $resp = $this->post('/register'); + $this->assertPermissionError($resp); + } + protected function withGet(array $options, callable $callback) { return $this->withGlobal($_GET, $options, $callback); diff --git a/tests/SharedTestHelpers.php b/tests/SharedTestHelpers.php index 3433f3b83..f7b7d5edf 100644 --- a/tests/SharedTestHelpers.php +++ b/tests/SharedTestHelpers.php @@ -262,4 +262,19 @@ trait SharedTestHelpers self::assertThat($passed, self::isTrue(), "Failed asserting that given map:\n\n{$toCheckStr}\n\nincludes:\n\n{$toIncludeStr}"); } + /** + * Assert a permission error has occurred. + */ + protected function assertPermissionError($response) + { + if ($response instanceof BrowserKitTest) { + $response = \Illuminate\Foundation\Testing\TestResponse::fromBaseResponse($response->response); + } + + $response->assertRedirect('/'); + $this->assertSessionHas('error'); + $error = session()->pull('error'); + $this->assertStringStartsWith('You do not have permission to access', $error); + } + } \ No newline at end of file diff --git a/tests/TestCase.php b/tests/TestCase.php index f20b20fd8..1f1d5ece7 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -16,19 +16,6 @@ abstract class TestCase extends BaseTestCase */ protected $baseUrl = 'http://localhost'; - /** - * Assert a permission error has occurred. - * @param TestResponse $response - * @return TestCase - */ - protected function assertPermissionError(TestResponse $response) - { - $response->assertRedirect('/'); - $this->assertSessionHas('error'); - session()->remove('error'); - return $this; - } - /** * Assert the session contains a specific entry. * @param string $key From 3991fbe726c527b89d06cb0b2afdca705cafa494 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 2 Feb 2020 17:31:00 +0000 Subject: [PATCH 172/191] Checked over and aligned registration option behavior across all auth options - Added tests to cover --- app/Auth/Access/ExternalAuthService.php | 6 +- .../Guards/ExternalBaseSessionGuard.php | 15 ++-- app/Auth/Access/Guards/LdapSessionGuard.php | 73 ++++++------------ app/Auth/Access/LdapService.php | 6 +- app/Auth/Access/RegistrationService.php | 74 +++++++++++++++---- app/Auth/Access/Saml2Service.php | 45 ++++------- app/Auth/Access/SocialAuthService.php | 4 +- app/Auth/User.php | 22 +++--- app/Auth/UserRepo.php | 34 ++------- app/Exceptions/Handler.php | 5 +- app/Http/Controllers/Auth/LoginController.php | 1 + .../Controllers/Auth/RegisterController.php | 7 +- app/Http/Controllers/Auth/Saml2Controller.php | 1 - .../Controllers/Auth/SocialController.php | 19 ++--- app/Providers/AuthServiceProvider.php | 5 +- resources/lang/en/errors.php | 1 - resources/lang/en/settings.php | 2 +- resources/views/settings/index.blade.php | 4 +- tests/Auth/LdapTest.php | 32 ++++++++ tests/Auth/Saml2Test.php | 22 +++++- 20 files changed, 200 insertions(+), 178 deletions(-) diff --git a/app/Auth/Access/ExternalAuthService.php b/app/Auth/Access/ExternalAuthService.php index 4bd8f8680..db8bd2dfb 100644 --- a/app/Auth/Access/ExternalAuthService.php +++ b/app/Auth/Access/ExternalAuthService.php @@ -64,10 +64,8 @@ class ExternalAuthService /** * Sync the groups to the user roles for the current user - * @param \BookStack\Auth\User $user - * @param array $userGroups */ - public function syncWithGroups(User $user, array $userGroups) + public function syncWithGroups(User $user, array $userGroups): void { // Get the ids for the roles from the names $groupsAsRoles = $this->matchGroupsToSystemsRoles($userGroups); @@ -75,7 +73,7 @@ class ExternalAuthService // Sync groups if ($this->config['remove_from_groups']) { $user->roles()->sync($groupsAsRoles); - $this->userRepo->attachDefaultRole($user); + $user->attachDefaultRole(); } else { $user->roles()->syncWithoutDetaching($groupsAsRoles); } diff --git a/app/Auth/Access/Guards/ExternalBaseSessionGuard.php b/app/Auth/Access/Guards/ExternalBaseSessionGuard.php index d1fb0b606..f3d05366d 100644 --- a/app/Auth/Access/Guards/ExternalBaseSessionGuard.php +++ b/app/Auth/Access/Guards/ExternalBaseSessionGuard.php @@ -2,10 +2,7 @@ namespace BookStack\Auth\Access\Guards; -use BookStack\Auth\User; -use BookStack\Auth\UserRepo; -use BookStack\Exceptions\LoginAttemptEmailNeededException; -use BookStack\Exceptions\LoginAttemptException; +use BookStack\Auth\Access\RegistrationService; use Illuminate\Auth\GuardHelpers; use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; use Illuminate\Contracts\Auth\StatefulGuard; @@ -56,23 +53,23 @@ class ExternalBaseSessionGuard implements StatefulGuard protected $loggedOut = false; /** - * Repository to perform user-specific actions. + * Service to handle common registration actions. * - * @var UserRepo + * @var RegistrationService */ - protected $userRepo; + protected $registrationService; /** * Create a new authentication guard. * * @return void */ - public function __construct(string $name, UserProvider $provider, Session $session, UserRepo $userRepo) + public function __construct(string $name, UserProvider $provider, Session $session, RegistrationService $registrationService) { $this->name = $name; $this->session = $session; $this->provider = $provider; - $this->userRepo = $userRepo; + $this->registrationService = $registrationService; } /** diff --git a/app/Auth/Access/Guards/LdapSessionGuard.php b/app/Auth/Access/Guards/LdapSessionGuard.php index 6c416bf30..3c98140f6 100644 --- a/app/Auth/Access/Guards/LdapSessionGuard.php +++ b/app/Auth/Access/Guards/LdapSessionGuard.php @@ -3,13 +3,17 @@ namespace BookStack\Auth\Access\Guards; use BookStack\Auth\Access\LdapService; +use BookStack\Auth\Access\RegistrationService; use BookStack\Auth\User; use BookStack\Auth\UserRepo; use BookStack\Exceptions\LdapException; use BookStack\Exceptions\LoginAttemptException; use BookStack\Exceptions\LoginAttemptEmailNeededException; +use BookStack\Exceptions\UserRegistrationException; use Illuminate\Contracts\Auth\UserProvider; use Illuminate\Contracts\Session\Session; +use Illuminate\Support\Facades\Hash; +use Illuminate\Support\Str; class LdapSessionGuard extends ExternalBaseSessionGuard { @@ -23,11 +27,11 @@ class LdapSessionGuard extends ExternalBaseSessionGuard UserProvider $provider, Session $session, LdapService $ldapService, - UserRepo $userRepo + RegistrationService $registrationService ) { $this->ldapService = $ldapService; - parent::__construct($name, $provider, $session, $userRepo); + parent::__construct($name, $provider, $session, $registrationService); } /** @@ -56,6 +60,7 @@ class LdapSessionGuard extends ExternalBaseSessionGuard * @throws LoginAttemptEmailNeededException * @throws LoginAttemptException * @throws LdapException + * @throws UserRegistrationException */ public function attempt(array $credentials = [], $remember = false) { @@ -70,12 +75,9 @@ class LdapSessionGuard extends ExternalBaseSessionGuard } if (is_null($user)) { - $user = $this->freshUserInstanceFromLdapUserDetails($userDetails); + $user = $this->createNewFromLdapAndCreds($userDetails, $credentials); } - $this->checkForUserEmail($user, $credentials['email'] ?? ''); - $this->saveIfNew($user); - // Sync LDAP groups if required if ($this->ldapService->shouldSyncGroups()) { $this->ldapService->syncGroups($user, $username); @@ -86,58 +88,27 @@ class LdapSessionGuard extends ExternalBaseSessionGuard } /** - * Save the give user if they don't yet existing in the system. - * @throws LoginAttemptException - */ - protected function saveIfNew(User $user) - { - if ($user->exists) { - return; - } - - // Check for existing users with same email - $alreadyUser = $user->newQuery()->where('email', '=', $user->email)->count() > 0; - if ($alreadyUser) { - throw new LoginAttemptException(trans('errors.error_user_exists_different_creds', ['email' => $user->email])); - } - - $user->save(); - $this->userRepo->attachDefaultRole($user); - $this->userRepo->downloadAndAssignUserAvatar($user); - } - - /** - * Ensure the given user has an email. - * Takes the provided email in the request if a value is provided - * and the user does not have an existing email. + * Create a new user from the given ldap credentials and login credentials * @throws LoginAttemptEmailNeededException + * @throws LoginAttemptException + * @throws UserRegistrationException */ - protected function checkForUserEmail(User $user, string $providedEmail) + protected function createNewFromLdapAndCreds(array $ldapUserDetails, array $credentials): User { - // Request email if missing from user and missing from request - if (is_null($user->email) && !$providedEmail) { + $email = trim($ldapUserDetails['email'] ?: ($credentials['email'] ?? '')); + + if (empty($email)) { throw new LoginAttemptEmailNeededException(); } - // Add email to model if non-existing and email provided in request - if (!$user->exists && is_null($user->email) && $providedEmail) { - $user->email = $providedEmail; - } - } + $details = [ + 'name' => $ldapUserDetails['name'], + 'email' => $ldapUserDetails['email'] ?: $credentials['email'], + 'external_auth_id' => $ldapUserDetails['uid'], + 'password' => Str::random(32), + ]; - /** - * Create a fresh user instance from details provided by a LDAP lookup. - */ - protected function freshUserInstanceFromLdapUserDetails(array $ldapUserDetails): User - { - $user = new User(); - - $user->name = $ldapUserDetails['name']; - $user->external_auth_id = $ldapUserDetails['uid']; - $user->email = $ldapUserDetails['email']; - $user->email_confirmed = false; - - return $user; + return $this->registrationService->registerUser($details, null, false); } } diff --git a/app/Auth/Access/LdapService.php b/app/Auth/Access/LdapService.php index cc2890817..07e9f7b64 100644 --- a/app/Auth/Access/LdapService.php +++ b/app/Auth/Access/LdapService.php @@ -1,10 +1,8 @@ ldap = $ldap; $this->config = config('services.ldap'); - $this->userRepo = $userRepo; $this->enabled = config('auth.method') === 'ldap'; } diff --git a/app/Auth/Access/RegistrationService.php b/app/Auth/Access/RegistrationService.php index 74142301a..8cf76013a 100644 --- a/app/Auth/Access/RegistrationService.php +++ b/app/Auth/Access/RegistrationService.php @@ -1,6 +1,7 @@ registrationAllowed()) { + throw new UserRegistrationException(trans('auth.registrations_disabled'), '/login'); + } + } + + /** + * Check if standard BookStack User registrations are currently allowed. + * Does not prevent external-auth based registration. + */ + protected function registrationAllowed(): bool { $authMethod = config('auth.method'); $authMethodsWithRegistration = ['standard']; - if (!setting('registration-enabled') || !in_array($authMethod, $authMethodsWithRegistration)) { - throw new UserRegistrationException(trans('auth.registrations_disabled'), '/login'); - } + return in_array($authMethod, $authMethodsWithRegistration) && setting('registration-enabled'); } /** * The registrations flow for all users. * @throws UserRegistrationException */ - public function registerUser(array $userData, ?SocialAccount $socialAccount = null, bool $emailVerified = false) + public function registerUser(array $userData, ?SocialAccount $socialAccount = null, bool $emailConfirmed = false): User { - $registrationRestrict = setting('registration-restrict'); + $userEmail = $userData['email']; - if ($registrationRestrict) { - $restrictedEmailDomains = explode(',', str_replace(' ', '', $registrationRestrict)); - $userEmailDomain = $domain = mb_substr(mb_strrchr($userData['email'], "@"), 1); - if (!in_array($userEmailDomain, $restrictedEmailDomains)) { - throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), '/register'); - } + // Email restriction + $this->ensureEmailDomainAllowed($userEmail); + + // Ensure user does not already exist + $alreadyUser = !is_null($this->userRepo->getByEmail($userEmail)); + if ($alreadyUser) { + throw new UserRegistrationException(trans('errors.error_user_exists_different_creds', ['email' => $userEmail])); } - $newUser = $this->userRepo->registerNew($userData, $emailVerified); + // Create the user + $newUser = $this->userRepo->registerNew($userData, $emailConfirmed); + // Assign social account if given if ($socialAccount) { $newUser->socialAccounts()->save($socialAccount); } - if ($this->emailConfirmationService->confirmationRequired() && !$emailVerified) { + // Start email confirmation flow if required + if ($this->emailConfirmationService->confirmationRequired() && !$emailConfirmed) { $newUser->save(); $message = ''; @@ -68,7 +82,37 @@ class RegistrationService throw new UserRegistrationException($message, '/register/confirm'); } - auth()->login($newUser); + return $newUser; + } + + /** + * Ensure that the given email meets any active email domain registration restrictions. + * Throws if restrictions are active and the email does not match an allowed domain. + * @throws UserRegistrationException + */ + protected function ensureEmailDomainAllowed(string $userEmail): void + { + $registrationRestrict = setting('registration-restrict'); + + if (!$registrationRestrict) { + return; + } + + $restrictedEmailDomains = explode(',', str_replace(' ', '', $registrationRestrict)); + $userEmailDomain = $domain = mb_substr(mb_strrchr($userEmail, "@"), 1); + if (!in_array($userEmailDomain, $restrictedEmailDomains)) { + $redirect = $this->registrationAllowed() ? '/register' : '/login'; + throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), $redirect); + } + } + + /** + * Alias to the UserRepo method of the same name. + * Attaches the default system role, if configured, to the given user. + */ + public function attachDefaultRole(User $user): void + { + $this->userRepo->attachDefaultRole($user); } } \ No newline at end of file diff --git a/app/Auth/Access/Saml2Service.php b/app/Auth/Access/Saml2Service.php index c52dc3a39..8f9a24cde 100644 --- a/app/Auth/Access/Saml2Service.php +++ b/app/Auth/Access/Saml2Service.php @@ -1,9 +1,9 @@ config = config('saml2'); - $this->userRepo = $userRepo; + $this->registrationService = $registrationService; $this->user = $user; } @@ -78,6 +78,7 @@ class Saml2Service extends ExternalAuthService * @throws SamlException * @throws ValidationError * @throws JsonDebugException + * @throws UserRegistrationException */ public function processAcsResponse(?string $requestId): ?User { @@ -308,34 +309,10 @@ class Saml2Service extends ExternalAuthService return $defaultValue; } - /** - * Register a user that is authenticated but not already registered. - */ - protected function registerUser(array $userDetails): User - { - // Create an array of the user data to create a new user instance - $userData = [ - 'name' => $userDetails['name'], - 'email' => $userDetails['email'], - 'password' => Str::random(32), - 'external_auth_id' => $userDetails['external_id'], - 'email_confirmed' => true, - ]; - - $existingUser = $this->user->newQuery()->where('email', '=', $userDetails['email'])->first(); - if ($existingUser) { - throw new SamlException(trans('errors.saml_email_exists', ['email' => $userDetails['email']])); - } - - $user = $this->user->newQuery()->forceCreate($userData); - $this->userRepo->attachDefaultRole($user); - $this->userRepo->downloadAndAssignUserAvatar($user); - return $user; - } - /** * Get the user from the database for the specified details. * @throws SamlException + * @throws UserRegistrationException */ protected function getOrRegisterUser(array $userDetails): ?User { @@ -344,7 +321,14 @@ class Saml2Service extends ExternalAuthService ->first(); if (is_null($user)) { - $user = $this->registerUser($userDetails); + $userData = [ + 'name' => $userDetails['name'], + 'email' => $userDetails['email'], + 'password' => Str::random(32), + 'external_auth_id' => $userDetails['external_id'], + ]; + + $user = $this->registrationService->registerUser($userData, null, false); } return $user; @@ -355,6 +339,7 @@ class Saml2Service extends ExternalAuthService * they exist, optionally registering them automatically. * @throws SamlException * @throws JsonDebugException + * @throws UserRegistrationException */ public function processLoginCallback(string $samlID, array $samlAttributes): User { diff --git a/app/Auth/Access/SocialAuthService.php b/app/Auth/Access/SocialAuthService.php index cf836618a..16815a8e1 100644 --- a/app/Auth/Access/SocialAuthService.php +++ b/app/Auth/Access/SocialAuthService.php @@ -64,7 +64,7 @@ class SocialAuthService if ($this->userRepo->getByEmail($socialUser->getEmail())) { $email = $socialUser->getEmail(); - throw new UserRegistrationException(trans('errors.social_account_in_use', ['socialAccount'=>$socialDriver, 'email' => $email]), '/login'); + throw new UserRegistrationException(trans('errors.error_user_exists_different_creds', ['email' => $email]), '/login'); } return $socialUser; @@ -124,7 +124,7 @@ class SocialAuthService // Otherwise let the user know this social account is not used by anyone. $message = trans('errors.social_account_not_used', ['socialAccount' => $titleCaseDriver]); - if (setting('registration-enabled') && config('auth.method') !== 'ldap') { + if (setting('registration-enabled') && config('auth.method') !== 'ldap' && config('auth.method') !== 'saml2') { $message .= trans('errors.social_account_register_instructions', ['socialAccount' => $titleCaseDriver]); } diff --git a/app/Auth/User.php b/app/Auth/User.php index 35b3cd54f..28fb9c7fc 100644 --- a/app/Auth/User.php +++ b/app/Auth/User.php @@ -116,6 +116,17 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon return $this->roles->pluck('system_name')->contains($role); } + /** + * Attach the default system role to this user. + */ + public function attachDefaultRole(): void + { + $roleId = setting('registration-role'); + if ($roleId && $this->roles()->where('id', '=', $roleId)->count() === 0) { + $this->roles()->attach($roleId); + } + } + /** * Get all permissions belonging to a the current user. * @param bool $cache @@ -153,16 +164,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon */ public function attachRole(Role $role) { - $this->attachRoleId($role->id); - } - - /** - * Attach a role id to this user. - * @param $id - */ - public function attachRoleId($id) - { - $this->roles()->attach($id); + $this->roles()->attach($role->id); } /** diff --git a/app/Auth/UserRepo.php b/app/Auth/UserRepo.php index e082b2dd5..cfa7bfce1 100644 --- a/app/Auth/UserRepo.php +++ b/app/Auth/UserRepo.php @@ -29,10 +29,9 @@ class UserRepo } /** - * @param string $email - * @return User|null + * Get a user by their email address. */ - public function getByEmail($email) + public function getByEmail(string $email): ?User { return $this->user->where('email', '=', $email)->first(); } @@ -78,31 +77,16 @@ class UserRepo /** * Creates a new user and attaches a role to them. - * @param array $data - * @param boolean $verifyEmail - * @return User */ - public function registerNew(array $data, $verifyEmail = false) + public function registerNew(array $data, bool $emailConfirmed = false): User { - $user = $this->create($data, $verifyEmail); - $this->attachDefaultRole($user); + $user = $this->create($data, $emailConfirmed); + $user->attachDefaultRole(); $this->downloadAndAssignUserAvatar($user); return $user; } - /** - * Give a user the default role. Used when creating a new user. - * @param User $user - */ - public function attachDefaultRole(User $user) - { - $roleId = setting('registration-role'); - if ($roleId !== false && $user->roles()->where('id', '=', $roleId)->count() === 0) { - $user->attachRoleId($roleId); - } - } - /** * Assign a user to a system-level role. * @param User $user @@ -172,17 +156,15 @@ class UserRepo /** * Create a new basic instance of user. - * @param array $data - * @param boolean $verifyEmail - * @return User */ - public function create(array $data, $verifyEmail = false) + public function create(array $data, bool $emailConfirmed = false): User { return $this->user->forceCreate([ 'name' => $data['name'], 'email' => $data['email'], 'password' => bcrypt($data['password']), - 'email_confirmed' => $verifyEmail + 'email_confirmed' => $emailConfirmed, + 'external_auth_id' => $data['external_auth_id'] ?? '', ]); } diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 284d731d7..a3bc1e8b9 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -57,7 +57,10 @@ class Handler extends ExceptionHandler // Handle notify exceptions which will redirect to the // specified location then show a notification message. if ($this->isExceptionType($e, NotifyException::class)) { - session()->flash('error', $this->getOriginalMessage($e)); + $message = $this->getOriginalMessage($e); + if (!empty($message)) { + session()->flash('error', $message); + } return redirect($e->redirectLocation); } diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 4292ad6dd..ea584a3b6 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -5,6 +5,7 @@ namespace BookStack\Http\Controllers\Auth; use BookStack\Auth\Access\SocialAuthService; use BookStack\Exceptions\LoginAttemptEmailNeededException; use BookStack\Exceptions\LoginAttemptException; +use BookStack\Exceptions\UserRegistrationException; use BookStack\Http\Controllers\Controller; use Illuminate\Foundation\Auth\AuthenticatesUsers; use Illuminate\Http\Request; diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 56ec66bff..0bdeef9e6 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -74,7 +74,7 @@ class RegisterController extends Controller */ public function getRegister() { - $this->registrationService->checkRegistrationAllowed(); + $this->registrationService->ensureRegistrationAllowed(); $socialDrivers = $this->socialAuthService->getActiveDrivers(); return view('auth.register', [ 'socialDrivers' => $socialDrivers, @@ -87,12 +87,13 @@ class RegisterController extends Controller */ public function postRegister(Request $request) { - $this->registrationService->checkRegistrationAllowed(); + $this->registrationService->ensureRegistrationAllowed(); $this->validator($request->all())->validate(); $userData = $request->all(); try { - $this->registrationService->registerUser($userData); + $user = $this->registrationService->registerUser($userData); + auth()->login($user); } catch (UserRegistrationException $exception) { if ($exception->getMessage()) { $this->showErrorNotification($exception->getMessage()); diff --git a/app/Http/Controllers/Auth/Saml2Controller.php b/app/Http/Controllers/Auth/Saml2Controller.php index 8c0cb21d2..7ffcc572b 100644 --- a/app/Http/Controllers/Auth/Saml2Controller.php +++ b/app/Http/Controllers/Auth/Saml2Controller.php @@ -81,7 +81,6 @@ class Saml2Controller extends Controller return redirect('/login'); } - session()->put('last_login_type', 'saml2'); return redirect()->intended(); } diff --git a/app/Http/Controllers/Auth/SocialController.php b/app/Http/Controllers/Auth/SocialController.php index bcd82a9c0..ae7a1bc06 100644 --- a/app/Http/Controllers/Auth/SocialController.php +++ b/app/Http/Controllers/Auth/SocialController.php @@ -49,7 +49,7 @@ class SocialController extends Controller */ public function socialRegister(string $socialDriver) { - $this->registrationService->checkRegistrationAllowed(); + $this->registrationService->ensureRegistrationAllowed(); session()->put('social-callback', 'register'); return $this->socialAuthService->startRegister($socialDriver); } @@ -78,7 +78,7 @@ class SocialController extends Controller // Attempt login or fall-back to register if allowed. $socialUser = $this->socialAuthService->getSocialUser($socialDriver); - if ($action == 'login') { + if ($action === 'login') { try { return $this->socialAuthService->handleLoginCallback($socialDriver, $socialUser); } catch (SocialSignInAccountNotUsed $exception) { @@ -89,7 +89,7 @@ class SocialController extends Controller } } - if ($action == 'register') { + if ($action === 'register') { return $this->socialRegisterCallback($socialDriver, $socialUser); } @@ -108,7 +108,6 @@ class SocialController extends Controller /** * Register a new user after a registration callback. - * @return RedirectResponse|Redirector * @throws UserRegistrationException */ protected function socialRegisterCallback(string $socialDriver, SocialUser $socialUser) @@ -121,17 +120,11 @@ class SocialController extends Controller $userData = [ 'name' => $socialUser->getName(), 'email' => $socialUser->getEmail(), - 'password' => Str::random(30) + 'password' => Str::random(32) ]; - try { - $this->registrationService->registerUser($userData, $socialAccount, $emailVerified); - } catch (UserRegistrationException $exception) { - if ($exception->getMessage()) { - $this->showErrorNotification($exception->getMessage()); - } - return redirect($exception->redirectLocation); - } + $user = $this->registrationService->registerUser($userData, $socialAccount, $emailVerified); + auth()->login($user); $this->showSuccessNotification(trans('auth.register_success')); return redirect('/'); diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index a885628f3..fe52df168 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -8,6 +8,7 @@ use BookStack\Auth\Access\ExternalBaseUserProvider; use BookStack\Auth\Access\Guards\LdapSessionGuard; use BookStack\Auth\Access\Guards\Saml2SessionGuard; use BookStack\Auth\Access\LdapService; +use BookStack\Auth\Access\RegistrationService; use BookStack\Auth\UserRepo; use Illuminate\Support\ServiceProvider; @@ -31,7 +32,7 @@ class AuthServiceProvider extends ServiceProvider $provider, $this->app['session.store'], $app[LdapService::class], - $app[UserRepo::class] + $app[RegistrationService::class] ); }); @@ -41,7 +42,7 @@ class AuthServiceProvider extends ServiceProvider $name, $provider, $this->app['session.store'], - $app[UserRepo::class] + $app[RegistrationService::class] ); }); } diff --git a/resources/lang/en/errors.php b/resources/lang/en/errors.php index bb7b6148c..4752d8b0c 100644 --- a/resources/lang/en/errors.php +++ b/resources/lang/en/errors.php @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', - 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => 'No action defined', 'social_login_bad_response' => "Error received during :socialAccount login: \n:error", 'social_account_in_use' => 'This :socialAccount account is already in use, Try logging in via the :socialAccount option.', diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index 8c9675f09..692489afd 100755 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => 'Enable registration', 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', 'reg_default_role' => 'Default user role after registration', - 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', + 'reg_enable_external_warning' => 'The option above is ignore while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'Email Confirmation', 'reg_email_confirmation_toggle' => 'Require email confirmation', 'reg_confirm_email_desc' => 'If domain restriction is used then email confirmation will be required and this option will be ignored.', diff --git a/resources/views/settings/index.blade.php b/resources/views/settings/index.blade.php index 94605da6f..2585ec5e3 100644 --- a/resources/views/settings/index.blade.php +++ b/resources/views/settings/index.blade.php @@ -219,8 +219,8 @@ 'label' => trans('settings.reg_enable_toggle') ]) - @if(config('auth.method') === 'ldap') -
    {{ trans('settings.reg_enable_ldap_warning') }}
    + @if(in_array(config('auth.method'), ['ldap', 'saml2'])) +
    {{ trans('settings.reg_enable_external_warning') }}
    @endif diff --git a/tests/Auth/LdapTest.php b/tests/Auth/LdapTest.php index 92ff4a829..cb1194e22 100644 --- a/tests/Auth/LdapTest.php +++ b/tests/Auth/LdapTest.php @@ -86,6 +86,38 @@ class LdapTest extends BrowserKitTest ->seeInDatabase('users', ['email' => $this->mockUser->email, 'email_confirmed' => false, 'external_auth_id' => $this->mockUser->name]); } + public function test_email_domain_restriction_active_on_new_ldap_login() + { + $this->setSettings([ + 'registration-restrict' => 'testing.com' + ]); + + $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId); + $this->mockLdap->shouldReceive('setVersion')->once(); + $this->mockLdap->shouldReceive('setOption')->times(2); + $this->mockLdap->shouldReceive('searchAndGetEntries')->times(2) + ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) + ->andReturn(['count' => 1, 0 => [ + 'uid' => [$this->mockUser->name], + 'cn' => [$this->mockUser->name], + 'dn' => ['dc=test' . config('services.ldap.base_dn')] + ]]); + $this->mockLdap->shouldReceive('bind')->times(4)->andReturn(true); + $this->mockEscapes(2); + + $this->mockUserLogin() + ->seePageIs('/login') + ->see('Please enter an email to use for this account.'); + + $email = 'tester@invaliddomain.com'; + + $this->type($email, '#email') + ->press('Log In') + ->seePageIs('/login') + ->see('That email domain does not have access to this application') + ->dontSeeInDatabase('users', ['email' => $email]); + } + public function test_login_works_when_no_uid_provided_by_ldap_server() { $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId); diff --git a/tests/Auth/Saml2Test.php b/tests/Auth/Saml2Test.php index b3e6bd41b..9a3d6d8ec 100644 --- a/tests/Auth/Saml2Test.php +++ b/tests/Auth/Saml2Test.php @@ -73,7 +73,7 @@ class Saml2Test extends TestCase $this->assertDatabaseHas('users', [ 'email' => 'user@example.com', 'external_auth_id' => 'user', - 'email_confirmed' => true, + 'email_confirmed' => false, 'name' => 'Barry Scott' ]); @@ -209,7 +209,7 @@ class Saml2Test extends TestCase $acsPost = $this->post('/saml2/acs'); $acsPost->assertRedirect('/'); $errorMessage = session()->get('error'); - $this->assertEquals('Registration unsuccessful since a user already exists with email address "user@example.com"', $errorMessage); + $this->assertEquals('A user with the email user@example.com already exists but with different credentials.', $errorMessage); }); } @@ -271,6 +271,24 @@ class Saml2Test extends TestCase $this->assertPermissionError($resp); } + public function test_email_domain_restriction_active_on_new_saml_login() + { + $this->setSettings([ + 'registration-restrict' => 'testing.com' + ]); + config()->set([ + 'saml2.onelogin.strict' => false, + ]); + + $this->withPost(['SAMLResponse' => $this->acsPostData], function () { + $acsPost = $this->post('/saml2/acs'); + $acsPost->assertRedirect('/login'); + $errorMessage = session()->get('error'); + $this->assertStringContainsString('That email domain does not have access to this application', $errorMessage); + $this->assertDatabaseMissing('users', ['email' => 'user@example.com']); + }); + } + protected function withGet(array $options, callable $callback) { return $this->withGlobal($_GET, $options, $callback); From b4f2b735904169eb12a05cb0befc4ff38beaeaee Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 2 Feb 2020 17:35:16 +0000 Subject: [PATCH 173/191] Updated settings-save action to return to the same section --- app/Http/Controllers/SettingController.php | 18 ++---------------- resources/views/settings/index.blade.php | 9 ++++++--- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/app/Http/Controllers/SettingController.php b/app/Http/Controllers/SettingController.php index f0a078300..7f7724468 100644 --- a/app/Http/Controllers/SettingController.php +++ b/app/Http/Controllers/SettingController.php @@ -5,8 +5,6 @@ use BookStack\Notifications\TestEmail; use BookStack\Uploads\ImageRepo; use BookStack\Uploads\ImageService; use Illuminate\Http\Request; -use Illuminate\Http\Response; -use Setting; class SettingController extends Controller { @@ -14,7 +12,6 @@ class SettingController extends Controller /** * SettingController constructor. - * @param $imageRepo */ public function __construct(ImageRepo $imageRepo) { @@ -22,10 +19,8 @@ class SettingController extends Controller parent::__construct(); } - /** * Display a listing of the settings. - * @return Response */ public function index() { @@ -43,8 +38,6 @@ class SettingController extends Controller /** * Update the specified settings in storage. - * @param Request $request - * @return Response */ public function update(Request $request) { @@ -78,12 +71,11 @@ class SettingController extends Controller } $this->showSuccessNotification(trans('settings.settings_save_success')); - return redirect('/settings'); + return redirect('/settings#' . $request->get('section', '')); } /** * Show the page for application maintenance. - * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View */ public function showMaintenance() { @@ -98,9 +90,6 @@ class SettingController extends Controller /** * Action to clean-up images in the system. - * @param Request $request - * @param ImageService $imageService - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ public function cleanupImages(Request $request, ImageService $imageService) { @@ -127,11 +116,8 @@ class SettingController extends Controller /** * Action to send a test e-mail to the current user. - * @param Request $request - * @param User $user - * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector */ - public function sendTestEmail(Request $request) + public function sendTestEmail() { $this->checkPermission('settings-manage'); diff --git a/resources/views/settings/index.blade.php b/resources/views/settings/index.blade.php index 2585ec5e3..b3a11955d 100644 --- a/resources/views/settings/index.blade.php +++ b/resources/views/settings/index.blade.php @@ -15,9 +15,10 @@
    -

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

    +

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

    {!! csrf_field() !!} +
    @@ -79,9 +80,10 @@
    -

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

    +

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

    {!! csrf_field() !!} +
    @@ -202,9 +204,10 @@
    -

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

    +

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

    {!! csrf_field() !!} +
    From 9d77cca7340dec4872fba4742e7aa7c6d25e6052 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 2 Feb 2020 17:57:21 +0000 Subject: [PATCH 174/191] Cleaned setting section redirect path --- app/Http/Controllers/SettingController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/SettingController.php b/app/Http/Controllers/SettingController.php index 7f7724468..892b2d9cf 100644 --- a/app/Http/Controllers/SettingController.php +++ b/app/Http/Controllers/SettingController.php @@ -71,7 +71,8 @@ class SettingController extends Controller } $this->showSuccessNotification(trans('settings.settings_save_success')); - return redirect('/settings#' . $request->get('section', '')); + $redirectLocation = '/settings#' . $request->get('section', ''); + return redirect(rtrim($redirectLocation, '#')); } /** From 5ce3b861a9cbc27cc4564882f9def9a4d641f877 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 2 Feb 2020 21:04:43 +0000 Subject: [PATCH 175/191] Improved styling of the 500 error page --- resources/views/errors/500.blade.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/resources/views/errors/500.blade.php b/resources/views/errors/500.blade.php index 8c6822767..d06ddbc57 100644 --- a/resources/views/errors/500.blade.php +++ b/resources/views/errors/500.blade.php @@ -2,14 +2,16 @@ @section('content') -
    -
    -

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

    +
    + +
    -
    {{ $message ?? 'An unknown error occurred' }}
    +

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

    +
    {{ $message ?? 'An unknown error occurred' }}

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

    -
    + +
    @stop \ No newline at end of file From dea8343bc8f53a02797eda007a4723966b4cc105 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 2 Feb 2020 21:59:51 +0000 Subject: [PATCH 176/191] Made docs sidebar sticky, changed theme to default - MDN theme appeared fairly bad for markdown use, and the geometric background was a bit much. Swapped out to default theme. - Rough-added stickiness to docs sidebar, will need more work once it starts to expand possible screen height. --- resources/js/services/code.js | 2 +- resources/sass/_blocks.scss | 5 ++ resources/sass/_codemirror.scss | 80 ++++++++++++------------ resources/sass/_layout.scss | 1 - resources/views/api-docs/index.blade.php | 40 ++++++------ 5 files changed, 68 insertions(+), 60 deletions(-) diff --git a/resources/js/services/code.js b/resources/js/services/code.js index 0c5f75db3..718ef5721 100644 --- a/resources/js/services/code.js +++ b/resources/js/services/code.js @@ -185,7 +185,7 @@ function getMode(suggestion, content) { * @returns {*|string} */ function getTheme() { - return window.codeTheme || 'mdn-like'; + return window.codeTheme || 'default'; } /** diff --git a/resources/sass/_blocks.scss b/resources/sass/_blocks.scss index cc42dc736..ff344158f 100644 --- a/resources/sass/_blocks.scss +++ b/resources/sass/_blocks.scss @@ -258,4 +258,9 @@ &[data-method="POST"] { background-color: #cf4d03 } &[data-method="PUT"] { background-color: #0288D1 } &[data-method="DELETE"] { background-color: #ab0f0e } +} + +.sticky-sidebar { + position: sticky; + top: $-m; } \ No newline at end of file diff --git a/resources/sass/_codemirror.scss b/resources/sass/_codemirror.scss index 92287c484..dc1aef9bb 100644 --- a/resources/sass/_codemirror.scss +++ b/resources/sass/_codemirror.scss @@ -341,53 +341,55 @@ div.CodeMirror-dragcursors { /* Help users use markselection to safely style text background */ span.CodeMirror-selectedtext { background: none; } +/** + * Codemirror Default theme + */ -/* - MDN-LIKE Theme - Mozilla - Ported to CodeMirror by Peter Kroon - Report bugs/issues here: https://github.com/codemirror/CodeMirror/issues - GitHub: @peterkroon +.cm-s-default .cm-header {color: blue;} +.cm-s-default .cm-quote {color: #090;} +.cm-negative {color: #d44;} +.cm-positive {color: #292;} +.cm-header, .cm-strong {font-weight: bold;} +.cm-em {font-style: italic;} +.cm-link {text-decoration: underline;} +.cm-strikethrough {text-decoration: line-through;} - The mdn-like theme is inspired on the displayed code examples at: https://developer.mozilla.org/en-US/docs/Web/CSS/animation +.cm-s-default .cm-keyword {color: #708;} +.cm-s-default .cm-atom {color: #219;} +.cm-s-default .cm-number {color: #164;} +.cm-s-default .cm-def {color: #00f;} +.cm-s-default .cm-variable, +.cm-s-default .cm-punctuation, +.cm-s-default .cm-property, +.cm-s-default .cm-operator {} +.cm-s-default .cm-variable-2 {color: #05a;} +.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;} +.cm-s-default .cm-comment {color: #a50;} +.cm-s-default .cm-string {color: #a11;} +.cm-s-default .cm-string-2 {color: #f50;} +.cm-s-default .cm-meta {color: #555;} +.cm-s-default .cm-qualifier {color: #555;} +.cm-s-default .cm-builtin {color: #30a;} +.cm-s-default .cm-bracket {color: #997;} +.cm-s-default .cm-tag {color: #170;} +.cm-s-default .cm-attribute {color: #00c;} +.cm-s-default .cm-hr {color: #999;} +.cm-s-default .cm-link {color: #00c;} -*/ -.cm-s-mdn-like.CodeMirror { color: #999; background-color: #fff; } -.cm-s-mdn-like div.CodeMirror-selected { background: #cfc; } -.cm-s-mdn-like .CodeMirror-line::selection, .cm-s-mdn-like .CodeMirror-line > span::selection, .cm-s-mdn-like .CodeMirror-line > span > span::selection { background: #cfc; } -.cm-s-mdn-like .CodeMirror-line::-moz-selection, .cm-s-mdn-like .CodeMirror-line > span::-moz-selection, .cm-s-mdn-like .CodeMirror-line > span > span::-moz-selection { background: #cfc; } +.cm-s-default .cm-error {color: #f00;} +.cm-invalidchar {color: #f00;} -.cm-s-mdn-like .CodeMirror-gutters { background: #f8f8f8; border-left: 6px solid rgba(0,83,159,0.65); color: #333; } -.cm-s-mdn-like .CodeMirror-linenumber { color: #aaa; padding-left: 8px; } -.cm-s-mdn-like .CodeMirror-cursor { border-left: 2px solid #222; } +.CodeMirror-composing { border-bottom: 2px solid; } -.cm-s-mdn-like .cm-keyword { color: #6262FF; } -.cm-s-mdn-like .cm-atom { color: #F90; } -.cm-s-mdn-like .cm-number { color: #ca7841; } -.cm-s-mdn-like .cm-def { color: #8DA6CE; } -.cm-s-mdn-like span.cm-variable-2, .cm-s-mdn-like span.cm-tag { color: #690; } -.cm-s-mdn-like span.cm-variable-3, .cm-s-mdn-like span.cm-def, .cm-s-mdn-like span.cm-type { color: #07a; } +/* Default styles for common addons */ -.cm-s-mdn-like .cm-variable { color: #07a; } -.cm-s-mdn-like .cm-property { color: #905; } -.cm-s-mdn-like .cm-qualifier { color: #690; } +div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;} +div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} +.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } +.CodeMirror-activeline-background {background: #e8f2ff;} -.cm-s-mdn-like .cm-operator { color: #cda869; } -.cm-s-mdn-like .cm-comment { color:#777; font-weight:normal; } -.cm-s-mdn-like .cm-string { color:#07a; font-style:italic; } -.cm-s-mdn-like .cm-string-2 { color:#bd6b18; } /*?*/ -.cm-s-mdn-like .cm-meta { color: #000; } /*?*/ -.cm-s-mdn-like .cm-builtin { color: #9B7536; } /*?*/ -.cm-s-mdn-like .cm-tag { color: #997643; } -.cm-s-mdn-like .cm-attribute { color: #d6bb6d; } /*?*/ -.cm-s-mdn-like .cm-header { color: #FF6400; } -.cm-s-mdn-like .cm-hr { color: #AEAEAE; } -.cm-s-mdn-like .cm-link { color:#ad9361; font-style:italic; text-decoration:none; } -.cm-s-mdn-like .cm-error { border-bottom: 1px solid red; } +/* STOP */ -div.cm-s-mdn-like .CodeMirror-activeline-background { background: #efefff; } -div.cm-s-mdn-like span.CodeMirror-matchingbracket { outline:1px solid grey; color: inherit; } - -.cm-s-mdn-like.CodeMirror { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFcAAAAyCAYAAAAp8UeFAAAHvklEQVR42s2b63bcNgyEQZCSHCdt2vd/0tWF7I+Q6XgMXiTtuvU5Pl57ZQKkKHzEAOtF5KeIJBGJ8uvL599FRFREZhFx8DeXv8trn68RuGaC8TRfo3SNp9dlDDHedyLyTUTeRWStXKPZrjtpZxaRw5hPqozRs1N8/enzIiQRWcCgy4MUA0f+XWliDhyL8Lfyvx7ei/Ae3iQFHyw7U/59pQVIMEEPEz0G7XiwdRjzSfC3UTtz9vchIntxvry5iMgfIhJoEflOz2CQr3F5h/HfeFe+GTdLaKcu9L8LTeQb/R/7GgbsfKedyNdoHsN31uRPWrfZ5wsj/NzzRQHuToIdU3ahwnsKPxXCjJITuOsi7XLc7SG/v5GdALs7wf8JjTFiB5+QvTEfRyGOfX3Lrx8wxyQi3sNq46O7QahQiCsRFgqddjBouVEHOKDgXAQHD9gJCr5sMKkEdjwsarG/ww3BMHBU7OBjXnzdyY7SfCxf5/z6ATccrwlKuwC/jhznnPF4CgVzhhVf4xp2EixcBActO75iZ8/fM9zAs2OMzKdslgXWJ9XG8PQoOAMA5fGcsvORgv0doBXyHrCwfLJAOwo71QLNkb8n2Pl6EWiR7OCibtkPaz4Kc/0NNAze2gju3zOwekALDaCFPI5vjPFmgGY5AZqyGEvH1x7QfIb8YtxMnA/b+QQ0aQDAwc6JMFg8CbQZ4qoYEEHbRwNojuK3EHwd7VALSgq+MNDKzfT58T8qdpADrgW0GmgcAS1lhzztJmkAzcPNOQbsWEALBDSlMKUG0Eq4CLAQWvEVQ9WU57gZJwZtgPO3r9oBTQ9WO8TjqXINx8R0EYpiZEUWOF3FxkbJkgU9B2f41YBrIj5ZfsQa0M5kTgiAAqM3ShXLgu8XMqcrQBvJ0CL5pnTsfMB13oB8athpAq2XOQmcGmoACCLydx7nToa23ATaSIY2ichfOdPTGxlasXMLaL0MLZAOwAKIM+y8CmicobGdCcbbK9DzN+yYGVoNNI5iUKTMyYOjPse4A8SM1MmcXgU0toOq1yO/v8FOxlASyc7TgeYaAMBJHcY1CcCwGI/TK4AmDbDyKYBBtFUkRwto8gygiQEaByFgJ00BH2M8JWwQS1nafDXQCidWyOI8AcjDCSjCLk8ngObuAm3JAHAdubAmOaK06V8MNEsKPJOhobSprwQa6gD7DclRQdqcwL4zxqgBrQcabUiBLclRDKAlWp+etPkBaNMA0AKlrHwTdEByZAA4GM+SNluSY6wAzcMNewxmgig5Ks0nkrSpBvSaQHMdKTBAnLojOdYyGpQ254602ZILPdTD1hdlggdIm74jbTp8vDwF5ZYUeLWGJpWsh6XNyXgcYwVoJQTEhhTYkxzZjiU5npU2TaB979TQehlaAVq4kaGpiPwwwLkYUuBbQwocyQTv1tA0+1UFWoJF3iv1oq+qoSk8EQdJmwHkziIF7oOZk14EGitibAdjLYYK78H5vZOhtWpoI0ATGHs0Q8OMb4Ey+2bU2UYztCtA0wFAs7TplGLRVQCcqaFdGSPCeTI1QNIC52iWNzof6Uib7xjEp07mNNoUYmVosVItHrHzRlLgBn9LFyRHaQCtVUMbtTNhoXWiTOO9k/V8BdAc1Oq0ArSQs6/5SU0hckNy9NnXqQY0PGYo5dWJ7nINaN6o958FWin27aBaWRka1r5myvLOAm0j30eBJqCxHLReVclxhxOEN2JfDWjxBtAC7MIH1fVaGdoOp4qJYDgKtKPSFNID2gSnGldrCqkFZ+5UeQXQBIRrSwocbdZYQT/2LwRahBPBXoHrB8nxaGROST62DKUbQOMMzZIC9abkuELfQzQALWTnDNAm8KHWFOJgJ5+SHIvTPcmx1xQyZRhNL5Qci689aXMEaN/uNIWkEwDAvFpOZmgsBaaGnbs1NPa1Jm32gBZAIh1pCtG7TSH4aE0y1uVY4uqoFPisGlpP2rSA5qTecWn5agK6BzSpgAyD+wFaqhnYoSZ1Vwr8CmlTQbrcO3ZaX0NAEyMbYaAlyquFoLKK3SPby9CeVUPThrSJmkCAE0CrKUQadi4DrdSlWhmah0YL9z9vClH59YGbHx1J8VZTyAjQepJjmXwAKTDQI3omc3p1U4gDUf6RfcdYfrUp5ClAi2J3Ba6UOXGo+K+bQrjjssitG2SJzshaLwMtXgRagUNpYYoVkMSBLM+9GGiJZMvduG6DRZ4qc04DMPtQQxOjEtACmhO7K1AbNbQDEggZyJwscFpAGwENhoBeUwh3bWolhe8BTYVKxQEWrSUn/uhcM5KhvUu/+eQu0Lzhi+VrK0PrZZNDQKs9cpYUuFYgMVpD4/NxenJTiMCNqdUEUf1qZWjppLT5qSkkUZbCwkbZMSuVnu80hfSkzRbQeqCZSAh6huR4VtoM2gHAlLf72smuWgE+VV7XpE25Ab2WFDgyhnSuKbs4GuGzCjR+tIoUuMFg3kgcWKLTwRqanJQ2W00hAsenfaApRC42hbCvK1SlE0HtE9BGgneJO+ELamitD1YjjOYnNYVcraGhtKkW0EqVVeDx733I2NH581k1NNxNLG0i0IJ8/NjVaOZ0tYZ2Vtr0Xv7tPV3hkWp9EFkgS/J0vosngTaSoaG06WHi+xObQkaAdlbanP8B2+2l0f90LmUAAAAASUVORK5CYII=); } /** * Custom BookStack overrides diff --git a/resources/sass/_layout.scss b/resources/sass/_layout.scss index 1a7ff2cab..a280e4ed1 100644 --- a/resources/sass/_layout.scss +++ b/resources/sass/_layout.scss @@ -116,7 +116,6 @@ body.flexbox { min-height: 0; max-width: 100%; position: relative; - overflow-y: hidden; } .flex { diff --git a/resources/views/api-docs/index.blade.php b/resources/views/api-docs/index.blade.php index e9583838c..ab4db89e8 100644 --- a/resources/views/api-docs/index.blade.php +++ b/resources/views/api-docs/index.blade.php @@ -7,29 +7,31 @@
    -

    Getting Started

    +
    From 718a97537e3a59ebdcd1a1d19178d074be8d58bd Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 3 Feb 2020 20:33:10 +0000 Subject: [PATCH 177/191] Added app theme setting to complete env and fixed text error --- .env.example.complete | 5 +++++ resources/lang/en/settings.php | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.env.example.complete b/.env.example.complete index bc6b644aa..04cd73b90 100644 --- a/.env.example.complete +++ b/.env.example.complete @@ -37,6 +37,11 @@ APP_AUTO_LANG_PUBLIC=true # Valid timezone values can be found here: https://www.php.net/manual/en/timezones.php APP_TIMEZONE=UTC +# Application theme +# Used to specific a themes/ folder where BookStack UI +# overrides can be made. Defaults to disabled. +APP_THEME=false + # Database details # Host can contain a port (localhost:3306) or a separate DB_PORT option can be used. DB_HOST=localhost diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index 692489afd..ab274256f 100755 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => 'Enable registration', 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', 'reg_default_role' => 'Default user role after registration', - 'reg_enable_external_warning' => 'The option above is ignore while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'Email Confirmation', 'reg_email_confirmation_toggle' => 'Require email confirmation', 'reg_confirm_email_desc' => 'If domain restriction is used then email confirmation will be required and this option will be ignored.', From d8072cbef2cad710a780ff689b29195bad1d035b Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 3 Feb 2020 21:00:17 +0000 Subject: [PATCH 178/191] New Crowdin translations (#1850) * New translations settings.php (Korean) * New translations settings.php (Polish) * New translations settings.php (Ukrainian) * New translations settings.php (Turkish) * New translations settings.php (Swedish) * New translations settings.php (Spanish, Argentina) * New translations settings.php (Spanish) * New translations errors.php (Spanish) * New translations settings.php (Slovak) * New translations settings.php (Russian) * New translations settings.php (Portuguese, Brazilian) * New translations settings.php (Japanese) * New translations settings.php (Chinese Simplified) * New translations settings.php (Italian) * New translations settings.php (Hungarian) * New translations settings.php (German) * New translations settings.php (French) * New translations settings.php (Dutch) * New translations settings.php (Danish) * New translations settings.php (Czech) * New translations settings.php (Chinese Traditional) * New translations settings.php (Arabic) * New translations settings.php (German Informal) * New translations common.php (Dutch) * New translations settings.php (Spanish) * New translations errors.php (Hungarian) * New translations settings.php (Hungarian) * New translations common.php (Hungarian) * New translations errors.php (Hungarian) * New translations settings.php (Hungarian) * New translations validation.php (Hungarian) * New translations errors.php (Portuguese, Brazilian) * New translations errors.php (Chinese Simplified) * New translations settings.php (Chinese Simplified) * New translations settings.php (Chinese Simplified) * New translations settings.php (Chinese Simplified) * New translations auth.php (Chinese Traditional) * New translations common.php (Chinese Traditional) * New translations entities.php (Chinese Traditional) * New translations errors.php (Chinese Traditional) * New translations entities.php (Chinese Traditional) * New translations settings.php (Chinese Traditional) * New translations settings.php (Chinese Traditional) * New translations settings.php (Chinese Traditional) * New translations settings.php (Chinese Simplified) * New translations settings.php (Chinese Traditional) * New translations validation.php (Chinese Traditional) * New translations validation.php (Chinese Traditional) * New translations errors.php (German) * New translations errors.php (German) * New translations settings.php (German) * New translations settings.php (German Informal) * New translations errors.php (French) * New translations settings.php (French) * New translations errors.php (Portuguese, Brazilian) * New translations settings.php (Portuguese, Brazilian) * New translations settings.php (Portuguese, Brazilian) * New translations settings.php (Portuguese, Brazilian) * New translations settings.php (Hungarian) * New translations settings.php (Hungarian) * New translations validation.php (Hungarian) * New translations errors.php (Chinese Simplified) * New translations errors.php (Spanish) * New translations errors.php (Korean) * New translations settings.php (Korean) * New translations errors.php (Polish) * New translations settings.php (Polish) * New translations errors.php (Russian) * New translations settings.php (Russian) * New translations errors.php (Slovak) * New translations settings.php (Slovak) * New translations settings.php (Spanish) * New translations errors.php (Japanese) * New translations errors.php (Spanish, Argentina) * New translations settings.php (Spanish, Argentina) * New translations errors.php (Swedish) * New translations settings.php (Swedish) * New translations errors.php (Turkish) * New translations settings.php (Turkish) * New translations errors.php (Ukrainian) * New translations settings.php (Ukrainian) * New translations settings.php (Japanese) * New translations settings.php (Italian) * New translations settings.php (Chinese Simplified) * New translations settings.php (Portuguese, Brazilian) * New translations errors.php (Chinese Traditional) * New translations settings.php (Chinese Traditional) * New translations errors.php (French) * New translations settings.php (French) * New translations errors.php (German) * New translations settings.php (German) * New translations settings.php (Hungarian) * New translations errors.php (Portuguese, Brazilian) * New translations settings.php (German Informal) * New translations errors.php (Italian) * New translations errors.php (Arabic) * New translations settings.php (Arabic) * New translations errors.php (Czech) * New translations settings.php (Czech) * New translations errors.php (Danish) * New translations settings.php (Danish) * New translations errors.php (Dutch) * New translations settings.php (Dutch) * New translations errors.php (Hungarian) * New translations errors.php (German Informal) * New translations settings.php (Spanish) * New translations settings.php (French) * New translations settings.php (Chinese Simplified) * New translations settings.php (Japanese) * New translations settings.php (Turkish) * New translations settings.php (Swedish) * New translations settings.php (Spanish, Argentina) * New translations settings.php (Spanish) * New translations settings.php (Slovak) * New translations settings.php (Russian) * New translations settings.php (Polish) * New translations settings.php (Korean) * New translations settings.php (Italian) * New translations settings.php (Chinese Traditional) * New translations settings.php (Dutch) * New translations settings.php (Danish) * New translations settings.php (Czech) * New translations settings.php (Arabic) * New translations settings.php (German Informal) * New translations settings.php (Portuguese, Brazilian) * New translations settings.php (Hungarian) * New translations settings.php (German) * New translations settings.php (French) * New translations settings.php (Ukrainian) --- resources/lang/ar/errors.php | 1 - resources/lang/ar/settings.php | 5 +- resources/lang/cs/errors.php | 1 - resources/lang/cs/settings.php | 5 +- resources/lang/da/errors.php | 1 - resources/lang/da/settings.php | 5 +- resources/lang/de/errors.php | 15 ++- resources/lang/de/settings.php | 51 ++++----- resources/lang/de_informal/errors.php | 15 ++- resources/lang/de_informal/settings.php | 51 ++++----- resources/lang/es/errors.php | 15 ++- resources/lang/es/settings.php | 51 ++++----- resources/lang/es_AR/errors.php | 15 ++- resources/lang/es_AR/settings.php | 51 ++++----- resources/lang/fr/errors.php | 11 +- resources/lang/fr/settings.php | 43 ++++---- resources/lang/hu/common.php | 2 +- resources/lang/hu/errors.php | 15 ++- resources/lang/hu/settings.php | 49 ++++----- resources/lang/hu/validation.php | 6 +- resources/lang/it/errors.php | 1 - resources/lang/it/settings.php | 5 +- resources/lang/ja/errors.php | 1 - resources/lang/ja/settings.php | 5 +- resources/lang/ko/errors.php | 1 - resources/lang/ko/settings.php | 5 +- resources/lang/nl/common.php | 2 +- resources/lang/nl/errors.php | 1 - resources/lang/nl/settings.php | 5 +- resources/lang/pl/errors.php | 1 - resources/lang/pl/settings.php | 5 +- resources/lang/pt_BR/errors.php | 15 ++- resources/lang/pt_BR/settings.php | 55 +++++----- resources/lang/ru/errors.php | 1 - resources/lang/ru/settings.php | 5 +- resources/lang/sk/errors.php | 1 - resources/lang/sk/settings.php | 5 +- resources/lang/sv/errors.php | 1 - resources/lang/sv/settings.php | 5 +- resources/lang/tr/errors.php | 1 - resources/lang/tr/settings.php | 5 +- resources/lang/uk/errors.php | 1 - resources/lang/uk/settings.php | 5 +- resources/lang/zh_CN/errors.php | 15 ++- resources/lang/zh_CN/settings.php | 55 +++++----- resources/lang/zh_TW/auth.php | 24 ++--- resources/lang/zh_TW/common.php | 30 +++--- resources/lang/zh_TW/entities.php | 44 ++++---- resources/lang/zh_TW/errors.php | 29 +++--- resources/lang/zh_TW/settings.php | 131 ++++++++++++------------ resources/lang/zh_TW/validation.php | 48 ++++----- 51 files changed, 458 insertions(+), 458 deletions(-) diff --git a/resources/lang/ar/errors.php b/resources/lang/ar/errors.php index 961ce7351..c1f53e171 100644 --- a/resources/lang/ar/errors.php +++ b/resources/lang/ar/errors.php @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', - 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => 'لم يتم تعريف أي إجراء', 'social_login_bad_response' => "حصل خطأ خلال تسجيل الدخول باستخدام :socialAccount \n:error", 'social_account_in_use' => 'حساب :socialAccount قيد الاستخدام حالياً, الرجاء محاولة الدخول باستخدام خيار :socialAccount.', diff --git a/resources/lang/ar/settings.php b/resources/lang/ar/settings.php index 26b936254..c3216aa07 100755 --- a/resources/lang/ar/settings.php +++ b/resources/lang/ar/settings.php @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => 'Enable registration', 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', 'reg_default_role' => 'دور المستخدم الأساسي بعد التسجيل', - 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'Email Confirmation', 'reg_email_confirmation_toggle' => 'Require email confirmation', 'reg_confirm_email_desc' => 'إذا تم استخدام قيود للمجال سيصبح التأكيد عن طريق البريد الإلكتروني إلزامي وسيتم تجاهل القيمة أسفله.', @@ -131,7 +131,7 @@ return [ 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', 'users_send_invite_option' => 'Send user invite email', 'users_external_auth_id' => 'External Authentication ID', - 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your LDAP system.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'الرجاء ملئ الحقل أدناه فقط في حال أردتم تغيير كلمة المرور:', 'users_system_public' => 'هذا المستخدم يمثل أي ضيف يقوم بزيارة شيء يخصك. لا يمكن استخدامه لتسجيل الدخول ولكن يتم تعيينه تلقائياً.', 'users_delete' => 'حذف المستخدم', @@ -185,6 +185,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/cs/errors.php b/resources/lang/cs/errors.php index 5d9a3feb9..ebcf3f44e 100644 --- a/resources/lang/cs/errors.php +++ b/resources/lang/cs/errors.php @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', - 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => 'Nebyla zvolena žádá akce', 'social_login_bad_response' => "Nastala chyba během přihlašování přes :socialAccount \n:error", 'social_account_in_use' => 'Tento účet na :socialAccount se již používá. Pokuste se s ním přihlásit volbou Přihlásit přes :socialAccount.', diff --git a/resources/lang/cs/settings.php b/resources/lang/cs/settings.php index ca10a3318..7488560a7 100644 --- a/resources/lang/cs/settings.php +++ b/resources/lang/cs/settings.php @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => 'Enable registration', 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', 'reg_default_role' => 'Role přiřazená po registraci', - 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'Email Confirmation', 'reg_email_confirmation_toggle' => 'Require email confirmation', 'reg_confirm_email_desc' => 'Pokud zapnete omezení emailové domény, tak bude ověřování emailové adresy vyžadováno vždy.', @@ -131,7 +131,7 @@ return [ 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', 'users_send_invite_option' => 'Send user invite email', 'users_external_auth_id' => 'Přihlašovací identifikátory třetích stran', - 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your LDAP system.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Vyplňujte pouze v případě, že chcete heslo změnit:', 'users_system_public' => 'Symbolizuje libovolného veřejného návštěvníka, který navštívil vaší aplikaci. Nelze ho použít k přihlášení ale je přiřazen automaticky veřejnosti.', 'users_delete' => 'Smazat uživatele', @@ -185,6 +185,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/da/errors.php b/resources/lang/da/errors.php index 5d286b03c..e92dab45c 100644 --- a/resources/lang/da/errors.php +++ b/resources/lang/da/errors.php @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', - 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => 'No action defined', 'social_login_bad_response' => "Error received during :socialAccount login: \n:error", 'social_account_in_use' => 'This :socialAccount account is already in use, Try logging in via the :socialAccount option.', diff --git a/resources/lang/da/settings.php b/resources/lang/da/settings.php index 9bf384c3b..b653f0950 100644 --- a/resources/lang/da/settings.php +++ b/resources/lang/da/settings.php @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => 'Aktivér tilmelding', 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', 'reg_default_role' => 'Default user role after registration', - 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'Email bekræftelse', 'reg_email_confirmation_toggle' => 'Require email confirmation', 'reg_confirm_email_desc' => 'If domain restriction is used then email confirmation will be required and this option will be ignored.', @@ -131,7 +131,7 @@ return [ 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', 'users_send_invite_option' => 'Send user invite email', 'users_external_auth_id' => 'Ekstern godkendelses ID', - 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your LDAP system.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Only fill the below if you would like to change your password.', 'users_system_public' => 'This user represents any guest users that visit your instance. It cannot be used to log in but is assigned automatically.', 'users_delete' => 'Delete User', @@ -185,6 +185,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/de/errors.php b/resources/lang/de/errors.php index 1912d01a0..1b81bf36e 100644 --- a/resources/lang/de/errors.php +++ b/resources/lang/de/errors.php @@ -13,7 +13,7 @@ return [ 'email_already_confirmed' => 'Die E-Mail-Adresse ist bereits bestätigt. Bitte melden Sie sich an.', 'email_confirmation_invalid' => 'Der Bestätigungslink ist nicht gültig oder wurde bereits verwendet. Bitte registrieren Sie sich erneut.', 'email_confirmation_expired' => 'Der Bestätigungslink ist abgelaufen. Es wurde eine neue Bestätigungs-E-Mail gesendet.', - 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', + 'email_confirmation_awaiting' => 'Die E-Mail-Adresse für das verwendete Konto muss bestätigt werden', 'ldap_fail_anonymous' => 'Anonymer LDAP-Zugriff ist fehlgeschlafgen', 'ldap_fail_authed' => 'LDAP-Zugriff mit DN und Passwort ist fehlgeschlagen', 'ldap_extension_not_installed' => 'LDAP-PHP-Erweiterung ist nicht installiert.', @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => 'Es konnte keine E-Mail-Adresse für diesen Benutzer in den vom externen Authentifizierungssystem zur Verfügung gestellten Daten gefunden werden', 'saml_invalid_response_id' => 'Die Anfrage vom externen Authentifizierungssystem wird von einem von dieser Anwendung gestarteten Prozess nicht erkannt. Das Zurückgehen nach einem Login könnte dieses Problem verursachen.', 'saml_fail_authed' => 'Anmeldung mit :system fehlgeschlagen, System konnte keine erfolgreiche Autorisierung bereitstellen', - 'saml_email_exists' => 'Registrierung fehlgeschlagen, da bereits ein Benutzer mit der E-Mail-Adresse ":email" existiert', 'social_no_action_defined' => 'Es ist keine Aktion definiert', 'social_login_bad_response' => "Fehler bei der :socialAccount-Anmeldung: \n:error", 'social_account_in_use' => 'Dieses :socialAccount-Konto wird bereits verwendet. Bitte melden Sie sich mit dem :socialAccount-Konto an.', @@ -90,11 +89,11 @@ return [ 'back_soon' => 'Wir werden so schnell wie möglich wieder online sein.', // API errors - 'api_no_authorization_found' => 'No authorization token found on the request', - 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', - 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', - 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', - 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', - 'api_user_token_expired' => 'The authorization token used has expired', + 'api_no_authorization_found' => 'Kein Autorisierungs-Token für die Anfrage gefunden', + 'api_bad_authorization_format' => 'Ein Autorisierungs-Token wurde auf die Anfrage gefunden, aber das Format schien falsch zu sein', + 'api_user_token_not_found' => 'Es wurde kein passender API-Token für den angegebenen Autorisierungs-Token gefunden', + 'api_incorrect_token_secret' => 'Das für den angegebenen API-Token angegebene Kennwort ist falsch', + 'api_user_no_api_permission' => 'Der Besitzer des verwendeten API-Token hat keine Berechtigung für API-Aufrufe', + 'api_user_token_expired' => 'Das verwendete Autorisierungs-Token ist abgelaufen', ]; diff --git a/resources/lang/de/settings.php b/resources/lang/de/settings.php index 29f5d42bb..98a04b062 100644 --- a/resources/lang/de/settings.php +++ b/resources/lang/de/settings.php @@ -58,7 +58,7 @@ Wenn Sie nicht eingeben, wird die Anwendung auf die Standardfarbe zurückgesetzt 'reg_enable_toggle' => 'Registrierung erlauben', 'reg_enable_desc' => 'Wenn die Registrierung erlaubt ist, kann sich der Benutzer als Anwendungsbenutzer anmelden. Bei der Registrierung erhält er eine einzige, voreingestellte Benutzerrolle.', 'reg_default_role' => 'Standard-Benutzerrolle nach Registrierung', - 'reg_enable_ldap_warning' => 'Die obige Option wird während der LDAP-Authentifizierung nicht verwendet. Benutzerkonten für nicht existierende Mitglieder werden automatisch erzeugt, wenn die Authentifizierung gegen das verwendete LDAP-System erfolgreich ist.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'Bestätigung per E-Mail', 'reg_email_confirmation_toggle' => 'Bestätigung per E-Mail erforderlich', 'reg_confirm_email_desc' => 'Falls die Einschränkung für Domains genutzt wird, ist die Bestätigung per E-Mail zwingend erforderlich und der untenstehende Wert wird ignoriert.', @@ -106,7 +106,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'role_manage_entity_permissions' => 'Alle Buch-, Kapitel- und Seiten-Berechtigungen verwalten', 'role_manage_own_entity_permissions' => 'Nur Berechtigungen eigener Bücher, Kapitel und Seiten verwalten', 'role_manage_page_templates' => 'Seitenvorlagen verwalten', - 'role_access_api' => 'Access system API', + 'role_access_api' => 'Systemzugriffs-API', 'role_manage_settings' => 'Globaleinstellungen verwalten', 'role_asset' => 'Berechtigungen', 'role_asset_desc' => 'Diese Berechtigungen gelten für den Standard-Zugriff innerhalb des Systems. Berechtigungen für Bücher, Kapitel und Seiten überschreiben diese Berechtigungenen.', @@ -134,7 +134,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'users_send_invite_text' => 'Sie können diesem Benutzer eine Einladungs-E-Mail senden, die es ihm erlaubt, sein eigenes Passwort zu setzen, andernfalls können Sie sein Passwort selbst setzen.', 'users_send_invite_option' => 'Benutzer-Einladungs-E-Mail senden', 'users_external_auth_id' => 'Externe Authentifizierungs-ID', - 'users_external_auth_id_desc' => 'Dies ist die ID, die verwendet wird, um diesen Benutzer bei der Kommunikation mit Ihrem LDAP-System abzugleichen.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Füllen Sie die folgenden Felder nur aus, wenn Sie Ihr Passwort ändern möchten:', 'users_system_public' => 'Dieser Benutzer repräsentiert alle unangemeldeten Benutzer, die diese Seite betrachten. Er kann nicht zum Anmelden benutzt werden, sondern wird automatisch zugeordnet.', 'users_delete' => 'Benutzer löschen', @@ -155,32 +155,32 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'users_social_disconnect' => 'Social-Media-Konto lösen', 'users_social_connected' => ':socialAccount-Konto wurde erfolgreich mit dem Profil verknüpft.', 'users_social_disconnected' => ':socialAccount-Konto wurde erfolgreich vom Profil gelöst.', - 'users_api_tokens' => 'API Tokens', - 'users_api_tokens_none' => 'No API tokens have been created for this user', - 'users_api_tokens_create' => 'Create Token', - 'users_api_tokens_expires' => 'Expires', - 'users_api_tokens_docs' => 'API Documentation', + 'users_api_tokens' => 'API-Token', + 'users_api_tokens_none' => 'Für diesen Benutzer wurden keine API-Token erstellt', + 'users_api_tokens_create' => 'Token erstellen', + 'users_api_tokens_expires' => 'Endet', + 'users_api_tokens_docs' => 'API Dokumentation', // API Tokens - 'user_api_token_create' => 'Create API Token', + 'user_api_token_create' => 'Neuen API-Token erstellen', 'user_api_token_name' => 'Name', - 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', - 'user_api_token_expiry' => 'Expiry Date', - 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', - 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', - 'user_api_token_create_success' => 'API token successfully created', - 'user_api_token_update_success' => 'API token successfully updated', - 'user_api_token' => 'API Token', + 'user_api_token_name_desc' => 'Geben Sie Ihrem Token einen aussagekräftigen Namen als spätere Erinnerung an seinen Verwendungszweck.', + 'user_api_token_expiry' => 'Ablaufdatum', + 'user_api_token_expiry_desc' => 'Legen Sie ein Datum fest, an dem dieser Token abläuft. Nach diesem Datum funktionieren Anfragen, die mit diesem Token gestellt werden, nicht mehr. Wenn Sie dieses Feld leer lassen, wird ein Ablaufdatum von 100 Jahren in der Zukunft festgelegt.', + 'user_api_token_create_secret_message' => 'Unmittelbar nach der Erstellung dieses Tokens wird eine "Token ID" & ein "Token Kennwort" generiert und angezeigt. Das Kennwort wird nur ein einziges Mal angezeigt. Stellen Sie also sicher, dass Sie den Inhalt an einen sicheren Ort kopieren, bevor Sie fortfahren.', + 'user_api_token_create_success' => 'API-Token erfolgreich erstellt', + 'user_api_token_update_success' => 'API-Token erfolgreich aktualisiert', + 'user_api_token' => 'API-Token', 'user_api_token_id' => 'Token ID', - 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', - 'user_api_token_secret' => 'Token Secret', - 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', - 'user_api_token_created' => 'Token Created :timeAgo', - 'user_api_token_updated' => 'Token Updated :timeAgo', - 'user_api_token_delete' => 'Delete Token', - 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', - 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', - 'user_api_token_delete_success' => 'API token successfully deleted', + 'user_api_token_id_desc' => 'Dies ist ein nicht editierbarer, vom System generierter Identifikator für diesen Token, welcher bei API-Anfragen angegeben werden muss.', + 'user_api_token_secret' => 'Token Kennwort', + 'user_api_token_secret_desc' => 'Dies ist ein systemgeneriertes Kennwort für diesen Token, das bei API-Anfragen zur Verfügung gestellt werden muss. Es wird nur dieses eine Mal angezeigt, deshalb kopieren Sie diesen Wert an einen sicheren und geschützten Ort.', + 'user_api_token_created' => 'Token erstellt :timeAgo', + 'user_api_token_updated' => 'Token aktualisiert :timeAgo', + 'user_api_token_delete' => 'Lösche Token', + 'user_api_token_delete_warning' => 'Dies löscht den API-Token mit dem Namen \':tokenName\' vollständig aus dem System.', + 'user_api_token_delete_confirm' => 'Sind Sie sicher, dass Sie diesen API-Token löschen möchten?', + 'user_api_token_delete_success' => 'API-Token erfolgreich gelöscht', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. @@ -188,6 +188,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Dänisch', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/de_informal/errors.php b/resources/lang/de_informal/errors.php index 097c983af..a5dac12eb 100644 --- a/resources/lang/de_informal/errors.php +++ b/resources/lang/de_informal/errors.php @@ -13,7 +13,7 @@ return [ 'email_already_confirmed' => 'Die E-Mail-Adresse ist bereits bestätigt. Bitte melde dich an.', 'email_confirmation_invalid' => 'Der Bestätigungslink ist nicht gültig oder wurde bereits verwendet. Bitte registriere dich erneut.', 'email_confirmation_expired' => 'Der Bestätigungslink ist abgelaufen. Es wurde eine neue Bestätigungs-E-Mail gesendet.', - 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', + 'email_confirmation_awaiting' => 'Die E-Mail-Adresse für das verwendete Konto muss bestätigt werden', 'ldap_fail_anonymous' => 'Anonymer LDAP-Zugriff ist fehlgeschlafgen', 'ldap_fail_authed' => 'LDAP-Zugriff mit DN und Passwort ist fehlgeschlagen', 'ldap_extension_not_installed' => 'LDAP-PHP-Erweiterung ist nicht installiert.', @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => 'Es konnte keine E-Mail-Adresse für diesen Benutzer in den vom externen Authentifizierungssystem zur Verfügung gestellten Daten gefunden werden', 'saml_invalid_response_id' => 'Die Anfrage vom externen Authentifizierungssystem wird von einem von dieser Anwendung gestarteten Prozess nicht erkannt. Das Zurückgehen nach einem Login könnte dieses Problem verursachen.', 'saml_fail_authed' => 'Anmeldung mit :system fehlgeschlagen, System konnte keine erfolgreiche Autorisierung bereitstellen', - 'saml_email_exists' => 'Registrierung fehlgeschlagen, da bereits ein Benutzer mit der E-Mail-Adresse ":email" existiert', 'social_no_action_defined' => 'Es ist keine Aktion definiert', 'social_login_bad_response' => "Fehler bei der :socialAccount-Anmeldung: \n:error", 'social_account_in_use' => 'Dieses :socialAccount-Konto wird bereits verwendet. Bitte melde dich mit dem :socialAccount-Konto an.', @@ -90,11 +89,11 @@ return [ 'back_soon' => 'Wir werden so schnell wie möglich wieder online sein.', // API errors - 'api_no_authorization_found' => 'No authorization token found on the request', - 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', - 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', - 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', - 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', - 'api_user_token_expired' => 'The authorization token used has expired', + 'api_no_authorization_found' => 'Kein Autorisierungs-Token für die Anfrage gefunden', + 'api_bad_authorization_format' => 'Ein Autorisierungs-Token wurde auf die Anfrage gefunden, aber das Format schien falsch zu sein', + 'api_user_token_not_found' => 'Es wurde kein passender API-Token für den angegebenen Autorisierungs-Token gefunden', + 'api_incorrect_token_secret' => 'Das für den angegebenen API-Token angegebene Kennwort ist falsch', + 'api_user_no_api_permission' => 'Der Besitzer des verwendeten API-Token hat keine Berechtigung für API-Aufrufe', + 'api_user_token_expired' => 'Das verwendete Autorisierungs-Token ist abgelaufen', ]; diff --git a/resources/lang/de_informal/settings.php b/resources/lang/de_informal/settings.php index 260793f09..fb563ffdf 100644 --- a/resources/lang/de_informal/settings.php +++ b/resources/lang/de_informal/settings.php @@ -58,7 +58,7 @@ Wenn Du nichts eingibst, wird die Anwendung auf die Standardfarbe zurückgesetzt 'reg_enable_toggle' => 'Registrierung erlauben', 'reg_enable_desc' => 'Wenn die Registrierung erlaubt ist, kann sich der Benutzer als Anwendungsbenutzer anmelden. Bei der Registrierung erhält er eine einzige, voreingestellte Benutzerrolle.', 'reg_default_role' => 'Standard-Benutzerrolle nach Registrierung', - 'reg_enable_ldap_warning' => 'Die obige Option wird während der LDAP-Authentifizierung nicht verwendet. Benutzerkonten für nicht existierende Mitglieder werden automatisch erzeugt, wenn die Authentifizierung gegen das verwendete LDAP-System erfolgreich ist.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'Bestätigung per E-Mail', 'reg_email_confirmation_toggle' => 'Bestätigung per E-Mail erforderlich', 'reg_confirm_email_desc' => 'Falls die Einschränkung für Domains genutzt wird, ist die Bestätigung per E-Mail zwingend erforderlich und der untenstehende Wert wird ignoriert.', @@ -106,7 +106,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'role_manage_entity_permissions' => 'Alle Buch-, Kapitel- und Seiten-Berechtigungen verwalten', 'role_manage_own_entity_permissions' => 'Nur Berechtigungen eigener Bücher, Kapitel und Seiten verwalten', 'role_manage_page_templates' => 'Seitenvorlagen verwalten', - 'role_access_api' => 'Access system API', + 'role_access_api' => 'Systemzugriffs-API', 'role_manage_settings' => 'Globaleinstellungen verwalten', 'role_asset' => 'Berechtigungen', 'role_asset_desc' => 'Diese Berechtigungen gelten für den Standard-Zugriff innerhalb des Systems. Berechtigungen für Bücher, Kapitel und Seiten überschreiben diese Berechtigungenen.', @@ -134,7 +134,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'users_send_invite_text' => 'Sie können diesem Benutzer eine Einladungs-E-Mail senden, die es ihm erlaubt, sein eigenes Passwort zu setzen, andernfalls können Sie sein Passwort selbst setzen.', 'users_send_invite_option' => 'Benutzer-Einladungs-E-Mail senden', 'users_external_auth_id' => 'Externe Authentifizierungs-ID', - 'users_external_auth_id_desc' => 'Dies ist die ID, die verwendet wird, um diesen Benutzer bei der Kommunikation mit Ihrem LDAP-System abzugleichen.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Fülle die folgenden Felder nur aus, wenn Du Dein Passwort ändern möchtest:', 'users_system_public' => 'Dieser Benutzer repräsentiert alle unangemeldeten Benutzer, die diese Seite betrachten. Er kann nicht zum Anmelden benutzt werden, sondern wird automatisch zugeordnet.', 'users_delete' => 'Benutzer löschen', @@ -155,32 +155,32 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'users_social_disconnect' => 'Social-Media-Konto lösen', 'users_social_connected' => ':socialAccount-Konto wurde erfolgreich mit dem Profil verknüpft.', 'users_social_disconnected' => ':socialAccount-Konto wurde erfolgreich vom Profil gelöst.', - 'users_api_tokens' => 'API Tokens', - 'users_api_tokens_none' => 'No API tokens have been created for this user', - 'users_api_tokens_create' => 'Create Token', - 'users_api_tokens_expires' => 'Expires', - 'users_api_tokens_docs' => 'API Documentation', + 'users_api_tokens' => 'API-Token', + 'users_api_tokens_none' => 'Für diesen Benutzer wurden keine API-Token erstellt', + 'users_api_tokens_create' => 'Token erstellen', + 'users_api_tokens_expires' => 'Endet', + 'users_api_tokens_docs' => 'API Dokumentation', // API Tokens - 'user_api_token_create' => 'Create API Token', + 'user_api_token_create' => 'Neuen API-Token erstellen', 'user_api_token_name' => 'Name', - 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', - 'user_api_token_expiry' => 'Expiry Date', - 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', - 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', - 'user_api_token_create_success' => 'API token successfully created', - 'user_api_token_update_success' => 'API token successfully updated', - 'user_api_token' => 'API Token', + 'user_api_token_name_desc' => 'Geben Sie Ihrem Token einen aussagekräftigen Namen als spätere Erinnerung an seinen Verwendungszweck.', + 'user_api_token_expiry' => 'Ablaufdatum', + 'user_api_token_expiry_desc' => 'Legen Sie ein Datum fest, an dem dieser Token abläuft. Nach diesem Datum funktionieren Anfragen, die mit diesem Token gestellt werden, nicht mehr. Wenn Sie dieses Feld leer lassen, wird ein Ablaufdatum von 100 Jahren in der Zukunft festgelegt.', + 'user_api_token_create_secret_message' => 'Unmittelbar nach der Erstellung dieses Tokens wird eine "Token ID" & ein "Token Kennwort" generiert und angezeigt. Das Kennwort wird nur ein einziges Mal angezeigt. Stellen Sie also sicher, dass Sie den Inhalt an einen sicheren Ort kopieren, bevor Sie fortfahren.', + 'user_api_token_create_success' => 'API-Token erfolgreich erstellt', + 'user_api_token_update_success' => 'API-Token erfolgreich aktualisiert', + 'user_api_token' => 'API-Token', 'user_api_token_id' => 'Token ID', - 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', - 'user_api_token_secret' => 'Token Secret', - 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', - 'user_api_token_created' => 'Token Created :timeAgo', - 'user_api_token_updated' => 'Token Updated :timeAgo', - 'user_api_token_delete' => 'Delete Token', - 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', - 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', - 'user_api_token_delete_success' => 'API token successfully deleted', + 'user_api_token_id_desc' => 'Dies ist ein nicht editierbarer, vom System generierter Identifikator für diesen Token, welcher bei API-Anfragen angegeben werden muss.', + 'user_api_token_secret' => 'Token Kennwort', + 'user_api_token_secret_desc' => 'Dies ist ein systemgeneriertes Kennwort für diesen Token, das bei API-Anfragen zur Verfügung gestellt werden muss. Es wird nur dieses eine Mal angezeigt, deshalb kopieren Sie diesen Wert an einen sicheren und geschützten Ort.', + 'user_api_token_created' => 'Token erstellt :timeAgo', + 'user_api_token_updated' => 'Token aktualisiert :timeAgo', + 'user_api_token_delete' => 'Lösche Token', + 'user_api_token_delete_warning' => 'Dies löscht den API-Token mit dem Namen \':tokenName\' vollständig aus dem System.', + 'user_api_token_delete_confirm' => 'Sind Sie sicher, dass Sie diesen API-Token löschen möchten?', + 'user_api_token_delete_success' => 'API-Token erfolgreich gelöscht', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. @@ -188,6 +188,7 @@ Hinweis: Benutzer können ihre E-Mail Adresse nach erfolgreicher Registrierung 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Dänisch', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/es/errors.php b/resources/lang/es/errors.php index ddae6ee5c..65b20afc7 100644 --- a/resources/lang/es/errors.php +++ b/resources/lang/es/errors.php @@ -13,7 +13,7 @@ return [ 'email_already_confirmed' => 'El correo electrónico ya ha sido confirmado, intente acceder a la aplicación.', 'email_confirmation_invalid' => 'Este token de confirmación no es válido o ya ha sido usado, intente registrar uno nuevamente.', 'email_confirmation_expired' => 'El token de confirmación ha expirado, un nuevo email de confirmacón ha sido enviado.', - 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', + 'email_confirmation_awaiting' => 'La dirección de correo electrónico de la cuenta en uso debe ser confirmada', 'ldap_fail_anonymous' => 'El acceso con LDAP ha fallado usando binding anónimo', 'ldap_fail_authed' => 'El acceso LDAP ha fallado usando el dn & contraseña enviados', 'ldap_extension_not_installed' => 'La extensión LDAP PHP no se encuentra instalada', @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => 'No se pudo encontrar una dirección de correo electrónico, para este usuario, en los datos proporcionados por el sistema de autenticación externo', 'saml_invalid_response_id' => 'La solicitud del sistema de autenticación externo no está reconocida por un proceso iniciado por esta aplicación. Navegar hacia atrás después de un inicio de sesión podría causar este problema.', 'saml_fail_authed' => 'El inicio de sesión con :system falló, el sistema no proporcionó una autorización correcta', - 'saml_email_exists' => 'Registro fallido porque un usuario ya existe con la dirección de correo electrónico ":email"', 'social_no_action_defined' => 'Acción no definida', 'social_login_bad_response' => "Se ha recibido un error durante el acceso con :socialAccount error: \n:error", 'social_account_in_use' => 'la cuenta :socialAccount ya se encuentra en uso, intente acceder a través de la opción :socialAccount .', @@ -90,11 +89,11 @@ return [ 'back_soon' => 'Volverá a estar operativa pronto.', // API errors - 'api_no_authorization_found' => 'No authorization token found on the request', - 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', - 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', - 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', - 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', - 'api_user_token_expired' => 'The authorization token used has expired', + 'api_no_authorization_found' => 'No se encontró ningún token de autorización en la solicitud', + 'api_bad_authorization_format' => 'Se ha encontrado un token de autorización en la solicitud pero el formato era incorrecto', + 'api_user_token_not_found' => 'No se ha encontrado un token API que corresponda con el token de autorización proporcionado', + 'api_incorrect_token_secret' => 'El secreto proporcionado para el token API usado es incorrecto', + 'api_user_no_api_permission' => 'El propietario del token API usado no tiene permiso para hacer llamadas API', + 'api_user_token_expired' => 'El token de autorización usado ha caducado', ]; diff --git a/resources/lang/es/settings.php b/resources/lang/es/settings.php index 41e49fe29..ff5c40ee1 100644 --- a/resources/lang/es/settings.php +++ b/resources/lang/es/settings.php @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => 'Habilitar registro', 'reg_enable_desc' => 'Cuando se habilita el registro los usuarios podrán registrarse como usuarios de la aplicación. Al registrarse se les asigna un rol único por defecto.', 'reg_default_role' => 'Rol de usuario por defecto después del registro', - 'reg_enable_ldap_warning' => 'La opción anterior no se utiliza mientras la autenticación LDAP está activa. Las cuentas de usuario para los miembros no existentes se crearán automáticamente si la autenticación, contra el sistema LDAP en uso, es exitosa.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'Confirmación por Email', 'reg_email_confirmation_toggle' => 'Requerir confirmación por Email', 'reg_confirm_email_desc' => 'Si se emplea la restricción por dominio, entonces se requerirá la confirmación por correo electrónico y esta opción será ignorada.', @@ -103,7 +103,7 @@ return [ 'role_manage_entity_permissions' => 'Gestionar todos los permisos de libros, capítulos y páginas', 'role_manage_own_entity_permissions' => 'Gestionar permisos en libros, capítulos y páginas propias', 'role_manage_page_templates' => 'Administrar plantillas', - 'role_access_api' => 'Access system API', + 'role_access_api' => 'API de sistema de acceso', 'role_manage_settings' => 'Gestionar ajustes de la aplicación', 'role_asset' => 'Permisos de contenido', 'role_asset_desc' => 'Estos permisos controlan el acceso por defecto a los contenidos del sistema. Los permisos de Libros, Capítulos y Páginas sobreescribiran estos permisos.', @@ -131,7 +131,7 @@ return [ 'users_send_invite_text' => 'Puede enviar una invitación a este usuario por correo electrónico que le permitirá ajustar su propia contraseña, o puede usted ajustar su contraseña.', 'users_send_invite_option' => 'Enviar un correo electrónico de invitación', 'users_external_auth_id' => 'ID externo de autenticación', - 'users_external_auth_id_desc' => 'Esta es la ID usada para asociar este usuario con LDAP.', + 'users_external_auth_id_desc' => 'Esta es la ID usada para asociar este usuario con el sistema de autenticación externo.', 'users_password_warning' => 'Solo debe rellenar este campo si desea cambiar su contraseña.', 'users_system_public' => 'Este usuario representa cualquier usuario invitado que visita la aplicación. No puede utilizarse para acceder pero es asignado automáticamente.', 'users_delete' => 'Borrar usuario', @@ -152,32 +152,32 @@ return [ 'users_social_disconnect' => 'Desconectar cuenta', 'users_social_connected' => 'La cuenta :socialAccount ha sido añadida éxitosamente a su perfil.', 'users_social_disconnected' => 'La cuenta :socialAccount ha sido desconectada éxitosamente de su perfil.', - 'users_api_tokens' => 'API Tokens', - 'users_api_tokens_none' => 'No API tokens have been created for this user', - 'users_api_tokens_create' => 'Create Token', - 'users_api_tokens_expires' => 'Expires', - 'users_api_tokens_docs' => 'API Documentation', + 'users_api_tokens' => 'Tokens API', + 'users_api_tokens_none' => 'No se han creado tokens API para este usuario', + 'users_api_tokens_create' => 'Crear token', + 'users_api_tokens_expires' => 'Expira', + 'users_api_tokens_docs' => 'Documentación API', // API Tokens - 'user_api_token_create' => 'Create API Token', - 'user_api_token_name' => 'Name', - 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', - 'user_api_token_expiry' => 'Expiry Date', - 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', - 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', - 'user_api_token_create_success' => 'API token successfully created', - 'user_api_token_update_success' => 'API token successfully updated', - 'user_api_token' => 'API Token', + 'user_api_token_create' => 'Crear token API', + 'user_api_token_name' => 'Nombre', + 'user_api_token_name_desc' => 'Dale a tu token un nombre legible como un recordatorio futuro de su propósito.', + 'user_api_token_expiry' => 'Fecha de expiración', + 'user_api_token_expiry_desc' => 'Establece una fecha en la que este token expira. Después de esta fecha, las solicitudes realizadas usando este token ya no funcionarán. Dejar este campo en blanco fijará un vencimiento de 100 años en el futuro.', + 'user_api_token_create_secret_message' => 'Inmediatamente después de crear este token se generarán y mostrarán sus correspondientes "Token ID" y "Token Secret". El "Token Secret" sólo se mostrará una vez, así que asegúrese de copiar el valor a un lugar seguro antes de proceder.', + 'user_api_token_create_success' => 'Token API creado correctamente', + 'user_api_token_update_success' => 'Token API actualizado correctamente', + 'user_api_token' => 'Token API', 'user_api_token_id' => 'Token ID', - 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_id_desc' => 'Este es un identificador no editable generado por el sistema y único para este token que necesitará ser proporcionado en solicitudes de API.', 'user_api_token_secret' => 'Token Secret', - 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', - 'user_api_token_created' => 'Token Created :timeAgo', - 'user_api_token_updated' => 'Token Updated :timeAgo', - 'user_api_token_delete' => 'Delete Token', - 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', - 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', - 'user_api_token_delete_success' => 'API token successfully deleted', + 'user_api_token_secret_desc' => 'Esta es una clave no editable generada por el sistema que necesitará ser proporcionada en solicitudes de API. Solo se monstraré esta vez así que guarde su valor en un lugar seguro.', + 'user_api_token_created' => 'Token creado :timeAgo', + 'user_api_token_updated' => 'Token actualizado :timeAgo', + 'user_api_token_delete' => 'Borrar token', + 'user_api_token_delete_warning' => 'Esto eliminará completamente este token API con el nombre \':tokenName\' del sistema.', + 'user_api_token_delete_confirm' => '¿Está seguro de que desea borrar este API token?', + 'user_api_token_delete_success' => 'Token API borrado correctamente', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. @@ -185,6 +185,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Danés', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/es_AR/errors.php b/resources/lang/es_AR/errors.php index e14dccc22..a3ce98e08 100644 --- a/resources/lang/es_AR/errors.php +++ b/resources/lang/es_AR/errors.php @@ -13,7 +13,7 @@ return [ 'email_already_confirmed' => 'El email ya ha sido confirmado, Intente loguearse en la aplicación.', 'email_confirmation_invalid' => 'Este token de confirmación no e válido o ya ha sido usado,Intente registrar uno nuevamente.', 'email_confirmation_expired' => 'El token de confirmación ha expirado, Un nuevo email de confirmacón ha sido enviado.', - 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', + 'email_confirmation_awaiting' => 'La dirección de correo electrónico de la cuenta en uso debe ser confirmada', 'ldap_fail_anonymous' => 'El acceso con LDAP ha fallado usando binding anónimo', 'ldap_fail_authed' => 'El acceso LDAP usando el dn & password detallados', 'ldap_extension_not_installed' => 'La extensión LDAP PHP no se encuentra instalada', @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => 'No se pudo encontrar una dirección de correo electrónico, para este usuario, en los datos proporcionados por el sistema de autenticación externo', 'saml_invalid_response_id' => 'La solicitud del sistema de autenticación externo no está reconocida por un proceso iniciado por esta aplicación. Navegar hacia atrás después de un inicio de sesión podría causar este problema.', 'saml_fail_authed' => 'El inicio de sesión con :system falló, el sistema no proporcionó una autorización correcta', - 'saml_email_exists' => 'Registro fallido porque un usuario ya existe con la dirección de correo electrónico ":email"', 'social_no_action_defined' => 'Acción no definida', 'social_login_bad_response' => "SE recibió un Error durante el acceso con :socialAccount : \n:error", 'social_account_in_use' => 'la cuenta :socialAccount ya se encuentra en uso, intente loguearse a través de la opcón :socialAccount .', @@ -90,11 +89,11 @@ return [ 'back_soon' => 'Volverá a estar operativa en corto tiempo.', // API errors - 'api_no_authorization_found' => 'No authorization token found on the request', - 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', - 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', - 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', - 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', - 'api_user_token_expired' => 'The authorization token used has expired', + 'api_no_authorization_found' => 'No se encontró ningún token de autorización en la solicitud', + 'api_bad_authorization_format' => 'Se ha encontrado un token de autorización en la solicitud pero el formato era incorrecto', + 'api_user_token_not_found' => 'No se ha encontrado un token API que corresponda con el token de autorización proporcionado', + 'api_incorrect_token_secret' => 'El secreto proporcionado para el token API usado es incorrecto', + 'api_user_no_api_permission' => 'El propietario del token API usado no tiene permiso para hacer llamadas API', + 'api_user_token_expired' => 'El token de autorización usado ha caducado', ]; diff --git a/resources/lang/es_AR/settings.php b/resources/lang/es_AR/settings.php index 4250d7173..465e2ed07 100644 --- a/resources/lang/es_AR/settings.php +++ b/resources/lang/es_AR/settings.php @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => 'Habilitar registro', 'reg_enable_desc' => 'Cuando se habilita el registro, el usuario podrá crear su usuario en la aplicación. Con el regsitro, se le otorga un rol de usuario único y por defecto.', 'reg_default_role' => 'Rol de usuario por defecto despúes del registro', - 'reg_enable_ldap_warning' => 'La opción anterior no se utiliza mientras la autenticación LDAP está activa. Las cuentas de usuario para los miembros no existentes se crearán automáticamente si la autenticación, contra el sistema LDAP en uso, es exitosa.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'Confirmación de correo electrónico', 'reg_email_confirmation_toggle' => 'Requerir confirmación de correo electrónico', 'reg_confirm_email_desc' => 'Si se utiliza la restricción por dominio, entonces se requerirá la confirmación por correo electrónico y se ignorará el valor a continuación.', @@ -104,7 +104,7 @@ return [ 'role_manage_own_entity_permissions' => 'Gestionar permisos en libro s propios, capítulos y páginas', 'role_manage_page_templates' => 'Gestionar las plantillas de páginas', - 'role_access_api' => 'Access system API', + 'role_access_api' => 'API de sistema de acceso', 'role_manage_settings' => 'Gestionar ajustes de activos', 'role_asset' => 'Permisos de activos', 'role_asset_desc' => 'Estos permisos controlan el acceso por defecto a los activos del sistema. Permisos a Libros, Capítulos y Páginas sobreescribiran estos permisos.', @@ -132,7 +132,7 @@ return [ 'users_send_invite_text' => 'Puede optar por enviar a este usuario un correo electrónico de invitación que les permita establecer su propia contraseña; de lo contrario, puede establecerla contraseña usted mismo.', 'users_send_invite_option' => 'Enviar correo electrónico de invitación al usuario.', 'users_external_auth_id' => 'ID externo de autenticación', - 'users_external_auth_id_desc' => 'Esta es la ID usada para asociar este usuario con LDAP.', + 'users_external_auth_id_desc' => 'Esta es la ID usada para asociar este usuario con el sistema de autenticación externo.', 'users_password_warning' => 'Solo rellene a continuación si desea cambiar su password:', 'users_system_public' => 'Este usuario representa cualquier usuario invitado que visita la aplicación. No puede utilizarse para hacer login sino que es asignado automáticamente.', 'users_delete' => 'Borrar usuario', @@ -153,32 +153,32 @@ return [ 'users_social_disconnect' => 'Desconectar cuenta', 'users_social_connected' => 'La cuenta :socialAccount ha sido exitosamente añadida a su perfil.', 'users_social_disconnected' => 'La cuenta :socialAccount ha sido desconectada exitosamente de su perfil.', - 'users_api_tokens' => 'API Tokens', - 'users_api_tokens_none' => 'No API tokens have been created for this user', - 'users_api_tokens_create' => 'Create Token', - 'users_api_tokens_expires' => 'Expires', - 'users_api_tokens_docs' => 'API Documentation', + 'users_api_tokens' => 'Tokens API', + 'users_api_tokens_none' => 'No se han creado tokens API para este usuario', + 'users_api_tokens_create' => 'Crear token', + 'users_api_tokens_expires' => 'Expira', + 'users_api_tokens_docs' => 'Documentación API', // API Tokens - 'user_api_token_create' => 'Create API Token', - 'user_api_token_name' => 'Name', - 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', - 'user_api_token_expiry' => 'Expiry Date', - 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', - 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', - 'user_api_token_create_success' => 'API token successfully created', - 'user_api_token_update_success' => 'API token successfully updated', - 'user_api_token' => 'API Token', + 'user_api_token_create' => 'Crear token API', + 'user_api_token_name' => 'Nombre', + 'user_api_token_name_desc' => 'Dale a tu token un nombre legible como un recordatorio futuro de su propósito.', + 'user_api_token_expiry' => 'Fecha de expiración', + 'user_api_token_expiry_desc' => 'Establece una fecha en la que este token expira. Después de esta fecha, las solicitudes realizadas usando este token ya no funcionarán. Dejar este campo en blanco fijará un vencimiento de 100 años en el futuro.', + 'user_api_token_create_secret_message' => 'Inmediatamente después de crear este token se generarán y mostrarán sus correspondientes "Token ID" y "Token Secret". El "Token Secret" sólo se mostrará una vez, así que asegúrese de copiar el valor a un lugar seguro antes de proceder.', + 'user_api_token_create_success' => 'Token API creado correctamente', + 'user_api_token_update_success' => 'Token API actualizado correctamente', + 'user_api_token' => 'Token API', 'user_api_token_id' => 'Token ID', - 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_id_desc' => 'Este es un identificador no editable generado por el sistema y único para este token que necesitará ser proporcionado en solicitudes de API.', 'user_api_token_secret' => 'Token Secret', - 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', - 'user_api_token_created' => 'Token Created :timeAgo', - 'user_api_token_updated' => 'Token Updated :timeAgo', - 'user_api_token_delete' => 'Delete Token', - 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', - 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', - 'user_api_token_delete_success' => 'API token successfully deleted', + 'user_api_token_secret_desc' => 'Esta es una clave no editable generada por el sistema que necesitará ser proporcionada en solicitudes de API. Solo se monstraré esta vez así que guarde su valor en un lugar seguro.', + 'user_api_token_created' => 'Token creado :timeAgo', + 'user_api_token_updated' => 'Token actualizado :timeAgo', + 'user_api_token_delete' => 'Borrar token', + 'user_api_token_delete_warning' => 'Esto eliminará completamente este token API con el nombre \':tokenName\' del sistema.', + 'user_api_token_delete_confirm' => '¿Está seguro de que desea borrar este API token?', + 'user_api_token_delete_success' => 'Token API borrado correctamente', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. @@ -186,6 +186,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Danés', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/fr/errors.php b/resources/lang/fr/errors.php index cd8a83ffe..709b208b0 100644 --- a/resources/lang/fr/errors.php +++ b/resources/lang/fr/errors.php @@ -13,7 +13,7 @@ return [ 'email_already_confirmed' => 'Cet e-mail a déjà été validé, vous pouvez vous connecter.', 'email_confirmation_invalid' => 'Cette confirmation est invalide. Veuillez essayer de vous inscrire à nouveau.', 'email_confirmation_expired' => 'Le jeton de confirmation est périmé. Un nouvel e-mail vous a été envoyé.', - 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', + 'email_confirmation_awaiting' => 'L\'adresse e-mail du compte utilisé doit être confirmée', 'ldap_fail_anonymous' => 'L\'accès LDAP anonyme n\'a pas abouti', 'ldap_fail_authed' => 'L\'accès LDAP n\'a pas abouti avec cet utilisateur et ce mot de passe', 'ldap_extension_not_installed' => 'L\'extension LDAP PHP n\'est pas installée', @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => 'Impossible de trouver une adresse e-mail, pour cet utilisateur, dans les données fournies par le système d\'authentification externe', 'saml_invalid_response_id' => 'La requête du système d\'authentification externe n\'est pas reconnue par un processus démarré par cette application. Naviguer après une connexion peut causer ce problème.', 'saml_fail_authed' => 'Connexion avec :system échoue, le système n\'a pas fourni l\'autorisation réussie', - 'saml_email_exists' => 'L\'enregistrement a échoué car un utilisateur existe déjà avec l\'adresse e-mail ":email"', 'social_no_action_defined' => 'Pas d\'action définie', 'social_login_bad_response' => "Erreur pendant la tentative de connexion à :socialAccount : \n:error", 'social_account_in_use' => 'Ce compte :socialAccount est déjà utilisé. Essayez de vous connecter via :socialAccount.', @@ -90,11 +89,11 @@ return [ 'back_soon' => 'Nous serons bientôt de retour.', // API errors - 'api_no_authorization_found' => 'No authorization token found on the request', - 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', - 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_no_authorization_found' => 'Aucun jeton d\'autorisation trouvé pour la demande', + 'api_bad_authorization_format' => 'Un jeton d\'autorisation a été trouvé pour la requête, mais le format semble incorrect', + 'api_user_token_not_found' => 'Aucun jeton API correspondant n\'a été trouvé pour le jeton d\'autorisation fourni', 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', - 'api_user_token_expired' => 'The authorization token used has expired', + 'api_user_token_expired' => 'Le jeton d\'autorisation utilisé a expiré', ]; diff --git a/resources/lang/fr/settings.php b/resources/lang/fr/settings.php index 0ae45411c..2fd8980ae 100644 --- a/resources/lang/fr/settings.php +++ b/resources/lang/fr/settings.php @@ -43,8 +43,8 @@ return [ // Color settings 'content_colors' => 'Couleur du contenu', - 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', - 'bookshelf_color' => 'Shelf Color', + 'content_colors_desc' => 'Définit les couleurs pour tous les éléments de la hiérarchie d\'organisation des pages. Choisir les couleurs avec une luminosité similaire aux couleurs par défaut est recommandé pour la lisibilité.', + 'bookshelf_color' => 'Couleur de l\'étagère', 'book_color' => 'Couleur du livre', 'chapter_color' => 'Couleur du chapitre', 'page_color' => 'Couleur de la page', @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => 'Activer l\'inscription', 'reg_enable_desc' => 'Lorsque l\'inscription est activée, l\'utilisateur pourra s\'enregistrer en tant qu\'utilisateur de l\'application. Lors de l\'inscription, ils se voient attribuer un rôle par défaut.', 'reg_default_role' => 'Rôle par défaut lors de l\'inscription', - 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'Confirmation de l\'e-mail', 'reg_email_confirmation_toggle' => 'Obliger la confirmation par e-mail ?', 'reg_confirm_email_desc' => 'Si la restriction de domaine est activée, la confirmation sera automatiquement obligatoire et cette valeur sera ignorée.', @@ -103,7 +103,7 @@ return [ 'role_manage_entity_permissions' => 'Gérer les permissions sur les livres, chapitres et pages', 'role_manage_own_entity_permissions' => 'Gérer les permissions de ses propres livres, chapitres et pages', 'role_manage_page_templates' => 'Gérer les modèles de page', - 'role_access_api' => 'Access system API', + 'role_access_api' => 'Accès à l\'API du système', 'role_manage_settings' => 'Gérer les préférences de l\'application', 'role_asset' => 'Permissions des ressources', 'role_asset_desc' => 'Ces permissions contrôlent l\'accès par défaut des ressources dans le système. Les permissions dans les livres, les chapitres et les pages ignoreront ces permissions', @@ -131,7 +131,7 @@ return [ 'users_send_invite_text' => 'Vous pouvez choisir d\'envoyer à cet utilisateur un email d\'invitation qui lui permet de définir son propre mot de passe, sinon vous pouvez définir son mot de passe vous-même.', 'users_send_invite_option' => 'Envoyer l\'e-mail d\'invitation', 'users_external_auth_id' => 'Identifiant d\'authentification externe', - 'users_external_auth_id_desc' => 'Il s\'agit de l\'identifiant utilisé pour appairer cet utilisateur lors de la communication avec votre système LDAP.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Remplissez ce formulaire uniquement si vous souhaitez changer de mot de passe:', 'users_system_public' => 'Cet utilisateur représente les invités visitant votre instance. Il est assigné automatiquement aux invités.', 'users_delete' => 'Supprimer un utilisateur', @@ -152,32 +152,32 @@ return [ 'users_social_disconnect' => 'Déconnecter le compte', 'users_social_connected' => 'Votre compte :socialAccount a été ajouté avec succès.', 'users_social_disconnected' => 'Votre compte :socialAccount a été déconnecté avec succès', - 'users_api_tokens' => 'API Tokens', - 'users_api_tokens_none' => 'No API tokens have been created for this user', - 'users_api_tokens_create' => 'Create Token', - 'users_api_tokens_expires' => 'Expires', - 'users_api_tokens_docs' => 'API Documentation', + 'users_api_tokens' => 'Jetons de l\'API', + 'users_api_tokens_none' => 'Aucun jeton API n\'a été créé pour cet utilisateur', + 'users_api_tokens_create' => 'Créer un jeton', + 'users_api_tokens_expires' => 'Expiré', + 'users_api_tokens_docs' => 'Documentation de l\'API', // API Tokens - 'user_api_token_create' => 'Create API Token', - 'user_api_token_name' => 'Name', + 'user_api_token_create' => 'Créer un nouveau jeton API', + 'user_api_token_name' => 'Nom', 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', - 'user_api_token_expiry' => 'Expiry Date', + 'user_api_token_expiry' => 'Date d\'expiration', 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', - 'user_api_token_create_success' => 'API token successfully created', - 'user_api_token_update_success' => 'API token successfully updated', - 'user_api_token' => 'API Token', + 'user_api_token_create_success' => 'L\'API token a été créé avec succès', + 'user_api_token_update_success' => 'L\'API token a été mis à jour avec succès', + 'user_api_token' => 'Token API', 'user_api_token_id' => 'Token ID', 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', 'user_api_token_secret' => 'Token Secret', 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', - 'user_api_token_created' => 'Token Created :timeAgo', - 'user_api_token_updated' => 'Token Updated :timeAgo', - 'user_api_token_delete' => 'Delete Token', + 'user_api_token_created' => 'Jeton créé :timeAgo', + 'user_api_token_updated' => 'Jeton mis à jour :timeAgo', + 'user_api_token_delete' => 'Supprimer le Token', 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', - 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', - 'user_api_token_delete_success' => 'API token successfully deleted', + 'user_api_token_delete_confirm' => 'Souhaitez-vous vraiment effacer l\'API Token ?', + 'user_api_token_delete_success' => 'L\'API token a été supprimé avec succès', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. @@ -185,6 +185,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Danois', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/hu/common.php b/resources/lang/hu/common.php index adfaf7759..72bc3324b 100644 --- a/resources/lang/hu/common.php +++ b/resources/lang/hu/common.php @@ -38,7 +38,7 @@ return [ 'reset' => 'Visszaállítás', 'remove' => 'Eltávolítás', 'add' => 'Hozzáadás', - 'fullscreen' => 'Fullscreen', + 'fullscreen' => 'Teljes képernyő', // Sort Options 'sort_options' => 'Rendezési beállítások', diff --git a/resources/lang/hu/errors.php b/resources/lang/hu/errors.php index a557f1a98..c901e5423 100644 --- a/resources/lang/hu/errors.php +++ b/resources/lang/hu/errors.php @@ -13,7 +13,7 @@ return [ 'email_already_confirmed' => 'Az email cím már meg van erősítve, meg lehet próbálni a bejelentkezést.', 'email_confirmation_invalid' => 'A megerősítő vezérjel nem érvényes vagy használva volt. Meg kell próbálni újraregisztrálni.', 'email_confirmation_expired' => 'A megerősítő vezérjel lejárt. Egy új megerősítő email lett elküldve.', - 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', + 'email_confirmation_awaiting' => 'A használatban lévő fiók email címét meg kell erősíteni', 'ldap_fail_anonymous' => 'Nem sikerült az LDAP elérése névtelen csatlakozással', 'ldap_fail_authed' => 'Az LDAP hozzáférés nem sikerült a megadott DN és jelszó beállításokkal', 'ldap_extension_not_installed' => 'LDAP PHP kiterjesztés nincs telepítve', @@ -22,8 +22,7 @@ return [ 'saml_user_not_registered' => ':name felhasználó nincs regisztrálva és az automatikus regisztráció le van tiltva', 'saml_no_email_address' => 'Ehhez a felhasználóhoz nem található email cím a külső hitelesítő rendszer által átadott adatokban', 'saml_invalid_response_id' => 'A külső hitelesítő rendszerből érkező kérést nem ismerte fel az alkalmazás által indított folyamat. Bejelentkezés után az előző oldalra történő visszalépés okozhatja ezt a hibát.', - 'saml_fail_authed' => 'Bejelentkezés :system használatával sikertelen, a rendszer nem biztosított sikeres meghatalmazást', - 'saml_email_exists' => 'A regisztráció sikertelen mivel már létezik felhasználó ":email" email címmel', + 'saml_fail_authed' => 'Bejelentkezés :system használatával sikertelen, a rendszer nem biztosított sikeres hitelesítést', 'social_no_action_defined' => 'Nincs művelet meghatározva', 'social_login_bad_response' => "Hiba történt :socialAccount bejelentkezés közben:\n:error", 'social_account_in_use' => ':socialAccount fiók már használatban van. :socialAccount opción keresztül érdemes megpróbálni a bejelentkezést.', @@ -90,11 +89,11 @@ return [ 'back_soon' => 'Hamarosan újra elérhető lesz.', // API errors - 'api_no_authorization_found' => 'No authorization token found on the request', - 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', - 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', + 'api_no_authorization_found' => 'A kérésben nem található hitelesítési vezérjel', + 'api_bad_authorization_format' => 'A kérésben hitelesítési vezérjel található de a formátuma érvénytelennek tűnik', + 'api_user_token_not_found' => 'A megadott hitelesítési vezérjelhez nem található egyező API vezérjel', 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', - 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', - 'api_user_token_expired' => 'The authorization token used has expired', + 'api_user_no_api_permission' => 'A használt API vezérjel tulajdonosának nincs jogosultsága API hívások végrehajtásához', + 'api_user_token_expired' => 'A használt hitelesítési vezérjel lejárt', ]; diff --git a/resources/lang/hu/settings.php b/resources/lang/hu/settings.php index 549d3bd6a..1462fee5d 100644 --- a/resources/lang/hu/settings.php +++ b/resources/lang/hu/settings.php @@ -43,7 +43,7 @@ return [ // Color settings 'content_colors' => 'Tartalomszínek', - 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', + 'content_colors_desc' => 'Beállítja az elemek színét az oldalszervezési hierarchiában. Az olvashatóság szempontjából javasolt az alapértelmezés szerinti színhez hasonló fényerősséget választani.', 'bookshelf_color' => 'Polc színe', 'book_color' => 'Könyv színe', 'chapter_color' => 'Fejezet színe', @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => 'Regisztráció engedélyezése', 'reg_enable_desc' => 'Ha a regisztráció engedélyezett, akkor a felhasználó képes lesz bejelentkezni mint az alkalmazás egy felhasználója. Regisztráció után egy egyszerű, alapértelmezés szerinti felhasználói szerepkör lesz hozzárendelve.', 'reg_default_role' => 'Regisztráció utáni alapértelmezett felhasználói szerepkör', - 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'Email megerősítés', 'reg_email_confirmation_toggle' => 'Email megerősítés szükséges', 'reg_confirm_email_desc' => 'Ha a tartomány korlátozás be van állítva, akkor email megerősítés szükséges és ez a beállítás figyelmen kívül lesz hagyva.', @@ -103,7 +103,7 @@ return [ 'role_manage_entity_permissions' => 'Minden könyv, fejezet és oldalengedély kezelése', 'role_manage_own_entity_permissions' => 'Saját könyv, fejezet és oldalak engedélyeinek kezelése', 'role_manage_page_templates' => 'Oldalsablonok kezelése', - 'role_access_api' => 'Access system API', + 'role_access_api' => 'Hozzáférés a rendszer API-hoz', 'role_manage_settings' => 'Alkalmazás beállításainak kezelése', 'role_asset' => 'Eszköz jogosultságok', 'role_asset_desc' => 'Ezek a jogosultság vezérlik a alapértelmezés szerinti hozzáférést a rendszerben található eszközökhöz. A könyvek, fejezetek és oldalak jogosultságai felülírják ezeket a jogosultságokat.', @@ -131,7 +131,7 @@ return [ 'users_send_invite_text' => 'Lehetséges egy meghívó emailt küldeni ennek a felhasználónak ami lehetővé teszi, hogy beállíthassa a saját jelszavát. Máskülönben a jelszót az erre jogosult felhasználónak kell beállítania.', 'users_send_invite_option' => 'Felhasználó meghívó levél küldése', 'users_external_auth_id' => 'Külső hitelesítés azonosítója', - 'users_external_auth_id_desc' => 'Ez az azonosító lesz használva a felhasználó ellenőrzéséhez mikor az LDAP rendszerrel kommunikál.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'A lenti mezőket csak a jelszó módosításához kell kitölteni.', 'users_system_public' => 'Ez a felhasználó bármelyik, a példányt megtekintő felhasználót képviseli. Nem lehet vele bejelentkezni de automatikusan hozzá lesz rendelve.', 'users_delete' => 'Felhasználó törlése', @@ -152,32 +152,32 @@ return [ 'users_social_disconnect' => 'Fiók lecsatlakoztatása', 'users_social_connected' => ':socialAccount fiók sikeresen csatlakoztatva a profilhoz.', 'users_social_disconnected' => ':socialAccount fiók sikeresen lecsatlakoztatva a profilról.', - 'users_api_tokens' => 'API Tokens', - 'users_api_tokens_none' => 'No API tokens have been created for this user', - 'users_api_tokens_create' => 'Create Token', - 'users_api_tokens_expires' => 'Expires', - 'users_api_tokens_docs' => 'API Documentation', + 'users_api_tokens' => 'API vezérjelek', + 'users_api_tokens_none' => 'Ehhez a felhasználóhoz nincsenek létrehozva API vezérjelek', + 'users_api_tokens_create' => 'Vezérjel létrehozása', + 'users_api_tokens_expires' => 'Lejárat', + 'users_api_tokens_docs' => 'API dokumentáció', // API Tokens - 'user_api_token_create' => 'Create API Token', - 'user_api_token_name' => 'Name', + 'user_api_token_create' => 'API vezérjel létrehozása', + 'user_api_token_name' => 'Név', 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', - 'user_api_token_expiry' => 'Expiry Date', - 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', + 'user_api_token_expiry' => 'Lejárati dátum', + 'user_api_token_expiry_desc' => 'Dátum megadása ameddig a vezérjel érvényes. Ez után a dátum után az ezzel a vezérjellel történő kérések nem fognak működni. Üresen hagyva a lejárati idő 100 évre lesz beállítva.', 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', - 'user_api_token_create_success' => 'API token successfully created', - 'user_api_token_update_success' => 'API token successfully updated', - 'user_api_token' => 'API Token', - 'user_api_token_id' => 'Token ID', - 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', + 'user_api_token_create_success' => 'API vezérjel sikeresen létrehozva', + 'user_api_token_update_success' => 'API vezérjel sikeresen frissítve', + 'user_api_token' => 'API vezérjel', + 'user_api_token_id' => 'Vezérjel azonosító', + 'user_api_token_id_desc' => 'Ez egy nem szerkeszthető, a rendszer által létrehozott azonosító ehhez a vezérjelhez amire API kérésekben lehet szükség.', 'user_api_token_secret' => 'Token Secret', 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', - 'user_api_token_created' => 'Token Created :timeAgo', - 'user_api_token_updated' => 'Token Updated :timeAgo', - 'user_api_token_delete' => 'Delete Token', - 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', - 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', - 'user_api_token_delete_success' => 'API token successfully deleted', + 'user_api_token_created' => 'Vezérjel létrehozva :timeAgo', + 'user_api_token_updated' => 'Vezérjel frissítve :timeAgo', + 'user_api_token_delete' => 'Vezérjel törlése', + 'user_api_token_delete_warning' => '\':tokenName\' nevű API vezérjel teljesen törölve lesz a rendszerből.', + 'user_api_token_delete_confirm' => 'Biztosan törölhető ez az API vezérjel?', + 'user_api_token_delete_success' => 'API vezérjel sikeresen törölve', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. @@ -185,6 +185,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/hu/validation.php b/resources/lang/hu/validation.php index 8b292318f..845126cda 100644 --- a/resources/lang/hu/validation.php +++ b/resources/lang/hu/validation.php @@ -36,10 +36,10 @@ return [ 'numeric' => ':attribute nagyobb kell, hogy legyen, mint :value.', 'file' => ':attribute nagyobb kell, hogy legyen, mint :value kilobájt.', 'string' => ':attribute nagyobb kell legyen mint :value karakter.', - 'array' => 'The :attribute must have more than :value items.', + 'array' => ':attribute több, mint :value elemet kell, hogy tartalmazzon.', ], 'gte' => [ - 'numeric' => 'The :attribute must be greater than or equal :value.', + 'numeric' => ':attribute attribútumnak :value értéknél nagyobbnak vagy vele egyenlőnek kell lennie.', 'file' => 'The :attribute must be greater than or equal :value kilobytes.', 'string' => 'The :attribute must be greater than or equal :value characters.', 'array' => 'The :attribute must have :value items or more.', @@ -80,7 +80,7 @@ return [ ], 'no_double_extension' => ':attribute csak egy fájlkiterjesztéssel rendelkezhet.', 'not_in' => 'A kiválasztott :attribute érvénytelen.', - 'not_regex' => 'The :attribute format is invalid.', + 'not_regex' => ':attribute formátuma érvénytelen.', 'numeric' => ':attribute szám kell legyen.', 'regex' => ':attribute formátuma érvénytelen.', 'required' => ':attribute mező kötelező.', diff --git a/resources/lang/it/errors.php b/resources/lang/it/errors.php index f2514d0cb..977f26e19 100755 --- a/resources/lang/it/errors.php +++ b/resources/lang/it/errors.php @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => 'Impossibile trovare un indirizzo email per questo utente nei dati forniti dal sistema di autenticazione esterno', 'saml_invalid_response_id' => 'La richiesta dal sistema di autenticazione esterno non è riconosciuta da un processo iniziato da questa applicazione. Tornare indietro dopo un login potrebbe causare questo problema.', 'saml_fail_authed' => 'Accesso con :system non riuscito, il sistema non ha fornito l\'autorizzazione corretta', - 'saml_email_exists' => 'Registrazione non riuscita poiché esiste già un utente con indirizzo email ":email"', 'social_no_action_defined' => 'Nessuna azione definita', 'social_login_bad_response' => "Ricevuto error durante il login con :socialAccount : \n:error", 'social_account_in_use' => 'Questo account :socialAccount è già utilizzato, prova a loggarti usando l\'opzione :socialAccount.', diff --git a/resources/lang/it/settings.php b/resources/lang/it/settings.php index 8cdd4f758..3a1779f95 100755 --- a/resources/lang/it/settings.php +++ b/resources/lang/it/settings.php @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => 'Abilita registrazione', 'reg_enable_desc' => 'Quando la registrazione è abilitata, l\utente sarà in grado di registrarsi all\'applicazione. Al momento della registrazione gli verrà associato un ruolo utente predefinito.', 'reg_default_role' => 'Ruolo predefinito dopo la registrazione', - 'reg_enable_ldap_warning' => 'L\'opzione qui sopra non è usata mentre l\'autenticazione LDAP è attiva. Gli account per i membri non esistenti verranno creati automaticamente se l\'autenticazione, attraverso LDAP, avviene correttamente.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'Conferma Email', 'reg_email_confirmation_toggle' => 'Richiedi conferma email', 'reg_confirm_email_desc' => 'Se la restrizione per dominio è usata la conferma della mail sarà richiesta e la scelta ignorata.', @@ -131,7 +131,7 @@ return [ 'users_send_invite_text' => 'Puoi scegliere di inviare a questo utente un\'email di invito che permette loro di impostare la propria password altrimenti puoi impostare la password tu stesso.', 'users_send_invite_option' => 'Invia email di invito', 'users_external_auth_id' => 'ID Autenticazioni Esterna', - 'users_external_auth_id_desc' => 'Questo è l\'ID utilizzato per abbinare questo utente quando si comunica con il sistema LDAP.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Riempi solo se desideri cambiare la tua password:', 'users_system_public' => 'Questo utente rappresente qualsiasi ospite che visita il sito. Non può essere usato per effettuare il login ma è assegnato automaticamente.', 'users_delete' => 'Elimina Utente', @@ -185,6 +185,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/ja/errors.php b/resources/lang/ja/errors.php index 47932ca00..cd0dd777c 100644 --- a/resources/lang/ja/errors.php +++ b/resources/lang/ja/errors.php @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', - 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => 'アクションが定義されていません', 'social_login_bad_response' => "Error received during :socialAccount login: \n:error", 'social_account_in_use' => ':socialAccountアカウントは既に使用されています。:socialAccountのオプションからログインを試行してください。', diff --git a/resources/lang/ja/settings.php b/resources/lang/ja/settings.php index 1030499f7..5b1f31a05 100644 --- a/resources/lang/ja/settings.php +++ b/resources/lang/ja/settings.php @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => 'Enable registration', 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', 'reg_default_role' => '新規登録時のデフォルト役割', - 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'Email Confirmation', 'reg_email_confirmation_toggle' => 'Require email confirmation', 'reg_confirm_email_desc' => 'ドメイン制限を有効にしている場合はEメール認証が必須となり、この項目は無視されます。', @@ -131,7 +131,7 @@ return [ 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', 'users_send_invite_option' => 'Send user invite email', 'users_external_auth_id' => '外部認証ID', - 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your LDAP system.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'パスワードを変更したい場合のみ入力してください', 'users_system_public' => 'このユーザはアプリケーションにアクセスする全てのゲストを表します。ログインはできませんが、自動的に割り当てられます。', 'users_delete' => 'ユーザを削除', @@ -185,6 +185,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/ko/errors.php b/resources/lang/ko/errors.php index d3563fd83..506baf5a6 100644 --- a/resources/lang/ko/errors.php +++ b/resources/lang/ko/errors.php @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => '이 사용자에 대하여 외부 인증시스템에 의해 제공된 데이타 중 이메일 주소를 찾을 수 없습니다.', 'saml_invalid_response_id' => '이 응용프로그램에 의해 시작된 프로세스에 의하면 외부 인증시스템으로 온 요청이 인식되지 않습니다. 인증 후에 뒤로가기 기능을 사용했을 경우 이런 현상이 발생할 수 있습니다.', 'saml_fail_authed' => '시스템 로그인에 실패하였습니다. ( 해당 시스템이 인증성공값을 제공하지 않았습니다. )', - 'saml_email_exists' => '해당 사용자가 이미 존재하는 이메일주소를 입력하였기에 사용자 등록에 실패하였습니다.', 'social_no_action_defined' => '무슨 활동인지 알 수 없습니다.', 'social_login_bad_response' => ":socialAccount에 로그인할 수 없습니다. : \\n:error", 'social_account_in_use' => ':socialAccount(을)를 가진 사용자가 있습니다. :socialAccount로 로그인하세요.', diff --git a/resources/lang/ko/settings.php b/resources/lang/ko/settings.php index 544346dcd..5523ee4d3 100755 --- a/resources/lang/ko/settings.php +++ b/resources/lang/ko/settings.php @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => '사이트 가입 허용', 'reg_enable_desc' => '가입한 사용자는 단일한 권한을 가집니다.', 'reg_default_role' => '가입한 사용자의 기본 권한', - 'reg_enable_ldap_warning' => 'LDAP 인증이 활성화되었다면 위 옵션은 사용되지 않습니다. LDAP 시스템 인증 사용시 존재하지 않은 멤버 계정은 자동으로 생성됩니다.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => '메일 주소 확인', 'reg_email_confirmation_toggle' => '주소 확인 요구', 'reg_confirm_email_desc' => '도메인 차단을 쓰고 있으면 메일 주소를 확인해야 하고, 이 설정은 무시합니다.', @@ -131,7 +131,7 @@ return [ 'users_send_invite_text' => '비밀번호 설정을 권유하는 메일을 보내거나 내가 정할 수 있습니다.', 'users_send_invite_option' => '메일 보내기', 'users_external_auth_id' => 'LDAP 확인', - 'users_external_auth_id_desc' => 'LDAP 서버에 연결할 때 사용자를 확인합니다.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => '비밀번호를 바꿀 때만 쓰세요.', 'users_system_public' => '계정 없는 모든 사용자에 할당한 사용자입니다. 이 사용자로 로그인할 수 없어요.', 'users_delete' => '사용자 삭제', @@ -185,6 +185,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/nl/common.php b/resources/lang/nl/common.php index 93de8a11d..01e9969ef 100644 --- a/resources/lang/nl/common.php +++ b/resources/lang/nl/common.php @@ -26,7 +26,7 @@ return [ 'view' => 'Bekijk', 'view_all' => 'Bekijk Alle', 'create' => 'Aanmaken', - 'update' => 'Update', + 'update' => 'Bijwerken', 'edit' => 'Bewerk', 'sort' => 'Sorteer', 'move' => 'Verplaats', diff --git a/resources/lang/nl/errors.php b/resources/lang/nl/errors.php index f9c57b012..7dd2bdaa5 100644 --- a/resources/lang/nl/errors.php +++ b/resources/lang/nl/errors.php @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => 'Kan geen e-mailadres voor deze gebruiker vinden in de gegevens die door het externe verificatiesysteem worden verstrekt', 'saml_invalid_response_id' => 'Het verzoek van het externe verificatiesysteem is niet herkend door een door deze applicatie gestart proces. Het terug navigeren na een login kan dit probleem veroorzaken.', 'saml_fail_authed' => 'Inloggen met :system mislukt, het systeem gaf geen succesvolle autorisatie', - 'saml_email_exists' => 'Registratie is mislukt omdat een gebruiker al bestaat met e-mailadres ":email"', 'social_no_action_defined' => 'Geen actie gedefineerd', 'social_login_bad_response' => "Fout ontvangen tijdens :socialAccount login: \n:error", 'social_account_in_use' => 'Dit :socialAccount account is al in gebruik, Probeer in te loggen met de :socialAccount optie.', diff --git a/resources/lang/nl/settings.php b/resources/lang/nl/settings.php index 2fd7c4586..0c320be63 100644 --- a/resources/lang/nl/settings.php +++ b/resources/lang/nl/settings.php @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => 'Registratie inschakelen', 'reg_enable_desc' => 'Wanneer registratie is ingeschakeld, kan de gebruiker zich aanmelden als een gebruiker. Na registratie krijgen ze een enkele, standaard gebruikersrol.', 'reg_default_role' => 'Standaard rol na registratie', - 'reg_enable_ldap_warning' => 'De optie hierboven wordt niet gebruikt terwijl LDAP authenticatie actief is. Gebruikersaccounts voor niet-bestaande leden zullen automatisch worden gecreëerd als authenticatie tegen het gebruikte LDAP-systeem succesvol is.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'E-mail bevestiging', 'reg_email_confirmation_toggle' => 'E-mailbevestiging verplichten', 'reg_confirm_email_desc' => 'Als domeinrestricties aan staan dan is altijd e-maibevestiging nodig. Onderstaande instelling wordt dan genegeerd.', @@ -131,7 +131,7 @@ return [ 'users_send_invite_text' => 'U kunt ervoor kiezen om deze gebruiker een uitnodigingsmail te sturen waarmee hij zijn eigen wachtwoord kan instellen, anders kunt u zelf zijn wachtwoord instellen.', 'users_send_invite_option' => 'Stuur gebruiker uitnodigings e-mail', 'users_external_auth_id' => 'Externe authenticatie ID', - 'users_external_auth_id_desc' => 'Dit is het ID dat gebruikt wordt om deze gebruiker te vergelijken wanneer hij communiceert met uw LDAP-systeem.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Vul onderstaande formulier alleen in als je het wachtwoord wilt aanpassen:', 'users_system_public' => 'De eigenschappen van deze gebruiker worden voor elke gastbezoeker gebruikt. Er kan niet mee ingelogd worden en wordt automatisch toegewezen.', 'users_delete' => 'Verwijder gebruiker', @@ -185,6 +185,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/pl/errors.php b/resources/lang/pl/errors.php index 410e67a36..c31f04efa 100644 --- a/resources/lang/pl/errors.php +++ b/resources/lang/pl/errors.php @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => 'Nie można odnaleźć adresu email dla tego użytkownika w danych dostarczonych przez zewnętrzny system uwierzytelniania', 'saml_invalid_response_id' => 'Żądanie z zewnętrznego systemu uwierzytelniania nie zostało rozpoznane przez proces rozpoczęty przez tę aplikację. Cofnięcie po zalogowaniu mogło spowodować ten problem.', 'saml_fail_authed' => 'Logowanie przy użyciu :system nie powiodło się, system nie mógł pomyślnie ukończyć uwierzytelniania', - 'saml_email_exists' => 'Rejestracja nie powiodła się, ponieważ użytkownik z adresem email ":email" już istnieje', 'social_no_action_defined' => 'Brak zdefiniowanej akcji', 'social_login_bad_response' => "Podczas próby logowania :socialAccount wystąpił błąd: \n:error", 'social_account_in_use' => 'To konto :socialAccount jest już w użyciu. Spróbuj zalogować się za pomocą opcji :socialAccount.', diff --git a/resources/lang/pl/settings.php b/resources/lang/pl/settings.php index 868ac5694..4edb214da 100644 --- a/resources/lang/pl/settings.php +++ b/resources/lang/pl/settings.php @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => 'Włącz rejestrację', 'reg_enable_desc' => 'Kiedy rejestracja jest włączona użytkownicy mogą się rejestrować. Po rejestracji otrzymują jedną domyślną rolę użytkownika.', 'reg_default_role' => 'Domyślna rola użytkownika po rejestracji', - 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'Potwierdzenie adresu email', 'reg_email_confirmation_toggle' => 'Wymagaj potwierdzenia adresu email', 'reg_confirm_email_desc' => 'Jeśli restrykcje domenowe zostały ustawione, potwierdzenie adresu stanie się konieczne, a poniższa wartośc zostanie zignorowana.', @@ -131,7 +131,7 @@ return [ 'users_send_invite_text' => 'Możesz wybrać wysłanie do tego użytkownika wiadomości e-mail z zaproszeniem, która pozwala mu ustawić własne hasło, w przeciwnym razie możesz ustawić je samemu.', 'users_send_invite_option' => 'Wyślij e-mail z zaproszeniem', 'users_external_auth_id' => 'Zewnętrzne identyfikatory autentykacji', - 'users_external_auth_id_desc' => 'Jest to identyfikator używany do autoryzacji tego użytkownika podczas komunikacji z systemem LDAP.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Wypełnij poniżej tylko jeśli chcesz zmienić swoje hasło:', 'users_system_public' => 'Ten użytkownik reprezentuje każdego gościa odwiedzającego tę aplikację. Nie można się na niego zalogować, lecz jest przyznawany automatycznie.', 'users_delete' => 'Usuń użytkownika', @@ -185,6 +185,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/pt_BR/errors.php b/resources/lang/pt_BR/errors.php index 0b7c75839..d7aa69bf0 100644 --- a/resources/lang/pt_BR/errors.php +++ b/resources/lang/pt_BR/errors.php @@ -13,7 +13,7 @@ return [ 'email_already_confirmed' => 'E-mail já foi confirmado. Tente efetuar o login.', 'email_confirmation_invalid' => 'Esse token de confirmação não é válido ou já foi utilizado. Por favor, tente cadastrar-se novamente.', 'email_confirmation_expired' => 'O token de confirmação já expirou. Um novo e-mail foi enviado.', - 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', + 'email_confirmation_awaiting' => 'O endereço de e-mail da conta em uso precisa ser confirmado', 'ldap_fail_anonymous' => 'O acesso LDAP falhou ao tentar usar o anonymous bind', 'ldap_fail_authed' => 'O acesso LDAP falhou ao tentar os detalhes do dn e senha fornecidos', 'ldap_extension_not_installed' => 'A extensão LDAP PHP não está instalada', @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => 'Não foi possível encontrar um endereço de e-mail para este usuário nos dados providos pelo sistema de autenticação externa', 'saml_invalid_response_id' => 'A requisição do sistema de autenticação externa não foi reconhecia por um processo iniciado por esta aplicação. Após o login, navegar para o caminho anterior pode causar um problema.', 'saml_fail_authed' => 'Login utilizando :system falhou. Sistema não forneceu autorização bem sucedida', - 'saml_email_exists' => 'Registro malsucedido pois um usuário já existe com este endereço de e-mail ":email"', 'social_no_action_defined' => 'Nenhuma ação definida', 'social_login_bad_response' => "Erro recebido durante o login :socialAccount: \n:error", 'social_account_in_use' => 'Essa conta :socialAccount já está em uso. Por favor, tente entrar utilizando a opção :socialAccount.', @@ -90,11 +89,11 @@ return [ 'back_soon' => 'Voltaremos em breve.', // API errors - 'api_no_authorization_found' => 'No authorization token found on the request', - 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', - 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', - 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', - 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', - 'api_user_token_expired' => 'The authorization token used has expired', + 'api_no_authorization_found' => 'Nenhum token de autorização encontrado na requisição', + 'api_bad_authorization_format' => 'Um token de autorização foi encontrado na requisição, mas o formato parece incorreto', + 'api_user_token_not_found' => 'Nenhum token de API correspondente foi encontrado para o token de autorização fornecido', + 'api_incorrect_token_secret' => 'O segredo fornecido para o token de API usado está incorreto', + 'api_user_no_api_permission' => 'O proprietário do token de API utilizado não tem permissão para fazer requisições de API', + 'api_user_token_expired' => 'O token de autenticação expirou', ]; diff --git a/resources/lang/pt_BR/settings.php b/resources/lang/pt_BR/settings.php index 5376ab9c0..7c470da2a 100644 --- a/resources/lang/pt_BR/settings.php +++ b/resources/lang/pt_BR/settings.php @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => 'Habilitar cadastro', 'reg_enable_desc' => 'Quando o cadastro é habilitado, visitantes poderão cadastrar-se como usuários do aplicativo. Realizado o cadastro, recebem um único cargo padrão.', 'reg_default_role' => 'Cargo padrão para usuários após o cadastro', - 'reg_enable_ldap_warning' => 'A opção acima não é usada enquanto a autenticação por LDAP está ativa. Contas de usuário para membros não existentes serão criadas automaticamente se a autenticação contrária ao sistema LDAP em uso é bem sucedida.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'Confirmação de E-mail', 'reg_email_confirmation_toggle' => 'Requerer confirmação de e-mail', 'reg_confirm_email_desc' => 'Em caso da restrição de domínios estar em uso, a confirmação de e-mail será requerida e essa opção será ignorada.', @@ -103,7 +103,7 @@ return [ 'role_manage_entity_permissions' => 'Gerenciar todos os livros, capítulos e permissões de páginas', 'role_manage_own_entity_permissions' => 'Gerenciar permissões de seu próprio livro, capítulo e paginas', 'role_manage_page_templates' => 'Gerenciar modelos de página', - 'role_access_api' => 'Access system API', + 'role_access_api' => 'Acessar API do sistema', 'role_manage_settings' => 'Gerenciar configurações da aplicação', 'role_asset' => 'Permissões de Ativos', 'role_asset_desc' => 'Essas permissões controlam o acesso padrão para os ativos dentro do sistema. Permissões em Livros, Capítulos e Páginas serão sobrescritas por essas permissões.', @@ -131,7 +131,7 @@ return [ 'users_send_invite_text' => 'Você pode escolher enviar a este usuário um convite por e-mail que o possibilitará definir sua própria senha, ou defina você uma senha.', 'users_send_invite_option' => 'Enviar convite por e-mail', 'users_external_auth_id' => 'ID de Autenticação Externa', - 'users_external_auth_id_desc' => 'Este é o ID usado para identificar este usuário quando se comunicando com seu sistema LDAP.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Apenas preencha os dados abaixo caso queira modificar a sua senha.', 'users_system_public' => 'Esse usuário representa quaisquer convidados que visitam o aplicativo. Ele não pode ser usado para login mas é automaticamente atribuído.', 'users_delete' => 'Excluir Usuário', @@ -152,32 +152,32 @@ return [ 'users_social_disconnect' => 'Desconectar Conta', 'users_social_connected' => 'Conta :socialAccount foi conectada com sucesso ao seu perfil.', 'users_social_disconnected' => 'Conta :socialAccount foi desconectada com sucesso de seu perfil.', - 'users_api_tokens' => 'API Tokens', - 'users_api_tokens_none' => 'No API tokens have been created for this user', - 'users_api_tokens_create' => 'Create Token', - 'users_api_tokens_expires' => 'Expires', - 'users_api_tokens_docs' => 'API Documentation', + 'users_api_tokens' => 'Tokens de API', + 'users_api_tokens_none' => 'Nenhum token de API foi criado para este usuário', + 'users_api_tokens_create' => 'Criar Token', + 'users_api_tokens_expires' => 'Expira', + 'users_api_tokens_docs' => 'Documentação da API', // API Tokens - 'user_api_token_create' => 'Create API Token', - 'user_api_token_name' => 'Name', - 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', - 'user_api_token_expiry' => 'Expiry Date', - 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', - 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', - 'user_api_token_create_success' => 'API token successfully created', - 'user_api_token_update_success' => 'API token successfully updated', - 'user_api_token' => 'API Token', - 'user_api_token_id' => 'Token ID', - 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', - 'user_api_token_secret' => 'Token Secret', - 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', - 'user_api_token_created' => 'Token Created :timeAgo', - 'user_api_token_updated' => 'Token Updated :timeAgo', - 'user_api_token_delete' => 'Delete Token', - 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', - 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', - 'user_api_token_delete_success' => 'API token successfully deleted', + 'user_api_token_create' => 'Criar Token de API', + 'user_api_token_name' => 'Nome', + 'user_api_token_name_desc' => 'Dê ao seu token um nome legível como um futuro lembrete de seu propósito.', + 'user_api_token_expiry' => 'Data de Expiração', + 'user_api_token_expiry_desc' => 'Defina uma data em que este token expira. Depois desta data, as requisições feitas usando este token não funcionarão mais. Deixar este campo em branco definirá um prazo de 100 anos futuros.', + 'user_api_token_create_secret_message' => 'Imediatamente após a criação deste token, um "ID de token" e "Secreto de token" serão gerados e exibidos. O segredo só será mostrado uma única vez, portanto, certifique-se de copiar o valor para algum lugar seguro antes de prosseguir.', + 'user_api_token_create_success' => 'Token de API criado com sucesso', + 'user_api_token_update_success' => 'Token de API atualizado com sucesso', + 'user_api_token' => 'Token de API', + 'user_api_token_id' => 'ID do Token', + 'user_api_token_id_desc' => 'Este é um identificador de sistema não editável, gerado para este token, que precisará ser fornecido em solicitações de API.', + 'user_api_token_secret' => 'Segredo do Token', + 'user_api_token_secret_desc' => 'Este é um segredo de sistema gerado para este token que precisará ser fornecido em requisições de API. Isto só será mostrado nesta única vez, portanto, copie este valor para um lugar seguro.', + 'user_api_token_created' => 'Token Criado :timeAgo', + 'user_api_token_updated' => 'Token Atualizado :timeAgo', + 'user_api_token_delete' => 'Excluir Token', + 'user_api_token_delete_warning' => 'Isto irá excluir completamente este token de API com o nome \':tokenName\' do sistema.', + 'user_api_token_delete_confirm' => 'Você tem certeza que deseja excluir este token de API?', + 'user_api_token_delete_success' => 'Token de API excluído com sucesso', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. @@ -185,6 +185,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/ru/errors.php b/resources/lang/ru/errors.php index 1362fbb61..2f5f74caa 100644 --- a/resources/lang/ru/errors.php +++ b/resources/lang/ru/errors.php @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', - 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => 'Действие не определено', 'social_login_bad_response' => "При попытке входа с :socialAccount произошла ошибка: \\n:error", 'social_account_in_use' => 'Этот :socialAccount аккаунт уже исопльзуется, попробуйте войти с параметрами :socialAccount.', diff --git a/resources/lang/ru/settings.php b/resources/lang/ru/settings.php index 429fe037b..ecd80c283 100755 --- a/resources/lang/ru/settings.php +++ b/resources/lang/ru/settings.php @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => 'Разрешить регистрацию', 'reg_enable_desc' => 'Если регистрация разрешена, пользователь сможет зарегистрироваться в системе самостоятельно. При регистрации назначается роль пользователя по умолчанию', 'reg_default_role' => 'Роль пользователя по умолчанию после регистрации', - 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'Подтверждение электронной почты', 'reg_email_confirmation_toggle' => 'Требовать подтверждение по электронной почте', 'reg_confirm_email_desc' => 'При использовании ограничения по домену - подтверждение обязательно, этот пункт игнорируется.', @@ -131,7 +131,7 @@ return [ 'users_send_invite_text' => 'Вы можете отправить этому пользователю email с приглашением, которое позволит ему установить пароль самостоятельно или задайте пароль сами.', 'users_send_invite_option' => 'Отправить пользователю письмо с приглашением', 'users_external_auth_id' => 'Внешний ID аутентификации', - 'users_external_auth_id_desc' => 'Этот ID используется для связи с вашей LDAP системой.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Заполните ниже только если вы хотите сменить свой пароль.', 'users_system_public' => 'Этот пользователь представляет любых гостевых пользователей, которые посещают ваше приложение. Он не может использоваться для входа в систему и назначается автоматически.', 'users_delete' => 'Удалить пользователя', @@ -185,6 +185,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/sk/errors.php b/resources/lang/sk/errors.php index 6dac83fab..ef6474b4d 100644 --- a/resources/lang/sk/errors.php +++ b/resources/lang/sk/errors.php @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', - 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => 'Nebola definovaná žiadna akcia', 'social_login_bad_response' => "Error received during :socialAccount login: \n:error", 'social_account_in_use' => 'Tento :socialAccount účet sa už používa, skúste sa prihlásiť pomocou možnosti :socialAccount.', diff --git a/resources/lang/sk/settings.php b/resources/lang/sk/settings.php index 5ba754b5c..f4e67f2ff 100644 --- a/resources/lang/sk/settings.php +++ b/resources/lang/sk/settings.php @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => 'Enable registration', 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', 'reg_default_role' => 'Prednastavená používateľská rola po registrácii', - 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'Email Confirmation', 'reg_email_confirmation_toggle' => 'Require email confirmation', 'reg_confirm_email_desc' => 'Ak je použité obmedzenie domény, potom bude vyžadované overenie emailu a hodnota nižšie bude ignorovaná.', @@ -131,7 +131,7 @@ return [ 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', 'users_send_invite_option' => 'Send user invite email', 'users_external_auth_id' => 'Externé autentifikačné ID', - 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your LDAP system.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Pole nižšie vyplňte iba ak chcete zmeniť heslo:', 'users_system_public' => 'Tento účet reprezentuje každého hosťovského používateľa, ktorý navštívi Vašu inštanciu. Nedá sa pomocou neho prihlásiť a je priradený automaticky.', 'users_delete' => 'Zmazať používateľa', @@ -185,6 +185,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/sv/errors.php b/resources/lang/sv/errors.php index 1149867ff..a00109e3d 100644 --- a/resources/lang/sv/errors.php +++ b/resources/lang/sv/errors.php @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', - 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', 'social_no_action_defined' => 'Ingen åtgärd definierad', 'social_login_bad_response' => "Ett fel inträffade vid inloggning genom :socialAccount: \n:error", 'social_account_in_use' => 'Detta konto från :socialAccount används redan. Testa att logga in med :socialAccount istället.', diff --git a/resources/lang/sv/settings.php b/resources/lang/sv/settings.php index 38ac8a664..514f8f894 100644 --- a/resources/lang/sv/settings.php +++ b/resources/lang/sv/settings.php @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => 'Tillåt registrering', 'reg_enable_desc' => 'När registrering tillåts kan användaren logga in som en användare. Vid registreringen ges de en förvald användarroll.', 'reg_default_role' => 'Standardroll efter registrering', - 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'E-postbekräftelse', 'reg_email_confirmation_toggle' => 'Kräv e-postbekräftelse', 'reg_confirm_email_desc' => 'Om registrering begränas till vissa domäner kommer e-postbekräftelse alltid att krävas och den här inställningen kommer att ignoreras.', @@ -131,7 +131,7 @@ return [ 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', 'users_send_invite_option' => 'Send user invite email', 'users_external_auth_id' => 'Externt ID för autentisering', - 'users_external_auth_id_desc' => 'Detta är det ID som används för att matcha användaren när den kommunicerar med ditt LDAP-system.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Fyll i nedanstående fält endast om du vill byta lösenord:', 'users_system_public' => 'Den här användaren representerar eventuella gäster som använder systemet. Den kan inte användas för att logga in utan tilldeles automatiskt.', 'users_delete' => 'Ta bort användare', @@ -185,6 +185,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/tr/errors.php b/resources/lang/tr/errors.php index aef44c2b5..4e20e3b00 100644 --- a/resources/lang/tr/errors.php +++ b/resources/lang/tr/errors.php @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => 'Bu kullanıcı için, harici bir doğrulama siteminden elde edilen verilerde, bir e-posta adresi bulunamadı', 'saml_invalid_response_id' => 'Harici doğrulama sistemi tarafından sağlanan bir veri talebi, bu uygulama tarafından başlatılan bir işlem tarafından tanınamadı. Giriş yaptıktan sonra geri dönmek bu soruna yol açabilir.', 'saml_fail_authed' => ':system kullanarak giriş yapma başarısız, sistem başarılı bir doğrulama sağlamadı', - 'saml_email_exists' => '":email" adresiyle halihazırda kayıtlı bir kullanıcı olduğu için kayıt başarısız', 'social_no_action_defined' => 'Bir aksiyon tanımlanmadı', 'social_login_bad_response' => ":socialAccount girişi sırasında hata oluştu: \n:error", 'social_account_in_use' => 'Bu :socialAccount zaten kullanımda, :socialAccount hesabıyla giriş yapmayı deneyin.', diff --git a/resources/lang/tr/settings.php b/resources/lang/tr/settings.php index 6c8e9c96f..4e81344bd 100755 --- a/resources/lang/tr/settings.php +++ b/resources/lang/tr/settings.php @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => 'Kaydolmaya izin ver', 'reg_enable_desc' => 'Kayıt olmaya izin verdiğinizde kullanıcılar kendilerini uygulamaya kaydedebilecekler. Kayıt olduktan sonra kendilerine varsayılan kullanıcı rolü atanacaktır.', 'reg_default_role' => 'Kayıt olduktan sonra varsayılan kullanıcı rolü', - 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'Email Doğrulama', 'reg_email_confirmation_toggle' => 'E-mail onayı gerektir', 'reg_confirm_email_desc' => 'Eğer domain kısıtlaması kullanılıyorsa o zaman email doğrulaması gereklidir ve bu seçenek yok sayılacaktır.', @@ -131,7 +131,7 @@ return [ 'users_send_invite_text' => 'Bu kullanıcıya parolasını sıfırlayabilmesi için bir e-posta gönder veya şifresini sen belirle.', 'users_send_invite_option' => 'Kullanıcıya davet e-postası gönder', 'users_external_auth_id' => 'Harici Authentication ID\'si', - 'users_external_auth_id_desc' => 'Bu ID kullanıcı LDAP sunucu ile bağlantı kurarken kullanılır.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Sadece parolanızı değiştirmek istiyorsanız aşağıyı doldurunuz.', 'users_system_public' => 'Bu kullanıcı sizin uygulamanızı ziyaret eden bütün misafir kullanıcıları temsil eder. Giriş yapmak için kullanılamaz, otomatik olarak atanır.', 'users_delete' => 'Kullanıcı Sil', @@ -185,6 +185,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/uk/errors.php b/resources/lang/uk/errors.php index 8cf8ff936..a62911673 100644 --- a/resources/lang/uk/errors.php +++ b/resources/lang/uk/errors.php @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => 'Не вдалося знайти електронну адресу для цього користувача у даних, наданих зовнішньою системою аутентифікації', 'saml_invalid_response_id' => 'Запит із зовнішньої системи аутентифікації не розпізнається процесом, розпочатим цим додатком. Повернення назад після входу могла спричинити цю проблему.', 'saml_fail_authed' => 'Вхід із використанням «:system» не вдався, система не здійснила успішну авторизацію', - 'saml_email_exists' => 'Реєстрація не вдалася, оскільки користувач з електронною адресою «:email» вже існує', 'social_no_action_defined' => 'Жодних дій не визначено', 'social_login_bad_response' => "Помилка, отримана під час входу з :socialAccount помилка : \n:error", 'social_account_in_use' => 'Цей :socialAccount обліковий запис вже використовується, спробуйте ввійти з параметрами :socialAccount.', diff --git a/resources/lang/uk/settings.php b/resources/lang/uk/settings.php index 0f3986328..a41dc0d36 100644 --- a/resources/lang/uk/settings.php +++ b/resources/lang/uk/settings.php @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => 'Дозволити реєстрацію', 'reg_enable_desc' => 'При включенні реєстрації відвідувач зможе зареєструватися як користувач програми. Після реєстрації їм надається єдина роль користувача за замовчуванням.', 'reg_default_role' => 'Роль користувача за умовчанням після реєстрації', - 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => 'Підтвердження електронною поштою', 'reg_email_confirmation_toggle' => 'Необхідне підтвердження електронною поштою', 'reg_confirm_email_desc' => 'Якщо використовується обмеження домену, то підтвердження електронною поштою буде потрібно, а нижче значення буде проігноровано.', @@ -131,7 +131,7 @@ return [ 'users_send_invite_text' => 'Ви можете надіслати цьому користувачеві лист із запрошенням, що дозволить йому встановити пароль власноруч, або ви можете встановити йому пароль самостійно.', 'users_send_invite_option' => 'Надіслати листа із запрошенням користувачу', 'users_external_auth_id' => 'Зовнішній ID автентифікації', - 'users_external_auth_id_desc' => 'Цей ID використовується для пошуку збігу цього користувача під час зв\'язку з LDAP.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => 'Тільки якщо ви хочете змінити свій пароль, заповніть поля нижче:', 'users_system_public' => 'Цей користувач представляє будь-яких гостьових користувачів, які відвідують ваш екземпляр. Його не можна використовувати для входу, але він призначається автоматично.', 'users_delete' => 'Видалити користувача', @@ -185,6 +185,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => 'Dansk', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/zh_CN/errors.php b/resources/lang/zh_CN/errors.php index 46a0a6880..465592b6f 100644 --- a/resources/lang/zh_CN/errors.php +++ b/resources/lang/zh_CN/errors.php @@ -13,7 +13,7 @@ return [ 'email_already_confirmed' => 'Email已被确认,请尝试登录。', 'email_confirmation_invalid' => '此确认令牌无效或已被使用,请重新注册。', 'email_confirmation_expired' => '确认令牌已过期,已发送新的确认电子邮件。', - 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', + 'email_confirmation_awaiting' => '需要认证账户的电子邮箱地址', 'ldap_fail_anonymous' => '使用匿名绑定的LDAP访问失败。', 'ldap_fail_authed' => '带有标识名称和密码的LDAP访问失败。', 'ldap_extension_not_installed' => '未安装LDAP PHP扩展程序', @@ -23,7 +23,6 @@ return [ 'saml_no_email_address' => '无法找到有效Email地址,此用户数据由外部身份验证系统托管', 'saml_invalid_response_id' => '来自外部身份验证系统的请求没有被本应用程序认证,在登录后返回上一页可能会导致此问题。', 'saml_fail_authed' => '使用 :system 登录失败,登录系统未返回成功登录授权信息。', - 'saml_email_exists' => '注册失败,因此已经有用户使用了 ":email" 此Email地址了', 'social_no_action_defined' => '没有定义行为', 'social_login_bad_response' => "在 :socialAccount 登录时遇到错误:\n:error", 'social_account_in_use' => ':socialAccount 账户已被使用,请尝试通过 :socialAccount 选项登录。', @@ -90,11 +89,11 @@ return [ 'back_soon' => '请耐心等待网站的恢复。', // API errors - 'api_no_authorization_found' => 'No authorization token found on the request', - 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', - 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', - 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', - 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', - 'api_user_token_expired' => 'The authorization token used has expired', + 'api_no_authorization_found' => '未在请求中找到授权令牌', + 'api_bad_authorization_format' => '已在请求中找到授权令牌,但格式貌似不正确', + 'api_user_token_not_found' => '未能找到所匹配的API提供的授权令牌', + 'api_incorrect_token_secret' => '给已给出的API所提供的密钥不正确', + 'api_user_no_api_permission' => '使用过的 API 令牌的所有者没有进行API 调用的权限', + 'api_user_token_expired' => '所使用的身份令牌已过期', ]; diff --git a/resources/lang/zh_CN/settings.php b/resources/lang/zh_CN/settings.php index 9b534374d..0b936c8c0 100755 --- a/resources/lang/zh_CN/settings.php +++ b/resources/lang/zh_CN/settings.php @@ -56,7 +56,7 @@ return [ 'reg_enable_toggle' => '启用注册', 'reg_enable_desc' => '启用注册后,用户将可以自己注册为站点用户。 注册后,他们将获得一个默认的单一用户角色。', 'reg_default_role' => '注册后的默认用户角色', - 'reg_enable_ldap_warning' => 'LDAP 身份验证处于活动状态时不使用上面的选项。 如果使用的 LDAP 系统验证成功,将自动创建非现有会员的用户帐户。', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', 'reg_email_confirmation' => '邮箱确认n', 'reg_email_confirmation_toggle' => '需要电子邮件确认', 'reg_confirm_email_desc' => '如果使用域名限制,则需要Email验证,并且该值将被忽略。', @@ -103,7 +103,7 @@ return [ 'role_manage_entity_permissions' => '管理所有图书,章节和页面的权限', 'role_manage_own_entity_permissions' => '管理自己的图书,章节和页面的权限', 'role_manage_page_templates' => '管理页面模板', - 'role_access_api' => 'Access system API', + 'role_access_api' => '访问系统 API', 'role_manage_settings' => '管理App设置', 'role_asset' => '资源许可', 'role_asset_desc' => '对系统内资源的默认访问许可将由这些权限控制。单独设置在书籍,章节和页面上的权限将覆盖这里的权限设定。', @@ -131,7 +131,7 @@ return [ 'users_send_invite_text' => '您可以向该用户发送邀请电子邮件,允许他们设置自己的密码,否则,您可以自己设置他们的密码。', 'users_send_invite_option' => '发送邀请用户电子邮件', 'users_external_auth_id' => '外部身份认证ID', - 'users_external_auth_id_desc' => '与LDAP系统通信时,此ID用于匹配该用户。', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => '如果您想更改密码,请填写以下内容:', 'users_system_public' => '此用户代表访问您的App的任何访客。它不能用于登录,而是自动分配。', 'users_delete' => '删除用户', @@ -152,32 +152,32 @@ return [ 'users_social_disconnect' => '解除绑定账户', 'users_social_connected' => ':socialAccount 账户已经成功绑定到您的资料。', 'users_social_disconnected' => ':socialAccount 账户已经成功解除绑定。', - 'users_api_tokens' => 'API Tokens', - 'users_api_tokens_none' => 'No API tokens have been created for this user', - 'users_api_tokens_create' => 'Create Token', - 'users_api_tokens_expires' => 'Expires', - 'users_api_tokens_docs' => 'API Documentation', + 'users_api_tokens' => 'API令牌', + 'users_api_tokens_none' => '没有创建任何API令牌给此用户', + 'users_api_tokens_create' => '创建令牌', + 'users_api_tokens_expires' => '过期', + 'users_api_tokens_docs' => 'API文档', // API Tokens - 'user_api_token_create' => 'Create API Token', - 'user_api_token_name' => 'Name', - 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', - 'user_api_token_expiry' => 'Expiry Date', - 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', - 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', - 'user_api_token_create_success' => 'API token successfully created', - 'user_api_token_update_success' => 'API token successfully updated', - 'user_api_token' => 'API Token', - 'user_api_token_id' => 'Token ID', - 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', - 'user_api_token_secret' => 'Token Secret', - 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', - 'user_api_token_created' => 'Token Created :timeAgo', - 'user_api_token_updated' => 'Token Updated :timeAgo', - 'user_api_token_delete' => 'Delete Token', - 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', - 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', - 'user_api_token_delete_success' => 'API token successfully deleted', + 'user_api_token_create' => '创建 API 令牌', + 'user_api_token_name' => '姓名', + 'user_api_token_name_desc' => '请给您的可读令牌一个命名以在未来提醒您它的预期用途', + 'user_api_token_expiry' => '过期期限', + 'user_api_token_expiry_desc' => '请设置一个此令牌的过期时间,过期后此令牌所给出的请求将失效,若将此处留为空白将自动设置过期时间为100年。', + 'user_api_token_create_secret_message' => '创建此令牌后会立即生成“令牌ID”和“令牌密钥”。该密钥只会显示一次,所以请确保在继续操作之前将密钥记录或复制到一个安全的地方。', + 'user_api_token_create_success' => '成功创建API令牌。', + 'user_api_token_update_success' => '成功更新API令牌。', + 'user_api_token' => 'API令牌', + 'user_api_token_id' => '令牌ID', + 'user_api_token_id_desc' => '这是系统生成的一个不可编辑的令牌标识符,需要在API请求中才能提供。', + 'user_api_token_secret' => '令牌密钥', + 'user_api_token_secret_desc' => '这是此令牌系统生成的密钥,需要在API请求中才可以提供。 这只会显示一次,因此请将其复制到安全的地方。', + 'user_api_token_created' => '创建的令牌:timeAgo', + 'user_api_token_updated' => '令牌更新:timeAgo', + 'user_api_token_delete' => '删除令牌', + 'user_api_token_delete_warning' => '这将会从系统中完全删除名为“令牌命名”的API令牌', + 'user_api_token_delete_confirm' => '您确定要删除此API令牌吗?', + 'user_api_token_delete_success' => '成功删除API令牌', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. @@ -185,6 +185,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => '丹麦', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/zh_TW/auth.php b/resources/lang/zh_TW/auth.php index 4e834f700..6b1f75f75 100644 --- a/resources/lang/zh_TW/auth.php +++ b/resources/lang/zh_TW/auth.php @@ -7,7 +7,7 @@ return [ 'failed' => '使用者名稱或密碼錯誤。', - 'throttle' => '您的登入次數過多,請在:seconds秒後重試。', + 'throttle' => '您的登入次數過多,請在:秒後重試。', // Login & Register 'sign_up' => '註冊', @@ -23,11 +23,11 @@ return [ 'password_confirm' => '確認密碼', 'password_hint' => '必須超過7個字元', 'forgot_password' => '忘記密碼?', - 'remember_me' => '記住我', + 'remember_me' => '記住該賬戶密碼', 'ldap_email_hint' => '請輸入用於此帳號的電子郵件。', 'create_account' => '建立帳號', - 'already_have_account' => 'Already have an account?', - 'dont_have_account' => 'Don\'t have an account?', + 'already_have_account' => '已經擁有賬戶?', + 'dont_have_account' => '沒有賬戶?', 'social_login' => 'SNS登入', 'social_registration' => 'SNS註冊', 'social_registration_text' => '其他服務註冊/登入.', @@ -66,12 +66,12 @@ return [ 'email_not_confirmed_resend_button' => '重新發送確認Email', // User Invite - 'user_invite_email_subject' => 'You have been invited to join :appName!', - 'user_invite_email_greeting' => 'An account has been created for you on :appName.', - 'user_invite_email_text' => 'Click the button below to set an account password and gain access:', - 'user_invite_email_action' => 'Set Account Password', - 'user_invite_page_welcome' => 'Welcome to :appName!', - 'user_invite_page_text' => 'To finalise your account and gain access you need to set a password which will be used to log-in to :appName on future visits.', - 'user_invite_page_confirm_button' => 'Confirm Password', - 'user_invite_success' => 'Password set, you now have access to :appName!' + 'user_invite_email_subject' => '您被邀請加入:bookstack!', + 'user_invite_email_greeting' => '我們為您在bookstack上創建了一個新賬戶。', + 'user_invite_email_text' => '請點擊下面的按鈕設置賬戶密碼并獲取訪問權限:', + 'user_invite_email_action' => '請設置賬戶密碼', + 'user_invite_page_welcome' => '歡迎使用:bookstack', + 'user_invite_page_text' => '要完善您的賬戶并獲取訪問權限,您需要設置一個密碼,該密碼將在以後訪問時用於登陸:bookstack', + 'user_invite_page_confirm_button' => '請確定密碼', + 'user_invite_success' => '密碼已設置,您現在可以進入:bookstack了啦' ]; \ No newline at end of file diff --git a/resources/lang/zh_TW/common.php b/resources/lang/zh_TW/common.php index 278d51357..d82945ac0 100644 --- a/resources/lang/zh_TW/common.php +++ b/resources/lang/zh_TW/common.php @@ -11,7 +11,7 @@ return [ 'save' => '儲存', 'continue' => '繼續', 'select' => '選擇', - 'toggle_all' => 'Toggle All', + 'toggle_all' => '轉換全部', 'more' => '更多', // Form Labels @@ -24,7 +24,7 @@ return [ // Actions 'actions' => '動作', 'view' => '檢視', - 'view_all' => 'View All', + 'view_all' => '驗視全部', 'create' => '建立', 'update' => '更新', 'edit' => '編輯', @@ -38,16 +38,16 @@ return [ 'reset' => '重置', 'remove' => '刪除', 'add' => '新增', - 'fullscreen' => 'Fullscreen', + 'fullscreen' => '全屏顯示', // Sort Options - 'sort_options' => 'Sort Options', - 'sort_direction_toggle' => 'Sort Direction Toggle', - 'sort_ascending' => 'Sort Ascending', - 'sort_descending' => 'Sort Descending', - 'sort_name' => 'Name', - 'sort_created_at' => 'Created Date', - 'sort_updated_at' => 'Updated Date', + 'sort_options' => '選項分類', + 'sort_direction_toggle' => '順序方向切換', + 'sort_ascending' => '升序', + 'sort_descending' => '降序', + 'sort_name' => '名稱', + 'sort_created_at' => '創建日期', + 'sort_updated_at' => '更新日期', // Misc 'deleted_user' => '刪除使用者', @@ -60,18 +60,18 @@ return [ 'grid_view' => '縮圖檢視', 'list_view' => '清單撿視', 'default' => '預設', - 'breadcrumb' => 'Breadcrumb', + 'breadcrumb' => '導覽路徑', // Header - 'profile_menu' => 'Profile Menu', + 'profile_menu' => '個人資料菜單', 'view_profile' => '檢視資料', 'edit_profile' => '編輯資料', // Layout tabs - 'tab_info' => 'Info', - 'tab_content' => 'Content', + 'tab_info' => '訊息', + 'tab_content' => '內容', // Email Content 'email_action_help' => '如果您無法點選“:actionText”按鈕,請將下面的網址複製到您的瀏覽器中打開:', - 'email_rights' => 'All rights reserved', + 'email_rights' => '版權所有', ]; diff --git a/resources/lang/zh_TW/entities.php b/resources/lang/zh_TW/entities.php index 2383ab4c4..d3280217c 100644 --- a/resources/lang/zh_TW/entities.php +++ b/resources/lang/zh_TW/entities.php @@ -11,7 +11,7 @@ return [ 'recently_updated_pages' => '最新頁面', 'recently_created_chapters' => '最近建立的章節', 'recently_created_books' => '最近建立的書本', - 'recently_created_shelves' => 'Recently Created Shelves', + 'recently_created_shelves' => '最近建立的章節', 'recently_update' => '最近更新', 'recently_viewed' => '最近看過', 'recent_activity' => '近期活動', @@ -68,7 +68,7 @@ return [ // Shelves 'shelf' => '書架', 'shelves' => '書架', - 'x_shelves' => ':count Shelf|:count Shelves', + 'x_shelves' => ':架|:章節', 'shelves_long' => '書架', 'shelves_empty' => '不存在已建立的書架', 'shelves_create' => '建立書架', @@ -128,11 +128,11 @@ return [ 'books_navigation' => '書本導覽', 'books_sort' => '排序書本內容', 'books_sort_named' => '排序書本「:bookName」', - 'books_sort_name' => 'Sort by Name', - 'books_sort_created' => 'Sort by Created Date', - 'books_sort_updated' => 'Sort by Updated Date', - 'books_sort_chapters_first' => 'Chapters First', - 'books_sort_chapters_last' => 'Chapters Last', + 'books_sort_name' => '按名稱排序', + 'books_sort_created' => '按創建時間排序', + 'books_sort_updated' => '按更新時間排序', + 'books_sort_chapters_first' => '第一章', + 'books_sort_chapters_last' => '最後一章', 'books_sort_show_other' => '顯示其他書本', 'books_sort_save' => '儲存新順序', @@ -176,7 +176,7 @@ return [ 'pages_delete_confirm' => '您確定要刪除此頁面嗎?', 'pages_delete_draft_confirm' => '您確定要刪除此草稿頁面嗎?', 'pages_editing_named' => '正在編輯頁面“:pageName”', - 'pages_edit_draft_options' => 'Draft Options', + 'pages_edit_draft_options' => '草稿選項', 'pages_edit_save_draft' => '儲存草稿', 'pages_edit_draft' => '編輯頁面草稿', 'pages_editing_draft' => '正在編輯草稿', @@ -210,8 +210,8 @@ return [ 'pages_revisions_created_by' => '建立者', 'pages_revisions_date' => '修訂日期', 'pages_revisions_number' => '#', - 'pages_revisions_numbered' => 'Revision #:id', - 'pages_revisions_numbered_changes' => 'Revision #:id Changes', + 'pages_revisions_numbered' => '修訂編號:id', + 'pages_revisions_numbered_changes' => '修訂編號:id 更改', 'pages_revisions_changelog' => '更新說明', 'pages_revisions_changes' => '說明', 'pages_revisions_current' => '目前版本', @@ -234,7 +234,7 @@ return [ ], 'pages_draft_discarded' => '草稿已丟棄,編輯器已更新到目前頁面內容。', 'pages_specific' => '指定頁面', - 'pages_is_template' => 'Page Template', + 'pages_is_template' => '頁面模板', // Editor Sidebar 'page_tags' => '頁面標籤', @@ -242,12 +242,12 @@ return [ 'book_tags' => '書本標籤', 'shelf_tags' => '書架標籤', 'tag' => '標籤', - 'tags' => 'Tags', - 'tag_name' => 'Tag Name', + 'tags' => '標籤', + 'tag_name' => '標籤名稱', 'tag_value' => '標籤值 (非必要)', 'tags_explain' => "加入一些標籤以更好地對您的內容進行分類。\n您可以為標籤分配一個值,以進行更深入的組織。", 'tags_add' => '加入另一個標籤', - 'tags_remove' => 'Remove this tag', + 'tags_remove' => '移除此標籤', 'attachments' => '附件', 'attachments_explain' => '上傳一些檔案或附加連結顯示在您的網頁上。將顯示在在頁面的側邊欄。', 'attachments_explain_instant_save' => '這裡的更改將立即儲存。Changes here are saved instantly.', @@ -273,12 +273,12 @@ return [ 'attachments_file_uploaded' => '附件上傳成功', 'attachments_file_updated' => '附件更新成功', 'attachments_link_attached' => '連結成功附加到頁面', - 'templates' => 'Templates', - 'templates_set_as_template' => 'Page is a template', - 'templates_explain_set_as_template' => 'You can set this page as a template so its contents be utilized when creating other pages. Other users will be able to use this template if they have view permissions for this page.', - 'templates_replace_content' => 'Replace page content', - 'templates_append_content' => 'Append to page content', - 'templates_prepend_content' => 'Prepend to page content', + 'templates' => '樣本', + 'templates_set_as_template' => '頁面是模板', + 'templates_explain_set_as_template' => '您可以將此頁面設置為模板,以便在創建其他頁面時利用其內容。 如果其他用戶對此頁面擁有查看權限,則將可以使用此模板。', + 'templates_replace_content' => '替換頁面內容', + 'templates_append_content' => '附加到頁面內容', + 'templates_prepend_content' => '前置頁面內容', // Profile View 'profile_user_for_x' => '來這裡:time了', @@ -286,7 +286,7 @@ return [ 'profile_not_created_pages' => ':userName尚未建立任何頁面', 'profile_not_created_chapters' => ':userName尚未建立任何章節', 'profile_not_created_books' => ':userName尚未建立任何書本', - 'profile_not_created_shelves' => ':userName has not created any shelves', + 'profile_not_created_shelves' => ':用戶名 沒有創建任何書架', // Comments 'comment' => '評論', @@ -308,7 +308,7 @@ return [ // Revision 'revision_delete_confirm' => '您確定要刪除此修訂版嗎?', - 'revision_restore_confirm' => 'Are you sure you want to restore this revision? The current page contents will be replaced.', + 'revision_restore_confirm' => '您確定要還原此修訂版嗎? 當前頁面內容將被替換。', 'revision_delete_success' => '修訂刪除', 'revision_cannot_delete_latest' => '無法刪除最新版本。' ]; \ No newline at end of file diff --git a/resources/lang/zh_TW/errors.php b/resources/lang/zh_TW/errors.php index 7cbff8891..e71575e59 100644 --- a/resources/lang/zh_TW/errors.php +++ b/resources/lang/zh_TW/errors.php @@ -13,17 +13,16 @@ return [ 'email_already_confirmed' => 'Email已被確認,請嘗試登錄。', 'email_confirmation_invalid' => '此確認 Session 無效或已被使用,請重新註冊。', 'email_confirmation_expired' => '確認 Session 已過期,已發送新的確認電子郵件。', - 'email_confirmation_awaiting' => 'The email address for the account in use needs to be confirmed', + 'email_confirmation_awaiting' => '用於此賬戶的電子郵箱需要認證', 'ldap_fail_anonymous' => '使用匿名綁定的LDAP進入失敗。', 'ldap_fail_authed' => '帶有標識名稱和密碼的LDAP進入失敗。', 'ldap_extension_not_installed' => '未安裝LDAP PHP外掛程式', 'ldap_cannot_connect' => '無法連接到ldap伺服器,第一次連接失敗', - 'saml_already_logged_in' => 'Already logged in', - 'saml_user_not_registered' => 'The user :name is not registered and automatic registration is disabled', - 'saml_no_email_address' => 'Could not find an email address, for this user, in the data provided by the external authentication system', - 'saml_invalid_response_id' => 'The request from the external authentication system is not recognised by a process started by this application. Navigating back after a login could cause this issue.', - 'saml_fail_authed' => 'Login using :system failed, system did not provide successful authorization', - 'saml_email_exists' => 'Registration unsuccessful since a user already exists with email address ":email"', + 'saml_already_logged_in' => '已登陸', + 'saml_user_not_registered' => '用戶:name未註冊,自動註冊不可用', + 'saml_no_email_address' => '在外部認證系統提供的數據中找不到該用戶的電子郵件地址', + 'saml_invalid_response_id' => '該應用程序啟動的進程無法識別來自外部身份驗證系統的請求。 登錄後返回可能會導致此問題。', + 'saml_fail_authed' => '使用:system登錄失敗,系統未提供成功的授權', 'social_no_action_defined' => '沒有定義行為', 'social_login_bad_response' => "在 :socialAccount 登錄時遇到錯誤:\n:error", 'social_account_in_use' => ':socialAccount 帳號已被使用,請嘗試透過 :socialAccount 選項登錄。', @@ -34,7 +33,7 @@ return [ 'social_account_register_instructions' => '如果您還沒有帳號,您可以使用 :socialAccount 選項註冊帳號。', 'social_driver_not_found' => '未找到社交驅動程式', 'social_driver_not_configured' => '您的:socialAccount社交設定不正確。', - 'invite_token_expired' => 'This invitation link has expired. You can instead try to reset your account password.', + 'invite_token_expired' => '此邀請鏈接已過期,您可以嘗試重置您的賬戶密碼。', // System 'path_not_writable' => '無法上傳到檔案路徑“:filePath”,請確保它可寫入伺服器。', @@ -72,7 +71,7 @@ return [ 'role_cannot_be_edited' => '無法編輯這個角色', 'role_system_cannot_be_deleted' => '無法刪除系統角色', 'role_registration_default_cannot_delete' => '無法刪除設定為預設註冊的角色', - 'role_cannot_remove_only_admin' => 'This user is the only user assigned to the administrator role. Assign the administrator role to another user before attempting to remove it here.', + 'role_cannot_remove_only_admin' => '該用戶是分配作為管理員職務的唯一用戶。 在嘗試在此處刪除管理員職務之前,請將其分配給其他用戶。', // Comments 'comment_list' => '讀取評論時發生錯誤。', @@ -90,11 +89,11 @@ return [ 'back_soon' => '請耐心等待網站的恢複。', // API errors - 'api_no_authorization_found' => 'No authorization token found on the request', - 'api_bad_authorization_format' => 'An authorization token was found on the request but the format appeared incorrect', - 'api_user_token_not_found' => 'No matching API token was found for the provided authorization token', - 'api_incorrect_token_secret' => 'The secret provided for the given used API token is incorrect', - 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', - 'api_user_token_expired' => 'The authorization token used has expired', + 'api_no_authorization_found' => '在請求上找不到授權令牌', + 'api_bad_authorization_format' => '在請求中找到授權令牌,但格式似乎不正確', + 'api_user_token_not_found' => '找不到提供的授權令牌的匹配API令牌', + 'api_incorrect_token_secret' => '給定使用的API令牌提供的密鑰不正確', + 'api_user_no_api_permission' => '使用的API令牌的擁有者者無權進行API調用', + 'api_user_token_expired' => '授權令牌已過期', ]; diff --git a/resources/lang/zh_TW/settings.php b/resources/lang/zh_TW/settings.php index 052bd5394..061e7ad58 100644 --- a/resources/lang/zh_TW/settings.php +++ b/resources/lang/zh_TW/settings.php @@ -12,24 +12,24 @@ return [ 'settings_save_success' => '設定已儲存', // App Settings - 'app_customization' => 'Customization', - 'app_features_security' => 'Features & Security', + 'app_customization' => '自定義', + 'app_features_security' => '功能與安全', 'app_name' => 'App名', 'app_name_desc' => '此名稱將在網頁頂端和Email中顯示。', 'app_name_header' => '在網頁頂端顯示應用名稱?', - 'app_public_access' => 'Public Access', - 'app_public_access_desc' => 'Enabling this option will allow visitors, that are not logged-in, to access content in your BookStack instance.', - 'app_public_access_desc_guest' => 'Access for public visitors can be controlled through the "Guest" user.', - 'app_public_access_toggle' => 'Allow public access', + 'app_public_access' => '公共訪問', + 'app_public_access_desc' => '啟用此選項將允許未登錄的訪問者訪問BookStack實例中的內容。', + 'app_public_access_desc_guest' => '可以通過“訪客”控制公共訪問者的訪問。', + 'app_public_access_toggle' => '允許公開訪問', 'app_public_viewing' => '開放公開閱覽?', 'app_secure_images' => '啟用更高安全性的圖片上傳?', - 'app_secure_images_toggle' => 'Enable higher security image uploads', + 'app_secure_images_toggle' => '啟用更高安全性的圖片上傳', 'app_secure_images_desc' => '出於效能考量,所有圖片都是公開的。這個選項會在圖片的網址前加入一個隨機並難以猜測的字元串,從而使直接進入變得困難。', 'app_editor' => '頁面編輯器', 'app_editor_desc' => '選擇所有使用者將使用哪個編輯器來編輯頁面。', 'app_custom_html' => '自訂HTML頂端內容', 'app_custom_html_desc' => '此處加入的任何內容都將插入到每個頁面的部分的底部,這對於覆蓋樣式或加入分析程式碼很方便。', - 'app_custom_html_disabled_notice' => 'Custom HTML head content is disabled on this settings page to ensure any breaking changes can be reverted.', + 'app_custom_html_disabled_notice' => '在此設置頁面上禁用了自定義HTML標題內容,以確保可以恢復所有重大更改。', 'app_logo' => 'App Logo', 'app_logo_desc' => '這個圖片的高度應該為43px。
    大圖片將會被縮小。', 'app_primary_color' => 'App主要配色', @@ -38,27 +38,27 @@ return [ 'app_homepage_desc' => '選擇要做為首頁的頁面,這將會替換預設首頁,而且這個頁面的權限設定將被忽略。', 'app_homepage_select' => '預設首頁選擇', 'app_disable_comments' => '關閉評論', - 'app_disable_comments_toggle' => 'Disable comments', + 'app_disable_comments_toggle' => '禁用評論', 'app_disable_comments_desc' => '在App的所有頁面上關閉評論,已經存在的評論也不會顯示。', // Color settings - 'content_colors' => 'Content Colors', - 'content_colors_desc' => 'Sets colors for all elements in the page organisation hierarchy. Choosing colors with a similar brightness to the default colors is recommended for readability.', - 'bookshelf_color' => 'Shelf Color', - 'book_color' => 'Book Color', - 'chapter_color' => 'Chapter Color', - 'page_color' => 'Page Color', - 'page_draft_color' => 'Page Draft Color', + 'content_colors' => '內容顏色', + 'content_colors_desc' => '為頁面組織層次結構中的所有元素設置顏色。 為了提高可讀性,建議選擇亮度與默認顏色相似的顏色。', + 'bookshelf_color' => '书架顏色', + 'book_color' => '书本颜色', + 'chapter_color' => '章节颜色', + 'page_color' => '页面颜色', + 'page_draft_color' => '頁面草稿顏色', // Registration Settings 'reg_settings' => '註冊設定', - 'reg_enable' => 'Enable Registration', - 'reg_enable_toggle' => 'Enable registration', - 'reg_enable_desc' => 'When registration is enabled user will be able to sign themselves up as an application user. Upon registration they are given a single, default user role.', + 'reg_enable' => '啟用註冊', + 'reg_enable_toggle' => '啟用註冊', + 'reg_enable_desc' => '啟用註冊後,用戶將可以自己註冊為應用程序用戶,註冊後,他們將獲得一個默認的單一用戶角色。', 'reg_default_role' => '註冊後的預設使用者角色', - 'reg_enable_ldap_warning' => 'The option above is not used while LDAP authentication is active. User accounts for non-existing members will be auto-created if authentication, against the LDAP system in use, is successful.', - 'reg_email_confirmation' => 'Email Confirmation', - 'reg_email_confirmation_toggle' => 'Require email confirmation', + 'reg_enable_external_warning' => 'The option above is ignored while external LDAP or SAML authentication is active. User accounts for non-existing members will be auto-created if authentication, against the external system in use, is successful.', + 'reg_email_confirmation' => '电子邮箱认证', + 'reg_email_confirmation_toggle' => '需要電子郵件確認', 'reg_confirm_email_desc' => '如果使用網域名稱限制,則需要Email驗證,並且本設定將被忽略。', 'reg_confirm_restrict_domain' => '網域名稱限制', 'reg_confirm_restrict_domain_desc' => '輸入您想要限制註冊的Email域域名稱列表,用逗號隔開。在被允許與本系統連結之前,使用者會收到一封Email來確認他們的位址。
    注意,使用者在註冊成功後可以修改他們的Email位址。', @@ -73,13 +73,13 @@ return [ 'maint_image_cleanup_warning' => '發現了 :count 張可能未使用的圖像。您確定要刪除這些圖像嗎?', 'maint_image_cleanup_success' => '找到並刪除了 :count 張可能未使用的圖像!', 'maint_image_cleanup_nothing_found' => '找不到未使用的圖像,沒有刪除!', - 'maint_send_test_email' => 'Send a Test Email', - 'maint_send_test_email_desc' => 'This sends a test email to your email address specified in your profile.', - 'maint_send_test_email_run' => 'Send test email', - 'maint_send_test_email_success' => 'Email sent to :address', - 'maint_send_test_email_mail_subject' => 'Test Email', - 'maint_send_test_email_mail_greeting' => 'Email delivery seems to work!', - 'maint_send_test_email_mail_text' => 'Congratulations! As you received this email notification, your email settings seem to be configured properly.', + 'maint_send_test_email' => '發送測試電子郵件', + 'maint_send_test_email_desc' => '這會將測試電子郵件發送到您的個人資料中指定的電子郵件地址。', + 'maint_send_test_email_run' => '發送測試郵件', + 'maint_send_test_email_success' => '郵件發送到:地址', + 'maint_send_test_email_mail_subject' => '測試郵件', + 'maint_send_test_email_mail_greeting' => '電子郵件傳遞似乎有效!', + 'maint_send_test_email_mail_text' => '恭喜你! 收到此電子郵件通知時,您的電子郵件設置已經認證成功。', // Role Settings 'roles' => '角色', @@ -102,8 +102,8 @@ return [ 'role_manage_roles' => '管理角色與角色權限', 'role_manage_entity_permissions' => '管理所有圖書,章節和頁面的權限', 'role_manage_own_entity_permissions' => '管理自己的圖書,章節和頁面的權限', - 'role_manage_page_templates' => 'Manage page templates', - 'role_access_api' => 'Access system API', + 'role_manage_page_templates' => '管理頁面模板', + 'role_access_api' => '存取系統API', 'role_manage_settings' => '管理App設定', 'role_asset' => '資源項目', 'role_asset_desc' => '對系統內資源的預設權限將由這裡的權限控制。若有單獨設定在書本、章節和頁面上的權限,將會覆蓋這裡的權限設定。', @@ -121,17 +121,17 @@ return [ 'user_profile' => '使用者資料', 'users_add_new' => '加入使用者', 'users_search' => '搜尋使用者', - 'users_details' => 'User Details', - 'users_details_desc' => 'Set a display name and an email address for this user. The email address will be used for logging into the application.', - 'users_details_desc_no_email' => 'Set a display name for this user so others can recognise them.', + 'users_details' => '用戶詳情', + 'users_details_desc' => '請設置用戶的顯示名稱和電子郵件地址, 該電子郵件地址將用於登錄該應用。', + 'users_details_desc_no_email' => '設置一個用戶的顯示名稱,以便其他人可以認出你。', 'users_role' => '使用者角色', - 'users_role_desc' => 'Select which roles this user will be assigned to. If a user is assigned to multiple roles the permissions from those roles will stack and they will receive all abilities of the assigned roles.', - 'users_password' => 'User Password', - 'users_password_desc' => 'Set a password used to log-in to the application. This must be at least 6 characters long.', - 'users_send_invite_text' => 'You can choose to send this user an invitation email which allows them to set their own password otherwise you can set their password yourself.', - 'users_send_invite_option' => 'Send user invite email', + 'users_role_desc' => '選擇一個將分配給該用戶的角色。 如果將一個用戶分配給多個角色,則這些角色的權限將堆疊在一起,並且他們將獲得分配的角色的所有功能。', + 'users_password' => '用戶密碼', + 'users_password_desc' => '設置用於登錄賬戶的密碼, 密碼長度必須至少為6個字符。', + 'users_send_invite_text' => '您可以選擇向該用戶發送邀請電子郵件,允許他們設置自己的密碼,或者您可以自己設置他們的密碼。', + 'users_send_invite_option' => '向用戶發送邀請電子郵件', 'users_external_auth_id' => '外部身份驗證ID', - 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your LDAP system.', + 'users_external_auth_id_desc' => 'This is the ID used to match this user when communicating with your external authentication system.', 'users_password_warning' => '如果您想更改密碼,請填寫以下內容:', 'users_system_public' => '此使用者代表進入您的App的任何訪客。它不能用於登入,而是自動分配。', 'users_delete' => '刪除使用者', @@ -145,39 +145,39 @@ return [ 'users_avatar' => '使用者大頭照', 'users_avatar_desc' => '目前圖片應該為約256px的正方形。', 'users_preferred_language' => '語言', - 'users_preferred_language_desc' => 'This option will change the language used for the user-interface of the application. This will not affect any user-created content.', + 'users_preferred_language_desc' => '此選項將更改用於應用用戶界面的語言,但 這不會影響任何用戶創建的內容。', 'users_social_accounts' => '社群網站帳號', 'users_social_accounts_info' => '在這里,您可以連結您的其他帳號,以便方便地登入。如果您選擇解除連結,之後將不能透過此社群網站帳號登入,請設定社群網站帳號來取消本系統p的進入權限。', 'users_social_connect' => '連結帳號', 'users_social_disconnect' => '解除連結帳號', 'users_social_connected' => ':socialAccount 帳號已經成功連結到您的資料。', 'users_social_disconnected' => ':socialAccount 帳號已經成功解除連結。', - 'users_api_tokens' => 'API Tokens', - 'users_api_tokens_none' => 'No API tokens have been created for this user', - 'users_api_tokens_create' => 'Create Token', - 'users_api_tokens_expires' => 'Expires', - 'users_api_tokens_docs' => 'API Documentation', + 'users_api_tokens' => 'API令牌', + 'users_api_tokens_none' => '尚未為此用戶創建API令牌', + 'users_api_tokens_create' => '創建令牌', + 'users_api_tokens_expires' => '過期', + 'users_api_tokens_docs' => 'API檔案', // API Tokens - 'user_api_token_create' => 'Create API Token', - 'user_api_token_name' => 'Name', - 'user_api_token_name_desc' => 'Give your token a readable name as a future reminder of its intended purpose.', - 'user_api_token_expiry' => 'Expiry Date', - 'user_api_token_expiry_desc' => 'Set a date at which this token expires. After this date, requests made using this token will no longer work. Leaving this field blank will set an expiry 100 years into the future.', - 'user_api_token_create_secret_message' => 'Immediately after creating this token a "Token ID"" & "Token Secret" will be generated and displayed. The secret will only be shown a single time so be sure to copy the value to somewhere safe and secure before proceeding.', - 'user_api_token_create_success' => 'API token successfully created', - 'user_api_token_update_success' => 'API token successfully updated', - 'user_api_token' => 'API Token', - 'user_api_token_id' => 'Token ID', - 'user_api_token_id_desc' => 'This is a non-editable system generated identifier for this token which will need to be provided in API requests.', - 'user_api_token_secret' => 'Token Secret', - 'user_api_token_secret_desc' => 'This is a system generated secret for this token which will need to be provided in API requests. This will only be displayed this one time so copy this value to somewhere safe and secure.', - 'user_api_token_created' => 'Token Created :timeAgo', - 'user_api_token_updated' => 'Token Updated :timeAgo', - 'user_api_token_delete' => 'Delete Token', - 'user_api_token_delete_warning' => 'This will fully delete this API token with the name \':tokenName\' from the system.', - 'user_api_token_delete_confirm' => 'Are you sure you want to delete this API token?', - 'user_api_token_delete_success' => 'API token successfully deleted', + 'user_api_token_create' => '創建 API 令牌', + 'user_api_token_name' => '名稱', + 'user_api_token_name_desc' => '給您的令牌一個易讀的名稱,以備將來提醒其預期的用途。', + 'user_api_token_expiry' => '過期日期', + 'user_api_token_expiry_desc' => '設置此令牌到期的日期, 在此日期之後,使用此令牌發出的請求將不再起作用。 若該項留空則自動將在100年後到期。', + 'user_api_token_create_secret_message' => '創建此令牌後,將立即生成並顯示“令牌ID”和“令牌密鑰”,該密鑰只會顯示一次,因此請確保在繼續操作之前將其複製到安全的地方。', + 'user_api_token_create_success' => '成功創建API令牌', + 'user_api_token_update_success' => '成功更新API令牌', + 'user_api_token' => 'API 令牌', + 'user_api_token_id' => '令牌 ID', + 'user_api_token_id_desc' => '這是此令牌的不可編輯的系統生成的標識符,需要在API請求中提供。', + 'user_api_token_secret' => '令牌密鑰', + 'user_api_token_secret_desc' => '這是此令牌的系統生成的密鑰,需要在API請求中提供。 這只會顯示一次,因此請將其複製到安全的地方。', + 'user_api_token_created' => '令牌已創建:time Ago', + 'user_api_token_updated' => '令牌已更新:timeAgo', + 'user_api_token_delete' => '刪除令牌', + 'user_api_token_delete_warning' => '這將從系統中完全刪除名稱為\':tokenName\'的API令牌。', + 'user_api_token_delete_confirm' => '您確定要刪除這個API令牌嗎?', + 'user_api_token_delete_success' => 'API令牌成功刪除', //! If editing translations files directly please ignore this in all //! languages apart from en. Content will be auto-copied from en. @@ -185,6 +185,7 @@ return [ 'language_select' => [ 'en' => 'English', 'ar' => 'العربية', + 'da' => '丹麥', 'de' => 'Deutsch (Sie)', 'de_informal' => 'Deutsch (Du)', 'es' => 'Español', diff --git a/resources/lang/zh_TW/validation.php b/resources/lang/zh_TW/validation.php index 33a3c7119..046e24451 100644 --- a/resources/lang/zh_TW/validation.php +++ b/resources/lang/zh_TW/validation.php @@ -30,40 +30,40 @@ return [ 'digits' => ':attribute 必須為:digits位數。', 'digits_between' => ':attribute 必須為:min到:max位數。', 'email' => ':attribute 必須是有效的電子郵件位址。', - 'ends_with' => 'The :attribute must end with one of the following: :values', + 'ends_with' => ':attribute必須以下列之一結尾::values', 'filled' => ':attribute 字段是必需的。', 'gt' => [ - 'numeric' => 'The :attribute must be greater than :value.', - 'file' => 'The :attribute must be greater than :value kilobytes.', - 'string' => 'The :attribute must be greater than :value characters.', - 'array' => 'The :attribute must have more than :value items.', + 'numeric' => ':attribute必須大於:value。', + 'file' => ':attribute必須大於:value千字節。', + 'string' => ':attribute必須大於:value字符。', + 'array' => ':attribute必須包含比:value多的項目。', ], 'gte' => [ - 'numeric' => 'The :attribute must be greater than or equal :value.', - 'file' => 'The :attribute must be greater than or equal :value kilobytes.', - 'string' => 'The :attribute must be greater than or equal :value characters.', - 'array' => 'The :attribute must have :value items or more.', + 'numeric' => 'The :attribute必須大於或等於:value.', + 'file' => 'The :attribute必須大於或等於:value千字節。', + 'string' => 'The :attribute必須大於或等於:value字符。', + 'array' => 'The :attribute必須具有:value項或更多。', ], 'exists' => '選中的 :attribute 無效。', 'image' => ':attribute 必須是一個圖片。', - 'image_extension' => 'The :attribute must have a valid & supported image extension.', + 'image_extension' => 'The :attribute必須具有有效且受支持的圖像擴展名.', 'in' => '選中的 :attribute 無效。', 'integer' => ':attribute 必須是一個整數。', 'ip' => ':attribute 必須是一個有效的IP位址。', - 'ipv4' => 'The :attribute must be a valid IPv4 address.', - 'ipv6' => 'The :attribute must be a valid IPv6 address.', - 'json' => 'The :attribute must be a valid JSON string.', + 'ipv4' => 'The :attribute必須是有效的IPv4地址。', + 'ipv6' => 'The :attribute必須是有效的IPv6地址。', + 'json' => 'The :attribute必須是有效的JSON字符串。', 'lt' => [ - 'numeric' => 'The :attribute must be less than :value.', - 'file' => 'The :attribute must be less than :value kilobytes.', - 'string' => 'The :attribute must be less than :value characters.', - 'array' => 'The :attribute must have less than :value items.', + 'numeric' => 'The :attribute必須小於:value。', + 'file' => 'The :attribute必須小於:value千字節。', + 'string' => 'The :attribute必須小於:value字符。', + 'array' => 'The :attribute必須少於:value個項目。', ], 'lte' => [ - 'numeric' => 'The :attribute must be less than or equal :value.', - 'file' => 'The :attribute must be less than or equal :value kilobytes.', - 'string' => 'The :attribute must be less than or equal :value characters.', - 'array' => 'The :attribute must not have more than :value items.', + 'numeric' => 'The :attribute必須小於或等於:value。', + 'file' => 'The :attribute必須小於或等於:value千字節。', + 'string' => 'The :attribute必須小於或等於:value字符。', + 'array' => 'The :attribute不得超過:value個項目。', ], 'max' => [ 'numeric' => ':attribute 不能超過:max。', @@ -78,9 +78,9 @@ return [ 'string' => ':attribute 至少為:min個字元。', 'array' => ':attribute 至少有:min項。', ], - 'no_double_extension' => 'The :attribute must only have a single file extension.', + 'no_double_extension' => 'The :attribute必須僅具有一個文件擴展名。', 'not_in' => '選中的 :attribute 無效。', - 'not_regex' => 'The :attribute format is invalid.', + 'not_regex' => 'The :attribute格式無效。', 'numeric' => ':attribute 必須是一個數。', 'regex' => ':attribute 格式無效。', 'required' => ':attribute 字段是必需的。', @@ -100,7 +100,7 @@ return [ 'timezone' => ':attribute 必須是有效的區域。', 'unique' => ':attribute 已經被使用。', 'url' => ':attribute 格式無效。', - 'uploaded' => 'The file could not be uploaded. The server may not accept files of this size.', + 'uploaded' => '無法上傳文件, 服務器可能不接受此大小的文件。', // Custom validation lines 'custom' => [ From 33ef1cd4fa2e4f8b988658d0d244b2dd67ba09a2 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 3 Feb 2020 22:25:17 +0000 Subject: [PATCH 179/191] Updated translators file --- .github/translators.txt | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/.github/translators.txt b/.github/translators.txt index 5435cfc4d..c8d505e82 100644 --- a/.github/translators.txt +++ b/.github/translators.txt @@ -27,11 +27,11 @@ Name :: Languages @CliffyPrime :: German @kejjang :: Chinese Traditional @TheLastOperator :: French -@qianmengnet :: Chinese Simplified -@ezzra :: German Informal +@qianmengnet :: Simplified Chinese +@ezzra :: German; German Informal @vasiliev123 :: Polish @Mant1kor :: Ukrainian -@Xiphoseer German; German Informal +@Xiphoseer :: German; German Informal @maantje :: Dutch @cima :: Czech @agvol :: Russian @@ -43,10 +43,31 @@ Name :: Languages @danielroehrig-mm :: German @oykenfurkan :: Turkish @qligier :: French +@johnroyer :: Traditional Chinese +@artskoczylas :: Polish +@dellamina :: Italian +@jzoy :: Simplified Chinese +@ististudio :: Korean +@leomartinez :: Spanish Argentina cipi1965 :: Italian Mykola Ronik (Mantikor) :: Ukrainian furkanoyk :: Turkish m0uch0 :: Spanish Maxim Zalata (zlatin) :: Russian; Ukrainian nutsflag :: French -Leonardo Mario Martinez (leonardo.m.martinez) :: Spanish, Argentina \ No newline at end of file +Leonardo Mario Martinez (leonardo.m.martinez) :: Spanish, Argentina +Rodrigo Saczuk Niz (rodrigoniz) :: Portuguese, Brazilian +叫钦叔就好 (254351722) :: Chinese Traditional; Chinese Simplified +aekramer :: Dutch +JachuPL :: Polish +milesteg :: Hungarian +Beenbag :: German +Lett3rs :: Danish +Julian (julian.henneberg) :: German; German Informal +3GNWn :: Danish +dbguichu :: Chinese Simplified +Randy Kim (hyunjun) :: Korean +Francesco M. Taurino (ftaurino) :: Italian +DanielFrederiksen :: Danish +Finn Wessel (19finnwessel6) :: German +Gustav Kånåhols (Kurbitz) :: Swedish From 9533e0646ed25c3469fe7c8186be8f50e53df218 Mon Sep 17 00:00:00 2001 From: TBK Date: Fri, 14 Feb 2020 20:33:07 +0100 Subject: [PATCH 180/191] Fix for missing cover on create new shelf --- app/Http/Controllers/BookshelfController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/BookshelfController.php b/app/Http/Controllers/BookshelfController.php index 57e67dc00..c882ca7c3 100644 --- a/app/Http/Controllers/BookshelfController.php +++ b/app/Http/Controllers/BookshelfController.php @@ -90,7 +90,7 @@ class BookshelfController extends Controller $bookIds = explode(',', $request->get('books', '')); $shelf = $this->bookshelfRepo->create($request->all(), $bookIds); - $this->bookshelfRepo->updateCoverImage($shelf); + $this->bookshelfRepo->updateCoverImage($shelf, $request->file('image', null)); Activity::add($shelf, 'bookshelf_create'); return redirect($shelf->getUrl()); From 49386b42dae9ccd3d446d1819141ddd56676e3f7 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 15 Feb 2020 14:13:15 +0000 Subject: [PATCH 181/191] Updated email test send to show error on failure - Added test to cover - Closes #1874 --- app/Http/Controllers/SettingController.php | 10 ++++++++-- resources/lang/en/errors.php | 3 +++ tests/TestEmailTest.php | 19 +++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/SettingController.php b/app/Http/Controllers/SettingController.php index 892b2d9cf..00dd60ac7 100644 --- a/app/Http/Controllers/SettingController.php +++ b/app/Http/Controllers/SettingController.php @@ -122,8 +122,14 @@ class SettingController extends Controller { $this->checkPermission('settings-manage'); - user()->notify(new TestEmail()); - $this->showSuccessNotification(trans('settings.maint_send_test_email_success', ['address' => user()->email])); + try { + user()->notify(new TestEmail()); + $this->showSuccessNotification(trans('settings.maint_send_test_email_success', ['address' => user()->email])); + } catch (\Exception $exception) { + $errorMessage = trans('errors.maintenance_test_email_failure') . "\n" . $exception->getMessage(); + $this->showErrorNotification($errorMessage); + } + return redirect('/settings/maintenance#image-cleanup')->withInput(); } diff --git a/resources/lang/en/errors.php b/resources/lang/en/errors.php index 4752d8b0c..38f1ce28a 100644 --- a/resources/lang/en/errors.php +++ b/resources/lang/en/errors.php @@ -96,4 +96,7 @@ return [ 'api_user_no_api_permission' => 'The owner of the used API token does not have permission to make API calls', 'api_user_token_expired' => 'The authorization token used has expired', + // Settings & Maintenance + 'maintenance_test_email_failure' => 'Error thrown when sending a test email:', + ]; diff --git a/tests/TestEmailTest.php b/tests/TestEmailTest.php index c06311d84..76ff322ff 100644 --- a/tests/TestEmailTest.php +++ b/tests/TestEmailTest.php @@ -1,6 +1,7 @@ mock(Dispatcher::class); + $this->app[Dispatcher::class] = $mockDispatcher; + + $exception = new \Exception('A random error occurred when testing an email'); + $mockDispatcher->shouldReceive('send')->andThrow($exception); + + $admin = $this->getAdmin(); + $sendReq = $this->actingAs($admin)->post('/settings/maintenance/send-test-email'); + $sendReq->assertRedirect('/settings/maintenance#image-cleanup'); + $this->assertSessionHas('error'); + + $message = session()->get('error'); + $this->assertStringContainsString('Error thrown when sending a test email:', $message); + $this->assertStringContainsString('A random error occurred when testing an email', $message); + } + public function test_send_test_email_requires_settings_manage_permission() { Notification::fake(); From e8cfb4f2bed8c786da9ceccbe1599c33e23a6565 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 15 Feb 2020 14:24:55 +0000 Subject: [PATCH 182/191] Removed unintended extra lines in code blocks Fixes #1877 --- resources/js/services/code.js | 2 +- resources/sass/_text.scss | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/resources/js/services/code.js b/resources/js/services/code.js index 718ef5721..a8cede5f4 100644 --- a/resources/js/services/code.js +++ b/resources/js/services/code.js @@ -111,7 +111,7 @@ function highlightWithin(parent) { function highlightElem(elem) { const innerCodeElem = elem.querySelector('code[class^=language-]'); elem.innerHTML = elem.innerHTML.replace(//gi ,'\n'); - const content = elem.textContent; + const content = elem.textContent.trimEnd(); let mode = ''; if (innerCodeElem !== null) { diff --git a/resources/sass/_text.scss b/resources/sass/_text.scss index 77e0773eb..d28706781 100644 --- a/resources/sass/_text.scss +++ b/resources/sass/_text.scss @@ -238,7 +238,6 @@ code { padding: 1px 3px; white-space:pre-wrap; line-height: 1.2em; - margin-bottom: 1.2em; } span.code { From 14363edb73d8baacd5325c572b1f401f96404f58 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 15 Feb 2020 14:44:36 +0000 Subject: [PATCH 183/191] Fixed LDAP error thrown by not found user details - Added testing to cover. Related to #1876 --- app/Auth/Access/Guards/LdapSessionGuard.php | 23 ++++++++++++++------- app/Auth/Access/LdapService.php | 4 ++-- tests/Auth/LdapTest.php | 19 ++++++++++++++++- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/app/Auth/Access/Guards/LdapSessionGuard.php b/app/Auth/Access/Guards/LdapSessionGuard.php index 3c98140f6..84f54ad29 100644 --- a/app/Auth/Access/Guards/LdapSessionGuard.php +++ b/app/Auth/Access/Guards/LdapSessionGuard.php @@ -44,11 +44,14 @@ class LdapSessionGuard extends ExternalBaseSessionGuard public function validate(array $credentials = []) { $userDetails = $this->ldapService->getUserDetails($credentials['username']); - $this->lastAttempted = $this->provider->retrieveByCredentials([ - 'external_auth_id' => $userDetails['uid'] - ]); - return $this->ldapService->validateUserCredentials($userDetails, $credentials['username'], $credentials['password']); + if (isset($userDetails['uid'])) { + $this->lastAttempted = $this->provider->retrieveByCredentials([ + 'external_auth_id' => $userDetails['uid'] + ]); + } + + return $this->ldapService->validateUserCredentials($userDetails, $credentials['password']); } /** @@ -66,11 +69,15 @@ class LdapSessionGuard extends ExternalBaseSessionGuard { $username = $credentials['username']; $userDetails = $this->ldapService->getUserDetails($username); - $this->lastAttempted = $user = $this->provider->retrieveByCredentials([ - 'external_auth_id' => $userDetails['uid'] - ]); - if (!$this->ldapService->validateUserCredentials($userDetails, $username, $credentials['password'])) { + $user = null; + if (isset($userDetails['uid'])) { + $this->lastAttempted = $user = $this->provider->retrieveByCredentials([ + 'external_auth_id' => $userDetails['uid'] + ]); + } + + if (!$this->ldapService->validateUserCredentials($userDetails, $credentials['password'])) { return false; } diff --git a/app/Auth/Access/LdapService.php b/app/Auth/Access/LdapService.php index 07e9f7b64..0d6ebfc80 100644 --- a/app/Auth/Access/LdapService.php +++ b/app/Auth/Access/LdapService.php @@ -102,9 +102,9 @@ class LdapService extends ExternalAuthService * Check if the given credentials are valid for the given user. * @throws LdapException */ - public function validateUserCredentials(array $ldapUserDetails, string $username, string $password): bool + public function validateUserCredentials(?array $ldapUserDetails, string $password): bool { - if ($ldapUserDetails === null) { + if (is_null($ldapUserDetails)) { return false; } diff --git a/tests/Auth/LdapTest.php b/tests/Auth/LdapTest.php index cb1194e22..06f88c222 100644 --- a/tests/Auth/LdapTest.php +++ b/tests/Auth/LdapTest.php @@ -166,7 +166,7 @@ class LdapTest extends BrowserKitTest ->seeInDatabase('users', ['email' => $this->mockUser->email, 'email_confirmed' => false, 'external_auth_id' => 'cooluser456']); } - public function test_initial_incorrect_details() + public function test_initial_incorrect_credentials() { $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId); $this->mockLdap->shouldReceive('setVersion')->once(); @@ -186,6 +186,23 @@ class LdapTest extends BrowserKitTest ->dontSeeInDatabase('users', ['external_auth_id' => $this->mockUser->name]); } + public function test_login_not_found_username() + { + $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId); + $this->mockLdap->shouldReceive('setVersion')->once(); + $this->mockLdap->shouldReceive('setOption')->times(1); + $this->mockLdap->shouldReceive('searchAndGetEntries')->times(1) + ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) + ->andReturn(['count' => 0]); + $this->mockLdap->shouldReceive('bind')->times(1)->andReturn(true, false); + $this->mockEscapes(1); + + $this->mockUserLogin() + ->seePageIs('/login')->see('These credentials do not match our records.') + ->dontSeeInDatabase('users', ['external_auth_id' => $this->mockUser->name]); + } + + public function test_create_user_form() { $this->asAdmin()->visit('/settings/users/create') From ccd50fe918518b9b9fc76d57e6b56a445ce8f014 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 15 Feb 2020 15:34:06 +0000 Subject: [PATCH 184/191] Aligned export styles a little better and fixed potential DOMPDF css error - Removed different PDF template used on pages. - Updated export view files to have the intended format passed. - Shared the export CSS amoung the export templates. Should hopefully address #1886 --- app/Entities/ExportService.php | 30 +++++++++------- resources/sass/export-styles.scss | 1 - resources/views/books/export.blade.php | 5 ++- resources/views/chapters/export.blade.php | 6 ++-- resources/views/pages/export.blade.php | 31 +++++++++++++---- resources/views/pages/pdf.blade.php | 34 ------------------- .../views/partials/export-styles.blade.php | 29 ++++++++++++++++ 7 files changed, 76 insertions(+), 60 deletions(-) delete mode 100644 resources/views/pages/pdf.blade.php create mode 100644 resources/views/partials/export-styles.blade.php diff --git a/app/Entities/ExportService.php b/app/Entities/ExportService.php index 3ec867959..f945dfbe4 100644 --- a/app/Entities/ExportService.php +++ b/app/Entities/ExportService.php @@ -29,8 +29,9 @@ class ExportService public function pageToContainedHtml(Page $page) { $page->html = (new PageContent($page))->render(); - $pageHtml = view('pages/export', [ - 'page' => $page + $pageHtml = view('pages.export', [ + 'page' => $page, + 'format' => 'html', ])->render(); return $this->containHtml($pageHtml); } @@ -45,9 +46,10 @@ class ExportService $pages->each(function ($page) { $page->html = (new PageContent($page))->render(); }); - $html = view('chapters/export', [ + $html = view('chapters.export', [ 'chapter' => $chapter, - 'pages' => $pages + 'pages' => $pages, + 'format' => 'html', ])->render(); return $this->containHtml($html); } @@ -59,9 +61,10 @@ class ExportService public function bookToContainedHtml(Book $book) { $bookTree = (new BookContents($book))->getTree(false, true); - $html = view('books/export', [ + $html = view('books.export', [ 'book' => $book, - 'bookChildren' => $bookTree + 'bookChildren' => $bookTree, + 'format' => 'html', ])->render(); return $this->containHtml($html); } @@ -73,8 +76,9 @@ class ExportService public function pageToPdf(Page $page) { $page->html = (new PageContent($page))->render(); - $html = view('pages/pdf', [ - 'page' => $page + $html = view('pages.export', [ + 'page' => $page, + 'format' => 'pdf', ])->render(); return $this->htmlToPdf($html); } @@ -90,9 +94,10 @@ class ExportService $page->html = (new PageContent($page))->render(); }); - $html = view('chapters/export', [ + $html = view('chapters.export', [ 'chapter' => $chapter, - 'pages' => $pages + 'pages' => $pages, + 'format' => 'pdf', ])->render(); return $this->htmlToPdf($html); @@ -105,9 +110,10 @@ class ExportService public function bookToPdf(Book $book) { $bookTree = (new BookContents($book))->getTree(false, true); - $html = view('books/export', [ + $html = view('books.export', [ 'book' => $book, - 'bookChildren' => $bookTree + 'bookChildren' => $bookTree, + 'format' => 'pdf', ])->render(); return $this->htmlToPdf($html); } diff --git a/resources/sass/export-styles.scss b/resources/sass/export-styles.scss index 958b78807..6d9a1a718 100644 --- a/resources/sass/export-styles.scss +++ b/resources/sass/export-styles.scss @@ -5,7 +5,6 @@ @import "text"; @import "layout"; @import "blocks"; -@import "forms"; @import "tables"; @import "header"; @import "lists"; diff --git a/resources/views/books/export.blade.php b/resources/views/books/export.blade.php index 1cf91046d..e86a24e81 100644 --- a/resources/views/books/export.blade.php +++ b/resources/views/books/export.blade.php @@ -4,10 +4,9 @@ {{ $book->name }} + @include('partials.export-styles', ['format' => $format]) + - @yield('head') @include('partials.custom-head') diff --git a/resources/views/pages/export.blade.php b/resources/views/pages/export.blade.php index 4746a56f3..47a4d870a 100644 --- a/resources/views/pages/export.blade.php +++ b/resources/views/pages/export.blade.php @@ -4,12 +4,31 @@ {{ $page->name }} - - @yield('head') + @include('partials.export-styles', ['format' => $format]) + + @if($format === 'pdf') + + @endif + @include('partials.custom-head') diff --git a/resources/views/pages/pdf.blade.php b/resources/views/pages/pdf.blade.php deleted file mode 100644 index 33a009fee..000000000 --- a/resources/views/pages/pdf.blade.php +++ /dev/null @@ -1,34 +0,0 @@ -@extends('pages/export') - -@section('head') - -@stop \ No newline at end of file diff --git a/resources/views/partials/export-styles.blade.php b/resources/views/partials/export-styles.blade.php new file mode 100644 index 000000000..52bfda2a6 --- /dev/null +++ b/resources/views/partials/export-styles.blade.php @@ -0,0 +1,29 @@ + + +@if ($format === 'pdf') + +@endif \ No newline at end of file From e9d879bcc556a46d99fd63387b5893abda26a034 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 15 Feb 2020 15:47:17 +0000 Subject: [PATCH 185/191] Made some updates to project readme and license --- LICENSE | 2 +- readme.md | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/LICENSE b/LICENSE index 080c54b3e..61aeaad8c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2018 Dan Brown and the BookStack Project contributors +Copyright (c) 2020 Dan Brown and the BookStack Project contributors https://github.com/BookStackApp/BookStack/graphs/contributors Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/readme.md b/readme.md index fb26cede3..5b51b8eab 100644 --- a/readme.md +++ b/readme.md @@ -2,10 +2,11 @@ [![GitHub release](https://img.shields.io/github/release/BookStackApp/BookStack.svg)](https://github.com/BookStackApp/BookStack/releases/latest) [![license](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/BookStackApp/BookStack/blob/master/LICENSE) +[![Crowdin](https://badges.crowdin.net/bookstack/localized.svg)](https://crowdin.com/project/bookstack) [![Build Status](https://github.com/BookStackApp/BookStack/workflows/phpunit/badge.svg)](https://github.com/BookStackApp/BookStack/actions) [![Discord](https://img.shields.io/static/v1?label=Chat&message=Discord&color=738adb&logo=discord)](https://discord.gg/ztkBqR2) -A platform for storing and organising information and documentation. General information and documentation for BookStack can be found at https://www.bookstackapp.com/. +A platform for storing and organising information and documentation. Details for BookStack can be found on the official website at https://www.bookstackapp.com/. * [Installation Instructions](https://www.bookstackapp.com/docs/admin/installation) * [Documentation](https://www.bookstackapp.com/docs) @@ -25,7 +26,7 @@ In regards to development philosophy, BookStack has a relaxed, open & positive a Below is a high-level road map view for BookStack to provide a sense of direction of where the project is going. This can change at any point and does not reflect many features and improvements that will also be included as part of the journey along this road map. For more granular detail of what will be included in upcoming releases you can review the project milestones as defined in the "Release Process" section below. -- **Platform REST API** *(In Design)* +- **Platform REST API** *(Base Implemented, In review and roll-out)* - *A REST API covering, at minimum, control of core content models (Books, Chapters, Pages) for automation and platform extension.* - **Editor Alignment & Review** - *Review the page editors with goal of achieving increased interoperability & feature parity while also considering collaborative editing potential.* From ea3c3cde5aa7e25dd68821fe4b1b8247b2ab714a Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 15 Feb 2020 18:34:02 +0000 Subject: [PATCH 186/191] Added test to ensure shelf cover image gets set on create Related to #1897 --- tests/Entity/BookShelfTest.php | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/tests/Entity/BookShelfTest.php b/tests/Entity/BookShelfTest.php index 5c7673847..b44761203 100644 --- a/tests/Entity/BookShelfTest.php +++ b/tests/Entity/BookShelfTest.php @@ -1,14 +1,17 @@ getViewer(); @@ -83,6 +86,26 @@ class BookShelfTest extends TestCase $this->assertDatabaseHas('bookshelves_books', ['bookshelf_id' => $shelf->id, 'book_id' => $booksToInclude[1]->id]); } + public function test_shelves_create_sets_cover_image() + { + $shelfInfo = [ + 'name' => 'My test book' . Str::random(4), + 'description' => 'Test book description ' . Str::random(10) + ]; + + $imageFile = $this->getTestImage('shelf-test.png'); + $resp = $this->asEditor()->call('POST', '/shelves', $shelfInfo, [], ['image' => $imageFile]); + $resp->assertRedirect(); + + $lastImage = Image::query()->orderByDesc('id')->firstOrFail(); + $shelf = Bookshelf::query()->where('name', '=', $shelfInfo['name'])->first(); + $this->assertDatabaseHas('bookshelves', [ + 'id' => $shelf, + 'image_id' => $lastImage->id, + ]); + $this->assertEquals($lastImage->id, $shelf->cover->id); + } + public function test_shelf_view() { $shelf = Bookshelf::first(); From 5978d9a0d3766a884aa46d5fc2085eb3420a8ba8 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 15 Feb 2020 18:38:36 +0000 Subject: [PATCH 187/191] Updated cover image methods so image parameter is not optional but still nullable --- app/Entities/Repos/BaseRepo.php | 2 +- app/Entities/Repos/BookRepo.php | 2 +- app/Entities/Repos/BookshelfRepo.php | 2 +- tests/Entity/BookShelfTest.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/Entities/Repos/BaseRepo.php b/app/Entities/Repos/BaseRepo.php index 23f07f820..7c25e4981 100644 --- a/app/Entities/Repos/BaseRepo.php +++ b/app/Entities/Repos/BaseRepo.php @@ -76,7 +76,7 @@ class BaseRepo * @throws ImageUploadException * @throws \Exception */ - public function updateCoverImage(HasCoverImage $entity, UploadedFile $coverImage = null, bool $removeImage = false) + public function updateCoverImage(HasCoverImage $entity, ?UploadedFile $coverImage, bool $removeImage = false) { if ($coverImage) { $this->imageRepo->destroyImage($entity->cover); diff --git a/app/Entities/Repos/BookRepo.php b/app/Entities/Repos/BookRepo.php index 7fcc80fac..70db0fa65 100644 --- a/app/Entities/Repos/BookRepo.php +++ b/app/Entities/Repos/BookRepo.php @@ -108,7 +108,7 @@ class BookRepo * @throws ImageUploadException * @throws Exception */ - public function updateCoverImage(Book $book, UploadedFile $coverImage = null, bool $removeImage = false) + public function updateCoverImage(Book $book, ?UploadedFile $coverImage, bool $removeImage = false) { $this->baseRepo->updateCoverImage($book, $coverImage, $removeImage); } diff --git a/app/Entities/Repos/BookshelfRepo.php b/app/Entities/Repos/BookshelfRepo.php index 03b54f009..25fa97dae 100644 --- a/app/Entities/Repos/BookshelfRepo.php +++ b/app/Entities/Repos/BookshelfRepo.php @@ -123,7 +123,7 @@ class BookshelfRepo * @throws ImageUploadException * @throws Exception */ - public function updateCoverImage(Bookshelf $shelf, UploadedFile $coverImage = null, bool $removeImage = false) + public function updateCoverImage(Bookshelf $shelf, ?UploadedFile $coverImage, bool $removeImage = false) { $this->baseRepo->updateCoverImage($shelf, $coverImage, $removeImage); } diff --git a/tests/Entity/BookShelfTest.php b/tests/Entity/BookShelfTest.php index b44761203..a318ebe24 100644 --- a/tests/Entity/BookShelfTest.php +++ b/tests/Entity/BookShelfTest.php @@ -100,7 +100,7 @@ class BookShelfTest extends TestCase $lastImage = Image::query()->orderByDesc('id')->firstOrFail(); $shelf = Bookshelf::query()->where('name', '=', $shelfInfo['name'])->first(); $this->assertDatabaseHas('bookshelves', [ - 'id' => $shelf, + 'id' => $shelf->id, 'image_id' => $lastImage->id, ]); $this->assertEquals($lastImage->id, $shelf->cover->id); From 6caedc7a37a5ca6cee39b69c3c651230a5e30b52 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 15 Feb 2020 19:09:33 +0000 Subject: [PATCH 188/191] Fixed issues preventing breadcrumb navigation menus from opening - Added tests to cover endpoint Fixes #1884 --- app/Entities/Book.php | 2 +- app/Http/Controllers/SearchController.php | 2 +- tests/Entity/EntitySearchTest.php | 84 +++++++++++++++++++++-- 3 files changed, 80 insertions(+), 8 deletions(-) diff --git a/app/Entities/Book.php b/app/Entities/Book.php index 919f60035..df0d99228 100644 --- a/app/Entities/Book.php +++ b/app/Entities/Book.php @@ -115,7 +115,7 @@ class Book extends Entity implements HasCoverImage { $pages = $this->directPages()->visible()->get(); $chapters = $this->chapters()->visible()->get(); - return $pages->contact($chapters)->sortBy('priority')->sortByDesc('draft'); + return $pages->concat($chapters)->sortBy('priority')->sortByDesc('draft'); } /** diff --git a/app/Http/Controllers/SearchController.php b/app/Http/Controllers/SearchController.php index a5cd7ad6b..a5d57741d 100644 --- a/app/Http/Controllers/SearchController.php +++ b/app/Http/Controllers/SearchController.php @@ -109,7 +109,7 @@ class SearchController extends Controller // Page in chapter if ($entity->isA('page') && $entity->chapter) { - $entities = $entity->chapter->visiblePages(); + $entities = $entity->chapter->getVisiblePages(); } // Page in book or chapter diff --git a/tests/Entity/EntitySearchTest.php b/tests/Entity/EntitySearchTest.php index 3eb50a412..34c3cd4a8 100644 --- a/tests/Entity/EntitySearchTest.php +++ b/tests/Entity/EntitySearchTest.php @@ -1,6 +1,7 @@ first(); + $book = Book::all()->first(); $page = $book->pages->first(); $search = $this->asEditor()->get('/search?term=' . urlencode($page->name)); @@ -54,7 +55,7 @@ class EntitySearchTest extends TestCase public function test_book_search() { - $book = \BookStack\Entities\Book::first(); + $book = Book::first(); $page = $book->pages->last(); $chapter = $book->chapters->last(); @@ -67,7 +68,7 @@ class EntitySearchTest extends TestCase public function test_chapter_search() { - $chapter = \BookStack\Entities\Chapter::has('pages')->first(); + $chapter = Chapter::has('pages')->first(); $page = $chapter->pages[0]; $pageTestResp = $this->asEditor()->get('/search/chapter/' . $chapter->id . '?term=' . urlencode($page->name)); @@ -77,11 +78,11 @@ class EntitySearchTest extends TestCase public function test_tag_search() { $newTags = [ - new \BookStack\Actions\Tag([ + new Tag([ 'name' => 'animal', 'value' => 'cat' ]), - new \BookStack\Actions\Tag([ + new Tag([ 'name' => 'color', 'value' => 'red' ]) @@ -204,4 +205,75 @@ class EntitySearchTest extends TestCase $chapterSearch->assertSee($chapter->name); $chapterSearch->assertSee($chapter->book->getShortName(42)); } + + public function test_sibling_search_for_pages() + { + $chapter = Chapter::query()->with('pages')->first(); + $this->assertGreaterThan(2, count($chapter->pages), 'Ensure we\'re testing with at least 1 sibling'); + $page = $chapter->pages->first(); + + $search = $this->actingAs($this->getViewer())->get("/search/entity/siblings?entity_id={$page->id}&entity_type=page"); + $search->assertSuccessful(); + foreach ($chapter->pages as $page) { + $search->assertSee($page->name); + } + + $search->assertDontSee($chapter->name); + } + + public function test_sibling_search_for_pages_without_chapter() + { + $page = Page::query()->where('chapter_id', '=', 0)->firstOrFail(); + $bookChildren = $page->book->getDirectChildren(); + $this->assertGreaterThan(2, count($bookChildren), 'Ensure we\'re testing with at least 1 sibling'); + + $search = $this->actingAs($this->getViewer())->get("/search/entity/siblings?entity_id={$page->id}&entity_type=page"); + $search->assertSuccessful(); + foreach ($bookChildren as $child) { + $search->assertSee($child->name); + } + + $search->assertDontSee($page->book->name); + } + + public function test_sibling_search_for_chapters() + { + $chapter = Chapter::query()->firstOrFail(); + $bookChildren = $chapter->book->getDirectChildren(); + $this->assertGreaterThan(2, count($bookChildren), 'Ensure we\'re testing with at least 1 sibling'); + + $search = $this->actingAs($this->getViewer())->get("/search/entity/siblings?entity_id={$chapter->id}&entity_type=chapter"); + $search->assertSuccessful(); + foreach ($bookChildren as $child) { + $search->assertSee($child->name); + } + + $search->assertDontSee($chapter->book->name); + } + + public function test_sibling_search_for_books() + { + $books = Book::query()->take(10)->get(); + $book = $books->first(); + $this->assertGreaterThan(2, count($books), 'Ensure we\'re testing with at least 1 sibling'); + + $search = $this->actingAs($this->getViewer())->get("/search/entity/siblings?entity_id={$book->id}&entity_type=book"); + $search->assertSuccessful(); + foreach ($books as $expectedBook) { + $search->assertSee($expectedBook->name); + } + } + + public function test_sibling_search_for_shelves() + { + $shelves = Bookshelf::query()->take(10)->get(); + $shelf = $shelves->first(); + $this->assertGreaterThan(2, count($shelves), 'Ensure we\'re testing with at least 1 sibling'); + + $search = $this->actingAs($this->getViewer())->get("/search/entity/siblings?entity_id={$shelf->id}&entity_type=bookshelf"); + $search->assertSuccessful(); + foreach ($shelves as $expectedShelf) { + $search->assertSee($expectedShelf->name); + } + } } From 29cc35a304e4ca19db6bad77087fdf1b8a3f8ac5 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 15 Feb 2020 20:31:23 +0000 Subject: [PATCH 189/191] Added dump_user_details option to LDAP and added binary attribute decode option Related to #1872 --- .env.example.complete | 1 + app/Auth/Access/LdapService.php | 30 ++++++++++++++++--- app/Config/services.php | 1 + tests/Auth/LdapTest.php | 52 ++++++++++++++++++++++++++++++++- 4 files changed, 79 insertions(+), 5 deletions(-) diff --git a/.env.example.complete b/.env.example.complete index 04cd73b90..86a7351c2 100644 --- a/.env.example.complete +++ b/.env.example.complete @@ -200,6 +200,7 @@ LDAP_ID_ATTRIBUTE=uid LDAP_EMAIL_ATTRIBUTE=mail LDAP_DISPLAY_NAME_ATTRIBUTE=cn LDAP_FOLLOW_REFERRALS=true +LDAP_DUMP_USER_DETAILS=false # LDAP group sync configuration # Refer to https://www.bookstackapp.com/docs/admin/ldap-auth/ diff --git a/app/Auth/Access/LdapService.php b/app/Auth/Access/LdapService.php index 0d6ebfc80..d37770558 100644 --- a/app/Auth/Access/LdapService.php +++ b/app/Auth/Access/LdapService.php @@ -1,6 +1,7 @@ getUserResponseProperty($user, 'cn', null); - return [ + $formatted = [ 'uid' => $this->getUserResponseProperty($user, $idAttr, $user['dn']), 'name' => $this->getUserResponseProperty($user, $displayNameAttr, $userCn), 'dn' => $user['dn'], 'email' => $this->getUserResponseProperty($user, $emailAttr, null), ]; + + if ($this->config['dump_user_details']) { + throw new JsonDebugException([ + 'details_from_ldap' => $user, + 'details_bookstack_parsed' => $formatted, + ]); + } + + return $formatted; } /** * Get a property from an LDAP user response fetch. * Handles properties potentially being part of an array. + * If the given key is prefixed with 'BIN;', that indicator will be stripped + * from the key and any fetched values will be converted from binary to hex. */ protected function getUserResponseProperty(array $userDetails, string $propertyKey, $defaultValue) { + $isBinary = strpos($propertyKey, 'BIN;') === 0; $propertyKey = strtolower($propertyKey); - if (isset($userDetails[$propertyKey])) { - return (is_array($userDetails[$propertyKey]) ? $userDetails[$propertyKey][0] : $userDetails[$propertyKey]); + $value = $defaultValue; + + if ($isBinary) { + $propertyKey = substr($propertyKey, strlen('BIN;')); } - return $defaultValue; + if (isset($userDetails[$propertyKey])) { + $value = (is_array($userDetails[$propertyKey]) ? $userDetails[$propertyKey][0] : $userDetails[$propertyKey]); + if ($isBinary) { + $value = bin2hex($value); + } + } + + return $value; } /** diff --git a/app/Config/services.php b/app/Config/services.php index a0bdd078a..fcde621d2 100644 --- a/app/Config/services.php +++ b/app/Config/services.php @@ -118,6 +118,7 @@ return [ 'ldap' => [ 'server' => env('LDAP_SERVER', false), + 'dump_user_details' => env('LDAP_DUMP_USER_DETAILS', false), 'dn' => env('LDAP_DN', false), 'pass' => env('LDAP_PASS', false), 'base_dn' => env('LDAP_BASE_DN', false), diff --git a/tests/Auth/LdapTest.php b/tests/Auth/LdapTest.php index 06f88c222..f6c5997b3 100644 --- a/tests/Auth/LdapTest.php +++ b/tests/Auth/LdapTest.php @@ -1,5 +1,6 @@ set([ + config()->set([ 'auth.method' => 'ldap', 'auth.defaults.guard' => 'ldap', 'services.ldap.base_dn' => 'dc=ldap,dc=local', @@ -560,4 +561,53 @@ class LdapTest extends BrowserKitTest $resp = $this->post('/register'); $this->assertPermissionError($resp); } + + public function test_dump_user_details_option_works() + { + config()->set(['services.ldap.dump_user_details' => true]); + + $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId); + $this->mockLdap->shouldReceive('setVersion')->once(); + $this->mockLdap->shouldReceive('setOption')->times(1); + $this->mockLdap->shouldReceive('searchAndGetEntries')->times(1) + ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) + ->andReturn(['count' => 1, 0 => [ + 'uid' => [$this->mockUser->name], + 'cn' => [$this->mockUser->name], + 'dn' => ['dc=test' . config('services.ldap.base_dn')] + ]]); + $this->mockLdap->shouldReceive('bind')->times(1)->andReturn(true); + $this->mockEscapes(1); + + $this->post('/login', [ + 'username' => $this->mockUser->name, + 'password' => $this->mockUser->password, + ]); + $this->seeJsonStructure([ + 'details_from_ldap' => [], + 'details_bookstack_parsed' => [], + ]); + } + + public function test_ldap_attributes_can_be_binary_decoded_if_marked() + { + config()->set(['services.ldap.id_attribute' => 'BIN;uid']); + $ldapService = app()->make(LdapService::class); + + $this->mockLdap->shouldReceive('connect')->once()->andReturn($this->resourceId); + $this->mockLdap->shouldReceive('setVersion')->once(); + $this->mockLdap->shouldReceive('setOption')->times(1); + $this->mockLdap->shouldReceive('searchAndGetEntries')->times(1) + ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) + ->andReturn(['count' => 1, 0 => [ + 'uid' => [hex2bin('FFF8F7')], + 'cn' => [$this->mockUser->name], + 'dn' => ['dc=test' . config('services.ldap.base_dn')] + ]]); + $this->mockLdap->shouldReceive('bind')->times(1)->andReturn(true); + $this->mockEscapes(1); + + $details = $ldapService->getUserDetails('test'); + $this->assertEquals('fff8f7', $details['uid']); + } } From 54a4c6e6787734557f71e8a21719a96e9b09fee4 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 15 Feb 2020 21:37:41 +0000 Subject: [PATCH 190/191] Fixed code-block drag+drop handling - Added custom handling, Tracks if contenteditable blocks are being dragged. On drop the selection location will be roughly checked to put the block above or below the cursor block root element. --- resources/js/components/wysiwyg-editor.js | 34 +++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/resources/js/components/wysiwyg-editor.js b/resources/js/components/wysiwyg-editor.js index b9e3340a8..7818db260 100644 --- a/resources/js/components/wysiwyg-editor.js +++ b/resources/js/components/wysiwyg-editor.js @@ -593,6 +593,7 @@ class WysiwygEditor { registerEditorShortcuts(editor); let wrap; + let draggedContentEditable; function hasTextContent(node) { return node && !!( node.textContent || node.innerText ); @@ -601,12 +602,19 @@ class WysiwygEditor { editor.on('dragstart', function () { let node = editor.selection.getNode(); - if (node.nodeName !== 'IMG') return; - wrap = editor.dom.getParent(node, '.mceTemp'); + if (node.nodeName === 'IMG') { + wrap = editor.dom.getParent(node, '.mceTemp'); - if (!wrap && node.parentNode.nodeName === 'A' && !hasTextContent(node.parentNode)) { - wrap = node.parentNode; + if (!wrap && node.parentNode.nodeName === 'A' && !hasTextContent(node.parentNode)) { + wrap = node.parentNode; + } } + + // Track dragged contenteditable blocks + if (node.hasAttribute('contenteditable') && node.getAttribute('contenteditable') === 'false') { + draggedContentEditable = node; + } + }); editor.on('drop', function (event) { @@ -614,7 +622,7 @@ class WysiwygEditor { rng = tinymce.dom.RangeUtils.getCaretRangeFromPoint(event.clientX, event.clientY, editor.getDoc()); // Template insertion - const templateId = event.dataTransfer.getData('bookstack/template'); + const templateId = event.dataTransfer && event.dataTransfer.getData('bookstack/template'); if (templateId) { event.preventDefault(); window.$http.get(`/templates/${templateId}`).then(resp => { @@ -638,6 +646,22 @@ class WysiwygEditor { }); } + // Handle contenteditable section drop + if (!event.isDefaultPrevented() && draggedContentEditable) { + event.preventDefault(); + editor.undoManager.transact(function () { + const selectedNode = editor.selection.getNode(); + const range = editor.selection.getRng(); + const selectedNodeRoot = selectedNode.closest('body > *'); + if (range.startOffset > (range.startContainer.length / 2)) { + editor.$(selectedNodeRoot).after(draggedContentEditable); + } else { + editor.$(selectedNodeRoot).before(draggedContentEditable); + } + }); + } + + // Handle image insert if (!event.isDefaultPrevented()) { editorPaste(event, editor, context); } From 01b95d91baede787fc84c3603e6516fab22bf34e Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sat, 15 Feb 2020 22:35:15 +0000 Subject: [PATCH 191/191] Fixed side-effect in binary LDAP handling - Was not stripping prefix when sending value to LDAP server in search. - Updated test to cover. --- app/Auth/Access/LdapService.php | 7 +++++++ tests/Auth/LdapTest.php | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/Auth/Access/LdapService.php b/app/Auth/Access/LdapService.php index d37770558..92234edcf 100644 --- a/app/Auth/Access/LdapService.php +++ b/app/Auth/Access/LdapService.php @@ -45,6 +45,13 @@ class LdapService extends ExternalAuthService $ldapConnection = $this->getConnection(); $this->bindSystemUser($ldapConnection); + // Clean attributes + foreach ($attributes as $index => $attribute) { + if (strpos($attribute, 'BIN;') === 0) { + $attributes[$index] = substr($attribute, strlen('BIN;')); + } + } + // Find user $userFilter = $this->buildFilter($this->config['user_filter'], ['user' => $userName]); $baseDn = $this->config['base_dn']; diff --git a/tests/Auth/LdapTest.php b/tests/Auth/LdapTest.php index f6c5997b3..324e3041f 100644 --- a/tests/Auth/LdapTest.php +++ b/tests/Auth/LdapTest.php @@ -598,7 +598,7 @@ class LdapTest extends BrowserKitTest $this->mockLdap->shouldReceive('setVersion')->once(); $this->mockLdap->shouldReceive('setOption')->times(1); $this->mockLdap->shouldReceive('searchAndGetEntries')->times(1) - ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), \Mockery::type('array')) + ->with($this->resourceId, config('services.ldap.base_dn'), \Mockery::type('string'), ['cn', 'dn', 'uid', 'mail', 'cn']) ->andReturn(['count' => 1, 0 => [ 'uid' => [hex2bin('FFF8F7')], 'cn' => [$this->mockUser->name],