ทำไมวันที่และตัวเลขจึงต้องการการปรับให้เข้ากับท้องถิ่น

TABLE OF CONTENTS
หากคุณจัดส่งทั่วโลก สตริงเดียวกันสามารถมีความหมายต่างกันสำหรับผู้ใช้ต่างๆ: 12/01/2025
, 1.234
, 1,234
, 12:00
, 00:00
ความแตกต่างเล็กน้อยเหล่านี้ไม่ใช่เพียงแค่เรื่องของความสวยงาม—พวกมันส่งผลต่อความเชื่อถือ ความเข้าใจ และแม้กระทั่งการปฏิบัติตามกฎหมาย คู่มือฉบับนี้อธิบายว่าทำไมวันที่และตัวเลขต้องมีการแปลตามท้องถิ่น สิ่งที่เปลี่ยนแปลงจริงๆ ตามท้องถิ่น และวิธีการนำไปใช้ให้ถูกต้องทั่วทั้งผลิตภัณฑ์ของคุณ
สิ่งที่เปลี่ยนแปลงตามท้องถิ่น
- วันที่: ลำดับ (MDY vs DMY vs YMD), ตัวคั่น, ชื่อเดือน/วัน; บางตลาดใช้ปฏิทินที่ไม่ใช่ปฏิทินเกรกอเรียน
- เวลา: นาฬิกา 12 ชั่วโมง vs 24 ชั่วโมง, ตัวบ่งชี้ AM/PM, เขตเวลา, กฎการปรับเวลาตามฤดูกาล, วันเริ่มต้นสัปดาห์ (วันอาทิตย์ vs วันจันทร์)
- ตัวเลข: ตัวคั่นทศนิยม (
.
vs,
), รูปแบบการจัดกลุ่ม (1,234
vs1.234
vs1 234
), การจัดกลุ่มแบบอินเดีย (1,23,456
), ช่องว่างที่ไม่แตก, รูปแบบเครื่องหมายลบ/บวก (ขีด vs ลบแท้−
) - สกุลเงิน: สัญลักษณ์ vs รหัส ISO, ตำแหน่งสัญลักษณ์ (นำหน้า/ตามหลัง), ช่องว่างแคบ vs กว้าง, ความแม่นยำของทศนิยม (0, 2, หรือ 3+), การแสดงค่าลบในการบัญชี (เช่น
(1 234,56 €)
) - เปอร์เซ็นต์และหน่วย: การเว้นวรรคและตำแหน่งเครื่องหมาย (
50%
vs50 %
), ชื่อหน่วยตามท้องถิ่น, เมตริก vs อิมพีเรียล
ผลกระทบทางธุรกิจ
- ความเชื่อถือและการแปลง: ราคา ค่าธรรมเนียม และวันที่ที่ “ดูผิด” ลดการซื้อและเพิ่มการยกเลิก
- ความเสี่ยงในการดำเนินงาน: วันที่ที่อ่านผิดสามารถเปลี่ยนการจองหรือกำหนดเวลา; ข้อผิดพลาดในการแยกวิเคราะห์ทำให้ใบแจ้งหนี้ การส่งออก และการวิเคราะห์เสียหาย
- การปฏิบัติตามกฎระเบียบ: เอกสารทางการเงินที่มีรูปแบบผิดสามารถละเมิดกฎการออกใบแจ้งหนี้ ภาษี หรือการรายงาน
- ภาระงานสนับสนุน: ผู้ใช้เปิดตั๋วเพื่อชี้แจงเวลา สกุลเงิน และการป้อนตัวเลขที่ไม่ตรงกับความคาดหวัง
เหตุการณ์ในโลกจริง
แพลตฟอร์มการจองการเดินทางในยุโรปแสดงวันที่ออกเดินทางเป็น 01/03/2024
โดยไม่มีบริบทของท้องถิ่น ลูกค้าสหรัฐฯ ตีความว่าเป็น “วันที่ 3 มกราคม” ในขณะที่ลูกค้าในสหราชอาณาจักรและยุโรปอ่านว่า “วันที่ 1 มีนาคม”
ผลกระทบ:
- 12% ของการจองระหว่างประเทศถูกทำในวันที่ผิด
- ฝ่ายบริการลูกค้าได้รับตั๋วคำชี้แจงมากกว่า 3,400 ใบในหนึ่งสัปดาห์
- $2.3M ในการคืนเงินและค่าธรรมเนียมการจองใหม่
- 8% ของลูกค้าที่ได้รับผลกระทบเปลี่ยนไปใช้คู่แข่ง
สาเหตุหลัก: รูปแบบ DD/MM/YYYY
ที่ถูก hard-coded ในการยืนยันทางอีเมล ในขณะที่เว็บไซต์ใช้ MM/DD/YYYY
สำหรับผู้ใช้ในสหรัฐอเมริกา การแก้ไขใช้เวลาเพียง 3 ชั่วโมงของวิศวกร—ความคลุมเครือนี้มีค่าใช้จ่ายมากกว่า 800 เท่าของการป้องกัน
บทเรียน: วันที่ที่ไม่มีบริบทเป็นระเบิดเวลาสำหรับผลิตภัณฑ์ระดับโลกใดๆ
ข้อผิดพลาดทั่วไป
- รูปแบบที่ถูก hard-coded:
MM/DD/YYYY
หรือ1,234.56
ที่ฝังอยู่ใน UI, อีเมล, PDF หรือการส่งออก CSV - การจัดเก็บสตริงที่แปลแล้ว: การบันทึก “Dec 1, 2025” แทนที่จะเป็นเวลา ISO ทำให้เกิดข้อผิดพลาดในการแยกวิเคราะห์และการล่องลอยของเขตเวลา
- การแยกวิเคราะห์ที่ไร้เดียงสา: การใช้ค่าเริ่มต้นของเซิร์ฟเวอร์; การสันนิษฐานตัวคั่นหรือนาฬิกา 12/24 ชั่วโมง
- การต่อสตริง: การสร้าง “amount + currency” เช่น
"$" + 1234.56
แทนการจัดรูปแบบตามท้องถิ่น - ความคลุมเครือของเขตเวลา: การแสดงเวลาท้องถิ่นโดยไม่มีเขตที่ชัดเจนสำหรับการดำเนินการที่ไวต่อเวลา
- ความไม่สอดคล้องกันของเบราว์เซอร์: Safari, Firefox และ Chrome อาจจัดรูปแบบวันที่/ตัวเลขต่างกัน; ทดสอบเสมอในเบราว์เซอร์เป้าหมายทั้งหมด
- ช่องว่างในการเรนเดอร์ฝั่งเซิร์ฟเวอร์: Node.js ที่ไม่มีข้อมูล ICU เต็มรูปแบบ (
node --with-intl=full-icu
) ผลิตการจัดรูปแบบที่ไม่สมบูรณ์หรือไม่ถูกต้อง - กับดักประสิทธิภาพ: การสร้างอินสแตนซ์ใหม่
Intl.*
ในลูปหรือรอบการเรนเดอร์แทนการแคชตัวจัดรูปแบบ
แนวทางปฏิบัติที่ดีที่สุด
- เก็บค่ามาตรฐาน: วันที่/เวลาเป็น ISO‑8601 ใน UTC; เงินเป็นหน่วยย่อย (เซนต์) หรือทศนิยมความแม่นยำสูง
- แสดงผลตามท้องถิ่นของผู้ใช้: ใช้ API ที่รับรู้ท้องถิ่น (เช่น
Intl.DateTimeFormat
,Intl.NumberFormat
) สำหรับการแสดงผล - ตรวจสอบและแยกวิเคราะห์ตามท้องถิ่น: ยอมรับอินพุตท้องถิ่นเมื่อเหมาะสม; แสดงตัวอย่าง/ตัวอย่างเพื่อแนะนำผู้ใช้
- ระบุเวลาอย่างชัดเจน: แสดงตัวย่อหรือการชดเชยของเขตเวลา; อนุญาตให้ผู้ใช้เลือกเมื่อผลลัพธ์ขึ้นอยู่กับเวลา
- ความชัดเจนของสกุลเงิน: ใช้รหัส ISO เมื่อมีความคลุมเครือ; เคารพการวางสัญลักษณ์และการเว้นวรรคตามท้องถิ่น
- การจัดรูปแบบแบบรวมศูนย์: ชั้นยูทิลิตี้หนึ่งสำหรับทุกพื้นผิว (UI, อีเมล, PDF, ส่งออก) เพื่อให้แน่ใจว่ามีความสอดคล้อง
- แคชตัวจัดรูปแบบ: การเรียกตัวสร้าง
Intl.*
มีค่าใช้จ่ายสูง; สร้างครั้งเดียวและใช้ซ้ำอินสแตนซ์ต่อท้องถิ่น
เมื่อไม่ต้องแปลตามท้องถิ่น
ไม่ใช่ทุกอย่างที่ควรแปลตามท้องถิ่น นี่คือสถานการณ์ที่รูปแบบที่อ่านได้โดยเครื่องที่สอดคล้องกันดีกว่า:
- การส่งออกที่อ่านได้โดยเครื่อง: ไฟล์ CSV ที่ใช้โดยท่อข้อมูลหรือเครื่องมือวิเคราะห์ควรใช้รูปแบบคงที่ (เช่น วันที่ ISO-8601, จุดเป็นตัวคั่นทศนิยม) เอกสารรูปแบบนี้อย่างชัดเจนในส่วนหัวของการส่งออกหรือไฟล์ README
- การตอบสนองของ API: REST/GraphQL API ควรส่งคืนวันที่เป็นสตริง ISO-8601 และตัวเลขในรูปแบบ JSON มาตรฐาน ให้ลูกค้าจัดการการแปลตามท้องถิ่นตามความชอบของผู้ใช้
- บันทึกภายในและเมตริก: บันทึก, แดชบอร์ดการตรวจสอบ, และการสืบค้นฐานข้อมูลได้รับประโยชน์จากรูปแบบที่สอดคล้องกันสำหรับการแยกวิเคราะห์, การรวม, และการแจ้งเตือน ใช้ ISO-8601 และรูปแบบตัวเลขมาตรฐาน
- ตัวระบุที่เป็นมาตรฐาน: รหัสธุรกรรม, หมายเลขคำสั่งซื้อ, หรือการอ้างอิงที่ผู้ใช้อาจต้องสื่อสารข้ามท้องถิ่นควรหลีกเลี่ยงการจัดรูปแบบเฉพาะท้องถิ่น
กฎทั่วไป: แปลสำหรับมนุษย์ที่อ่านเนื้อหา; ใช้รูปแบบมาตรฐานสำหรับเครื่องที่ประมวลผลข้อมูล
แผนการดำเนินการ
- ตรวจสอบพื้นผิว: วันที่, เวลา, ตัวเลข, สกุลเงินใน UI, อีเมล, PDFs, การส่งออก CSV/Excel, การวิเคราะห์, บันทึก
- กำหนดพื้นที่: รายการพื้นที่ที่รองรับและการสำรองข้อมูลเริ่มต้น; ระบุนโยบาย 12/24 ชั่วโมงต่อพื้นที่
- สร้างยูทิลิตี้: ห่อ
Intl.*
APIs (หรือไลบรารี) ด้วยตัวช่วยและการทดสอบที่ใช้ร่วมกัน; ดำเนินการแคชการจัดรูปแบบ - กลยุทธ์การป้อนข้อมูล: อัปเดตแบบฟอร์มเพื่อยอมรับและตรวจสอบรูปแบบพื้นที่; เก็บค่ามาตรฐานพร้อมกับข้อมูลดิบ
- กฎเนื้อหา: จัดทำเอกสารสไตล์สำหรับวันที่สั้น/ยาว, วันที่สัมพันธ์, การแสดงสกุลเงิน, และการจัดรูปแบบเปอร์เซ็นต์
- การเปิดตัว: แปลงพื้นผิวที่มีการเข้าชมสูงและมีความเสี่ยงสูงก่อน; ส่งเบื้องหลังฟีเจอร์แฟล็กหากจำเป็น
กลยุทธ์การทดสอบ
นอกเหนือจาก QA ด้วยตนเอง ให้ดำเนินการทดสอบอัตโนมัติเพื่อป้องกันการถดถอย:
- การทดสอบสแนปชอต: แช่แข็งผลลัพธ์ที่จัดรูปแบบสำหรับแต่ละพื้นที่ที่รองรับ การเปลี่ยนแปลงจะกระตุ้นการตรวจสอบเพื่อให้แน่ใจว่ามีเจตนา
- การทดสอบแบบรอบทริป: ตรวจสอบว่า
format → parse → format
ให้ผลลัพธ์ที่เสถียร จับการสูญเสียความแม่นยำหรือรูปแบบที่ไม่ชัดเจน - กรณีขอบ: ทดสอบตัวเลขติดลบ, ศูนย์, ตัวเลขขนาดใหญ่มาก (พันล้าน/ล้านล้าน), การเปลี่ยนแปลง DST, ปีอธิกสุรทิน, และวันที่ขอบเขต (1 ม.ค., 31 ธ.ค.)
- การตรวจสอบข้ามเบราว์เซอร์: การทดสอบอัตโนมัติบน Chrome, Firefox, Safari, และ Edge เพื่อตรวจจับความแตกต่างในการแสดงผล
- การสำรองข้อมูลพื้นที่: ตรวจสอบการเสื่อมสภาพอย่างราบรื่นเมื่อมีการร้องขอพื้นที่ที่ไม่รองรับ
- เกณฑ์มาตรฐานประสิทธิภาพ: วัดต้นทุนการสร้างตัวจัดรูปแบบ; ตรวจสอบให้แน่ใจว่าการแคชทำงานในสภาพแวดล้อมการผลิต
เคล็ดลับประสิทธิภาพ
Intl.*
APIs ทรงพลังแต่สามารถช้าได้หากใช้งานผิดวิธี ปฏิบัติตามแนวทางเหล่านี้:
// ❌ ไม่ดี: สร้างตัวจัดรูปแบบใหม่ทุกครั้งที่เรียก
function formatPrice(amount, locale) {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency: 'USD'
}).format(amount);
}
// ✅ GOOD: Cache formatters per locale
const formatters = new Map();
function getFormatter(locale) {
if (!formatters.has(locale)) {
formatters.set(locale, new Intl.NumberFormat(locale, {
style: 'currency',
currency: 'USD'
}));
}
return formatters.get(locale);
}
function formatPrice(amount, locale) {
return getFormatter(locale).format(amount);
}
- แคชอินสแตนซ์ของฟอร์แมตเตอร์: การสร้าง
Intl.*
มีค่าใช้จ่ายสูง (~1–5ms); การจัดรูปแบบด้วยอินสแตนซ์ที่มีอยู่แล้วรวดเร็ว (~0.01ms) - หลีกเลี่ยงลูป: อย่าสร้างฟอร์แมตเตอร์ภายใน
map()
,forEach()
, หรือลูปการเรนเดอร์ - โหลดข้อมูลท้องถิ่นแบบ Lazy-load: สำหรับเว็บแอป ให้พิจารณาการแยกโค้ดเพื่อโหลดเฉพาะท้องถิ่นที่จำเป็น ลดขนาดบันเดิล
- ฝั่งเซิร์ฟเวอร์: ใช้ฟอร์แมตเตอร์เดียวต่อรอบการร้องขอ/ตอบกลับ; หลีกเลี่ยงการสร้างต่อรายการในชุดข้อมูลขนาดใหญ่
รายการตรวจสอบ QA
- วันที่ไม่คลุมเครือใน
en-US
,en-GB
,de-DE
,fr-FR
,hi-IN
,ja-JP
,ar-EG
- เวลาใช้รูปแบบ 12/24 ชั่วโมงที่ถูกต้อง; ตัวบ่งชี้ AM/PM ปรากฏตามที่คาดหวัง; โซนเวลาปรากฏในกระบวนการที่สำคัญต่อเวลา
- ตัวเลขใช้ตัวคั่นทศนิยมและกลุ่มที่ถูกต้อง; เว้นวรรคที่ไม่แตกหักตามมาตรฐาน (เช่น
fr-FR
) - สกุลเงินแสดงสัญลักษณ์/รหัสที่ถูกต้อง, ตำแหน่ง, และความละเอียดทศนิยมสำหรับแต่ละท้องถิ่น; แสดงค่าลบอย่างถูกต้อง
- อินพุตยอมรับและแยกวิเคราะห์ข้อมูลท้องถิ่นของผู้ใช้ (หรือบังคับใช้รูปแบบที่รองรับอย่างชัดเจน); ข้อความการตรวจสอบความถูกต้องรับรู้ท้องถิ่น
- การส่งออก (CSV/PDF) ตรงกับความคาดหวังของท้องถิ่นหรือเอกสารรูปแบบคงที่สำหรับการบริโภคของเครื่องอย่างชัดเจน
- ข้ามเบราว์เซอร์: วันที่, เวลา, และตัวเลขแสดงผลสม่ำเสมอบน Chrome, Firefox, Safari, และ Edge
- ประสิทธิภาพ: ไม่มีการสร้างฟอร์แมตเตอร์ในลูป; อินสแตนซ์ที่แคชถูกใช้ซ้ำในการเรนเดอร์
ตัวอย่างโค้ด
JavaScript
// Dates
const date = new Date('2025-01-12T00:00:00Z');
console.log(new Intl.DateTimeFormat('en-US', { dateStyle: 'short', timeZone: 'UTC' }).format(date));
// → 1/12/25
```javascript
console.log(new Intl.DateTimeFormat('en-GB', { dateStyle: 'short', timeZone: 'UTC' }).format(date));
// → 12/01/2025 (day/month/year)
console.log(new Intl.DateTimeFormat('ja-JP', { dateStyle: 'medium', timeZone: 'UTC' }).format(date));
// → 2025/01/12
// Times with timezone display
const time = new Date('2025-01-12T18:05:00Z');
console.log(new Intl.DateTimeFormat('en-US', {
dateStyle: 'short',
timeStyle: 'short',
timeZone: 'America/New_York',
timeZoneName: 'short'
}).format(time));
// → 1/12/25, 1:05 PM EST
console.log(new Intl.DateTimeFormat('de-DE', {
timeStyle: 'short',
timeZone: 'Europe/Berlin',
hour12: false
}).format(time));
// → 19:05
// Numbers
const n = 1234.56;
console.log(new Intl.NumberFormat('en-US').format(n)); // → 1,234.56
console.log(new Intl.NumberFormat('de-DE').format(n)); // → 1.234,56
console.log(new Intl.NumberFormat('fr-FR').format(n)); // → 1 234,56 (NBSP as group separator)
// Indian numbering
console.log(new Intl.NumberFormat('hi-IN').format(1234567.89)); // → 12,34,567.89
// Currency
console.log(new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(n));
// → $1,234.56
console.log(new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(n));
// → 1.234,56 €
console.log(new Intl.NumberFormat('ja-JP', { style: 'currency', currency: 'JPY' }).format(1234));
// → ¥1,234 (no decimals)
// Percent and units
console.log(new Intl.NumberFormat('en-US', { style: 'percent', maximumFractionDigits: 0 }).format(0.5));
// → 50%
console.log(new Intl.NumberFormat('fr-FR', { style: 'percent', maximumFractionDigits: 0 }).format(0.5));
// → 50 %
// Formatter caching example
class LocaleFormatter {
constructor() {
this.cache = new Map();
}
getDateFormatter(locale, options) {
const key = `date:${locale}:${JSON.stringify(options)}`;
if (!this.cache.has(key)) {
this.cache.set(key, new Intl.DateTimeFormat(locale, options));
}
return this.cache.get(key);
}
formatDate(date, locale, options = { dateStyle: 'medium' }) {
return this.getDateFormatter(locale, options).format(date);
}
}
const formatter = new LocaleFormatter();
console.log(formatter.formatDate(new Date(), 'en-US')); // → Jan 12, 2025
console.log(formatter.formatDate(new Date(), 'fr-FR')); // → 12 janv. 2025
Python
from babel.dates import format_date, format_time, format_datetime
from babel.numbers import format_number, format_currency, format_percent
from datetime import datetime
import pytz
# Dates
date = datetime(2025, 1, 12)
print(format_date(date, format='short', locale='en_US')) # → 1/12/25
print(format_date(date, format='short', locale='en_GB')) # → 12/01/2025
print(format_date(date, format='medium', locale='ja_JP')) # → 2025/01/12
# Times with timezone
tz_ny = pytz.timezone('America/New_York')
tz_berlin = pytz.timezone('Europe/Berlin')
time = datetime(2025, 1, 12, 18, 5, tzinfo=pytz.UTC)
print(format_datetime(time.astimezone(tz_ny), 'short', tzinfo=tz_ny, locale='en_US'))
# → 1/12/25, 1:05 PM
print(format_time(time.astimezone(tz_berlin), format='short', tzinfo=tz_berlin, locale='de_DE'))
# → 19:05
# Numbers
n = 1234.56
print(format_number(n, locale='en_US')) # → 1,234.56
print(format_number(n, locale='de_DE')) # → 1.234,56
print(format_number(n, locale='fr_FR')) # → 1 234,56
# Indian numbering
print(format_number(1234567.89, locale='hi_IN')) # → 12,34,567.89
# Currency
print(format_currency(n, 'USD', locale='en_US')) # → $1,234.56
print(format_currency(n, 'EUR', locale='de_DE')) # → 1.234,56 €
print(format_currency(1234, 'JPY', locale='ja_JP')) # → ¥1,234
# Percent
print(format_percent(0.5, locale='en_US')) # → 50%
print(format_percent(0.5, locale='fr_FR')) # → 50 %
Java
import java.text.NumberFormat;
import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;
import java.util.Currency;
// Dates
ZonedDateTime date = ZonedDateTime.of(2025, 1, 12, 0, 0, 0, 0, ZoneId.of("UTC"));
DateTimeFormatter usFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)
.withLocale(Locale.US);
System.out.println(usFormatter.format(date)); // → 1/12/25
DateTimeFormatter gbFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)
.withLocale(Locale.UK);
System.out.println(gbFormatter.format(date)); // → 12/01/2025
DateTimeFormatter jpFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
.withLocale(Locale.JAPAN);
System.out.println(jpFormatter.format(date)); // → 2025/01/12
// Times
ZonedDateTime time = ZonedDateTime.of(2025, 1, 12, 18, 5, 0, 0, ZoneId.of("UTC"));
ZonedDateTime timeNY = time.withZoneSameInstant(ZoneId.of("America/New_York"));
DateTimeFormatter usTimeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
.withLocale(Locale.US);
System.out.println(usTimeFormatter.format(timeNY)); // → 1:05 PM
// Numbers
double n = 1234.56;
NumberFormat usFormat = NumberFormat.getInstance(Locale.US);
System.out.println(usFormat.format(n)); // → 1,234.56
NumberFormat deFormat = NumberFormat.getInstance(Locale.GERMANY);
System.out.println(deFormat.format(n)); // → 1.234,56
NumberFormat frFormat = NumberFormat.getInstance(Locale.FRANCE);
System.out.println(frFormat.format(n)); // → 1 234,56
// Currency
NumberFormat usCurrency = NumberFormat.getCurrencyInstance(Locale.US);
usCurrency.setCurrency(Currency.getInstance("USD"));
System.out.println(usCurrency.format(n)); // → $1,234.56
NumberFormat deCurrency = NumberFormat.getCurrencyInstance(Locale.GERMANY);
deCurrency.setCurrency(Currency.getInstance("EUR"));
System.out.println(deCurrency.format(n)); // → 1.234,56 €
NumberFormat jpCurrency = NumberFormat.getCurrencyInstance(Locale.JAPAN); jpCurrency.setCurrency(Currency.getInstance(“JPY”)); System.out.println(jpCurrency.format(1234)); // → ¥1,234
### Go
```go
package main
import (
"fmt"
"time"
"golang.org/x/text/language"
"golang.org/x/text/message"
"golang.org/x/text/number"
)
func main() {
// Numbers
n := 1234.56
pUS := message.NewPrinter(language.AmericanEnglish)
fmt.Println(pUS.Sprintf("%.2f", n)) // → 1,234.56
pDE := message.NewPrinter(language.German)
fmt.Println(pDE.Sprintf("%.2f", n)) // → 1.234,56
pFR := message.NewPrinter(language.French)
fmt.Println(pFR.Sprintf("%.2f", n)) // → 1 234,56
// Currency (using number package)
fmt.Println(pUS.Sprint(number.Decimal(n, number.Scale(2)))) // → 1,234.56
// Dates - Go's time package uses layouts instead of locale formatting
// For full i18n date formatting, use github.com/goodsign/monday or similar
date := time.Date(2025, 1, 12, 0, 0, 0, 0, time.UTC)
fmt.Println(date.Format("01/02/2006")) // US: 01/12/2025
fmt.Println(date.Format("02/01/2006")) // EU: 12/01/2025
fmt.Println(date.Format("2006/01/02")) // ISO: 2025/01/12
}
หมายเหตุ: ไลบรารีมาตรฐานของ Go มีการสนับสนุน locale จำกัด สำหรับการใช้งานในโปรดักชั่น พิจารณา:
golang.org/x/text
สำหรับการจัดรูปแบบตัวเลขgithub.com/goodsign/monday
สำหรับการจัดรูปแบบวันที่/เวลาแบบ localizedgithub.com/bojanz/currency
สำหรับการจัดการสกุลเงิน
แหล่งข้อมูลที่มีประโยชน์
- มาตรฐาน: Unicode CLDR (มาตรฐานข้อมูลท้องถิ่น), IETF BCP 47 (ตัวระบุท้องถิ่น)
- เอกสาร: MDN Intl Reference
- ไลบรารี:
- Luxon (ไลบรารีวันที่/เวลาแบบสมัยใหม่พร้อม i18n)
- date-fns พร้อมโมดูลท้องถิ่น
- Globalize.js (i18n ครอบคลุมตาม CLDR)
- Format.js (i18n ที่เน้น React พร้อมไวยากรณ์ข้อความ ICU)
- การทดสอบ: Intl polyfill สำหรับเบราว์เซอร์รุ่นเก่า
ปิด
การจัดการวันที่และตัวเลขให้ถูกต้องเป็นการลงทุนที่ใช้ความพยายามน้อยแต่ให้ผลกระทบสูง: เพิ่มความเชื่อถือ ลดข้อผิดพลาด และสร้างประสบการณ์ระดับโลกที่ราบรื่น การจัดรูปแบบให้เป็นศูนย์กลาง เก็บค่ามาตรฐาน ใช้ API ที่รับรู้ท้องถิ่นทุกที่ที่ผู้ใช้ของคุณอ่านหรือพิมพ์เวลา เงิน หรือเลข—และรู้ว่าเมื่อใดควรข้ามการแปลสำหรับข้อมูลที่เครื่องอ่านได้ ด้วยการแคชและการทดสอบที่เหมาะสม คุณจะสร้างระบบที่แข็งแกร่งซึ่งขยายได้ทั่วท้องถิ่นโดยไม่ลดทอนประสิทธิภาพ