Skip to main content

Hướng dẫn đầy đủ về bản địa hóa Unreal Engine

Từ macro FText đến chuỗi dự phòng ngôn ngữ: bản địa hóa trò chơi UE5 của bạn bằng Localization Dashboard, String Tables, C++, Blueprints và dịch thuật tự động.

1

FText & quy trình bản địa hóa

FText là kiểu chuỗi hỗ trợ bản địa hóa của Unreal Engine. Mọi chuỗi hiển thị cho người dùng trong trò chơi — nhãn giao diện, hội thoại, chú giải công cụ, thông báo — đều phải dùng FText để tham gia quy trình bản địa hóa. Chỉ dùng FString cho logic nội bộ.

LOCTEXT cần hai đối số: một khóa và một chuỗi nguồn. Khóa phải là duy nhất trong không gian tên. Trình thu thập văn bản của UE dùng các khóa này để theo dõi bản dịch giữa các ngôn ngữ. NSLOCTEXT cho phép bạn chỉ định rõ không gian tên; LOCTEXT dùng không gian tên do macro LOCTEXT_NAMESPACE bao quanh xác định.
FText Basics
// FText is UE's localization-aware string type.
// ALWAYS use FText for user-facing text, never FString.

// LOCTEXT: localize a literal string (most common)
FText Title = LOCTEXT("MainMenuTitle", "Start Game");

// NSLOCTEXT: specify namespace explicitly
FText Msg = NSLOCTEXT("UI", "WelcomeMessage", "Welcome, adventurer!");

// INVTEXT: invariant text (never translated — debug/logging only)
FText Debug = INVTEXT("Debug overlay active");

// FText::Format: safe variable interpolation
FText Greeting = FText::Format(
    LOCTEXT("PlayerGreeting", "Hello, {PlayerName}!"),
    FText::FromString(PlayerName)
);
MainMenuWidget.cpp
// In a UMG Widget (C++)
void UMainMenuWidget::NativeConstruct()
{
    Super::NativeConstruct();

    // Bind localized text to UI elements
    if (TitleLabel)
    {
        TitleLabel->SetText(LOCTEXT("GameTitle", "My Epic Game"));
    }

    if (PlayButton)
    {
        PlayButton->SetText(LOCTEXT("PlayButtonLabel", "Play Now"));
    }
}

// IMPORTANT: Always use LOCTEXT for UMG widget text.
// Setting text via FString bypasses the localization pipeline.
Tuyệt đối không tạo văn bản hiển thị cho người dùng bằng FString::Printf hoặc phép nối chuỗi. Chúng hoàn toàn bỏ qua quy trình bản địa hóa — văn bản tạo ra không thể được thu thập, dịch hoặc hiển thị đúng trong các ngôn ngữ RTL. Thay vào đó, luôn dùng FText::Format với mẫu LOCTEXT.
2

Thiết lập Localization Dashboard

Localization Dashboard là công cụ tích hợp sẵn của UE để quản lý bản dịch. Công cụ này thu thập mọi chuỗi LOCTEXT và NSLOCTEXT từ mã nguồn, xuất thành tệp .po để dịch và biên dịch kết quả thành tệp nhị phân .locres mà UE tải khi chạy.

Localization Dashboard Workflow
# 1. Open the Localization Dashboard:
#    Window > Localization Dashboard

# 2. Add a localization target (e.g., "Game")

# 3. Add cultures:
#    Click "Add New Culture" > select languages (de, ja, fr, es, ko, zh-Hans...)

# 4. Gather text:
#    Click "Gather Text" — UE scans all LOCTEXT/NSLOCTEXT macros

# 5. Export translations:
#    Click "Export" to generate .po files for each culture

# 6. Import translations:
#    After translating .po files, click "Import"

# 7. Compile translations:
#    Click "Compile" to generate .locres binary files

# 8. Preview:
#    Editor Preferences > Region & Language > Preview Game Language
Chạy 'Gather Text' sau mỗi thay đổi mã có thêm hoặc sửa macro LOCTEXT. Nếu bỏ qua bước này, chuỗi mới sẽ không xuất hiện trong tệp .po nên người dịch không thể thấy chúng. Hãy thêm bước thu thập vào quy trình tự động hóa bản dựng để tự động phát hiện vấn đề này.
3

Dùng String Tables cho văn bản dựa trên dữ liệu

String Tables cho phép bạn xác định chuỗi đã bản địa hóa trong một tài nguyên tập trung thay vì rải macro LOCTEXT khắp các tệp nguồn. Chúng rất phù hợp với văn bản giao diện, hội thoại và mọi chuỗi mà nhà thiết kế hoặc người viết cần chỉnh sửa mà không phải đụng đến mã. Bạn có thể xác định String Tables dưới dạng tài nguyên UE hoặc nhập từ CSV.

StringTableUsage.cpp
// StringTables provide a data-driven approach to localization.
// Define strings in a CSV asset instead of scattering LOCTEXT across code.

// 1. Create a String Table asset:
//    Content Browser > Right-click > Miscellaneous > String Table

// 2. Or define via CSV (importable into UE):
// Key,SourceString
// MainMenu_Title,Start Game
// MainMenu_Continue,Continue
// MainMenu_Settings,Settings
// MainMenu_Quit,Quit to Desktop
// HUD_Health,Health
// HUD_Ammo,Ammo: {0}
// Dialog_Merchant_Greeting,Welcome to my shop!

// 3. Reference in C++:
FText Title = FText::FromStringTable(
    FName(TEXT("/Game/Localization/ST_MainMenu")),
    TEXT("MainMenu_Title")
);

// 4. Reference in Blueprints:
//    Use the "Make Text from String Table" node
//    Set Table ID and Key
Localization Dashboard tự động thu thập String Tables. Bạn không cần macro LOCTEXT cho chuỗi được xác định trong String Table — chỉ cần tham chiếu bằng ID bảng và khóa trong C++ hoặc Blueprints.
4

Mẫu bản địa hóa C++

Trong C++, hãy xác định một LOCTEXT_NAMESPACE ở đầu mỗi tệp .cpp và dùng LOCTEXT cho mọi chuỗi hiển thị cho người dùng. Dùng FText::Format cho nội dung động có biến. Luôn hủy định nghĩa không gian tên ở cuối tệp để tránh rò rỉ.

MainMenuWidget.cpp
// Define a namespace at the top of each .cpp file
// All LOCTEXT calls in this file use this namespace
#define LOCTEXT_NAMESPACE "MyGame.MainMenu"

#include "MainMenuWidget.h"

void UMainMenuWidget::NativeConstruct()
{
    Super::NativeConstruct();

    // These use the "MyGame.MainMenu" namespace automatically
    TitleText->SetText(LOCTEXT("Title", "Main Menu"));
    PlayText->SetText(LOCTEXT("PlayButton", "Play"));
    SettingsText->SetText(LOCTEXT("SettingsButton", "Settings"));
    QuitText->SetText(LOCTEXT("QuitButton", "Quit"));
}

// CRITICAL: Always undefine at the end of the file
#undef LOCTEXT_NAMESPACE
FText::Format Examples
// FText::Format — the safe way to build localized strings
// NEVER use FString::Printf or string concatenation for user-facing text.

// Named arguments (recommended)
FText ItemPickup = FText::Format(
    LOCTEXT("ItemPickup", "You picked up {ItemName} x{Count}"),
    FText::FromString(ItemName),
    FText::AsNumber(Count)
);

// FText::AsNumber respects locale formatting:
//   English: 1,234,567
//   German:  1.234.567
//   French:  1 234 567

// FText::AsCurrency for prices:
FText Price = FText::AsCurrency(
    9.99,
    TEXT("USD"),
    &FInternationalization::Get().GetCurrentCulture().Get()
);

// FText::AsDate and FText::AsTime for dates:
FText DateStr = FText::AsDate(FDateTime::Now());
Đối số của FText::Format cũng phải là FText, không phải FString thô. Dùng FText::FromString() để chuyển đổi giá trị FString, FText::AsNumber() để định dạng số theo ngôn ngữ và FText::AsCurrency() để định dạng giá. Phép nối FString thô tạo ra văn bản không tuân thủ quy tắc định dạng ngôn ngữ.
5

Bản địa hóa Blueprint

Theo mặc định, mọi thuộc tính Text trong Blueprints đều là FText nên đã sẵn sàng để bản địa hóa. Đặt Key và Namespace trong bảng chi tiết thuộc tính để hệ thống có thể thu thập chuỗi. Dùng nút Format Text cho nội dung động có biến.

Blueprint Localization Patterns
// Blueprint Localization Basics:
//
// 1. All Text properties in Blueprints are FText by default
//    (already localization-ready)
//
// 2. Set the Text property in the Details panel
//    Expand the dropdown to set:
//    - Key: unique identifier for translation
//    - Namespace: grouping for organization
//    - Source String: the text to display/translate
//
// 3. For dynamic text, use the "Format Text" node:
//    Format: "Hello, {PlayerName}!"
//    Connect a "Find" pin named "PlayerName" to your variable
//
// 4. For plurals, use "Text Format with Arguments":
//    Pattern: "{Count}|plural(one=item,other=items)"
//
// 5. Culture switching at runtime:
//    Use "Set Current Culture" node
//    Input: culture code string (e.g., "de", "ja", "fr")
Mở rộng trình đơn thuộc tính văn bản trong bảng Blueprint Details để xem các trường Key, Namespace và Source String. Đặt Key có ý nghĩa sẽ giúp người dịch nhận diện chuỗi trong tệp .po dễ dàng hơn nhiều.
6

Xử lý số nhiều và giới tính

Unreal Engine hỗ trợ định dạng thông báo ICU cho dạng số nhiều và văn bản phụ thuộc vào giới tính. Hãy xác định quy tắc số nhiều trong chuỗi nguồn để UE tự động chọn dạng đúng theo quy tắc CLDR của ngôn ngữ đang dùng.

ICU Plural & Gender Rules
// UE uses ICU message format for plurals.
// Define plural rules in your .po or String Table:

// English source:
// "{Count}|plural(one=You have # item,other=You have # items)"

// German translation:
// "{Count}|plural(one=Du hast # Gegenstand,other=Du hast # Gegenstaende)"

// Arabic translation (6 forms):
// "{Count}|plural(zero=لا عناصر,one=عنصر واحد,two=عنصران,few=# عناصر,many=# عنصرًا,other=# عنصر)"

// Japanese (1 form):
// "{Count}|plural(other=アイテム#個)"

// In C++:
FText ItemCount = FText::Format(
    LOCTEXT("ItemCount",
        "{Count}|plural(one=You have {Count} item,other=You have {Count} items)"),
    ItemCount
);

// Gender-dependent text:
// "{Gender}|gender(masculine=Il est,feminine=Elle est) prêt{Gender}|gender(masculine=,feminine=e)"
Tuyệt đối không viết cứng count == 1 để phát hiện số ít. Tiếng Pháp coi 0 là số ít. Tiếng Nga có các dạng riêng cho 'few' và 'many'. Tiếng Ả Rập có 6 dạng số nhiều. Hãy để quy tắc số nhiều ICU xử lý logic — xác định mọi dạng cần thiết để UE chọn đúng dạng cho từng ngôn ngữ.
7

Đóng gói và kiểm thử bản địa hóa

Trước khi phát hành, hãy xác minh mọi ngôn ngữ đích đều có tệp .locres đã biên dịch và văn bản hiển thị đúng khi chạy. Dùng chế độ xem trước ngôn ngữ của Editor, tùy chọn ghi đè ngôn ngữ trên dòng lệnh và quy trình kiểm tra tự động để phát hiện bản dịch thiếu hoặc lỗi.

Packaging & Testing Workflow
# Compile and test localization before packaging:

# 1. Editor Preferences > Region & Language > Preview Game Language
#    Set to each target language and verify all text renders correctly.

# 2. Command-line culture override for testing:
MyGame.exe -culture=ja

# 3. Packaging settings:
#    Project Settings > Packaging > Localizations to Package
#    Select all cultures you want to include in the build.

# 4. Verify .locres files exist after packaging:
MyGame/Content/Localization/Game/
├── en/
│   └── Game.locres
├── de/
│   └── Game.locres
├── ja/
│   └── Game.locres
├── fr/
│   └── Game.locres
└── ko/
    └── Game.locres

# 5. Runtime culture switching:
#    FInternationalization::Get().SetCurrentCulture(TEXT("ja"));
#    This reloads all FText strings from the new culture's .locres files.
Nếu một ngôn ngữ không có trong Project Settings > Packaging > Localizations to Package, bản dựng sẽ loại trừ các tệp .locres của ngôn ngữ đó. Người chơi chọn ngôn ngữ này khi chạy sẽ thấy văn bản dự phòng hoặc chuỗi trống. Luôn xác minh cài đặt đóng gói khớp với các ngôn ngữ bạn hỗ trợ.
8

Thêm chuỗi dự phòng ngôn ngữ

Cơ chế bản địa hóa mặc định của Unreal Engine chỉ dự phòng theo hệ phân cấp thẻ con IETF. Người dùng pt-BR thiếu bản dịch sẽ nhận văn bản tiếng Anh thay vì bản dịch pt-PT hoàn toàn phù hợp. locale-chain-ue bổ sung chuỗi dự phòng ngang có thể cấu hình qua FTextLocalizationManager để người dùng từng khu vực luôn thấy bản dịch gần nhất hiện có.

locale-chain-ue (C++)
// locale-chain-ue: Smart fallback chains for UE5
// Problem: UE falls back to default when a locale is missing.
// pt-BR user gets English instead of pt-PT translations.

// Solution: One function call at startup.
#include "LocaleChain.h"

void UMyGameInstance::Init()
{
    Super::Init();
    ULocaleChain::Configure();  // Load 75 built-in fallback chains
}

// Now resolve strings with per-key fallback:
FString Greeting = ULocaleChain::Resolve(
    TEXT("greeting"), TEXT("MyNamespace")
);
// pt-BR user: tries pt-BR -> pt-PT -> pt -> default

// Custom overrides:
TMap<FString, FString> Overrides;
Overrides.Add(TEXT("pt-BR"), TEXT("pt"));       // Simplify chain
Overrides.Add(TEXT("sv-FI"), TEXT("sv"));        // Add new chain
ULocaleChain::ConfigureWithOverrides(Overrides);

// Full control (C++ only):
TMap<FString, TArray<FString>> Custom;
Custom.Add(TEXT("pt-BR"), {TEXT("pt-PT"), TEXT("pt")});
Custom.Add(TEXT("es-MX"), {TEXT("es-419"), TEXT("es")});
ULocaleChain::ConfigureCustom(Custom, false);
Gọi ULocaleChain::Configure() một lần khi khởi động để tải 75 chuỗi dự phòng tích hợp sẵn, bao phủ 11 họ ngôn ngữ. Dùng ConfigureWithOverrides để tùy chỉnh thuận tiện trong Blueprint hoặc ConfigureCustom trong C++ để kiểm soát hoàn toàn hành vi dự phòng.

Tự động hóa chất lượng bản dịch

Phát hiện khóa thiếu và placeholder lỗi trước khi phát hành bằng i18n-validate. Kiểm thử giao diện bằng bản dịch giả lập với i18n-pseudo trước khi có bản dịch thật.

Lỗi thường gặp

Dùng FString cho văn bản hiển thị cho người dùng

FString bỏ qua toàn bộ quy trình bản địa hóa. Hệ thống không thể thu thập, dịch hoặc hiển thị đúng văn bản tạo bằng FString::Printf hay phép nối chuỗi trong các ngôn ngữ RTL. Luôn dùng FText với macro LOCTEXT và FText::Format cho chuỗi hiển thị cho người dùng.

Thiếu #undef LOCTEXT_NAMESPACE

Quên #undef LOCTEXT_NAMESPACE ở cuối tệp .cpp khiến không gian tên rò rỉ sang các đơn vị biên dịch tiếp theo. Việc này âm thầm gán sai không gian tên cho chuỗi trong các tệp khác khiến bản dịch xuất hiện sai ngữ cảnh.

Logic số nhiều viết cứng

Viết 'count == 1 ? singular : plural' sẽ bỏ qua quy tắc CLDR. Tiếng Pháp coi 0 là số ít, tiếng Nga có 4 dạng số nhiều còn tiếng Ả Rập có 6 dạng. Hãy dùng cú pháp số nhiều ICU trong mẫu FText và để UE xử lý quy tắc theo từng ngôn ngữ.

Quên biên dịch sau khi nhập

Nhập tệp .po sẽ cập nhật dữ liệu văn bản nhưng không tạo tệp nhị phân .locres. Khi chạy, trò chơi vẫn tải các bản dịch cũ đã biên dịch. Luôn chạy 'Compile' trong Localization Dashboard sau khi nhập hoặc thêm bước này vào quy trình tự động hóa bản dựng.

Cấu trúc dự án đề xuất

Project Structure
MyUnrealProject/
├── Config/
│   └── Localization/
│       └── Game.ini                  # Localization target config
├── Content/
│   └── Localization/
│       ├── Game/
│       │   ├── Game.manifest         # Gather manifest
│       │   ├── en/
│       │   │   ├── Game.po           # Source strings (.po)
│       │   │   └── Game.locres       # Compiled binary
│       │   ├── de/
│       │   │   ├── Game.po
│       │   │   └── Game.locres
│       │   ├── ja/
│       │   │   ├── Game.po
│       │   │   └── Game.locres
│       │   └── fr/
│       │       ├── Game.po
│       │       └── Game.locres
│       └── StringTables/
│           ├── ST_MainMenu.uasset    # String Table asset
│           └── ST_HUD.uasset
├── Plugins/
│   └── LocaleChain/                  # locale-chain-ue plugin
│       ├── LocaleChain.uplugin
│       └── Source/
│           └── LocaleChain/
├── Source/
│   └── MyGame/
│       ├── UI/
│       │   ├── MainMenuWidget.h
│       │   └── MainMenuWidget.cpp    # LOCTEXT macros here
│       └── MyGameInstance.cpp        # ULocaleChain::Configure()
└── MyUnrealProject.uproject

Dùng thử i18n Agent ngay

Thả tệp bản dịch của bạn vào đây

JSON, YAML, PO, XML, CSV, Markdown, Properties

hoặc nhấp để duyệt

Ngôn ngữ đích

Không cần đăng kýBáo giá tức thì

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