Merge branch '4.3' into 4

This commit is contained in:
Aaron Carlino 2018-11-07 23:20:44 +13:00
commit 76936d863d
46 changed files with 1609 additions and 296 deletions

View File

@ -0,0 +1,13 @@
# 4.3.0-rc1
<!--- Changes below this line will be automatically regenerated -->
## Change Log
### Features and Enhancements
* 2018-07-25 [79a5ea3](https://github.com/silverstripe/recipe-cms/commit/79a5ea3dace336558ef4d5be4a86cc1a0e84badc) Add versioned-admin (Luke Edwards)
### Bugfixes
* 2018-06-15 [5e4ad34](https://github.com/silverstripe/silverstripe-installer/commit/5e4ad341622565cc998bd8537ad3ec7a6a6a7913) Fix incorrect base recipe dependency (Damian Mooyman)

View File

@ -150,7 +150,4 @@ ar:
LOGIN: دخول
LOSTPASSWORDHEADER: 'كلمة مرور مفقودة'
NOTEPAGESECURED: 'هذه الصفحة محمية بكلمة مرور ، أدخل بيانات دخولك بالأسفل ليتم السماح لك بالوصول للصفحة'
NOTERESETLINKINVALID: "<p> رابط إعادة تعيين كلمة المرور غير صحيح أو نفذت صلاحيته.</p>\n<p> \nيمكنك طلب رابط جديد <\"{a href=\"{link1\"> هنا </a>\n أو تغيير كلمة المرور الخاصة بك بعد <\"{a href=\"{link2\"> تسجيل دخولك</a>.\n</p>"
NOTERESETPASSWORD: 'أدخل بريدك الإلكتروني و سيتم إرسال رابط إعادة تهيئة كلمة المرور '
PASSWORDSENTHEADER: 'رابط استعادة كلمة المرور تم إرساله إلى ''{بريدك}'''
PASSWORDSENTTEXT: 'شكرا لك! تم إرسال رابط إعادة تعيين إلى ''{بريدك}''، بشرط وجود حساب قائم بالنسبة لعنوان هذا البريد الإلكتروني .'

View File

@ -313,7 +313,4 @@ bg:
LOGOUT: Изход
LOSTPASSWORDHEADER: 'Забравена парола'
NOTEPAGESECURED: 'Тази страница е защитена. Въведете вашите данни по-долу, за да продължите.'
NOTERESETLINKINVALID: '<p>Връзката за нулиране на парола не е вярна или е просрочена.</p><p>Можете да заявите нова <a href="{link1}">тук</a> или да промените паролата си след като <a href="{link2}">влезете</a>.</p>'
NOTERESETPASSWORD: 'Въведете вашият email адрес и ще ви изпратим линк, с който ще можете да смените паролата си'
PASSWORDSENTHEADER: 'Връзка за нулиране на парола беше изпратена на ''{email}'''
PASSWORDSENTTEXT: 'Благодарим ви! Връзка за нулиране на паролата беше изпратен на ''{email}'', ако съществува акаунт с този имейл адрес.'

View File

@ -194,7 +194,4 @@ cs:
LOGIN: Přihlásit
LOSTPASSWORDHEADER: 'Zapomenuté heslo'
NOTEPAGESECURED: 'Tato stránka je zabezpečená. Vložte své přihlašovací údaje a my Vám zároveň pošleme práva.'
NOTERESETLINKINVALID: '<p>Odkaz na resetování hesla není platný nebo je prošlý.</p><p>Můžete požádat o nový <a href="{link1}">zde</a> nebo změňte své heslo až <a href="{link2}">se přihlásíte</a>.</p>'
NOTERESETPASSWORD: 'Zadejte svou e-mailovou adresu a bude vám zaslán nulovací odkaz pro Vaše heslo'
PASSWORDSENTHEADER: 'Odkaz na resetování hesla byl odeslán na ''{email}'''
PASSWORDSENTTEXT: 'Děkujeme! Resetovací odkaz byl odeslán na ''{email}'', pokud účet existuje pro tuto emailovou adresu.'

View File

@ -1,5 +1,328 @@
da:
SilverStripe\Admin\LeftAndMain:
VersionUnknown: ukendt
SilverStripe\AssetAdmin\Forms\UploadField:
Dimensions: Dimensioner
EDIT: Rediger
EDITINFO: 'Rediger denne fil'
REMOVE: Fjern
SilverStripe\Control\ChangePasswordEmail_ss:
CHANGEPASSWORDFOREMAIL: 'Koden for kontoen med email addressen {email} er ændret. Hvis du ikke har skiftet din kode, så skift venligst din kode ved at klikke på linket herunder'
CHANGEPASSWORDTEXT1: 'Du skiftede dit kodeord for'
CHANGEPASSWORDTEXT3: 'Skift kodeord'
HELLO: Hej
SilverStripe\Control\Email\ForgotPasswordEmail_ss:
HELLO: Hej
TEXT1: 'Her er din'
TEXT2: 'link til at nulstille dit kodeord'
TEXT3: for
SilverStripe\Control\RequestProcessor:
INVALID_REQUEST: 'Ugyldig forespørgsel'
REQUEST_ABORTED: 'Forespørgsel annulleret'
SilverStripe\Core\Manifest\VersionProvider:
VERSIONUNKNOWN: Ukendt
SilverStripe\Forms\CheckboxField:
NOANSWER: Nej
YESANSWER: Ja
SilverStripe\Forms\CheckboxSetField_ss:
NOOPTIONSAVAILABLE: 'Ingen tilgængelige muligheder'
SilverStripe\Forms\ConfirmedPasswordField:
ATLEAST: 'Kodeord skal være mindst {min} tegn lang.'
BETWEEN: 'Kodeord skal være {min} til {max} karakterer lang.'
CURRENT_PASSWORD_ERROR: 'Det nuværende kodeord du har indtastet er ikke korrekt.'
CURRENT_PASSWORD_MISSING: 'Du skal indtaste dit nuværende kodeord.'
LOGGED_IN_ERROR: 'Du skal være logget ind for at skifte dit kodeord.'
MAXIMUM: 'Kodeord må maks være {max} tegn lang'
SHOWONCLICKTITLE: 'Skift kodeord'
SilverStripe\Forms\CurrencyField:
CURRENCYSYMBOL: DKK
SilverStripe\Forms\DateField:
VALIDDATEFORMAT2: 'Indtats venligst et gyldigt datoformat ({format})'
VALIDDATEMAXDATE: 'Din dato skal være ældre end eller matche den maksimalt tilladte dato ({date})'
VALIDDATEMINDATE: 'Din dato skal være yngre end eller matche den minimum tilladte dato ({date})'
SilverStripe\Forms\DatetimeField:
VALIDDATEMAXDATETIME: 'Din dato skal være ældre end eller matche den maksimalt tilladte dato ({datetime})'
VALIDDATETIMEFORMAT: 'Indtats venligst et gyldigt dato- og tidsformat ({format})'
VALIDDATETIMEMINDATE: 'Din dato skal være yngre end eller matche den minimum tilladte dato og tid ({datetime})'
SilverStripe\Forms\DropdownField:
CHOOSE: (Vælg)
CHOOSE_MODEL: '(Vælg {name})'
SOURCE_VALIDATION: 'Venligst vælg en eksisterende værdi fra listen. {value} er ikke en tilladt mulighed'
SilverStripe\Forms\EmailField:
VALIDATION: 'Indtast venligst en emailadresse'
SilverStripe\Forms\FileUploadReceiver:
FIELDNOTSET: 'Fil information ikke fundet'
SilverStripe\Forms\Form:
BAD_METHOD: 'Denne form kræver en {method} indsendelse'
CSRF_EXPIRED_MESSAGE: 'Din session er udløbet. Venligst gensend formularen.'
CSRF_FAILED_MESSAGE: 'Det ser ud til der har været et teknisk problem. Klik venligst på tilbageknappen, tryk opdater i din browser og prøv igen.'
VALIDATIONPASSWORDSDONTMATCH: 'Kodeordene er ikke identiske'
VALIDATIONPASSWORDSNOTEMPTY: 'Kodeord kan ikke være tomme'
VALIDATIONSTRONGPASSWORD: 'Kodeord skal mindst have et tal og et alfanumerisk tegn'
VALIDATOR: Validering
VALIDCURRENCY: 'Indtast venligst en gyldig valuta'
SilverStripe\Forms\FormField:
EXAMPLE: 'f.eks. {format}'
NONE: ingen
SilverStripe\Forms\FormScaffolder:
TABMAIN: Primær
SilverStripe\Forms\GridField\GridField:
Filter: Filter
Add: 'Tilføj {name}'
CSVEXPORT: 'Eksporter til CSV'
CSVIMPORT: 'Importer CSV'
Filter: Filtrer
FilterBy: 'Filtrer på'
Find: Find
LinkExisting: 'Link eksisterende'
NewRecord: 'Ny {type}'
NoItemsFound: 'Ingen elementer fundet'
PRINTEDAT: 'Printet d.'
PRINTEDBY: 'Printet af'
PlaceHolder: 'Find {type}'
PlaceHolderWithLabels: 'Find {type} på {name}'
Print: Print
RelationSearch: Relationssøgning
ResetFilter: Nulstil
SilverStripe\Forms\GridField\GridFieldDeleteAction:
Delete: Slet
DeletePermissionsFailure: 'Ingen slette rettigheder'
EditPermissionsFailure: 'Ingen rettighed til at fjerne emnet'
UnlinkRelation: Fjern
SilverStripe\Forms\GridField\GridFieldDetailForm:
CancelBtn: Annuller
Create: Opret
Delete: Slet
DeletePermissionsFailure: 'Ingen slette rettigheder'
Deleted: 'Slet {type} {name}'
Save: Gem
SilverStripe\Forms\GridField\GridFieldEditButton:
EDIT: Rediger
SilverStripe\Forms\GridField\GridFieldGroupDeleteAction:
UnlinkSelfFailure: 'Kan ikke fjerne dig selv fra denne gruppe, du vil miste administrator rettigheder'
SilverStripe\Forms\GridField\GridFieldPaginator:
OF: af
Page: Side
View: Vis
SilverStripe\Forms\MoneyField:
FIELDLABELAMOUNT: Beløb
FIELDLABELCURRENCY: Valuta
INVALID_CURRENCY: 'Valuta {currency} er ikke i listen over tilladte valutaer'
SilverStripe\Forms\MultiSelectField:
SOURCE_VALIDATION: 'Vælg venligst eksisterende værdier fra listen. Ugyldig mulighed(er) {value} valgt'
SilverStripe\Forms\NullableField:
IsNullLabel: 'Er Null'
SilverStripe\Forms\NumericField:
VALIDATION: '''{value}'' er ikke et tal, kun tal accepteres i dette felt'
SilverStripe\Forms\TimeField:
VALIDATEFORMAT: 'Indtats venligst et gyldigt tidsformat ({format})'
SilverStripe\ORM\DataObject:
PLURALNAME: Dataobjekter
PLURALS:
one: 'Et dataobjekt'
other: '{count} dataobjekter'
SINGULARNAME: Dataobjekt
SilverStripe\ORM\FieldType\DBBoolean:
ANY: Enhver
NOANSWER: Nej
YESANSWER: Ja
SilverStripe\ORM\FieldType\DBDate:
DAYS_SHORT_PLURALS:
one: '{count} dag'
other: '{count} dage'
HOURS_SHORT_PLURALS:
one: '{count} time'
other: '{count} timer'
LessThanMinuteAgo: 'mindre end et minut'
MINUTES_SHORT_PLURALS:
one: '{count} minut'
other: '{count} minutter'
MONTHS_SHORT_PLURALS:
one: '{count} måned'
other: '{count} måneder'
SECONDS_SHORT_PLURALS:
one: '{count} sekund'
other: '{count} sekunder'
TIMEDIFFAGO: '{difference} siden'
TIMEDIFFIN: 'i {difference}'
YEARS_SHORT_PLURALS:
one: '{count} år'
other: '{count} år'
SilverStripe\ORM\FieldType\DBEnum:
ANY: Enhver
SilverStripe\ORM\FieldType\DBForeignKey:
DROPDOWN_THRESHOLD_FALLBACK_MESSAGE: 'For mange relaterede objekter; fallback felt i brug'
SilverStripe\ORM\Hierarchy:
LIMITED_TITLE: 'For mange underelementer ({count})'
SilverStripe\ORM\Hierarchy\Hierarchy:
InfiniteLoopNotAllowed: 'Uendeligt løkke fundet i "{type}" hierarkiet. Ændre venligst det overliggende element for at løse dette'
LIMITED_TITLE: 'For mange underelementer ({count})'
SilverStripe\ORM\ValidationException:
DEFAULT_ERROR: Valideringsfejl
SilverStripe\Security\BasicAuth:
ENTERINFO: 'Indtast venligst et brugernavn og kodeord.'
ERRORNOTADMIN: 'Den bruger er ikke en administrator.'
ERRORNOTREC: 'Brugernavn / kodeord kunne ikke genkendes'
SilverStripe\Security\CMSMemberLoginForm:
PASSWORDEXPIRED: '<p>Dit kodeord er udløbet. <a target="_top" href="{link}">Vælg venligst et nyt.</a></p>'
SilverStripe\Security\CMSSecurity:
INVALIDUSER: '<p>Ugyldig bruger. <a target="_top" href="{link}">Log venligst ind igen her</a> for at fortsætte.</p>'
LOGIN_MESSAGE: '<p>Din session er løbet ud pga. inaktivitet</p>'
LOGIN_TITLE: 'Log ind igen, for at fortsætte hvor du slap.'
SUCCESS: Succes
SUCCESSCONTENT: '<p>Logget ind. Hvis du ikke automatisk viderestilles så <a target="_top" href="{link}">klik her</a></p>'
SUCCESS_TITLE: 'Logget ind med sucess'
SilverStripe\Security\DefaultAdminService:
DefaultAdminFirstname: 'Standard admin'
SilverStripe\Security\Group:
AddRole: 'Tilføj en rolle for denne gruppe'
Code: 'Gruppe kode'
DefaultGroupTitleAdministrators: Administratorer
DefaultGroupTitleContentAuthors: Indholdsforfattere
Description: Beskrivelse
GROUPNAME: Gruppenavn
GroupReminder: 'Hvis du vælger en overliggende gruppe, får denne gruppe alle dens roller'
HierarchyPermsError: 'Kan ikke tildele overliggende gruppe "{group}" med fortrinsrettigheder (kræver ADMIN adgang)'
Locked: 'Låst?'
MEMBERS: Brugere
NEWGROUP: 'Ny gruppe'
NoRoles: 'Ingen roller fundet'
PERMISSIONS: Rettigheder
PLURALNAME: Grupper
PLURALS:
one: 'En gruppe'
other: '{count} grupper'
Parent: 'Overliggende gruppe'
ROLES: Roller
ROLESDESCRIPTION: 'Roller er et prædefineret sæt af rettigheder, som kan tildeles grupper.<br />De bliver nedarvet fra en overliggende grupper hvis krævet.'
RolesAddEditLink: 'Administrer roller'
SINGULARNAME: Gruppe
Sort: Sortering
has_many_Permissions: Rettigheder
many_many_Members: Brugere
SilverStripe\Security\LoginAttempt:
Email: 'Email adresse'
EmailHashed: 'Email adresse (hashed)'
IP: 'IP addresse'
PLURALNAME: Loginforsøg
PLURALS:
one: 'Et loginforsøg'
other: '{count} loginforsøg'
SINGULARNAME: 'Login forsøg'
Status: Status
SilverStripe\Security\Member:
ADDGROUP: 'Tilføj gruppe'
BUTTONCHANGEPASSWORD: 'Skift kodeord'
BUTTONLOGIN: 'Log ind'
BUTTONLOGINOTHER: 'Log ind med en anden bruger'
BUTTONLOGOUT: 'Log ud'
BUTTONLOSTPASSWORD: 'Jeg har glemt mit kodeord'
CONFIRMNEWPASSWORD: 'Bekræft nyt kodeord'
CONFIRMPASSWORD: 'Bekræft kodeord'
CURRENT_PASSWORD: 'Nuværende kodeord'
EDIT_PASSWORD: 'Nyt kodeord'
EMAIL: Email
EMPTYNEWPASSWORD: 'Det nye kodeord kan ikke være tom, prøv venligst igen'
ENTEREMAIL: 'Indtast venligst en email adresse for at få et nulstillingslink.'
ERRORLOCKEDOUT2: 'Din konto er blevet midlertidigt deaktiveret pga. for mange fejlslagne loginforsøg. Forsøg venligst igen om {count} minutter.'
ERRORNEWPASSWORD: 'Du har indtastet dit nye kodeord forskelligt, forsøg igen'
ERRORPASSWORDNOTMATCH: 'Dit nuværende kodeord matcher ikke, forsøg venligst igen'
ERRORWRONGCRED: 'De indtastede værdier ser ikke ud til at være korrekte. Forsøg venligst igen.'
FIRSTNAME: Fornavn
INTERFACELANG: 'Sprog i brugerfladen'
KEEPMESIGNEDIN: 'Hold mig logget ind'
LOGGEDINAS: 'Du er logget ind som {name}.'
NEWPASSWORD: 'Nyt kodeord'
PASSWORD: Kodeord
PASSWORDEXPIRED: 'Dit kodeord er udløbet. Vælg venligst et nyt.'
PLURALNAME: Brugere
PLURALS:
one: 'En bruger'
other: '{count} brugere'
REMEMBERME: 'Husk mig til næste gang? (i {count} dage på denne enhed)'
SINGULARNAME: Bruger
SUBJECTPASSWORDCHANGED: 'Dit kodeord er blevet ændret'
SUBJECTPASSWORDRESET: 'Link til at nulstille dit kodeord'
SURNAME: Efternavn
VALIDATIONADMINLOSTACCESS: 'Kan ikke fjerne alle admin grupper fra din profil'
ValidationIdentifierFailed: 'Kan ikke overskrive eksisterende bruger #{id} med identisk identifikator ({name} = {value}))'
WELCOMEBACK: 'Velkommen tilbage, {firstname}'
YOUROLDPASSWORD: 'Dit gamle kodeord'
belongs_many_many_Groups: Grupper
db_Locale: 'Sprog i brugerfladen'
db_LockedOutUntil: 'Låst ude indtil'
db_Password: Kodeord
db_PasswordExpiry: Kodeordsudløbsdato
SilverStripe\Security\MemberAuthenticator\CMSMemberLoginForm:
AUTHENTICATORNAME: 'CMS bruger loginform'
BUTTONFORGOTPASSWORD: 'Glemt kodeord'
BUTTONLOGIN: 'Log mig ind igen'
BUTTONLOGOUT: 'Log ud'
SilverStripe\Security\MemberAuthenticator\MemberAuthenticator:
ERRORWRONGCRED: 'De indtastede værdier ser ikke ud til at være korrekte. Forsøg venligst igen.'
NoPassword: 'Der er ikke en kode på denne bruger.'
SilverStripe\Security\MemberAuthenticator\MemberLoginForm:
AUTHENTICATORNAME: 'Email og kodeord'
SilverStripe\Security\MemberPassword:
PLURALNAME: 'Bruger kodeord'
PLURALS:
one: 'Et bruger kodeord'
other: '{count} bruger kodeord'
SINGULARNAME: 'Bruger kodeord'
SilverStripe\Security\PasswordValidator:
LOWCHARSTRENGTH: 'Forøg venligst kodeordets styrke, ved at tilføje nogle af følgende tegn: {chars}'
PREVPASSWORD: 'Du har tidligere brugt dette kodeord, vælg venligst et nyt kodeord'
TOOSHORT: 'Kodeordet er for kort, det skal mindst være {minimum} eller flere tegn langt'
SilverStripe\Security\Permission:
AdminGroup: Administrator
CMS_ACCESS_CATEGORY: 'CMS Adgang'
CONTENT_CATEGORY: Indholdsrettigheder
FULLADMINRIGHTS: 'Fuld administrator rettighed'
FULLADMINRIGHTS_HELP: 'Indebærer og overskriver alle andre tildelte rettigheder.'
PERMISSIONS_CATEGORY: 'Roller og adgangsrettigheder'
PLURALNAME: Rettigheder
PLURALS:
one: 'En rettighed'
other: '{count} rettigheder'
SINGULARNAME: Rettighed
UserPermissionsIntro: 'Tildeling af grupper til denne bruger, ændrer de rettigheder brugeren har. Se gruppe området for rettigheds detaljer på de individuelle grupper.'
SilverStripe\Security\PermissionCheckboxSetField:
AssignedTo: 'tildelt til "{title}"'
FromGroup: 'nedarvet fra gruppen "{title}"'
FromRole: 'nedarvet fra rollen "{title}"'
FromRoleOnGroup: 'nedarvet fra rollen "{roletitle}" på gruppen "{grouptitle}"'
SilverStripe\Security\PermissionRole:
OnlyAdminCanApply: 'Kun administratorer kan tilføje'
PLURALNAME: Roller
PLURALS:
one: 'En rolle'
other: '{count} roller'
SINGULARNAME: Rolle
Title: Titel
SilverStripe\Security\PermissionRoleCode:
PLURALNAME: 'Rettigheds rolle koder'
PLURALS:
one: 'En rettigheds rolle kode'
other: '{count} rettigheds rolle koder'
PermsError: 'Kan ikke tildele koden "{code}" med fortrinsrettigheder (kræver ADMIN adgang)'
SINGULARNAME: 'Rettighed rolle kode'
SilverStripe\Security\RememberLoginHash:
PLURALNAME: 'Login hashes'
PLURALS:
one: 'Et login hash'
other: '{count} Login Hashes'
SINGULARNAME: 'Login hash'
SilverStripe\Security\Security:
ALREADYLOGGEDIN: 'Du har ikke adgang til denne side. Hvis du har en anden bruger der har adgang til denne side, kan du logge ind med denne herunder.'
BUTTONSEND: 'Send mig linket til at nulstille kodeordet'
CHANGEPASSWORDBELOW: 'Du kan ændre dit kodeord herunder.'
CHANGEPASSWORDHEADER: 'Skift dit kodeord'
CONFIRMLOGOUT: 'Klik venligst på knappen herunder, for at bekræfte at du vil logge ud.'
ENTERNEWPASSWORD: 'Indtast venligst et nyt kodeord.'
ERRORPASSWORDPERMISSION: 'Du skal være logget ind, for at kunne ændre dit kodeord!'
LOGIN: 'Log ind'
LOGOUT: 'Log ud'
LOSTPASSWORDHEADER: 'Glemt kodeord'
NOTEPAGESECURED: 'Denne side er beskyttet. Indtast dine loginoplysninger herunder for at få adgang.'
NOTERESETPASSWORD: 'Indtast din email adresse, så sender vi dig et link som du kan nulstille dit kodeord med'
PASSWORDRESETSENTHEADER: 'link til at nulstille kodeord afsendt'
PASSWORDRESETSENTTEXT: 'Tak for det. Et link til at nulstille dit kodeord er afsendt, hvis der findes en bruger med denne email adresse.'

View File

@ -190,7 +190,4 @@ de:
LOGIN: Anmelden
LOSTPASSWORDHEADER: 'Passwort vergessen'
NOTEPAGESECURED: 'Diese Seite ist geschützt. Bitte melden Sie sich an und Sie werden sofort weitergeleitet.'
NOTERESETLINKINVALID: '<p>Der Link zum Zurücksetzen des Passworts ist entweder nicht korrekt oder abgelaufen</p><p>Sie können <a href="{link1}">einen neuen Link anfordern</a> oder Ihr Passwort nach dem <a href="{link2}">einloggen</a> ändern.</p>'
NOTERESETPASSWORD: 'Geben Sie Ihre E-Mail-Adresse ein und wir werden Ihnen einen Link zuschicken, mit dem Sie Ihr Passwort zurücksetzen können.'
PASSWORDSENTHEADER: 'Der Link zum Zurücksetzen des Passworts wurde an ''{email}'' gesendet'
PASSWORDSENTTEXT: 'Vielen Dank! Wenn ein Account zu der E-Mail Adresse ''{email}'' existiert, wurde eine E-Mail mit dem Link zum Zurücksetzen des Passworts verschickt.'

View File

@ -78,6 +78,7 @@ en:
LinkExisting: 'Link Existing'
NewRecord: 'New {type}'
NoItemsFound: 'No items found'
OpenFilter: 'Open search and filter'
PRINTEDAT: 'Printed at'
PRINTEDBY: 'Printed by'
PlaceHolder: 'Find {type}'
@ -85,10 +86,6 @@ en:
Print: Print
RelationSearch: 'Relation search'
ResetFilter: Reset
OpenFilter: 'Open search and filter'
SilverStripe\Forms\GridField\GridFieldFilterHeader:
Search: 'Search "{name}"'
SearchFormFaliure: 'No search form could be generated'
SilverStripe\Forms\GridField\GridFieldDeleteAction:
Delete: Delete
DeletePermissionsFailure: 'No delete permissions'
@ -103,6 +100,9 @@ en:
Save: Save
SilverStripe\Forms\GridField\GridFieldEditButton:
EDIT: Edit
SilverStripe\Forms\GridField\GridFieldFilterHeader:
Search: 'Search "{name}"'
SearchFormFaliure: 'No search form could be generated'
SilverStripe\Forms\GridField\GridFieldGroupDeleteAction:
UnlinkSelfFailure: 'Cannot remove yourself from this group, you will lose admin rights'
SilverStripe\Forms\GridField\GridFieldPaginator:

View File

@ -95,6 +95,8 @@ eo:
DeletePermissionsFailure: 'Mankas permeso forigi'
Deleted: 'Forigita {type} {name}'
Save: Konservi
SilverStripe\Forms\GridField\GridFieldEditButton:
EDIT: Redakti
SilverStripe\Forms\GridField\GridFieldGroupDeleteAction:
UnlinkSelfFailure: 'Ne povas forigi vin el ĉi tiu grupo; vi perdus administrajn rajtojn'
SilverStripe\Forms\GridField\GridFieldPaginator:
@ -147,6 +149,8 @@ eo:
other: '{count} jaroj'
SilverStripe\ORM\FieldType\DBEnum:
ANY: Ajna
SilverStripe\ORM\FieldType\DBForeignKey:
DROPDOWN_THRESHOLD_FALLBACK_MESSAGE: 'Tro multaj objektoj; retropaŝa kampo uzata'
SilverStripe\ORM\Hierarchy:
LIMITED_TITLE: 'Tro da idoj ({count})'
SilverStripe\ORM\Hierarchy\Hierarchy:
@ -319,7 +323,6 @@ eo:
LOGOUT: Elsaluti
LOSTPASSWORDHEADER: 'Perdis pasvorton'
NOTEPAGESECURED: 'Tiu paĝo estas sekurigita. Enigu viajn akreditaĵojn sube kaj vi aliros pluen.'
NOTERESETLINKINVALID: '<p>La pasvorta reagorda ligilo estas malvalida aŭ finiĝis.</p><p>Vi povas peti novan <a href="{link1}">ĉi tie</a> aŭ ŝanĝi vian pasvorton post <a href="{link2}">vi ensalutis</a>.</p>'
NOTERESETPASSWORD: 'Enigu vian retpoŝtan adreson kaj ni sendos al vi ligilon per kiu vi povas reagordi vian pasvorton'
PASSWORDSENTHEADER: 'Pasvorta reagorda ligilo sendiĝis al ''{email}'''
PASSWORDSENTTEXT: 'Dankon! Reagordita ligilo sendiĝis al ''{email}'', kondiĉe ke konto ekzistas por tiu retadreso.'
PASSWORDRESETSENTHEADER: 'Pasvorta reagorda ligilo sendiĝis'
PASSWORDRESETSENTTEXT: 'Dankon. Reagorda ligilo sendiĝis, kondiĉe ke konto ekzistas por ĉi tiu retadreso.'

View File

@ -249,7 +249,4 @@ es:
LOGIN: Entrar
LOSTPASSWORDHEADER: '¿Contraseña Perdida?'
NOTEPAGESECURED: 'Esa página está protegida. Introduzca sus datos de acreditación a continuación y lo enviaremos a ella en un momento.'
NOTERESETLINKINVALID: '<p>El enlace para restablecer la contraseña es inválido o ha expirado.</p><p>Usted puede solicitar uno nuevo <a href="{link1}">aqui</a> o cambiar su contraseña después de que se haya <a href="{link2}">conectado</a>.</p>'
NOTERESETPASSWORD: 'Introduzca su dirección de e-mail, y le enviaremos un enlace, con el cual podrá restaurar su contraseña'
PASSWORDSENTHEADER: 'Un enlace para restablecer la contraseña ha sido enviado a ''{email}'''
PASSWORDSENTTEXT: 'Gracias! Un enlace para restablecer la contraseña ha sido enviado a ''{email}'', siempre que una cuenta exista para la dirección de email indicada.'

View File

@ -139,7 +139,4 @@ et_EE:
ERRORPASSWORDPERMISSION: 'Pead olema sisseloginud, et parooli muuta!'
LOGIN: 'Logi sisse'
NOTEPAGESECURED: 'See leht on turvatud. Sisesta enda andmed allpool ja me saadame sind otse edasi'
NOTERESETLINKINVALID: '<p>Parooli lähtestamise link on kehtetu või aegunud.</p><p>Saate taotleda uut linki <a href="{link1}">siin</a> või muuta parooli pärast <a href="{link2}">sisselogimist</a>.</p>'
NOTERESETPASSWORD: 'Sisesta oma email ja me saadame sulle lingi kus saad oma parooli tühistada.'
PASSWORDSENTHEADER: 'Parooli lähtestamise link saadeti aadressile ''{email}'''
PASSWORDSENTTEXT: 'Aitäh! Lähtestamislink saadeti aadressile ''{email}'' eeldusel, et selle e-posti aadressiga seotud konto on olemas.'

View File

@ -168,4 +168,3 @@ fa_IR:
ERRORPASSWORDPERMISSION: 'جهت تغییر گذرواژه خود باید وارد شده باشید!'
LOGIN: ورود
LOSTPASSWORDHEADER: 'فراموشی گذرواژه'
PASSWORDSENTHEADER: 'لینک ازنوسازی گذرواژه به ''{email}'' ارسال شد'

View File

@ -76,6 +76,7 @@ fi:
LinkExisting: 'Linkitä olemassaoleva'
NewRecord: 'Uusi {type}'
NoItemsFound: 'Ei kohteita'
OpenFilter: 'Avaa haku ja suodatus'
PRINTEDAT: Tulostettu
PRINTEDBY: Tulostaja
PlaceHolder: 'Etsi {type}'
@ -95,12 +96,19 @@ fi:
DeletePermissionsFailure: 'Ei oikeuksia poistamiseen'
Deleted: 'Poistettiin {type} {name}'
Save: Tallenna
SilverStripe\Forms\GridField\GridFieldEditButton:
EDIT: Muokkaa
SilverStripe\Forms\GridField\GridFieldFilterHeader:
Search: 'Haku "{name}"'
SearchFormFaliure: 'Hakulomaketta ei pystytty luomaan.'
SilverStripe\Forms\GridField\GridFieldGroupDeleteAction:
UnlinkSelfFailure: 'Et voi siirtää itseäsi pois tästä ryhmästä: menettäisit pääkäyttäjän oikeudet'
SilverStripe\Forms\GridField\GridFieldPaginator:
OF: /
Page: Sivu
View: Näytä
SilverStripe\Forms\GridField\GridFieldViewButton:
VIEW: Avaa
SilverStripe\Forms\MoneyField:
FIELDLABELAMOUNT: Määrä
FIELDLABELCURRENCY: Valuutta
@ -147,6 +155,8 @@ fi:
other: '{count} vuotta'
SilverStripe\ORM\FieldType\DBEnum:
ANY: Yhtään
SilverStripe\ORM\FieldType\DBForeignKey:
DROPDOWN_THRESHOLD_FALLBACK_MESSAGE: 'Liian monta samaan liittyvää objektia: oletuskenttä käytössä'
SilverStripe\ORM\Hierarchy:
LIMITED_TITLE: 'Liian monta lapsiobjektia ({count}}'
SilverStripe\ORM\Hierarchy\Hierarchy:
@ -197,6 +207,7 @@ fi:
many_many_Members: Jäsenet
SilverStripe\Security\LoginAttempt:
Email: Sähköpostiosoite
EmailHashed: 'Sähköpostiosoite (tiivistetty)'
IP: IP-osoite
PLURALNAME: Kirjautumisyritykset
PLURALS:
@ -255,6 +266,8 @@ fi:
SilverStripe\Security\MemberAuthenticator\MemberAuthenticator:
ERRORWRONGCRED: 'Antamasi tiedot eivät näytä oikeilta. Yritä uudelleen.'
NoPassword: 'Tällä käyttäjällä ei ole salasanaa'
SilverStripe\Security\MemberAuthenticator\MemberLoginForm:
AUTHENTICATORNAME: 'Sähköpostiosoite & salasana'
SilverStripe\Security\MemberPassword:
PLURALNAME: 'Käyttäjän salasanat'
PLURALS:
@ -318,5 +331,5 @@ fi:
NOTEPAGESECURED: 'Tämä sivu on suojattu. Syötä tunnistetietosi alle niin pääset eteenpäin.'
NOTERESETLINKINVALID: '<p>Salasanan palautuslinkki on virheellinen tai vanhentunut.</p><p>Voit pyytää uuden <a href="{link1}">napsauttamalla tästä</a> tai vaihtaa salasanasi <a href="{link2}">kirjautumisen jälkeen</a>.</p>'
NOTERESETPASSWORD: 'Syötä sähköpostiosoitteesi ja lähetämme sinulle linkin, jonka avulla saat palautettua salasanasi'
PASSWORDSENTHEADER: 'Salasanan palautuslinkki lähetettiin osoitteeseen ''{email}'''
PASSWORDSENTTEXT: 'Kiitos! Salasanan palautuslinkki lähetettiin osoitteeseen ''{email}'', joka on liitettynä tähän käyttäjätiliin.'
PASSWORDRESETSENTHEADER: 'Salasanan palautuslinkki lähetetty'
PASSWORDRESETSENTTEXT: 'Kiitos, palautuslinkki on lähetetty käyttäjätilille asetettuun sähköpostiosoitteeseen.'

View File

@ -84,7 +84,6 @@ fr:
RelationSearch: 'Rechercher relations'
ResetFilter: Réinitialiser
SilverStripe\Forms\GridField\GridFieldDeleteAction:
DELETE_DESCRIPTION: Supprimer
Delete: Supprimer
DeletePermissionsFailure: 'Vous navez pas les autorisations pour supprimer'
EditPermissionsFailure: 'Pas de permissions pour délier l''enregistrement'
@ -96,8 +95,6 @@ fr:
DeletePermissionsFailure: 'Vous navez pas les autorisations pour supprimer'
Deleted: '{type} {name} supprimés'
Save: Enregistrer
SilverStripe\Forms\GridField\GridFieldEditButton_ss:
EDIT: Éditer
SilverStripe\Forms\GridField\GridFieldGroupDeleteAction:
UnlinkSelfFailure: 'Impossible de retirer votre propre profil de ce groupe, vous perdriez vos droits d''administration'
SilverStripe\Forms\GridField\GridFieldPaginator:
@ -322,7 +319,4 @@ fr:
LOGOUT: 'Se déconnecter'
LOSTPASSWORDHEADER: 'Mot de passe oublié'
NOTEPAGESECURED: 'Cette page est sécurisée. Entrez vos identifiants ci-dessous et vous pourrez y avoir accès.'
NOTERESETLINKINVALID: '<p>Le lien de réinitialisation du mot de passe nest pas valide ou a expiré.</p><p>Vous pouvez en demander un nouveau <a href="{link1}">en suivant ce lien</a> ou changer de mot de passe après <a href="{link2}">connexion</a>.</p>'
NOTERESETPASSWORD: 'Entrez votre adresse email et nous vous enverrons un lien pour modifier votre mot de passe'
PASSWORDSENTHEADER: "Lien de réinitialisation de mot de passe envoyé à «\_{email}\_»"
PASSWORDSENTTEXT: "Merci\_! Un lien de réinitialisation vient dêtre envoyé à «\_{email}\_», à condition que cette adresse existe."

View File

@ -167,7 +167,4 @@ id:
LOGIN: Masuk
LOSTPASSWORDHEADER: 'Kata Kunci yang Terlupa'
NOTEPAGESECURED: 'Laman ini diamankan. Isikan data berikut untuk dikirimkan hak akses Anda.'
NOTERESETLINKINVALID: '<p>Tautan penggantian kata kunci tidak valid atau sudah kadaluarsa.</p><p>Anda dapat meminta yang baru <a href="{link1}">di sini</a> atau mengganti kata kunci setelah Anda <a href="{link2}">masuk</a>.</p>'
NOTERESETPASSWORD: 'Isikan alamat email Anda untuk mendapatkan tautan penggantian kata kunci'
PASSWORDSENTHEADER: 'Tautan penggantian kata kunci dikirimkan ke ''{email}'''
PASSWORDSENTTEXT: 'Terimakasih! Tautan reset telah dikirim ke ''{email}'', berisi informasi akun untuk alamat email ini.'

View File

@ -166,7 +166,4 @@ id_ID:
LOGIN: Masuk
LOSTPASSWORDHEADER: 'Kata Kunci yang Terlupa'
NOTEPAGESECURED: 'Laman ini diamankan. Isikan data berikut untuk dikirimkan hak akses Anda.'
NOTERESETLINKINVALID: '<p>Tautan penggantian kata kunci tidak valid atau sudah kadaluarsa.</p><p>Anda dapat meminta yang baru <a href="{link1}">di sini</a> atau mengganti kata kunci setelah Anda <a href="{link2}">masuk</a>.</p>'
NOTERESETPASSWORD: 'Isikan alamat email Anda untuk mendapatkan tautan penggantian kata kunci'
PASSWORDSENTHEADER: 'Tautan penggantian kata kunci dikirimkan ke ''{email}'''
PASSWORDSENTTEXT: 'Terimakasih! Tautan reset telah dikirim ke ''{email}'', berisi informasi akun untuk alamat email ini.'

View File

@ -95,6 +95,10 @@ it:
DeletePermissionsFailure: 'Non hai i permessi per eliminare'
Deleted: 'Eliminato {type} {name}'
Save: Salva
SilverStripe\Forms\GridField\GridFieldEditButton:
EDIT: Modifica
SilverStripe\Forms\GridField\GridFieldGroupDeleteAction:
UnlinkSelfFailure: 'Non è possibile rimuovere te stesso da questo gruppo, perderesti i diritti di admin'
SilverStripe\Forms\GridField\GridFieldPaginator:
OF: di
Page: Pagina
@ -145,6 +149,8 @@ it:
other: '{count} anni'
SilverStripe\ORM\FieldType\DBEnum:
ANY: Qualsiasi
SilverStripe\ORM\FieldType\DBForeignKey:
DROPDOWN_THRESHOLD_FALLBACK_MESSAGE: 'Troppi oggetti correlati; campo di fallback in uso'
SilverStripe\ORM\Hierarchy:
LIMITED_TITLE: 'Troppi figli ({count})'
SilverStripe\ORM\Hierarchy\Hierarchy:
@ -195,6 +201,7 @@ it:
many_many_Members: Membri
SilverStripe\Security\LoginAttempt:
Email: 'Indirizzo e-mail'
EmailHashed: 'Indirizzo email (hash)'
IP: 'Indirizzo IP'
PLURALNAME: 'Tentativi d''accesso'
PLURALS:
@ -236,6 +243,7 @@ it:
SUBJECTPASSWORDCHANGED: 'La tua password è stata cambiata'
SUBJECTPASSWORDRESET: 'Link per azzerare la tua password'
SURNAME: Cognome
VALIDATIONADMINLOSTACCESS: 'Non è possibile rimuovere tutti i gruppi admin dal tuo profilo'
ValidationIdentifierFailed: 'Non posso sovrascrivere l''utente esistente #{id} con identificatore identico ({name} = {value}))'
WELCOMEBACK: 'Bentornato, {firstname}'
YOUROLDPASSWORD: 'La tua vecchia password'
@ -252,6 +260,8 @@ it:
SilverStripe\Security\MemberAuthenticator\MemberAuthenticator:
ERRORWRONGCRED: 'I dettagli forniti non sembrano corretti. Per favore riprovare.'
NoPassword: 'Manca la password per questo utente.'
SilverStripe\Security\MemberAuthenticator\MemberLoginForm:
AUTHENTICATORNAME: 'E-mail & Password'
SilverStripe\Security\MemberPassword:
PLURALNAME: 'Password utenti'
PLURALS:
@ -313,7 +323,6 @@ it:
LOGOUT: Scollegati
LOSTPASSWORDHEADER: 'Password smarrita'
NOTEPAGESECURED: 'La pagina è protetta. Inserisci le credenziali qui sotto per poter andare avanti.'
NOTERESETLINKINVALID: '<p>Il link per azzerare la password non è valido o è scaduto.</p><p>Puoi richiederne uno nuovo <a href="{link1}">qui</a> o cambiare la tua password dopo che ti sei <a href="{link2}">connesso</a>.</p>'
NOTERESETPASSWORD: 'Inserisci il tuo indirizzo e-mail e ti verrà inviato un link per poter azzerare la tua password.'
PASSWORDSENTHEADER: 'Link per azzeramento della password inviato a ''{email}'''
PASSWORDSENTTEXT: 'Grazie! Un link di azzeramento è stato inviato a ''{email}'', fornito un account esistente per questo indirizzo e-mail.'
PASSWORDRESETSENTHEADER: 'Link di azzeramento password inviato'
PASSWORDRESETSENTTEXT: 'Grazie! Un link di azzeramento è stato inviato, supponendo un account esista a quell''indirizzo e-mail.'

View File

@ -146,7 +146,4 @@ ja:
ERRORPASSWORDPERMISSION: パスワードを変更する為に、ログインしなければなりません!
LOGIN: ログイン
NOTEPAGESECURED: このページはセキュリティで保護されております証明書キーを下記に入力してください。こちらからすぐに送信します
NOTERESETLINKINVALID: '<p>パスワードのリセットリンクは有効でないか期限切れです。</p><p> 新しいパスワードを要求することができます <a href="{link1}"> ここ </a> もしくはパスワードを変更することができます <a href="{link2}"> ログインした後 </a>.</p>'
NOTERESETPASSWORD: メールアドレスを入力してください、パスワードをリセットするURLを送信致します
PASSWORDSENTHEADER: 'パスワードリセットリンクは ''{email}'' に送信されました'
PASSWORDSENTTEXT: 'ありがとうございました! リセットリンクは、''{email}'' に、このアカウントが存在することを前提として送信されました。'

View File

@ -167,7 +167,4 @@ lt:
LOGIN: Prisijungti
LOSTPASSWORDHEADER: 'Slaptažodžio atstatymas'
NOTEPAGESECURED: 'Šis puslapis yra apsaugotas. Įveskite savo duomenis į žemiau esančius laukelius.'
NOTERESETLINKINVALID: '<p>Neteisinga arba negaliojanti slaptažodžio atstatymo nuoroda.</p><p>Galite atsisiųsti naują <a href="{link1}">čia</a> arba pasikeisti slaptažodį po to, kai <a href="{link2}">prisijungsite</a>.</p>'
NOTERESETPASSWORD: 'Įveskite savo e. pašto adresą ir atsiųsime slaptažodžio atstatymui skirtą nuorodą'
PASSWORDSENTHEADER: 'Slaptažodžio atstatymo nuoroda nusiųsta į ''{email}'''
PASSWORDSENTTEXT: 'Atstatymo nuoroda nusiųsta į ''{email}'''

View File

@ -149,7 +149,4 @@ mi:
LOGIN: Takiuru
LOSTPASSWORDHEADER: 'Kupuhipa Ngaro'
NOTEPAGESECURED: 'Kua ngita tēnā whārangi. Tāurua ō taipitoptio tuakiri ki raro, ā, mā mātou koe e tuku kia haere tonu.'
NOTERESETLINKINVALID: '<p>He muhu, kua mōnehu rānei te hono tautuhi kupuhipa anō.</p><p>Ka taea te tono i te mea hōu<a href="{link1}">i konei</a> ka huri rānei i tō kupuhipa ā muri i tō<a href="{link2}">takiuru</a>.</p>'
NOTERESETPASSWORD: 'Tāurua tō wāhitau īmēra, mā mātou e tuku tētahi hono ki a koe e taea ai te tautuhi anō i tō kupuhipa'
PASSWORDSENTHEADER: 'I tukuna he hono tautuhi kupuhipa anō ki ''{email}'''
PASSWORDSENTTEXT: 'Kia ora! Kua tukuna he hono tautuhi anō ki ''{email}'',engari rā kei te tīariari he pūkete mō taua wāhitau īmēra.'

View File

@ -152,7 +152,4 @@ nb:
LOGIN: 'Logg inn'
LOSTPASSWORDHEADER: 'Mistet passord'
NOTEPAGESECURED: 'Den siden er sikret. Skriv inn gyldig innloggingsinfo så kommer du inn.'
NOTERESETLINKINVALID: '<p>Lenken for å nullstille passordet er ugyldig eller utgått.</p><p>Du kan kreve en ny <a href="{link1}">her</a> eller endre passordet etter at du har <a href="{link2}">logget inn</a>.</p>'
NOTERESETPASSWORD: 'Skriv inn epostadressen din og vi vil sende deg en lenke som nullstiller passordet.'
PASSWORDSENTHEADER: 'Lenke for nullstilling av passord ble sendt til ''{email}'''
PASSWORDSENTTEXT: 'Takk! En lenke for å lage nytt passord er sendt til ''{email}'', forutsatt at det eksisterer en konto for denne epostadressen.'

View File

@ -1,4 +1,26 @@
nl:
SilverStripe\Admin\LeftAndMain:
VersionUnknown: onbekend
SilverStripe\AssetAdmin\Forms\UploadField:
Dimensions: Afmetingen
EDIT: Bewerken
EDITINFO: 'Bewerk dit bestand'
REMOVE: Verwijder
SilverStripe\Control\ChangePasswordEmail_ss:
CHANGEPASSWORDFOREMAIL: 'Het wachtwoord voor het account met e-mailadres {email} is aangepast. Indien u uw wachtwoord niet heeft aangepast kunt u dat doen met onderstaande link.'
CHANGEPASSWORDTEXT1: 'U heeft het wachtwoord veranderd voor'
CHANGEPASSWORDTEXT3: 'Wachtwoord veranderen'
HELLO: Hallo
SilverStripe\Control\Email\ForgotPasswordEmail_ss:
HELLO: Hallo
TEXT1: 'Hier is uw'
TEXT2: 'link om uw wachtwoord opnieuw aan te maken'
TEXT3: voor
SilverStripe\Control\RequestProcessor:
INVALID_REQUEST: 'Fout bij verwerken'
REQUEST_ABORTED: 'Fout bij verwerken (geannuleerd)'
SilverStripe\Core\Manifest\VersionProvider:
VERSIONUNKNOWN: Onbekend
SilverStripe\Forms\CheckboxField:
NOANSWER: Nee
YESANSWER: Ja
@ -8,6 +30,8 @@ nl:
ATLEAST: 'Een wachtwoord moet tenminste {min} karakters hebben.'
BETWEEN: 'Een wachtwoord moet tussen de {min} en {max} karakters hebben'
CURRENT_PASSWORD_ERROR: 'Het wachtwoord dat u heeft ingevoerd is niet juist.'
CURRENT_PASSWORD_MISSING: 'Voer uw huidige wachtwoord in.'
LOGGED_IN_ERROR: 'U moet ingelogd zijn om uw wachtwoord te kunnen veranderen!'
MAXIMUM: 'Een wachtwoord mag maximaal {max} karakters hebben.'
SHOWONCLICKTITLE: 'Verander wachtwoord'
SilverStripe\Forms\CurrencyField:
@ -16,12 +40,20 @@ nl:
VALIDDATEFORMAT2: 'Vul een geldig datumformaat in ({format})'
VALIDDATEMAXDATE: 'De datum moet ouder of gelijk zijn aan de maximale datum ({date})'
VALIDDATEMINDATE: 'De datum moet nieuwer of gelijk zijn aan de minimale datum ({date})'
SilverStripe\Forms\DatetimeField:
VALIDDATEMAXDATETIME: 'De datum moet ouder of gelijk zijn aan de maximale datum ({datetime})'
VALIDDATETIMEFORMAT: 'Vul een geldige datum in ({format})'
VALIDDATETIMEMINDATE: 'De datum moet nieuwer of gelijk zijn aan de minimale datum ({datetime})'
SilverStripe\Forms\DropdownField:
CHOOSE: (Kies)
CHOOSE_MODEL: '(Selecteer {name})'
SOURCE_VALIDATION: 'Selecteer een optie uit de lijst. {value} is geen geldige keuze.'
SilverStripe\Forms\EmailField:
VALIDATION: 'Gelieve een e-mailadres in te voeren.'
SilverStripe\Forms\FileUploadReceiver:
FIELDNOTSET: 'Bestandsinformatie niet gevonden'
SilverStripe\Forms\Form:
BAD_METHOD: 'Dit formulier moet middels {method} verzonden worden'
CSRF_EXPIRED_MESSAGE: 'Uw sessie is verlopen. Verzend het formulier opnieuw.'
CSRF_FAILED_MESSAGE: 'Er lijkt een technisch probleem te zijn. Klik op de knop terug, vernieuw uw browser, en probeer het opnieuw.'
VALIDATIONPASSWORDSDONTMATCH: 'Wachtwoorden komen niet overeen'
@ -30,7 +62,10 @@ nl:
VALIDATOR: Validator
VALIDCURRENCY: 'Vul een geldige munteenheid in'
SilverStripe\Forms\FormField:
EXAMPLE: 'bijv. {format}'
NONE: geen
SilverStripe\Forms\FormScaffolder:
TABMAIN: Hoofdgedeelte
SilverStripe\Forms\GridField\GridField:
Add: '{name} toevoegen'
CSVEXPORT: 'Exporteer naar CSV'
@ -41,6 +76,7 @@ nl:
LinkExisting: 'Koppel een bestaand item'
NewRecord: 'Nieuw {type}'
NoItemsFound: 'Geen items gevonden.'
OpenFilter: 'Zoeken en filteren openen'
PRINTEDAT: 'Geprint op'
PRINTEDBY: 'Geprint door'
PlaceHolder: 'Zoek {type}'
@ -60,27 +96,72 @@ nl:
DeletePermissionsFailure: 'Onvoldoende rechten om te verwijderen'
Deleted: '{type} {name} verwijderd'
Save: Opslaan
SilverStripe\Forms\GridField\GridFieldEditButton:
EDIT: Bewerken
SilverStripe\Forms\GridField\GridFieldFilterHeader:
Search: 'Zoek naar "{name}"'
SearchFormFaliure: 'Er kon geen zoekformulier worden aangemaakt'
SilverStripe\Forms\GridField\GridFieldGroupDeleteAction:
UnlinkSelfFailure: 'U kunt uzelf niet verwijderen van deze groep, omdat u dan geen admin-rechten meer heeft.'
SilverStripe\Forms\GridField\GridFieldPaginator:
OF: van
Page: Pagina
View: Bekijk
SilverStripe\Forms\GridField\GridFieldViewButton:
VIEW: Bekijk
SilverStripe\Forms\MoneyField:
FIELDLABELAMOUNT: Aantal
FIELDLABELCURRENCY: Munteenheid
INVALID_CURRENCY: 'Valuta {currency} is niet toegestaan'
SilverStripe\Forms\MultiSelectField:
SOURCE_VALIDATION: 'Selecteer een optie uit de lijst. {value} is geen geldige keuze.'
SilverStripe\Forms\NullableField:
IsNullLabel: 'Is null'
SilverStripe\Forms\NumericField:
VALIDATION: '''{value}'' is geen getal, enkel getallen worden door dit veld geaccepteerd'
SilverStripe\Forms\TimeField:
VALIDATEFORMAT: 'Vul een geldig datumformaat in ({format})'
SilverStripe\ORM\DataObject:
PLURALNAME: 'Data objecten'
PLURALS:
one: 'Data object'
other: '{count} Data objecten'
SINGULARNAME: 'Data object'
SilverStripe\ORM\FieldType\DBBoolean:
ANY: Elke
NOANSWER: Nee
YESANSWER: Ja
SilverStripe\ORM\FieldType\DBDate:
DAYS_SHORT_PLURALS:
one: '{count} dag'
other: '{count} dagen'
HOURS_SHORT_PLURALS:
one: '{count} uur'
other: '{count} uren'
LessThanMinuteAgo: 'minder dan één minuut'
MINUTES_SHORT_PLURALS:
one: '{count} minuut'
other: '{count} minuten'
MONTHS_SHORT_PLURALS:
one: '{count} maand'
other: '{count} maanden'
SECONDS_SHORT_PLURALS:
one: '{count} seconde'
other: '{count} seconden'
TIMEDIFFAGO: '{difference} geleden'
TIMEDIFFIN: 'in {difference}'
YEARS_SHORT_PLURALS:
one: '{count} jaar'
other: '{count} jaren'
SilverStripe\ORM\FieldType\DBEnum:
ANY: Elke
SilverStripe\ORM\FieldType\DBForeignKey:
DROPDOWN_THRESHOLD_FALLBACK_MESSAGE: 'Teveel keuzes in de lijst; een alternatief veld wordt getoond.'
SilverStripe\ORM\Hierarchy:
LIMITED_TITLE: 'Teveel onderliggende items ({count})'
SilverStripe\ORM\Hierarchy\Hierarchy:
InfiniteLoopNotAllowed: 'Oneindige lus gevonden in "{type}" hiërarchie. Wijzig het hogere niveau om dit op te lossen'
LIMITED_TITLE: 'Teveel onderliggende items ({count})'
SilverStripe\ORM\ValidationException:
DEFAULT_ERROR: Validatiefout
SilverStripe\Security\BasicAuth:
@ -91,34 +172,60 @@ nl:
PASSWORDEXPIRED: '<p>Uw wachtwoord is verlopen. <a target="_top" href="{link}">Kies een nieuw wachtwoord.</a></p>'
SilverStripe\Security\CMSSecurity:
INVALIDUSER: '<p>Ongeldige gebruiker <a target="_top" href="{link}">Log hier opnieuw in</a> om verder te gaan.</p>'
LOGIN_MESSAGE: 'Sessie is verlopen'
LOGIN_TITLE: '<p>U kunt verder met wat u aan het doen was, door opnieuw in te loggen.</p>'
SUCCESS: Succes
SUCCESSCONTENT: '<p>U bent ingelogd. <a target="_top" href="{link}">Klik hier</a> als u niet automatisch wordt doorgestuurd.</p>'
SUCCESS_TITLE: 'Inloggen is gelukt'
SilverStripe\Security\DefaultAdminService:
DefaultAdminFirstname: 'Standaard Beheerder'
SilverStripe\Security\Group:
AddRole: 'Voeg een rol toe aan deze groep'
Code: 'Groep code'
DefaultGroupTitleAdministrators: Beheerders
DefaultGroupTitleContentAuthors: 'Inhoud Auteurs'
Description: 'Omschrijving '
GROUPNAME: 'Groep naam'
GroupReminder: 'Als u de bovenliggende groep selecteert, neemt deze groep alle rollen over'
HierarchyPermsError: 'U moet (ADMIN) rechten hebben om de bovenliggende groep "{group}" toe te kennen'
Locked: 'Gesloten?'
MEMBERS: Leden
NEWGROUP: 'Nieuwe groep'
NoRoles: 'Geen rollen gevonden'
PERMISSIONS: Rechten
PLURALNAME: Groepen
PLURALS:
one: 'Een groep'
other: '{count} groepen'
Parent: 'Bovenliggende groep'
ROLES: Rollen
ROLESDESCRIPTION: 'Rollen zijn logische groeperingen van rechten die in het Rollen tabblad gewijzigd kunnen worden.<br />Rollen worden automatisch overgenomen van bovenliggende groepen.'
RolesAddEditLink: 'Rollen beheren'
SINGULARNAME: Groep
Sort: Sorteer-richting
has_many_Permissions: Rechten
many_many_Members: Leden
SilverStripe\Security\LoginAttempt:
Email: 'E-mailadres '
EmailHashed: 'E-mailadres (versleuteld)'
IP: 'IP adres'
PLURALNAME: Inlogpogingen
PLURALS:
one: 'Een inlogpoging'
other: '{count} inlogpogingen'
SINGULARNAME: Inlogpogingen
Status: Status
SilverStripe\Security\Member:
ADDGROUP: 'Groep toevoegen'
BUTTONCHANGEPASSWORD: 'Wachtwoord veranderen'
BUTTONLOGIN: Inloggen
BUTTONLOGINOTHER: 'Als iemand anders inloggen'
BUTTONLOGOUT: Uitloggen
BUTTONLOSTPASSWORD: 'Ik ben mijn wachtwoord vergeten'
CONFIRMNEWPASSWORD: 'Bevestig het nieuwe wachtwoord'
CONFIRMPASSWORD: 'Bevestig wachtwoord'
CURRENT_PASSWORD: 'Huidige wachtwoord'
EDIT_PASSWORD: 'Nieuw wachtwoord'
EMAIL: E-mail
EMPTYNEWPASSWORD: 'Het nieuwe wachtwoord mag niet leeg zijn, probeer opnieuw'
ENTEREMAIL: 'Typ uw e-mailadres om een link te ontvangen waarmee u uw wachtwoord kunt resetten.'
@ -128,13 +235,21 @@ nl:
ERRORWRONGCRED: 'De ingevulde gegevens lijken niet correct. Probeer het nog een keer.'
FIRSTNAME: Voornaam
INTERFACELANG: 'Interface taal'
KEEPMESIGNEDIN: 'Houd mij ingelogd'
LOGGEDINAS: 'U bent ingelogd als {name}.'
NEWPASSWORD: 'Nieuw wachtwoord'
PASSWORD: Wachtwoord
PASSWORDEXPIRED: 'Uw wachtwoord is verlopen. Kies een nieuw wachtwoord.'
PLURALNAME: Leden
PLURALS:
one: 'Een lid'
other: '{count} leden'
REMEMBERME: 'Onthoud mij voor volgende keer? (voor {count} dagen op dit apparaat)'
SINGULARNAME: Lid
SUBJECTPASSWORDCHANGED: 'Uw wachtwoord is veranderd'
SUBJECTPASSWORDRESET: 'Link om uw wachtwoord opnieuw aan te maken'
SURNAME: Achternaam
VALIDATIONADMINLOSTACCESS: 'Niet mogelijk om alle admin-groepen te verwijderen van uw profiel'
ValidationIdentifierFailed: 'Een bestaande gebruiker #{id} kan niet dezelfde unieke velden hebben ({name} = {value}))'
WELCOMEBACK: 'Welkom terug, {firstname}'
YOUROLDPASSWORD: 'Uw oude wachtwoord'
@ -143,15 +258,38 @@ nl:
db_LockedOutUntil: 'Gesloten tot'
db_Password: Wachtwoord
db_PasswordExpiry: 'Wachtwoord vervaldatum'
SilverStripe\Security\MemberAuthenticator\CMSMemberLoginForm:
AUTHENTICATORNAME: Inlogformulier
BUTTONFORGOTPASSWORD: 'Wachtwoord vergeten'
BUTTONLOGIN: 'Opnieuw inloggen'
BUTTONLOGOUT: Uitloggen
SilverStripe\Security\MemberAuthenticator\MemberAuthenticator:
ERRORWRONGCRED: 'De ingevulde gegevens lijken niet correct. Probeer het nog een keer.'
NoPassword: 'Er is geen wachtwoord voor deze gebruiker.'
SilverStripe\Security\MemberAuthenticator\MemberLoginForm:
AUTHENTICATORNAME: 'E-mail & wachtwoord'
SilverStripe\Security\MemberPassword:
PLURALNAME: Gebruikerswachtwoorden
PLURALS:
one: 'Een gebruikerswachtwoord'
other: '{count} Gebruikerswachtwoorden'
SINGULARNAME: Gebruikerswachtwoord
SilverStripe\Security\PasswordValidator:
LOWCHARSTRENGTH: 'Maak a.u.b. uw wachtwoord sterker door enkele van de volgende karakters te gebruiken: {chars}'
PREVPASSWORD: 'U heeft dit wachtwoord in het verleden al gebruikt, kies a.u.b. een nieuw wachtwoord.'
TOOSHORT: 'Het wachtwoord is te kort, het moet minimaal {minimum} karakters hebben'
SilverStripe\Security\Permission:
AdminGroup: Beheerder
CMS_ACCESS_CATEGORY: 'CMS toegang'
CONTENT_CATEGORY: Inhoudsrechten
FULLADMINRIGHTS: 'Volledige admin rechten'
FULLADMINRIGHTS_HELP: 'Impliceert en overstemt alle andere toegewezen rechten.'
PERMISSIONS_CATEGORY: 'Rollen en toegangsrechten'
PLURALNAME: Rechten
PLURALS:
one: Machtiging
other: '{count} rechten'
SINGULARNAME: Machtiging
UserPermissionsIntro: 'Groepen aan deze gebruiker toewijzen zullen diens permissies aanpassen. Zie de sectie Groepen voor meer informatie over machtigingen voor afzonderlijke groepen.'
SilverStripe\Security\PermissionCheckboxSetField:
AssignedTo: 'toegewezen aan "{title}"'
@ -161,21 +299,37 @@ nl:
SilverStripe\Security\PermissionRole:
OnlyAdminCanApply: 'Alleen admin kan doorvoeren'
PLURALNAME: Rollen
PLURALS:
one: 'Een rol'
other: '{count} rollen'
SINGULARNAME: Rol
Title: Titel
SilverStripe\Security\PermissionRoleCode:
PLURALNAME: 'Permissie codes'
PLURALS:
one: 'Een permissiecode'
other: '{count} permissiecodes'
PermsError: 'U moet (ADMIN) rechten hebben om de code "{code}" toe te kennen'
SINGULARNAME: Permissiecode
SilverStripe\Security\RememberLoginHash:
PLURALNAME: 'Versleutelde logins'
PLURALS:
one: 'Een versleutelde login'
other: '{count} versleutelde logins'
SINGULARNAME: 'Versleutelde login'
SilverStripe\Security\Security:
ALREADYLOGGEDIN: 'U hebt geen toegang tot deze pagina. Als u een andere account met de nodige rechten hebt, kan u hieronder opnieuw inloggen.'
BUTTONSEND: 'Nieuw wachtwoord aanmaken'
CHANGEPASSWORDBELOW: 'U kunt uw wachtwoord hieronder veranderen.'
CHANGEPASSWORDHEADER: 'Verander uw wachtwoord'
CONFIRMLOGOUT: 'Klik op onderstaande knop om uit te loggen.'
ENTERNEWPASSWORD: 'Voer een nieuw wachtwoord in.'
ERRORPASSWORDPERMISSION: 'U moet ingelogd zijn om uw wachtwoord te kunnen veranderen!'
LOGIN: 'Meld aan'
LOGOUT: Uitloggen
LOSTPASSWORDHEADER: 'Wachtwoord vergeten'
NOTEPAGESECURED: 'Deze pagina is beveiligd. Voer uw gegevens in en u wordt automatisch doorgestuurd.'
NOTERESETLINKINVALID: '<p>De link om uw wachtwoord te kunnen wijzigen is niet meer geldig.</p><p>U kunt <a href="{link1}">een nieuwe link aanvragen</a> of uw wachtwoord aanpassen door <a href="{link2}">in te loggen</a>.</p>'
NOTERESETLINKINVALID: '<p>De reset link is ongeldig of komen te vervallen.</p><p>Je kan <a href="{link1}">hier</a> een nieuwe link aanvragen of het wachtwoord veranderen nadat je bent <a href="{link2}">ingelogd</a>.</p>'
NOTERESETPASSWORD: 'Voer uw e-mailadres in en we sturen een link waarmee u een nieuw wachtwoord kunt instellen.'
PASSWORDSENTHEADER: 'Wachtwoord herstel link verzonden naar {email}'
PASSWORDSENTTEXT: 'Bedankt! Er is een link verstuurd naar {email} om uw wachtwoord opnieuw in te stellen, in de veronderstelling dat er een account bestaat voor dit e-mailadres.'
PASSWORDRESETSENTHEADER: 'link om uw wachtwoord opnieuw aan te maken'
PASSWORDRESETSENTTEXT: 'Bedankt! Er is een link verstuurd om uw wachtwoord opnieuw in te stellen (mits het mailadres reeds bekend is bij ons).'

View File

@ -84,7 +84,6 @@ pl:
RelationSearch: 'Wyszukiwanie powiązań'
ResetFilter: Resetuj
SilverStripe\Forms\GridField\GridFieldDeleteAction:
DELETE_DESCRIPTION: Usuń
Delete: Usuń
DeletePermissionsFailure: 'Brak uprawnień do usuwania'
EditPermissionsFailure: 'Nie masz uprawnień, aby odłączyć rekord'
@ -96,8 +95,6 @@ pl:
DeletePermissionsFailure: 'Brak uprawnień do usuwania'
Deleted: 'Usunięto {type} {name}'
Save: Zapisz
SilverStripe\Forms\GridField\GridFieldEditButton_ss:
EDIT: Edytuj
SilverStripe\Forms\GridField\GridFieldGroupDeleteAction:
UnlinkSelfFailure: 'Nie możesz usunąć siebie z tej grupy, stracone zostałby prawa administratora'
SilverStripe\Forms\GridField\GridFieldPaginator:
@ -352,7 +349,4 @@ pl:
LOGOUT: 'Wyloguj się'
LOSTPASSWORDHEADER: 'Nie pamiętam hasła'
NOTEPAGESECURED: 'Ta strona jest zabezpieczona. Wpisz swoje dane a my wyślemy Ci potwierdzenie niebawem'
NOTERESETLINKINVALID: '<p>Link resetujący hasło wygasł lub jest nieprawidłowy.</p><p>Możesz poprosić o nowy <a href="{link1}">tutaj</a> lub zmień swoje hasło po <a href="{link2}">zalogowaniu się</a>.</p>'
NOTERESETPASSWORD: 'Wpisz adres e-mail, na który mamy wysłać link gdzie możesz zresetować swoje hasło'
PASSWORDSENTHEADER: 'Link resetujący hasła został wysłany do ''{email}'''
PASSWORDSENTTEXT: 'Dziękujemy! Link resetujący hasło został wysłany do ''{email}'', o ile konto użytkownika dla takiego e-maila istnieje.'

View File

@ -339,7 +339,4 @@ ru:
LOGOUT: Выйти
LOSTPASSWORDHEADER: 'Восстановление пароля'
NOTEPAGESECURED: 'Эта страница защищена. Пожалуйста, введите свои учетные данные для входа.'
NOTERESETLINKINVALID: '<p>Неверная ссылка переустановки пароля или время действия ссылки истекло.</p><p>Вы можете повторно запросить ссылку, щелкнув <a href="{link1}">здесь</a>, или поменять пароль, <a href="{link2}">войдя в систему</a>.</p> '
NOTERESETPASSWORD: 'Введите Ваш адрес email, и Вам будет отправлена ссылка, по которой Вы сможете переустановить свой пароль'
PASSWORDSENTHEADER: 'Ссылка для переустановки пароля выслана на ''{email}'''
PASSWORDSENTTEXT: 'Ссылка переустановки пароля была выслана на адрес ''{email}'' (письмо дойдет до получателя только в том случае, если аккаунт с таким электронным адресом действительно зарегистрирован).'

View File

@ -228,7 +228,4 @@ sk:
LOGIN: Prihlásiť
LOSTPASSWORDHEADER: 'Zabudnuté heslo'
NOTEPAGESECURED: 'Táto stránka je zabezpečená. Zadajte svoje prihlasovacie údaje a my Vám zároveň pošleme práva.'
NOTERESETLINKINVALID: '<p>Odkaz na resetovanie hesla nie je platný alebo je vypršala jeho platnosť.</p><p>Môžete požiadať o nový <a href="{link1}">tu</a> alebo zmeňte svoje heslo po <a href="{link2}">prihlásení</a>.</p>'
NOTERESETPASSWORD: 'Zadajte svoju e-mailovú adresu a my Vám pošleme odkaz na resetovanie hesla'
PASSWORDSENTHEADER: 'Odkaz na resetovanie hesla bol odoslaný na ''{email}'''
PASSWORDSENTTEXT: 'Ďakujeme! Resetovací odkaz bol odoslaný na ''''{email}'''', pokiaľ účet existuje pre túto emailovú adresu.'

View File

@ -135,7 +135,4 @@ sl:
LOGIN: Prijava
LOSTPASSWORDHEADER: 'Izgubljeno geslo'
NOTEPAGESECURED: 'Stran je zaščitena. Da bi lahko nadaljevali, vpišite svoje podatke.'
NOTERESETLINKINVALID: '<p>Povezava za ponastavitev gesla je napačna ali pa je njena veljavnost potekla.</p><p><a href="{link1}">Tukaj</a> lahko zaprosite za novo povezavo or pa zamenjate geslo, ko <a href="{link2}">se prijavite v sistem</a>.</p>'
NOTERESETPASSWORD: 'Vpišite e-naslov, na katerega vam bomo poslali povezavo za ponastavitev gesla'
PASSWORDSENTHEADER: 'Povezava za ponastavitev gesla je bila poslana na e-naslov ''{email}''.'
PASSWORDSENTTEXT: 'Hvala! Povezava za ponastavitev gesla je bila poslana na e-naslov ''{email}'', ki je naveden kot e-naslov vašega računa. '

View File

@ -151,7 +151,4 @@ sr:
ERRORPASSWORDPERMISSION: 'Морате да будете пријављени да бисте променили своју лозинку!'
LOGIN: Пријављивање
NOTEPAGESECURED: 'Ова страна је обезбеђена. Унесите своје податке и ми ћемо вам послати садржај.'
NOTERESETLINKINVALID: '<p>Линк за ресетовање лозинке је погрешан или је истекло време за његово коришћење.</p><p>Можете да захтевате нови <a href="{link1}">овде</a> или да промените Вашу лозинку након што се <a href="{link2}">пријавите</a>.</p>'
NOTERESETPASSWORD: 'Унесите своју адресу е-поште и ми ћемо вам послати линк помоћу којег можете да промените своју лозинку'
PASSWORDSENTHEADER: 'Линк за ресетовање лозинке послат је на адресу е-поште: ''{email}'''
PASSWORDSENTTEXT: 'Хвала Вам! Линк за ресетовање лозинке је послат не адресу е-поште ''{email}''. Порука ће стићи примаоцу само ако постоји регистрован налог са том адресом е-поште.'

View File

@ -150,7 +150,4 @@ sr@latin:
ERRORPASSWORDPERMISSION: 'Morate da budete prijavljeni da biste promenili svoju lozinku!'
LOGIN: Prijavljivanje
NOTEPAGESECURED: 'Ova strana je obezbeđena. Unesite svoje podatke i mi ćemo vam poslati sadržaj.'
NOTERESETLINKINVALID: '<p>Link za resetovanje lozinke je pogrešan ili je isteklo vreme za njegovo korišćenje.</p><p>Možete da zahtevate novi <a href="{link1}">ovde</a> ili da promenite Vašu lozinku nakon što se <a href="{link2}">prijavite</a>.</p>'
NOTERESETPASSWORD: 'Unesite svoju adresu e-pošte i mi ćemo vam poslati link pomoću kojeg možete da promenite svoju lozinku'
PASSWORDSENTHEADER: 'Link za resetovanje lozinke poslat je na adresu e-pošte: ''{email}'''
PASSWORDSENTTEXT: 'Hvala Vam! Link za resetovanje lozinke je poslat ne adresu e-pošte ''{email}''. Poruka će stići primaocu samo ako postoji registrovan nalog sa tom adresom e-pošte.'

View File

@ -150,7 +150,4 @@ sr_RS:
ERRORPASSWORDPERMISSION: 'Морате да будете пријављени да бисте променили своју лозинку!'
LOGIN: Пријављивање
NOTEPAGESECURED: 'Ова страна је обезбеђена. Унесите своје податке и ми ћемо вам послати садржај.'
NOTERESETLINKINVALID: '<p>Линк за ресетовање лозинке је погрешан или је истекло време за његово коришћење.</p><p>Можете да захтевате нови <a href="{link1}">овде</a> или да промените Вашу лозинку након што се <a href="{link2}">пријавите</a>.</p>'
NOTERESETPASSWORD: 'Унесите своју адресу е-поште и ми ћемо вам послати линк помоћу којег можете да промените своју лозинку'
PASSWORDSENTHEADER: 'Линк за ресетовање лозинке послат је на адресу е-поште: ''{email}'''
PASSWORDSENTTEXT: 'Хвала Вам! Линк за ресетовање лозинке је послат не адресу е-поште ''{email}''. Порука ће стићи примаоцу само ако постоји регистрован налог са том адресом е-поште.'

View File

@ -151,7 +151,4 @@ sr_RS@latin:
ERRORPASSWORDPERMISSION: 'Morate da budete prijavljeni da biste promenili svoju lozinku!'
LOGIN: Prijavljivanje
NOTEPAGESECURED: 'Ova strana je obezbeđena. Unesite svoje podatke i mi ćemo vam poslati sadržaj.'
NOTERESETLINKINVALID: '<p>Link za resetovanje lozinke je pogrešan ili je isteklo vreme za njegovo korišćenje.</p><p>Možete da zahtevate novi <a href="{link1}">ovde</a> ili da promenite Vašu lozinku nakon što se <a href="{link2}">prijavite</a>.</p>'
NOTERESETPASSWORD: 'Unesite svoju adresu e-pošte i mi ćemo vam poslati link pomoću kojeg možete da promenite svoju lozinku'
PASSWORDSENTHEADER: 'Link za resetovanje lozinke poslat je na adresu e-pošte: ''{email}'''
PASSWORDSENTTEXT: 'Hvala Vam! Link za resetovanje lozinke je poslat ne adresu e-pošte ''{email}''. Poruka će stići primaocu samo ako postoji registrovan nalog sa tom adresom e-pošte.'

View File

@ -93,7 +93,12 @@ sv:
DeletePermissionsFailure: 'Rättighet för att radera saknas'
Deleted: 'Raderade {type} {name}'
Save: Spara
SilverStripe\Forms\GridField\GridFieldEditButton:
EDIT: Ändra
SilverStripe\Forms\GridField\GridFieldGroupDeleteAction:
UnlinkSelfFailure: 'Du kan inte radera dig själv från den här gruppen, då du då kommer att förlora dina admin-rättigheter'
SilverStripe\Forms\GridField\GridFieldPaginator:
OF: av
Page: Sida
View: Visa
SilverStripe\Forms\MoneyField:
@ -108,6 +113,12 @@ sv:
VALIDATION: '''{value}'' är inget nummer, bara siffror (utan mellanslag) kan accepteras för det här fältet'
SilverStripe\Forms\TimeField:
VALIDATEFORMAT: 'Var god att ange tid i ett giltigt format ({format})'
SilverStripe\ORM\DataObject:
PLURALNAME: Dataobjekt
PLURALS:
one: 'Ett dataobjekt'
other: '{count} Dataobjekt'
SINGULARNAME: Dataobjekt
SilverStripe\ORM\FieldType\DBBoolean:
ANY: 'Vilken som helst'
NOANSWER: Nej
@ -136,6 +147,8 @@ sv:
other: '{count} år'
SilverStripe\ORM\FieldType\DBEnum:
ANY: 'Vilken som helst'
SilverStripe\ORM\FieldType\DBForeignKey:
DROPDOWN_THRESHOLD_FALLBACK_MESSAGE: 'För många relaterade objekt; använder fallback-fält'
SilverStripe\ORM\Hierarchy:
LIMITED_TITLE: 'För många barn ({count})'
SilverStripe\ORM\Hierarchy\Hierarchy:
@ -221,6 +234,7 @@ sv:
PLURALS:
one: 'En medlem'
other: '{count} medlemmar'
REMEMBERME: 'Kom ihåg mig nästa gång? (i {count} dagar på denna enhet)'
SINGULARNAME: Medlem
SUBJECTPASSWORDCHANGED: 'Ditt lösenord har ändrats'
SUBJECTPASSWORDRESET: 'Din återställningslänk'
@ -288,7 +302,6 @@ sv:
LOGOUT: 'Logga ut'
LOSTPASSWORDHEADER: 'Bortglömt lösenord'
NOTEPAGESECURED: 'Den här sidan är låst. Fyll i dina uppgifter nedan så skickar vi dig vidare.'
NOTERESETLINKINVALID: '<p>Återställningslänk för lösenord är felaktig eller för gammal.</p><p>Du kan begära en ny <a href="{link1}">här</a> eller ändra ditt lösenord när du <a href="{link2}">loggat in</a>.</p>'
NOTERESETPASSWORD: 'Ange din e-postadress så skickar vi en länk med vilken du kan återställa ditt lösenord'
PASSWORDSENTHEADER: 'Återställningslänk för lösenord har skickats till ''{email}'''
PASSWORDSENTTEXT: 'Tack en återställningslänk har skickats till ''{email}'', förutsatt att ett konto med den addressen finns.'
PASSWORDRESETSENTHEADER: 'Återställningslänk för lösenord skickad'
PASSWORDRESETSENTTEXT: 'Tack. En återställningslänk har skickats, förutsatt att ett konto med denna adress existerar.'

View File

@ -166,7 +166,4 @@ zh:
LOGIN: 登录
LOSTPASSWORDHEADER: 忘记密码
NOTEPAGESECURED: 该页面受安全保护。请在下面输入您的证书,然后我们会立即将您引导至该页面。
NOTERESETLINKINVALID: '<p>密码重设链接无效或已过期。</p><p>您可以在<a href="{link1}">这里</a> 要求一个新的或在<a href="{link2}">登录</a>后更改您的密码。</p>'
NOTERESETPASSWORD: 请输入您的电子邮件地址,然后我们会将一个链接发送给您,您可以用它来重设您的密码
PASSWORDSENTHEADER: '密码重设链接已发送至''{email}'''
PASSWORDSENTTEXT: '谢谢!复位链接已发送到 ''{email}'',假定此电子邮件地址存在一个帐户。'

View File

@ -41,7 +41,7 @@ class HTTPApplication implements Application
*/
public function handle(HTTPRequest $request)
{
$flush = array_key_exists('flush', $request->getVars()) || strpos($request->getURL(), 'dev/build') === 0;
$flush = array_key_exists('flush', $request->getVars()) || ($request->getURL() === 'dev/build');
// Ensure boot is invoked
return $this->execute($request, function (HTTPRequest $request) {

View File

@ -0,0 +1,192 @@
<?php
namespace SilverStripe\Core\Startup;
use SilverStripe\Control\Controller;
use SilverStripe\Control\Director;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Convert;
use SilverStripe\Security\RandomGenerator;
/**
* Shared functionality for token-based authentication of potentially dangerous URLs or query
* string parameters
*
* @internal This class is designed specifically for use pre-startup and may change without warning
*/
abstract class AbstractConfirmationToken
{
/**
* @var HTTPRequest
*/
protected $request = null;
/**
* The validated and checked token for this parameter
*
* @var string|null A string value, or null if either not provided or invalid
*/
protected $token = null;
/**
* Given a list of token names, suppress all tokens that have not been validated, and
* return the non-validated token with the highest priority
*
* @param array $keys List of token keys in ascending priority (low to high)
* @param HTTPRequest $request
* @return static The token container for the unvalidated $key given with the highest priority
*/
public static function prepare_tokens($keys, HTTPRequest $request)
{
$target = null;
foreach ($keys as $key) {
$token = new static($key, $request);
// Validate this token
if ($token->reloadRequired() || $token->reloadRequiredIfError()) {
$token->suppress();
$target = $token;
}
}
return $target;
}
/**
* Generate a local filesystem path to store a token
*
* @param $token
* @return string
*/
protected function pathForToken($token)
{
return TEMP_PATH . DIRECTORY_SEPARATOR . 'token_' . preg_replace('/[^a-z0-9]+/', '', $token);
}
/**
* Generate a new random token and store it
*
* @return string Token name
*/
protected function genToken()
{
// Generate a new random token (as random as possible)
$rg = new RandomGenerator();
$token = $rg->randomToken('md5');
// Store a file in the session save path (safer than /tmp, as open_basedir might limit that)
file_put_contents($this->pathForToken($token), $token);
return $token;
}
/**
* Is the necessary token provided for this parameter?
* A value must be provided for the token
*
* @return bool
*/
public function tokenProvided()
{
return !empty($this->token);
}
/**
* Validate a token
*
* @param string $token
* @return boolean True if the token is valid
*/
protected function checkToken($token)
{
if (!$token) {
return false;
}
$file = $this->pathForToken($token);
$content = null;
if (file_exists($file)) {
$content = file_get_contents($file);
unlink($file);
}
return $content === $token;
}
/**
* Get redirect url, excluding querystring
*
* @return string
*/
public function currentURL()
{
return Controller::join_links(Director::baseURL(), $this->request->getURL(false));
}
/**
* Forces a reload of the request with the token included
*
* @return HTTPResponse
*/
public function reloadWithToken()
{
$location = $this->redirectURL();
$locationJS = Convert::raw2js($location);
$locationATT = Convert::raw2att($location);
$body = <<<HTML
<script>location.href='$locationJS';</script>
<noscript><meta http-equiv="refresh" content="0; url=$locationATT"></noscript>
You are being redirected. If you are not redirected soon, <a href="$locationATT">click here to continue</a>
HTML;
// Build response
$result = new HTTPResponse($body);
$result->redirect($location);
return $result;
}
/**
* Is this parameter requested without a valid token?
*
* @return bool True if the parameter is given without a valid token
*/
abstract public function reloadRequired();
/**
* Check if this token is provided either in the backurl, or directly,
* but without a token
*
* @return bool
*/
abstract public function reloadRequiredIfError();
/**
* Suppress the current parameter for the duration of this request
*/
abstract public function suppress();
/**
* Determine the querystring parameters to include
*
* @param bool $includeToken Include the token value?
* @return array List of querystring parameters, possibly including token parameter
*/
abstract public function params($includeToken = true);
/**
* @return string
*/
abstract public function getRedirectUrlBase();
/**
* @return array
*/
abstract public function getRedirectUrlParams();
/**
* Get redirection URL
*
* @return string
*/
abstract protected function redirectURL();
}

View File

@ -0,0 +1,178 @@
<?php
namespace SilverStripe\Core\Startup;
use SilverStripe\Control\Controller;
use SilverStripe\Control\Director;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Convert;
/**
* A chain of confirmation tokens to be validated on each request. This allows the application to
* check multiple tokens at once without having to potentially redirect the user for each of them
*
* @internal This class is designed specifically for use pre-startup and may change without warning
*/
class ConfirmationTokenChain
{
/**
* @var array
*/
protected $tokens = [];
/**
* @param AbstractConfirmationToken $token
*/
public function pushToken(AbstractConfirmationToken $token)
{
$this->tokens[] = $token;
}
/**
* Collect all tokens that require a redirect
*
* @return \Generator
*/
protected function filteredTokens()
{
foreach ($this->tokens as $token) {
if ($token->reloadRequired() || $token->reloadRequiredIfError()) {
yield $token;
}
}
}
/**
* @return bool
*/
public function suppressionRequired()
{
foreach ($this->tokens as $token) {
if ($token->reloadRequired()) {
return true;
}
}
return false;
}
/**
* Suppress URLs & GET vars from tokens that require a redirect
*/
public function suppressTokens()
{
foreach ($this->filteredTokens() as $token) {
$token->suppress();
}
}
/**
* @return bool
*/
public function reloadRequired()
{
foreach ($this->tokens as $token) {
if ($token->reloadRequired()) {
return true;
}
}
return false;
}
/**
* @return bool
*/
public function reloadRequiredIfError()
{
foreach ($this->tokens as $token) {
if ($token->reloadRequiredIfError()) {
return true;
}
}
return false;
}
/**
* @param bool $includeToken
* @return array
*/
public function params($includeToken = true)
{
$params = [];
foreach ($this->tokens as $token) {
$params = array_merge($params, $token->params($includeToken));
}
return $params;
}
/**
* Fetch the URL we want to redirect to, excluding query string parameters. This may
* be the same URL (with a token to be added outside this method), or to a different
* URL if the current one has been suppressed
*
* @return string
*/
public function getRedirectUrlBase()
{
// URLConfirmationTokens may alter the URL to suppress the URL they're protecting,
// so we need to ensure they're inspected last and therefore take priority
$tokens = iterator_to_array($this->filteredTokens(), false);
usort($tokens, function ($a, $b) {
return ($a instanceof URLConfirmationToken) ? 1 : 0;
});
$urlBase = Director::baseURL();
foreach ($tokens as $token) {
$urlBase = $token->getRedirectUrlBase();
}
return $urlBase;
}
/**
* Collate GET vars from all token providers that need to apply a token
*
* @return array
*/
public function getRedirectUrlParams()
{
$params = [];
foreach ($this->filteredTokens() as $token) {
$params = array_merge($params, $token->getRedirectUrlParams());
}
return $params;
}
/**
* @return string
*/
protected function redirectURL()
{
$params = http_build_query($this->getRedirectUrlParams());
return Controller::join_links($this->getRedirectUrlBase(), '?' . $params);
}
/**
* @return HTTPResponse
*/
public function reloadWithTokens()
{
$location = $this->redirectURL();
$locationJS = Convert::raw2js($location);
$locationATT = Convert::raw2att($location);
$body = <<<HTML
<script>location.href='$locationJS';</script>
<noscript><meta http-equiv="refresh" content="0; url=$locationATT"></noscript>
You are being redirected. If you are not redirected soon, <a href="$locationATT">click here to continue</a>
HTML;
// Build response
$result = new HTTPResponse($body);
$result->redirect($location);
return $result;
}
}

View File

@ -15,8 +15,7 @@ use Exception;
* $chain = new ErrorControlChain();
* $chain->then($callback1)->then($callback2)->thenIfErrored($callback3)->execute();
*
* WARNING: This class is experimental and designed specifically for use pre-startup.
* It will likely be heavily refactored before the release of 3.2
* @internal This class is designed specifically for use pre-startup and may change without warning
*/
class ErrorControlChain
{

View File

@ -12,6 +12,8 @@ use SilverStripe\Security\Security;
/**
* Decorates application bootstrapping with errorcontrolchain
*
* @internal This class is designed specifically for use pre-startup and may change without warning
*/
class ErrorControlChainMiddleware implements HTTPMiddleware
{
@ -30,27 +32,42 @@ class ErrorControlChainMiddleware implements HTTPMiddleware
$this->application = $application;
}
/**
* @param HTTPRequest $request
* @return ConfirmationTokenChain
*/
protected function prepareConfirmationTokenChain(HTTPRequest $request)
{
$chain = new ConfirmationTokenChain();
$chain->pushToken(new URLConfirmationToken('dev/build', $request));
foreach (['isTest', 'isDev', 'flush'] as $parameter) {
$chain->pushToken(new ParameterConfirmationToken($parameter, $request));
}
return $chain;
}
public function process(HTTPRequest $request, callable $next)
{
$result = null;
// Prepare tokens and execute chain
$reloadToken = ParameterConfirmationToken::prepare_tokens(
['isTest', 'isDev', 'flush'],
$request
);
$chain = new ErrorControlChain();
$chain
->then(function () use ($request, $chain, $reloadToken, $next, &$result) {
// If no redirection is necessary then we can disable error supression
if (!$reloadToken) {
$chain->setSuppression(false);
$confirmationTokenChain = $this->prepareConfirmationTokenChain($request);
$errorControlChain = new ErrorControlChain();
$errorControlChain
->then(function () use ($request, $errorControlChain, $confirmationTokenChain, $next, &$result) {
if ($confirmationTokenChain->suppressionRequired()) {
$confirmationTokenChain->suppressTokens();
} else {
// If no redirection is necessary then we can disable error supression
$errorControlChain->setSuppression(false);
}
try {
// Check if a token is requesting a redirect
if ($reloadToken && $reloadToken->reloadRequired()) {
$result = $this->safeReloadWithToken($request, $reloadToken);
if ($confirmationTokenChain && $confirmationTokenChain->reloadRequired()) {
$result = $this->safeReloadWithTokens($request, $confirmationTokenChain);
} else {
// If no reload necessary, process application
$result = call_user_func($next, $request);
@ -60,10 +77,16 @@ class ErrorControlChainMiddleware implements HTTPMiddleware
}
})
// Finally if a token was requested but there was an error while figuring out if it's allowed, do it anyway
->thenIfErrored(function () use ($reloadToken) {
if ($reloadToken && $reloadToken->reloadRequiredIfError()) {
$result = $reloadToken->reloadWithToken();
$result->output();
->thenIfErrored(function () use ($confirmationTokenChain) {
if ($confirmationTokenChain && $confirmationTokenChain->reloadRequiredIfError()) {
try {
// Reload requires manual boot
$this->getApplication()->getKernel()->boot(false);
} finally {
// Given we're in an error state here, try to continue even if the kernel boot fails
$result = $confirmationTokenChain->reloadWithTokens();
$result->output();
}
}
})
->execute();
@ -75,10 +98,10 @@ class ErrorControlChainMiddleware implements HTTPMiddleware
* or authentication is impossible.
*
* @param HTTPRequest $request
* @param ParameterConfirmationToken $reloadToken
* @param ConfirmationTokenChain $confirmationTokenChain
* @return HTTPResponse
*/
protected function safeReloadWithToken(HTTPRequest $request, $reloadToken)
protected function safeReloadWithTokens(HTTPRequest $request, ConfirmationTokenChain $confirmationTokenChain)
{
// Safe reload requires manual boot
$this->getApplication()->getKernel()->boot(false);
@ -87,9 +110,9 @@ class ErrorControlChainMiddleware implements HTTPMiddleware
$request->getSession()->init($request);
// Request with ErrorDirector
$result = ErrorDirector::singleton()->handleRequestWithToken(
$result = ErrorDirector::singleton()->handleRequestWithTokenChain(
$request,
$reloadToken,
$confirmationTokenChain,
$this->getApplication()->getKernel()
);
if ($result) {
@ -97,8 +120,8 @@ class ErrorControlChainMiddleware implements HTTPMiddleware
}
// Fail and redirect the user to the login page
$params = array_merge($request->getVars(), $reloadToken->params(false));
$backURL = $request->getURL() . '?' . http_build_query($params);
$params = array_merge($request->getVars(), $confirmationTokenChain->params(false));
$backURL = $confirmationTokenChain->getRedirectUrlBase() . '?' . http_build_query($params);
$loginPage = Director::absoluteURL(Security::config()->get('login_url'));
$loginPage .= "?BackURL=" . urlencode($backURL);
$result = new HTTPResponse();

View File

@ -21,18 +21,21 @@ class ErrorDirector extends Director
* Redirect with token if allowed, or null if not allowed
*
* @param HTTPRequest $request
* @param ParameterConfirmationToken $token
* @param ConfirmationTokenChain $confirmationTokenChain
* @param Kernel $kernel
* @return null|HTTPResponse Redirection response, or null if not able to redirect
*/
public function handleRequestWithToken(HTTPRequest $request, ParameterConfirmationToken $token, Kernel $kernel)
{
public function handleRequestWithTokenChain(
HTTPRequest $request,
ConfirmationTokenChain $confirmationTokenChain,
Kernel $kernel
) {
Injector::inst()->registerService($request, HTTPRequest::class);
// Next, check if we're in dev mode, or the database doesn't have any security data, or we are admin
$reload = function (HTTPRequest $request) use ($token, $kernel) {
$reload = function (HTTPRequest $request) use ($confirmationTokenChain, $kernel) {
if ($kernel->getEnvironment() === Kernel::DEV || !Security::database_is_ready() || Permission::check('ADMIN')) {
return $token->reloadWithToken();
return $confirmationTokenChain->reloadWithTokens();
}
return null;
};

View File

@ -3,24 +3,21 @@
namespace SilverStripe\Core\Startup;
use SilverStripe\Control\Controller;
use SilverStripe\Control\Director;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Convert;
use SilverStripe\Security\RandomGenerator;
/**
* Class ParameterConfirmationToken
* This is used to protect dangerous GET parameters that need to be detected early in the request
* lifecycle by generating a one-time-use token & redirecting with that token included in the
* redirected URL
*
* When you need to use a dangerous GET parameter that needs to be set before core/Core.php is
* established, this class takes care of allowing some other code of confirming the parameter,
* by generating a one-time-use token & redirecting with that token included in the redirected URL
*
* WARNING: This class is experimental and designed specifically for use pre-startup.
* It will likely be heavily refactored before the release of 3.2
* @internal This class is designed specifically for use pre-startup and may change without warning
*/
class ParameterConfirmationToken
class ParameterConfirmationToken extends AbstractConfirmationToken
{
/**
* The name of the parameter
*
@ -28,11 +25,6 @@ class ParameterConfirmationToken
*/
protected $parameterName = null;
/**
* @var HTTPRequest
*/
protected $request = null;
/**
* The parameter given in the main request
*
@ -48,60 +40,6 @@ class ParameterConfirmationToken
protected $parameterBackURL = null;
/**
* The validated and checked token for this parameter
*
* @var string|null A string value, or null if either not provided or invalid
*/
protected $token = null;
protected function pathForToken($token)
{
return TEMP_PATH . DIRECTORY_SEPARATOR . 'token_' . preg_replace('/[^a-z0-9]+/', '', $token);
}
/**
* Generate a new random token and store it
*
* @return string Token name
*/
protected function genToken()
{
// Generate a new random token (as random as possible)
$rg = new RandomGenerator();
$token = $rg->randomToken('md5');
// Store a file in the session save path (safer than /tmp, as open_basedir might limit that)
file_put_contents($this->pathForToken($token), $token);
return $token;
}
/**
* Validate a token
*
* @param string $token
* @return boolean True if the token is valid
*/
protected function checkToken($token)
{
if (!$token) {
return false;
}
$file = $this->pathForToken($token);
$content = null;
if (file_exists($file)) {
$content = file_get_contents($file);
unlink($file);
}
return $content == $token;
}
/**
* Create a new ParameterConfirmationToken
*
* @param string $parameterName Name of the querystring parameter to check
* @param HTTPRequest $request
*/
@ -176,54 +114,23 @@ class ParameterConfirmationToken
return $this->parameterBackURL !== null;
}
/**
* Is the necessary token provided for this parameter?
* A value must be provided for the token
*
* @return bool
*/
public function tokenProvided()
{
return !empty($this->token);
}
/**
* Is this parameter requested without a valid token?
*
* @return bool True if the parameter is given without a valid token
*/
public function reloadRequired()
{
return $this->parameterProvided() && !$this->tokenProvided();
}
/**
* Check if this token is provided either in the backurl, or directly,
* but without a token
*
* @return bool
*/
public function reloadRequiredIfError()
{
// Don't reload if token exists
return $this->reloadRequired() || $this->existsInReferer();
}
/**
* Suppress the current parameter by unsetting it from $_GET
*/
public function suppress()
{
unset($_GET[$this->parameterName]);
$this->request->offsetUnset($this->parameterName);
}
/**
* Determine the querystring parameters to include
*
* @param bool $includeToken Include the token value as well?
* @return array List of querystring parameters with name and token parameters
*/
public function params($includeToken = true)
{
$params = array(
@ -235,80 +142,21 @@ class ParameterConfirmationToken
return $params;
}
/**
* Get redirect url, excluding querystring
*
* @return string
*/
protected function currentURL()
public function getRedirectUrlBase()
{
return Controller::join_links(
BASE_URL ?: '/',
$this->request->getURL(false)
);
return ($this->existsInReferer() && !$this->parameterProvided()) ? Director::baseURL() : $this->currentURL();
}
public function getRedirectUrlParams()
{
return ($this->existsInReferer() && !$this->parameterProvided())
? $this->params()
: array_merge($this->request->getVars(), $this->params());
}
/**
* Get redirection URL
*
* @return string
*/
protected function redirectURL()
{
// If url is encoded via BackURL, defer to home page (prevent redirect to form action)
if ($this->existsInReferer() && !$this->parameterProvided()) {
$url = BASE_URL ?: '/';
$params = $this->params();
} else {
$url = $this->currentURL();
$params = array_merge($this->request->getVars(), $this->params());
}
// Merge get params with current url
return Controller::join_links($url, '?' . http_build_query($params));
}
/**
* Forces a reload of the request with the token included
*
* @return HTTPResponse
*/
public function reloadWithToken()
{
$location = $this->redirectURL();
$locationJS = Convert::raw2js($location);
$locationATT = Convert::raw2att($location);
$body = <<<HTML
<script>location.href='$locationJS';</script>
<noscript><meta http-equiv="refresh" content="0; url=$locationATT"></noscript>
You are being redirected. If you are not redirected soon, <a href="$locationATT">click here to continue the flush</a>
HTML;
// Build response
$result = new HTTPResponse($body);
$result->redirect($location);
return $result;
}
/**
* Given a list of token names, suppress all tokens that have not been validated, and
* return the non-validated token with the highest priority
*
* @param array $keys List of token keys in ascending priority (low to high)
* @param HTTPRequest $request
* @return ParameterConfirmationToken The token container for the unvalidated $key given with the highest priority
*/
public static function prepare_tokens($keys, HTTPRequest $request)
{
$target = null;
foreach ($keys as $key) {
$token = new ParameterConfirmationToken($key, $request);
// Validate this token
if ($token->reloadRequired() || $token->reloadRequiredIfError()) {
$token->suppress();
$target = $token;
}
}
return $target;
$query = http_build_query($this->getRedirectUrlParams());
return Controller::join_links($this->getRedirectUrlBase(), '?' . $query);
}
}

View File

@ -0,0 +1,139 @@
<?php
namespace SilverStripe\Core\Startup;
use SilverStripe\Control\Controller;
use SilverStripe\Control\Director;
use SilverStripe\Control\HTTPRequest;
/**
* This is used to protect dangerous URLs that need to be detected early in the request lifecycle
* by generating a one-time-use token & redirecting with that token included in the redirected URL
*
* @internal This class is designed specifically for use pre-startup and may change without warning
*/
class URLConfirmationToken extends AbstractConfirmationToken
{
/**
* @var string
*/
protected $urlToCheck;
/**
* @var string
*/
protected $currentURL;
/**
* @var string
*/
protected $tokenParameterName;
/**
* @var bool
*/
protected $urlExistsInBackURL;
/**
* @param string $urlToCheck URL to check
* @param HTTPRequest $request
*/
public function __construct($urlToCheck, HTTPRequest $request)
{
$this->urlToCheck = $urlToCheck;
$this->request = $request;
$this->currentURL = $request->getURL(false);
$this->tokenParameterName = preg_replace('/[^a-z0-9]/i', '', $urlToCheck) . 'token';
$this->urlExistsInBackURL = $this->getURLExistsInBackURL($request);
// If the token provided is valid, mark it as such
$token = $request->getVar($this->tokenParameterName);
if ($this->checkToken($token)) {
$this->token = $token;
}
}
/**
* @param HTTPRequest $request
* @return bool
*/
protected function getURLExistsInBackURL(HTTPRequest $request)
{
$backURL = ltrim($request->getVar('BackURL'), '/');
return (strpos($backURL, $this->urlToCheck) === 0);
}
/**
* @return bool
*/
protected function urlMatches()
{
return ($this->currentURL === $this->urlToCheck);
}
/**
* @return string
*/
public function getURLToCheck()
{
return $this->urlToCheck;
}
/**
* @return bool
*/
public function urlExistsInBackURL()
{
return $this->urlExistsInBackURL;
}
public function reloadRequired()
{
return $this->urlMatches() && !$this->tokenProvided();
}
public function reloadRequiredIfError()
{
return $this->reloadRequired() || $this->urlExistsInBackURL();
}
public function suppress()
{
$_SERVER['REQUEST_URI'] = '/';
$this->request->setURL('/');
}
public function params($includeToken = true)
{
$params = [];
if ($includeToken) {
$params[$this->tokenParameterName] = $this->genToken();
}
return $params;
}
public function currentURL()
{
return Controller::join_links(Director::baseURL(), $this->currentURL);
}
public function getRedirectUrlBase()
{
return ($this->urlExistsInBackURL && !$this->urlMatches()) ? Director::baseURL() : $this->currentURL();
}
public function getRedirectUrlParams()
{
return ($this->urlExistsInBackURL && !$this->urlMatches())
? $this->params()
: array_merge($this->request->getVars(), $this->params());
}
protected function redirectURL()
{
$query = http_build_query($this->getRedirectUrlParams());
return Controller::join_links($this->getRedirectUrlBase(), '?' . $query);
}
}

View File

@ -26,6 +26,7 @@ class Backtrace
array('PDO', '__construct'),
array('mysqli', 'mysqli'),
array('mysqli', 'select_db'),
array('mysqli', 'real_connect'),
array('SilverStripe\\ORM\\DB', 'connect'),
array('SilverStripe\\Security\\Security', 'check_default_admin'),
array('SilverStripe\\Security\\Security', 'encrypt_password'),

View File

@ -0,0 +1,185 @@
<?php
namespace SilverStripe\Core\Tests\Startup;
use SilverStripe\Core\Startup\ConfirmationTokenChain;
use SilverStripe\Core\Startup\ParameterConfirmationToken;
use SilverStripe\Core\Startup\URLConfirmationToken;
use SilverStripe\Dev\SapphireTest;
class ConfirmationTokenChainTest extends SapphireTest
{
protected function getTokenRequiringReload($requiresReload = true, $extraMethods = [])
{
$methods = array_merge(['reloadRequired'], $extraMethods);
$mock = $this->createPartialMock(ParameterConfirmationToken::class, $methods);
$mock->expects($this->any())
->method('reloadRequired')
->will($this->returnValue($requiresReload));
return $mock;
}
protected function getTokenRequiringReloadIfError($requiresReload = true, $extraMethods = [])
{
$methods = array_merge(['reloadRequired', 'reloadRequiredIfError'], $extraMethods);
$mock = $this->createPartialMock(ParameterConfirmationToken::class, $methods);
$mock->expects($this->any())
->method('reloadRequired')
->will($this->returnValue(false));
$mock->expects($this->any())
->method('reloadRequiredIfError')
->will($this->returnValue($requiresReload));
return $mock;
}
public function testFilteredTokens()
{
$chain = new ConfirmationTokenChain();
$chain->pushToken($tokenRequiringReload = $this->getTokenRequiringReload());
$chain->pushToken($tokenNotRequiringReload = $this->getTokenRequiringReload(false));
$chain->pushToken($tokenRequiringReloadIfError = $this->getTokenRequiringReloadIfError());
$chain->pushToken($tokenNotRequiringReloadIfError = $this->getTokenRequiringReloadIfError(false));
$reflectionMethod = new \ReflectionMethod(ConfirmationTokenChain::class, 'filteredTokens');
$reflectionMethod->setAccessible(true);
$tokens = iterator_to_array($reflectionMethod->invoke($chain));
$this->assertContains($tokenRequiringReload, $tokens, 'Token requiring a reload was not returned');
$this->assertNotContains($tokenNotRequiringReload, $tokens, 'Token not requiring a reload was returned');
$this->assertContains($tokenRequiringReloadIfError, $tokens, 'Token requiring a reload on error was not returned');
$this->assertNotContains($tokenNotRequiringReloadIfError, $tokens, 'Token not requiring a reload on error was returned');
}
public function testSuppressionRequired()
{
$chain = new ConfirmationTokenChain();
$chain->pushToken($this->getTokenRequiringReload(false));
$this->assertFalse($chain->suppressionRequired(), 'Suppression incorrectly marked as required');
$chain = new ConfirmationTokenChain();
$chain->pushToken($this->getTokenRequiringReloadIfError(false));
$this->assertFalse($chain->suppressionRequired(), 'Suppression incorrectly marked as required');
$chain = new ConfirmationTokenChain();
$chain->pushToken($this->getTokenRequiringReload());
$this->assertTrue($chain->suppressionRequired(), 'Suppression not marked as required');
$chain = new ConfirmationTokenChain();
$chain->pushToken($this->getTokenRequiringReloadIfError());
$this->assertFalse($chain->suppressionRequired(), 'Suppression incorrectly marked as required');
}
public function testSuppressTokens()
{
$mockToken = $this->getTokenRequiringReload(true, ['suppress']);
$mockToken->expects($this->once())
->method('suppress');
$secondMockToken = $this->getTokenRequiringReloadIfError(true, ['suppress']);
$secondMockToken->expects($this->once())
->method('suppress');
$chain = new ConfirmationTokenChain();
$chain->pushToken($mockToken);
$chain->pushToken($secondMockToken);
$chain->suppressTokens();
}
public function testReloadRequired()
{
$mockToken = $this->getTokenRequiringReload(true);
$secondMockToken = $this->getTokenRequiringReload(false);
$chain = new ConfirmationTokenChain();
$chain->pushToken($mockToken);
$chain->pushToken($secondMockToken);
$this->assertTrue($chain->reloadRequired());
}
public function testReloadRequiredIfError()
{
$mockToken = $this->getTokenRequiringReloadIfError(true);
$secondMockToken = $this->getTokenRequiringReloadIfError(false);
$chain = new ConfirmationTokenChain();
$chain->pushToken($mockToken);
$chain->pushToken($secondMockToken);
$this->assertTrue($chain->reloadRequiredIfError());
}
public function testParams()
{
$mockToken = $this->getTokenRequiringReload(true, ['params']);
$mockToken->expects($this->once())
->method('params')
->with($this->isTrue())
->will($this->returnValue(['mockTokenParam' => '1']));
$secondMockToken = $this->getTokenRequiringReload(true, ['params']);
$secondMockToken->expects($this->once())
->method('params')
->with($this->isTrue())
->will($this->returnValue(['secondMockTokenParam' => '2']));
$chain = new ConfirmationTokenChain();
$chain->pushToken($mockToken);
$chain->pushToken($secondMockToken);
$this->assertEquals(['mockTokenParam' => '1', 'secondMockTokenParam' => '2'], $chain->params(true));
$mockToken = $this->getTokenRequiringReload(true, ['params']);
$mockToken->expects($this->once())
->method('params')
->with($this->isFalse())
->will($this->returnValue(['mockTokenParam' => '1']));
$chain = new ConfirmationTokenChain();
$chain->pushToken($mockToken);
$this->assertEquals(['mockTokenParam' => '1'], $chain->params(false));
}
public function testGetRedirectUrlBase()
{
$mockUrlToken = $this->createPartialMock(URLConfirmationToken::class, ['reloadRequired', 'getRedirectUrlBase']);
$mockUrlToken->expects($this->any())
->method('reloadRequired')
->will($this->returnValue(true));
$mockUrlToken->expects($this->any())
->method('getRedirectUrlBase')
->will($this->returnValue('url-base'));
$mockParameterToken = $this->createPartialMock(ParameterConfirmationToken::class, ['reloadRequired', 'getRedirectUrlBase']);
$mockParameterToken->expects($this->any())
->method('reloadRequired')
->will($this->returnValue(true));
$mockParameterToken->expects($this->any())
->method('getRedirectUrlBase')
->will($this->returnValue('parameter-base'));
$chain = new ConfirmationTokenChain();
$chain->pushToken($mockParameterToken);
$chain->pushToken($mockUrlToken);
$this->assertEquals('url-base', $chain->getRedirectUrlBase(), 'URLConfirmationToken url base should take priority');
// Push them in reverse order to check priority still correct
$chain = new ConfirmationTokenChain();
$chain->pushToken($mockUrlToken);
$chain->pushToken($mockParameterToken);
$this->assertEquals('url-base', $chain->getRedirectUrlBase(), 'URLConfirmationToken url base should take priority');
}
public function testGetRedirectUrlParams()
{
$mockToken = $this->getTokenRequiringReload(true, ['getRedirectUrlParams']);
$mockToken->expects($this->once())
->method('getRedirectUrlParams')
->will($this->returnValue(['mockTokenParam' => '1']));
$secondMockToken = $this->getTokenRequiringReload(true, ['getRedirectUrlParams']);
$secondMockToken->expects($this->once())
->method('getRedirectUrlParams')
->will($this->returnValue(['secondMockTokenParam' => '2']));
$chain = new ConfirmationTokenChain();
$chain->pushToken($mockToken);
$chain->pushToken($secondMockToken);
$this->assertEquals(['mockTokenParam' => '1', 'secondMockTokenParam' => '2'], $chain->getRedirectUrlParams());
}
}

View File

@ -73,4 +73,104 @@ class ErrorControlChainMiddlewareTest extends SapphireTest
$this->assertNotContains('?flush=1&flushtoken=', $location);
$this->assertContains('Security/login', $location);
}
public function testLiveBuildAdmin()
{
// Mock admin
$adminID = $this->logInWithPermission('ADMIN');
$this->logOut();
// Mock app
$app = new HTTPApplication(new BlankKernel(BASE_PATH));
$app->getKernel()->setEnvironment(Kernel::LIVE);
// Test being logged in as admin
$chain = new ErrorControlChainMiddleware($app);
$request = new HTTPRequest('GET', '/dev/build/');
$request->setSession(new Session(['loggedInAs' => $adminID]));
$result = $chain->process($request, function () {
return null;
});
$this->assertInstanceOf(HTTPResponse::class, $result);
$location = $result->getHeader('Location');
$this->assertContains('/dev/build', $location);
$this->assertContains('?devbuildtoken=', $location);
$this->assertNotContains('Security/login', $location);
}
public function testLiveBuildUnauthenticated()
{
// Mock app
$app = new HTTPApplication(new BlankKernel(BASE_PATH));
$app->getKernel()->setEnvironment(Kernel::LIVE);
// Test being logged in as no one
Security::setCurrentUser(null);
$chain = new ErrorControlChainMiddleware($app);
$request = new HTTPRequest('GET', '/dev/build');
$request->setSession(new Session(['loggedInAs' => 0]));
$result = $chain->process($request, function () {
return null;
});
// Should be directed to login, not to flush
$this->assertInstanceOf(HTTPResponse::class, $result);
$location = $result->getHeader('Location');
$this->assertNotContains('/dev/build', $location);
$this->assertNotContains('?devbuildtoken=', $location);
$this->assertContains('Security/login', $location);
}
public function testLiveBuildAndFlushAdmin()
{
// Mock admin
$adminID = $this->logInWithPermission('ADMIN');
$this->logOut();
// Mock app
$app = new HTTPApplication(new BlankKernel(BASE_PATH));
$app->getKernel()->setEnvironment(Kernel::LIVE);
// Test being logged in as admin
$chain = new ErrorControlChainMiddleware($app);
$request = new HTTPRequest('GET', '/dev/build/', ['flush' => '1']);
$request->setSession(new Session(['loggedInAs' => $adminID]));
$result = $chain->process($request, function () {
return null;
});
$this->assertInstanceOf(HTTPResponse::class, $result);
$location = $result->getHeader('Location');
$this->assertContains('/dev/build', $location);
$this->assertContains('flush=1', $location);
$this->assertContains('devbuildtoken=', $location);
$this->assertContains('flushtoken=', $location);
$this->assertNotContains('Security/login', $location);
}
public function testLiveBuildAndFlushUnauthenticated()
{
// Mock app
$app = new HTTPApplication(new BlankKernel(BASE_PATH));
$app->getKernel()->setEnvironment(Kernel::LIVE);
// Test being logged in as no one
Security::setCurrentUser(null);
$chain = new ErrorControlChainMiddleware($app);
$request = new HTTPRequest('GET', '/dev/build', ['flush' => '1']);
$request->setSession(new Session(['loggedInAs' => 0]));
$result = $chain->process($request, function () {
return null;
});
// Should be directed to login, not to flush
$this->assertInstanceOf(HTTPResponse::class, $result);
$location = $result->getHeader('Location');
$this->assertNotContains('/dev/build', $location);
$this->assertNotContains('flush=1', $location);
$this->assertNotContains('devbuildtoken=', $location);
$this->assertNotContains('flushtoken=', $location);
$this->assertContains('Security/login', $location);
}
}

View File

@ -149,14 +149,14 @@ class ParameterConfirmationTokenTest extends SapphireTest
}
/**
* currentAbsoluteURL needs to handle base or url being missing, or any combination of slashes.
* currentURL needs to handle base or url being missing, or any combination of slashes.
*
* There should always be exactly one slash between each part in the result, and any trailing slash
* should be preserved.
*
* @dataProvider dataProviderURLs
*/
public function testCurrentAbsoluteURLHandlesSlashes($url)
public function testCurrentURLHandlesSlashes($url)
{
$this->request->setUrl($url);

View File

@ -0,0 +1,148 @@
<?php
namespace SilverStripe\Core\Tests\Startup;
use SilverStripe\Control\Controller;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\Session;
use SilverStripe\Core\Startup\URLConfirmationToken;
use SilverStripe\Core\Tests\Startup\URLConfirmationTokenTest\StubToken;
use SilverStripe\Core\Tests\Startup\URLConfirmationTokenTest\StubValidToken;
use SilverStripe\Dev\SapphireTest;
class URLConfirmationTokenTest extends SapphireTest
{
public function testValidToken()
{
$request = new HTTPRequest('GET', 'token/test/url', ['tokentesturltoken' => 'value']);
$validToken = new StubValidToken('token/test/url', $request);
$this->assertTrue($validToken->urlMatches());
$this->assertFalse($validToken->urlExistsInBackURL());
$this->assertTrue($validToken->tokenProvided()); // Actually forced to true for this test
$this->assertFalse($validToken->reloadRequired());
$this->assertFalse($validToken->reloadRequiredIfError());
$this->assertStringStartsWith(Controller::join_links(BASE_URL, '/', 'token/test/url'), $validToken->redirectURL());
}
public function testTokenWithLeadingSlashInUrl()
{
$request = new HTTPRequest('GET', '/leading/slash/url', []);
$leadingSlash = new StubToken('leading/slash/url', $request);
$this->assertTrue($leadingSlash->urlMatches());
$this->assertFalse($leadingSlash->urlExistsInBackURL());
$this->assertFalse($leadingSlash->tokenProvided());
$this->assertTrue($leadingSlash->reloadRequired());
$this->assertTrue($leadingSlash->reloadRequiredIfError());
$this->assertContains('leading/slash/url', $leadingSlash->redirectURL());
$this->assertContains('leadingslashurltoken', $leadingSlash->redirectURL());
}
public function testTokenWithTrailingSlashInUrl()
{
$request = new HTTPRequest('GET', 'trailing/slash/url/', []);
$trailingSlash = new StubToken('trailing/slash/url', $request);
$this->assertTrue($trailingSlash->urlMatches());
$this->assertFalse($trailingSlash->urlExistsInBackURL());
$this->assertFalse($trailingSlash->tokenProvided());
$this->assertTrue($trailingSlash->reloadRequired());
$this->assertTrue($trailingSlash->reloadRequiredIfError());
$this->assertContains('trailing/slash/url', $trailingSlash->redirectURL());
$this->assertContains('trailingslashurltoken', $trailingSlash->redirectURL());
}
public function testTokenWithUrlMatchedInBackUrl()
{
$request = new HTTPRequest('GET', '/', ['BackURL' => 'back/url']);
$backUrl = new StubToken('back/url', $request);
$this->assertFalse($backUrl->urlMatches());
$this->assertTrue($backUrl->urlExistsInBackURL());
$this->assertFalse($backUrl->tokenProvided());
$this->assertFalse($backUrl->reloadRequired());
$this->assertTrue($backUrl->reloadRequiredIfError());
$home = (BASE_URL ?: '/') . '?';
$this->assertStringStartsWith($home, $backUrl->redirectURL());
$this->assertContains('backurltoken', $backUrl->redirectURL());
}
public function testUrlSuppressionWhenTokenMissing()
{
// Check suppression
$request = new HTTPRequest('GET', 'test/url', []);
$token = new StubToken('test/url', $request);
$this->assertEquals('test/url', $request->getURL(false));
$token->suppress();
$this->assertEquals('', $request->getURL(false));
}
public function testPrepareTokens()
{
$request = new HTTPRequest('GET', 'test/url', []);
$token = URLConfirmationToken::prepare_tokens(
[
'test/url',
'test',
'url'
],
$request
);
// Test no invalid tokens
$this->assertEquals('test/url', $token->getURLToCheck());
$this->assertNotEquals('test/url', $request->getURL(false), 'prepare_tokens() did not suppress URL');
}
public function testPrepareTokensDoesntSuppressWhenNotMatched()
{
$request = new HTTPRequest('GET', 'test/url', []);
$token = URLConfirmationToken::prepare_tokens(
['another/url'],
$request
);
$this->assertEmpty($token);
$this->assertEquals('test/url', $request->getURL(false), 'prepare_tokens() incorrectly suppressed URL');
}
public function testPrepareTokensWithUrlMatchedInBackUrl()
{
// Test backurl token
$request = new HTTPRequest('GET', '/', ['BackURL' => 'back/url']);
$token = URLConfirmationToken::prepare_tokens(
[ 'back/url' ],
$request
);
$this->assertNotEmpty($token);
$this->assertEquals('back/url', $token->getURLToCheck());
$this->assertNotEquals('back/url', $request->getURL(false), 'prepare_tokens() did not suppress URL');
}
public function dataProviderURLs()
{
return [
[''],
['/'],
['bar'],
['bar/'],
['/bar'],
['/bar/'],
];
}
/**
* currentURL needs to handle base or url being missing, or any combination of slashes.
*
* There should always be exactly one slash between each part in the result, and any trailing slash
* should be preserved.
*
* @dataProvider dataProviderURLs
*/
public function testCurrentURLHandlesSlashes($url)
{
$request = new HTTPRequest('GET', $url, []);
$token = new StubToken(
'another/url',
$request
);
$expected = rtrim(Controller::join_links(BASE_URL, '/', $url), '/') ?: '/';
$this->assertEquals($expected, $token->currentURL(), "Invalid redirect for request url $url");
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace SilverStripe\Core\Tests\Startup\URLConfirmationTokenTest;
use SilverStripe\Core\Startup\URLConfirmationToken;
use SilverStripe\Dev\TestOnly;
/**
* Dummy url token
*/
class StubToken extends URLConfirmationToken implements TestOnly
{
public function urlMatches()
{
return parent::urlMatches();
}
public function currentURL()
{
return parent::currentURL();
}
public function redirectURL()
{
return parent::redirectURL();
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace SilverStripe\Core\Tests\Startup\URLConfirmationTokenTest;
/**
* A token that always validates a given token
*/
class StubValidToken extends StubToken
{
protected function checkToken($token)
{
return true;
}
}