xuk 22c87d2bf7 i18n: add runtime language switching infrastructure
- Add i18n/ module: imgui_i18n.h (Tr() macro + stub when disabled),
  imgui_i18n.cpp (lookup table, Meyers singleton, placeholder substitution),
  locale/zh_CN.cpp (Simplified Chinese translation table),
  tools/extract_strings.py (helper to extract translatable strings)
- Opt-in via IMGUI_DEMO_ENABLE_I18N build flag; without it Tr(s) expands
  to (s) at compile time with zero overhead and no extra dependencies
- See i18n/README.md for integration guide and how to add a new language
2026-06-08 11:22:10 +08:00
..

Dear ImGui — i18n (Internationalization)

Runtime language switching for imgui_demo.cpp.
Currently ships with Simplified Chinese (zh_CN).


How It Works

Component Role
imgui_i18n.h Tr() macro + namespace declaration
imgui_i18n.cpp Lookup table, fallback, $1/$2 placeholder substitution
locale/zh_CN.cpp Chinese translation table (static initializer, auto-registered)
tools/extract_strings.py Helper to extract translatable strings from a source range

Every user-visible string literal in imgui_demo.cpp is wrapped with Tr("...").
Tr() looks up the active locale table and returns the translated string, or falls back to the original English if no translation exists.

Opt-in build flag

Define IMGUI_DEMO_ENABLE_I18N in your build to activate i18n.
Without it, Tr(s) expands to (s) at compile time — zero overhead, no extra files needed.


Quick Start (macOS example_apple_metal)

# Makefile already includes IMGUI_DEMO_ENABLE_I18N and the i18n sources.
cd examples/example_apple_metal
make && ./example_apple_metal
# Open the Language menu in the demo window menu bar → switch to 中文

For other platforms/examples, see Integrating into Your Build below.


Adding a New Language

1. Create a locale file

Copy locale/zh_CN.cpp to locale/<locale_id>.cpp (e.g. locale/ja_JP.cpp).

// locale/ja_JP.cpp
#include "../imgui_i18n.h"

namespace {
struct JaJPRegistrar {
    JaJPRegistrar() {
        imgui_i18n::registerLocale("ja_JP", {
            {"Configuration",  "設定"},
            {"Dear ImGui Demo","Dear ImGui デモ"},
            // ... add all entries
        });
    }
} s_ja_jp;
} // namespace

Key rules:

  • The key is the exact English string as it appears in imgui_demo.cpp (including punctuation and newlines).
  • Missing keys automatically fall back to English — you can ship a partial translation.
  • For strings containing ## (ImGui internal IDs like "Configuration##2"), the key in the table is only the visible part ("Configuration"); the ##2 suffix is appended in code.

2. Add the locale file to your build

Makefile (Linux/macOS):

SOURCES += $(IMGUI_DIR)/i18n/imgui_i18n.cpp
SOURCES += $(IMGUI_DIR)/i18n/locale/ja_JP.cpp   # add your new locale
CXXFLAGS += -I$(IMGUI_DIR)/i18n -DIMGUI_DEMO_ENABLE_I18N

CMake:

target_sources(my_app PRIVATE
    ${IMGUI_DIR}/i18n/imgui_i18n.cpp
    ${IMGUI_DIR}/i18n/locale/ja_JP.cpp
)
target_include_directories(my_app PRIVATE ${IMGUI_DIR}/i18n)
target_compile_definitions(my_app PRIVATE IMGUI_DEMO_ENABLE_I18N)

Xcode: Add both .cpp files to the target's Compile Sources phase.

3. Add a menu item for the new language

In imgui_demo.cpp, find the Language menu (search for BeginMenu(Tr("Language"))):

if (ImGui::MenuItem("日本語", nullptr, is_ja) && !is_ja)
{
    imgui_i18n::setLocale("ja_JP");
#if defined(__APPLE__)
    g_need_font_rebuild = true;   // triggers CJK font reload on Apple Metal
#endif
}

4. Font loading (CJK / non-Latin scripts)

For languages requiring non-Latin glyphs, add font loading logic in your platform's main file (see examples/example_apple_metal/main.mm → RebuildFonts() for reference).

The pattern:

  1. Call io.Fonts->AddFontDefault(&cfg) with explicit SizePixels first (required by ImGui v1.92+).
  2. Merge the target-language font with cfg.MergeMode = true.
  3. Choose glyph ranges: use io.Fonts->GetGlyphRangesChineseSimplifiedCommon() for Chinese, GetGlyphRangesJapanese() for Japanese, etc.
  4. Call io.Fonts->Build().

Extracting Strings for Translation

Use the helper script to generate a translation skeleton for a range of lines:

cd imgui-master    # or wherever imgui_demo.cpp lives
python3 i18n/tools/extract_strings.py imgui_demo.cpp <start_line> <end_line>

Output is ready-to-paste {"English key", ""}, entries.
Paste them into your locale file and fill in the translated values.


Integrating into Your Build (Other Examples)

Only example_apple_metal ships with i18n enabled by default.
To enable it for any other example:

  1. Add imgui_i18n.cpp and your locale .cpp files to the build.
  2. Add -I<imgui_root>/i18n to include paths.
  3. Add -DIMGUI_DEMO_ENABLE_I18N to compiler flags.
  4. Add font loading + language-switch UI to your platform's main file
    (use examples/example_apple_metal/main.mm as a reference).

API Reference

// imgui_i18n.h (available when IMGUI_DEMO_ENABLE_I18N is defined)

Tr("key")                         // translate key, return const char*
TrF("Draw $1 of $2", {"3","10"}) // translate + substitute placeholders

imgui_i18n::setLocale("zh_CN");   // switch language (call before NewFrame)
imgui_i18n::getLocale();          // returns current locale string ("" = English)
imgui_i18n::registerLocale(       // called by locale/*.cpp static initializers
    "locale_id",
    { {"English key", "Translation"}, ... }
);

Current Translations

Locale Language Coverage
(default) English 100% (source)
zh_CN Simplified Chinese ~100% of imgui_demo.cpp

Contributions welcome — see Adding a New Language above.