›
byrcsc/laravel-approval · 1.x
Customize notification text, localization, subjects, and email views.
The shipped notifications use generic wording, such as "You have been asked to approve Purchase Order #41." You can change the wording without replacing the notification classes. Pick the smallest option that fits:
| You want to | Publish |
|---|---|
| Reword or translate the messages | approval-translations |
| Restructure the emails, add a link into your UI | approval-views |
| Change who receives them, or the whole message | Neither, see Notifications |
Nothing here is required. The package ships working English messages and mail views, and an application that never publishes either still sends mail.
Every user-facing string lives in one file:
php artisan vendor:publish --tag="approval-translations"That writes lang/vendor/approval/en/approval.php:
return [
'requested' => [
'subject' => 'Approval needed: :subject',
'body' => 'You have been asked to approve :subject.',
],
'approved' => [
'subject' => 'Approved: :subject',
'body' => ':subject has been approved.',
],
// rejected, returned, assigned, overdue, conflicted
'reason' => 'Reason: :reason',
'reference' => 'Reference: :reference.',
'deleted_record' => 'a deleted record',
];Each event has a subject and a body. conflicted also has an unresolved
line. The reason, reference, and deleted_record keys are shared across
messages.
To reword a message, edit the file in place. To translate, copy the directory
to es, fr, or another locale. The package resolves messages through
trans() at send time, so they follow the application locale. A request routed
to a French-speaking approver reads in French if
lang/vendor/approval/fr/approval.php exists.
A placeholder can appear anywhere in the line. Concatenated strings fix the word order, so translations go through this file instead:
'requested' => [
'subject' => 'Approbation requise : :subject',
'body' => 'Il vous est demandé d\'approuver :subject.',
],:subject is a readable name for the record. It is the record's name,
title, reference, or label attribute, or ClassName #key if none is set.
See
Notifications for the full resolution order and what a
deleted record reads as.
A key with no translation renders as the key itself instead of throwing an exception. An incomplete locale file produces visibly wrong mail, not a failed queue job.
To add a button into your own UI, change the layout, or drop a line entirely:
php artisan vendor:publish --tag="approval-views"That writes resources/views/vendor/approval/mail/, one Blade file per message:
approved.blade.php rejected.blade.php conflicted.blade.php
requested.blade.php returned.blade.php overdue.blade.php
assigned.blade.phpEach is an ordinary markdown mail view. The shipped files carry only the message and reference lines. A published copy can add interface elements such as a review button:
<x-mail::message>
{{ __('approval::approval.requested.body', ['subject' => $subject]) }}
<x-mail::button :url="route('approvals.show', $request)">
{{ __('Review it') }}
</x-mail::button>
{{ __('approval::approval.reference', ['reference' => $reference]) }}
</x-mail::message>| Variable | |
|---|---|
$subject | The readable record name used in the subject line. |
$reference | The request's public ULID. |
$request | The ApprovalRequest. |
$approvable | The record, or null if it has been deleted since. |
$notification | The notification instance, for anything else you need. |
The rejected and returned views also receive a nullable $reason. Both
shipped views guard it with @if ($reason !== null). Keep that guard, or a
decision recorded without a comment renders an empty "Reason:" line.
Guard $approvable too. If a record is hard-deleted between the decision and
the send, the notification has a request but no record. A published view that
calls route('orders.show', $approvable) then fails for that mail.
The shipped views read their wording through __('approval::approval.…')
instead of hardcoding English. If you publish the views, the translations still
apply. If you publish the translations, the views use them. You can also publish
both, because the views and the translations share the same keys.
The translations apply only if your published views keep reading them. A view with inline text still works, but that message leaves the locale system. Mail to a French approver is then part French and part the text you typed.
To change the audience as well, point the event at your own notification class. See Notifications for the map and the recipient helpers.
A replacement class does not lose access to the published content. Extend
ApprovalNotification and call the protected mailFor(), which builds the
MailMessage from the same translation keys and views:
use ByRcsc\LaravelApproval\Events\ApprovalEvent;
use ByRcsc\LaravelApproval\Notifications\ApprovalNotification;
use Illuminate\Notifications\Messages\MailMessage;
final class PurchaseOrderNeedsApproval extends ApprovalNotification
{
public static function recipients(ApprovalEvent $event): iterable
{
return self::activeApprovers($event);
}
public function toMail(object $notifiable): MailMessage
{
return $this->mailFor('requested');
}
}recipients() is abstract on the base class, so every replacement declares
its audience. See
why notifications declare their own recipients.
mailFor($key, $with = []) reads approval::approval.{$key}.subject for the
subject, renders approval::mail.{$key}, and passes the five variables above.
mailFor() merges anything in $with into the view variables. The shipped
rejected and returned notifications use $with to supply $reason:
return $this->mailFor('rejected', ['reason' => $this->reason()]);A class that needs only different recipients can keep the published wording. A class that needs a different message can pass extra variables to its own view.
Publishing translations and views changes what the mail channel sends. Neither reaches the others.
database and broadcast render toArray(), which carries structured data
rather than prose:
[
'request' => '01JG3…', // the public ULID
'state' => 'pending',
'subject' => 'Purchase Order #41',
]The payload has nothing to translate. subject is the record's readable name,
not a translated line, so rewording approval.php does not change a database
notification. An application that renders an in-app inbox from these rows
writes its own wording based on state. People read the row long after the
package writes it, so the text should use the reader's locale, not the locale
in effect when the row was stored.
To change the payload itself, override toArray() on a replacement class.