Pesan error bawaan Laravel memang akurat, tetapi ditulis dalam bahasa Inggris dengan gaya teknis: “The judul field must be at least 5 characters.” Untuk aplikasi berbahasa Indonesia, kalimat semacam itu terasa dingin di hadapan pengguna akhir — apalagi nama field seperti kode_promo tampil mentah apa adanya. Laravel menyediakan tiga lapisan kustomisasi pesan: per rule di class FormRequest, penggantian nama attribute, dan file bahasa yang mengubah seluruh pesan bawaan sekaligus. Chapter ini membedah ketiganya secara berurutan, masing-masing dengan hasil nyatanya.

messages(): Pesan per Field dan Rule #

Method messages() pada FormRequest menerima array dengan key berformat field.rule dan nilai berupa teks penggantinya:

php
class StorePostCustomRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [
            'judul' => ['required', 'string', 'min:5'],
            'isi' => ['required', 'string'],
            'email' => ['required', 'email'],
        ];
    }

    public function messages(): array
    {
        return [
            'judul.required' => 'Judul tulisan wajib diisi.',
            'judul.min' => 'Judul minimal :min karakter.',
            'email.required' => 'Alamat email wajib diisi.',
            'email.email' => 'Format :attribute tidak valid.',
        ];
    }
}

Perhatikan dua placeholder di dalam pesan: :min akan diganti nilai parameter rule, dan :attribute diganti nama field. Key yang tidak kita sentuh — misalnya isi.required — tetap memakai pesan bawaan. Kita uji dengan request yang gagal di tiga field sekaligus:

php
$response = $this->postJson('/custom/posts', [
    'judul' => 'abc',
    'isi' => '',
    'email' => 'bukan-email',
]);

Output yang Dihasilkan:

text
{"message":"Judul minimal 5 karakter. (and 2 more errors)","errors":{"judul":["Judul minimal 5 karakter."],"isi":["The isi field is required."],"email":["Format :attribute tidak valid."]}}

Hasilnya sangat informatif: judul tampil dengan pesan buatan kita dan :min terisi angka 5, isi jatuh ke pesan bawaan Inggris, dan pesan email.email masih menampilkan :attribute mentah karena — akan kita rapikan segera — attributes() belum diisi.

attributes(): Nama Field yang Ramah #

Method attributes() memetakan nama field teknis ke label yang manusiawi. Placeholder :attribute di pesan mana pun — termasuk pesan bawaan — akan memakai pemetaan ini:

php
public function attributes(): array
{
    return [
        'judul' => 'judul tulisan',
        'email' => 'alamat email',
    ];
}

Dengan penambahan tersebut, request yang sama menghasilkan:

Output yang Dihasilkan:

text
{"message":"Judul minimal 5 karakter. (and 2 more errors)","errors":{"judul":["Judul minimal 5 karakter."],"isi":["The isi field is required."],"email":["Format alamat email tidak valid."]}}

Pesan terakhir kini berbunyi Format alamat email tidak valid. — :attribute tergantikan oleh nilai dari attributes(). Perubahan ini juga berlaku untuk semua pesan bawaan lain yang menyebut nama field.

Inline di Controller: Argumen Tambahan validate() #

Jika validasi masih ditulis inline di controller, kedua kustomisasi itu tersedia sebagai argumen kedua dan ketiga validate():

php
$validated = $request->validate(
    [
        'nama' => ['required', 'string'],
        'email' => ['required', 'email'],
    ],
    [
        'nama.required' => 'Nama lengkap wajib diisi.',
        'email.email' => ':Attribute harus berformat email yang benar.',
    ],
    [
        'nama' => 'nama lengkap',
    ],
);

Argumen kedua adalah array messages, argumen ketiga array attributes — isinya persis seperti method di FormRequest. Placeholder :Attribute dengan huruf kapital di depan otomatis mengkapitalkan huruf pertama hasilnya:

Output yang Dihasilkan:

text
{"message":"Nama lengkap wajib diisi. (and 1 more error)","errors":{"nama":["Nama lengkap wajib diisi."],"email":["Email harus berformat email yang benar."]}}

File Bahasa: Mengubah Pesan Secara Global #

Untuk mengganti pesan di seluruh aplikasi, kita perlu menerbitkan file bahasa Laravel terlebih dahulu:

bash
php artisan lang:publish

Output yang Dihasilkan:

text

   INFO  Language files published successfully.  

Perintah ini membuat direktori lang/en/ berisi validation.php, auth.php, pagination.php, dan passwords.php. Isi lang/en/validation.php adalah array raksasa yang memetakan setiap rule ke teks pesannya:

php
return [
    // ...

    'required' => 'The :attribute field is required.',
    'email' => 'The :attribute field must be a valid email address.',
    'min' => [
        'string' => 'The :attribute field must be at least :min characters.',
        // ...
    ],

    // ...
];

Mengubah satu baris di berkas ini mengubah pesan di seluruh aplikasi. Sebagai contoh, kita ganti baris 'required' menjadi 'Kolom :attribute wajib diisi.' lalu kirim request dengan isi kosong:

Output yang Dihasilkan:

text
{"message":"Kolom isi wajib diisi.","errors":{"isi":["Kolom isi wajib diisi."]}}

File bahasa juga mendukung dua seksi khusus di bagian bawahnya. Seksi custom mengganti pesan untuk kombinasi field dan rule tertentu tanpa menyentuh messages():

php
'custom' => [
    'attribute-name' => [
        'rule-name' => 'custom-message',
    ],
    'isi' => [
        'required' => 'Isi tulisan tidak boleh kosong ya.',
    ],
],

Dengan entri 'isi' => ['required' => 'Isi tulisan tidak boleh kosong ya.'] diaktifkan, request dengan isi kosong menghasilkan {"message":"Isi tulisan tidak boleh kosong ya.",...}. Sementara seksi 'attributes' => [] yang masih kosong berfungsi persis seperti method attributes() — tempat mendefinisikan nama ramah untuk seluruh aplikasi. Untuk aplikasi berbahasa Indonesia penuh, kita bisa menyalin direktori lang/en menjadi lang/id dan mengatur APP_LOCALE=id.

Dengan pesan error yang sudah berbahasa manusia, tugas berikutnya adalah menampilkannya di halaman form dengan rapi — mulai dari ringkasan semua error sampai penandaan field yang bermasalah. Itulah pembahasan chapter Error Messages di Blade . Rujukan resminya ada di dokumentasi Validation — Custom Messages .