ฟอร์มหลังบ้านภาษาไทยทั้งหน้า แต่พอเปิดสวิตช์ "ออกใบกำกับภาษี" แล้วกดบันทึกโดยยังไม่เลือกที่อยู่ ใต้ช่องกลับขึ้นข้อความว่า
The ที่อยู่ออกใบกำกับภาษี field is required when ออกใบกำกับภาษี is accepted.
ชื่อช่องเป็นไทยถูกต้อง แต่ประโยครอบ ๆ เป็นภาษาอังกฤษ ใครตั้ง APP_LOCALE=th ไว้น่าจะเคยเห็นอาการนี้สักครั้ง และมักโผล่กับกฎที่ไม่ได้ใช้บ่อย
ข้อความ validation มาจากไฟล์ภาษาของ Laravel
ทุกกฎ validation มีข้อความของตัวเองอยู่ใน validation.php เช่น required, email, required_if_accepted ข้อความชุดภาษาอังกฤษอยู่ใน framework เองที่ vendor/laravel/framework/src/Illuminate/Translation/lang/en/validation.php โปรเจกต์ใหม่จึงไม่มีโฟลเดอร์ lang เลย ถ้าอยากแก้ข้อความ สั่ง php artisan lang:publish แล้ว Laravel จะคัดลอกไฟล์ภาษาอังกฤษมาไว้ที่ lang/en ให้ (Laravel docs: Localization)
พอตั้ง locale เป็น th Laravel จะหาข้อความของกฎนั้นใน lang/th/validation.php ก่อน ถ้าไม่เจอจึงไปหาใน fallback_locale ผลที่ได้จึงมีสามแบบ
| ไฟล์ภาษาไทย | สิ่งที่ผู้ใช้เห็น |
|---|---|
| มีบรรทัดของกฎนั้น และแปลแล้ว | ข้อความภาษาไทย |
| มีบรรทัดนั้น แต่ยังเป็นภาษาอังกฤษ | ภาษาอังกฤษ แบบตัวอย่างข้างบน |
| ไม่มีบรรทัดนั้นเลย | ข้อความของ fallback_locale ถ้าเป็น en จะได้ภาษาอังกฤษ แต่ถ้าเป็นค่าที่ไม่มีไฟล์ เช่น en_US จะได้ key ดิบ ๆ อย่าง validation.ascii |
ส่วนชื่อช่องที่แทนลงใน :attribute กับ :other มาจาก attributes() ของ Form Request แต่ละตัว ไฟล์ภาษาดูแลแค่ประโยครอบชื่อช่อง ตัวอย่างข้างบนชื่อช่องจึงเป็นไทย แม้ประโยคจะยังเป็นอังกฤษ
Laravel ดูแลแค่ภาษาอังกฤษ ภาษาอื่นอยู่ที่ Laravel Lang
ใน framework มีโฟลเดอร์ภาษาเดียวคือ en ภาษาอื่นรวมถึงภาษาไทยอยู่ที่โปรเจกต์ชุมชนชื่อ Laravel Lang (laravel-lang/lang) ติดตั้งผ่าน laravel-lang/common แล้วเพิ่มภาษาด้วยคำสั่ง
composer require laravel-lang/common
php artisan lang:add th
หลังอัปเดตแพ็กเกจ สั่ง php artisan lang:update ไฟล์ภาษาจะตามกฎใหม่ให้ (Laravel Lang: Basic usage) และในรายการภาษาที่รองรับก็มีภาษาไทย
ที่ผ่านมาเรามักเลือกหนึ่งในสองทาง คือติดตั้ง Laravel Lang หรือคัดลอก lang/th/validation.php จากที่ไหนสักแห่งมาใส่ตอนเริ่มโปรเจกต์แล้วก็ลืมไป ผมเองก็ใช้ทางที่สองมาตลอด
ไฟล์ที่คัดลอกไว้ครั้งเดียวจะตามกฎใหม่ไม่ทัน
Laravel เพิ่มกฎ validation ใหม่แทบทุกรุ่น อย่าง ascii, decimal, uppercase, ulid, missing_*, present_*, contains, any_of หรือ required_if_declined แต่ละกฎมาพร้อมบรรทัดใหม่ในไฟล์ภาษาอังกฤษของ framework ไฟล์ภาษาไทยที่คัดลอกมาเมื่อหลายปีก่อนไม่มีบรรทัดเหล่านี้ และไม่มีอะไรเตือนเราเลย จนวันที่มีคนใช้กฎนั้นในฟอร์ม
อีกเรื่องที่เจอบ่อยคือไฟล์ที่แปลไม่ครบตั้งแต่แรก คนแปลเลือกแปลกฎที่ใช้บ่อย อย่าง required, email, min ส่วนบรรทัดที่เหลือปล่อยเป็นภาษาอังกฤษไว้ ไฟล์จึงดูเหมือนภาษาไทย แต่ข้างในยังมี "The :attribute…" อยู่หลายสิบบรรทัด
เลือกใช้ Laravel Lang หรือดูแลไฟล์เอง
| ทาง | ข้อดี | ข้อเสีย |
|---|---|---|
ติดตั้ง laravel-lang/common |
lang:update ตามกฎใหม่ให้เอง |
สำนวนเป็นของชุมชน และมี dependency เพิ่มหนึ่งตัว |
| ดูแลไฟล์ภาษาไทยเอง | สำนวนเดียวกันทุกระบบ ไม่มี dependency เพิ่ม | ต้องเพิ่มบรรทัดเองเมื่อ Laravel มีกฎใหม่ |
ถ้าไม่อยากดูแลไฟล์เอง Laravel Lang เป็นทางที่ดี ผมเลือกดูแลเองเพราะอยากให้ข้อความทุกระบบที่ดูแลอ่านเป็นสำนวนเดียวกัน แลกกับการต้องคอยเทียบไฟล์ทุกครั้งที่อัปเกรด Laravel
วิธีเขียนไฟล์ภาษาไทยให้อ่านเป็นภาษาเดียวกัน
แปลให้ครบทุกกฎที่ framework มี และตั้งหลักสำนวนไว้ก่อนลงมือ หลักที่ผมใช้คือกฎตระกูล required ทุกตัวใช้ประโยคเดียวกันว่า "กรุณาระบุ:attribute" เพราะเงื่อนไขอยู่บนหน้าจอให้ผู้ใช้เห็นอยู่แล้ว ในตัวอย่างข้างบน สวิตช์ออกใบกำกับภาษีเปิดอยู่ตรงหน้า ประโยคยาว ๆ อย่าง "จำเป็นต้องระบุที่อยู่เมื่อออกใบกำกับภาษีถูกยอมรับ" จึงไม่ได้บอกอะไรเพิ่ม คนไทยอ่านแบบสั้นแล้วเข้าใจเร็วกว่า
'required' => 'กรุณาระบุ:attribute',
'required_if' => 'กรุณาระบุ:attribute',
'required_if_accepted' => 'กรุณาระบุ:attribute',
'required_with' => 'กรุณาระบุ:attribute',
'email' => ':attribute ต้องเป็นอีเมลที่ถูกต้อง',
'unique' => 'มี:attributeนี้อยู่แล้ว',
'decimal' => ':attribute ต้องมีทศนิยม :decimal ตำแหน่ง',
'attributes' => [],
ปล่อย attributes ว่างไว้ แล้วตั้งชื่อช่องภาษาไทยใน attributes() ของ Form Request แต่ละตัวแทน ฟอร์มสองหน้าที่มีช่อง address เหมือนกันจะได้ใช้ชื่อต่างกันได้ ไฟล์ภาษาก็ดูแลแค่ประโยค ไม่ต้องรู้จักทุกช่องในระบบ
ตัวอย่างจากระบบหลังบ้านร้านค้าออนไลน์
ข้อความในตอนต้นโพสต์มาจากระบบหลังบ้านร้านค้าออนไลน์ของลูกค้าที่เราดูแล ระบบนี้ตั้ง locale เป็นไทยมาตั้งแต่แรก และมีไฟล์ lang/th/validation.php ที่คัดลอกมาตอนเริ่มโปรเจกต์ ฟอร์มสร้างคำสั่งซื้อใหม่มีสวิตช์ออกใบกำกับภาษี และช่องที่อยู่ใช้กฎ required_if_accepted:is_tax_invoice
พอเทียบไฟล์กับ framework ที่ใช้อยู่ (Laravel 12) ซึ่งมีข้อความ 135 key ไฟล์เดิมมีแค่ 111 key และ 79 บรรทัดในนั้นยังเป็นภาษาอังกฤษ รวม required_if_accepted ด้วย อีก 26 กฎไม่มีบรรทัดเลย เครื่องที่ตั้ง APP_FALLBACK_LOCALE=en_US ไว้ ถ้ามีฟอร์มไหนใช้กฎกลุ่มนั้น ผู้ใช้จะเห็น key ดิบแทนข้อความ
เราแปลใหม่ครบทุกกฎในสำนวนข้างบน แล้วเก็บไฟล์นี้ไว้ที่เดียวเป็นมาตรฐานของทุกโปรเจกต์ โปรเจกต์ใหม่ก็คัดลอกไปใช้ แทนการเพิ่มแพ็กเกจ ผมเก็บไว้ใน skill ของ Claude Code ที่ใช้ตั้งต้นและตรวจโปรเจกต์ Laravel ทุกตัว (วิธีที่ผมใช้ skill กับงานที่ไม่ใช่โค้ด) ระบบเดียวกันมี API ให้หน้าร้านที่ตอบภาษาไทยด้วย ไฟล์นี้จึงแก้ให้ทั้งสองฝั่งในคราวเดียว
เช็กไฟล์ของตัวเองวันนี้
ถ้าโปรเจกต์ไหนตั้ง locale เป็นไทยอยู่ ลองเปิด lang/th/validation.php เทียบกับไฟล์ภาษาอังกฤษของ framework รุ่นที่ใช้อยู่ดูครับ ค้นคำว่า The :attribute ก็พอเห็นแล้วว่ายังเหลือกี่บรรทัด และกฎไหนยังไม่มีในไฟล์ไทย ถ้าเลือกดูแลไฟล์เอง ทำแบบนี้อีกรอบทุกครั้งที่อัปเกรด Laravel
ถ้าอยากทบทวนว่า validation ใน Laravel เขียนได้กี่แบบ และข้อความ error มาจากตรงไหน ลองอ่านพื้นฐาน Laravel Validationต่อได้ครับ






