Globalization: i18n và đa ngôn ngữ trong ứng dụng là gì

Tác giả: IT Sectr Đã đăng: 2026-02-26 Thời gian đọc: 8 phút

Globalization (toàn cầu hóa, còn gọi là quốc tế hóa, i18n) — quá trình chuẩn bị ứng dụng di động để hoạt động với nhiều ngôn ngữ và định dạng khu vực mà không thay đổi mã nguồn. Bao gồm trích xuất tài nguyên chuỗi khỏi mã, hỗ trợ các định dạng ngày, số và tiền tệ khác nhau, xử lý hướng văn bản (LTR/RTL) và thích ứng bố cục cho các ngôn ngữ khác nhau. iOS sử dụng NSLocalizedString và Localizable.strings, Android sử dụng strings.xml trong thư mục values-{lang}. Tìm hiểu thêm trong tài liệu quốc tế hóa của Apple.

Những điểm chính

  • Globalization (i18n) — chuẩn bị mã ứng dụng cho nhiều ngôn ngữ và khu vực
  • NSLocalizedString — macro Swift để lấy chuỗi đã dịch từ Localizable.strings
  • strings.xml — tệp XML Android lưu trữ chuỗi tài nguyên cho mỗi ngôn ngữ
  • RTL — hỗ trợ ngôn ngữ viết từ phải sang trái (tiếng Ả Rập, tiếng Do Thái, tiếng Urdu)
  • Định dạng — ngày, số và tiền tệ phải được định dạng qua API phụ thuộc Locale

Globalization (i18n) là gì và tại sao cần?

Globalization (viết tắt i18n — 18 chữ cái giữa "i" và "n") là sự chuẩn bị về mặt kiến trúc của ứng dụng để hoạt động với bất kỳ ngôn ngữ và khu vực nào. Quy tắc chính của i18n: không một chuỗi văn bản nào được mã hóa cứng (hardcoded) trong mã nguồn. Thay vào đó, các chuỗi được trích xuất vào tệp tài nguyên và mã truy cập chúng qua khóa (key). Khi thêm ngôn ngữ mới, chỉ cần thêm tệp dịch — mã không thay đổi. Điều này phân biệt i18n với bản địa hóa (l10n), nơi các chuỗi tự được dịch.

Lý do kinh doanh — toàn cầu hóa mở rộng thị trường. Theo Common Sense Advisory (2023), hơn 70% người dùng thích mua hàng trong ứng dụng bằng tiếng mẹ đẻ. Bản địa hóa sang 10 ngôn ngữ tăng đối tượng tiềm năng lên 80%. Không có i18n, mỗi lần mở rộng sang ngôn ngữ mới đều yêu cầu thay đổi mã, làm chậm thời gian tiếp cận thị trường và tăng chi phí lên 5–10 lần. Kiến trúc i18n đúng đắn cho phép hỗ trợ 40+ ngôn ngữ với chi phí tối thiểu.

Các thành phần i18n bao gồm: ngoại hóa chuỗi (string externalization), số nhiều (pluralization cho 1/2/5+), định dạng ngày và số (DateFormatter/SimpleDateFormat), hỗ trợ ngôn ngữ RTL (Right-to-Left), sắp xếp theo quy tắc locale (Collator), ký hiệu khu vực (dấu phân cách hàng nghìn, dấu thập phân). Tại IT Sectr, chúng tôi đưa i18n vào giai đoạn kiến trúc, không thêm sau — điều này tiết kiệm tới 60% thời gian trong quá trình bản địa hóa sau này.

Quốc tế hóa trong iOS: NSLocalizedString và XLIFF

NSLocalizedString — macro Swift chính để làm việc với bản dịch. Định dạng: NSLocalizedString("key", comment: "mô tả cho người dịch"). Macro tự động thay thế chuỗi từ Localizable.strings cho locale hiện tại của thiết bị (NSLocale.preferredLanguages). Nếu không tìm thấy bản dịch cho khóa, bản thân khóa hoặc giá trị trong ngôn ngữ phát triển (thường là en) được trả về. Apple khuyên dùng các khóa có ý nghĩa thay vì sử dụng chuỗi tiếng Anh làm khóa.

swift
// Localizable.strings (en)
// "welcome_title" = "Welcome!";
// Localizable.strings (ru)
// "welcome_title" = "Chào mừng bạn!";

// Mã Swift — thống nhất cho mọi ngôn ngữ
titleLabel.text = NSLocalizedString(
    "welcome_title",
    comment: "Tiêu đề màn hình chào mừng"
)

// Số nhiều qua Localizable.stringsdict
// 
// <dict>
//     <key>items_count</key>
//     <dict>
//         <key>NSStringLocalizedFormatKey</key>
//         <string>%#@items@</string>
//         <key>items</key>
//         <dict>
//             <key>one</key>
//             <string>%d sản phẩm</string>
//             <key>few</key>
//             <string>%d sản phẩm</string>
//             <key>many</key>
//             <string>%d sản phẩm</string>
//         </dict>
//     </dict>
// </dict>

// Sử dụng số nhiều
let items = 5
let label = String.localizedStringWithFormat(
    NSLocalizedString("items_count", comment: ""), items
)

XLIFF — định dạng trao đổi bản dịch giữa nhà phát triển và người dịch. Xcode xuất tệp XLIFF (Editor → Export for Localization) chứa tất cả chuỗi cần dịch. Người dịch làm việc với XLIFF trong các công cụ CAT (Trados, memoQ, Smartcat). Sau khi dịch, XLIFF được nhập lại vào Xcode (Editor → Import Localizations). XLIFF tự động cập nhật tất cả thư mục .lproj. Đây là quy trình bản địa hóa tiêu chuẩn cho ứng dụng iOS trong sản xuất.

SwiftUI và i18n

SwiftUI hoạt động với NSLocalizedString qua hàm khởi tạo Text. Văn bản trong SwiftUI tự động được quốc tế hóa: Text("welcome_title") tìm bản dịch trong Localizable.strings giống như NSLocalizedString. Đối với số nhiều, sử dụng Text("%d items", count: items). SwiftUI hỗ trợ định dạng ngày qua Text(date, style: .date) — nó tự động sử dụng Locale.current. Apple khuyên dùng SwiftUI cho các dự án mới vì quốc tế hóa trong đó minh bạch hơn.

Quốc tế hóa trong Android: strings.xml và RTL

Android i18n được xây dựng trên hệ thống tài nguyên. Chuỗi được đặt trong res/values/strings.xml cho ngôn ngữ mặc định (thường là tiếng Anh). Cho mỗi ngôn ngữ, một thư mục riêng được tạo: res/values-ru/strings.xml (tiếng Nga), res/values-de/strings.xml (tiếng Đức), res/values-fr/strings.xml (tiếng Pháp). Android tự động chọn chuỗi dựa trên ngôn ngữ hệ thống của thiết bị (Locale.getDefault()). Nếu không tìm thấy locale chính xác, bản gốc (values/strings.xml) được sử dụng.

kotlin
// res/values/strings.xml (tiếng Anh, mặc định)
<resources>
    <string name="welcome_title">Welcome!</string>
    <string name="items_count">%d item(s)</string>
</resources>

// res/values-ru/strings.xml (tiếng Nga)
<resources>
    <string name="welcome_title">Chào mừng!</string>
    <plurals name="items_count">
        <item quantity="one">%d sản phẩm</item>
        <item quantity="few">%d sản phẩm</item>
        <item quantity="many">%d sản phẩm</item>
    </plurals>
</resources>

// Mã Kotlin
textView.text = getString(R.string.welcome_title)

// Số nhiều
val items = 5
textView.text = resources.getQuantityString(
    R.plurals.items_count, items, items
)

// Hỗ trợ RTL trong mã
textView.textDirection = View.TEXT_DIRECTION_LOCALE
// Manifest: supportsRtl="true"

RTL (Right-to-Left) — hỗ trợ ngôn ngữ mà văn bản được đọc từ phải sang trái (tiếng Ả Rập, tiếng Do Thái, tiếng Urdu, tiếng Ba Tư). Android hỗ trợ RTL qua các thuộc tính android:layoutDirection và android:textDirection. Trong tệp kê khai (manifest), chỉ định android:supportsRtl="true" — và Android sẽ tự động phản chiếu bố cục. NavDrawer, biểu tượng quay lại/tiếp, căn chỉnh văn bản phải hoạt động theo cả hai hướng. Trong mã, sử dụng View.LAYOUT_DIRECTION_LOCALE và Gravity.START/END thay vì LEFT/RIGHT.

Tài nguyên đã bản địa hóa

Android Resource Qualifiers cho phép bản địa hóa không chỉ chuỗi mà còn hình ảnh (res/drawable-ru/), bố cục (res/layout-ru/), hoạt ảnh, màu sắc. Đối với tiếng Ả Rập và tiếng Do Thái, cần bố cục riêng với các phần tử được phản chiếu — sử dụng res/layout-ar/ (tiếng Ả Rập). Android cũng hỗ trợ biến thể khu vực: values-rUS, values-rGB, values-de-DE. Các bộ định tính có thể kết hợp: values-ldrtl-ru — tiếng Nga cho màn hình RTL.

Định dạng khu vực: ngày, số, tiền tệ trong iOS và Android

Ngày và giờ — một trong những khía cạnh chính của i18n. Các khu vực khác nhau sử dụng định dạng khác nhau: Nga — DD.MM.YYYY, Mỹ — MM/DD/YYYY, Nhật Bản — YYYY.MM.DD. Sử dụng định dạng cố định (yyyy-MM-dd) để hiển thị cho người dùng là sai. Trong iOS, sử dụng DateFormatter với Locale(identifier: locale), trong Android — DateFormat.getDateInstance(DateFormat.SHORT, locale). Đối với trợ lý giọng nói và tìm kiếm AI, ngày tháng phải ở định dạng ISO 8601 nội bộ.

Số và tiền tệ — các khu vực khác nhau có dấu phân cách khác nhau: 1,234.56 (Mỹ) vs 1.234,56 (Nga), 1 234,56 (Pháp). iOS: NumberFormatter với .locale = locale. Android: DecimalFormat với DecimalFormatSymbols(locale). Đối với tiền tệ: định dạng ¥1,234 (Nhật Bản) vs $1,234.56 (Mỹ) vs 1 234,56 ₽ (Nga). Không bao giờ nối tiền tệ và số thủ công — sử dụng NumberFormatter.currencyCode và .currencySymbol.

Khu vựcNgàySốTiền tệ
Nga31.12.20241 234,561 234,56 ₽
Mỹ12/31/20241,234.56$1,234.56
Đức31.12.20241.234,561.234,56 €
Nhật Bản2024/12/311,234¥1,234
Ả Rập Saudi31/12/20241,234.561,234.56 SAR

Sắp xếp (Collation) — thứ tự bảng chữ cái khác nhau giữa các ngôn ngữ. Trong tiếng Tây Ban Nha, "ch" đứng sau "c". Trong tiếng Thụy Điển, "ä" ở cuối bảng chữ cái. Trong tiếng Đức, "ß" được sắp xếp như "ss". iOS: LocalizedComparison (String.localizedCompare). Android: Collator.getInstance(locale). Không bao giờ sử dụng compareTo() cho chuỗi hiển thị cho người dùng — nó sử dụng thứ tự Unicode Code Point, không xét đến quy tắc khu vực.

Thực tiễn tốt nhất về quốc tế hóa ứng dụng di động

Nguyên tắc kiến trúc — bắt đầu i18n từ commit đầu tiên. Mọi chuỗi trong mã phải đi qua hàm bao bọc (tr("key")) chưa tồn tại cho đến khi i18n được thiết lập — điều này buộc nhà phát triển phải ngoại hóa chuỗi ngay lập tức. Không sử dụng chuỗi tiếng Anh làm khóa — khi cách diễn đạt tiếng Anh thay đổi, tất cả bản dịch phải được cập nhật. Sử dụng khóa có ý nghĩa: "profile.title", "settings.language.label".

Giả bản địa hóa (Pseudolocalization) — kỹ thuật kiểm tra i18n trước khi dịch thực tế. Thay thế mỗi chữ cái Latinh bằng ký tự có dấu phụ (á, é, ñ, ü) để kiểm tra mã hóa, thêm tiền tố [XXX] để kiểm tra việc cắt chuỗi. Xcode: lược đồ chạy — ngôn ngữ giả "Double-Length Pseudolanguage". Android: Tùy chọn nhà phát triển — Buộc hướng bố cục RTL, tỷ lệ phông hệ thống lên 200%. Giả bản địa hóa phát hiện 80% vấn đề i18n mà không cần người dịch.

Danh sách kiểm tra i18n của IT Sectr — trước khi phát hành, chúng tôi kiểm tra: (1) không có chuỗi mã hóa cứng trong mã (ngoại lệ: nhật ký), (2) số nhiều hoạt động chính xác cho tất cả ngôn ngữ, (3) ngày/số được định dạng qua Locale API, (4) bố cục hiển thị chính xác trên ngôn ngữ RTL, (5) chuỗi không bị cắt ở tỷ lệ tối đa, (6) giả bản địa hóa không phát hiện lỗi, (7) tất cả ngôn ngữ khai báo trong cửa hàng có đầy đủ bộ bản dịch.

Câu hỏi thường gặp

i18n khác l10n như thế nào?

i18n (quốc tế hóa) — chuẩn bị mã: ngoại hóa chuỗi, hỗ trợ RTL, định dạng. Nhà phát triển thực hiện một lần. l10n (bản địa hóa) — dịch chuỗi sang ngôn ngữ cụ thể. Người dịch thực hiện nhiều lần cho mỗi locale. i18n là kiến trúc, l10n là nội dung. Không có i18n, bản địa hóa về nguyên tắc là không thể.

NSLocalizedString trong Swift hoạt động thế nào?

NSLocalizedString — macro tìm giá trị theo khóa trong Localizable.strings cho locale hiện tại của thiết bị. Nếu tìm thấy bản dịch, trả về bản dịch. Nếu không, trả về khóa. Định dạng: NSLocalizedString("key", comment: "mô tả"). Để định dạng với tham số, sử dụng String.localizedStringWithFormat().

strings.xml trong Android được cấu trúc thế nào?

strings.xml — tệp có bản dịch trong thư mục res/values/{lang}/. Phiên bản cơ sở trong values/strings.xml, bản dịch trong values-ru/strings.xml. Mã truy cập qua getString(R.string.key). Android tự động chọn tệp phù hợp dựa trên ngôn ngữ hệ thống. Cho số nhiều, tài nguyên <plurals> được sử dụng với bộ định tính zero/one/few/many/other.

RTL trong ngữ cảnh i18n là gì?

RTL (Right-to-Left) — hướng viết cho tiếng Ả Rập, tiếng Do Thái, tiếng Urdu, tiếng Ba Tư. Android: supportsRtl="true" trong tệp kê khai, android:layoutDirection, Gravity.START/END. iOS: UISemanticContentAttribute.forceLeftToRight cho RTL bắt buộc. Bố cục phải được phản chiếu: menu bên phải, văn bản — từ phải sang trái, biểu tượng điều hướng — đảo ngược.

Những ngôn ngữ nào bắt buộc để xuất bản?

Để xuất bản toàn cầu, bộ tối thiểu: tiếng Anh, tiếng Tây Ban Nha, tiếng Pháp, tiếng Đức, tiếng Nhật, tiếng Trung, tiếng Hàn, tiếng Bồ Đào Nha, tiếng Nga, tiếng Ý. App Store yêu cầu tối thiểu bản địa hóa tiếng Anh. Mỗi locale bổ sung mở rộng đối tượng tiềm năng. Cho thị trường địa phương, 1–2 ngôn ngữ là đủ.

Tóm tắt

  • Globalization (i18n) — chuẩn bị kiến trúc ứng dụng cho nhiều ngôn ngữ và khu vực
  • NSLocalizedString — macro Swift để dịch chuỗi qua Localizable.strings + xuất XLIFF
  • strings.xml — tài nguyên Android với bản dịch trong thư mục values-{lang}
  • RTL — hỗ trợ bắt buộc cho tiếng Ả Rập, tiếng Do Thái, tiếng Urdu và tiếng Ba Tư
  • Định dạng — ngày và số được định dạng chặt chẽ qua Locale API, không thủ công
  • Số nhiều — iOS: stringsdict, Android: <plurals> với sáu dạng số lượng
  • Giả bản địa hóa — kỹ thuật kiểm tra i18n trước khi dịch (phát hiện 80% vấn đề)

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm