If you did not request this password reset, please ignore this email.
-
Thank you.
]]>
-
-
+
+ <p>Password Reset Request!</p>
+<p>Hello! A password reset has been requested for your account.</p>
+<p>Please use the following token to reset your password:</p>
+<p><a href="%confirmation_link%">Reset Password</a></p>
+<p>If you did not request this password reset, please ignore this email.</p>
+<p>Thank you.</p>
+ Password Reset Request!
Hello! A password reset has been requested for your account.
Please use the following token to reset your password:
If you did not request this password reset, please ignore this email.
Thank you.
- ]]>
-
-
-
-
- Please confirm your subscription
- Please confirm your subscription
-
-
-
- Thank you for subscribing!
+
+ ]]>
+
+
+ Request for confirmation
+ Request for confirmation
+
+
+ Thank you for subscribing!
Please confirm your subscription by clicking the link below:
@@ -92,7 +85,7 @@
If you did not request this subscription, please ignore this email.
- Thank you for subscribing!
+ Thank you for subscribing!
Please confirm your subscription by clicking the link below:
@@ -100,351 +93,597 @@
If you did not request this subscription, please ignore this email.
-
-
-
- Thank you for subscribing!
-
Please confirm your subscription by clicking the link below:
If you did not request this subscription, please ignore this email.
]]>
+
+
+ <p>Thank you for subscribing!</p>
+<p>Please confirm your subscription by clicking the link below:</p>
+<p><a href="%confirmation_link%">Confirm Subscription</a></p>
+<p>If you did not request this subscription, please ignore this email.</p>
- Thank you for subscribing!
+ Thank you for subscribing!
Please confirm your subscription by clicking the link below:
If you did not request this subscription, please ignore this email.
]]>
-
-
-
-
-
- PHP IMAP extension not available. Falling back to Webklex IMAP.
- PHP IMAP extension not available. Falling back to Webklex IMAP.
-
-
-
- Could not apply force lock. Aborting.
- Could not apply force lock. Aborting.
-
-
-
- Another bounce processing is already running. Aborting.
- Another bounce processing is already running. Aborting.
-
-
-
- Queue is already being processed by another instance.
- Queue is already being processed by another instance.
-
-
-
- The system is in maintenance mode, stopping. Try again later.
- The system is in maintenance mode, stopping. Try again later.
-
-
-
- Bounce processing completed.
- Bounce processing completed.
-
-
-
- Recipient email address not provided
- Recipient email address not provided
-
-
-
- Invalid email address: %email%
- Invalid email address: %email%
-
-
-
- Sending test email synchronously to %email%
- Sending test email synchronously to %email%
-
-
-
- Queuing test email for %email%
- Queuing test email for %email%
-
-
-
- Test email sent successfully!
- Test email sent successfully!
-
-
-
- Test email queued successfully! It will be sent asynchronously.
- Test email queued successfully! It will be sent asynchronously.
-
-
-
- Failed to send test email: %error%
- Failed to send test email: %error%
-
-
-
- Email address auto blacklisted by bounce rule %rule_id%
- Email address auto blacklisted by bounce rule %rule_id%
-
-
-
- Auto Unsubscribed
- Auto Unsubscribed
-
-
-
- User auto unsubscribed for bounce rule %rule_id%
- User auto unsubscribed for bounce rule %rule_id%
-
-
-
- email auto unsubscribed for bounce rule %rule_id%
- email auto unsubscribed for bounce rule %rule_id%
-
-
-
- Subscriber auto blacklisted by bounce rule %rule_id%
- Subscriber auto blacklisted by bounce rule %rule_id%
-
-
-
- User auto unsubscribed for bounce rule %%rule_id%
- User auto unsubscribed for bounce rule %%rule_id%
-
-
-
- Auto confirmed
- Auto confirmed
-
-
-
- Auto unconfirmed
- Auto unconfirmed
-
-
-
- Subscriber auto confirmed for bounce rule %rule_id%
- Subscriber auto confirmed for bounce rule %rule_id%
-
-
-
- Requeued campaign; next embargo at %time%
- Requeued campaign; next embargo at %time%
-
-
-
- Subscriber auto unconfirmed for bounce rule %rule_id%
- Subscriber auto unconfirmed for bounce rule %rule_id%
-
-
-
- Running in test mode, not deleting messages from mailbox
- Running in test mode, not deleting messages from mailbox
-
-
-
- Processed messages will be deleted from the mailbox
- Processed messages will be deleted from the mailbox
-
-
-
- Processing bounces based on active bounce rules
- Processing bounces based on active bounce rules
-
-
-
- No active rules
- No active rules
-
-
-
- Processed %processed% out of %total% bounces for advanced bounce rules
- Processed %processed% out of %total% bounces for advanced bounce rules
-
-
-
- %processed% bounces processed by advanced processing
- %processed% bounces processed by advanced processing
-
-
- %not_processed% bounces were not matched by advanced processing rules
- %not_processed% bounces were not matched by advanced processing rules
-
-
-
- Opening mbox %file%
- Opening mbox %file%
-
-
- Connecting to %mailbox%
- Connecting to %mailbox%
-
-
- Please do not interrupt this process
- Please do not interrupt this process
-
-
- mbox file path must be provided with --mailbox.
- mbox file path must be provided with --mailbox.
-
-
-
- Invalid email, marking unconfirmed: %email%
- Invalid email, marking unconfirmed: %email%
-
-
- Failed to send to: %email%
- Failed to send to: %email%
-
-
-
- Reprocessing unidentified bounces
- Reprocessing unidentified bounces
-
-
- %total% bounces to reprocess
- %total% bounces to reprocess
-
-
- %count% out of %total% processed
- %count% out of %total% processed
-
-
- %reparsed% bounces were re-processed and %reidentified% bounces were re-identified
- %reparsed% bounces were re-processed and %reidentified% bounces were re-identified
-
-
-
- Identifying consecutive bounces
- Identifying consecutive bounces
-
-
- Nothing to do
- Nothing to do
-
-
- Processed %processed% out of %total% subscribers
- Processed %processed% out of %total% subscribers
-
-
- Total of %total% subscribers processed
- Total of %total% subscribers processed
-
-
- Subscriber auto unconfirmed for %count% consecutive bounces
- Subscriber auto unconfirmed for %count% consecutive bounces
-
-
- %count% consecutive bounces, threshold reached
- %count% consecutive bounces, threshold reached
-
-
-
- Reached max processing time; stopping cleanly.
- Reached max processing time; stopping cleanly.
-
-
-
- Giving a UUID to %count% subscribers, this may take a while
- Giving a UUID to %count% subscribers, this may take a while
-
-
- Giving a UUID to %count% campaigns
- Giving a UUID to %count% campaigns
-
-
-
- Batch limit reached, sleeping %sleep%s to respect MAILQUEUE_BATCH_PERIOD
- Batch limit reached, sleeping %sleep%s to respect MAILQUEUE_BATCH_PERIOD
-
-
-
- Value must be an array of image URLs.
- Value must be an array of image URLs.
-
-
- Image "%url%" is not a full URL.
- Image "%url%" is not a full URL.
-
-
- Image "%url%" does not exist (HTTP %code%)
- Image "%url%" does not exist (HTTP %code%)
-
-
- Image "%url%" could not be validated: %message%
- Image "%url%" could not be validated: %message%
-
-
-
- Not full URLs: %urls%
- Not full URLs: %urls%
-
-
-
-
-
- Subscriber list not found.
- Subscriber list not found.
-
-
-
- Subscriber does not exists.
- Subscriber does not exists.
-
-
-
- Subscription not found for this subscriber and list.
- Subscription not found for this subscriber and list.
-
-
- Attribute definition already exists
- Attribute definition already exists
-
-
- Another attribute with this name already exists.
- Another attribute with this name already exists.
-
-
-
- Subscribe page not found
- Subscribe page not found
-
-
- Value is required
- Value is required
-
-
- Subscriber not found
- Subscriber not found
-
-
- Unexpected error: %error%
- Unexpected error: %error%
-
-
- Added to blacklist for reason %reason%
- Added to blacklist for reason %reason%
-
-
- Could not read the uploaded file.
- Could not read the uploaded file.
-
-
- Error processing %email%: %error%
- Error processing %email%: %error%
-
-
- General import error: %error%
- General import error: %error%
-
-
- Value must be a string.
- Value must be a string.
-
-
- Invalid attribute type: "%type%". Valid types are: %valid_types%
- Invalid attribute type: "%type%". Valid types are: %valid_types%
-
-
-
-
+
If you did not request this subscription, please ignore this email.
+ ]]>
+
+
+ PHP IMAP extension not available. Falling back to Webklex IMAP.
+ PHP IMAP extension not available. Falling back to Webklex IMAP.
+
+
+ Could not apply force lock. Aborting.
+ Could not apply force lock. Aborting.
+
+
+ Another bounce processing is already running. Aborting.
+ Another bounce processing is already running. Aborting.
+
+
+ Queue is already being processed by another instance.
+ Queue is already being processed by another instance.
+
+
+ The system is in maintenance mode, stopping. Try again later.
+ The system is in maintenance mode, stopping. Try again later.
+
+
+ Bounce processing completed.
+ Bounce processing completed.
+
+
+ Recipient email address not provided
+ Recipient email address not provided
+
+
+ Invalid email address: %email%
+ Invalid email address: %email%
+
+
+ Sending test email synchronously to %email%
+ Sending test email synchronously to %email%
+
+
+ Queuing test email for %email%
+ Queuing test email for %email%
+
+
+ Test email sent successfully!
+ Test email sent successfully!
+
+
+ Test email queued successfully! It will be sent asynchronously.
+ Test email queued successfully! It will be sent asynchronously.
+
+
+ Failed to send test email: %error%
+ Failed to send test email: %error%
+
+
+ Email address auto blacklisted by bounce rule %rule_id%
+ Email address auto blacklisted by bounce rule %rule_id%
+
+
+ Auto Unsubscribed
+ Auto Unsubscribed
+
+
+ User auto unsubscribed for bounce rule %rule_id%
+ User auto unsubscribed for bounce rule %rule_id%
+
+
+ email auto unsubscribed for bounce rule %rule_id%
+ email auto unsubscribed for bounce rule %rule_id%
+
+
+ Subscriber auto blacklisted by bounce rule %rule_id%
+ Subscriber auto blacklisted by bounce rule %rule_id%
+
+
+ User auto unsubscribed for bounce rule %%rule_id%
+ User auto unsubscribed for bounce rule %%rule_id%
+
+
+ Auto confirmed
+ Auto confirmed
+
+
+ Auto unconfirmed
+ Auto unconfirmed
+
+
+ Subscriber auto confirmed for bounce rule %rule_id%
+ Subscriber auto confirmed for bounce rule %rule_id%
+
+
+ Requeued campaign; next embargo at %time%
+ Requeued campaign; next embargo at %time%
+
+
+ Subscriber auto unconfirmed for bounce rule %rule_id%
+ Subscriber auto unconfirmed for bounce rule %rule_id%
+
+
+ Running in test mode, not deleting messages from mailbox
+ Running in test mode, not deleting messages from mailbox
+
+
+ Processed messages will be deleted from the mailbox
+ Processed messages will be deleted from the mailbox
+
+
+ Processing bounces based on active bounce rules
+ Processing bounces based on active bounce rules
+
+
+ No active rules
+ No active rules
+
+
+ Processed %processed% out of %total% bounces for advanced bounce rules
+ Processed %processed% out of %total% bounces for advanced bounce rules
+
+
+ %processed% bounces processed by advanced processing
+ %processed% bounces processed by advanced processing
+
+
+ %not_processed% bounces were not matched by advanced processing rules
+ %not_processed% bounces were not matched by advanced processing rules
+
+
+ Opening mbox %file%
+ Opening mbox %file%
+
+
+ Connecting to %mailbox%
+ Connecting to %mailbox%
+
+
+ Please do not interrupt this process
+ Please do not interrupt this process
+
+
+ mbox file path must be provided with --mailbox.
+ mbox file path must be provided with --mailbox.
+
+
+ Invalid email, marking unconfirmed: %email%
+ Invalid email, marking unconfirmed: %email%
+
+
+ Failed to send to: %email%
+ Failed to send to: %email%
+
+
+ Reprocessing unidentified bounces
+ Reprocessing unidentified bounces
+
+
+ %total% bounces to reprocess
+ %total% bounces to reprocess
+
+
+ %count% out of %total% processed
+ %count% out of %total% processed
+
+
+ %reparsed% bounces were re-processed and %reidentified% bounces were re-identified
+ %reparsed% bounces were re-processed and %reidentified% bounces were re-identified
+
+
+ Identifying consecutive bounces
+ Identifying consecutive bounces
+
+
+ Nothing to do
+ Nothing to do
+
+
+ Processed %processed% out of %total% subscribers
+ Processed %processed% out of %total% subscribers
+
+
+ Total of %total% subscribers processed
+ Total of %total% subscribers processed
+
+
+ Subscriber auto unconfirmed for %count% consecutive bounces
+ Subscriber auto unconfirmed for %count% consecutive bounces
+
+
+ %count% consecutive bounces, threshold reached
+ %count% consecutive bounces, threshold reached
+
+
+ Reached max processing time; stopping cleanly.
+ Reached max processing time; stopping cleanly.
+
+
+ Giving a UUID to %count% subscribers, this may take a while
+ Giving a UUID to %count% subscribers, this may take a while
+
+
+ Giving a UUID to %count% campaigns
+ Giving a UUID to %count% campaigns
+
+
+ Batch limit reached, sleeping %sleep%s to respect MAILQUEUE_BATCH_PERIOD
+ Batch limit reached, sleeping %sleep%s to respect MAILQUEUE_BATCH_PERIOD
+
+
+ Value must be an array of image URLs.
+ Value must be an array of image URLs.
+
+
+ Image "%url%" is not a full URL.
+ Image "%url%" is not a full URL.
+
+
+ Image "%url%" does not exist (HTTP %code%)
+ Image "%url%" does not exist (HTTP %code%)
+
+
+ Image "%url%" could not be validated: %message%
+ Image "%url%" could not be validated: %message%
+
+
+ Not full URLs: %urls%
+ Not full URLs: %urls%
+
+
+ Subscriber list not found.
+ Subscriber list not found.
+
+
+ Subscriber does not exists.
+ Subscriber does not exists.
+
+
+ Subscription not found for this subscriber and list.
+ Subscription not found for this subscriber and list.
+
+
+ Attribute definition already exists
+ Attribute definition already exists
+
+
+ Another attribute with this name already exists.
+ Another attribute with this name already exists.
+
+
+ Subscribe page not found
+ Subscribe page not found
+
+
+ Value is required
+ Value is required
+
+
+ Subscriber not found
+ Subscriber not found
+
+
+ Unexpected error: %error%
+ Unexpected error: %error%
+
+
+ Added to blacklist for reason %reason%
+ Added to blacklist for reason %reason%
+
+
+ Could not read the uploaded file.
+ Could not read the uploaded file.
+
+
+ Error processing %email%: %error%
+ Error processing %email%: %error%
+
+
+ General import error: %error%
+ General import error: %error%
+
+
+ Value must be a string.
+ Value must be a string.
+
+
+ Invalid attribute type: "%type%". Valid types are: %valid_types%
+ Invalid attribute type: "%type%". Valid types are: %valid_types%
+
+
+ Thank you for subscribing!
+
+Please confirm your subscription by clicking the link below:
+
+%confirmation_link%
+
+If you did not request this subscription, please ignore this email.
+ __Thank you for subscribing!
+
+Please confirm your subscription by clicking the link below:
+
+%confirmation_link%
+
+If you did not request this subscription, please ignore this email.
+
+
+ <p>Thank you for subscribing!</p><p>Please confirm your subscription by clicking the link below:</p><p><a href="%confirmation_link%">Confirm Subscription</a></p><p>If you did not request this subscription, please ignore this email.</p>
+ Thank you for subscribing!
Please confirm your subscription by clicking the link below:
If you did not request this subscription, please ignore this email.
]]>
+
+
+ Hello,
+
+A password reset has been requested for your account.
+Please use the following token to reset your password:
+
+%token%
+
+If you did not request this password reset, please ignore this email.
+
+Thank you.
+ __Hello,
+
+A password reset has been requested for your account.
+Please use the following token to reset your password:
+
+%token%
+
+If you did not request this password reset, please ignore this email.
+
+Thank you.
+
+
+ <p>Password Reset Request!</p><p>Hello! A password reset has been requested for your account.</p><p>Please use the following token to reset your password:</p><p><a href="%confirmation_link%">Reset Password</a></p><p>If you did not request this password reset, please ignore this email.</p><p>Thank you.</p>
+ Password Reset Request!
Hello! A password reset has been requested for your account.
Please use the following token to reset your password:
If you did not request this password reset, please ignore this email.
Thank you.
]]>
+
+
+ Person in charge of this system (one email address)
+ __Person in charge of this system (one email address)
+
+
+ Name of the organisation
+ __Name of the organisation
+
+
+ Logo of the organisation
+ __Logo of the organisation
+
+
+ Date format
+ __Date format
+
+
+ Show notification for Release Candidates
+ __Show notification for Release Candidates
+
+
+ Secret for remote processing
+ __Secret for remote processing
+
+
+ Notify admin on login from new location
+ __Notify admin on login from new location
+
+
+ List of email addresses to CC in system messages (separate by commas)
+ __List of email addresses to CC in system messages (separate by commas)
+
+
+ Default for 'From:' in a campaign
+ __Default for 'From:' in a campaign
+
+
+ Default for 'address to alert when sending starts'
+ __Default for 'address to alert when sending starts'
+
+
+ Default for 'address to alert when sending finishes'
+ __Default for 'address to alert when sending finishes'
+
+
+ Always add analytics tracking code to campaigns
+ __Always add analytics tracking code to campaigns
+
+
+ Analytics tracking code to add to campaign URLs
+ __Analytics tracking code to add to campaign URLs
+
+
+ Who gets the reports (email address, separate multiple emails with a comma)
+ __Who gets the reports (email address, separate multiple emails with a comma)
+
+
+ From email address for system messages
+ __From email address for system messages
+
+
+ Webmaster
+ __Webmaster
+
+
+ Name for system messages
+ __Name for system messages
+
+
+ Reply-to email address for system messages
+ __Reply-to email address for system messages
+
+
+ If there is only one visible list, should it be hidden in the page and automatically subscribe users who sign up
+ __If there is only one visible list, should it be hidden in the page and automatically subscribe users who sign up
+
+
+ Categories for lists. Separate with commas.
+ __Categories for lists. Separate with commas.
+
+
+ Display list categories on subscribe page
+ __Display list categories on subscribe page
+
+
+ Width of a textline field (numerical)
+ __Width of a textline field (numerical)
+
+
+ Dimensions of a textarea field (rows,columns)
+ __Dimensions of a textarea field (rows,columns)
+
+
+ Send notifications about subscribe, update and unsubscribe
+ __Send notifications about subscribe, update and unsubscribe
+
+
+ The default subscribe page when there are multiple
+ __The default subscribe page when there are multiple
+
+
+ The default HTML template to use when sending a message
+ __The default HTML template to use when sending a message
+
+
+ The HTML wrapper template for system messages
+ __The HTML wrapper template for system messages
+
+
+ URL where subscribers can sign up
+ __URL where subscribers can sign up
+
+
+ URL where subscribers can unsubscribe
+ __URL where subscribers can unsubscribe
+
+
+ URL where unknown users can unsubscribe (do-not-send-list)
+ __URL where unknown users can unsubscribe (do-not-send-list)
+
+
+ URL where subscribers have to confirm their subscription
+ __URL where subscribers have to confirm their subscription
+
+
+ URL where subscribers can update their details
+ __URL where subscribers can update their details
+
+
+ URL for forwarding messages
+ __URL for forwarding messages
+
+
+ URL for downloading vcf card
+ __URL for downloading vcf card
+
+
+ <h3>Thanks, you have been added to our newsletter</h3><p>You will receive an email to confirm your subscription. Please click the link in the email to confirm</p>
+ Thanks, you have been added to our newsletter
You will receive an email to confirm your subscription. Please click the link in the email to confirm
]]>
+
+
+ Text to display when subscription with an AJAX request was successful
+ __Text to display when subscription with an AJAX request was successful
+
+
+ Subject of the message subscribers receive when they sign up
+ __Subject of the message subscribers receive when they sign up
+
+
+ Message subscribers receive when they sign up
+ __Message subscribers receive when they sign up
+
+
+ Goodbye from our Newsletter
+ __Goodbye from our Newsletter
+
+
+ Subject of the message subscribers receive when they unsubscribe
+ __Subject of the message subscribers receive when they unsubscribe
+
+
+ Message subscribers receive when they unsubscribe
+ __Message subscribers receive when they unsubscribe
+
+
+ Welcome to our Newsletter
+ __Welcome to our Newsletter
+
+
+ Subject of the message subscribers receive after confirming their email address
+ __Subject of the message subscribers receive after confirming their email address
+
+
+ Message subscribers receive after confirming their email address
+ __Message subscribers receive after confirming their email address
+
+
+ [notify] Change of List-Membership details
+ __[notify] Change of List-Membership details
+
+
+ Subject of the message subscribers receive when they have changed their details
+ __Subject of the message subscribers receive when they have changed their details
+
+
+ Message subscribers receive when they have changed their details
+ __Message subscribers receive when they have changed their details
+
+
+ Part of the message that is sent to their new email address when subscribers change their information, and the email address has changed
+ __Part of the message that is sent to their new email address when subscribers change their information, and the email address has changed
+
+
+ Part of the message that is sent to their old email address when subscribers change their information, and the email address has changed
+ __Part of the message that is sent to their old email address when subscribers change their information, and the email address has changed
+
+
+ Your personal location
+ __Your personal location
+
+
+ Subject of message when subscribers request their personal location
+ __Subject of message when subscribers request their personal location
+
+
+ Default footer for sending a campaign
+ __Default footer for sending a campaign
+
+
+ Footer used when a message has been forwarded
+ __Footer used when a message has been forwarded
+
+
+ Message to send when they request their personal location
+ __Message to send when they request their personal location
+
+
+ String to always append to remote URL when using send-a-webpage
+ __String to always append to remote URL when using send-a-webpage
+
+
+ Width for Wordwrap of Text messages
+ __Width for Wordwrap of Text messages
+
+
+ CSS for HTML messages without a template
+ __CSS for HTML messages without a template
+
+
+ Domains that only accept text emails, one per line
+ __Domains that only accept text emails, one per line
+
+
+ last time TLDs were fetched
+ __last time TLDs were fetched
+
+
+ Top level domains
+ __Top level domains
+
+
+ Header of public pages.
+ __Header of public pages.
+
+
+ Footer of public pages
+ __Footer of public pages
+
+
+
diff --git a/resources/translations/security.en.xlf b/resources/translations/security.en.xlf
new file mode 100644
index 00000000..d053cd60
--- /dev/null
+++ b/resources/translations/security.en.xlf
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+ An authentication exception occurred.
+ An authentication exception occurred.
+
+
+ Authentication credentials could not be found.
+ Authentication credentials could not be found.
+
+
+ Authentication request could not be processed due to a system problem.
+ Authentication request could not be processed due to a system problem.
+
+
+ Invalid credentials.
+ Invalid credentials.
+
+
+ Cookie has already been used by someone else.
+ Cookie has already been used by someone else.
+
+
+ Not privileged to request the resource.
+ Not privileged to request the resource.
+
+
+ Invalid CSRF token.
+ Invalid CSRF token.
+
+
+ No authentication provider found to support the authentication token.
+ No authentication provider found to support the authentication token.
+
+
+ No session available, it either timed out or cookies are not enabled.
+ No session available, it either timed out or cookies are not enabled.
+
+
+ No token could be found.
+ No token could be found.
+
+
+ Username could not be found.
+ Username could not be found.
+
+
+ Account has expired.
+ Account has expired.
+
+
+ Credentials have expired.
+ Credentials have expired.
+
+
+ Account is disabled.
+ Account is disabled.
+
+
+ Account is locked.
+ Account is locked.
+
+
+ Too many failed login attempts, please try again later.
+ Too many failed login attempts, please try again later.
+
+
+ Invalid or expired login link.
+ Invalid or expired login link.
+
+
+ Too many failed login attempts, please try again in %minutes% minute.
+ Too many failed login attempts, please try again in %minutes% minute.
+
+
+ Too many failed login attempts, please try again in %minutes% minutes.
+ Too many failed login attempts, please try again in %minutes% minutes.
+
+
+
+
diff --git a/resources/translations/validators.en.xlf b/resources/translations/validators.en.xlf
new file mode 100644
index 00000000..41617e3b
--- /dev/null
+++ b/resources/translations/validators.en.xlf
@@ -0,0 +1,694 @@
+
+
+
+
+
+
+
+
+ This value should be false.
+ This value should be false.
+
+
+ This value should be true.
+ This value should be true.
+
+
+ This value should be of type {{ type }}.
+ This value should be of type {{ type }}.
+
+
+ This value should be blank.
+ This value should be blank.
+
+
+ The value you selected is not a valid choice.
+ The value you selected is not a valid choice.
+
+
+ You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices.
+ You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices.
+
+
+ You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices.
+ You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices.
+
+
+ One or more of the given values is invalid.
+ One or more of the given values is invalid.
+
+
+ This field was not expected.
+ This field was not expected.
+
+
+ This field is missing.
+ This field is missing.
+
+
+ This value is not a valid date.
+ This value is not a valid date.
+
+
+ This value is not a valid datetime.
+ This value is not a valid datetime.
+
+
+ This value is not a valid email address.
+ This value is not a valid email address.
+
+
+ The file could not be found.
+ The file could not be found.
+
+
+ The file is not readable.
+ The file is not readable.
+
+
+ The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}.
+ The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}.
+
+
+ The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}.
+ The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}.
+
+
+ This value should be {{ limit }} or less.
+ This value should be {{ limit }} or less.
+
+
+ This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less.
+ This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less.
+
+
+ This value should be {{ limit }} or more.
+ This value should be {{ limit }} or more.
+
+
+ This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more.
+ This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more.
+
+
+ This value should not be blank.
+ This value should not be blank.
+
+
+ This value should not be null.
+ This value should not be null.
+
+
+ This value should be null.
+ This value should be null.
+
+
+ This value is not valid.
+ This value is not valid.
+
+
+ This value is not a valid time.
+ This value is not a valid time.
+
+
+ This value is not a valid URL.
+ This value is not a valid URL.
+
+
+ The two values should be equal.
+ The two values should be equal.
+
+
+ The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}.
+ The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}.
+
+
+ The file is too large.
+ The file is too large.
+
+
+ The file could not be uploaded.
+ The file could not be uploaded.
+
+
+ This value should be a valid number.
+ This value should be a valid number.
+
+
+ This file is not a valid image.
+ This file is not a valid image.
+
+
+ This is not a valid IP address.
+ This value is not a valid IP address.
+
+
+ This value is not a valid language.
+ This value is not a valid language.
+
+
+ This value is not a valid locale.
+ This value is not a valid locale.
+
+
+ This value is not a valid country.
+ This value is not a valid country.
+
+
+ This value is already used.
+ This value is already used.
+
+
+ The size of the image could not be detected.
+ The size of the image could not be detected.
+
+
+ The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px.
+ The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px.
+
+
+ The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px.
+ The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px.
+
+
+ The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px.
+ The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px.
+
+
+ The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px.
+ The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px.
+
+
+ This value should be the user's current password.
+ This value should be the user's current password.
+
+
+ This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters.
+ This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters.
+
+
+ The file was only partially uploaded.
+ The file was only partially uploaded.
+
+
+ No file was uploaded.
+ No file was uploaded.
+
+
+ No temporary folder was configured in php.ini.
+ No temporary folder was configured in php.ini, or the configured folder does not exist.
+
+
+ Cannot write temporary file to disk.
+ Cannot write temporary file to disk.
+
+
+ A PHP extension caused the upload to fail.
+ A PHP extension caused the upload to fail.
+
+
+ This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more.
+ This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more.
+
+
+ This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less.
+ This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less.
+
+
+ This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements.
+ This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements.
+
+
+ Invalid card number.
+ Invalid card number.
+
+
+ Unsupported card type or invalid card number.
+ Unsupported card type or invalid card number.
+
+
+ This is not a valid International Bank Account Number (IBAN).
+ This value is not a valid International Bank Account Number (IBAN).
+
+
+ This value is not a valid ISBN-10.
+ This value is not a valid ISBN-10.
+
+
+ This value is not a valid ISBN-13.
+ This value is not a valid ISBN-13.
+
+
+ This value is neither a valid ISBN-10 nor a valid ISBN-13.
+ This value is neither a valid ISBN-10 nor a valid ISBN-13.
+
+
+ This value is not a valid ISSN.
+ This value is not a valid ISSN.
+
+
+ This value is not a valid currency.
+ This value is not a valid currency.
+
+
+ This value should be equal to {{ compared_value }}.
+ This value should be equal to {{ compared_value }}.
+
+
+ This value should be greater than {{ compared_value }}.
+ This value should be greater than {{ compared_value }}.
+
+
+ This value should be greater than or equal to {{ compared_value }}.
+ This value should be greater than or equal to {{ compared_value }}.
+
+
+ This value should be identical to {{ compared_value_type }} {{ compared_value }}.
+ This value should be identical to {{ compared_value_type }} {{ compared_value }}.
+
+
+ This value should be less than {{ compared_value }}.
+ This value should be less than {{ compared_value }}.
+
+
+ This value should be less than or equal to {{ compared_value }}.
+ This value should be less than or equal to {{ compared_value }}.
+
+
+ This value should not be equal to {{ compared_value }}.
+ This value should not be equal to {{ compared_value }}.
+
+
+ This value should not be identical to {{ compared_value_type }} {{ compared_value }}.
+ This value should not be identical to {{ compared_value_type }} {{ compared_value }}.
+
+
+ The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}.
+ The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}.
+
+
+ The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}.
+ The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}.
+
+
+ The image is square ({{ width }}x{{ height }}px). Square images are not allowed.
+ The image is square ({{ width }}x{{ height }}px). Square images are not allowed.
+
+
+ The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed.
+ The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed.
+
+
+ The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed.
+ The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed.
+
+
+ An empty file is not allowed.
+ An empty file is not allowed.
+
+
+ The host could not be resolved.
+ The host could not be resolved.
+
+
+ This value does not match the expected {{ charset }} charset.
+ This value does not match the expected {{ charset }} charset.
+
+
+ This is not a valid Business Identifier Code (BIC).
+ This value is not a valid Business Identifier Code (BIC).
+
+
+ Error
+ Error
+
+
+ This is not a valid UUID.
+ This value is not a valid UUID.
+
+
+ This value should be a multiple of {{ compared_value }}.
+ This value should be a multiple of {{ compared_value }}.
+
+
+ This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}.
+ This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}.
+
+
+ This value should be valid JSON.
+ This value should be valid JSON.
+
+
+ This collection should contain only unique elements.
+ This collection should contain only unique elements.
+
+
+ This value should be positive.
+ This value should be positive.
+
+
+ This value should be either positive or zero.
+ This value should be either positive or zero.
+
+
+ This value should be negative.
+ This value should be negative.
+
+
+ This value should be either negative or zero.
+ This value should be either negative or zero.
+
+
+ This value is not a valid timezone.
+ This value is not a valid timezone.
+
+
+ This password has been leaked in a data breach, it must not be used. Please use another password.
+ This password has been leaked in a data breach, it must not be used. Please use another password.
+
+
+ This value should be between {{ min }} and {{ max }}.
+ This value should be between {{ min }} and {{ max }}.
+
+
+ This value is not a valid hostname.
+ This value is not a valid hostname.
+
+
+ The number of elements in this collection should be a multiple of {{ compared_value }}.
+ The number of elements in this collection should be a multiple of {{ compared_value }}.
+
+
+ This value should satisfy at least one of the following constraints:
+ This value should satisfy at least one of the following constraints:
+
+
+ Each element of this collection should satisfy its own set of constraints.
+ Each element of this collection should satisfy its own set of constraints.
+
+
+ This value is not a valid International Securities Identification Number (ISIN).
+ This value is not a valid International Securities Identification Number (ISIN).
+
+
+ This value should be a valid expression.
+ This value should be a valid expression.
+
+
+ This value is not a valid CSS color.
+ This value is not a valid CSS color.
+
+
+ This value is not a valid CIDR notation.
+ This value is not a valid CIDR notation.
+
+
+ The value of the netmask should be between {{ min }} and {{ max }}.
+ The value of the netmask should be between {{ min }} and {{ max }}.
+
+
+ The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less.
+ The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less.
+
+
+ The password strength is too low. Please use a stronger password.
+ The password strength is too low. Please use a stronger password.
+
+
+ This value contains characters that are not allowed by the current restriction-level.
+ This value contains characters that are not allowed by the current restriction-level.
+
+
+ Using invisible characters is not allowed.
+ Using invisible characters is not allowed.
+
+
+ Mixing numbers from different scripts is not allowed.
+ Mixing numbers from different scripts is not allowed.
+
+
+ Using hidden overlay characters is not allowed.
+ Using hidden overlay characters is not allowed.
+
+
+ The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}.
+ The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}.
+
+
+ The detected character encoding is invalid ({{ detected }}). Allowed encodings are {{ encodings }}.
+ The detected character encoding is invalid ({{ detected }}). Allowed encodings are {{ encodings }}.
+
+
+ This value is not a valid MAC address.
+ This value is not a valid MAC address.
+
+
+ This URL is missing a top-level domain.
+ This URL is missing a top-level domain.
+
+
+ This value is too short. It should contain at least one word.|This value is too short. It should contain at least {{ min }} words.
+ This value is too short. It should contain at least one word.|This value is too short. It should contain at least {{ min }} words.
+
+
+ This value is too long. It should contain one word.|This value is too long. It should contain {{ max }} words or less.
+ This value is too long. It should contain one word.|This value is too long. It should contain {{ max }} words or less.
+
+
+ This value does not represent a valid week in the ISO 8601 format.
+ This value does not represent a valid week in the ISO 8601 format.
+
+
+ This value is not a valid week.
+ This value is not a valid week.
+
+
+ This value should not be before week "{{ min }}".
+ This value should not be before week "{{ min }}".
+
+
+ This value should not be after week "{{ max }}".
+ This value should not be after week "{{ max }}".
+
+
+ This value is not a valid Twig template.
+ This value is not a valid Twig template.
+
+
+ This file is not a valid video.
+ This file is not a valid video.
+
+
+ The size of the video could not be detected.
+ The size of the video could not be detected.
+
+
+ The video width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px.
+ The video width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px.
+
+
+ The video width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px.
+ The video width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px.
+
+
+ The video height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px.
+ The video height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px.
+
+
+ The video height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px.
+ The video height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px.
+
+
+ The video has too few pixels ({{ pixels }} pixels). Minimum amount expected is {{ min_pixels }} pixels.
+ The video has too few pixels ({{ pixels }} pixels). Minimum amount expected is {{ min_pixels }} pixels.
+
+
+ The video has too many pixels ({{ pixels }} pixels). Maximum amount expected is {{ max_pixels }} pixels.
+ The video has too many pixels ({{ pixels }} pixels). Maximum amount expected is {{ max_pixels }} pixels.
+
+
+ The video ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}.
+ The video ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}.
+
+
+ The video ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}.
+ The video ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}.
+
+
+ The video is square ({{ width }}x{{ height }}px). Square videos are not allowed.
+ The video is square ({{ width }}x{{ height }}px). Square videos are not allowed.
+
+
+ The video is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented videos are not allowed.
+ The video is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented videos are not allowed.
+
+
+ The video is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented videos are not allowed.
+ The video is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented videos are not allowed.
+
+
+ The video file is corrupted.
+ The video file is corrupted.
+
+
+ The video contains multiple streams. Only one stream is allowed.
+ The video contains multiple streams. Only one stream is allowed.
+
+
+ Unsupported video codec "{{ codec }}".
+ Unsupported video codec "{{ codec }}".
+
+
+ Unsupported video container "{{ container }}".
+ Unsupported video container "{{ container }}".
+
+
+ The image file is corrupted.
+ The image file is corrupted.
+
+
+ The image has too few pixels ({{ pixels }} pixels). Minimum amount expected is {{ min_pixels }} pixels.
+ The image has too few pixels ({{ pixels }} pixels). Minimum amount expected is {{ min_pixels }} pixels.
+
+
+ The image has too many pixels ({{ pixels }} pixels). Maximum amount expected is {{ max_pixels }} pixels.
+ The image has too many pixels ({{ pixels }} pixels). Maximum amount expected is {{ max_pixels }} pixels.
+
+
+ This filename does not match the expected charset.
+ This filename does not match the expected charset.
+
+
+ This form should not contain extra fields.
+ This form should not contain extra fields.
+
+
+ The uploaded file was too large. Please try to upload a smaller file.
+ The uploaded file was too large. Please try to upload a smaller file.
+
+
+ The CSRF token is invalid. Please try to resubmit the form.
+ The CSRF token is invalid. Please try to resubmit the form.
+
+
+ This value is not a valid HTML5 color.
+ This value is not a valid HTML5 color.
+
+
+ Please enter a valid birthdate.
+ Please enter a valid birthdate.
+
+
+ The selected choice is invalid.
+ The selected choice is invalid.
+
+
+ The collection is invalid.
+ The collection is invalid.
+
+
+ Please select a valid color.
+ Please select a valid color.
+
+
+ Please select a valid country.
+ Please select a valid country.
+
+
+ Please select a valid currency.
+ Please select a valid currency.
+
+
+ Please choose a valid date interval.
+ Please choose a valid date interval.
+
+
+ Please enter a valid date and time.
+ Please enter a valid date and time.
+
+
+ Please enter a valid date.
+ Please enter a valid date.
+
+
+ Please select a valid file.
+ Please select a valid file.
+
+
+ The hidden field is invalid.
+ The hidden field is invalid.
+
+
+ Please enter an integer.
+ Please enter an integer.
+
+
+ Please select a valid language.
+ Please select a valid language.
+
+
+ Please select a valid locale.
+ Please select a valid locale.
+
+
+ Please enter a valid money amount.
+ Please enter a valid money amount.
+
+
+ Please enter a number.
+ Please enter a number.
+
+
+ The password is invalid.
+ The password is invalid.
+
+
+ Please enter a percentage value.
+ Please enter a percentage value.
+
+
+ The values do not match.
+ The values do not match.
+
+
+ Please enter a valid time.
+ Please enter a valid time.
+
+
+ Please select a valid timezone.
+ Please select a valid timezone.
+
+
+ Please enter a valid URL.
+ Please enter a valid URL.
+
+
+ Please enter a valid search term.
+ Please enter a valid search term.
+
+
+ Please provide a valid phone number.
+ Please provide a valid phone number.
+
+
+ The checkbox has an invalid value.
+ The checkbox has an invalid value.
+
+
+ Please enter a valid email address.
+ Please enter a valid email address.
+
+
+ Please select a valid option.
+ Please select a valid option.
+
+
+ Please select a valid range.
+ Please select a valid range.
+
+
+ Please enter a valid week.
+ Please enter a valid week.
+
+
+
+
diff --git a/src/Core/ConfigProvider.php b/src/Core/ParameterProvider.php
similarity index 93%
rename from src/Core/ConfigProvider.php
rename to src/Core/ParameterProvider.php
index b78f365f..ac278984 100644
--- a/src/Core/ConfigProvider.php
+++ b/src/Core/ParameterProvider.php
@@ -4,7 +4,7 @@
namespace PhpList\Core\Core;
-class ConfigProvider
+class ParameterProvider
{
public function __construct(private readonly array $config)
{
diff --git a/src/Domain/Analytics/Service/LinkTrackService.php b/src/Domain/Analytics/Service/LinkTrackService.php
index 2252a0f0..75242104 100644
--- a/src/Domain/Analytics/Service/LinkTrackService.php
+++ b/src/Domain/Analytics/Service/LinkTrackService.php
@@ -4,7 +4,7 @@
namespace PhpList\Core\Domain\Analytics\Service;
-use PhpList\Core\Core\ConfigProvider;
+use PhpList\Core\Core\ParameterProvider;
use PhpList\Core\Domain\Analytics\Exception\MissingMessageIdException;
use PhpList\Core\Domain\Analytics\Model\LinkTrack;
use PhpList\Core\Domain\Analytics\Repository\LinkTrackRepository;
@@ -13,12 +13,12 @@
class LinkTrackService
{
private LinkTrackRepository $linkTrackRepository;
- private ConfigProvider $configProvider;
+ private ParameterProvider $paramProvider;
- public function __construct(LinkTrackRepository $linkTrackRepository, ConfigProvider $configProvider)
+ public function __construct(LinkTrackRepository $linkTrackRepository, ParameterProvider $paramProvider)
{
$this->linkTrackRepository = $linkTrackRepository;
- $this->configProvider = $configProvider;
+ $this->paramProvider = $paramProvider;
}
public function getUrlById(int $id): ?string
@@ -29,7 +29,7 @@ public function getUrlById(int $id): ?string
public function isExtractAndSaveLinksApplicable(): bool
{
- return (bool)$this->configProvider->get('click_track', false);
+ return (bool)$this->paramProvider->get('click_track', false);
}
/**
diff --git a/src/Domain/Configuration/Model/ConfigOption.php b/src/Domain/Configuration/Model/ConfigOption.php
new file mode 100644
index 00000000..86b9286e
--- /dev/null
+++ b/src/Domain/Configuration/Model/ConfigOption.php
@@ -0,0 +1,18 @@
+findOneBy(['key' => $name])?->getValue();
+ }
}
diff --git a/src/Domain/Configuration/Service/LegacyUrlBuilder.php b/src/Domain/Configuration/Service/LegacyUrlBuilder.php
new file mode 100644
index 00000000..4bc6366f
--- /dev/null
+++ b/src/Domain/Configuration/Service/LegacyUrlBuilder.php
@@ -0,0 +1,29 @@
+configRepository = $configRepository;
}
- public function inMaintenanceMode(): bool
- {
- $config = $this->getByItem('maintenancemode');
- return $config?->getValue() === '1';
- }
-
/**
* Get a configuration item by its key
*/
diff --git a/src/Domain/Configuration/Service/PlaceholderResolver.php b/src/Domain/Configuration/Service/PlaceholderResolver.php
new file mode 100644
index 00000000..3a0a3464
--- /dev/null
+++ b/src/Domain/Configuration/Service/PlaceholderResolver.php
@@ -0,0 +1,33 @@
+ */
+ private array $providers = [];
+
+ public function register(string $token, callable $provider): void
+ {
+ // tokens like [UNSUBSCRIBEURL] (case-insensitive)
+ $this->providers[strtoupper($token)] = $provider;
+ }
+
+ public function resolve(?string $input): ?string
+ {
+ if ($input === null || $input === '') {
+ return $input;
+ }
+
+ // Replace [TOKEN] (case-insensitive)
+ return preg_replace_callback('/\[(\w+)\]/i', function ($map) {
+ $key = strtoupper($map[1]);
+ if (!isset($this->providers[$key])) {
+ return $map[0];
+ }
+ return (string) ($this->providers[$key])();
+ }, $input);
+ }
+}
diff --git a/src/Domain/Configuration/Service/Provider/ConfigProvider.php b/src/Domain/Configuration/Service/Provider/ConfigProvider.php
new file mode 100644
index 00000000..a1db70fc
--- /dev/null
+++ b/src/Domain/Configuration/Service/Provider/ConfigProvider.php
@@ -0,0 +1,85 @@
+booleanValues)) {
+ throw new InvalidArgumentException('Invalid boolean value key');
+ }
+ $config = $this->configRepository->findOneBy(['item' => $key->value]);
+
+ if ($config !== null) {
+ return $config->getValue() === '1';
+ }
+
+ return $this->defaultConfigs->has($key->value) && $this->defaultConfigs->get($key->value)['value'] === '1';
+ }
+
+ /**
+ * Get configuration value by its key, from settings or default configs or default value (if provided)
+ * @SuppressWarnings(PHPMD.StaticAccess)
+ * @throws InvalidArgumentException
+ */
+ public function getValue(ConfigOption $key): ?string
+ {
+ if (in_array($key, $this->booleanValues)) {
+ throw new InvalidArgumentException('Key is a boolean value, use isEnabled instead');
+ }
+ $cacheKey = 'cfg:' . $key->value;
+ $value = $this->cache->get($cacheKey);
+ if ($value === null) {
+ $value = $this->configRepository->findValueByItem($key->value);
+ $this->cache->set($cacheKey, $value, $this->ttlSeconds);
+ }
+
+ if ($value !== null) {
+ return $value;
+ }
+
+ return $this->defaultConfigs->has($key->value) ? $this->defaultConfigs->get($key->value)['value'] : null;
+ }
+
+ /** @SuppressWarnings(PHPMD.StaticAccess) */
+ public function getValueWithNamespace(ConfigOption $key): ?string
+ {
+ $full = $this->getValue($key);
+ if ($full !== null && $full !== '') {
+ return $full;
+ }
+
+ if (str_contains($key->value, ':')) {
+ [$parent] = explode(':', $key->value, 2);
+ $parentKey = ConfigOption::from($parent);
+
+ return $this->getValue($parentKey);
+ }
+
+ return null;
+ }
+}
diff --git a/src/Domain/Configuration/Service/Provider/DefaultConfigProvider.php b/src/Domain/Configuration/Service/Provider/DefaultConfigProvider.php
new file mode 100644
index 00000000..bbe14a46
--- /dev/null
+++ b/src/Domain/Configuration/Service/Provider/DefaultConfigProvider.php
@@ -0,0 +1,587 @@
+defaults)) {
+ return;
+ }
+
+ $publicSchema = 'http';
+ $pageRoot = '/api/v2';
+
+ $this->defaults = [
+ 'admin_address' => [
+ 'value' => 'webmaster@[DOMAIN]',
+ 'description' => $this->translator->trans('Person in charge of this system (one email address)'),
+ 'type' => 'email',
+ 'allowempty' => false,
+ 'category' => 'general',
+ ],
+ 'organisation_name' => [
+ 'value' => '',
+ 'description' => $this->translator->trans('Name of the organisation'),
+ 'type' => 'text',
+ 'allowempty' => true,
+ 'allowtags' => '
You will receive an email to confirm your subscription. Please click the link in the email to confirm
'),
+ 'description' => $this->translator->trans('Text to display when subscription with an AJAX request was successful'),
+ 'type' => 'textarea',
+ 'allowempty' => true,
+ 'category' => 'subscription',
+ ],
+ 'subscribesubject' => [
+ 'value' => $this->translator->trans('Request for confirmation'),
+ 'description' => $this->translator->trans(
+ 'Subject of the message subscribers receive when they sign up'
+ ),
+ 'infoicon' => true,
+ 'type' => 'text',
+ 'allowempty' => 0,
+ 'category' => 'transactional',
+ ],
+ 'subscribemessage' => [
+ 'value' => ' You have been subscribed to the following newsletters:
+
+[LISTS]
+
+
+Please click the following link to confirm it\'s really you:
+
+[CONFIRMATIONURL]
+
+
+In order to provide you with this service we\'ll need to
+
+Transfer your contact information to [DOMAIN]
+Store your contact information in your [DOMAIN] account
+Send you emails from [DOMAIN]
+Track your interactions with these emails for marketing purposes
+
+If this is not correct, or you do not agree, simply take no action and delete this message.'
+ ,
+ 'description' => $this->translator->trans('Message subscribers receive when they sign up'),
+ 'type' => 'textarea',
+ 'allowempty' => 0,
+ 'category' => 'transactional',
+ ],
+ 'unsubscribesubject' => [
+ 'value' => $this->translator->trans('Goodbye from our Newsletter'),
+ 'description' => $this->translator->trans(
+ 'Subject of the message subscribers receive when they unsubscribe'
+ ),
+ 'type' => 'text',
+ 'allowempty' => 0,
+ 'category' => 'transactional',
+ ],
+ 'unsubscribemessage' => [
+ 'value' => 'Goodbye from our Newsletter, sorry to see you go.
+
+You have been unsubscribed from our newsletters.
+
+This is the last email you will receive from us. Our newsletter system, phpList,
+will refuse to send you any further messages, without manual intervention by our administrator.
+
+If there is an error in this information, you can re-subscribe:
+please go to [SUBSCRIBEURL] and follow the steps.
+
+Thank you'
+ ,
+ 'description' => $this->translator->trans('Message subscribers receive when they unsubscribe'),
+ 'type' => 'textarea',
+ 'allowempty' => 0,
+ 'category' => 'transactional',
+ ],
+ 'confirmationsubject' => [
+ 'value' => $this->translator->trans('Welcome to our Newsletter'),
+ 'description' => $this->translator->trans(
+ 'Subject of the message subscribers receive after confirming their email address'
+ ),
+ 'type' => 'text',
+ 'allowempty' => 0,
+ 'category' => 'transactional',
+ ],
+ 'confirmationmessage' => [
+ 'value' => 'Welcome to our Newsletter
+
+Please keep this message for later reference.
+
+Your email address has been added to the following newsletter(s):
+[LISTS]
+
+To update your details and preferences please go to [PREFERENCESURL].
+If you do not want to receive any more messages, please go to [UNSUBSCRIBEURL].
+
+Thank you'
+ ,
+ 'description' => $this->translator->trans(
+ 'Message subscribers receive after confirming their email address'
+ ),
+ 'type' => 'textarea',
+ 'allowempty' => 0,
+ 'category' => 'transactional',
+ ],
+ 'updatesubject' => [
+ 'value' => $this->translator->trans('[notify] Change of List-Membership details'),
+ 'description' => $this->translator->trans(
+ 'Subject of the message subscribers receive when they have changed their details'
+ ),
+ 'type' => 'text',
+ 'allowempty' => 0,
+ 'category' => 'transactional',
+ ],
+ // the message that is sent when a user updates their information.
+ // just to make sure they approve of it.
+ // confirmationinfo is replaced by one of the options below
+ // userdata is replaced by the information in the database
+ 'updatemessage' => [
+ 'value' => 'This message is to inform you of a change of your details on our newsletter database
+
+You are currently member of the following newsletters:
+
+[LISTS]
+
+[CONFIRMATIONINFO]
+
+The information on our system for you is as follows:
+
+[USERDATA]
+
+If this is not correct, please update your information at the following location:
+
+[PREFERENCESURL]
+
+Thank you'
+ ,
+ 'description' => $this->translator->trans(
+ 'Message subscribers receive when they have changed their details'
+ ),
+ 'type' => 'textarea',
+ 'allowempty' => 0,
+ 'category' => 'transactional',
+ ],
+ // this is the text that is placed in the [!-- confirmation --] location of the above
+ // message, in case the email is sent to their new email address and they have changed
+ // their email address
+ 'emailchanged_text' => [
+ 'value' => '
+ When updating your details, your email address has changed.
+ Please confirm your new email address by visiting this webpage:
+
+ [CONFIRMATIONURL]
+
+ ',
+ 'description' => $this->translator->trans('Part of the message that is sent to their new email address when subscribers change their information, and the email address has changed'),
+ 'type' => 'textarea',
+ 'allowempty' => 0,
+ 'category' => 'transactional',
+ ],
+ // this is the text that is placed in the [!-- confirmation --] location of the above
+ // message, in case the email is sent to their old email address and they have changed
+ // their email address
+ 'emailchanged_text_oldaddress' => [
+ 'value' => 'Please Note: when updating your details, your email address has changed.
+
+A message has been sent to your new email address with a URL
+to confirm this change. Please visit this website to activate
+your membership.'
+ ,
+ 'description' => $this->translator->trans('Part of the message that is sent to their old email address when subscribers change their information, and the email address has changed'),
+ 'type' => 'textarea',
+ 'allowempty' => 0,
+ 'category' => 'transactional',
+ ],
+ 'personallocation_subject' => [
+ 'value' => $this->translator->trans('Your personal location'),
+ 'description' => $this->translator->trans(
+ 'Subject of message when subscribers request their personal location'
+ ),
+ 'type' => 'text',
+ 'allowempty' => 0,
+ 'category' => 'transactional',
+ ],
+ 'messagefooter' => [
+ 'value' => '--
+
+
+
+ ',
+ 'description' => $this->translator->trans('Default footer for sending a campaign'),
+ 'type' => 'textarea',
+ 'allowempty' => 0,
+ 'category' => 'campaign',
+ ],
+ 'forwardfooter' => [
+ 'value' => '
+
+ ',
+ 'description' => $this->translator->trans('Footer used when a message has been forwarded'),
+ 'type' => 'textarea',
+ 'allowempty' => 0,
+ 'category' => 'campaign',
+ ],
+ 'personallocation_message' => [
+ 'value' => 'You have requested your personal location to update your details from our website.
+The location is below. Please make sure that you use the full line as mentioned below.
+Sometimes email programmes can wrap the line into multiple lines.
+
+Your personal location is:
+[PREFERENCESURL]
+
+Thank you.'
+ ,
+ 'description' => $this->translator->trans('Message to send when they request their personal location'),
+ 'type' => 'textarea',
+ 'allowempty' => 0,
+ 'category' => 'transactional',
+ ],
+ 'remoteurl_append' => [
+ 'value' => '',
+ 'description' => $this->translator->trans(
+ 'String to always append to remote URL when using send-a-webpage'
+ ),
+ 'type' => 'text',
+ 'allowempty' => true,
+ 'category' => 'campaign',
+ ],
+ 'wordwrap' => [
+ 'value' => '75',
+ 'description' => $this->translator->trans('Width for Wordwrap of Text messages'),
+ 'type' => 'text',
+ 'allowempty' => true,
+ 'category' => 'campaign',
+ ],
+ 'html_email_style' => [
+ 'value' => '',
+ 'description' => $this->translator->trans('CSS for HTML messages without a template'),
+ 'type' => 'textarea',
+ 'allowempty' => true,
+ 'category' => 'campaign',
+ ],
+ 'alwayssendtextto' => [
+ 'value' => '',
+ 'description' => $this->translator->trans('Domains that only accept text emails, one per line'),
+ 'type' => 'textarea',
+ 'allowempty' => true,
+ 'category' => 'campaign',
+ ],
+ 'tld_last_sync' => [
+ 'value' => '0',
+ 'description' => $this->translator->trans('last time TLDs were fetched'),
+ 'type' => 'text',
+ 'allowempty' => true,
+ 'category' => 'system',
+ 'hidden' => true,
+ ],
+ 'internet_tlds' => [
+ 'value' => '',
+ 'description' => $this->translator->trans('Top level domains'),
+ 'type' => 'textarea',
+ 'allowempty' => true,
+ 'category' => 'system',
+ 'hidden' => true,
+ ],
+ 'pageheader' => [
+ 'value' => '