วิธีตั้ง Laravel validation message เป็นภาษาไทยให้ครบทุกกฎ

Laravel มีข้อความ validation มาแค่ภาษาอังกฤษ ไฟล์ lang/th/validation.php ที่คัดลอกมาตอนเริ่มโปรเจกต์จึงค่อย ๆ ตามกฎใหม่ไม่ทัน แปลให้ครบทุกกฎในสำนวนเดียวกัน แล้วเทียบกับไฟล์ภาษาอังกฤษของ framework ทุกครั้งที่อัปเกรด ภาษาอังกฤษจะไม่หลุดไปถึงผู้ใช้

ในโพสต์นี้ 7 หัวข้อ
  1. ข้อความ validation มาจากไฟล์ภาษาของ Laravel
  2. Laravel ดูแลแค่ภาษาอังกฤษ ภาษาอื่นอยู่ที่ Laravel Lang
  3. ไฟล์ที่คัดลอกไว้ครั้งเดียวจะตามกฎใหม่ไม่ทัน
  4. เลือกใช้ Laravel Lang หรือดูแลไฟล์เอง
  5. วิธีเขียนไฟล์ภาษาไทยให้อ่านเป็นภาษาเดียวกัน
  6. ตัวอย่างจากระบบหลังบ้านร้านค้าออนไลน์
  7. เช็กไฟล์ของตัวเองวันนี้

ฟอร์มหลังบ้านภาษาไทยทั้งหน้า แต่พอเปิดสวิตช์ "ออกใบกำกับภาษี" แล้วกดบันทึกโดยยังไม่เลือกที่อยู่ ใต้ช่องกลับขึ้นข้อความว่า

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ต่อได้ครับ

อ่านต่อ

ล่าสุด

ดูทั้งหมด →