Now.js Framework Documentation
I18nManager - ระบบจัดการหลายภาษา
I18nManager - ระบบจัดการหลายภาษา
เอกสารสำหรับ I18nManager ซึ่งเป็นระบบจัดการภาษาหลายภาษา (Internationalization/Localization)
📋 สารบัญ
- ภาพรวม
- การติดตั้งและนำเข้า
- การใช้งานพื้นฐาน
- ไฟล์คำแปล
- การทำงานร่วมกับ HTML
- การแปลแบบไดนามิก
- การแทรกค่าพารามิเตอร์
- การจัดการภาษา
- การตั้งค่า
- ตัวอย่างการใช้งาน
- เอกสารอ้างอิง API
- แนวทางปฏิบัติที่ดี
ภาพรวม
I18nManager เป็นระบบจัดการภาษาหลายภาษาที่ช่วยให้แอปพลิเคชันรองรับหลายภาษาได้อย่างง่ายดาย
คุณสมบัติหลัก
- ✅ Multiple Locales: รองรับภาษาหลายภาษา
- ✅ Auto Detection: ตรวจจับภาษาเบราว์เซอร์อัตโนมัติ
- ✅ HTML Integration: อัปเดต DOM elements อัตโนมัติ
- ✅ Parameter Interpolation: แทรกค่าตัวแปรใน translations
- ✅ Lazy Loading: โหลด translations เมื่อต้องการ
- ✅ LocalStorage: จดจำภาษาที่เลือก
- ✅ Fallback: ใช้ fallback เมื่อหาคำแปลไม่เจอ
- ✅ Nested Keys: รองรับ nested object keys
- ✅ Event System: Emit events เมื่อเปลี่ยนภาษา
- ✅ No Translation Mode: ข้ามการแปลสำหรับภาษาอังกฤษ
กรณีการใช้งาน
✅ เหมาะสำหรับ:
- แอปพลิเคชันหลายภาษา
- เว็บแอปสำหรับผู้ใช้ทั่วโลก
- ระบบปรับภาษาให้ตรงกับความต้องการผู้ใช้
- ระบบจัดการเนื้อหา (CMS)
- แพลตฟอร์มอีคอมเมิร์ซ
- บริการรูปแบบ SaaS
การติดตั้งและนำเข้า
I18nManager โหลดพร้อมกับ Now.js Framework:
// ไม่ต้อง import - พร้อมใช้งานทันที
console.log(window.I18nManager); // I18nManager object
// เข้าถึงผ่าน Now.js
const i18n = Now.getManager('i18n');โมดูลที่จำเป็น
I18nManager ต้องการ dependencies เหล่านี้:
- ErrorManager - สำหรับจัดการข้อผิดพลาด
- ApiService หรือ simpleFetch - สำหรับโหลด translation files
- EventManager - สำหรับ emit events (optional)
การใช้งานพื้นฐาน
1. เริ่มต้นใช้งาน
// การตั้งค่าเริ่มต้นใช้งาน
await I18nManager.init({
enabled: true,
defaultLocale: 'en',
availableLocales: ['en', 'th', 'ja'],
storageKey: 'app_lang',
useBrowserLocale: true,
noTranslateEnglish: true
});
// ตรวจสอบภาษาปัจจุบัน
console.log(I18nManager.getCurrentLocale()); // 'en'2. เปลี่ยนภาษา
// เปลี่ยนภาษาเป็นไทย
await I18nManager.setLocale('th');
// เปลี่ยนภาษาและบังคับให้อัปเดตทันที (force update)
await I18nManager.setLocale('en', true);3. แปลข้อความ
// แปลโดยใช้ key
const greeting = I18nManager.translate('greeting.hello');
console.log(greeting); // 'สวัสดี'
// แปลพร้อมส่งพารามิเตอร์
const welcome = I18nManager.translate('greeting.welcome', {
name: 'John'
});
console.log(welcome); // 'ยินดีต้อนรับ John'4. ฟัง Events
// ฟัง event เมื่อเปลี่ยนภาษา
Now.on('locale:changed', (data) => {
console.log('Locale changed to:', data.locale);
console.log('Forced:', data.forced);
});
// ฟัง event เมื่อ initialized
Now.on('i18n:initialized', () => {
console.log('I18n system ready');
});
// ฟัง event เมื่อ update elements
Now.on('i18n:elements:updated', (data) => {
console.log('Updated elements:', data.elementsUpdated);
console.log('Current locale:', data.locale);
});ไฟล์คำแปล
โครงสร้างไฟล์
ไฟล์คำแปลต้องอยู่ในโฟลเดอร์ translations/ และใช้รูปแบบไฟล์ JSON:
translations/
├── en.json
├── th.json
├── ja.json
└── zh.jsonรูปแบบไฟล์คำแปล
// translations/en.json
{
"app": {
"name": "My Application",
"tagline": "The best app ever"
},
"greeting": {
"hello": "Hello",
"goodbye": "Goodbye",
"welcome": "Welcome {name}",
"welcomeBack": "Welcome back, {name}!"
},
"button": {
"save": "Save",
"cancel": "Cancel",
"delete": "Delete",
"confirm": "Confirm"
},
"validation": {
"required": "This field is required",
"email": "Please enter a valid email",
"minLength": "Minimum {min} characters required",
"maxLength": "Maximum {max} characters allowed"
},
"message": {
"success": "Operation completed successfully",
"error": "An error occurred",
"loading": "Loading..."
}
}// translations/th.json
{
"app": {
"name": "แอปพลิเคชันของฉัน",
"tagline": "แอปที่ดีที่สุด"
},
"greeting": {
"hello": "สวัสดี",
"goodbye": "ลาก่อน",
"welcome": "ยินดีต้อนรับ {name}",
"welcomeBack": "ยินดีต้อนรับกลับมา {name}"
},
"button": {
"save": "บันทึก",
"cancel": "ยกเลิก",
"delete": "ลบ",
"confirm": "ยืนยัน"
},
"validation": {
"required": "กรุณากรอกข้อมูลในช่องนี้",
"email": "กรุณากรอกอีเมลให้ถูกต้อง",
"minLength": "ต้องมีอย่างน้อย {min} ตัวอักษร",
"maxLength": "มีได้สูงสุด {max} ตัวอักษร"
},
"message": {
"success": "ดำเนินการสำเร็จ",
"error": "เกิดข้อผิดพลาด",
"loading": "กำลังโหลด..."
}
}คีย์แบบซ้อน
// ใช้ dot notation สำหรับ nested keys
I18nManager.translate('app.name'); // 'My Application'
I18nManager.translate('greeting.hello'); // 'Hello'
I18nManager.translate('validation.required'); // 'This field is required'การทำงานร่วมกับ HTML
แอตทริบิวต์ data-i18n
<!-- ใช้ data-i18n เพื่อแปลอัตโนมัติ -->
<h1 data-i18n="app.name">My Application</h1>
<p data-i18n="app.tagline">The best app ever</p>
<!-- ปุ่ม -->
<button data-i18n="button.save">Save</button>
<button data-i18n="button.cancel">Cancel</button>
<button data-i18n="button.delete">Delete</button>
<!-- ข้อความ placeholder ของ input -->
<input type="text" placeholder="Email" data-i18n="form.email">
<textarea placeholder="Message" data-i18n="form.message"></textarea>การแปลอัตโนมัติ
// เมื่อเปลี่ยนภาษา elements จะถูกแปลอัตโนมัติ
await I18nManager.setLocale('th');
// <h1 data-i18n="app.name">แอปพลิเคชันของฉัน</h1>
// <button data-i18n="button.save">บันทึก</button>อัปเดตเฉพาะคอนเทนเนอร์ที่ต้องการ
// อัปเดตเฉพาะใน container
const container = document.querySelector('#content');
await I18nManager.updateElements(container);
// อัปเดตทั้งหน้า
await I18nManager.updateElements();การแปลแบบไดนามิก
เมธอด translate()
// แปลข้อความใน JavaScript
const greeting = I18nManager.translate('greeting.hello');
console.log(greeting); // 'Hello' หรือ 'สวัสดี'
// แปลพร้อมใช้ค่า fallback
const message = I18nManager.translate('unknown.key');
console.log(message); // 'unknown.key' (ใช้ key เป็นค่า fallback)การแปลโดยระบุภาษา
// แปลในภาษาเฉพาะ (ไม่เปลี่ยนภาษาปัจจุบัน)
const enGreeting = I18nManager.translate('greeting.hello', {}, 'en');
const thGreeting = I18nManager.translate('greeting.hello', {}, 'th');
console.log(enGreeting); // 'Hello'
console.log(thGreeting); // 'สวัสดี'รับฟังก์ชันแปลตามภาษา
// สร้าง translator function สำหรับภาษาเฉพาะ
const t = I18nManager.getTranslator('th');
console.log(t('greeting.hello')); // 'สวัสดี'
console.log(t('button.save')); // 'บันทึก'
// รองรับการส่งพารามิเตอร์
console.log(t('greeting.welcome', {name: 'John'})); // 'ยินดีต้อนรับ John'การแทรกค่าพารามิเตอร์
การแทรกแบบพื้นฐาน
// การแปลด้วย placeholder รูปแบบ {key}
// "welcome": "Welcome {name}"
const message = I18nManager.translate('greeting.welcome', {
name: 'John'
});
console.log(message); // 'Welcome John'การแทรกหลายพารามิเตอร์
// "userInfo": "User {name} has {count} items"
const info = I18nManager.translate('user.info', {
name: 'Alice',
count: 5
});
console.log(info); // 'User Alice has 5 items'ข้อความตรวจสอบข้อมูล (Validation)
// "minLength": "Minimum {min} characters required"
// "maxLength": "Maximum {max} characters allowed"
const minMsg = I18nManager.translate('validation.minLength', {
min: 8
});
console.log(minMsg); // 'Minimum 8 characters required'
const maxMsg = I18nManager.translate('validation.maxLength', {
max: 100
});
console.log(maxMsg); // 'Maximum 100 characters allowed'การอ้างอิงคีย์แบบซ้อน
// พารามิเตอร์สามารถอ้างถึงคีย์อื่นได้
// "message": "Welcome to {app.name}"
const welcome = I18nManager.translate('greeting.message');
console.log(welcome); // 'Welcome to My Application'การจัดการภาษา
ตรวจสอบภาษาปัจจุบัน
const currentLocale = I18nManager.getCurrentLocale();
console.log(currentLocale); // 'en'ดึงคำแปลที่มีอยู่
// ได้รับ translations ทั้งหมดของภาษาปัจจุบัน
const translations = I18nManager.getTranslations();
console.log(translations);
// {
// app: { name: 'My Application', ... },
// greeting: { hello: 'Hello', ... },
// ...
// }
// ได้รับ translations ของภาษาเฉพาะ
const thTranslations = I18nManager.getTranslations('th');ดูคำแปลของคีย์ในทุกภาษา
// ได้รับการแปลของ key ในทุกภาษา
const translations = I18nManager.getKeyTranslations('greeting.hello');
console.log(translations);
// {
// en: 'Hello',
// th: 'สวัสดี',
// ja: 'こんにちは'
// }ตรวจสอบว่ามีคำแปลหรือไม่
// ตรวจสอบว่ามีการแปลหรือไม่
const exists = I18nManager.hasTranslation('greeting.hello');
console.log(exists); // true
const notExists = I18nManager.hasTranslation('unknown.key');
console.log(notExists); // false
// ตรวจสอบในภาษาเฉพาะ
const hasThTranslation = I18nManager.hasTranslation('greeting.hello', 'th');การตั้งค่า
ตัวเลือกการตั้งค่า
const config = {
// เปิด/ปิด ระบบ i18n
enabled: true,
// ภาษาเริ่มต้น
defaultLocale: 'en',
// ภาษาที่รองรับ
availableLocales: ['en', 'th', 'ja', 'zh'],
// localStorage key สำหรับเก็บภาษาที่เลือก
storageKey: 'app_lang',
// ใช้ภาษาของเบราว์เซอร์เป็นเริ่มต้น
useBrowserLocale: true,
// ข้ามการแปลสำหรับภาษาอังกฤษ
// เมื่อเป็น true ภาษาอังกฤษจะไม่ต้องโหลด translation file
noTranslateEnglish: true
};
await I18nManager.init(config);ตัวเลือก noTranslateEnglish
// เมื่อ noTranslateEnglish = true
// ภาษาอังกฤษจะ return key โดยตรง ไม่ต้องโหลด translation file
await I18nManager.init({
enabled: true,
defaultLocale: 'en',
availableLocales: ['en', 'th'],
noTranslateEnglish: true
});
// เมื่อภาษาเป็น 'en' จะไม่โหลด en.json
await I18nManager.setLocale('en');
I18nManager.translate('greeting.hello'); // 'greeting.hello'
// เมื่อเปลี่ยนเป็น 'th' จะโหลด th.json
await I18nManager.setLocale('th');
I18nManager.translate('greeting.hello'); // 'สวัสดี'ปิดการทำงานของ I18n
// ปิดระบบ i18n
await I18nManager.init({
enabled: false
});
// เมื่อปิด method ทั้งหมดจะไม่ทำงาน
await I18nManager.setLocale('th'); // ไม่ทำอะไร
I18nManager.translate('key'); // return 'key'ตัวอย่างการใช้งาน
1. เว็บไซต์หลายภาษา
// เริ่มต้นใช้งาน i18n
await I18nManager.init({
enabled: true,
defaultLocale: 'en',
availableLocales: ['en', 'th', 'ja', 'zh'],
storageKey: 'website_lang',
useBrowserLocale: true
});
// HTML ตัวอย่าง
/*
<nav>
<select id="lang-selector">
<option value="en">English</option>
<option value="th">ไทย</option>
<option value="ja">日本語</option>
<option value="zh">中文</option>
</select>
</nav>
<main>
<h1 data-i18n="page.title">Welcome</h1>
<p data-i18n="page.description">This is a multi-language website</p>
<button data-i18n="button.getStarted">Get Started</button>
</main>
*/
// ส่วนเลือกภาษา
const selector = document.querySelector('#lang-selector');
selector.value = I18nManager.getCurrentLocale();
selector.addEventListener('change', async (e) => {
await I18nManager.setLocale(e.target.value);
});
// ฟัง event เมื่อมีการเปลี่ยนภาษา
Now.on('locale:changed', (data) => {
console.log('Language changed to:', data.locale);
// อัปเดต UI อื่นๆ ที่ต้องการ
updateUI();
});2. ตรวจสอบฟอร์มพร้อมคำแปล
// ตรวจสอบฟอร์มพร้อมข้อความที่ถูกแปล
function validateForm(formData) {
const errors = [];
// ตรวจสอบช่องบังคับ
if (!formData.email) {
errors.push(I18nManager.translate('validation.required'));
}
// ตรวจสอบรูปแบบอีเมล
if (formData.email && !isValidEmail(formData.email)) {
errors.push(I18nManager.translate('validation.email'));
}
// ความยาวขั้นต่ำ
if (formData.password && formData.password.length < 8) {
errors.push(I18nManager.translate('validation.minLength', {
min: 8
}));
}
// ความยาวสูงสุด
if (formData.bio && formData.bio.length > 500) {
errors.push(I18nManager.translate('validation.maxLength', {
max: 500
}));
}
return errors;
}
// การใช้งาน
const formData = {
email: '',
password: '123',
bio: 'Some text...'
};
const errors = validateForm(formData);
errors.forEach(error => {
console.error(error);
});3. การแปลคอนเทนต์แบบไดนามิก
// แปล content ที่โหลดจาก API
async function loadUserProfile(userId) {
const user = await fetchUser(userId);
// แปล UI
const container = document.querySelector('#profile');
container.innerHTML = `
<h2>${user.name}</h2>
<p data-i18n="profile.memberSince">Member since</p>
<p>${user.joinDate}</p>
<button data-i18n="button.edit">Edit</button>
<button data-i18n="button.save">Save</button>
`;
// อัปเดต translations
await I18nManager.updateElements(container);
}4. ข้อความแจ้งเตือน
// สร้าง notification พร้อมแปลภาษา
function showNotification(type, messageKey, params = {}) {
const message = I18nManager.translate(messageKey, params);
const notification = document.createElement('div');
notification.className = `notification notification-${type}`;
notification.textContent = message;
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 3000);
}
// การใช้งาน
showNotification('success', 'message.success');
showNotification('error', 'message.error');
showNotification('info', 'user.welcomeBack', {name: 'John'});5. รถเข็นสินค้าแบบหลายภาษา
// รถเข็นสินค้าในระบบอีคอมเมิร์ซ
class ShoppingCart {
constructor() {
this.items = [];
}
addItem(product, quantity) {
this.items.push({product, quantity});
const message = I18nManager.translate('cart.itemAdded', {
name: product.name,
quantity: quantity
});
showNotification('success', message);
}
removeItem(index) {
const item = this.items[index];
this.items.splice(index, 1);
const message = I18nManager.translate('cart.itemRemoved', {
name: item.product.name
});
showNotification('info', message);
}
getTotal() {
const total = this.items.reduce((sum, item) => {
return sum + (item.product.price * item.quantity);
}, 0);
return I18nManager.translate('cart.total', {
amount: total.toFixed(2)
});
}
render() {
const container = document.querySelector('#cart');
if (this.items.length === 0) {
container.innerHTML = `
<p data-i18n="cart.empty">Your cart is empty</p>
`;
} else {
container.innerHTML = `
<h2 data-i18n="cart.title">Shopping Cart</h2>
<ul>
${this.items.map(item => `
<li>
${item.product.name} x ${item.quantity}
<button data-i18n="button.remove">Remove</button>
</li>
`).join('')}
</ul>
<p>${this.getTotal()}</p>
<button data-i18n="button.checkout">Checkout</button>
`;
}
I18nManager.updateElements(container);
}
}6. การแปลวันที่และเวลา
// จัดรูปแบบวันที่ตามภาษา
function formatDate(date) {
const locale = I18nManager.getCurrentLocale();
const formatted = new Intl.DateTimeFormat(locale, {
year: 'numeric',
month: 'long',
day: 'numeric'
}).format(date);
return formatted;
}
// เวลาแบบสัมพัทธ์
function getRelativeTime(date) {
const now = new Date();
const diff = now - date;
const seconds = Math.floor(diff / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
if (days > 0) {
return I18nManager.translate('time.daysAgo', {days});
} else if (hours > 0) {
return I18nManager.translate('time.hoursAgo', {hours});
} else if (minutes > 0) {
return I18nManager.translate('time.minutesAgo', {minutes});
} else {
return I18nManager.translate('time.justNow');
}
}
// ตัวอย่างการใช้งาน
const date = new Date('2024-01-15');
console.log(formatDate(date)); // 'January 15, 2024' หรือ '15 มกราคม 2024'
const postDate = new Date(Date.now() - 3600000); // 1 ชั่วโมงที่ผ่านมา
console.log(getRelativeTime(postDate)); // '1 hour ago' หรือ '1 ชั่วโมงที่แล้ว'7. โมดัลหลายภาษา
// Modal พร้อม i18n
class Modal {
constructor(contentKey, options = {}) {
this.contentKey = contentKey;
this.options = options;
}
show() {
const modal = document.createElement('div');
modal.className = 'modal';
modal.innerHTML = `
<div class="modal-overlay"></div>
<div class="modal-content">
<h2 data-i18n="${this.contentKey}.title">Title</h2>
<p data-i18n="${this.contentKey}.message">Message</p>
<div class="modal-actions">
<button class="btn-cancel" data-i18n="button.cancel">Cancel</button>
<button class="btn-confirm" data-i18n="button.confirm">Confirm</button>
</div>
</div>
`;
document.body.appendChild(modal);
// แปลภาษา
I18nManager.updateElements(modal);
// จัดการเหตุการณ์
modal.querySelector('.btn-cancel').addEventListener('click', () => {
this.close();
});
modal.querySelector('.btn-confirm').addEventListener('click', () => {
if (this.options.onConfirm) {
this.options.onConfirm();
}
this.close();
});
modal.querySelector('.modal-overlay').addEventListener('click', () => {
this.close();
});
this.modal = modal;
}
close() {
if (this.modal) {
this.modal.remove();
this.modal = null;
}
}
}
// การใช้งาน
const deleteModal = new Modal('modal.deleteConfirm', {
onConfirm: () => {
deleteItem();
}
});
deleteModal.show();8. ระบบค้นหาพร้อมคำแนะนำอัตโนมัติ
// ระบบค้นหาพร้อมคำแนะนำและรองรับหลายภาษา
class SearchAutocomplete {
constructor(inputElement) {
this.input = inputElement;
this.results = [];
this.setupUI();
}
setupUI() {
// ข้อความ placeholder
const placeholder = I18nManager.translate('search.placeholder');
this.input.setAttribute('placeholder', placeholder);
// กล่องผลลัพธ์
this.container = document.createElement('div');
this.container.className = 'autocomplete-results';
this.input.parentElement.appendChild(this.container);
// ผูกเหตุการณ์
this.input.addEventListener('input', (e) => {
this.search(e.target.value);
});
// อัปเดตเมื่อเปลี่ยนภาษา
Now.on('locale:changed', () => {
const placeholder = I18nManager.translate('search.placeholder');
this.input.setAttribute('placeholder', placeholder);
this.render();
});
}
async search(query) {
if (!query) {
this.results = [];
this.render();
return;
}
// เรียก API ค้นหา
this.results = await searchAPI(query);
this.render();
}
render() {
if (this.results.length === 0) {
this.container.innerHTML = `
<div class="no-results" data-i18n="search.noResults">
No results found
</div>
`;
} else {
this.container.innerHTML = `
<div class="results-header" data-i18n="search.resultsCount">
Found {count} results
</div>
<ul>
${this.results.map(result => `
<li data-id="${result.id}">${result.name}</li>
`).join('')}
</ul>
`;
}
I18nManager.updateElements(this.container);
}
}9. ตั้งค่าผู้ใช้และภาษาที่ต้องการ
// ตั้งค่าผู้ใช้พร้อมตัวเลือกภาษา
class UserSettings {
constructor(user) {
this.user = user;
}
async saveLanguage(locale) {
// บันทึกใน database
await api.updateUser(this.user.id, {
language: locale
});
// เปลี่ยนภาษา
await I18nManager.setLocale(locale);
// แจ้งเตือน
const message = I18nManager.translate('settings.languageUpdated');
showNotification('success', message);
}
render() {
const container = document.querySelector('#settings');
container.innerHTML = `
<div class="settings-section">
<h3 data-i18n="settings.language">Language</h3>
<select id="language-select">
<option value="en">English</option>
<option value="th">ไทย</option>
<option value="ja">日本語</option>
</select>
</div>
<div class="settings-section">
<h3 data-i18n="settings.notifications">Notifications</h3>
<label>
<input type="checkbox" id="email-notifications">
<span data-i18n="settings.emailNotifications">Email notifications</span>
</label>
</div>
<button data-i18n="button.save">Save</button>
`;
// แปลภาษา
I18nManager.updateElements(container);
// ตั้งค่าภาษาปัจจุบัน
const select = container.querySelector('#language-select');
select.value = I18nManager.getCurrentLocale();
// จัดการเหตุการณ์เปลี่ยนภาษา
select.addEventListener('change', (e) => {
this.saveLanguage(e.target.value);
});
}
}10. ข้อความข้อผิดพลาด
// จัดการข้อผิดพลาดพร้อมการรองรับหลายภาษา
class ErrorHandler {
static handle(error, context = {}) {
let messageKey = 'error.unknown';
let params = {};
// จับคู่ประเภทข้อผิดพลาดกับคีย์คำแปล
switch (error.code) {
case 'NETWORK_ERROR':
messageKey = 'error.network';
break;
case 'UNAUTHORIZED':
messageKey = 'error.unauthorized';
break;
case 'NOT_FOUND':
messageKey = 'error.notFound';
params = {resource: context.resource};
break;
case 'VALIDATION_ERROR':
messageKey = 'error.validation';
params = {field: context.field};
break;
case 'SERVER_ERROR':
messageKey = 'error.server';
break;
default:
messageKey = 'error.unknown';
}
const message = I18nManager.translate(messageKey, params);
// แสดงผลข้อผิดพลาดให้ผู้ใช้เห็น
showErrorNotification(message);
// บันทึกลง log เพื่อการดีบัก
console.error(message, error);
}
}
// การใช้งาน
try {
await api.deleteUser(userId);
} catch (error) {
ErrorHandler.handle(error, {
resource: 'user',
action: 'delete'
});
}เอกสารอ้างอิง API
การกำหนดค่า
{
enabled: boolean, // เปิด/ปิดระบบ i18n
defaultLocale: string, // ภาษาเริ่มต้น
availableLocales: string[], // ภาษาที่รองรับ
storageKey: string, // คีย์ใน localStorage สำหรับเก็บค่าภาษา
useBrowserLocale: boolean, // ใช้ภาษาเบราว์เซอร์เป็นค่าเริ่มต้น
noTranslateEnglish: boolean // ข้ามการแปลภาษาอังกฤษ
}เมธอด
การเริ่มต้น
// เริ่มต้นระบบ i18n
init(options?: object): Promise<I18nManager>การจัดการภาษา
// ตั้งค่าภาษาปัจจุบัน
setLocale(locale: string, force?: boolean): Promise<void>
// อ่านค่าภาษาปัจจุบัน
getCurrentLocale(): stringการแปล
// แปลข้อความผ่านคีย์
translate(key: string, params?: object, locale?: string): string
// รับฟังก์ชันสำหรับแปลตามภาษา
getTranslator(locale: string): (key: string, params?: object) => string
// ดึงคำแปลของภาษาที่ระบุ
getTranslations(locale?: string): object
// ดึงคำแปลของคีย์เดียวกันในทุกภาษา
getKeyTranslations(key: string): object
// ตรวจสอบว่ามีคำแปลหรือไม่
hasTranslation(key: string, locale?: string): booleanการอัปเดตองค์ประกอบ
// อัปเดตคำแปลใน DOM ทั้งหมด
updateTranslations()
// อัปเดตคำแปลเฉพาะในองค์ประกอบที่กำหนด
updateElements(container?: Element)เมธอดภายใน
// โหลดคำแปลจากไฟล์
loadTranslations(locale: string): Promise<void>
// คืนค่าคำแปลพร้อม fallback
getTranslation(key: string, translations: object, params?: object): string
// คืนค่าคำแปลสำรอง
getFallbackTranslation(key: string, params: object): string
// แทรกพารามิเตอร์ลงในข้อความ
interpolate(text: string, params: object, translations?: object): string
// โหลดภาษาที่ใช้ครั้งแรก
loadInitialLocale(): Promise<void>เหตุการณ์
// ระบบ i18n พร้อมใช้งานแล้ว
'i18n:initialized'
// มีการเปลี่ยนภาษา
'locale:changed' -> {
locale: string,
forced: boolean
}
// องค์ประกอบในหน้าได้รับการอัปเดตคำแปลแล้ว
'i18n:elements:updated' -> {
container: Element,
elementsUpdated: number,
locale: string
}สถานะ
{
current: string | null, // ภาษาปัจจุบัน
initialized: boolean, // เริ่มต้นแล้ว
translations: Map, // แคชคำแปล
disabled: boolean // ระบบถูกปิด
}แนวทางปฏิบัติที่ดี
1. ✅ ใช้ Nested Keys
// ✅ ดี: จัดโครงสร้างเป็นหมวดหมู่
{
"user": {
"profile": {
"name": "Name",
"email": "Email"
}
}
}
I18nManager.translate('user.profile.name');
// ❌ ไม่ดี: โครงสร้างแบน
{
"userProfileName": "Name",
"userProfileEmail": "Email"
}2. ✅ ใช้ data-i18n สำหรับ Static Content
<!-- ✅ ดี: แปลอัตโนมัติ -->
<h1 data-i18n="page.title">Welcome</h1>
<!-- ❌ ไม่ดี: ต้องแปลเอง -->
<h1 id="title">Welcome</h1>
<script>
document.getElementById('title').textContent =
I18nManager.translate('page.title');
</script>3. ✅ เก็บ Translations แยกไฟล์
// ✅ ดี: แยกไฟล์คำแปลชัดเจน
translations/
├── en.json
├── th.json
└── ja.json
// ❌ ไม่ดี: ฝังคำแปลไว้ในโค้ดโดยตรง
const translations = {
en: {...},
th: {...}
};4. ✅ ใช้ Parameters สำหรับ Dynamic Content
// ✅ ดี: ใช้พารามิเตอร์ให้ยืดหยุ่น
{
"welcome": "Welcome {name}"
}
I18nManager.translate('welcome', {name: 'John'});
// ❌ ไม่ดี: ต่อสตริงเอง
{
"welcome": "Welcome "
}
I18nManager.translate('welcome') + name;5. ✅ กำหนดค่า Fallback
// ✅ ดี: ใช้ defaultLocale เป็นค่า fallback
await I18nManager.init({
defaultLocale: 'en',
availableLocales: ['en', 'th', 'ja']
});
// หากไม่มีคำแปลจะใช้ key เป็นค่า fallback
I18nManager.translate('unknown.key'); // 'unknown.key'6. ✅ จัดการสถานะกำลังโหลด
// ✅ ดี: แสดงสถานะกำลังโหลด
async function changeLanguage(locale) {
showLoading();
try {
await I18nManager.setLocale(locale);
} catch (error) {
showError(error);
} finally {
hideLoading();
}
}7. ✅ ตั้งชื่อคีย์ให้สอดคล้อง
// ✅ ดี: ตั้งชื่อคีย์ให้สอดคล้องกัน
{
"button.save": "Save",
"button.cancel": "Cancel",
"button.delete": "Delete"
}
// ❌ ไม่ดี: ตั้งชื่อไม่เป็นระบบ
{
"saveBtn": "Save",
"cancelButton": "Cancel",
"delete": "Delete"
}8. ✅ อัปเดตองค์ประกอบหลังโหลดข้อมูลแบบไดนามิก
// ✅ ดี: อัปเดตหลังโหลดข้อมูล
async function loadContent() {
const data = await fetchData();
const container = document.querySelector('#content');
container.innerHTML = generateHTML(data);
// อัปเดต translations
await I18nManager.updateElements(container);
}9. ✅ เก็บค่าภาษาที่ผู้ใช้เลือก
// ✅ ดี: เก็บค่าภาษาไว้ให้อัตโนมัติ
await I18nManager.init({
storageKey: 'app_lang' // จะจดจำภาษาที่เลือก
});
// ✅ ดี: ซิงค์กับเซิร์ฟเวอร์
Now.on('locale:changed', async (data) => {
await api.updateUserPreference({
language: data.locale
});
});10. ✅ ทดสอบทุกภาษา
// ✅ ดี: ทดสอบทุกภาษา
async function testTranslations() {
const locales = ['en', 'th', 'ja'];
for (const locale of locales) {
await I18nManager.setLocale(locale);
// ตรวจสอบ key ที่สำคัญ
const keys = [
'app.name',
'button.save',
'message.success'
];
keys.forEach(key => {
const translation = I18nManager.translate(key);
console.log(`${locale} - ${key}:`, translation);
});
}
}สรุป
คุณสมบัติหลัก
| คุณสมบัติ | รองรับ | หมายเหตุ |
|---|---|---|
| รองรับหลายภาษา | ✅ | ใช้งานได้ไม่จำกัดจำนวน |
| ตรวจจับภาษาอัตโนมัติ | ✅ | อิงภาษาจากเบราว์เซอร์ |
| ทำงานร่วมกับ HTML | ✅ | ใช้แอตทริบิวต์ data-i18n |
| แทรกค่าพารามิเตอร์ | ✅ | ใช้ไวยากรณ์ {key} |
| โหลดตามต้องการ | ✅ | โหลดไฟล์คำแปลเฉพาะที่จำเป็น |
| จดจำภาษาใน LocalStorage | ✅ | บันทึกค่าภาษาไว้ให้ผู้ใช้ |
| ระบบ Fallback | ✅ | ใช้ key หรือ default locale |
| คีย์แบบซ้อน | ✅ | ใช้ dot notation |
| ระบบเหตุการณ์ | ✅ | มี event locale:changed |
| โหมดไม่ต้องแปลภาษาอังกฤษ | ✅ | เปิดใช้ผ่าน noTranslateEnglish |
เมื่อใดควรใช้ I18nManager
| กรณีใช้งาน | ควรใช้ I18nManager หรือไม่ | หมายเหตุ |
|---|---|---|
| แอปพลิเคชันหลายภาษา | ✅ ใช่ | กรณีใช้งานหลัก |
| บันทึกภาษาที่ผู้ใช้เลือก | ✅ ใช่ | เก็บใน LocalStorage หรือ API |
| แปลคอนเทนต์แบบไดนามิก | ✅ ใช่ | ใช้เมธอด translate() |
| แปล HTML แบบสแตติก | ✅ ใช่ | ใช้แอตทริบิวต์ data-i18n |
| ข้อความตรวจสอบฟอร์ม | ✅ ใช่ | รองรับพารามิเตอร์ |
| ข้อความข้อผิดพลาด | ✅ ใช่ | ให้ประสบการณ์สอดคล้อง |
| จัดรูปแบบวันที่/เวลา | ⚠️ บางส่วน | ควรใช้ร่วมกับ Intl API |
| จัดรูปแบบสกุลเงิน | ⚠️ บางส่วน | ควรใช้ร่วมกับ Intl API |