Now.js Framework Documentation

Now.js Framework Documentation

I18nManager

TH 22 Feb 2026 03:12

I18nManager

ภาพรวม

I18nManager คือระบบ internationalization (i18n) ใน Now.js Framework รองรับ multi-language translations และ locale management

ใช้เมื่อ:

  • ต้องการ multi-language support
  • ต้องการเปลี่ยนภาษาแบบ dynamic
  • ต้องการ translate UI elements
  • ต้องการ locale-aware formatting

ทำไมต้องใช้:

  • ✅ File-based translations (JSON)
  • ✅ Dynamic locale switching
  • ✅ HTML attribute support (data-i18n)
  • ✅ Parameter interpolation
  • ✅ Fallback locale
  • ✅ Browser locale detection
  • ✅ LocalStorage persistence

การใช้งานพื้นฐาน

Initialization

await I18nManager.init({
  enabled: true,
  defaultLocale: 'en',
  availableLocales: ['en', 'th', 'ja'],
  useBrowserLocale: true
});

HTML Declarative

<!-- Simple translation -->
<h1 data-i18n="welcome">Welcome</h1>

<!-- With parameters -->
<p data-i18n="greeting" data-i18n-params='{"name": "John"}'>
  Hello, John!
</p>

<!-- Attribute translation -->
<input data-i18n-placeholder="searchPlaceholder" placeholder="Search...">
<button data-i18n-title="saveTooltip" title="Save">💾</button>

JavaScript API

// Translate
const text = I18nManager.translate('welcome');
// => 'ยินดีต้อนรับ' (if locale is 'th')

// With parameters
const greeting = I18nManager.translate('greeting', { name: 'John' });
// => 'สวัสดี John!' (if locale is 'th')

// Change locale
await I18nManager.setLocale('th');

Translation Files

สร้างไฟล์ JSON ใน /translations/:

/translations/
  en.json
  th.json
  ja.json

en.json

{
  "welcome": "Welcome",
  "greeting": "Hello, {name}!",
  "nav": {
    "home": "Home",
    "about": "About",
    "contact": "Contact"
  },
  "buttons": {
    "save": "Save",
    "cancel": "Cancel",
    "delete": "Delete"
  }
}

th.json

{
  "welcome": "ยินดีต้อนรับ",
  "greeting": "สวัสดี {name}!",
  "nav": {
    "home": "หน้าแรก",
    "about": "เกี่ยวกับ",
    "contact": "ติดต่อ"
  },
  "buttons": {
    "save": "บันทึก",
    "cancel": "ยกเลิก",
    "delete": "ลบ"
  }
}

Data Attributes

Attribute คำอธิบาย
data-i18n Translation key สำหรับ text content
data-i18n-tpl (สร้างอัตโนมัติ) เก็บ innerHTML template สำหรับ smart mode
data-i18n-params JSON parameters สำหรับ interpolation
data-i18n-placeholder Translation key สำหรับ placeholder
data-i18n-title Translation key สำหรับ title
data-i18n-aria-label Translation key สำหรับ aria-label
data-i18n-[attr] Translation key สำหรับ attribute ใดๆ
<input type="text"
       data-i18n-placeholder="search.placeholder"
       data-i18n-aria-label="search.ariaLabel">

<img data-i18n-alt="images.logo.alt" src="/logo.png">

Smart Translation (รักษา Child Elements)

เมื่อ element ที่มี data-i18n มี child HTML elements อยู่ภายใน (เช่น <em>, <a>, <span>, <input>) ระบบแปลภาษาจะใช้ smart mode — รักษา child elements ทั้งหมดไว้ และแปลเฉพาะ text nodes ระดับนอกสุดเท่านั้น

หลักการทำงาน

  1. พบครั้งแรก: บันทึก innerHTML ดั้งเดิมเป็น template ไว้ใน data-i18n-tpl
  2. แปลภาษา: interpolate เฉพาะ direct text nodes ({LNG_...} → ค่าที่แปลแล้ว) child elements ไม่ถูกกระทบ
  3. เปลี่ยนภาษา: ใช้ template ที่บันทึกไว้ซ้ำ ทำให้แปลใหม่ได้สะอาดทุกครั้ง

ตัวอย่างพื้นฐาน

<!-- Smart mode: tag <em> ถูกรักษาไว้ -->
<div class="comment" data-i18n>
  {LNG_Facebook profile username eg} https://www.facebook.com/<em>username</em>
</div>

<!-- หลังแปลภาษา (locale: th) -->
<div class="comment" data-i18n data-i18n-tpl="...original...">
  ชื่อผู้ใช้ Facebook เช่น https://www.facebook.com/<em>username</em>
</div>

แปล Child Elements แยกแต่ละตัว

โดยปกติ child elements จะ ถูกข้าม ถ้าต้องการแปล child element ให้เพิ่ม data-i18n บน child นั้น:

<div class="info" data-i18n>
  {LNG_Select file type}: <strong data-i18n>{LNG_PDF Document}</strong>
</div>

ผลลัพธ์: ทั้ง text ด้านนอกและเนื้อหาใน <strong> ถูกแปลแยกอิสระจากกัน

ทำงานร่วมกับ data-text, data-attr

Child elements ที่ใช้ directive อย่าง data-text หรือ data-attr จะถูกรักษาไว้ใน template และทำงานแยกอิสระ:

<label data-i18n>
  {LNG_Allowed IPs}:
  <textarea name="api_ips" data-text="api_ips" placeholder="{LNG_All IP addresses}"></textarea>
</label>
  • data-i18n บน <label> แปล {LNG_Allowed IPs}:
  • data-text บน <textarea> จัดการโดย FormManager/AppConfigManager
  • placeholder ที่มี {LNG_...} จัดการโดย translateAttributesIn()
  • ไม่มีความขัดแย้งระหว่าง managers

Simple Mode (เข้ากันได้ย้อนหลัง)

เมื่อ element ไม่มี child elements จะใช้วิธี textContent แบบเดิม — เข้ากันได้ย้อนหลังทั้งหมด:

<!-- Simple mode: ไม่มี child elements -->
<h1 data-i18n>{LNG_Welcome}</h1>
<button data-i18n="buttons.save">Save</button>

การตั้งค่า

await I18nManager.init({
  // Enable i18n
  enabled: true,

  // Default locale
  defaultLocale: 'en',

  // Available locales
  availableLocales: ['en', 'th', 'ja', 'zh'],

  // Storage key for persisting locale
  storageKey: 'app_lang',

  // Use browser's locale if available
  useBrowserLocale: true,

  // Skip English lookup (use key as fallback)
  noTranslateEnglish: true
});

API อ้างอิง

I18nManager.setLocale(locale, force?)

เปลี่ยนภาษา

Parameter Type Description
locale string Locale code (e.g., 'th', 'en')
force boolean Force reload translations

Returns: Promise<void>

await I18nManager.setLocale('th');

I18nManager.getCurrentLocale()

รับ locale ปัจจุบัน

Returns: string

const locale = I18nManager.getCurrentLocale();
// 'th'

I18nManager.translate(key, params?, locale?)

แปลข้อความ

Parameter Type Description
key string Translation key (dot notation supported)
params object Interpolation parameters
locale string Specific locale (optional)

Returns: string

// Simple
I18nManager.translate('welcome');

// Nested key
I18nManager.translate('nav.home');

// With params
I18nManager.translate('greeting', { name: 'John' });

// Specific locale
I18nManager.translate('welcome', {}, 'ja');

I18nManager.updateElements(container?)

อัพเดท translations ใน DOM

Parameter Type Description
container HTMLElement Container to update (default: document)
// Update all elements
I18nManager.updateElements();

// Update specific container
I18nManager.updateElements(document.getElementById('modal'));

I18nManager.hasTranslation(key, locale?)

ตรวจสอบว่ามี translation หรือไม่

Parameter Type Description
key string Translation key
locale string Specific locale (optional)

Returns: boolean

I18nManager.getTranslations(locale?)

รับ translations ทั้งหมด

Returns: object

เหตุการณ์

Event เมื่อเกิด Detail
i18n:locale-changed ภาษาเปลี่ยน {locale, previous}
i18n:translations-loaded โหลด translations เสร็จ {locale}
EventManager.on('i18n:locale-changed', (data) => {
  console.log(`Language changed to: ${data.locale}`);
});

ตัวอย่างการใช้งานจริง

Language Switcher

<select id="language-select">
  <option value="en">English</option>
  <option value="th">ไทย</option>
  <option value="ja">日本語</option>
</select>

<script>
const select = document.getElementById('language-select');

// Set current value
select.value = I18nManager.getCurrentLocale();

// Handle change
select.addEventListener('change', async (e) => {
  await I18nManager.setLocale(e.target.value);
});
</script>

Dynamic Content Translation

// After loading dynamic content
async function loadProducts() {
  const products = await ApiService.get('/api/products');

  const container = document.getElementById('products');
  container.innerHTML = products.map(p => `
    <div class="product">
      <h3>${p.name}</h3>
      <button data-i18n="buttons.addToCart">Add to Cart</button>
    </div>
  `).join('');

  // Update translations for new elements
  I18nManager.updateElements(container);
}

Pluralization

// th.json
{
  "items": {
    "zero": "ไม่มีรายการ",
    "one": "1 รายการ",
    "other": "{count} รายการ"
  }
}
function translatePlural(key, count) {
  const pluralKey = count === 0 ? 'zero' : count === 1 ? 'one' : 'other';
  return I18nManager.translate(`${key}.${pluralKey}`, { count });
}

translatePlural('items', 0);  // 'ไม่มีรายการ'
translatePlural('items', 1);  // '1 รายการ'
translatePlural('items', 5);  // '5 รายการ'

ข้อควรระวัง

⚠️ 1. รอ Translations โหลดก่อน

// ❌ ใช้ก่อน init
I18nManager.translate('key');

// ✅ รอ init
await I18nManager.init({ enabled: true });
I18nManager.translate('key');

⚠️ 2. อัพเดท Dynamic Content

// ❌ ลืม update หลังเพิ่ม content
container.innerHTML = newContent;

// ✅ เรียก updateElements
container.innerHTML = newContent;
I18nManager.updateElements(container);

⚠️ 3. Fallback Keys

// หาก key ไม่มี จะใช้ key เป็น fallback
I18nManager.translate('missing.key');
// => 'missing.key'

// เพิ่ม default locale fallback
// en.json ควรมีครบทุก key

⚠️ 4. Smart Mode ใช้ innerHTML Template

<!-- ✅ ใช้ pattern {LNG_...} สำหรับข้อความที่ต้องการแปล -->
<div data-i18n>
  {LNG_Description}: <em>example</em>
</div>

<!-- ❌ อย่าแก้ไข innerHTML หลังจากแปลครั้งแรก
     (template ที่ cache ไว้จะไม่อัปเดต) -->
<script>
  // การทำแบบนี้จะทำให้ template cache เสีย
  element.innerHTML = 'new content <em>here</em>';
  // ✅ ถ้าต้องการอัปเดต ให้ trigger การแปลใหม่:
  I18nManager.updateElements(element.parentElement);
</script>

เอกสารที่เกี่ยวข้อง