Now.js Framework Documentation

Now.js Framework Documentation

I18nManager - ระบบจัดการหลายภาษา

TH 24 Nov 2025 08:34

I18nManager - ระบบจัดการหลายภาษา

เอกสารสำหรับ I18nManager ซึ่งเป็นระบบจัดการภาษาหลายภาษา (Internationalization/Localization)

📋 สารบัญ

  1. ภาพรวม
  2. การติดตั้งและนำเข้า
  3. การใช้งานพื้นฐาน
  4. ไฟล์คำแปล
  5. การทำงานร่วมกับ HTML
  6. การแปลแบบไดนามิก
  7. การแทรกค่าพารามิเตอร์
  8. การจัดการภาษา
  9. การตั้งค่า
  10. ตัวอย่างการใช้งาน
  11. เอกสารอ้างอิง API
  12. แนวทางปฏิบัติที่ดี

ภาพรวม

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