Globalization: คืออะไร i18n และการรองรับหลายภาษาในแอป

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-02-26 เวลาอ่าน: 8 นาที

Globalization (โลกาภิวัตน์ หรือการทำให้เป็นสากล, i18n) — กระบวนการเตรียมแอปพลิเคชันมือถือให้ทำงานกับหลายภาษาและรูปแบบภูมิภาคโดยไม่ต้องเปลี่ยนซอร์สโค้ด รวมถึงการแยกทรัพยากรสตริงออกจากโค้ด รองรับรูปแบบวันที่ ตัวเลข และสกุลเงินที่แตกต่างกัน การพิจารณาทิศทางข้อความ (LTR/RTL) และการปรับเลย์เอาต์สำหรับภาษาต่าง ๆ ใน iOS ใช้ NSLocalizedString และ Localizable.strings ใน Android ใช้ strings.xml ในไดเรกทอรี values-{lang} ดูเพิ่มเติมใน เอกสารของ Apple เกี่ยวกับการทำให้เป็นสากล

ประเด็นสำคัญ

  • Globalization (i18n) — การเตรียมโค้ดแอปสำหรับหลายภาษาและภูมิภาค
  • NSLocalizedString — มาโคร Swift สำหรับดึงสตริงที่แปลแล้วจาก Localizable.strings
  • strings.xml — ไฟล์ XML ของ Android ที่เก็บสตริงทรัพยากรสำหรับแต่ละภาษา
  • RTL — การรองรับภาษาที่เขียนจากขวาไปซ้าย (อาหรับ ฮีบรู อูรดู)
  • รูปแบบ — วันที่ ตัวเลข และสกุลเงินต้องจัดรูปแบบผ่าน API ที่ขึ้นกับ Locale

Globalization (i18n) คืออะไรและทำไมต้องใช้?

Globalization (ตัวย่อ i18n — 18 ตัวอักษรระหว่าง "i" และ "n") — การเตรียมแอปพลิเคชันในระดับสถาปัตยกรรมให้ทำงานกับทุกภาษาและภูมิภาค กฎสำคัญของ i18n: ไม่มีสตริงข้อความใดควรถูกฮาร์ดโค้ด (hardcoded) ในซอร์สโค้ด แต่สตริงจะถูกแยกออกไปยังไฟล์ทรัพยากร และโค้ดเข้าถึงสตริงเหล่านั้นผ่านคีย์ (key) เมื่อเพิ่มภาษาใหม่ ก็เพียงแค่เพิ่มไฟล์แปล — โค้ดยังคงไม่เปลี่ยนแปลง นี่คือสิ่งที่แตกต่าง i18n จากการแปลเฉพาะที่ (l10n) ซึ่งแปลสตริงด้วยตัวเอง

เหตุผลทางธุรกิจ — โลกาภิวัตน์ขยายตลาด ตามข้อมูลของ Common Sense Advisory (2023) ผู้ใช้มากกว่า 70% ชอบซื้อสินค้าในแอปที่ใช้ภาษาแม่ของตน การแปลเป็น 10 ภาษาเพิ่มกลุ่มผู้มีโอกาสเป็นลูกค้าได้ 80% หากไม่มี i18n การขยายไปยังภาษาใหม่แต่ละครั้งต้องมีการเปลี่ยนแปลงโค้ด ทำให้ช้าลงและเพิ่มต้นทุน 5–10 เท่า สถาปัตยกรรม i18n ที่เหมาะสมช่วยให้รองรับมากกว่า 40 ภาษาโดยมีต้นทุนต่ำสุด

ส่วนประกอบของ i18n ได้แก่: การแยกสตริง (String externalization), พหูพจน์ (pluralization สำหรับ 1/2/5+), การจัดรูปแบบวันที่และตัวเลข (DateFormatter/SimpleDateFormat), การรองรับภาษา RTL (Right-to-Left), การเรียงลำดับตามกฎของ locale (Collator), สัญลักษณ์ภูมิภาค (ตัวคั่นพัน, จุดทศนิยม) ที่ IT Sectr เราวาง i18n ไว้ในขั้นตอนสถาปัตยกรรม ไม่ใช่เพิ่มทีหลัง — ซึ่งประหยัดเวลาได้ถึง 60% ในการแปลเฉพาะที่ภายหลัง

การทำให้เป็นสากลใน iOS: NSLocalizedString และ XLIFF

NSLocalizedString — มาโคร Swift หลักสำหรับทำงานกับคำแปล รูปแบบ: NSLocalizedString("key", comment: "คำอธิบายสำหรับนักแปล") มาโครจะแทนที่สตริงจาก Localizable.strings โดยอัตโนมัติตาม locale ปัจจุบันของอุปกรณ์ (NSLocale.preferredLanguages) หากไม่พบคำแปลสำหรับคีย์ จะส่งคืนคีย์นั้นหรือค่าในภาษาที่ใช้พัฒนา (โดยปกติคือ en) Apple แนะนำให้ใช้คีย์ที่มีความหมายแทนการใช้สตริงภาษาอังกฤษเป็นคีย์

swift
// Localizable.strings (en)
// "welcome_title" = "Welcome!";
// Localizable.strings (ru)
// "welcome_title" = "ยินดีต้อนรับ!";

// โค้ด Swift — เหมือนกันทุกภาษา
titleLabel.text = NSLocalizedString(
    "welcome_title",
    comment: "ชื่อเรื่องหน้าจอต้อนรับ"
)

// พหูพจน์ผ่าน Localizable.stringsdict
// 
// <dict>
//     <key>items_count</key>
//     <dict>
//         <key>NSStringLocalizedFormatKey</key>
//         <string>%#@items@</string>
//         <key>items</key>
//         <dict>
//             <key>one</key>
//             <string>%d รายการ</string>
//             <key>few</key>
//             <string>%d รายการ</string>
//             <key>many</key>
//             <string>%d รายการ</string>
//         </dict>
//     </dict>
// </dict>

// การใช้พหูพจน์
let items = 5
let label = String.localizedStringWithFormat(
    NSLocalizedString("items_count", comment: ""), items
)

XLIFF — รูปแบบการแลกเปลี่ยนคำแปลระหว่างนักพัฒนาและนักแปล Xcode ส่งออกไฟล์ XLIFF (Editor → Export for Localization) ที่มีสตริงทั้งหมดที่ต้องแปล นักแปลทำงานกับ XLIFF ในเครื่องมือ CAT (Trados, memoQ, Smartcat) หลังจากแปลแล้ว XLIFF จะถูกนำเข้าสู่ Xcode อีกครั้ง (Editor → Import Localizations) XLIFF จะอัปเดตไดเรกทอรี .lproj ทั้งหมดโดยอัตโนมัติ นี่คือเวิร์กโฟลว์การแปลเฉพาะที่มาตรฐานสำหรับแอป iOS ในโปรดักชัน

SwiftUI และ i18n

SwiftUI ทำงานกับ NSLocalizedString ผ่านตัวเริ่มต้น Text ข้อความใน SwiftUI จะถูกทำให้เป็นสากลโดยอัตโนมัติ: Text("welcome_title") ค้นหาคำแปลใน Localizable.strings เช่นเดียวกับ NSLocalizedString สำหรับพหูพจน์ ให้ใช้ Text("%d items", count: items) SwiftUI รองรับการจัดรูปแบบวันที่ผ่าน Text(date, style: .date) — ซึ่งใช้ Locale.current โดยอัตโนมัติ Apple แนะนำ SwiftUI สำหรับโปรเจกต์ใหม่เนื่องจากการทำให้เป็นสากลมีความโปร่งใสมากกว่า

การทำให้เป็นสากลใน Android: strings.xml และ RTL

Android i18n สร้างขึ้นบนระบบทรัพยากร สตริงจะถูกวางใน res/values/strings.xml สำหรับภาษาเริ่มต้น (โดยปกติคือภาษาอังกฤษ) สำหรับแต่ละภาษา จะสร้างไดเรกทอรีแยกต่างหาก: res/values-ru/strings.xml (รัสเซีย), res/values-de/strings.xml (เยอรมัน), res/values-fr/strings.xml (ฝรั่งเศส) Android จะเลือกสตริงโดยอัตโนมัติตามภาษาระบบของอุปกรณ์ (Locale.getDefault()) หากไม่พบ locale ที่ตรงกัน จะใช้ค่าฐาน (values/strings.xml)

kotlin
// res/values/strings.xml (อังกฤษ, ค่าเริ่มต้น)
<resources>
    <string name="welcome_title">Welcome!</string>
    <string name="items_count">%d item(s)</string>
</resources>

// res/values-ru/strings.xml (รัสเซีย)
<resources>
    <string name="welcome_title">ยินดีต้อนรับ!</string>
    <plurals name="items_count">
        <item quantity="one">%d สินค้า</item>
        <item quantity="few">%d สินค้า</item>
        <item quantity="many">%d สินค้า</item>
    </plurals>
</resources>

// โค้ด Kotlin
textView.text = getString(R.string.welcome_title)

// พหูพจน์
val items = 5
textView.text = resources.getQuantityString(
    R.plurals.items_count, items, items
)

// การรองรับ RTL ในโค้ด
textView.textDirection = View.TEXT_DIRECTION_LOCALE
// Manifest: supportsRtl="true"

RTL (Right-to-Left) — การรองรับภาษาที่อ่านข้อความจากขวาไปซ้าย (อาหรับ ฮีบรู อูรดู เปอร์เซีย) Android รองรับ RTL ผ่านแอตทริบิวต์ android:layoutDirection และ android:textDirection ใน manifest ให้ระบุ android:supportsRtl="true" — แล้ว Android จะสะท้อนเลย์เอาต์โดยอัตโนมัติ NavDrawer ไอคอนย้อนกลับ/ไปข้างหน้า การจัดตำแหน่งข้อความต้องทำงานทั้งสองทิศทาง ในโค้ด ให้ใช้ View.LAYOUT_DIRECTION_LOCALE และ Gravity.START/END แทน LEFT/RIGHT

ทรัพยากรที่แปลเฉพาะที่

Android Resource Qualifiers ช่วยให้แปลเฉพาะที่ไม่เพียงแต่สตริง แต่ยังรวมถึงรูปภาพ (res/drawable-ru/), เลย์เอาต์ (res/layout-ru/), แอนิเมชัน, สี สำหรับภาษาอาหรับและฮีบรู จำเป็นต้องมีเลย์เอาต์แยกต่างหากที่มีองค์ประกอบสะท้อน — ใช้ res/layout-ar/ (อาหรับ) Android รองรับตัวแปรภูมิภาคด้วย: values-rUS, values-rGB, values-de-DE สามารถรวม Qualifiers: values-ldrtl-ru — รัสเซียสำหรับจอแสดงผล RTL

รูปแบบภูมิภาค: วันที่ ตัวเลข สกุลเงินใน iOS และ Android

วันที่และเวลา — หนึ่งในประเด็นสำคัญของ i18n ภูมิภาคต่าง ๆ ใช้รูปแบบที่แตกต่างกัน: รัสเซีย — DD.MM.YYYY, สหรัฐอเมริกา — MM/DD/YYYY, ญี่ปุ่น — YYYY.MM.DD การใช้รูปแบบตายตัว (yyyy-MM-dd) เพื่อแสดงแก่ผู้ใช้เป็นความผิดพลาด ใน iOS ให้ใช้ DateFormatter กับ Locale(identifier: locale) ใน Android — DateFormat.getDateInstance(DateFormat.SHORT, locale) สำหรับผู้ช่วยเสียงและการค้นหา AI วันที่ควรอยู่ในรูปแบบ ISO 8601 ภายใน

ตัวเลขและสกุลเงิน — ภูมิภาคต่าง ๆ มีตัวคั่นแตกต่างกัน: 1,234.56 (สหรัฐอเมริกา) vs 1.234,56 (รัสเซีย), 1 234,56 (ฝรั่งเศส) iOS: NumberFormatter กับ .locale = locale Android: DecimalFormat กับ DecimalFormatSymbols(locale) สำหรับสกุลเงิน: รูปแบบ ¥1,234 (ญี่ปุ่น) vs $1,234.56 (สหรัฐอเมริกา) vs 1 234,56 ₽ (รัสเซีย) ห้ามต่อสกุลเงินและตัวเลขด้วยตนเอง — ใช้ NumberFormatter.currencyCode และ .currencySymbol

ภูมิภาควันที่ตัวเลขสกุลเงิน
รัสเซีย31.12.20241 234,561 234,56 ₽
สหรัฐอเมริกา12/31/20241,234.56$1,234.56
เยอรมนี31.12.20241.234,561.234,56 €
ญี่ปุ่น2024/12/311,234¥1,234
ซาอุดีอาระเบีย31/12/20241,234.561,234.56 SAR

การเรียงลำดับ (Collation) — การเรียงลำดับตัวอักษรแตกต่างกันไปตามภาษา ในภาษาสเปน "ch" มาหลัง "c" ในภาษาสวีเดน "ä" อยู่ท้ายตัวอักษร ในภาษาเยอรมัน "ß" เรียงเป็น "ss" iOS: LocalizedComparison (String.localizedCompare) Android: Collator.getInstance(locale) ห้ามใช้ compareTo() สำหรับสตริงที่แสดงแก่ผู้ใช้ — มันใช้ลำดับ Unicode Code Point ซึ่งไม่คำนึงถึงกฎภูมิภาค

แนวทางปฏิบัติที่ดีที่สุดสำหรับการทำให้แอปมือถือเป็นสากล

หลักการทางสถาปัตยกรรม — เริ่ม i18n ตั้งแต่ commit แรก ทุกสตริงในโค้ดต้องผ่านฟังก์ชันห่อหุ้ม (tr("key")) ซึ่งไม่มีอยู่จนกว่าจะตั้งค่า i18n — ซึ่งบังคับให้นักพัฒนาแยกสตริงทันที อย่าใช้สตริงภาษาอังกฤษเป็นคีย์ — เมื่อข้อความภาษาอังกฤษเปลี่ยน จะต้องอัปเดตคำแปลทั้งหมด ใช้คีย์ที่มีความหมาย: "profile.title", "settings.language.label"

การแปลเทียม (Pseudolocalization) — เทคนิคการทดสอบ i18n ก่อนการแปลจริง แทนที่ตัวอักษรละตินแต่ละตัวด้วยอักขระที่มีเครื่องหมายเสริม (á, é, ñ, ü) เพื่อตรวจสอบการเข้ารหัส เพิ่มคำนำหน้า [XXX] เพื่อตรวจสอบการตัดสตริง Xcode: สคีมาเรียกใช้ — ภาษาเทียม "Double-Length Pseudolanguage" Android: ตัวเลือกนักพัฒนา — บังคับทิศทางเลย์เอาต์ RTL, มาตราส่วนฟอนต์ระบบสูงถึง 200% การแปลเทียมค้นพบ 80% ของปัญหา i18n โดยไม่ต้องมีนักแปล

รายการตรวจสอบ i18n ของ IT Sectr — ก่อนเผยแพร่เราตรวจสอบ: (1) ไม่มีสตริงฮาร์ดโค้ดในโค้ด (ยกเว้น: ล็อก), (2) พหูพจน์ทำงานถูกต้องสำหรับทุกภาษา, (3) วันที่/ตัวเลขจัดรูปแบบผ่าน Locale API, (4) เลย์เอาต์แสดงผลถูกต้องบนภาษา RTL, (5) สตริงไม่ถูกตัดที่มาตราส่วนสูงสุด, (6) การแปลเทียมไม่พบข้อผิดพลาด, (7) ทุกภาษาที่ประกาศในสโตร์มีชุดคำแปลครบถ้วน

คำถามที่พบบ่อย

i18n แตกต่างจาก l10n อย่างไร?

i18n (การทำให้เป็นสากล) — การเตรียมโค้ด: การแยกสตริง, การรองรับ RTL, การจัดรูปแบบ นักพัฒนาทำครั้งเดียว l10n (การแปลเฉพาะที่) — การแปลสตริงเป็นภาษาเฉพาะ นักแปลทำหลายครั้งสำหรับแต่ละ locale i18n คือสถาปัตยกรรม l10n คือเนื้อหา หากไม่มี i18n การแปลเฉพาะที่เป็นไปไม่ได้ในหลักการ

NSLocalizedString ใน Swift ทำงานอย่างไร?

NSLocalizedString — มาโครที่ค้นหาค่าตามคีย์ใน Localizable.strings สำหรับ locale ปัจจุบันของอุปกรณ์ หากพบคำแปลจะส่งคืน หากไม่พบจะส่งคืนคีย์ รูปแบบ: NSLocalizedString("key", comment: "คำอธิบาย") สำหรับการจัดรูปแบบด้วยพารามิเตอร์ ให้ใช้ String.localizedStringWithFormat()

strings.xml ใน Android มีโครงสร้างอย่างไร?

strings.xml — ไฟล์ที่มีคำแปลในไดเรกทอรี res/values/{lang}/ เวอร์ชันฐานอยู่ใน values/strings.xml คำแปลอยู่ใน values-ru/strings.xml โค้ดเข้าถึงผ่าน getString(R.string.key) Android เลือกไฟล์ที่เหมาะสมโดยอัตโนมัติตามภาษาระบบ สำหรับพหูพจน์ จะใช้ทรัพยากร <plurals> กับตัวระบุ zero/one/few/many/other

RTL ในบริบทของ i18n คืออะไร?

RTL (Right-to-Left) — ทิศทางการเขียนสำหรับอาหรับ ฮีบรู อูรดู เปอร์เซีย Android: supportsRtl="true" ใน manifest, android:layoutDirection, Gravity.START/END iOS: UISemanticContentAttribute.forceLeftToRight สำหรับ RTL แบบบังคับ เลย์เอาต์ควรถูกสะท้อน: เมนูทางขวา ข้อความ — จากขวาไปซ้าย ไอคอนนำทาง — กลับด้าน

ภาษาใดบ้างที่จำเป็นสำหรับการเผยแพร่?

สำหรับการเผยแพร่ทั่วโลก ชุดขั้นต่ำ: อังกฤษ, สเปน, ฝรั่งเศส, เยอรมัน, ญี่ปุ่น, จีน, เกาหลี, โปรตุเกส, รัสเซีย, อิตาลี App Store ต้องการอย่างน้อยการแปลเฉพาะที่เป็นภาษาอังกฤษ แต่ละ locale เพิ่มเติมขยายกลุ่มผู้มีโอกาสเป็นลูกค้า สำหรับตลาดท้องถิ่น 1–2 ภาษาก็เพียงพอ

สรุป

  • Globalization (i18n) — การเตรียมแอปพลิเคชันในระดับสถาปัตยกรรมสำหรับหลายภาษาและภูมิภาค
  • NSLocalizedString — มาโคร Swift สำหรับแปลสตริงผ่าน Localizable.strings + การส่งออก XLIFF
  • strings.xml — ทรัพยากร Android ที่มีคำแปลในไดเรกทอรี values-{lang}
  • RTL — การรองรับบังคับสำหรับอาหรับ ฮีบรู อูรดู และเปอร์เซีย
  • รูปแบบ — วันที่และตัวเลขจัดรูปแบบอย่างเคร่งครัดผ่าน Locale API ไม่ใช่ด้วยตนเอง
  • พหูพจน์ — iOS: stringsdict, Android: <plurals> หกรูปแบบปริมาณ
  • การแปลเทียม — เทคนิคการทดสอบ i18n ก่อนการแปล (ตรวจจับ 80% ของปัญหา)

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม