From 22c87d2bf71bbe0cdf01cbba9387bae912383e01 Mon Sep 17 00:00:00 2001 From: xuk Date: Mon, 8 Jun 2026 11:22:10 +0800 Subject: [PATCH 01/12] 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 --- i18n/README.md | 169 +++++++ i18n/imgui_i18n.cpp | 60 +++ i18n/imgui_i18n.h | 47 ++ i18n/locale/zh_CN.cpp | 834 ++++++++++++++++++++++++++++++++++ i18n/tools/extract_strings.py | 25 + 5 files changed, 1135 insertions(+) create mode 100644 i18n/README.md create mode 100644 i18n/imgui_i18n.cpp create mode 100644 i18n/imgui_i18n.h create mode 100644 i18n/locale/zh_CN.cpp create mode 100644 i18n/tools/extract_strings.py diff --git a/i18n/README.md b/i18n/README.md new file mode 100644 index 000000000000..7a729e4dd738 --- /dev/null +++ b/i18n/README.md @@ -0,0 +1,169 @@ +# 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) + +```bash +# 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/.cpp` (e.g. `locale/ja_JP.cpp`). + +```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):** +```makefile +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:** +```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"))`): + +```cpp +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: + +```bash +cd imgui-master # or wherever imgui_demo.cpp lives +python3 i18n/tools/extract_strings.py imgui_demo.cpp +``` + +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/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 + +```cpp +// 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. diff --git a/i18n/imgui_i18n.cpp b/i18n/imgui_i18n.cpp new file mode 100644 index 000000000000..653da987f4a0 --- /dev/null +++ b/i18n/imgui_i18n.cpp @@ -0,0 +1,60 @@ +// i18n/imgui_i18n.cpp +#include "imgui_i18n.h" +#include +#include + +namespace imgui_i18n { + +// Meyers Singleton — 保证跨编译单元 static initializer 调用时已初始化(避免 SIOF) +static std::string& locale() { + static std::string s; + return s; +} + +static std::unordered_map>& tables() { + static std::unordered_map> s; + return s; +} + +void setLocale(const char* loc) { + locale() = loc ? loc : ""; +} + +const char* getLocale() { + return locale().c_str(); +} + +const char* translate(const char* key) { + if (!key) return ""; + if (locale().empty()) return key; // English fast path + auto it = tables().find(locale()); + if (it == tables().end()) return key; + auto it2 = it->second.find(key); + if (it2 == it->second.end()) return key; + return it2->second.c_str(); +} + +std::string fmt(const char* key, std::initializer_list args) { + std::string result = translate(key); + int i = 1; + for (const auto& arg : args) { + std::string ph = "$" + std::to_string(i++); + size_t pos; + while ((pos = result.find(ph)) != std::string::npos) + result.replace(pos, ph.size(), arg); + } + return result; +} + +void registerLocale( + const char* loc, + std::initializer_list> entries) +{ + // 注意:registerLocale 必须在第一次调用 translate() 之前全部完成(通常由 static initializer 保证) + // 注册完成后不可再追加,否则 unordered_map rehash 会使已返回的 c_str() 指针失效 + auto& table = tables()[loc]; + for (const auto& e : entries) + table[e.first] = e.second; +} + +} // namespace imgui_i18n diff --git a/i18n/imgui_i18n.h b/i18n/imgui_i18n.h new file mode 100644 index 000000000000..f9847b880379 --- /dev/null +++ b/i18n/imgui_i18n.h @@ -0,0 +1,47 @@ +// dear imgui - i18n (internationalization) module +// Provides runtime language switching for imgui_demo.cpp. +// +// Usage: +// Define IMGUI_DEMO_ENABLE_I18N in your build system to opt in. +// Without it, Tr(s) is a no-op and other examples are unaffected. +// +// See i18n/README.md for details and how to add a new language. +#pragma once + +#ifdef IMGUI_DEMO_ENABLE_I18N + +#include +#include +#include + +// Wrap every user-visible string literal in imgui_demo.cpp with Tr(). +#define Tr(s) imgui_i18n::translate(s) +// Variant with $1/$2/... placeholder substitution. +#define TrF(s, ...) imgui_i18n::fmt(s, __VA_ARGS__) + +namespace imgui_i18n { + +// Set active locale: "" or "en" = English (default, zero-overhead fast path). +void setLocale(const char* locale); +const char* getLocale(); + +// Look up key in the active locale table; falls back to key itself if not found. +const char* translate(const char* key); + +// Replace $1, $2, ... placeholders with args (in order). +std::string fmt(const char* key, std::initializer_list args); + +// Register a translation table for a locale (called by locale/*.cpp static initializers). +void registerLocale( + const char* locale, + std::initializer_list> entries); + +} // namespace imgui_i18n + +#else // IMGUI_DEMO_ENABLE_I18N not defined + +// Stub: Tr() is a compile-time identity — zero overhead, no dependencies. +#define Tr(s) (s) +#define TrF(s, ...) (s) + +#endif // IMGUI_DEMO_ENABLE_I18N diff --git a/i18n/locale/zh_CN.cpp b/i18n/locale/zh_CN.cpp new file mode 100644 index 000000000000..af48793d0664 --- /dev/null +++ b/i18n/locale/zh_CN.cpp @@ -0,0 +1,834 @@ +// i18n/locale/zh_CN.cpp +// 中文翻译表 —— 按批次追加,static initializer 在 main() 前自动注册 +#include "../imgui_i18n.h" + +namespace { +struct ZhCNRegistrar { + ZhCNRegistrar() { + imgui_i18n::registerLocale("zh_CN", { + // === Step 1: Demo Window + MenuBar === + {"Dear ImGui Demo", "Dear ImGui 演示"}, + {"Configuration", "配置"}, + {"Window options", "窗口选项"}, + {"No titlebar", "无标题栏"}, + {"No scrollbar", "无滚动条"}, + {"No menu", "无菜单"}, + {"No move", "禁止移动"}, + {"No resize", "禁止缩放"}, + {"No collapse", "禁止折叠"}, + {"No close", "无关闭按钮"}, + {"No nav", "无键盘/手柄导航"}, + {"No background", "无背景"}, + {"No bring to front", "不置顶"}, + {"Unsaved document", "未保存标记"}, + {"Widgets", "控件"}, + {"Layout & Scrolling", "布局与滚动"}, + {"Popups & Modal windows", "弹窗与模态框"}, + {"Tables & Columns", "表格与列"}, + {"Inputs & Focus", "输入与焦点"}, + {"Disable All", "全部禁用"}, + {"Disable (section)", "禁用(区域)"}, + {"Menu", "菜单"}, + {"Examples", "示例"}, + {"Main menu bar", "主菜单栏"}, + {"Assets Browser", "资产浏览器"}, + {"Console", "控制台"}, + {"Custom rendering", "自定义渲染"}, + {"Documents", "文档管理"}, + {"Image Viewer", "图片查看器"}, + {"Log", "日志"}, + {"Property editor", "属性编辑器"}, + {"Simple layout", "简单布局"}, + {"Simple overlay", "简单浮层"}, + {"Mini apps", "迷你应用"}, + {"Concepts", "概念演示"}, + {"Auto-resizing window", "自动调整大小的窗口"}, + {"Constrained-resizing window", "约束调整大小的窗口"}, + {"Fullscreen window", "全屏窗口"}, + {"Long text display", "长文本显示"}, + {"Manipulating window titles", "操控窗口标题"}, + {"Tools", "工具"}, + {"Metrics/Debugger", "性能/调试器"}, + {"Debug Options", "调试选项"}, + {"Highlight ID Conflicts", "高亮 ID 冲突"}, + {"Assert on error recovery", "错误恢复时断言"}, + {"(see Demo->Configuration for more)", "(详见 Demo->配置)"}, + {"Debug Log", "调试日志"}, + {"ID Stack Tool", "ID 栈工具"}, + {"Item Picker", "元素拾取器"}, + {"Style Editor", "样式编辑器"}, + {"About Dear ImGui", "关于 Dear ImGui"}, + {"Language", "语言"}, + {"File", "文件"}, + {"New", "新建"}, + {"Open", "打开"}, + {"Open Recent", "最近打开"}, + {"Save", "保存"}, + {"Save As..", "另存为.."}, + {"Export", "导出"}, + {"Quit", "退出"}, + {"Options", "选项"}, + {"Enabled", "已启用"}, + {"Size", "大小"}, + {"Color", "颜色"}, + {"SeparatorText", "分隔文字"}, + {"Dear ImGui Style Editor", "Dear ImGui 样式编辑器"}, + // --- Step 1 补充(Configuration 面板) --- + {"dear imgui says hello! (%s) (%d)", "亲爱的 imgui 向你问好!(%s) (%d)"}, + {"<>", "<<按空格键禁用>>"}, + {"Also see Style->Rendering for rendering options.", "另见 样式->渲染 中的渲染选项。"}, + {"General", "通用"}, + {"Keyboard/Gamepad Navigation", "键盘/手柄导航"}, + {"Windows", "窗口"}, + {"Error Handling", "错误处理"}, + {"Debug", "调试"}, + {"Backend Flags", "后端标志"}, + {"Style, Fonts", "样式与字体"}, + {"Capture/Logging", "截图/日志"}, + {"Copy \"Hello, world!\" to clipboard", "复制 \"Hello, world!\" 到剪贴板"}, + // === Step 2: WidgetsBasic + Bullets + CollapsingHeaders === + {"Basic", "基础"}, + {"Selectable", "可选项"}, + {"Images", "图片"}, + {"Combos", "下拉框"}, + {"Drag and Drop", "拖放"}, + {"Color/Picker Widgets", "颜色/选色控件"}, + {"Multi-component Widgets", "多组件控件"}, + {"Plotting", "绘图"}, + {"Progress Bars", "进度条"}, + {"Text Input", "文本输入"}, + {"Drags and Sliders", "拖拽与滑块"}, + {"Selectables", "可选列表项"}, + {"Tree Nodes", "树节点"}, + {"Collapsing Headers", "折叠标题"}, + {"Tooltips", "提示框"}, + {"Tabs", "标签页"}, + {"Text", "文字"}, + {"List Boxes", "列表框"}, + {"Vertical Sliders", "垂直滑块"}, + {"Filtered Text Input", "过滤文本输入"}, + {"Disable Widgets", "禁用控件"}, + {"Data Types", "数据类型"}, + {"Multi-Select", "多选"}, + {"Bullet Widgets", "项目符号控件"}, + {"Bullet point 1", "项目符号 1"}, + {"Bullet point 2\nOn multiple lines", "项目符号 2\n(多行文本)"}, + {"Button", "按钮"}, + {"Click me", "点击我"}, + {"Clicked!", "已点击!"}, + {"Arrows", "箭头按钮"}, + {"Toggle disabled", "切换禁用"}, + {"Checkbox", "复选框"}, + {"RadioButton", "单选按钮"}, + {"(Disabled)", "(禁用)"}, + {"(Enabled)", "(启用)"}, + {"Hold to repeat:", "长按重复:"}, + {"Press and hold to repeat", "长按重复"}, + {"Right-click on buttons too!", "按钮也支持右键!"}, + {"Hovering over me changes the cursor to an arrow!", "悬停切换为箭头光标!"}, + {"Hovering over me changes the cursor to a hand!", "悬停切换为手形光标!"}, + {"Tooltip when hovering:", "悬停提示:"}, + {"Tooltip always visible:", "始终显示提示:"}, + {"Hold to repeat (filtered)", "长按重复(过滤)"}, + {"Another bullet point", "另一个叶节点"}, + {"Header 1: open by default", "标题 1:默认展开"}, + {"Header 2: do not show a bullet", "标题 2:无项目符号"}, + {"(more empty content)", "(更多空内容)"}, + {"(see Widgets->Selectable for more)", "(详见 控件->可选列表项)"}, + {"Thanks for clicking me!", "感谢点击!"}, + {"checkbox", "复选框"}, + {"radio a", "单选 a"}, + {"radio b", "单选 b"}, + {"radio c", "单选 c"}, + {"Click", "点击"}, + {"Tooltip", "提示"}, + {"I am a tooltip", "我是一个提示框"}, + {"label", "标签"}, + {"Value", "值"}, + {"input text", "输入文本"}, + {"input text (w/ hint)", "输入文本(带提示)"}, + {"enter text here", "在此输入"}, + {"input int", "输入整数"}, + {"input float", "输入浮点数"}, + {"input double", "输入双精度"}, + {"input scientific", "科学计数法输入"}, + {"input float3", "输入 float3"}, + {"drag int", "拖拽整数"}, + {"drag int 0..100", "拖拽整数 0..100"}, + {"drag int wrap 100..200", "拖拽整数环绕 100..200"}, + {"drag float", "拖拽浮点数"}, + {"drag small float", "拖拽小浮点数"}, + {"slider int", "滑块整数"}, + {"slider float", "滑块浮点数"}, + {"slider float (log)", "滑块浮点数(对数)"}, + {"slider angle", "滑块角度"}, + {"slider enum", "滑块枚举"}, + {"color 1", "颜色 1"}, + {"color 2", "颜色 2"}, + {"combo", "下拉框"}, + {"listbox", "列表框"}, + {"Bullets", "项目符号"}, + {"Tree node", "树节点"}, + {"Bullet point 3 (two calls)", "项目符号 3(两次调用)"}, + {"Show 2nd header", "显示第 2 个标题"}, + {"Header", "标题"}, + {"Header with a close button", "带关闭按钮的标题"}, + {"IsItemHovered: %d", "IsItemHovered: %d"}, + {"Some content %d", "部分内容 %d"}, + {"More content %d", "更多内容 %d"}, + {"Inputs", "输入"}, + {"Drags", "拖拽"}, + {"Sliders", "滑块"}, + {"Selectors/Pickers", "选择器/拾色器"}, + // === Step 3: ComboBoxes + ListBoxes + Tabs === + {"Combo", "下拉框"}, + {"One-liner variants", "单行变体"}, + {"Only makes a difference if the popup is larger than the combo", "仅在弹窗比下拉框宽时有效"}, + {"Highlight hovered item in second listbox", "在第二个列表框中高亮悬停项"}, + {"Full-width:", "全宽:"}, + {"This is the Avocado tab!\nblah blah blah blah blah", "这是鳄梨标签页!\n内容内容内容内容内容"}, + {"This is the Broccoli tab!\nblah blah blah blah blah", "这是西兰花标签页!\n内容内容内容内容内容"}, + {"This is the Cucumber tab!\nblah blah blah blah blah", "这是黄瓜标签页!\n内容内容内容内容内容"}, + {"Advanced & Close Button", "高级与关闭按钮"}, + {"Opened:", "已打开:"}, + {"This is the %s tab!", "这是 %s 标签页!"}, + {"I am an odd tab.", "我是一个奇数标签页。"}, + {"TabItemButton & Leading/Trailing flags", "标签按钮与前导/尾随标志"}, + {"Show Leading TabItemButton()", "显示前导标签按钮"}, + {"Show Trailing TabItemButton()", "显示尾随标签按钮"}, + {"Hello!", "你好!"}, + // === Step 4: DragsSliders + DataTypes + VerticalSliders === + {"Drag Int", "拖拽整数"}, + {"Drag Float", "拖拽浮点"}, + {"Drag small float", "拖拽小浮点"}, + {"Slider Int", "整数滑块"}, + {"Slider Float", "浮点滑块"}, + {"Slider angle", "角度滑块"}, + {"Reversed", "反向"}, + {"Clamp On Input", "限制输入范围"}, + {"Round to format", "按格式取整"}, + {"Logarithmic", "对数"}, + {"Whole Numbers", "整数"}, + {"Without border", "无边框"}, + {"With border", "有边框"}, + {"Input", "输入"}, + {"Sliders (DragXXX, SliderXXX)", "拖拽与滑块(DragXXX, SliderXXX)"}, + {"Drag/Slider Flags", "拖拽/滑块标志"}, + {"Underlying float value: %f", "底层浮点值:%f"}, + {"Cannot drop here!", "无法拖放到此处!"}, + {"drag me", "拖动我"}, + {"Clamp integers to 0..50", "将整数限制在 0..50"}, + {"Sliders (reverse)", "反向滑块"}, + {"Show step buttons", "显示步进按钮"}, + {"Misc", "其他"}, + {"Saturation", "饱和度"}, + {"As 0..255", "范围 0..255"}, + // === Step 5: Text + TextFilter + TextInput === + {"Text Display", "文字显示"}, + {"Colored Text", "彩色文字"}, + {"Word Wrapping", "自动换行"}, + {"UTF-8 Text", "UTF-8 文字"}, + {"Single-line text input", "单行文本输入"}, + {"Password input", "密码输入"}, + {"Multi-line text input", "多行文本输入"}, + {"Completion:", "补全:"}, + {"History:", "历史:"}, + {"Info:", "信息:"}, + {"Lock And Scroll", "锁定并滚动"}, + {"Read-only", "只读"}, + {"Resize according to text", "根据文本自动缩放"}, + {"Filtered Input", "过滤输入"}, + {"Misc inputs", "其他输入"}, + {"Upper-case input", "大写输入"}, + {"Filter with a callback", "回调过滤"}, + {"No spaces", "无空格"}, + {"Hexadecimal", "十六进制"}, + {"Scientific", "科学计数"}, + {"Custom", "自定义"}, + {"Password", "密码"}, + {"In a popup", "在弹窗中"}, + {"Pressing ENTER will submit", "按 Enter 提交"}, + {"Multiline", "多行"}, + {"Editable", "可编辑"}, + {"Font Size", "字体大小"}, + // === Step 6: Color/Pickers + Images + Plotting + ProgressBars === + {"Color widget:", "颜色控件:"}, + {"Color widget HSV with Alpha:", "HSV 带透明度:"}, + {"Color widget with Float Display:", "浮点显示颜色:"}, + {"Color button with Custom Picker Popup:", "自定义选色弹窗:"}, + {"my color", "我的颜色"}, + {"Color picker", "颜色选取器"}, + {"Set defaults in code:", "在代码中设置默认值:"}, + {"Both types:", "两种类型:"}, + {"HSV encoded colors", "HSV 编码颜色"}, + {"Color widget with InputHSV:", "InputHSV 颜色控件:"}, + {"Hover the texture for a zoomed view!", "悬停纹理查看放大视图!"}, + {"Image()/ImageWithBg() function", "Image()/ImageWithBg() 函数"}, + {"Interactive Image Viewer", "交互式图片查看器"}, + {"Textured Buttons", "纹理按钮"}, + {"And now some textured buttons..", "以下是一些纹理按钮.."}, + {"Need better plotting and graphing? Consider using ImPlot:", "需要更好的绘图?考虑使用 ImPlot:"}, + {"Animate", "动画"}, + {"Frame Times", "帧时间"}, + {"Histogram", "直方图"}, + {"Functions", "函数"}, + {"Sample count", "采样数"}, + // === Step 7: DragDrop + QueryingStatuses + DisableBlocks === + {"Disable Blocks", "禁用块"}, + {"Disable entire section above", "禁用上方全部控件"}, + {"Demonstrate using BeginDisabled()/EndDisabled() across other sections.", "演示跨区域使用 BeginDisabled()/EndDisabled()。"}, + {"Drag and drop in standard widgets", "在标准控件中拖放"}, + {"You can drag from the color squares.", "可以从颜色方块拖动。"}, + {"Drag and drop to copy/swap items", "拖放以复制/交换项目"}, + {"Copy", "复制"}, + {"Move", "移动"}, + {"Swap", "交换"}, + {"Drag to reorder items (simple)", "拖放重新排序(简单)"}, + {"Tooltip at target location", "目标位置工具提示"}, + {"Drag to re-order", "拖放以重新排序"}, + {"Hold CTRL to copy", "按住 CTRL 复制"}, + {"Querying Item Status (Edited/Active/Hovered etc.)", "查询控件状态(已编辑/激活/悬停等)"}, + {"Querying Window Status (Focused/Hovered etc.)", "查询窗口状态(聚焦/悬停等)"}, + {"Embed everything inside a child window for testing _RootWindow flag.", "将所有内容嵌入子窗口以测试 _RootWindow 标志。"}, + {"Querying Mouse Status", "查询鼠标状态"}, + {"Disabled Widgets", "禁用控件"}, + {"Disable all items", "禁用所有控件"}, + {"First", "第一"}, + {"Second", "第二"}, + {"Third", "第三"}, + {"IsItemHovered()", "IsItemHovered()"}, + {"IsItemActive()", "IsItemActive()"}, + {"IsItemFocused()", "IsItemFocused()"}, + {"IsItemClicked()", "IsItemClicked()"}, + {"IsItemVisible()", "IsItemVisible()"}, + {"IsItemEdited()", "IsItemEdited()"}, + {"IsItemActivated()", "IsItemActivated()"}, + {"IsItemDeactivated()", "IsItemDeactivated()"}, + {"IsItemDeactivatedAfterEdit()", "IsItemDeactivatedAfterEdit()"}, + {"IsItemToggledOpen()", "IsItemToggledOpen()"}, + {"GetItemRectMin()", "GetItemRectMin()"}, + {"GetItemRectMax()", "GetItemRectMax()"}, + {"GetItemRectSize()", "GetItemRectSize()"}, + {"Mouse Cursors", "鼠标光标"}, + {"Display all cursors", "显示所有光标"}, + {"Hovering over them changes the mouse cursor.", "悬停改变光标样式。"}, + + // === Step 8: Selectables + MultiSelect + TreeNodes + Tooltips === + {"1. Direct output", "1. 直接输出"}, + {"2. Checkbox-like behavior", "2. 复选框行为"}, + {"3. Mixed usage", "3. 混合用法"}, + {"4. Full-width selectable, with a custom overlay", "4. 全宽可选项(带覆盖层)"}, + {"5. Rendering more items (150)", "5. 渲染更多项目(150 个)"}, + {"Multiple items on the same line", "同行多项目"}, + {"In Tables", "在表格中"}, + {"Grid", "网格"}, + {"Alignment", "对齐"}, + {"Selection: None", "选中:无"}, + {"(Selection: None)", "(选中:无)"}, + {"Selection State & Multi-Select", "选中状态与多选"}, + {"Single-Select", "单选"}, + {"Multi-Select (manual/simplified, without BeginMultiSelect)", "多选(手动简化版,不使用 BeginMultiSelect)"}, + {"Supported features:", "支持的功能:"}, + {"Added features:", "新增功能:"}, + {"Dynamic list with Delete key support.", "动态列表(支持 Delete 键删除)。"}, + {"Multi-Select (with clipper)", "多选(带裁剪器)"}, + {"Multi-Select (with deletion)", "多选(含删除)"}, + {"Multi-Select (dual list box)", "多选(双列表框)"}, + {"Multi-Select (in a table)", "多选(在表格中)"}, + {"Multi-Select (checkboxes)", "多选(复选框)"}, + {"In a list of checkboxes (not selectable):", "复选框列表(非 Selectable):"}, + {"Using _NoAutoSelect + _NoAutoClear flags.", "使用 _NoAutoSelect + _NoAutoClear 标志。"}, + {"Shift+Click to check multiple boxes.", "Shift+点击 勾选多个框。"}, + {"Shift+Keyboard to copy current value to other boxes.", "Shift+键盘 将当前值复制到其他框。"}, + {"Multi-Select (multiple scopes)", "多选(多作用域)"}, + {"Selection scope", "选中作用域"}, + {"Multi-Select (tiled assets browser)", "多选(平铺资产浏览器)"}, + {"(also access from 'Examples->Assets Browser' in menu)", "(也可从菜单 'Examples->Assets Browser' 进入)"}, + {"Multi-Select (trees)", "多选(树)"}, + {"Selection size: %d", "已选:%d"}, + {"Multi-Select (advanced)", "多选(高级)"}, + {"Tree nodes", "树节点项"}, + {"Enable clipper", "启用裁剪器"}, + {"Enable deletion", "启用删除"}, + {"Enable drag & drop", "启用拖放"}, + {"Show in a table", "显示在表格中"}, + {"Show color button", "显示颜色按钮"}, + {"Dragging %d objects", "正在拖动 %d 个对象"}, + {"Close", "关闭"}, + {"Wiki page:", "Wiki 页面:"}, + {"Multi-select and multiple columns", "多选与多列"}, + {"Multi-select tree", "多选树"}, + {"Multi-select table", "多选表格"}, + {"Use CTRL+Click to select multiple items.", "CTRL+点击 选择多项。"}, + {"Hold SHIFT to select a range.", "SHIFT 选择范围。"}, + {"Basic Trees", "基础树"}, + {"Hierarchy Lines", "层级连线"}, + {"Clipping Large Trees", "裁剪大型树"}, + {"Selectable Nodes", "可选节点"}, + {"Advanced", "高级"}, + {"Parent", "父节点"}, + {"Child 1", "子节点 1"}, + {"Child 2", "子节点 2"}, + {"Button for Child 1", "子节点 1 按钮"}, + {"Button for Child 2", "子节点 2 按钮"}, + {"Remaining contents", "剩余内容"}, + {"blah blah", "内容内容"}, + {"button", "按钮"}, + {"This is a drag and drop source", "这是一个拖放源"}, + {"Blah blah\nBlah Blah", "内容内容\n内容内容"}, + {"", "<节点内容>"}, + {"Align label with current X position", "与当前 X 位置对齐标签"}, + {"Make Tree Nodes as drag & drop sources", "将树节点作为拖放源"}, + {"Basic trees", "基础树"}, + {"Advanced, with Selectable nodes", "高级(带可选节点)"}, + {"Leaf node", "叶节点"}, + {"Child node 0", "子节点 0"}, + {"Child node 1", "子节点 1"}, + {"Fancy", "高级"}, + {"Curve", "曲线"}, + {"Sin(time) = %f", "Sin(时间) = %f"}, + {"Always On", "始终显示"}, + {"Off", "关闭"}, + {"Always On (Simple)", "始终显示(简单)"}, + {"Always On (Advanced)", "始终显示(高级)"}, + {"I am following you around.", "我在跟随你。"}, + {"I am a fancy tooltip", "我是一个高级提示框"}, + {"flags for a specific tooltip instance.", "针对特定提示框实例的标志。"}, + {"Manual", "手动"}, + {"I am a manually emitted tooltip.", "我是手动触发的提示框。"}, + {"DelayNone", "无延迟"}, + {"I am a tooltip with no delay.", "我是一个无延迟的提示框。"}, + {"DelayShort", "短延迟"}, + {"I am a tooltip with a short delay (%0.2f sec).", "我是一个短延迟提示框(%0.2f 秒)。"}, + {"DelayLong", "长延迟"}, + {"I am a tooltip with a long delay (%0.2f sec).", "我是一个长延迟提示框(%0.2f 秒)。"}, + {"Stationary", "静止触发"}, + {"I am a tooltip requiring mouse to be stationary before activating.", "我需要鼠标静止后才会显示。"}, + {"Disabled item", "禁用项"}, + {"I am a tooltip for a disabled item.", "我是禁用项的提示框。"}, + {"Always on", "始终显示"}, + {"Delay", "延迟"}, + {"Programmatic", "程序化"}, + {"Variable delay", "可变延迟"}, + {"Short", "短"}, + {"Long", "长"}, + {"Stationary delay", "静止延迟"}, + {"Scroll to select", "滚动选择"}, + {"Fixed", "固定"}, + {"(close)", "(关闭)"}, + {"(Closed)", "(已关闭)"}, + // === Step 9: Layout === + {"Child windows", "子窗口"}, + {"Disable Mouse Wheel", "禁用鼠标滚轮"}, + {"Disable Menu", "禁用菜单"}, + {"%04d: scrollable region", "%04d: 可滚动区域"}, + {"Manual-resize", "手动调整大小"}, + {"Auto-resize with constraints", "带约束的自动调整大小"}, + {"Lines Count", "行数"}, + {"Max Height (in Lines)", "最大高度(行数)"}, + {"Misc/Advanced", "杂项/高级"}, + {"Offset X", "X 偏移"}, + {"Override ChildBg color", "覆盖子窗口背景色"}, + {"Some test %d", "测试项 %d"}, + {"Hovered: %d", "悬浮: %d"}, + {"Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", "子窗口矩形: (%.0f,%.0f) (%.0f,%.0f)"}, + {"Widgets Width", "控件宽度"}, + {"Show indented items", "显示缩进项"}, + {"SetNextItemWidth/PushItemWidth(100)", "SetNextItemWidth/PushItemWidth(100)"}, + {"Fixed width.", "固定宽度。"}, + {"SetNextItemWidth/PushItemWidth(-100)", "SetNextItemWidth/PushItemWidth(-100)"}, + {"Align to right edge minus 100", "对齐到右边缘减 100"}, + {"SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)", "SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)"}, + {"Half of available width.\n(~ right-cursor_pos)\n(works within a column set)", "可用宽度的一半。\n(~ 右侧光标位置)\n(在列集中有效)"}, + {"SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)", "SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)"}, + {"Align to right edge minus half", "对齐到右边缘减半"}, + {"SetNextItemWidth/PushItemWidth(-FLT_MIN)", "SetNextItemWidth/PushItemWidth(-FLT_MIN)"}, + {"Align to right edge", "对齐到右边缘"}, + {"Basic Horizontal Layout", "基础水平布局"}, + {"(Use ImGui::SameLine() to keep adding items to the right of the preceding item)", "(使用 ImGui::SameLine() 在前一个控件右侧继续添加控件)"}, + {"Two items: Hello", "两个控件: Hello"}, + {"Sailor", "水手"}, + {"More spacing: Hello", "更大间距: Hello"}, + {"Normal buttons", "普通按钮"}, + {"Banana", "香蕉"}, + {"Apple", "苹果"}, + {"Corniflower", "矢车菊"}, + {"Small buttons", "小按钮"}, + {"Like this one", "像这个"}, + {"can fit within a text block.", "可以嵌入文本块中。"}, + {"Aligned", "对齐"}, + {"x=150", "x=150"}, + {"x=300", "x=300"}, + {"My", "我的"}, + {"Tailor", "裁缝"}, + {"Is", "是"}, + {"Rich", "富有的"}, + {"Lists:", "列表:"}, + {"Manual wrapping:", "手动换行:"}, + {"Groups", "分组"}, + {"Text Baseline Alignment", "文字基线对齐"}, + {"Text baseline:", "文字基线:"}, + {"Multi-line text:", "多行文本:"}, + {"Misc items:", "杂项控件:"}, + {"Item %d..", "项目 %d.."}, + {"Scrolling", "滚动"}, + {"Decoration", "装饰"}, + {"Item = %d", "项目 = %d"}, + {"Track", "跟踪"}, + {"+%.0f px", "+%.0f px"}, + {"Scroll Offset", "滚动偏移"}, + {"X/Y = %.0f px", "X/Y = %.0f px"}, + {"Scroll To Pos", "滚动到位置"}, + {"Top", "顶部"}, + {"25%", "25%"}, + {"Center", "居中"}, + {"75%", "75%"}, + {"Bottom", "底部"}, + {"Item %d", "项目 %d"}, + {"%.0f/%.0f", "%.0f/%.0f"}, + {"Left", "左"}, + {"Right", "右"}, + {"%s\n%.0f/%.0f", "%s\n%.0f/%.0f"}, + {"Lines", "行数"}, + {"Scroll from code", "代码控制滚动"}, + {"<<", "<<"}, + {">>", ">>"}, + {"Show Horizontal contents size demo window", "显示水平内容尺寸演示窗口"}, + {"Horizontal contents size demo window", "水平内容尺寸演示窗口"}, + {"Use 'Metrics->Tools->Show windows rectangles' to visualize rectangles.", "使用 'Metrics->Tools->Show windows rectangles' 可视化矩形。"}, + {"H-scrollbar", "水平滚动条"}, + {"Text wrapped", "自动换行文本"}, + {"Columns", "列"}, + {"Tab bar", "标签栏"}, + {"Child", "子窗口"}, + {"Explicit content size", "显式内容尺寸"}, + {"Scroll %.1f/%.1f %.1f/%.1f", "滚动 %.1f/%.1f %.1f/%.1f"}, + {"this is a 300-wide button", "这是一个 300 宽的按钮"}, + {"this is a tree node", "这是一个树节点"}, + {"another one of those tree node...", "另一个树节点..."}, + {"Some tree contents", "树节点内容"}, + {"CollapsingHeader", "折叠标题"}, + {"This text should automatically wrap on the edge of the work rectangle.", "这段文字应在工作区边缘自动换行。"}, + {"Tables:", "表格:"}, + {"Width %.2f", "宽度 %.2f"}, + {"Columns:", "列:"}, + {"Text Clipping", "文字裁剪"}, + {"(Click and drag to scroll)", "(点击并拖拽以滚动)"}, + {"Overlap Mode", "重叠模式"}, + {"Enable AllowOverlap", "启用重叠允许"}, + {"Button 1", "按钮 1"}, + {"Button 2", "按钮 2"}, + {"Some Selectable", "可选项"}, + // === Step 10: Popups + About + UserGuide === + {"Popups", "弹窗"}, + {"Select..", "选择.."}, + {"Right-click here", "在此右键"}, + {"right-click me!", "右键点我!"}, + {"right-click on this text", "右键点击此文字"}, + {"Modal windows", "模态框"}, + {"Delete?", "确认删除?"}, + {"This is a modal window", "这是一个模态框"}, + {"Yes", "是"}, + {"No", "否"}, + {"Stacked modals", "嵌套模态框"}, + {"Open another modal", "打开另一个模态框"}, + {"Popups in a menu", "菜单中的弹窗"}, + {"Menus", "菜单"}, + {"Context menus", "右键菜单"}, + {"Menu in a popup", "弹窗内菜单"}, + {"Popups with window restoring focus", "弹窗恢复焦点"}, + {"Open a popup!", "打开弹窗!"}, + {"Dear ImGui is an immediate mode GUI library for C++.", "Dear ImGui 是一个 C++ 即时模式 GUI 库。"}, + {"License:", "许可证:"}, + {"Build Information:", "构建信息:"}, + {"User Guide", "用户指南"}, + {"PROGRAMMER GUIDE", "程序员指南"}, + {"MOUSE & DRAG AND DROP", "鼠标与拖放"}, + {"KEYBOARD, GAMEPAD & FOCUS", "键盘、手柄与焦点"}, + {"Read 'Programmer Guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase.", "阅读 imgui.cpp 中的《程序员指南》了解集成方法。"}, + {"Understood!", "明白了!"}, + {"Oops, button is disabled!", "按钮已被禁用!"}, + // === Step 11: Tables(前半段)=== + {"Borders, background", "边框与背景"}, + {"Resizable, stretch", "可缩放(拉伸)"}, + {"Resizable, fixed", "可缩放(固定)"}, + {"Resizable, mixed", "可缩放(混合)"}, + {"Sizing policies", "尺寸策略"}, + {"Vertical scrolling, with clipping", "垂直滚动(带裁剪)"}, + {"Horizontal scrolling", "水平滚动"}, + {"Columns flags", "列标志"}, + {"Columns widths", "列宽"}, + {"Nested tables", "嵌套表格"}, + {"Row height", "行高"}, + {"Outer size", "外部尺寸"}, + {"Reorderable, hideable, with headers", "可重排、可隐藏(带表头)"}, + {"Padding", "内边距"}, + {"Disable tree indentation", "禁用树缩进"}, + {"Expand all", "展开全部"}, + {"Collapse all", "折叠全部"}, + {"Display headers", "显示表头"}, + // === Step 11b 预留(Tables 后半段)=== + {"Headers", "表头"}, + {"Row flags", "行标志"}, + {"Reordering", "重排"}, + {"Hiding", "隐藏"}, + {"Sorting", "排序"}, + {"Column types", "列类型"}, + {"Borders", "边框"}, + {"Full headers", "完整表头"}, + {"Foot0", "底部0"}, + {"Foot1", "底部1"}, + {"Foot2", "底部2"}, + {"Seat#", "座位号"}, + {"Age", "年龄"}, + {"Average", "平均"}, + {"Sum", "总计"}, + {"First Name", "名"}, + {"Last Name", "姓"}, + {"Bream", "鲷鱼"}, + {"Haddock", "黑线鳕"}, + {"Mackerel", "鲭鱼"}, + {"Pollock", "鳕鱼"}, + {"Tilefish", "马头鱼"}, + {"Dragonfruit", "火龙果"}, + {"Eggplant", "茄子"}, + {"Fig", "无花果"}, + {"Guava", "番石榴"}, + {"Vertical headers", "垂直表头"}, + {"Custom headers", "自定义表头"}, + {"Row background color", "行背景色"}, + // === Step 11b: Tables 后半段 === + {"Background color", "背景色"}, + {"Tree view", "树形视图"}, + {"Item width", "条目宽度"}, + {"Angled headers", "斜角表头"}, + {"Style settings", "样式设置"}, + {"Synced instances", "同步实例"}, + {"Legacy Columns API", "旧版 Columns API"}, + {"Mixed items", "混合条目"}, + {"Word-wrapping", "自动换行"}, + {"Horizontal Scrolling", "水平滚动"}, + {"Tree", "树形"}, + {"Name", "名称"}, + {"Type", "类型"}, + {"small", "小"}, + {"half", "半"}, + {"right-align", "右对齐"}, + {"Apricot", "杏"}, + {"Cherry", "樱桃"}, + {"One", "一"}, + {"Two", "二"}, + {"Three", "三"}, + {"ID", "ID"}, + {"Action", "操作"}, + {"Quantity", "数量"}, + {"Description", "描述"}, + {"Without border:", "无边框:"}, + {"With border:", "有边框:"}, + {"Path", "路径"}, + {"Hovered", "悬停"}, + {"horizontal", "水平"}, + {"vertical", "垂直"}, + {"Long text that is likely to clip", "很可能被截断的长文本"}, + {"Hello", "你好"}, + {"An extra line here.", "这里额外一行。"}, + {"Category A", "类别 A"}, + {"Category B", "类别 B"}, + {"Category C", "类别 C"}, + {"Blah blah blah", "巴拉巴拉巴拉"}, + {"Node contents", "节点内容"}, + {"Tree in column", "列中的树"}, + {"Even more contents", "更多内容"}, + {"The quick brown fox jumps over the lazy dog", "快速的棕色狐狸跳过了懒狗"}, + // === Step 12: Inputs + Style Editor === + {"This is a simplified view. See more detailed input state:\n- in 'Tools->Metrics/Debugger->Inputs'.\n- in 'Tools->Debug Log->IO'.", "这是简化视图。详细输入状态请查看:\n- 'Tools->Metrics/Debugger->Inputs'\n- 'Tools->Debug Log->IO'"}, + {"Mouse pos: (%g, %g)", "鼠标位置:(%g, %g)"}, + {"Mouse pos: ", "鼠标位置:<无效>"}, + {"Mouse delta: (%g, %g)", "鼠标增量:(%g, %g)"}, + {"Mouse down:", "鼠标按下:"}, + {"Mouse wheel: %.1f", "鼠标滚轮:%.1f"}, + {"Mouse clicked count:", "鼠标点击次数:"}, + {"Keys down:", "按下的键:"}, + {"Keys mods: %s%s%s%s", "修饰键:%s%s%s%s"}, + {"Chars queue:", "字符队列:"}, + {"Outputs", "输出"}, + {"WantCapture override", "捕获覆盖"}, + {"Hovering the colored canvas will override io.WantCaptureXXX fields.\nNotice how normally (when set to none), the value of io.WantCaptureKeyboard would be false when hovering and true when clicking.", "悬停在彩色画布上将覆盖 io.WantCaptureXXX 字段。\n注意通常情况下(设为 none 时),悬停时 io.WantCaptureKeyboard 为 false,点击时为 true。"}, + {"None", "无"}, + {"Set to false", "设为 false"}, + {"Set to true", "设为 true"}, + {"SetNextFrameWantCaptureMouse() on hover", "悬停时调用 SetNextFrameWantCaptureMouse()"}, + {"SetNextFrameWantCaptureKeyboard() on hover", "悬停时调用 SetNextFrameWantCaptureKeyboard()"}, + {"Shortcuts", "快捷键"}, + {"Using SetNextItemShortcut()", "使用 SetNextItemShortcut()"}, + {"Using Shortcut()", "使用 Shortcut()"}, + {"Factor", "系数"}, + {"Press Ctrl+A and see who receives it!", "按 Ctrl+A 查看谁接收到了!"}, + {"Current mouse cursor = %d: %s", "当前鼠标光标 = %d: %s"}, + {"Hover to see mouse cursors:", "悬停查看鼠标光标:"}, + {"Tabbing", "Tab 键导航"}, + {"Use Tab/Shift+Tab to cycle through keyboard editable fields.", "使用 Tab/Shift+Tab 在可编辑字段间切换。"}, + {"Focus from code", "代码设置焦点"}, + {"Focus on 1", "聚焦到 1"}, + {"Focus on 2", "聚焦到 2"}, + {"Focus on 3", "聚焦到 3"}, + {"Focus on X", "聚焦到 X"}, + {"Focus on Y", "聚焦到 Y"}, + {"Focus on Z", "聚焦到 Z"}, + {"Dragging", "拖拽"}, + {"GetMouseDragDelta(0):", "GetMouseDragDelta(0):"}, + // Style Editor + {"For instructions, see:", "使用说明请查看:"}, + {"Save Ref", "保存参考"}, + {"Revert Ref", "还原参考"}, + {"Details", "详细设置"}, + {"Sizes", "尺寸"}, + {"Colors", "颜色"}, + {"Fonts", "字体"}, + {"Rendering", "渲染"}, + {"Only Modified Colors", "仅显示修改的颜色"}, + {"Filter colors", "过滤颜色"}, + {"Opaque", "不透明"}, + {"Alpha", "Alpha"}, + {"Both", "两者"}, + {"Revert", "还原"}, + {"Anti-aliased lines", "抗锯齿线条"}, + {"Anti-aliased lines use texture", "抗锯齿线条使用纹理"}, + {"Anti-aliased fill", "抗锯齿填充"}, + {"Curve Tessellation Tolerance", "曲线细分容差"}, + {"Circle Tessellation Max Error", "圆形细分最大误差"}, + // === Step 13: Example Apps === + {"Example: Main Menu Bar", "示例:主菜单栏"}, + {"Edit", "编辑"}, + {"Undo", "撤销"}, + {"Redo", "重做"}, + {"Cut", "剪切"}, + {"Paste", "粘贴"}, + {"Example: Console", "示例:控制台"}, + {"Command:", "命令:"}, + {"Clear", "清空"}, + {"Scroll to bottom", "滚动到底部"}, + {"Auto-scroll", "自动滚动"}, + {"Enter 'HELP' for help.", "输入 'HELP' 获取帮助。"}, + {"Example: Log", "示例:日志"}, + {"Enable scrolling", "启用自动滚动"}, + {"Add Dummy Text", "添加示例文字"}, + {"Add Dummy Error", "添加示例错误"}, + {"Example: Simple Layout", "示例:简单布局"}, + {"Example: Property editor", "示例:属性编辑器"}, + {"Example: Long text display", "示例:长文本显示"}, + {"Example: Auto-resizing window", "示例:自动缩放窗口"}, + {"Example: Constrained-resizing window", "示例:约束缩放窗口"}, + {"Example: Simple overlay", "示例:简单浮层"}, + {"n/a", "不可用"}, + {"Example: Fullscreen window", "示例:全屏窗口"}, + {"Example: Manipulating window titles", "示例:操控窗口标题"}, + {"Example: Custom rendering", "示例:自定义渲染"}, + {"Example: Documents", "示例:文档管理"}, + {"(Untitled)", "(未命名)"}, + {"Erase", "擦除"}, + {"Stroke", "描边"}, + {"Primitives", "图元"}, + {"BG/FG draw lists", "前/后景绘制列表"}, + {"Mesh", "网格"}, + {"Textures", "纹理"}, + {"Example: Assets Browser", "示例:资产浏览器"}, + {"HELP", "帮助"}, + {"HISTORY", "历史"}, + {"CLEAR", "清空"}, + {"Close Me", "关闭"}, + // Additional strings from Step 13 + {"Use work area instead of main area", "使用工作区而非主区域"}, + {"Close this window", "关闭此窗口"}, + {"This window has a changing title.", "此窗口具有动态标题。"}, + {"Simple overlay\n(right-click to change position)", "简单浮层\n(右键更改位置)"}, + {"Mouse Position: ", "鼠标位置:<无效>"}, + {"(Hold Shift to display a dummy viewport)", "(按住 Shift 显示虚拟视口)"}, + {"Auto-resize", "自动缩放"}, + {"Constraint", "约束"}, + {"Use Clipper", "使用裁剪器"}, + {"Printing unusually long amount of text.", "正在打印超长文本。"}, + {"Test type", "测试类型"}, + {"Gradients", "渐变"}, + {"All primitives", "所有图元"}, + {"Draw in Background draw list", "在背景绘制列表中绘制"}, + {"Draw in Foreground draw list", "在前景绘制列表中绘制"}, + {"Blue shape is drawn first: appears in back", "蓝色形状先绘制:显示在后面"}, + {"Red shape is drawn after: appears in front", "红色形状后绘制:显示在前面"}, + {"Blue shape is drawn first, into channel 1: appears in front", "蓝色形状先绘制到通道1:显示在前面"}, + {"Red shape is drawn after, into channel 0: appears in back", "红色形状后绘制到通道0:显示在后面"}, + {"After reordering, contents of channel 0 appears below channel 1.", "重排后,通道0的内容显示在通道1下方。"}, + {"Close All Documents", "关闭所有文档"}, + {"Rename..", "重命名.."}, + {"Modify", "修改"}, + {"Save change to the following items?", "将更改保存到以下项目?"}, + {"Cancel", "取消"}, + {"Add 10000 items", "添加10000个项目"}, + {"Clear items", "清除项目"}, + {"Delete", "删除"}, + {"Contents", "内容"}, + {"Selection Behavior", "选择行为"}, + {"Layout", "布局"}, + {"Show Type Overlay", "显示类型覆盖"}, + {"Allow Sorting", "允许排序"}, + {"Allow box-selection", "允许框选"}, + {"Allow box-selection from selected items", "允许从已选项目框选"}, + {"Allow dragging unselected item", "允许拖拽未选项目"}, + {"Icon Size", "图标大小"}, + {"Icon Spacing", "图标间距"}, + {"Icon Hit Spacing", "图标命中间距"}, + {"Stretch Spacing", "拉伸间距"}, + {"Use ScrollX", "启用水平滚动"}, + {"%d assets", "%d 个资产"}, + {"Selection: %d items", "已选:%d 个项目"}, + {"Help", "帮助"}, + // === main.mm window === + {"Hello, world!", "你好,世界!"}, + {"This is some useful text.", "这是一段有用的文字。"}, + {"Demo Window", "演示窗口"}, + {"Another Window", "另一个窗口"}, + {"float", "浮点"}, + {"clear color", "背景颜色"}, + {"Button", "按钮"}, + {"counter = %d", "计数器 = %d"}, + {"Application average %.3f ms/frame (%.1f FPS)", "应用程序平均 %.3f 毫秒/帧(%.1f FPS)"}, + {"Hello from another window!", "来自另一个窗口的问候!"}, + {"Close Me", "关闭"}, + // === Help 折叠内容 === + {"ABOUT THIS DEMO:", "关于本演示:"}, + {"Sections below are demonstrating many aspects of the library.", "下方各章节展示了库的众多特性。"}, + {"The \"Examples\" menu above leads to more demo contents.", "上方「示例」菜单包含更多演示内容。"}, + {"The \"Tools\" menu above gives access to: About Box, Style Editor,\nand Metrics/Debugger (general purpose Dear ImGui debugging tool).", "上方「工具」菜单可访问:关于弹窗、样式编辑器\n以及指标/调试器(通用 Dear ImGui 调试工具)。"}, + {"Web demo (w/ source code browser): ", "在线演示(含源码浏览器):"}, + {"PROGRAMMER GUIDE:", "程序员指南:"}, + {"See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!", "参阅 imgui_demo.cpp 中的 ShowDemoWindow() 代码。← 你在这里!"}, + {"See comments in imgui.cpp.", "参阅 imgui.cpp 中的注释。"}, + {"See example applications in the examples/ folder.", "参阅 examples/ 目录下的示例程序。"}, + {"Read the FAQ at ", "阅读 FAQ:"}, + {"Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.", "设置 'io.ConfigFlags |= NavEnableKeyboard' 以启用键盘控制。"}, + {"Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.", "设置 'io.ConfigFlags |= NavEnableGamepad' 以启用手柄控制。"}, + {"USER GUIDE:", "用户指南:"}, + // === Configuration HelpMarker 提示 === + {"Enable keyboard controls.", "启用键盘控制。"}, + {"Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.", "启用手柄控制。需要后端设置 io.BackendFlags |= ImGuiBackendFlags_HasGamepad。\n\n详情请阅读 imgui.cpp 中的说明。"}, + {"Instruct dear imgui to disable mouse inputs and interactions.", "禁止 Dear ImGui 处理鼠标输入和交互。"}, + {"Instruct backend to not alter mouse cursor shape and visibility.", "禁止后端修改鼠标光标形状和可见性。"}, + {"Instruct dear imgui to disable keyboard inputs and interactions.", "禁止 Dear ImGui 处理键盘输入和交互。"}, + {"Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.", "启用输入队列滴流:同一帧内提交的某些事件(如按下+抬起)将分散到多帧处理,改善低帧率下的交互体验。"}, + {"Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).", "让 Dear ImGui 自行渲染鼠标光标。通过 GPU 渲染的软件光标会比硬件光标略有延迟,但与其他画面更同步。\n\n部分桌面应用会同时使用两种光标(如仅在拖拽/缩放时启用软件光标)。"}, + {"Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult", "方向键/Tab 导航会瞬移鼠标光标。在难以移动虚拟鼠标的电视/主机系统上很有用。"}, + {"Pressing Escape clears focused item.", "按 Escape 键清除焦点控件。"}, + {"Pressing Escape clears focused window.", "按 Escape 键清除焦点窗口。"}, + {"Using directional navigation key makes the cursor visible. Mouse click hides the cursor.", "使用方向导航键时显示光标,鼠标点击时隐藏光标。"}, + {"Navigation cursor is always visible.", "导航光标始终可见。"}, + {"Enable resizing of windows from their edges and from the lower-left corner.\nThis requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback.", "允许从窗口边缘和左下角调整大小。\n需要 ImGuiBackendFlags_HasMouseCursors 以获得更好的光标反馈。"}, + {"*EXPERIMENTAL* Ctrl+C copy the contents of focused window into the clipboard.\n\nExperimental because:\n- (1) has known issues with nested Begin/End pairs.\n- (2) text output quality varies.\n- (3) text output is in submission order rather than spatial order.", "*实验性* Ctrl+C 将焦点窗口内容复制到剪贴板。\n\n实验性原因:\n- (1) 嵌套 Begin/End 有已知问题。\n- (2) 文字输出质量不稳定。\n- (3) 输出按提交顺序而非空间顺序排列。"}, + {"Enable scrolling page by page when clicking outside the scrollbar grab.\nWhen disabled, always scroll to clicked location.\nWhen enabled, Shift+Click scrolls to clicked location.", "点击滚动条轨道时逐页滚动。\n禁用时:始终滚动到点击位置。\n启用时:Shift+点击滚动到点击位置。"}, + {"Enable blinking cursor (optional as some users consider it to be distracting).", "启用闪烁光标(部分用户认为会分散注意力,可选)。"}, + {"Pressing Enter will reactivate item and select all text (single-line only).", "按 Enter 键重新激活控件并全选文字(仅单行)。"}, + {"Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving).", "点击 DragXXX 控件后不移动即可切换为文本输入模式。"}, + {"Swap Cmd<>Ctrl keys, enable various MacOS style behaviors.", "交换 Cmd<>Ctrl 键,启用各种 macOS 风格行为。"}, + }); + } +} s_zh_cn; +} // namespace diff --git a/i18n/tools/extract_strings.py b/i18n/tools/extract_strings.py new file mode 100644 index 000000000000..d9f54b0111a7 --- /dev/null +++ b/i18n/tools/extract_strings.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +""" +用法:python3 extract_strings.py imgui_demo.cpp 302 737 +输出 zh_CN.cpp 条目骨架(key=英文,value 留空供人工翻译) +""" +import sys, re + +def extract(path, start, end): + with open(path) as f: + lines = f.readlines() + chunk = ''.join(lines[start-1:end-1]) + strings = re.findall(r'"([^"\n]{2,80})"', chunk) + seen = set() + results = [] + skip = re.compile(r'^(##|###|%[0-9.]*[dfsx]$|[0-9.]+$)') + for s in strings: + if s in seen or skip.match(s): continue + seen.add(s) + results.append(s) + for s in results: + escaped = s.replace('\\', '\\\\').replace('"', '\\"') + print(f' {{"{escaped}", ""}},') + +if __name__ == '__main__': + extract(sys.argv[1], int(sys.argv[2]), int(sys.argv[3])) From 0576c0e3a10de511bf2e64885a7d126954cc2442 Mon Sep 17 00:00:00 2001 From: xuk Date: Mon, 8 Jun 2026 11:22:24 +0800 Subject: [PATCH 02/12] i18n: add Simplified Chinese translation for imgui_demo + Apple Metal example - imgui_demo.cpp: wrap all user-visible string literals with Tr(); add Language menu in DemoWindowMenuBar (guarded by IMGUI_DEMO_ENABLE_I18N); guard extern g_need_font_rebuild with IMGUI_DEMO_ENABLE_I18N + __APPLE__ - examples/example_apple_metal/main.mm: CJK font loading via RebuildFonts() (always loads 2-glyph stub in English, full range in zh_CN); Language menu triggers font atlas rebuild before next NewFrame(); wrap demo window strings with Tr(); fix v1.92 ImplicitRefSize assertion by passing explicit SizePixels to AddFontDefault() - examples/example_apple_metal/Makefile: add i18n sources and -DIMGUI_DEMO_ENABLE_I18N flag --- examples/example_apple_metal/Makefile | 4 +- examples/example_apple_metal/main.mm | 72 +- imgui_demo.cpp | 1414 +++++++++++++------------ 3 files changed, 787 insertions(+), 703 deletions(-) diff --git a/examples/example_apple_metal/Makefile b/examples/example_apple_metal/Makefile index 9412c9b53316..936375871850 100644 --- a/examples/example_apple_metal/Makefile +++ b/examples/example_apple_metal/Makefile @@ -5,8 +5,10 @@ IMGUI_DIR = ../../ SOURCES = main.mm SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp SOURCES += $(IMGUI_DIR)/backends/imgui_impl_osx.mm $(IMGUI_DIR)/backends/imgui_impl_metal.mm +SOURCES += $(IMGUI_DIR)/i18n/imgui_i18n.cpp +SOURCES += $(IMGUI_DIR)/i18n/locale/zh_CN.cpp -CXXFLAGS = -std=c++11 -ObjC++ -fobjc-arc -Wall -Wextra -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends +CXXFLAGS = -std=c++11 -ObjC++ -fobjc-arc -Wall -Wextra -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends -I$(IMGUI_DIR)/i18n -DIMGUI_DEMO_ENABLE_I18N FRAMEWORKS = -framework AppKit -framework Metal -framework MetalKit -framework QuartzCore -framework GameController all: $(EXE) diff --git a/examples/example_apple_metal/main.mm b/examples/example_apple_metal/main.mm index b8edbd2d1f91..01038716babe 100644 --- a/examples/example_apple_metal/main.mm +++ b/examples/example_apple_metal/main.mm @@ -18,6 +18,8 @@ #import #include "imgui.h" +#include "imgui_i18n.h" +#include #include "imgui_impl_metal.h" #if TARGET_OS_OSX #include "imgui_impl_osx.h" @@ -38,6 +40,43 @@ @interface AppViewController () // AppViewController //----------------------------------------------------------------------------------- +bool g_need_font_rebuild = false; + +static void RebuildFonts() +{ + ImGuiIO& io = ImGui::GetIO(); + io.Fonts->ClearFonts(); + // v1.92: must pass explicit SizePixels so base font is not marked ImplicitRefSize, + // otherwise MergeMode on the CJK font triggers an assertion. + ImFontConfig default_cfg; + default_cfg.SizePixels = 13.0f; + io.Fonts->AddFontDefault(&default_cfg); + + // Merge CJK font: + // zh_CN → full common range (~2500 glyphs, renders all translated text) + // English → only "中文" (2 glyphs U+4E2D,U+6587) so Language menu label renders correctly + // Hiragino Sans GB is designed for Simplified Chinese; fall back to STHeiti. + const char* font_paths[] = { + "/System/Library/Fonts/Hiragino Sans GB.ttc", + "/System/Library/Fonts/STHeiti Light.ttc", + nullptr + }; + const char* chosen = nullptr; + for (int i = 0; font_paths[i]; ++i) { + if (access(font_paths[i], R_OK) == 0) { chosen = font_paths[i]; break; } + } + if (chosen) { + static const ImWchar zh_label_ranges[] = { 0x4E2D, 0x4E2D, 0x6587, 0x6587, 0 }; + bool is_zh = (strcmp(imgui_i18n::getLocale(), "zh_CN") == 0); + ImFontConfig cfg; + cfg.MergeMode = true; + cfg.PixelSnapH = true; + io.Fonts->AddFontFromFileTTF(chosen, 13.0f, &cfg, + is_zh ? io.Fonts->GetGlyphRangesChineseSimplifiedCommon() : zh_label_ranges); + } + io.Fonts->Build(); +} + @implementation AppViewController -(instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil @@ -110,6 +149,9 @@ -(void)viewDidLoad ImGui_ImplOSX_Init(self.view); [NSApp activateIgnoringOtherApps:YES]; #endif + + // Build initial font atlas with CJK glyphs so the Language menu renders correctly from the start. + RebuildFonts(); } -(void)drawInMTKView:(MTKView*)view @@ -134,6 +176,12 @@ -(void)drawInMTKView:(MTKView*)view return; } + // 语言切换后重建字体 Atlas(必须在 NewFrame 之前,避免当帧纹理 use-after-free) + if (g_need_font_rebuild) { + g_need_font_rebuild = false; + RebuildFonts(); + } + // Start the Dear ImGui frame ImGui_ImplMetal_NewFrame(renderPassDescriptor); #if TARGET_OS_OSX @@ -155,30 +203,30 @@ -(void)drawInMTKView:(MTKView*)view static float f = 0.0f; static int counter = 0; - ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. + ImGui::Begin(Tr("Hello, world!")); - ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) - ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state - ImGui::Checkbox("Another Window", &show_another_window); + ImGui::Text("%s", Tr("This is some useful text.")); + ImGui::Checkbox(Tr("Demo Window"), &show_demo_window); + ImGui::Checkbox(Tr("Another Window"), &show_another_window); - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f - ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color + ImGui::SliderFloat(Tr("float"), &f, 0.0f, 1.0f); + ImGui::ColorEdit3(Tr("clear color"), (float*)&clear_color); - if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) + if (ImGui::Button(Tr("Button"))) counter++; ImGui::SameLine(); - ImGui::Text("counter = %d", counter); + ImGui::Text(Tr("counter = %d"), counter); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); + ImGui::Text(Tr("Application average %.3f ms/frame (%.1f FPS)"), 1000.0f / io.Framerate, io.Framerate); ImGui::End(); } // 3. Show another simple window. if (show_another_window) { - ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) - ImGui::Text("Hello from another window!"); - if (ImGui::Button("Close Me")) + ImGui::Begin(Tr("Another Window"), &show_another_window); + ImGui::Text("%s", Tr("Hello from another window!")); + if (ImGui::Button(Tr("Close Me"))) show_another_window = false; ImGui::End(); } diff --git a/imgui_demo.cpp b/imgui_demo.cpp index e0bbd9af6ffc..69474c0f0507 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -130,6 +130,14 @@ Index of this file: #endif #include "imgui.h" +// i18n support: opt-in by defining IMGUI_DEMO_ENABLE_I18N in your build. +// When not defined, Tr(s) is a no-op and this header has no dependencies. +#include "i18n/imgui_i18n.h" +#ifdef IMGUI_DEMO_ENABLE_I18N +#if defined(__APPLE__) +extern bool g_need_font_rebuild; // defined in main.mm (Apple Metal example only) +#endif +#endif // IMGUI_DEMO_ENABLE_I18N #ifndef IMGUI_DISABLE // System includes @@ -375,7 +383,7 @@ void ImGui::ShowDemoWindow(bool* p_open) if (demo_data.ShowAbout) { ImGui::ShowAboutWindow(&demo_data.ShowAbout); } if (demo_data.ShowStyleEditor) { - ImGui::Begin("Dear ImGui Style Editor", &demo_data.ShowStyleEditor); + ImGui::Begin(Tr("Dear ImGui Style Editor"), &demo_data.ShowStyleEditor); ImGui::ShowStyleEditor(); ImGui::End(); } @@ -413,7 +421,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver); // Main body of the Demo window starts here. - if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags)) + if (!ImGui::Begin(Tr("Dear ImGui Demo"), p_open, window_flags)) { // Early out if the window is collapsed, as an optimization. ImGui::End(); @@ -437,49 +445,51 @@ void ImGui::ShowDemoWindow(bool* p_open) // Menu Bar DemoWindowMenuBar(&demo_data); - ImGui::Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); + ImGui::Text(Tr("dear imgui says hello! (%s) (%d)"), IMGUI_VERSION, IMGUI_VERSION_NUM); ImGui::Spacing(); - if (ImGui::CollapsingHeader("Help")) + if (ImGui::CollapsingHeader(Tr("Help"))) { IMGUI_DEMO_MARKER("Help"); - ImGui::SeparatorText("ABOUT THIS DEMO:"); - ImGui::BulletText("Sections below are demonstrating many aspects of the library."); - ImGui::BulletText("The \"Examples\" menu above leads to more demo contents."); - ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n" - "and Metrics/Debugger (general purpose Dear ImGui debugging tool)."); - ImGui::BulletText("Web demo (w/ source code browser): "); + ImGui::SeparatorText(Tr("ABOUT THIS DEMO:")); + ImGui::BulletText("%s", Tr("Sections below are demonstrating many aspects of the library.")); + ImGui::BulletText("%s", Tr("The \"Examples\" menu above leads to more demo contents.")); + ImGui::BulletText("%s", Tr("The \"Tools\" menu above gives access to: About Box, Style Editor,\nand Metrics/Debugger (general purpose Dear ImGui debugging tool).")); + ImGui::BulletText("%s", Tr("Web demo (w/ source code browser): ")); ImGui::SameLine(0, 0); ImGui::TextLinkOpenURL("https://pthom.github.io/imgui_explorer"); - ImGui::SeparatorText("PROGRAMMER GUIDE:"); - ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!"); - ImGui::BulletText("See comments in imgui.cpp."); - ImGui::BulletText("See example applications in the examples/ folder."); - ImGui::BulletText("Read the FAQ at "); + ImGui::SeparatorText(Tr("PROGRAMMER GUIDE:")); + ImGui::BulletText("%s", Tr("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!")); + ImGui::BulletText("%s", Tr("See comments in imgui.cpp.")); + ImGui::BulletText("%s", Tr("See example applications in the examples/ folder.")); + ImGui::BulletText("%s", Tr("Read the FAQ at ")); ImGui::SameLine(0, 0); ImGui::TextLinkOpenURL("https://www.dearimgui.com/faq/"); - ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls."); - ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls."); + ImGui::BulletText("%s", Tr("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.")); + ImGui::BulletText("%s", Tr("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.")); - ImGui::SeparatorText("USER GUIDE:"); + ImGui::SeparatorText(Tr("USER GUIDE:")); ImGui::ShowUserGuide(); + } - if (ImGui::CollapsingHeader("Configuration")) + if (ImGui::CollapsingHeader(Tr("Configuration"))) { ImGuiIO& io = ImGui::GetIO(); - if (ImGui::TreeNode("Configuration##2")) + char config_node_label[64]; + snprintf(config_node_label, sizeof(config_node_label), "%s##2", Tr("Configuration")); + if (ImGui::TreeNode(config_node_label)) { IMGUI_DEMO_MARKER("Configuration"); - ImGui::SeparatorText("General"); + ImGui::SeparatorText(Tr("General")); ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); - ImGui::SameLine(); HelpMarker("Enable keyboard controls."); + ImGui::SameLine(); HelpMarker(Tr("Enable keyboard controls.")); ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); - ImGui::SameLine(); HelpMarker("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details."); + ImGui::SameLine(); HelpMarker(Tr("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.")); ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", &io.ConfigFlags, ImGuiConfigFlags_NoMouse); - ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable mouse inputs and interactions."); + ImGui::SameLine(); HelpMarker(Tr("Instruct dear imgui to disable mouse inputs and interactions.")); // The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it: if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) @@ -487,7 +497,7 @@ void ImGui::ShowDemoWindow(bool* p_open) if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f) { ImGui::SameLine(); - ImGui::Text("<>"); + ImGui::Text("%s", Tr("<>")); } // Prevent both being checked if (ImGui::IsKeyPressed(ImGuiKey_Space) || (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard)) @@ -495,51 +505,51 @@ void ImGui::ShowDemoWindow(bool* p_open) } ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", &io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange); - ImGui::SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility."); + ImGui::SameLine(); HelpMarker(Tr("Instruct backend to not alter mouse cursor shape and visibility.")); ImGui::CheckboxFlags("io.ConfigFlags: NoKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NoKeyboard); - ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable keyboard inputs and interactions."); + ImGui::SameLine(); HelpMarker(Tr("Instruct dear imgui to disable keyboard inputs and interactions.")); ImGui::Checkbox("io.ConfigInputTrickleEventQueue", &io.ConfigInputTrickleEventQueue); - ImGui::SameLine(); HelpMarker("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates."); + ImGui::SameLine(); HelpMarker(Tr("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.")); ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); - ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something)."); + ImGui::SameLine(); HelpMarker(Tr("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).")); - ImGui::SeparatorText("Keyboard/Gamepad Navigation"); + ImGui::SeparatorText(Tr("Keyboard/Gamepad Navigation")); ImGui::Checkbox("io.ConfigNavSwapGamepadButtons", &io.ConfigNavSwapGamepadButtons); ImGui::Checkbox("io.ConfigNavMoveSetMousePos", &io.ConfigNavMoveSetMousePos); - ImGui::SameLine(); HelpMarker("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult"); + ImGui::SameLine(); HelpMarker(Tr("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult")); ImGui::Checkbox("io.ConfigNavCaptureKeyboard", &io.ConfigNavCaptureKeyboard); ImGui::Checkbox("io.ConfigNavEscapeClearFocusItem", &io.ConfigNavEscapeClearFocusItem); - ImGui::SameLine(); HelpMarker("Pressing Escape clears focused item."); + ImGui::SameLine(); HelpMarker(Tr("Pressing Escape clears focused item.")); ImGui::Checkbox("io.ConfigNavEscapeClearFocusWindow", &io.ConfigNavEscapeClearFocusWindow); - ImGui::SameLine(); HelpMarker("Pressing Escape clears focused window."); + ImGui::SameLine(); HelpMarker(Tr("Pressing Escape clears focused window.")); ImGui::Checkbox("io.ConfigNavCursorVisibleAuto", &io.ConfigNavCursorVisibleAuto); - ImGui::SameLine(); HelpMarker("Using directional navigation key makes the cursor visible. Mouse click hides the cursor."); + ImGui::SameLine(); HelpMarker(Tr("Using directional navigation key makes the cursor visible. Mouse click hides the cursor.")); ImGui::Checkbox("io.ConfigNavCursorVisibleAlways", &io.ConfigNavCursorVisibleAlways); - ImGui::SameLine(); HelpMarker("Navigation cursor is always visible."); + ImGui::SameLine(); HelpMarker(Tr("Navigation cursor is always visible.")); - ImGui::SeparatorText("Windows"); + ImGui::SeparatorText(Tr("Windows")); ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); - ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback."); + ImGui::SameLine(); HelpMarker(Tr("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback.")); ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly); ImGui::Checkbox("io.ConfigWindowsCopyContentsWithCtrlC", &io.ConfigWindowsCopyContentsWithCtrlC); // [EXPERIMENTAL] - ImGui::SameLine(); HelpMarker("*EXPERIMENTAL* Ctrl+C copy the contents of focused window into the clipboard.\n\nExperimental because:\n- (1) has known issues with nested Begin/End pairs.\n- (2) text output quality varies.\n- (3) text output is in submission order rather than spatial order."); + ImGui::SameLine(); HelpMarker(Tr("*EXPERIMENTAL* Ctrl+C copy the contents of focused window into the clipboard.\n\nExperimental because:\n- (1) has known issues with nested Begin/End pairs.\n- (2) text output quality varies.\n- (3) text output is in submission order rather than spatial order.")); ImGui::Checkbox("io.ConfigScrollbarScrollByPage", &io.ConfigScrollbarScrollByPage); - ImGui::SameLine(); HelpMarker("Enable scrolling page by page when clicking outside the scrollbar grab.\nWhen disabled, always scroll to clicked location.\nWhen enabled, Shift+Click scrolls to clicked location."); + ImGui::SameLine(); HelpMarker(Tr("Enable scrolling page by page when clicking outside the scrollbar grab.\nWhen disabled, always scroll to clicked location.\nWhen enabled, Shift+Click scrolls to clicked location.")); - ImGui::SeparatorText("Widgets"); + ImGui::SeparatorText(Tr("Widgets")); ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); - ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting)."); + ImGui::SameLine(); HelpMarker(Tr("Enable blinking cursor (optional as some users consider it to be distracting).")); ImGui::Checkbox("io.ConfigInputTextEnterKeepActive", &io.ConfigInputTextEnterKeepActive); - ImGui::SameLine(); HelpMarker("Pressing Enter will reactivate item and select all text (single-line only)."); + ImGui::SameLine(); HelpMarker(Tr("Pressing Enter will reactivate item and select all text (single-line only).")); ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText); - ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving)."); + ImGui::SameLine(); HelpMarker(Tr("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving).")); ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors); - ImGui::SameLine(); HelpMarker("Swap Cmd<>Ctrl keys, enable various MacOS style behaviors."); - ImGui::Text("Also see Style->Rendering for rendering options."); + ImGui::SameLine(); HelpMarker(Tr("Swap Cmd<>Ctrl keys, enable various MacOS style behaviors.")); + ImGui::Text("%s", Tr("Also see Style->Rendering for rendering options.")); // Also read: https://github.com/ocornut/imgui/wiki/Error-Handling - ImGui::SeparatorText("Error Handling"); + ImGui::SeparatorText(Tr("Error Handling")); ImGui::Checkbox("io.ConfigErrorRecovery", &io.ConfigErrorRecovery); ImGui::SameLine(); HelpMarker( @@ -556,7 +566,7 @@ void ImGui::ShowDemoWindow(bool* p_open) io.ConfigErrorRecoveryEnableAssert = io.ConfigErrorRecoveryEnableDebugLog = io.ConfigErrorRecoveryEnableTooltip = true; // Also read: https://github.com/ocornut/imgui/wiki/Debug-Tools - ImGui::SeparatorText("Debug"); + ImGui::SeparatorText(Tr("Debug")); ImGui::Checkbox("io.ConfigDebugIsDebuggerPresent", &io.ConfigDebugIsDebuggerPresent); ImGui::SameLine(); HelpMarker("Enable various tools calling IM_DEBUG_BREAK().\n\nRequires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application."); ImGui::Checkbox("io.ConfigDebugHighlightIdConflicts", &io.ConfigDebugHighlightIdConflicts); @@ -576,7 +586,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::Spacing(); } - if (ImGui::TreeNode("Backend Flags")) + if (ImGui::TreeNode(Tr("Backend Flags"))) { IMGUI_DEMO_MARKER("Configuration/Backend Flags"); HelpMarker( @@ -596,17 +606,17 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::Spacing(); } - if (ImGui::TreeNode("Style, Fonts")) + if (ImGui::TreeNode(Tr("Style, Fonts"))) { IMGUI_DEMO_MARKER("Configuration/Style, Fonts"); - ImGui::Checkbox("Style Editor", &demo_data.ShowStyleEditor); + ImGui::Checkbox(Tr("Style Editor"), &demo_data.ShowStyleEditor); ImGui::SameLine(); HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function."); ImGui::TreePop(); ImGui::Spacing(); } - if (ImGui::TreeNode("Capture/Logging")) + if (ImGui::TreeNode(Tr("Capture/Logging"))) { IMGUI_DEMO_MARKER("Configuration/Capture, Logging"); HelpMarker( @@ -616,7 +626,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::LogButtons(); HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output."); - if (ImGui::Button("Copy \"Hello, world!\" to clipboard")) + if (ImGui::Button(Tr("Copy \"Hello, world!\" to clipboard"))) { ImGui::LogToClipboard(); ImGui::LogText("Hello, world!"); @@ -626,22 +636,22 @@ void ImGui::ShowDemoWindow(bool* p_open) } } - if (ImGui::CollapsingHeader("Window options")) + if (ImGui::CollapsingHeader(Tr("Window options"))) { IMGUI_DEMO_MARKER("Window options"); if (ImGui::BeginTable("split", 3)) { - ImGui::TableNextColumn(); ImGui::Checkbox("No titlebar", &no_titlebar); - ImGui::TableNextColumn(); ImGui::Checkbox("No scrollbar", &no_scrollbar); - ImGui::TableNextColumn(); ImGui::Checkbox("No menu", &no_menu); - ImGui::TableNextColumn(); ImGui::Checkbox("No move", &no_move); - ImGui::TableNextColumn(); ImGui::Checkbox("No resize", &no_resize); - ImGui::TableNextColumn(); ImGui::Checkbox("No collapse", &no_collapse); - ImGui::TableNextColumn(); ImGui::Checkbox("No close", &no_close); - ImGui::TableNextColumn(); ImGui::Checkbox("No nav", &no_nav); - ImGui::TableNextColumn(); ImGui::Checkbox("No background", &no_background); - ImGui::TableNextColumn(); ImGui::Checkbox("No bring to front", &no_bring_to_front); - ImGui::TableNextColumn(); ImGui::Checkbox("Unsaved document", &unsaved_document); + ImGui::TableNextColumn(); ImGui::Checkbox(Tr("No titlebar"), &no_titlebar); + ImGui::TableNextColumn(); ImGui::Checkbox(Tr("No scrollbar"), &no_scrollbar); + ImGui::TableNextColumn(); ImGui::Checkbox(Tr("No menu"), &no_menu); + ImGui::TableNextColumn(); ImGui::Checkbox(Tr("No move"), &no_move); + ImGui::TableNextColumn(); ImGui::Checkbox(Tr("No resize"), &no_resize); + ImGui::TableNextColumn(); ImGui::Checkbox(Tr("No collapse"), &no_collapse); + ImGui::TableNextColumn(); ImGui::Checkbox(Tr("No close"), &no_close); + ImGui::TableNextColumn(); ImGui::Checkbox(Tr("No nav"), &no_nav); + ImGui::TableNextColumn(); ImGui::Checkbox(Tr("No background"), &no_background); + ImGui::TableNextColumn(); ImGui::Checkbox(Tr("No bring to front"), &no_bring_to_front); + ImGui::TableNextColumn(); ImGui::Checkbox(Tr("Unsaved document"), &unsaved_document); ImGui::EndTable(); } } @@ -666,39 +676,39 @@ static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data) { if (ImGui::BeginMenuBar()) { - if (ImGui::BeginMenu("Menu")) + if (ImGui::BeginMenu(Tr("Menu"))) { IMGUI_DEMO_MARKER("Menu/File"); ShowExampleMenuFile(); ImGui::EndMenu(); } - if (ImGui::BeginMenu("Examples")) + if (ImGui::BeginMenu(Tr("Examples"))) { IMGUI_DEMO_MARKER("Menu/Examples"); - ImGui::MenuItem("Main menu bar", NULL, &demo_data->ShowMainMenuBar); - - ImGui::SeparatorText("Mini apps"); - ImGui::MenuItem("Assets Browser", NULL, &demo_data->ShowAppAssetsBrowser); - ImGui::MenuItem("Console", NULL, &demo_data->ShowAppConsole); - ImGui::MenuItem("Custom rendering", NULL, &demo_data->ShowAppCustomRendering); - ImGui::MenuItem("Documents", NULL, &demo_data->ShowAppDocuments); - ImGui::MenuItem("Image Viewer", NULL, &demo_data->ShowAppImageViewer); - ImGui::MenuItem("Log", NULL, &demo_data->ShowAppLog); - ImGui::MenuItem("Property editor", NULL, &demo_data->ShowAppPropertyEditor); - ImGui::MenuItem("Simple layout", NULL, &demo_data->ShowAppLayout); - ImGui::MenuItem("Simple overlay", NULL, &demo_data->ShowAppSimpleOverlay); - - ImGui::SeparatorText("Concepts"); - ImGui::MenuItem("Auto-resizing window", NULL, &demo_data->ShowAppAutoResize); - ImGui::MenuItem("Constrained-resizing window", NULL, &demo_data->ShowAppConstrainedResize); - ImGui::MenuItem("Fullscreen window", NULL, &demo_data->ShowAppFullscreen); - ImGui::MenuItem("Long text display", NULL, &demo_data->ShowAppLongText); - ImGui::MenuItem("Manipulating window titles", NULL, &demo_data->ShowAppWindowTitles); + ImGui::MenuItem(Tr("Main menu bar"), NULL, &demo_data->ShowMainMenuBar); + + ImGui::SeparatorText(Tr("Mini apps")); + ImGui::MenuItem(Tr("Assets Browser"), NULL, &demo_data->ShowAppAssetsBrowser); + ImGui::MenuItem(Tr("Console"), NULL, &demo_data->ShowAppConsole); + ImGui::MenuItem(Tr("Custom rendering"), NULL, &demo_data->ShowAppCustomRendering); + ImGui::MenuItem(Tr("Documents"), NULL, &demo_data->ShowAppDocuments); + ImGui::MenuItem(Tr("Image Viewer"), NULL, &demo_data->ShowAppImageViewer); + ImGui::MenuItem(Tr("Log"), NULL, &demo_data->ShowAppLog); + ImGui::MenuItem(Tr("Property editor"), NULL, &demo_data->ShowAppPropertyEditor); + ImGui::MenuItem(Tr("Simple layout"), NULL, &demo_data->ShowAppLayout); + ImGui::MenuItem(Tr("Simple overlay"), NULL, &demo_data->ShowAppSimpleOverlay); + + ImGui::SeparatorText(Tr("Concepts")); + ImGui::MenuItem(Tr("Auto-resizing window"), NULL, &demo_data->ShowAppAutoResize); + ImGui::MenuItem(Tr("Constrained-resizing window"), NULL, &demo_data->ShowAppConstrainedResize); + ImGui::MenuItem(Tr("Fullscreen window"), NULL, &demo_data->ShowAppFullscreen); + ImGui::MenuItem(Tr("Long text display"), NULL, &demo_data->ShowAppLongText); + ImGui::MenuItem(Tr("Manipulating window titles"), NULL, &demo_data->ShowAppWindowTitles); ImGui::EndMenu(); } //if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar! - if (ImGui::BeginMenu("Tools")) + if (ImGui::BeginMenu(Tr("Tools"))) { IMGUI_DEMO_MARKER("Menu/Tools"); ImGuiIO& io = ImGui::GetIO(); @@ -707,28 +717,50 @@ static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data) #else const bool has_debug_tools = false; #endif - ImGui::MenuItem("Metrics/Debugger", NULL, &demo_data->ShowMetrics, has_debug_tools); - if (ImGui::BeginMenu("Debug Options")) + ImGui::MenuItem(Tr("Metrics/Debugger"), NULL, &demo_data->ShowMetrics, has_debug_tools); + if (ImGui::BeginMenu(Tr("Debug Options"))) { ImGui::BeginDisabled(!has_debug_tools); - ImGui::Checkbox("Highlight ID Conflicts", &io.ConfigDebugHighlightIdConflicts); + ImGui::Checkbox(Tr("Highlight ID Conflicts"), &io.ConfigDebugHighlightIdConflicts); ImGui::EndDisabled(); - ImGui::Checkbox("Assert on error recovery", &io.ConfigErrorRecoveryEnableAssert); - ImGui::TextDisabled("(see Demo->Configuration for more)"); + ImGui::Checkbox(Tr("Assert on error recovery"), &io.ConfigErrorRecoveryEnableAssert); + ImGui::TextDisabled("%s", Tr("(see Demo->Configuration for more)")); ImGui::EndMenu(); } - ImGui::MenuItem("Debug Log", NULL, &demo_data->ShowDebugLog, has_debug_tools); - ImGui::MenuItem("ID Stack Tool", NULL, &demo_data->ShowIDStackTool, has_debug_tools); + ImGui::MenuItem(Tr("Debug Log"), NULL, &demo_data->ShowDebugLog, has_debug_tools); + ImGui::MenuItem(Tr("ID Stack Tool"), NULL, &demo_data->ShowIDStackTool, has_debug_tools); bool is_debugger_present = io.ConfigDebugIsDebuggerPresent; - if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools))// && is_debugger_present)) + if (ImGui::MenuItem(Tr("Item Picker"), NULL, false, has_debug_tools))// && is_debugger_present)) ImGui::DebugStartItemPicker(); if (!is_debugger_present) ImGui::SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable some extra features to avoid casual users crashing the application."); - ImGui::MenuItem("Style Editor", NULL, &demo_data->ShowStyleEditor); - ImGui::MenuItem("About Dear ImGui", NULL, &demo_data->ShowAbout); + ImGui::MenuItem(Tr("Style Editor"), NULL, &demo_data->ShowStyleEditor); + ImGui::MenuItem(Tr("About Dear ImGui"), NULL, &demo_data->ShowAbout); ImGui::EndMenu(); } +#ifdef IMGUI_DEMO_ENABLE_I18N + if (ImGui::BeginMenu(Tr("Language"))) + { + bool is_en = (imgui_i18n::getLocale()[0] == '\0'); + bool is_zh = (strcmp(imgui_i18n::getLocale(), "zh_CN") == 0); + if (ImGui::MenuItem("English", nullptr, is_en) && !is_en) + { + imgui_i18n::setLocale(""); +#if defined(__APPLE__) + g_need_font_rebuild = true; +#endif + } + if (ImGui::MenuItem("\xe4\xb8\xad\xe6\x96\x87", nullptr, is_zh) && !is_zh) + { + imgui_i18n::setLocale("zh_CN"); +#if defined(__APPLE__) + g_need_font_rebuild = true; +#endif + } + ImGui::EndMenu(); + } +#endif // IMGUI_DEMO_ENABLE_I18N ImGui::EndMenuBar(); } } @@ -918,30 +950,30 @@ static void ExampleImageViewer_DrawCanvas(ExampleImageViewerData* data, ImVec2 c static void DemoWindowWidgetsBasic() { - if (ImGui::TreeNode("Basic")) + if (ImGui::TreeNode(Tr("Basic"))) { IMGUI_DEMO_MARKER("Widgets/Basic"); - ImGui::SeparatorText("General"); + ImGui::SeparatorText(Tr("General")); IMGUI_DEMO_MARKER("Widgets/Basic/Button"); static int clicked = 0; - if (ImGui::Button("Button")) + if (ImGui::Button(Tr("Button"))) clicked++; if (clicked & 1) { ImGui::SameLine(); - ImGui::Text("Thanks for clicking me!"); + ImGui::Text("%s", Tr("Thanks for clicking me!")); } IMGUI_DEMO_MARKER("Widgets/Basic/Checkbox"); static bool check = true; - ImGui::Checkbox("checkbox", &check); + ImGui::Checkbox(Tr("checkbox"), &check); IMGUI_DEMO_MARKER("Widgets/Basic/RadioButton"); static int e = 0; - ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine(); - ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine(); - ImGui::RadioButton("radio c", &e, 2); + ImGui::RadioButton(Tr("radio a"), &e, 0); ImGui::SameLine(); + ImGui::RadioButton(Tr("radio b"), &e, 1); ImGui::SameLine(); + ImGui::RadioButton(Tr("radio c"), &e, 2); ImGui::AlignTextToFramePadding(); ImGui::TextLinkOpenURL("Hyperlink", "https://github.com/ocornut/imgui/wiki/Error-Handling"); @@ -956,7 +988,7 @@ static void DemoWindowWidgetsBasic() ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f)); ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f)); - ImGui::Button("Click"); + ImGui::Button(Tr("Click")); ImGui::PopStyleColor(3); ImGui::PopID(); } @@ -965,7 +997,7 @@ static void DemoWindowWidgetsBasic() // (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!) // See 'Demo->Layout->Text Baseline Alignment' for details. ImGui::AlignTextToFramePadding(); - ImGui::Text("Hold to repeat:"); + ImGui::Text("%s", Tr("Hold to repeat:")); ImGui::SameLine(); // Arrow buttons with Repeater @@ -980,12 +1012,12 @@ static void DemoWindowWidgetsBasic() ImGui::SameLine(); ImGui::Text("%d", counter); - ImGui::Button("Tooltip"); - ImGui::SetItemTooltip("I am a tooltip"); + ImGui::Button(Tr("Tooltip")); + ImGui::SetItemTooltip("%s", Tr("I am a tooltip")); - ImGui::LabelText("label", "Value"); + ImGui::LabelText(Tr("label"), Tr("Value")); - ImGui::SeparatorText("Inputs"); + ImGui::SeparatorText(Tr("Inputs")); { // If you want to use InputText() with std::string or any custom dynamic string type: @@ -993,7 +1025,7 @@ static void DemoWindowWidgetsBasic() // - Otherwise, see the 'Dear ImGui Demo->Widgets->Text Input->Resize Callback' for using ImGuiInputTextFlags_CallbackResize. IMGUI_DEMO_MARKER("Widgets/Basic/InputText"); static char str0[128] = "Hello, world!"; - ImGui::InputText("input text", str0, IM_COUNTOF(str0)); + ImGui::InputText(Tr("input text"), str0, IM_COUNTOF(str0)); ImGui::SameLine(); HelpMarker( "USER:\n" "Hold Shift or use mouse to select text.\n" @@ -1008,62 +1040,62 @@ static void DemoWindowWidgetsBasic() "in imgui_demo.cpp)."); static char str1[128] = ""; - ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_COUNTOF(str1)); + ImGui::InputTextWithHint(Tr("input text (w/ hint)"), Tr("enter text here"), str1, IM_COUNTOF(str1)); IMGUI_DEMO_MARKER("Widgets/Basic/InputInt, InputFloat"); static int i0 = 123; - ImGui::InputInt("input int", &i0); + ImGui::InputInt(Tr("input int"), &i0); static float f0 = 0.001f; - ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f"); + ImGui::InputFloat(Tr("input float"), &f0, 0.01f, 1.0f, "%.3f"); static double d0 = 999999.00000001; - ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f"); + ImGui::InputDouble(Tr("input double"), &d0, 0.01f, 1.0f, "%.8f"); static float f1 = 1.e10f; - ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e"); + ImGui::InputFloat(Tr("input scientific"), &f1, 0.0f, 0.0f, "%e"); ImGui::SameLine(); HelpMarker( "You can input value using the scientific notation,\n" " e.g. \"1e+8\" becomes \"100000000\"."); static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; - ImGui::InputFloat3("input float3", vec4a); + ImGui::InputFloat3(Tr("input float3"), vec4a); } - ImGui::SeparatorText("Drags"); + ImGui::SeparatorText(Tr("Drags")); { IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat"); static int i1 = 50, i2 = 42, i3 = 128; - ImGui::DragInt("drag int", &i1, 1); + ImGui::DragInt(Tr("drag int"), &i1, 1); ImGui::SameLine(); HelpMarker( "Click and drag to edit value.\n" "Hold Shift/Alt for faster/slower edit.\n" "Double-Click or Ctrl+Click to input value."); - ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp); - ImGui::DragInt("drag int wrap 100..200", &i3, 1, 100, 200, "%d", ImGuiSliderFlags_WrapAround); + ImGui::DragInt(Tr("drag int 0..100"), &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp); + ImGui::DragInt(Tr("drag int wrap 100..200"), &i3, 1, 100, 200, "%d", ImGuiSliderFlags_WrapAround); static float f1 = 1.00f, f2 = 0.0067f; - ImGui::DragFloat("drag float", &f1, 0.005f); - ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); + ImGui::DragFloat(Tr("drag float"), &f1, 0.005f); + ImGui::DragFloat(Tr("drag small float"), &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); //ImGui::DragFloat("drag wrap -1..1", &f3, 0.005f, -1.0f, 1.0f, NULL, ImGuiSliderFlags_WrapAround); } - ImGui::SeparatorText("Sliders"); + ImGui::SeparatorText(Tr("Sliders")); { IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat"); static int i1 = 0; - ImGui::SliderInt("slider int", &i1, -1, 3); + ImGui::SliderInt(Tr("slider int"), &i1, -1, 3); ImGui::SameLine(); HelpMarker("Ctrl+Click to input value."); static float f1 = 0.123f, f2 = 0.0f; - ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f"); - ImGui::SliderFloat("slider float (log)", &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic); + ImGui::SliderFloat(Tr("slider float"), &f1, 0.0f, 1.0f, "ratio = %.3f"); + ImGui::SliderFloat(Tr("slider float (log)"), &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic); IMGUI_DEMO_MARKER("Widgets/Basic/SliderAngle"); static float angle = 0.0f; - ImGui::SliderAngle("slider angle", &angle); + ImGui::SliderAngle(Tr("slider angle"), &angle); // Using the format string to display a name instead of an integer. // Here we completely omit '%d' from the format string, so it'll only display a name. @@ -1073,24 +1105,24 @@ static void DemoWindowWidgetsBasic() static int elem = Element_Fire; const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" }; const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown"; - ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name); // Use ImGuiSliderFlags_NoInput flag to disable Ctrl+Click here. + ImGui::SliderInt(Tr("slider enum"), &elem, 0, Element_COUNT - 1, elem_name); // Use ImGuiSliderFlags_NoInput flag to disable Ctrl+Click here. ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer."); } - ImGui::SeparatorText("Selectors/Pickers"); + ImGui::SeparatorText(Tr("Selectors/Pickers")); { IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4"); static float col1[3] = { 1.0f, 0.0f, 0.2f }; static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; - ImGui::ColorEdit3("color 1", col1); + ImGui::ColorEdit3(Tr("color 1"), col1); ImGui::SameLine(); HelpMarker( "Click on the color square to open a color picker.\n" "Click and hold to use drag and drop.\n" "Right-Click on the color square to show options.\n" "Ctrl+Click on individual component to input value.\n"); - ImGui::ColorEdit4("color 2", col2); + ImGui::ColorEdit4(Tr("color 2"), col2); } { @@ -1099,7 +1131,7 @@ static void DemoWindowWidgetsBasic() IMGUI_DEMO_MARKER("Widgets/Basic/Combo"); const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" }; static int item_current = 0; - ImGui::Combo("combo", &item_current, items, IM_COUNTOF(items)); + ImGui::Combo(Tr("combo"), &item_current, items, IM_COUNTOF(items)); ImGui::SameLine(); HelpMarker( "Using the simplified one-liner Combo API here.\n" "Refer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API."); @@ -1111,7 +1143,7 @@ static void DemoWindowWidgetsBasic() IMGUI_DEMO_MARKER("Widgets/Basic/ListBox"); const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; static int item_current = 1; - ImGui::ListBox("listbox", &item_current, items, IM_COUNTOF(items), 4); + ImGui::ListBox(Tr("listbox"), &item_current, items, IM_COUNTOF(items), 4); ImGui::SameLine(); HelpMarker( "Using the simplified one-liner ListBox API here.\n" "Refer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API."); @@ -1133,18 +1165,18 @@ static void DemoWindowWidgetsBasic() static void DemoWindowWidgetsBullets() { - if (ImGui::TreeNode("Bullets")) + if (ImGui::TreeNode(Tr("Bullets"))) { IMGUI_DEMO_MARKER("Widgets/Bullets"); - ImGui::BulletText("Bullet point 1"); - ImGui::BulletText("Bullet point 2\nOn multiple lines"); - if (ImGui::TreeNode("Tree node")) + ImGui::BulletText("%s", Tr("Bullet point 1")); + ImGui::BulletText("%s", Tr("Bullet point 2\nOn multiple lines")); + if (ImGui::TreeNode(Tr("Tree node"))) { - ImGui::BulletText("Another bullet point"); + ImGui::BulletText("%s", Tr("Another bullet point")); ImGui::TreePop(); } - ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)"); - ImGui::Bullet(); ImGui::SmallButton("Button"); + ImGui::Bullet(); ImGui::Text("%s", Tr("Bullet point 3 (two calls)")); + ImGui::Bullet(); ImGui::SmallButton(Tr("Button")); ImGui::TreePop(); } } @@ -1155,22 +1187,22 @@ static void DemoWindowWidgetsBullets() static void DemoWindowWidgetsCollapsingHeaders() { - if (ImGui::TreeNode("Collapsing Headers")) + if (ImGui::TreeNode(Tr("Collapsing Headers"))) { IMGUI_DEMO_MARKER("Widgets/Collapsing Headers"); static bool closable_group = true; - ImGui::Checkbox("Show 2nd header", &closable_group); - if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None)) + ImGui::Checkbox(Tr("Show 2nd header"), &closable_group); + if (ImGui::CollapsingHeader(Tr("Header"), ImGuiTreeNodeFlags_None)) { - ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); + ImGui::Text(Tr("IsItemHovered: %d"), ImGui::IsItemHovered()); for (int i = 0; i < 5; i++) - ImGui::Text("Some content %d", i); + ImGui::Text(Tr("Some content %d"), i); } - if (ImGui::CollapsingHeader("Header with a close button", &closable_group)) + if (ImGui::CollapsingHeader(Tr("Header with a close button"), &closable_group)) { - ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); + ImGui::Text(Tr("IsItemHovered: %d"), ImGui::IsItemHovered()); for (int i = 0; i < 5; i++) - ImGui::Text("More content %d", i); + ImGui::Text(Tr("More content %d"), i); } /* if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet)) @@ -1186,7 +1218,7 @@ static void DemoWindowWidgetsCollapsingHeaders() static void DemoWindowWidgetsColorAndPickers() { - if (ImGui::TreeNode("Color/Picker Widgets")) + if (ImGui::TreeNode(Tr("Color/Picker Widgets"))) { IMGUI_DEMO_MARKER("Widgets/Color"); static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f); @@ -1204,18 +1236,18 @@ static void DemoWindowWidgetsColorAndPickers() IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit"); ImGui::SeparatorText("Inline color editor"); - ImGui::Text("Color widget:"); + ImGui::Text("%s", Tr("Color widget:")); ImGui::SameLine(); HelpMarker( "Click on the color square to open a color picker.\n" "Ctrl+Click on individual component to input value.\n"); ImGui::ColorEdit3("MyColor##1", (float*)&color, base_flags); IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)"); - ImGui::Text("Color widget HSV with Alpha:"); + ImGui::Text("%s", Tr("Color widget HSV with Alpha:")); ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | base_flags); IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)"); - ImGui::Text("Color widget with Float Display:"); + ImGui::Text("%s", Tr("Color widget with Float Display:")); ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | base_flags); IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)"); @@ -1227,7 +1259,7 @@ static void DemoWindowWidgetsColorAndPickers() ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | base_flags); IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)"); - ImGui::Text("Color button with Custom Picker Popup:"); + ImGui::Text("%s", Tr("Color button with Custom Picker Popup:")); // Generate a default palette. The palette will persist and can be edited. static bool saved_palette_init = true; @@ -1254,19 +1286,19 @@ static void DemoWindowWidgetsColorAndPickers() } if (ImGui::BeginPopup("mypicker")) { - ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!"); + ImGui::Text("%s", "MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!"); ImGui::Separator(); ImGui::ColorPicker4("##picker", (float*)&color, base_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview); ImGui::SameLine(); ImGui::BeginGroup(); // Lock X position - ImGui::Text("Current"); + ImGui::Text("%s", "Current"); ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)); - ImGui::Text("Previous"); + ImGui::Text("%s", "Previous"); if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40))) color = backup_color; ImGui::Separator(); - ImGui::Text("Palette"); + ImGui::Text("%s", "Palette"); for (int n = 0; n < IM_COUNTOF(saved_palette); n++) { ImGui::PushID(n); @@ -1301,7 +1333,7 @@ static void DemoWindowWidgetsColorAndPickers() ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, base_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80)); IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker"); - ImGui::SeparatorText("Color picker"); + ImGui::SeparatorText(Tr("Color picker")); static bool ref_color = false; static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f); @@ -1342,7 +1374,7 @@ static void DemoWindowWidgetsColorAndPickers() if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex; ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL); - ImGui::Text("Set defaults in code:"); + ImGui::Text("%s", Tr("Set defaults in code:")); ImGui::SameLine(); HelpMarker( "SetColorEditOptions() is designed to allow you to set boot-time default.\n" "We don't have Push/Pop functions because you can force options on a per-widget basis if needed, " @@ -1355,7 +1387,7 @@ static void DemoWindowWidgetsColorAndPickers() // Always display a small version of both types of pickers // (that's in order to make it more visible in the demo to people who are skimming quickly through it) - ImGui::Text("Both types:"); + ImGui::Text("%s", Tr("Both types:")); float w = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.y) * 0.40f; ImGui::SetNextItemWidth(w); ImGui::ColorPicker3("##MyColor##5", (float*)&color, ImGuiColorEditFlags_PickerHueBar | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha); @@ -1367,12 +1399,12 @@ static void DemoWindowWidgetsColorAndPickers() // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0) static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV! ImGui::Spacing(); - ImGui::Text("HSV encoded colors"); + ImGui::Text("%s", Tr("HSV encoded colors")); ImGui::SameLine(); HelpMarker( "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV " "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the " "added benefit that you can manipulate hue values with the picker even when saturation or value are zero."); - ImGui::Text("Color widget with InputHSV:"); + ImGui::Text("%s", Tr("Color widget with InputHSV:")); ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f); @@ -1387,14 +1419,14 @@ static void DemoWindowWidgetsColorAndPickers() static void DemoWindowWidgetsComboBoxes() { - if (ImGui::TreeNode("Combo")) + if (ImGui::TreeNode(Tr("Combo"))) { IMGUI_DEMO_MARKER("Widgets/Combo"); // Combo Boxes are also called "Dropdown" in other systems // Expose flags as checkbox for the demo static ImGuiComboFlags flags = 0; ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", &flags, ImGuiComboFlags_PopupAlignLeft); - ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo"); + ImGui::SameLine(); HelpMarker(Tr("Only makes a difference if the popup is larger than the combo")); if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", &flags, ImGuiComboFlags_NoArrowButton)) flags &= ~ImGuiComboFlags_NoPreview; // Clear incompatible flags if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", &flags, ImGuiComboFlags_NoPreview)) @@ -1457,7 +1489,7 @@ static void DemoWindowWidgetsComboBoxes() } ImGui::Spacing(); - ImGui::SeparatorText("One-liner variants"); + ImGui::SeparatorText(Tr("One-liner variants")); HelpMarker("The Combo() function is not greatly useful apart from cases were you want to embed all options in a single strings.\nFlags above don't apply to this section."); // Simplified one-liner Combo() API, using values packed in a single constant string @@ -1484,7 +1516,7 @@ static void DemoWindowWidgetsComboBoxes() static void DemoWindowWidgetsDataTypes() { - if (ImGui::TreeNode("Data Types")) + if (ImGui::TreeNode(Tr("Data Types"))) { IMGUI_DEMO_MARKER("Widgets/Data Types"); // DragScalar/InputScalar/SliderScalar functions allow various data types @@ -1535,8 +1567,8 @@ static void DemoWindowWidgetsDataTypes() const float drag_speed = 0.2f; static bool drag_clamp = false; IMGUI_DEMO_MARKER("Widgets/Data Types/Drags"); - ImGui::SeparatorText("Drags"); - ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp); + ImGui::SeparatorText(Tr("Drags")); + ImGui::Checkbox(Tr("Clamp integers to 0..50"), &drag_clamp); ImGui::SameLine(); HelpMarker( "As with every widget in dear imgui, we never modify values unless there is a user interaction.\n" "You can override the clamping limits by using Ctrl+Click to input a value."); @@ -1555,7 +1587,7 @@ static void DemoWindowWidgetsDataTypes() ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic); IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders"); - ImGui::SeparatorText("Sliders"); + ImGui::SeparatorText(Tr("Sliders")); ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d"); ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u"); ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d"); @@ -1580,7 +1612,7 @@ static void DemoWindowWidgetsDataTypes() ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiSliderFlags_Logarithmic); ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams"); - ImGui::SeparatorText("Sliders (reverse)"); + ImGui::SeparatorText(Tr("Sliders (reverse)")); ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d"); ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u"); ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d"); @@ -1591,8 +1623,8 @@ static void DemoWindowWidgetsDataTypes() IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs"); static bool inputs_step = true; static ImGuiInputTextFlags flags = ImGuiInputTextFlags_None; - ImGui::SeparatorText("Inputs"); - ImGui::Checkbox("Show step buttons", &inputs_step); + ImGui::SeparatorText(Tr("Inputs")); + ImGui::Checkbox(Tr("Show step buttons"), &inputs_step); ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly); ImGui::CheckboxFlags("ImGuiInputTextFlags_ParseEmptyRefVal", &flags, ImGuiInputTextFlags_ParseEmptyRefVal); ImGui::CheckboxFlags("ImGuiInputTextFlags_DisplayEmptyRefVal", &flags, ImGuiInputTextFlags_DisplayEmptyRefVal); @@ -1619,11 +1651,11 @@ static void DemoWindowWidgetsDataTypes() static void DemoWindowWidgetsDisableBlocks(ImGuiDemoWindowData* demo_data) { - if (ImGui::TreeNode("Disable Blocks")) + if (ImGui::TreeNode(Tr("Disable Blocks"))) { IMGUI_DEMO_MARKER("Widgets/Disable Blocks"); - ImGui::Checkbox("Disable entire section above", &demo_data->DisableSections); - ImGui::SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across other sections."); + ImGui::Checkbox(Tr("Disable entire section above"), &demo_data->DisableSections); + ImGui::SameLine(); HelpMarker(Tr("Demonstrate using BeginDisabled()/EndDisabled() across other sections.")); ImGui::TreePop(); } } @@ -1634,17 +1666,17 @@ static void DemoWindowWidgetsDisableBlocks(ImGuiDemoWindowData* demo_data) static void DemoWindowWidgetsDragAndDrop() { - if (ImGui::TreeNode("Drag and Drop")) + if (ImGui::TreeNode(Tr("Drag and Drop"))) { IMGUI_DEMO_MARKER("Widgets/Drag and drop"); - if (ImGui::TreeNode("Drag and drop in standard widgets")) + if (ImGui::TreeNode(Tr("Drag and drop in standard widgets"))) { IMGUI_DEMO_MARKER("Widgets/Drag and drop/Standard widgets"); // ColorEdit widgets automatically act as drag source and drag target. // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F // to allow your own widgets to use colors in their drag and drop interaction. // Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo. - HelpMarker("You can drag from the color squares."); + HelpMarker(Tr("You can drag from the color squares.")); static float col1[3] = { 1.0f, 0.0f, 0.2f }; static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; ImGui::ColorEdit3("color 1", col1); @@ -1652,7 +1684,7 @@ static void DemoWindowWidgetsDragAndDrop() ImGui::TreePop(); } - if (ImGui::TreeNode("Drag and drop to copy/swap items")) + if (ImGui::TreeNode(Tr("Drag and drop to copy/swap items"))) { IMGUI_DEMO_MARKER("Widgets/Drag and drop/Copy-swap items"); enum Mode @@ -1662,9 +1694,9 @@ static void DemoWindowWidgetsDragAndDrop() Mode_Swap }; static int mode = 0; - if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine(); - if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine(); - if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; } + if (ImGui::RadioButton(Tr("Copy"), mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine(); + if (ImGui::RadioButton(Tr("Move"), mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine(); + if (ImGui::RadioButton(Tr("Swap"), mode == Mode_Swap)) { mode = Mode_Swap; } static const char* names[9] = { "Bobby", "Beatrice", "Betty", @@ -1720,7 +1752,7 @@ static void DemoWindowWidgetsDragAndDrop() ImGui::TreePop(); } - if (ImGui::TreeNode("Drag to reorder items (simple)")) + if (ImGui::TreeNode(Tr("Drag to reorder items (simple)"))) { IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)"); // FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be submitting twice. @@ -1754,7 +1786,7 @@ static void DemoWindowWidgetsDragAndDrop() ImGui::TreePop(); } - if (ImGui::TreeNode("Tooltip at target location")) + if (ImGui::TreeNode(Tr("Tooltip at target location"))) { IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Tooltip at target location"); for (int n = 0; n < 2; n++) @@ -1768,7 +1800,7 @@ static void DemoWindowWidgetsDragAndDrop() { IM_UNUSED(payload); ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed); - ImGui::SetTooltip("Cannot drop here!"); + ImGui::SetTooltip("%s", Tr("Cannot drop here!")); } ImGui::EndDragDropTarget(); } @@ -1776,7 +1808,7 @@ static void DemoWindowWidgetsDragAndDrop() // Drop source static ImVec4 col4 = { 1.0f, 0.0f, 0.2f, 1.0f }; if (n == 0) - ImGui::ColorButton("drag me", col4); + ImGui::ColorButton(Tr("drag me"), col4); } ImGui::TreePop(); @@ -1792,7 +1824,7 @@ static void DemoWindowWidgetsDragAndDrop() static void DemoWindowWidgetsDragsAndSliders() { - if (ImGui::TreeNode("Drag/Slider Flags")) + if (ImGui::TreeNode(Tr("Drag/Slider Flags"))) { IMGUI_DEMO_MARKER("Widgets/Drag and Slider Flags"); // Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same! @@ -1818,7 +1850,7 @@ static void DemoWindowWidgetsDragsAndSliders() static float drag_f = 0.5f; static float drag_f4[4]; static int drag_i = 50; - ImGui::Text("Underlying float value: %f", drag_f); + ImGui::Text(Tr("Underlying float value: %f"), drag_f); ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", flags); ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags); ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags); @@ -1833,7 +1865,7 @@ static void DemoWindowWidgetsDragsAndSliders() static float slider_f4[4]; static int slider_i = 50; const ImGuiSliderFlags flags_for_sliders = (flags & ~ImGuiSliderFlags_WrapAround); - ImGui::Text("Underlying float value: %f", slider_f); + ImGui::Text(Tr("Underlying float value: %f"), slider_f); ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags_for_sliders); ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags_for_sliders); ImGui::SliderFloat4("SliderFloat4 (0 -> 1)", slider_f4, 0.0f, 1.0f, "%.3f", flags); // Multi-component item, mostly here to document the effect of ImGuiSliderFlags_ColorMarkers. @@ -1848,7 +1880,7 @@ static void DemoWindowWidgetsDragsAndSliders() static void DemoWindowWidgetsFonts() { - if (ImGui::TreeNode("Fonts")) + if (ImGui::TreeNode(Tr("Fonts"))) { IMGUI_DEMO_MARKER("Widgets/Fonts"); ImFontAtlas* atlas = ImGui::GetIO().Fonts; @@ -1864,7 +1896,7 @@ static void DemoWindowWidgetsFonts() static void DemoWindowWidgetsImages() { - if (ImGui::TreeNode("Images")) + if (ImGui::TreeNode(Tr("Images"))) { IMGUI_DEMO_MARKER("Widgets/Images"); ImGuiIO& io = ImGui::GetIO(); @@ -1896,7 +1928,7 @@ static void DemoWindowWidgetsImages() ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h); // Basic drawing - ImGui::SeparatorText("Image()/ImageWithBg() function"); + ImGui::SeparatorText(Tr("Image()/ImageWithBg() function")); ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right ImGui::PushStyleVar(ImGuiStyleVar_ImageBorderSize, IM_MAX(1.0f, ImGui::GetStyle().ImageBorderSize)); @@ -1904,15 +1936,15 @@ static void DemoWindowWidgetsImages() ImGui::PopStyleVar(); // Fancy widget - ImGui::SeparatorText("Interactive Image Viewer"); + ImGui::SeparatorText(Tr("Interactive Image Viewer")); static ExampleImageViewerData image_viewer; ImVec2 canvas_size(ImGui::GetContentRegionAvail().x, my_tex_h * 2.0f); ExampleImageViewer_DrawOptions(&image_viewer); ExampleImageViewer_DrawCanvas(&image_viewer, canvas_size, my_tex_id, (int)my_tex_w, (int)my_tex_h); IMGUI_DEMO_MARKER("Widgets/Images/Textured buttons"); - ImGui::SeparatorText("Textured Buttons"); - ImGui::TextWrapped("And now some textured buttons.."); + ImGui::SeparatorText(Tr("Textured Buttons")); + ImGui::TextWrapped("%s", Tr("And now some textured buttons..")); static int pressed_count = 0; for (int i = 0; i < 8; i++) { @@ -1946,7 +1978,7 @@ static void DemoWindowWidgetsImages() static void DemoWindowWidgetsListBoxes() { - if (ImGui::TreeNode("List Boxes")) + if (ImGui::TreeNode(Tr("List Boxes"))) { IMGUI_DEMO_MARKER("Widgets/List Boxes"); // BeginListBox() is essentially a thin wrapper to using BeginChild()/EndChild() @@ -1962,7 +1994,7 @@ static void DemoWindowWidgetsListBoxes() static bool item_highlight = false; int item_highlighted_idx = -1; // Here we store our highlighted data as an index. - ImGui::Checkbox("Highlight hovered item in second listbox", &item_highlight); + ImGui::Checkbox(Tr("Highlight hovered item in second listbox"), &item_highlight); if (ImGui::BeginListBox("listbox 1")) { @@ -1981,10 +2013,10 @@ static void DemoWindowWidgetsListBoxes() } ImGui::EndListBox(); } - ImGui::SameLine(); HelpMarker("Here we are sharing selection state between both boxes."); + ImGui::SameLine(); HelpMarker(Tr("Here we are sharing selection state between both boxes.")); // Custom size: use all width, 5 items tall - ImGui::Text("Full-width:"); + ImGui::Text("%s", Tr("Full-width:")); if (ImGui::BeginListBox("##listbox 2", ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing()))) { for (int n = 0; n < IM_COUNTOF(items); n++) @@ -2064,20 +2096,20 @@ static void DemoWindowWidgetsPlotting() // Plot/Graph widgets are not very good. // Consider using a third-party library such as ImPlot: https://github.com/epezent/implot // (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions) - if (ImGui::TreeNode("Plotting")) + if (ImGui::TreeNode(Tr("Plotting"))) { IMGUI_DEMO_MARKER("Widgets/Plotting"); - ImGui::Text("Need better plotting and graphing? Consider using ImPlot:"); + ImGui::Text("%s", Tr("Need better plotting and graphing? Consider using ImPlot:")); ImGui::TextLinkOpenURL("https://github.com/epezent/implot"); ImGui::Separator(); static bool animate = true; - ImGui::Checkbox("Animate", &animate); + ImGui::Checkbox(Tr("Animate"), &animate); // Plot as lines and plot as histogram static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; - ImGui::PlotLines("Frame Times", arr, IM_COUNTOF(arr)); - ImGui::PlotHistogram("Histogram", arr, IM_COUNTOF(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f)); + ImGui::PlotLines(Tr("Frame Times"), arr, IM_COUNTOF(arr)); + ImGui::PlotHistogram(Tr("Histogram"), arr, IM_COUNTOF(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f)); //ImGui::SameLine(); HelpMarker("Consider using ImPlot instead!"); // Fill an array of contiguous float values to plot @@ -2118,11 +2150,11 @@ static void DemoWindowWidgetsPlotting() static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; } }; static int func_type = 0, display_count = 70; - ImGui::SeparatorText("Functions"); + ImGui::SeparatorText(Tr("Functions")); ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); ImGui::Combo("func", &func_type, "Sin\0Saw\0"); ImGui::SameLine(); - ImGui::SliderInt("Sample count", &display_count, 1, 400); + ImGui::SliderInt(Tr("Sample count"), &display_count, 1, 400); float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; ImGui::PlotLines("Lines##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); ImGui::PlotHistogram("Histogram##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); @@ -2137,7 +2169,7 @@ static void DemoWindowWidgetsPlotting() static void DemoWindowWidgetsProgressBars() { - if (ImGui::TreeNode("Progress Bars")) + if (ImGui::TreeNode(Tr("Progress Bars"))) { IMGUI_DEMO_MARKER("Widgets/Progress Bars"); // Animate a simple progress bar @@ -2147,6 +2179,8 @@ static void DemoWindowWidgetsProgressBars() if (progress_accum <= -0.1f) { progress_accum = -0.1f; progress_dir *= -1.0f; } const float progress = IM_CLAMP(progress_accum, 0.0f, 1.0f); + + printf("Progress Bars == %f\n", progress); // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width, // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth. @@ -2174,7 +2208,7 @@ static void DemoWindowWidgetsProgressBars() static void DemoWindowWidgetsQueryingStatuses() { - if (ImGui::TreeNode("Querying Item Status (Edited/Active/Hovered etc.)")) + if (ImGui::TreeNode(Tr("Querying Item Status (Edited/Active/Hovered etc.)"))) { IMGUI_DEMO_MARKER("Widgets/Querying Item Status (Edited,Active,Hovered etc.)"); // Select an item type @@ -2286,11 +2320,11 @@ static void DemoWindowWidgetsQueryingStatuses() ImGui::TreePop(); } - if (ImGui::TreeNode("Querying Window Status (Focused/Hovered etc.)")) + if (ImGui::TreeNode(Tr("Querying Window Status (Focused/Hovered etc.)"))) { IMGUI_DEMO_MARKER("Widgets/Querying Window Status (Focused,Hovered etc.)"); static bool embed_all_inside_a_child_window = false; - ImGui::Checkbox("Embed everything inside a child window for testing _RootWindow flag.", &embed_all_inside_a_child_window); + ImGui::Checkbox(Tr("Embed everything inside a child window for testing _RootWindow flag."), &embed_all_inside_a_child_window); if (embed_all_inside_a_child_window) ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), ImGuiChildFlags_Borders); @@ -2376,7 +2410,7 @@ static void DemoWindowWidgetsQueryingStatuses() static void DemoWindowWidgetsSelectables() { //ImGui::SetNextItemOpen(true, ImGuiCond_Once); - if (ImGui::TreeNode("Selectables")) + if (ImGui::TreeNode(Tr("Selectables"))) { IMGUI_DEMO_MARKER("Widgets/Selectables"); // Selectable() has 2 overloads: @@ -2386,7 +2420,7 @@ static void DemoWindowWidgetsSelectables() // The earlier is more flexible, as in real application your selection may be stored in many different ways // and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc). IMGUI_DEMO_MARKER("Widgets/Selectables/Basic"); - if (ImGui::TreeNode("Basic")) + if (ImGui::TreeNode(Tr("Basic"))) { static bool selection[5] = { false, true, false, false }; ImGui::Selectable("1. I am selectable", &selection[0]); @@ -2399,7 +2433,7 @@ static void DemoWindowWidgetsSelectables() } IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more items on the same line"); - if (ImGui::TreeNode("Multiple items on the same line")) + if (ImGui::TreeNode(Tr("Multiple items on the same line"))) { IMGUI_DEMO_MARKER("Widgets/Selectables/Multiple items on the same line"); // - Using SetNextItemAllowOverlap() @@ -2440,7 +2474,7 @@ static void DemoWindowWidgetsSelectables() ImGui::TreePop(); } - if (ImGui::TreeNode("In Tables")) + if (ImGui::TreeNode(Tr("In Tables"))) { IMGUI_DEMO_MARKER("Widgets/Selectables/In Tables"); static bool selected[10] = {}; @@ -2476,7 +2510,7 @@ static void DemoWindowWidgetsSelectables() ImGui::TreePop(); } - if (ImGui::TreeNode("Grid")) + if (ImGui::TreeNode(Tr("Grid"))) { IMGUI_DEMO_MARKER("Widgets/Selectables/Grid"); static char selected[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }; @@ -2510,7 +2544,7 @@ static void DemoWindowWidgetsSelectables() ImGui::PopStyleVar(); ImGui::TreePop(); } - if (ImGui::TreeNode("Alignment")) + if (ImGui::TreeNode(Tr("Alignment"))) { IMGUI_DEMO_MARKER("Widgets/Selectables/Alignment"); HelpMarker( @@ -2773,7 +2807,7 @@ struct ExampleDualListBox static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_data) { - if (ImGui::TreeNode("Selection State & Multi-Select")) + if (ImGui::TreeNode(Tr("Selection State & Multi-Select"))) { IMGUI_DEMO_MARKER("Widgets/Selection State & Multi-Select"); HelpMarker("Selections can be built using Selectable(), TreeNode() or other widgets. Selection state is owned by application code/data."); @@ -2783,7 +2817,7 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d ImGui::TextLinkOpenURL("imgui/wiki/Multi-Select", "https://github.com/ocornut/imgui/wiki/Multi-Select"); // Without any fancy API: manage single-selection yourself. - if (ImGui::TreeNode("Single-Select")) + if (ImGui::TreeNode(Tr("Single-Select"))) { IMGUI_DEMO_MARKER("Widgets/Selection State/Single-Select"); static int selected = -1; @@ -2799,7 +2833,7 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d // Demonstrate implementation a most-basic form of multi-selection manually // This doesn't support the Shift modifier which requires BeginMultiSelect()! - if (ImGui::TreeNode("Multi-Select (manual/simplified, without BeginMultiSelect)")) + if (ImGui::TreeNode(Tr("Multi-Select (manual/simplified, without BeginMultiSelect)"))) { IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (manual/simplified, without BeginMultiSelect)"); HelpMarker("Hold Ctrl and Click to select multiple items."); @@ -2821,10 +2855,10 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d // Demonstrate handling proper multi-selection using the BeginMultiSelect/EndMultiSelect API. // Shift+Click w/ Ctrl and other standard features are supported. // We use the ImGuiSelectionBasicStorage helper which you may freely reimplement. - if (ImGui::TreeNode("Multi-Select")) + if (ImGui::TreeNode(Tr("Multi-Select"))) { IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select"); - ImGui::Text("Supported features:"); + ImGui::Text("%s", Tr("Supported features:")); ImGui::BulletText("Keyboard navigation (arrows, page up/down, home/end, space)."); ImGui::BulletText("Ctrl modifier to preserve and toggle selection."); ImGui::BulletText("Shift modifier for range selection."); @@ -2862,13 +2896,13 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d } // Demonstrate using the clipper with BeginMultiSelect()/EndMultiSelect() - if (ImGui::TreeNode("Multi-Select (with clipper)")) + if (ImGui::TreeNode(Tr("Multi-Select (with clipper)"))) { IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (with clipper)"); // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection static ImGuiSelectionBasicStorage selection; - ImGui::Text("Added features:"); + ImGui::Text("%s", Tr("Added features:")); ImGui::BulletText("Using ImGuiListClipper."); const int ITEMS_COUNT = 10000; @@ -2909,7 +2943,7 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d // - (3) BeginXXXX process // - (4) Focus process // - (5) EndXXXX process - if (ImGui::TreeNode("Multi-Select (with deletion)")) + if (ImGui::TreeNode(Tr("Multi-Select (with deletion)"))) { IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (with deletion)"); // Storing items data separately from selection data. @@ -2920,8 +2954,8 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d selection.UserData = (void*)&items; selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { ImVector* p_items = (ImVector*)self->UserData; return (*p_items)[idx]; }; // Index -> ID - ImGui::Text("Added features:"); - ImGui::BulletText("Dynamic list with Delete key support."); + ImGui::Text("%s", Tr("Added features:")); + ImGui::BulletText("%s", Tr("Dynamic list with Delete key support.")); ImGui::Text("Selection size: %d/%d", selection.Size, items.Size); // Initialize default list with 50 items + button to add/remove items. @@ -2970,7 +3004,7 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d } // Implement a Dual List Box (#6648) - if (ImGui::TreeNode("Multi-Select (dual list box)")) + if (ImGui::TreeNode(Tr("Multi-Select (dual list box)"))) { IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (dual list box)"); // Init default state @@ -2986,7 +3020,7 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d } // Demonstrate using the clipper with BeginMultiSelect()/EndMultiSelect() - if (ImGui::TreeNode("Multi-Select (in a table)")) + if (ImGui::TreeNode(Tr("Multi-Select (in a table)"))) { IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (in a table)"); static ImGuiSelectionBasicStorage selection; @@ -3033,13 +3067,13 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d ImGui::TreePop(); } - if (ImGui::TreeNode("Multi-Select (checkboxes)")) + if (ImGui::TreeNode(Tr("Multi-Select (checkboxes)"))) { IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (checkboxes)"); - ImGui::Text("In a list of checkboxes (not selectable):"); - ImGui::BulletText("Using _NoAutoSelect + _NoAutoClear flags."); - ImGui::BulletText("Shift+Click to check multiple boxes."); - ImGui::BulletText("Shift+Keyboard to copy current value to other boxes."); + ImGui::Text("%s", Tr("In a list of checkboxes (not selectable):")); + ImGui::BulletText("%s", Tr("Using _NoAutoSelect + _NoAutoClear flags.")); + ImGui::BulletText("%s", Tr("Shift+Click to check multiple boxes.")); + ImGui::BulletText("%s", Tr("Shift+Keyboard to copy current value to other boxes.")); // If you have an array of checkboxes, you may want to use NoAutoSelect + NoAutoClear and the ImGuiSelectionExternalStorage helper. static bool items[20] = {}; @@ -3071,7 +3105,7 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d } // Demonstrate individual selection scopes in same window - if (ImGui::TreeNode("Multi-Select (multiple scopes)")) + if (ImGui::TreeNode(Tr("Multi-Select (multiple scopes)"))) { IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (multiple scopes)"); // Use default select: Pass index to SetNextItemSelectionUserData(), store index in Selection @@ -3095,7 +3129,7 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection->Size, ITEMS_COUNT); selection->ApplyRequests(ms_io); - ImGui::SeparatorText("Selection scope"); + ImGui::SeparatorText(Tr("Selection scope")); ImGui::Text("Selection size: %d/%d", selection->Size, ITEMS_COUNT); for (int n = 0; n < ITEMS_COUNT; n++) @@ -3116,10 +3150,10 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d } // See ShowExampleAppAssetsBrowser() - if (ImGui::TreeNode("Multi-Select (tiled assets browser)")) + if (ImGui::TreeNode(Tr("Multi-Select (tiled assets browser)"))) { - ImGui::Checkbox("Assets Browser", &demo_data->ShowAppAssetsBrowser); - ImGui::Text("(also access from 'Examples->Assets Browser' in menu)"); + ImGui::Checkbox(Tr("Assets Browser"), &demo_data->ShowAppAssetsBrowser); + ImGui::Text("%s", Tr("(also access from 'Examples->Assets Browser' in menu)")); ImGui::TreePop(); } @@ -3133,7 +3167,7 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d // are more likely to build an array mapping sequential indices to visible tree nodes, since your // filtering/search + clipping process will benefit from it. Having this will make this interpolation much easier. // - Consider this a prototype: we are working toward simplifying some of it. - if (ImGui::TreeNode("Multi-Select (trees)")) + if (ImGui::TreeNode(Tr("Multi-Select (trees)"))) { IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (trees)"); HelpMarker( @@ -3251,7 +3285,7 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d static ImGuiSelectionBasicStorage selection; if (demo_data->DemoTree == NULL) demo_data->DemoTree = ExampleTree_CreateDemoTree(); // Create tree once - ImGui::Text("Selection size: %d", selection.Size); + ImGui::Text(Tr("Selection size: %d"), selection.Size); if (ImGui::BeginChild("##Tree", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY)) { @@ -3276,7 +3310,7 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d // - Showcase TreeNode variant (note that tree node don't expand in the demo: supporting expanding tree nodes + clipping a separate thing). // - Showcase using inside a table. //ImGui::SetNextItemOpen(true, ImGuiCond_Once); - if (ImGui::TreeNode("Multi-Select (advanced)")) + if (ImGui::TreeNode(Tr("Multi-Select (advanced)"))) { IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (advanced)"); // Options @@ -3289,18 +3323,18 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d; static WidgetType widget_type = WidgetType_Selectable; - if (ImGui::TreeNode("Options")) + if (ImGui::TreeNode(Tr("Options"))) { - if (ImGui::RadioButton("Selectables", widget_type == WidgetType_Selectable)) { widget_type = WidgetType_Selectable; } + if (ImGui::RadioButton(Tr("Selectables"), widget_type == WidgetType_Selectable)) { widget_type = WidgetType_Selectable; } ImGui::SameLine(); - if (ImGui::RadioButton("Tree nodes", widget_type == WidgetType_TreeNode)) { widget_type = WidgetType_TreeNode; } + if (ImGui::RadioButton(Tr("Tree nodes"), widget_type == WidgetType_TreeNode)) { widget_type = WidgetType_TreeNode; } ImGui::SameLine(); HelpMarker("TreeNode() is technically supported but... using this correctly is more complicated (you need some sort of linear/random access to your tree, which is suited to advanced trees setups already implementing filters and clipper. We will work toward simplifying and demoing this.\n\nFor now the tree demo is actually a little bit meaningless because it is an empty tree with only root nodes."); - ImGui::Checkbox("Enable clipper", &use_clipper); - ImGui::Checkbox("Enable deletion", &use_deletion); - ImGui::Checkbox("Enable drag & drop", &use_drag_drop); - ImGui::Checkbox("Show in a table", &show_in_table); - ImGui::Checkbox("Show color button", &show_color_button); + ImGui::Checkbox(Tr("Enable clipper"), &use_clipper); + ImGui::Checkbox(Tr("Enable deletion"), &use_deletion); + ImGui::Checkbox(Tr("Enable drag & drop"), &use_drag_drop); + ImGui::Checkbox(Tr("Show in a table"), &show_in_table); + ImGui::Checkbox(Tr("Show color button"), &show_color_button); ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SingleSelect", &flags, ImGuiMultiSelectFlags_SingleSelect); ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoSelectAll", &flags, ImGuiMultiSelectFlags_NoSelectAll); ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoRangeSelect", &flags, ImGuiMultiSelectFlags_NoRangeSelect); @@ -3448,7 +3482,7 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d if (payload_count == 1) ImGui::Text("Object %05d: %s", payload_items[0], ExampleNames[payload_items[0] % IM_COUNTOF(ExampleNames)]); else - ImGui::Text("Dragging %d objects", payload_count); + ImGui::Text(Tr("Dragging %d objects"), payload_count); ImGui::EndDragDropSource(); } @@ -3464,7 +3498,7 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d if (ImGui::Selectable(label)) request_deletion_from_menu = true; ImGui::EndDisabled(); - ImGui::Selectable("Close"); + ImGui::Selectable(Tr("Close")); ImGui::EndPopup(); } @@ -3525,28 +3559,28 @@ static void EditTabBarFittingPolicyFlags(ImGuiTabBarFlags* p_flags) static void DemoWindowWidgetsTabs() { - if (ImGui::TreeNode("Tabs")) + if (ImGui::TreeNode(Tr("Tabs"))) { IMGUI_DEMO_MARKER("Widgets/Tabs"); - if (ImGui::TreeNode("Basic")) + if (ImGui::TreeNode(Tr("Basic"))) { IMGUI_DEMO_MARKER("Widgets/Tabs/Basic"); ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None; if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) { - if (ImGui::BeginTabItem("Avocado")) + if (ImGui::BeginTabItem(Tr("Avocado"))) { - ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah"); + ImGui::Text("%s", Tr("This is the Avocado tab!\nblah blah blah blah blah")); ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("Broccoli")) + if (ImGui::BeginTabItem(Tr("Broccoli"))) { - ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah"); + ImGui::Text("%s", Tr("This is the Broccoli tab!\nblah blah blah blah blah")); ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("Cucumber")) + if (ImGui::BeginTabItem(Tr("Cucumber"))) { - ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah"); + ImGui::Text("%s", Tr("This is the Cucumber tab!\nblah blah blah blah blah")); ImGui::EndTabItem(); } ImGui::EndTabBar(); @@ -3555,7 +3589,7 @@ static void DemoWindowWidgetsTabs() ImGui::TreePop(); } - if (ImGui::TreeNode("Advanced & Close Button")) + if (ImGui::TreeNode(Tr("Advanced & Close Button"))) { IMGUI_DEMO_MARKER("Widgets/Tabs/Advanced & Close Button"); // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). @@ -3569,7 +3603,7 @@ static void DemoWindowWidgetsTabs() // Tab Bar ImGui::AlignTextToFramePadding(); - ImGui::Text("Opened:"); + ImGui::Text("%s", Tr("Opened:")); const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" }; static bool opened[4] = { true, true, true, true }; // Persistent user state for (int n = 0; n < IM_COUNTOF(opened); n++) @@ -3585,9 +3619,9 @@ static void DemoWindowWidgetsTabs() for (int n = 0; n < IM_COUNTOF(opened); n++) if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None)) { - ImGui::Text("This is the %s tab!", names[n]); + ImGui::Text(Tr("This is the %s tab!"), names[n]); if (n & 1) - ImGui::Text("I am an odd tab."); + ImGui::Text("%s", Tr("I am an odd tab.")); ImGui::EndTabItem(); } ImGui::EndTabBar(); @@ -3596,7 +3630,7 @@ static void DemoWindowWidgetsTabs() ImGui::TreePop(); } - if (ImGui::TreeNode("TabItemButton & Leading/Trailing flags")) + if (ImGui::TreeNode(Tr("TabItemButton & Leading/Trailing flags"))) { IMGUI_DEMO_MARKER("Widgets/Tabs/TabItemButton & Leading-Trailing flags"); static ImVector active_tabs; @@ -3610,8 +3644,8 @@ static void DemoWindowWidgetsTabs() // but they tend to make more sense together) static bool show_leading_button = true; static bool show_trailing_button = true; - ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button); - ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button); + ImGui::Checkbox(Tr("Show Leading TabItemButton()"), &show_leading_button); + ImGui::Checkbox(Tr("Show Trailing TabItemButton()"), &show_trailing_button); // Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyShrink; @@ -3625,7 +3659,7 @@ static void DemoWindowWidgetsTabs() ImGui::OpenPopup("MyHelpMenu"); if (ImGui::BeginPopup("MyHelpMenu")) { - ImGui::Selectable("Hello!"); + ImGui::Selectable(Tr("Hello!")); ImGui::EndPopup(); } @@ -3644,7 +3678,7 @@ static void DemoWindowWidgetsTabs() snprintf(name, IM_COUNTOF(name), "%04d", active_tabs[n]); if (ImGui::BeginTabItem(name, &open, ImGuiTabItemFlags_None)) { - ImGui::Text("This is the %s tab!", name); + ImGui::Text(Tr("This is the %s tab!"), name); ImGui::EndTabItem(); } @@ -3669,21 +3703,21 @@ static void DemoWindowWidgetsTabs() static void DemoWindowWidgetsText() { - if (ImGui::TreeNode("Text")) + if (ImGui::TreeNode(Tr("Text"))) { IMGUI_DEMO_MARKER("Widgets/Text"); - if (ImGui::TreeNode("Colorful Text")) + if (ImGui::TreeNode(Tr("Colorful Text"))) { IMGUI_DEMO_MARKER("Widgets/Text/Colored Text"); // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility. - ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink"); - ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow"); - ImGui::TextDisabled("Disabled"); + ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "%s", Tr("Pink")); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "%s", Tr("Yellow")); + ImGui::TextDisabled("%s", Tr("Disabled")); ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle."); ImGui::TreePop(); } - if (ImGui::TreeNode("Font Size")) + if (ImGui::TreeNode(Tr("Font Size"))) { IMGUI_DEMO_MARKER("Widgets/Text/Font Size"); ImGuiStyle& style = ImGui::GetStyle(); @@ -3720,7 +3754,7 @@ static void DemoWindowWidgetsText() ImGui::TreePop(); } - if (ImGui::TreeNode("Word Wrapping")) + if (ImGui::TreeNode(Tr("Word Wrapping"))) { IMGUI_DEMO_MARKER("Widgets/Text/Word Wrapping"); // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility. @@ -3735,7 +3769,7 @@ static void DemoWindowWidgetsText() ImDrawList* draw_list = ImGui::GetWindowDrawList(); for (int n = 0; n < 2; n++) { - ImGui::Text("Test paragraph %d:", n); + ImGui::Text(Tr("Test paragraph %d:"), n); ImVec2 pos = ImGui::GetCursorScreenPos(); ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y); ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()); @@ -3754,7 +3788,7 @@ static void DemoWindowWidgetsText() ImGui::TreePop(); } - if (ImGui::TreeNode("UTF-8 Text")) + if (ImGui::TreeNode(Tr("UTF-8 Text"))) { IMGUI_DEMO_MARKER("Widgets/Text/UTF-8 Text"); // UTF-8 test with Japanese characters @@ -3788,7 +3822,7 @@ static void DemoWindowWidgetsText() static void DemoWindowWidgetsTextFilter() { - if (ImGui::TreeNode("Text Filter")) + if (ImGui::TreeNode(Tr("Text Filter"))) { IMGUI_DEMO_MARKER("Widgets/Text Filter"); // Helper class to easy setup a text filter. @@ -3799,7 +3833,7 @@ static void DemoWindowWidgetsTextFilter() " \"\" display all lines\n" " \"xxx\" display lines containing \"xxx\"\n" " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n" - " \"-xxx\" hide lines containing \"xxx\""); + " \"-xxx\" hide lines containing \"xxx\""); // Keep as-is (technical reference text) filter.Draw(); const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }; for (int i = 0; i < IM_COUNTOF(lines); i++) @@ -3817,10 +3851,10 @@ static void DemoWindowWidgetsTextInput() { // To wire InputText() with std::string or any other custom string type, // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. - if (ImGui::TreeNode("Text Input")) + if (ImGui::TreeNode(Tr("Text Input"))) { IMGUI_DEMO_MARKER("Widgets/Text Input"); - if (ImGui::TreeNode("Multi-line Text Input")) + if (ImGui::TreeNode(Tr("Multi-line Text Input"))) { IMGUI_DEMO_MARKER("Widgets/Text Input/Multi-line Text Input"); // WE ARE USING A FIXED-SIZE BUFFER FOR SIMPLICITY HERE. @@ -3851,7 +3885,7 @@ static void DemoWindowWidgetsTextInput() ImGui::TreePop(); } - if (ImGui::TreeNode("Filtered Text Input")) + if (ImGui::TreeNode(Tr("Filtered Text Input"))) { IMGUI_DEMO_MARKER("Widgets/Text Input/Filtered Text Input"); struct TextFilters @@ -3883,18 +3917,18 @@ static void DemoWindowWidgetsTextInput() ImGui::TreePop(); } - if (ImGui::TreeNode("Password Input")) + if (ImGui::TreeNode(Tr("Password Input"))) { IMGUI_DEMO_MARKER("Widgets/Text Input/Password input"); static char password[64] = "password123"; - ImGui::InputText("password", password, IM_COUNTOF(password), ImGuiInputTextFlags_Password); + ImGui::InputText(Tr("password"), password, IM_COUNTOF(password), ImGuiInputTextFlags_Password); ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n"); - ImGui::InputTextWithHint("password (w/ hint)", "", password, IM_COUNTOF(password), ImGuiInputTextFlags_Password); - ImGui::InputText("password (clear)", password, IM_COUNTOF(password)); + ImGui::InputTextWithHint(Tr("password (w/ hint)"), Tr(""), password, IM_COUNTOF(password), ImGuiInputTextFlags_Password); + ImGui::InputText(Tr("password (clear)"), password, IM_COUNTOF(password)); ImGui::TreePop(); } - if (ImGui::TreeNode("Completion, History, Edit Callbacks")) + if (ImGui::TreeNode(Tr("Completion, History, Edit Callbacks"))) { IMGUI_DEMO_MARKER("Widgets/Text Input/Completion, History, Edit Callbacks"); struct Funcs @@ -3935,20 +3969,20 @@ static void DemoWindowWidgetsTextInput() } }; static char buf1[64]; - ImGui::InputText("Completion", buf1, IM_COUNTOF(buf1), ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback); + ImGui::InputText(Tr("Completion"), buf1, IM_COUNTOF(buf1), ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback); ImGui::SameLine(); HelpMarker( "Here we append \"..\" each time Tab is pressed. " "See 'Examples>Console' for a more meaningful demonstration of using this callback."); static char buf2[64]; - ImGui::InputText("History", buf2, IM_COUNTOF(buf2), ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback); + ImGui::InputText(Tr("History"), buf2, IM_COUNTOF(buf2), ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback); ImGui::SameLine(); HelpMarker( "Here we replace and select text each time Up/Down are pressed. " "See 'Examples>Console' for a more meaningful demonstration of using this callback."); static char buf3[64]; static int edit_count = 0; - ImGui::InputText("Edit", buf3, IM_COUNTOF(buf3), ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count); + ImGui::InputText(Tr("Edit"), buf3, IM_COUNTOF(buf3), ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count); ImGui::SameLine(); HelpMarker( "Here we toggle the casing of the first character on every edit + count edits."); ImGui::SameLine(); ImGui::Text("(%d)", edit_count); @@ -3956,7 +3990,7 @@ static void DemoWindowWidgetsTextInput() ImGui::TreePop(); } - if (ImGui::TreeNode("Resize Callback")) + if (ImGui::TreeNode(Tr("Resize Callback"))) { IMGUI_DEMO_MARKER("Widgets/Text Input/Resize Callback"); // To wire InputText() with std::string or any other custom string type, @@ -4002,7 +4036,7 @@ static void DemoWindowWidgetsTextInput() ImGui::TreePop(); } - if (ImGui::TreeNode("Eliding, Alignment")) + if (ImGui::TreeNode(Tr("Eliding, Alignment"))) { IMGUI_DEMO_MARKER("Widgets/Text Input/Eliding, Alignment"); static char buf1[128] = "/path/to/some/folder/with/long/filename.cpp"; @@ -4012,7 +4046,7 @@ static void DemoWindowWidgetsTextInput() ImGui::TreePop(); } - if (ImGui::TreeNode("Miscellaneous")) + if (ImGui::TreeNode(Tr("Miscellaneous"))) { IMGUI_DEMO_MARKER("Widgets/Text Input/Miscellaneous"); static char buf1[16]; @@ -4035,11 +4069,11 @@ static void DemoWindowWidgetsTextInput() static void DemoWindowWidgetsTooltips() { - if (ImGui::TreeNode("Tooltips")) + if (ImGui::TreeNode(Tr("Tooltips"))) { IMGUI_DEMO_MARKER("Widgets/Tooltips"); // Tooltips are windows following the mouse. They do not take focus away. - ImGui::SeparatorText("General"); + ImGui::SeparatorText(Tr("General")); // Typical use cases: // - Short-form (text only): SetItemTooltip("Hello"); @@ -4054,38 +4088,38 @@ static void DemoWindowWidgetsTooltips() ImVec2 sz = ImVec2(-FLT_MIN, 0.0f); - ImGui::Button("Basic", sz); + ImGui::Button(Tr("Basic"), sz); ImGui::SetItemTooltip("I am a tooltip"); - ImGui::Button("Fancy", sz); + ImGui::Button(Tr("Fancy"), sz); if (ImGui::BeginItemTooltip()) { - ImGui::Text("I am a fancy tooltip"); + ImGui::Text("%s", Tr("I am a fancy tooltip")); static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; - ImGui::PlotLines("Curve", arr, IM_COUNTOF(arr)); - ImGui::Text("Sin(time) = %f", sinf((float)ImGui::GetTime())); + ImGui::PlotLines(Tr("Curve"), arr, IM_COUNTOF(arr)); + ImGui::Text(Tr("Sin(time) = %f"), sinf((float)ImGui::GetTime())); ImGui::EndTooltip(); } - ImGui::SeparatorText("Always On"); + ImGui::SeparatorText(Tr("Always On")); // Showcase NOT relying on a IsItemHovered() to emit a tooltip. // Here the tooltip is always emitted when 'always_on == true'. static int always_on = 0; - ImGui::RadioButton("Off", &always_on, 0); + ImGui::RadioButton(Tr("Off"), &always_on, 0); ImGui::SameLine(); - ImGui::RadioButton("Always On (Simple)", &always_on, 1); + ImGui::RadioButton(Tr("Always On (Simple)"), &always_on, 1); ImGui::SameLine(); - ImGui::RadioButton("Always On (Advanced)", &always_on, 2); + ImGui::RadioButton(Tr("Always On (Advanced)"), &always_on, 2); if (always_on == 1) - ImGui::SetTooltip("I am following you around."); + ImGui::SetTooltip("%s", Tr("I am following you around.")); else if (always_on == 2 && ImGui::BeginTooltip()) { ImGui::ProgressBar(sinf((float)ImGui::GetTime()) * 0.5f + 0.5f, ImVec2(ImGui::GetFontSize() * 25, 0.0f)); ImGui::EndTooltip(); } - ImGui::SeparatorText("Custom"); + ImGui::SeparatorText(Tr("Custom")); HelpMarker( "Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize " @@ -4096,32 +4130,32 @@ static void DemoWindowWidgetsTooltips() // Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from // 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or keyboard/gamepad is being used. // With default settings, ImGuiHoveredFlags_ForTooltip is equivalent to ImGuiHoveredFlags_DelayShort + ImGuiHoveredFlags_Stationary. - ImGui::Button("Manual", sz); + ImGui::Button(Tr("Manual"), sz); if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip)) - ImGui::SetTooltip("I am a manually emitted tooltip."); + ImGui::SetTooltip("%s", Tr("I am a manually emitted tooltip.")); - ImGui::Button("DelayNone", sz); + ImGui::Button(Tr("DelayNone"), sz); if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNone)) - ImGui::SetTooltip("I am a tooltip with no delay."); + ImGui::SetTooltip("%s", Tr("I am a tooltip with no delay.")); - ImGui::Button("DelayShort", sz); + ImGui::Button(Tr("DelayShort"), sz); if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_NoSharedDelay)) - ImGui::SetTooltip("I am a tooltip with a short delay (%0.2f sec).", ImGui::GetStyle().HoverDelayShort); + ImGui::SetTooltip(Tr("I am a tooltip with a short delay (%0.2f sec)."), ImGui::GetStyle().HoverDelayShort); - ImGui::Button("DelayLong", sz); + ImGui::Button(Tr("DelayLong"), sz); if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay)) - ImGui::SetTooltip("I am a tooltip with a long delay (%0.2f sec).", ImGui::GetStyle().HoverDelayNormal); + ImGui::SetTooltip(Tr("I am a tooltip with a long delay (%0.2f sec)."), ImGui::GetStyle().HoverDelayNormal); - ImGui::Button("Stationary", sz); + ImGui::Button(Tr("Stationary"), sz); if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - ImGui::SetTooltip("I am a tooltip requiring mouse to be stationary before activating."); + ImGui::SetTooltip("%s", Tr("I am a tooltip requiring mouse to be stationary before activating.")); // Using ImGuiHoveredFlags_ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav', // which default value include the ImGuiHoveredFlags_AllowWhenDisabled flag. ImGui::BeginDisabled(); - ImGui::Button("Disabled item", sz); + ImGui::Button(Tr("Disabled item"), sz); if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip)) - ImGui::SetTooltip("I am a tooltip for a disabled item."); + ImGui::SetTooltip("%s", Tr("I am a tooltip for a disabled item.")); ImGui::EndDisabled(); ImGui::TreePop(); @@ -4134,11 +4168,11 @@ static void DemoWindowWidgetsTooltips() static void DemoWindowWidgetsTreeNodes() { - if (ImGui::TreeNode("Tree Nodes")) + if (ImGui::TreeNode(Tr("Tree Nodes"))) { IMGUI_DEMO_MARKER("Widgets/Tree Nodes"); // See see "Examples -> Property Editor" (ShowExampleAppPropertyEditor() function) for a fancier, data-driven tree. - if (ImGui::TreeNode("Basic Trees")) + if (ImGui::TreeNode(Tr("Basic Trees"))) { IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic Trees"); for (int i = 0; i < 5; i++) @@ -4154,9 +4188,9 @@ static void DemoWindowWidgetsTreeNodes() ImGui::PushID(i); if (ImGui::TreeNode("", "Child %d", i)) { - ImGui::Text("blah blah"); + ImGui::Text("%s", Tr("blah blah")); ImGui::SameLine(); - if (ImGui::SmallButton("button")) {} + if (ImGui::SmallButton(Tr("button"))) {} ImGui::TreePop(); } ImGui::PopID(); @@ -4164,7 +4198,7 @@ static void DemoWindowWidgetsTreeNodes() ImGui::TreePop(); } - if (ImGui::TreeNode("Hierarchy Lines")) + if (ImGui::TreeNode(Tr("Hierarchy Lines"))) { IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Hierarchy Lines"); static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DefaultOpen; @@ -4173,27 +4207,27 @@ static void DemoWindowWidgetsTreeNodes() ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", &base_flags, ImGuiTreeNodeFlags_DrawLinesFull); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", &base_flags, ImGuiTreeNodeFlags_DrawLinesToNodes); - if (ImGui::TreeNodeEx("Parent", base_flags)) + if (ImGui::TreeNodeEx(Tr("Parent"), base_flags)) { - if (ImGui::TreeNodeEx("Child 1", base_flags)) + if (ImGui::TreeNodeEx(Tr("Child 1"), base_flags)) { - ImGui::Button("Button for Child 1"); + ImGui::Button(Tr("Button for Child 1")); ImGui::TreePop(); } - if (ImGui::TreeNodeEx("Child 2", base_flags)) + if (ImGui::TreeNodeEx(Tr("Child 2"), base_flags)) { - ImGui::Button("Button for Child 2"); + ImGui::Button(Tr("Button for Child 2")); ImGui::TreePop(); } - ImGui::Text("Remaining contents"); - ImGui::Text("Remaining contents"); + ImGui::Text("%s", Tr("Remaining contents")); + ImGui::Text("%s", Tr("Remaining contents")); ImGui::TreePop(); } ImGui::TreePop(); } - if (ImGui::TreeNode("Clipping Large Trees")) + if (ImGui::TreeNode(Tr("Clipping Large Trees"))) { IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Clipping Large Trees"); ImGui::TextWrapped( @@ -4203,7 +4237,7 @@ static void DemoWindowWidgetsTreeNodes() ImGui::TreePop(); } - if (ImGui::TreeNode("Selectable Nodes")) + if (ImGui::TreeNode(Tr("Selectable Nodes"))) { IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Selectable Nodes"); HelpMarker( @@ -4233,7 +4267,7 @@ static void DemoWindowWidgetsTreeNodes() node_clicked_idx = node_n; if (is_open) { - ImGui::BulletText(""); + ImGui::BulletText("%s", Tr("")); ImGui::TreePop(); } } @@ -4248,7 +4282,7 @@ static void DemoWindowWidgetsTreeNodes() ImGui::TreePop(); } - if (ImGui::TreeNode("Advanced")) + if (ImGui::TreeNode(Tr("Advanced"))) { IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced"); static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth; @@ -4270,8 +4304,8 @@ static void DemoWindowWidgetsTreeNodes() ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", &base_flags, ImGuiTreeNodeFlags_DrawLinesFull); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", &base_flags, ImGuiTreeNodeFlags_DrawLinesToNodes); - ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position); - ImGui::Checkbox("Make Tree Nodes as drag & drop sources", &use_drag_and_drop); + ImGui::Checkbox(Tr("Align label with current X position"), &align_label_with_current_x_position); + ImGui::Checkbox(Tr("Make Tree Nodes as drag & drop sources"), &use_drag_and_drop); if (align_label_with_current_x_position) ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing()); @@ -4285,20 +4319,20 @@ static void DemoWindowWidgetsTreeNodes() if (use_drag_and_drop && ImGui::BeginDragDropSource()) { ImGui::SetDragDropPayload("MY_TREENODE_PAYLOAD_TYPE", NULL, 0); - ImGui::Text("This is a drag and drop source"); + ImGui::Text("%s", Tr("This is a drag and drop source")); ImGui::EndDragDropSource(); } if (node_n == 2 && (base_flags & ImGuiTreeNodeFlags_SpanLabelWidth)) { // Item 2 has an additional inline button to help demonstrate SpanLabelWidth. ImGui::SameLine(); - if (ImGui::SmallButton("button")) {} + if (ImGui::SmallButton(Tr("button"))) {} } if (is_open) { - ImGui::BulletText("Blah blah\nBlah Blah"); + ImGui::BulletText("%s", Tr("Blah blah\nBlah Blah")); ImGui::SameLine(); - ImGui::SmallButton("Button"); + ImGui::SmallButton(Tr("Button")); ImGui::TreePop(); } } @@ -4312,7 +4346,7 @@ static void DemoWindowWidgetsTreeNodes() if (use_drag_and_drop && ImGui::BeginDragDropSource()) { ImGui::SetDragDropPayload("MY_TREENODE_PAYLOAD_TYPE", NULL, 0); - ImGui::Text("This is a drag and drop source"); + ImGui::Text("%s", Tr("This is a drag and drop source")); ImGui::EndDragDropSource(); } } @@ -4331,7 +4365,7 @@ static void DemoWindowWidgetsTreeNodes() static void DemoWindowWidgetsVerticalSliders() { - if (ImGui::TreeNode("Vertical Sliders")) + if (ImGui::TreeNode(Tr("Vertical Sliders"))) { IMGUI_DEMO_MARKER("Widgets/Vertical Sliders"); const float spacing = 4; @@ -4454,19 +4488,19 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) static void DemoWindowLayout() { - if (!ImGui::CollapsingHeader("Layout & Scrolling")) + if (!ImGui::CollapsingHeader(Tr("Layout & Scrolling"))) return; - if (ImGui::TreeNode("Child windows")) + if (ImGui::TreeNode(Tr("Child windows"))) { IMGUI_DEMO_MARKER("Layout/Child windows"); - ImGui::SeparatorText("Child windows"); + ImGui::SeparatorText(Tr("Child windows")); HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window."); static bool disable_mouse_wheel = false; static bool disable_menu = false; - ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel); - ImGui::Checkbox("Disable Menu", &disable_menu); + ImGui::Checkbox(Tr("Disable Mouse Wheel"), &disable_mouse_wheel); + ImGui::Checkbox(Tr("Disable Menu"), &disable_menu); // Child 1: no border, enable horizontal scrollbar { @@ -4475,7 +4509,7 @@ static void DemoWindowLayout() window_flags |= ImGuiWindowFlags_NoScrollWithMouse; ImGui::BeginChild("ChildL", ImVec2(ImGui::GetContentRegionAvail().x * 0.5f, 260), ImGuiChildFlags_None, window_flags); for (int i = 0; i < 100; i++) - ImGui::Text("%04d: scrollable region", i); + ImGui::Text(Tr("%04d: scrollable region"), i); ImGui::EndChild(); } @@ -4515,7 +4549,7 @@ static void DemoWindowLayout() } // Child 3: manual-resize - ImGui::SeparatorText("Manual-resize"); + ImGui::SeparatorText(Tr("Manual-resize")); { HelpMarker("Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents."); //if (ImGui::Button("Set Height to 200")) @@ -4530,14 +4564,14 @@ static void DemoWindowLayout() } // Child 4: auto-resizing height with a limit - ImGui::SeparatorText("Auto-resize with constraints"); + ImGui::SeparatorText(Tr("Auto-resize with constraints")); { static int draw_lines = 3; static int max_height_in_lines = 10; ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); - ImGui::DragInt("Lines Count", &draw_lines, 0.2f); + ImGui::DragInt(Tr("Lines Count"), &draw_lines, 0.2f); ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); - ImGui::DragInt("Max Height (in Lines)", &max_height_in_lines, 0.2f); + ImGui::DragInt(Tr("Max Height (in Lines)"), &max_height_in_lines, 0.2f); ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 1), ImVec2(FLT_MAX, ImGui::GetTextLineHeightWithSpacing() * max_height_in_lines)); if (ImGui::BeginChild("ConstrainedChild", ImVec2(-FLT_MIN, 0.0f), ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY)) @@ -4546,7 +4580,7 @@ static void DemoWindowLayout() ImGui::EndChild(); } - ImGui::SeparatorText("Misc/Advanced"); + ImGui::SeparatorText(Tr("Misc/Advanced")); // Demonstrate a few extra things // - Changing ImGuiCol_ChildBg (which is transparent black in default styles) @@ -4560,8 +4594,8 @@ static void DemoWindowLayout() static bool override_bg_color = true; static ImGuiChildFlags child_flags = ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY; ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); - ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000); - ImGui::Checkbox("Override ChildBg color", &override_bg_color); + ImGui::DragInt(Tr("Offset X"), &offset_x, 1.0f, -1000, 1000); + ImGui::Checkbox(Tr("Override ChildBg color"), &override_bg_color); ImGui::CheckboxFlags("ImGuiChildFlags_Borders", &child_flags, ImGuiChildFlags_Borders); ImGui::CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", &child_flags, ImGuiChildFlags_AlwaysUseWindowPadding); ImGui::CheckboxFlags("ImGuiChildFlags_ResizeX", &child_flags, ImGuiChildFlags_ResizeX); @@ -4579,31 +4613,31 @@ static void DemoWindowLayout() ImGui::PopStyleColor(); for (int n = 0; n < 50; n++) - ImGui::Text("Some test %d", n); + ImGui::Text(Tr("Some test %d"), n); ImGui::EndChild(); bool child_is_hovered = ImGui::IsItemHovered(); ImVec2 child_rect_min = ImGui::GetItemRectMin(); ImVec2 child_rect_max = ImGui::GetItemRectMax(); - ImGui::Text("Hovered: %d", child_is_hovered); - ImGui::Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y); + ImGui::Text(Tr("Hovered: %d"), child_is_hovered); + ImGui::Text(Tr("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)"), child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y); } ImGui::TreePop(); } - if (ImGui::TreeNode("Widgets Width")) + if (ImGui::TreeNode(Tr("Widgets Width"))) { IMGUI_DEMO_MARKER("Layout/Widgets Width"); static float f = 0.0f; static bool show_indented_items = true; - ImGui::Checkbox("Show indented items", &show_indented_items); + ImGui::Checkbox(Tr("Show indented items"), &show_indented_items); // Use SetNextItemWidth() to set the width of a single upcoming item. // Use PushItemWidth()/PopItemWidth() to set the width of a group of items. // In real code use you'll probably want to choose width values that are proportional to your font size // e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc. - ImGui::Text("SetNextItemWidth/PushItemWidth(100)"); + ImGui::Text("%s", Tr("SetNextItemWidth/PushItemWidth(100)")); ImGui::SameLine(); HelpMarker("Fixed width."); ImGui::PushItemWidth(100); ImGui::DragFloat("float##1b", &f); @@ -4615,7 +4649,7 @@ static void DemoWindowLayout() } ImGui::PopItemWidth(); - ImGui::Text("SetNextItemWidth/PushItemWidth(-100)"); + ImGui::Text("%s", Tr("SetNextItemWidth/PushItemWidth(-100)")); ImGui::SameLine(); HelpMarker("Align to right edge minus 100"); ImGui::PushItemWidth(-100); ImGui::DragFloat("float##2a", &f); @@ -4627,7 +4661,7 @@ static void DemoWindowLayout() } ImGui::PopItemWidth(); - ImGui::Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)"); + ImGui::Text("%s", Tr("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)")); ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)"); ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.5f); ImGui::DragFloat("float##3a", &f); @@ -4639,7 +4673,7 @@ static void DemoWindowLayout() } ImGui::PopItemWidth(); - ImGui::Text("SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)"); + ImGui::Text("%s", Tr("SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)")); ImGui::SameLine(); HelpMarker("Align to right edge minus half"); ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f); ImGui::DragFloat("float##4a", &f); @@ -4664,7 +4698,7 @@ static void DemoWindowLayout() // Demonstrate using PushItemWidth to surround three items. // Calling SetNextItemWidth() before each of them would have the same effect. - ImGui::Text("SetNextItemWidth/PushItemWidth(-FLT_MIN)"); + ImGui::Text("%s", Tr("SetNextItemWidth/PushItemWidth(-FLT_MIN)")); ImGui::SameLine(); HelpMarker("Align to right edge"); ImGui::PushItemWidth(-FLT_MIN); ImGui::DragFloat("##float6a", &f); @@ -4679,48 +4713,48 @@ static void DemoWindowLayout() ImGui::TreePop(); } - if (ImGui::TreeNode("Basic Horizontal Layout")) + if (ImGui::TreeNode(Tr("Basic Horizontal Layout"))) { IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout"); - ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)"); + ImGui::TextWrapped("%s", Tr("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)")); // Text IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine"); - ImGui::Text("Two items: Hello"); ImGui::SameLine(); - ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor"); + ImGui::Text("%s", Tr("Two items: Hello")); ImGui::SameLine(); + ImGui::TextColored(ImVec4(1, 1, 0, 1), "%s", Tr("Sailor")); // Adjust spacing - ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20); - ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor"); + ImGui::Text("%s", Tr("More spacing: Hello")); ImGui::SameLine(0, 20); + ImGui::TextColored(ImVec4(1, 1, 0, 1), "%s", Tr("Sailor")); // Button ImGui::AlignTextToFramePadding(); - ImGui::Text("Normal buttons"); ImGui::SameLine(); - ImGui::Button("Banana"); ImGui::SameLine(); - ImGui::Button("Apple"); ImGui::SameLine(); - ImGui::Button("Corniflower"); + ImGui::Text("%s", Tr("Normal buttons")); ImGui::SameLine(); + ImGui::Button(Tr("Banana")); ImGui::SameLine(); + ImGui::Button(Tr("Apple")); ImGui::SameLine(); + ImGui::Button(Tr("Corniflower")); // Button - ImGui::Text("Small buttons"); ImGui::SameLine(); - ImGui::SmallButton("Like this one"); ImGui::SameLine(); - ImGui::Text("can fit within a text block."); + ImGui::Text("%s", Tr("Small buttons")); ImGui::SameLine(); + ImGui::SmallButton(Tr("Like this one")); ImGui::SameLine(); + ImGui::Text("%s", Tr("can fit within a text block.")); // Aligned to arbitrary position. Easy/cheap column. IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (with offset)"); - ImGui::Text("Aligned"); - ImGui::SameLine(150); ImGui::Text("x=150"); - ImGui::SameLine(300); ImGui::Text("x=300"); - ImGui::Text("Aligned"); - ImGui::SameLine(150); ImGui::SmallButton("x=150"); - ImGui::SameLine(300); ImGui::SmallButton("x=300"); + ImGui::Text("%s", Tr("Aligned")); + ImGui::SameLine(150); ImGui::Text("%s", Tr("x=150")); + ImGui::SameLine(300); ImGui::Text("%s", Tr("x=300")); + ImGui::Text("%s", Tr("Aligned")); + ImGui::SameLine(150); ImGui::SmallButton(Tr("x=150")); + ImGui::SameLine(300); ImGui::SmallButton(Tr("x=300")); // Checkbox IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (more)"); static bool c1 = false, c2 = false, c3 = false, c4 = false; - ImGui::Checkbox("My", &c1); ImGui::SameLine(); - ImGui::Checkbox("Tailor", &c2); ImGui::SameLine(); - ImGui::Checkbox("Is", &c3); ImGui::SameLine(); - ImGui::Checkbox("Rich", &c4); + ImGui::Checkbox(Tr("My"), &c1); ImGui::SameLine(); + ImGui::Checkbox(Tr("Tailor"), &c2); ImGui::SameLine(); + ImGui::Checkbox(Tr("Is"), &c3); ImGui::SameLine(); + ImGui::Checkbox(Tr("Rich"), &c4); // Various static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f; @@ -4732,7 +4766,7 @@ static void DemoWindowLayout() ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine(); ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f); - ImGui::Text("Lists:"); + ImGui::Text("%s", Tr("Lists:")); static int selection[4] = { 0, 1, 2, 3 }; for (int i = 0; i < 4; i++) { @@ -4754,7 +4788,7 @@ static void DemoWindowLayout() // Manually wrapping // (we should eventually provide this as an automatic layout feature, but for now you can do it manually) IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Manual wrapping"); - ImGui::Text("Manual wrapping:"); + ImGui::Text("%s", Tr("Manual wrapping:")); ImGuiStyle& style = ImGui::GetStyle(); int buttons_count = 20; float window_visible_x2 = ImGui::GetCursorScreenPos().x + ImGui::GetContentRegionAvail().x; @@ -4772,7 +4806,7 @@ static void DemoWindowLayout() ImGui::TreePop(); } - if (ImGui::TreeNode("Groups")) + if (ImGui::TreeNode(Tr("Groups"))) { IMGUI_DEMO_MARKER("Layout/Groups"); HelpMarker( @@ -4819,11 +4853,11 @@ static void DemoWindowLayout() ImGui::TreePop(); } - if (ImGui::TreeNode("Text Baseline Alignment")) + if (ImGui::TreeNode(Tr("Text Baseline Alignment"))) { IMGUI_DEMO_MARKER("Layout/Text Baseline Alignment"); { - ImGui::BulletText("Text baseline:"); + ImGui::BulletText("%s", Tr("Text baseline:")); ImGui::SameLine(); HelpMarker( "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. " "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets."); @@ -4860,7 +4894,7 @@ static void DemoWindowLayout() ImGui::Spacing(); { - ImGui::BulletText("Multi-line text:"); + ImGui::BulletText("%s", Tr("Multi-line text:")); ImGui::Indent(); ImGui::Text("One\nTwo\nThree"); ImGui::SameLine(); ImGui::Text("Hello\nWorld"); ImGui::SameLine(); @@ -4884,7 +4918,7 @@ static void DemoWindowLayout() ImGui::Spacing(); { - ImGui::BulletText("Misc items:"); + ImGui::BulletText("%s", Tr("Misc items:")); ImGui::Indent(); // SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button. @@ -4905,7 +4939,7 @@ static void DemoWindowLayout() { // Placeholder tree data for (int i = 0; i < 6; i++) - ImGui::BulletText("Item %d..", i); + ImGui::BulletText(Tr("Item %d.."), i); ImGui::TreePop(); } @@ -4929,7 +4963,7 @@ static void DemoWindowLayout() { // Placeholder tree data for (int i = 0; i < 6; i++) - ImGui::BulletText("Item %d..", i); + ImGui::BulletText(Tr("Item %d.."), i); ImGui::TreePop(); } @@ -4947,7 +4981,7 @@ static void DemoWindowLayout() ImGui::TreePop(); } - if (ImGui::TreeNode("Scrolling")) + if (ImGui::TreeNode(Tr("Scrolling"))) { IMGUI_DEMO_MARKER("Layout/Scrolling/Vertical"); // Vertical scroll functions @@ -4959,20 +4993,20 @@ static void DemoWindowLayout() static float scroll_to_off_px = 0.0f; static float scroll_to_pos_px = 200.0f; - ImGui::Checkbox("Decoration", &enable_extra_decorations); + ImGui::Checkbox(Tr("Decoration"), &enable_extra_decorations); ImGui::PushItemWidth(ImGui::GetFontSize() * 10); - enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d"); + enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, Tr("Item = %d")); ImGui::SameLine(); - ImGui::Checkbox("Track", &enable_track); + ImGui::Checkbox(Tr("Track"), &enable_track); - bool scroll_to_off = ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px"); + bool scroll_to_off = ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, Tr("+%.0f px")); ImGui::SameLine(); - scroll_to_off |= ImGui::Button("Scroll Offset"); + scroll_to_off |= ImGui::Button(Tr("Scroll Offset")); - bool scroll_to_pos = ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px"); + bool scroll_to_pos = ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, Tr("X/Y = %.0f px")); ImGui::SameLine(); - scroll_to_pos |= ImGui::Button("Scroll To Pos"); + scroll_to_pos |= ImGui::Button(Tr("Scroll To Pos")); ImGui::PopItemWidth(); if (scroll_to_off || scroll_to_pos) @@ -4987,7 +5021,7 @@ static void DemoWindowLayout() { if (i > 0) ImGui::SameLine(); ImGui::BeginGroup(); - const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" }; + const char* names[] = { Tr("Top"), Tr("25%"), Tr("Center"), Tr("75%"), Tr("Bottom") }; ImGui::TextUnformatted(names[i]); const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0; @@ -5008,19 +5042,19 @@ static void DemoWindowLayout() { if (enable_track && item == track_item) { - ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); + ImGui::TextColored(ImVec4(1, 1, 0, 1), Tr("Item %d"), item); ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom } else { - ImGui::Text("Item %d", item); + ImGui::Text(Tr("Item %d"), item); } } } float scroll_y = ImGui::GetScrollY(); float scroll_max_y = ImGui::GetScrollMaxY(); ImGui::EndChild(); - ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y); + ImGui::Text(Tr("%.0f/%.0f"), scroll_y, scroll_max_y); ImGui::EndGroup(); } ImGui::PopID(); @@ -5052,12 +5086,12 @@ static void DemoWindowLayout() ImGui::SameLine(); if (enable_track && item == track_item) { - ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); + ImGui::TextColored(ImVec4(1, 1, 0, 1), Tr("Item %d"), item); ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right } else { - ImGui::Text("Item %d", item); + ImGui::Text(Tr("Item %d"), item); } } } @@ -5065,8 +5099,8 @@ static void DemoWindowLayout() float scroll_max_x = ImGui::GetScrollMaxX(); ImGui::EndChild(); ImGui::SameLine(); - const char* names[] = { "Left", "25%", "Center", "75%", "Right" }; - ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x); + const char* names[] = { Tr("Left"), Tr("25%"), Tr("Center"), Tr("75%"), Tr("Right") }; + ImGui::Text(Tr("%s\n%.0f/%.0f"), names[i], scroll_x, scroll_max_x); ImGui::Spacing(); } ImGui::PopID(); @@ -5077,7 +5111,7 @@ static void DemoWindowLayout() "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n" "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin()."); static int lines = 7; - ImGui::SliderInt("Lines", &lines, 1, 15); + ImGui::SliderInt(Tr("Lines"), &lines, 1, 15); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f)); ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30); @@ -5110,16 +5144,16 @@ static void DemoWindowLayout() ImGui::EndChild(); ImGui::PopStyleVar(2); float scroll_x_delta = 0.0f; - ImGui::SmallButton("<<"); + ImGui::SmallButton(Tr("<<")); if (ImGui::IsItemActive()) scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; ImGui::SameLine(); - ImGui::Text("Scroll from code"); ImGui::SameLine(); - ImGui::SmallButton(">>"); + ImGui::Text("%s", Tr("Scroll from code")); ImGui::SameLine(); + ImGui::SmallButton(Tr(">>")); if (ImGui::IsItemActive()) scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; ImGui::SameLine(); - ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x); + ImGui::Text(Tr("%.0f/%.0f"), scroll_x, scroll_max_x); if (scroll_x_delta != 0.0f) { // Demonstrate a trick: you can use Begin to set yourself in the context of another window @@ -5131,7 +5165,7 @@ static void DemoWindowLayout() ImGui::Spacing(); static bool show_horizontal_contents_size_demo_window = false; - ImGui::Checkbox("Show Horizontal contents size demo window", &show_horizontal_contents_size_demo_window); + ImGui::Checkbox(Tr("Show Horizontal contents size demo window"), &show_horizontal_contents_size_demo_window); if (show_horizontal_contents_size_demo_window) { @@ -5146,22 +5180,22 @@ static void DemoWindowLayout() static float contents_size_x = 300.0f; if (explicit_content_size) ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f)); - ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0); + ImGui::Begin(Tr("Horizontal contents size demo window"), &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0); IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal contents size demo window"); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0)); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0)); HelpMarker( "Test how different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\n" "Use 'Metrics->Tools->Show windows rectangles' to visualize rectangles."); - ImGui::Checkbox("H-scrollbar", &show_h_scrollbar); - ImGui::Checkbox("Button", &show_button); // Will grow contents size (unless explicitly overwritten) - ImGui::Checkbox("Tree nodes", &show_tree_nodes); // Will grow contents size and display highlight over full width - ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size - ImGui::Checkbox("Columns", &show_columns); // Will use contents size - ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size - ImGui::Checkbox("Child", &show_child); // Will grow and use contents size - ImGui::Checkbox("Explicit content size", &explicit_content_size); - ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY()); + ImGui::Checkbox(Tr("H-scrollbar"), &show_h_scrollbar); + ImGui::Checkbox(Tr("Button"), &show_button); // Will grow contents size (unless explicitly overwritten) + ImGui::Checkbox(Tr("Tree nodes"), &show_tree_nodes); // Will grow contents size and display highlight over full width + ImGui::Checkbox(Tr("Text wrapped"), &show_text_wrapped);// Will grow and use contents size + ImGui::Checkbox(Tr("Columns"), &show_columns); // Will use contents size + ImGui::Checkbox(Tr("Tab bar"), &show_tab_bar); // Will use contents size + ImGui::Checkbox(Tr("Child"), &show_child); // Will grow and use contents size + ImGui::Checkbox(Tr("Explicit content size"), &explicit_content_size); + ImGui::Text(Tr("Scroll %.1f/%.1f %.1f/%.1f"), ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY()); if (explicit_content_size) { ImGui::SameLine(); @@ -5176,43 +5210,43 @@ static void DemoWindowLayout() ImGui::Separator(); if (show_button) { - ImGui::Button("this is a 300-wide button", ImVec2(300, 0)); + ImGui::Button(Tr("this is a 300-wide button"), ImVec2(300, 0)); } if (show_tree_nodes) { bool open = true; - if (ImGui::TreeNode("this is a tree node")) + if (ImGui::TreeNode(Tr("this is a tree node"))) { - if (ImGui::TreeNode("another one of those tree node...")) + if (ImGui::TreeNode(Tr("another one of those tree node..."))) { - ImGui::Text("Some tree contents"); + ImGui::Text("%s", Tr("Some tree contents")); ImGui::TreePop(); } ImGui::TreePop(); } - ImGui::CollapsingHeader("CollapsingHeader", &open); + ImGui::CollapsingHeader(Tr("CollapsingHeader"), &open); } if (show_text_wrapped) { - ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle."); + ImGui::TextWrapped("%s", Tr("This text should automatically wrap on the edge of the work rectangle.")); } if (show_columns) { - ImGui::Text("Tables:"); + ImGui::Text("%s", Tr("Tables:")); if (ImGui::BeginTable("table", 4, ImGuiTableFlags_Borders)) { for (int n = 0; n < 4; n++) { ImGui::TableNextColumn(); - ImGui::Text("Width %.2f", ImGui::GetContentRegionAvail().x); + ImGui::Text(Tr("Width %.2f"), ImGui::GetContentRegionAvail().x); } ImGui::EndTable(); } - ImGui::Text("Columns:"); + ImGui::Text("%s", Tr("Columns:")); ImGui::Columns(4); for (int n = 0; n < 4; n++) { - ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); + ImGui::Text(Tr("Width %.2f"), ImGui::GetColumnWidth()); ImGui::NextColumn(); } ImGui::Columns(1); @@ -5236,13 +5270,13 @@ static void DemoWindowLayout() ImGui::TreePop(); } - if (ImGui::TreeNode("Text Clipping")) + if (ImGui::TreeNode(Tr("Text Clipping"))) { IMGUI_DEMO_MARKER("Layout/Text Clipping"); static ImVec2 size(100.0f, 100.0f); static ImVec2 offset(30.0f, 30.0f); ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f"); - ImGui::TextWrapped("(Click and drag to scroll)"); + ImGui::TextWrapped("%s", Tr("(Click and drag to scroll)")); HelpMarker( "(Left) Using ImGui::PushClipRect():\n" @@ -5301,7 +5335,7 @@ static void DemoWindowLayout() ImGui::TreePop(); } - if (ImGui::TreeNode("Overlap Mode")) + if (ImGui::TreeNode(Tr("Overlap Mode"))) { IMGUI_DEMO_MARKER("Layout/Overlap Mode"); static bool enable_allow_overlap = true; @@ -5310,22 +5344,22 @@ static void DemoWindowLayout() "Hit-testing is by default performed in item submission order, which generally is perceived as 'back-to-front'.\n\n" "By using SetNextItemAllowOverlap() you can notify that an item may be overlapped by another. " "Doing so alters the hovering logic: items using AllowOverlap mode requires an extra frame to accept hovered state."); - ImGui::Checkbox("Enable AllowOverlap", &enable_allow_overlap); + ImGui::Checkbox(Tr("Enable AllowOverlap"), &enable_allow_overlap); ImVec2 button1_pos = ImGui::GetCursorScreenPos(); ImVec2 button2_pos = ImVec2(button1_pos.x + 50.0f, button1_pos.y + 50.0f); if (enable_allow_overlap) ImGui::SetNextItemAllowOverlap(); - ImGui::Button("Button 1", ImVec2(80, 80)); + ImGui::Button(Tr("Button 1"), ImVec2(80, 80)); ImGui::SetCursorScreenPos(button2_pos); - ImGui::Button("Button 2", ImVec2(80, 80)); + ImGui::Button(Tr("Button 2"), ImVec2(80, 80)); // This is typically used with width-spanning items. // (note that Selectable() has a dedicated flag ImGuiSelectableFlags_AllowOverlap, which is a shortcut // for using SetNextItemAllowOverlap(). For demo purpose we use SetNextItemAllowOverlap() here.) if (enable_allow_overlap) ImGui::SetNextItemAllowOverlap(); - ImGui::Selectable("Some Selectable", false); + ImGui::Selectable(Tr("Some Selectable"), false); ImGui::SameLine(); ImGui::SmallButton("++"); @@ -5339,7 +5373,7 @@ static void DemoWindowLayout() static void DemoWindowPopups() { - if (!ImGui::CollapsingHeader("Popups & Modal windows")) + if (!ImGui::CollapsingHeader(Tr("Popups & Modal windows"))) return; // The properties of popups windows are: @@ -5360,7 +5394,7 @@ static void DemoWindowPopups() // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state. // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below. - if (ImGui::TreeNode("Popups")) + if (ImGui::TreeNode(Tr("Popups"))) { IMGUI_DEMO_MARKER("Popups/Popups"); ImGui::TextWrapped( @@ -5373,7 +5407,7 @@ static void DemoWindowPopups() // Simple selection popup (if you want to show the current selection inside the Button itself, // you may want to build a string using the "###" operator to preserve a constant ID with a variable label) - if (ImGui::Button("Select..")) + if (ImGui::Button(Tr("Select.."))) ImGui::OpenPopup("my_select_popup"); ImGui::SameLine(); ImGui::TextUnformatted(selected_fish == -1 ? "" : names[selected_fish]); @@ -5453,7 +5487,7 @@ static void DemoWindowPopups() ImGui::TreePop(); } - if (ImGui::TreeNode("Context menus")) + if (ImGui::TreeNode(Tr("Context menus"))) { IMGUI_DEMO_MARKER("Popups/Context menus"); HelpMarker("\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier."); @@ -5481,7 +5515,7 @@ static void DemoWindowPopups() { selected = n; ImGui::Text("This is a popup for \"%s\"!", names[n]); - if (ImGui::Button("Close")) + if (ImGui::Button(Tr("Close"))) ImGui::CloseCurrentPopup(); ImGui::EndPopup(); } @@ -5530,7 +5564,7 @@ static void DemoWindowPopups() { ImGui::Text("Edit name:"); ImGui::InputText("##edit", name, IM_COUNTOF(name)); - if (ImGui::Button("Close")) + if (ImGui::Button(Tr("Close"))) ImGui::CloseCurrentPopup(); ImGui::EndPopup(); } @@ -5540,7 +5574,7 @@ static void DemoWindowPopups() ImGui::TreePop(); } - if (ImGui::TreeNode("Modals")) + if (ImGui::TreeNode(Tr("Modal windows"))) { IMGUI_DEMO_MARKER("Popups/Modals"); ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside."); @@ -5604,12 +5638,12 @@ static void DemoWindowPopups() { ImGui::Text("Hello from Stacked The Second!"); ImGui::ColorEdit4("Color", color); // Allow opening another nested popup - if (ImGui::Button("Close")) + if (ImGui::Button(Tr("Close"))) ImGui::CloseCurrentPopup(); ImGui::EndPopup(); } - if (ImGui::Button("Close")) + if (ImGui::Button(Tr("Close"))) ImGui::CloseCurrentPopup(); ImGui::EndPopup(); } @@ -5617,7 +5651,7 @@ static void DemoWindowPopups() ImGui::TreePop(); } - if (ImGui::TreeNode("Menus inside a regular window")) + if (ImGui::TreeNode(Tr("Menus"))) { IMGUI_DEMO_MARKER("Popups/Menus inside a regular window"); ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!"); @@ -5803,7 +5837,7 @@ static void ShowTableColumnsStatusFlags(ImGuiTableColumnFlags flags) static void DemoWindowTables() { //ImGui::SetNextItemOpen(true, ImGuiCond_Once); - if (!ImGui::CollapsingHeader("Tables & Columns")) + if (!ImGui::CollapsingHeader(Tr("Tables & Columns"))) return; // Using those as a base value to create width/height that are factor of the size of our font @@ -5813,16 +5847,16 @@ static void DemoWindowTables() ImGui::PushID("Tables"); int open_action = -1; - if (ImGui::Button("Expand all")) + if (ImGui::Button(Tr("Expand all"))) open_action = 1; ImGui::SameLine(); - if (ImGui::Button("Collapse all")) + if (ImGui::Button(Tr("Collapse all"))) open_action = 0; ImGui::SameLine(); // Options static bool disable_indent = false; - ImGui::Checkbox("Disable tree indentation", &disable_indent); + ImGui::Checkbox(Tr("Disable tree indentation"), &disable_indent); ImGui::SameLine(); HelpMarker("Disable the indenting of tree nodes so demo tables can use the full window width."); ImGui::Separator(); @@ -5842,7 +5876,7 @@ static void DemoWindowTables() // Demos if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Basic")) + if (ImGui::TreeNode(Tr("Basic"))) { IMGUI_DEMO_MARKER("Tables/Basic"); // Here we will showcase three different ways to output a table. @@ -5905,7 +5939,7 @@ static void DemoWindowTables() if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Borders, background")) + if (ImGui::TreeNode(Tr("Borders, background"))) { IMGUI_DEMO_MARKER("Tables/Borders, background"); // Expose a few Borders related flags interactively @@ -5939,7 +5973,7 @@ static void DemoWindowTables() ImGui::AlignTextToFramePadding(); ImGui::Text("Cell contents:"); ImGui::SameLine(); ImGui::RadioButton("Text", &contents_type, CT_Text); ImGui::SameLine(); ImGui::RadioButton("FillButton", &contents_type, CT_FillButton); - ImGui::Checkbox("Display headers", &display_headers); + ImGui::Checkbox(Tr("Display headers"), &display_headers); ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers)"); PopStyleCompact(); @@ -5976,7 +6010,7 @@ static void DemoWindowTables() if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Resizable, stretch")) + if (ImGui::TreeNode(Tr("Resizable, stretch"))) { IMGUI_DEMO_MARKER("Tables/Resizable, stretch"); // By default, if we don't enable ScrollX the sizing policy for each column is "Stretch" @@ -6008,7 +6042,7 @@ static void DemoWindowTables() if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Resizable, fixed")) + if (ImGui::TreeNode(Tr("Resizable, fixed"))) { IMGUI_DEMO_MARKER("Tables/Resizable, fixed"); // Here we use ImGuiTableFlags_SizingFixedFit (even though _ScrollX is not set) @@ -6042,7 +6076,7 @@ static void DemoWindowTables() if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Resizable, mixed")) + if (ImGui::TreeNode(Tr("Resizable, mixed"))) { IMGUI_DEMO_MARKER("Tables/Resizable, mixed"); HelpMarker( @@ -6092,7 +6126,7 @@ static void DemoWindowTables() if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Reorderable, hideable, with headers")) + if (ImGui::TreeNode(Tr("Reorderable, hideable, with headers"))) { IMGUI_DEMO_MARKER("Tables/Reorderable, hideable, with headers"); HelpMarker( @@ -6152,7 +6186,7 @@ static void DemoWindowTables() if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Padding")) + if (ImGui::TreeNode(Tr("Padding"))) { IMGUI_DEMO_MARKER("Tables/Padding"); // First example: showcase use of padding flags and effect of BorderOuterV/BorderInnerV on X padding. @@ -6262,7 +6296,7 @@ static void DemoWindowTables() if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Sizing policies")) + if (ImGui::TreeNode(Tr("Sizing policies"))) { IMGUI_DEMO_MARKER("Tables/Explicit widths"); static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody; @@ -6371,7 +6405,7 @@ static void DemoWindowTables() if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Vertical scrolling, with clipping")) + if (ImGui::TreeNode(Tr("Vertical scrolling, with clipping"))) { IMGUI_DEMO_MARKER("Tables/Vertical scrolling, with clipping"); HelpMarker( @@ -6416,7 +6450,7 @@ static void DemoWindowTables() if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Horizontal scrolling")) + if (ImGui::TreeNode(Tr("Horizontal scrolling"))) { IMGUI_DEMO_MARKER("Tables/Horizontal scrolling"); HelpMarker( @@ -6507,7 +6541,7 @@ static void DemoWindowTables() if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Columns flags")) + if (ImGui::TreeNode(Tr("Columns flags"))) { IMGUI_DEMO_MARKER("Tables/Columns flags"); // Create a first table just to show all the options/flags we want to make visible in our example! @@ -6582,7 +6616,7 @@ static void DemoWindowTables() if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Columns widths")) + if (ImGui::TreeNode(Tr("Columns widths"))) { IMGUI_DEMO_MARKER("Tables/Columns widths"); HelpMarker("Using TableSetupColumn() to setup default width."); @@ -6651,7 +6685,7 @@ static void DemoWindowTables() if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Nested tables")) + if (ImGui::TreeNode(Tr("Nested tables"))) { IMGUI_DEMO_MARKER("Tables/Nested tables"); HelpMarker("This demonstrates embedding a table into another table cell."); @@ -6696,7 +6730,7 @@ static void DemoWindowTables() if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Row height")) + if (ImGui::TreeNode(Tr("Row height"))) { IMGUI_DEMO_MARKER("Tables/Row height"); HelpMarker( @@ -6761,7 +6795,7 @@ static void DemoWindowTables() if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Outer size")) + if (ImGui::TreeNode(Tr("Outer size"))) { IMGUI_DEMO_MARKER("Tables/Outer size"); // Showcasing use of ImGuiTableFlags_NoHostExtendX and ImGuiTableFlags_NoHostExtendY @@ -6829,7 +6863,7 @@ static void DemoWindowTables() if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Background color")) + if (ImGui::TreeNode(Tr("Background color"))) { IMGUI_DEMO_MARKER("Tables/Background color"); static ImGuiTableFlags flags = ImGuiTableFlags_RowBg; @@ -6887,7 +6921,7 @@ static void DemoWindowTables() if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Tree view")) + if (ImGui::TreeNode(Tr("Tree view"))) { IMGUI_DEMO_MARKER("Tables/Tree view"); static ImGuiTableFlags table_flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody; @@ -6903,9 +6937,9 @@ static void DemoWindowTables() if (ImGui::BeginTable("3ways", 3, table_flags)) { // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On - ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide); - ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f); - ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 18.0f); + ImGui::TableSetupColumn(Tr("Name"), ImGuiTableColumnFlags_NoHide); + ImGui::TableSetupColumn(Tr("Size"), ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f); + ImGui::TableSetupColumn(Tr("Type"), ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 18.0f); ImGui::TableHeadersRow(); // Simple storage to output a dummy file-system. @@ -6975,7 +7009,7 @@ static void DemoWindowTables() if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Item width")) + if (ImGui::TreeNode(Tr("Item width"))) { IMGUI_DEMO_MARKER("Tables/Item width"); HelpMarker( @@ -6984,9 +7018,9 @@ static void DemoWindowTables() "e.g. right-alignment doesn't make sense."); if (ImGui::BeginTable("table_item_width", 3, ImGuiTableFlags_Borders)) { - ImGui::TableSetupColumn("small"); - ImGui::TableSetupColumn("half"); - ImGui::TableSetupColumn("right-align"); + ImGui::TableSetupColumn(Tr("small")); + ImGui::TableSetupColumn(Tr("half")); + ImGui::TableSetupColumn(Tr("right-align")); ImGui::TableHeadersRow(); for (int row = 0; row < 3; row++) @@ -7022,15 +7056,15 @@ static void DemoWindowTables() // Demonstrate using TableHeader() calls instead of TableHeadersRow() if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Custom headers")) + if (ImGui::TreeNode(Tr("Custom headers"))) { IMGUI_DEMO_MARKER("Tables/Custom headers"); const int COLUMNS_COUNT = 3; if (ImGui::BeginTable("table_custom_headers", COLUMNS_COUNT, ImGuiTableFlags_Borders | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) { - ImGui::TableSetupColumn("Apricot"); - ImGui::TableSetupColumn("Banana"); - ImGui::TableSetupColumn("Cherry"); + ImGui::TableSetupColumn(Tr("Apricot")); + ImGui::TableSetupColumn(Tr("Banana")); + ImGui::TableSetupColumn(Tr("Cherry")); // Dummy entire-column selection storage // FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox. @@ -7075,7 +7109,7 @@ static void DemoWindowTables() // Demonstrate using ImGuiTableColumnFlags_AngledHeader flag to create angled headers if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Angled headers")) + if (ImGui::TreeNode(Tr("Angled headers"))) { IMGUI_DEMO_MARKER("Tables/Angled headers"); const char* column_names[] = { "Track", "cabasa", "ride", "smash", "tom-hi", "tom-mid", "tom-low", "hihat-o", "hihat-c", "snare-s", "snare-c", "clap", "rim", "kick" }; @@ -7099,7 +7133,7 @@ static void DemoWindowTables() ImGui::SliderInt("Frozen rows", &frozen_rows, 0, 2); ImGui::CheckboxFlags("Disable header contributing to column width", &column_flags, ImGuiTableColumnFlags_NoHeaderWidth); - if (ImGui::TreeNode("Style settings")) + if (ImGui::TreeNode(Tr("Style settings"))) { ImGui::SameLine(); HelpMarker("Giving access to some ImGuiStyle value in this demo for convenience."); @@ -7144,7 +7178,7 @@ static void DemoWindowTables() // while playing it nice with context menus provided by TableHeadersRow()/TableHeader() if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Context menus")) + if (ImGui::TreeNode(Tr("Context menus"))) { IMGUI_DEMO_MARKER("Tables/Context menus"); HelpMarker( @@ -7162,9 +7196,9 @@ static void DemoWindowTables() const int COLUMNS_COUNT = 3; if (ImGui::BeginTable("table_context_menu", COLUMNS_COUNT, flags1)) { - ImGui::TableSetupColumn("One"); - ImGui::TableSetupColumn("Two"); - ImGui::TableSetupColumn("Three"); + ImGui::TableSetupColumn(Tr("One")); + ImGui::TableSetupColumn(Tr("Two")); + ImGui::TableSetupColumn(Tr("Three")); // [1.1]] Right-click on the TableHeadersRow() line to open the default table context menu. ImGui::TableHeadersRow(); @@ -7192,9 +7226,9 @@ static void DemoWindowTables() ImGuiTableFlags flags2 = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders; if (ImGui::BeginTable("table_context_menu_2", COLUMNS_COUNT, flags2)) { - ImGui::TableSetupColumn("One"); - ImGui::TableSetupColumn("Two"); - ImGui::TableSetupColumn("Three"); + ImGui::TableSetupColumn(Tr("One")); + ImGui::TableSetupColumn(Tr("Two")); + ImGui::TableSetupColumn(Tr("Three")); // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu. ImGui::TableHeadersRow(); @@ -7214,7 +7248,7 @@ static void DemoWindowTables() if (ImGui::BeginPopupContextItem()) { ImGui::Text("This is the popup for Button(\"..\") in Cell %d,%d", column, row); - if (ImGui::Button("Close")) + if (ImGui::Button(Tr("Close"))) ImGui::CloseCurrentPopup(); ImGui::EndPopup(); } @@ -7239,7 +7273,7 @@ static void DemoWindowTables() ImGui::Text("This is a custom popup for unused space after the last column."); else ImGui::Text("This is a custom popup for Column %d", column); - if (ImGui::Button("Close")) + if (ImGui::Button(Tr("Close"))) ImGui::CloseCurrentPopup(); ImGui::EndPopup(); } @@ -7255,7 +7289,7 @@ static void DemoWindowTables() // Demonstrate creating multiple tables with the same ID if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Synced instances")) + if (ImGui::TreeNode(Tr("Synced instances"))) { IMGUI_DEMO_MARKER("Tables/Synced instances"); HelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc."); @@ -7272,9 +7306,9 @@ static void DemoWindowTables() bool open = ImGui::CollapsingHeader(buf, ImGuiTreeNodeFlags_DefaultOpen); if (open && ImGui::BeginTable("Table", 3, flags, ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 5))) { - ImGui::TableSetupColumn("One"); - ImGui::TableSetupColumn("Two"); - ImGui::TableSetupColumn("Three"); + ImGui::TableSetupColumn(Tr("One")); + ImGui::TableSetupColumn(Tr("Two")); + ImGui::TableSetupColumn(Tr("Three")); ImGui::TableHeadersRow(); const int cell_count = (n == 1) ? 27 : 9; // Make second table have a scrollbar to verify that additional decoration is not affecting column positions. for (int cell = 0; cell < cell_count; cell++) @@ -7298,7 +7332,7 @@ static void DemoWindowTables() }; if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Sorting")) + if (ImGui::TreeNode(Tr("Sorting"))) { IMGUI_DEMO_MARKER("Tables/Sorting"); // Create item list @@ -7337,10 +7371,10 @@ static void DemoWindowTables() // - ImGuiTableColumnFlags_DefaultSort // - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / ImGuiTableColumnFlags_NoSortDescending // - ImGuiTableColumnFlags_PreferSortAscending / ImGuiTableColumnFlags_PreferSortDescending - ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_ID); - ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name); - ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action); - ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, 0.0f, MyItemColumnID_Quantity); + ImGui::TableSetupColumn(Tr("ID"), ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_ID); + ImGui::TableSetupColumn(Tr("Name"), ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name); + ImGui::TableSetupColumn(Tr("Action"), ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action); + ImGui::TableSetupColumn(Tr("Quantity"), ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, 0.0f, MyItemColumnID_Quantity); ImGui::TableSetupScrollFreeze(0, 1); // Make row always visible ImGui::TableHeadersRow(); @@ -7383,7 +7417,7 @@ static void DemoWindowTables() //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // [DEBUG] if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); - if (ImGui::TreeNode("Advanced")) + if (ImGui::TreeNode(Tr("Advanced"))) { IMGUI_DEMO_MARKER("Tables/Advanced"); static ImGuiTableFlags flags = @@ -7408,7 +7442,7 @@ static void DemoWindowTables() static bool show_wrapped_text = false; //static ImGuiTextFilter filter; //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // FIXME-TABLE: Enabling this results in initial clipped first pass on table which tend to affect column sizing - if (ImGui::TreeNode("Options")) + if (ImGui::TreeNode(Tr("Options"))) { // Make the UI compact because there are so many fields PushStyleCompact(); @@ -7557,11 +7591,11 @@ static void DemoWindowTables() // Declare columns // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! - ImGui::TableSetupColumn("ID", columns_base_flags | ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, 0.0f, MyItemColumnID_ID); - ImGui::TableSetupColumn("Name", columns_base_flags | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name); - ImGui::TableSetupColumn("Action", columns_base_flags | ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action); - ImGui::TableSetupColumn("Quantity", columns_base_flags | ImGuiTableColumnFlags_PreferSortDescending, 0.0f, MyItemColumnID_Quantity); - ImGui::TableSetupColumn("Description", columns_base_flags | ((flags & ImGuiTableFlags_NoHostExtendX) ? 0 : ImGuiTableColumnFlags_WidthStretch), 0.0f, MyItemColumnID_Description); + ImGui::TableSetupColumn(Tr("ID"), columns_base_flags | ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, 0.0f, MyItemColumnID_ID); + ImGui::TableSetupColumn(Tr("Name"), columns_base_flags | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name); + ImGui::TableSetupColumn(Tr("Action"), columns_base_flags | ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action); + ImGui::TableSetupColumn(Tr("Quantity"), columns_base_flags | ImGuiTableColumnFlags_PreferSortDescending, 0.0f, MyItemColumnID_Quantity); + ImGui::TableSetupColumn(Tr("Description"), columns_base_flags | ((flags & ImGuiTableFlags_NoHostExtendX) ? 0 : ImGuiTableColumnFlags_WidthStretch), 0.0f, MyItemColumnID_Description); ImGui::TableSetupColumn("Hidden", columns_base_flags | ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort); ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows); @@ -7707,17 +7741,17 @@ static void DemoWindowTables() // [2020: Columns are under-featured and not maintained. Prefer using the more flexible and powerful BeginTable() API!] static void DemoWindowColumns() { - bool open = ImGui::TreeNode("Legacy Columns API"); + bool open = ImGui::TreeNode(Tr("Legacy Columns API")); ImGui::SameLine(); HelpMarker("Columns() is an old API! Prefer using the more flexible and powerful BeginTable() API!"); if (!open) return; // Basic columns - if (ImGui::TreeNode("Basic")) + if (ImGui::TreeNode(Tr("Basic"))) { IMGUI_DEMO_MARKER("Columns (legacy API)/Basic"); - ImGui::Text("Without border:"); + ImGui::Text(Tr("Without border:")); ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border ImGui::Separator(); for (int n = 0; n < 14; n++) @@ -7731,13 +7765,13 @@ static void DemoWindowColumns() ImGui::Columns(1); ImGui::Separator(); - ImGui::Text("With border:"); + ImGui::Text(Tr("With border:")); ImGui::Columns(4, "mycolumns"); // 4-ways, with border ImGui::Separator(); - ImGui::Text("ID"); ImGui::NextColumn(); - ImGui::Text("Name"); ImGui::NextColumn(); - ImGui::Text("Path"); ImGui::NextColumn(); - ImGui::Text("Hovered"); ImGui::NextColumn(); + ImGui::Text(Tr("ID")); ImGui::NextColumn(); + ImGui::Text(Tr("Name")); ImGui::NextColumn(); + ImGui::Text(Tr("Path")); ImGui::NextColumn(); + ImGui::Text(Tr("Hovered")); ImGui::NextColumn(); ImGui::Separator(); const char* names[3] = { "One", "Two", "Three" }; const char* paths[3] = { "/path/one", "/path/two", "/path/three" }; @@ -7759,7 +7793,7 @@ static void DemoWindowColumns() ImGui::TreePop(); } - if (ImGui::TreeNode("Borders")) + if (ImGui::TreeNode(Tr("Borders"))) { IMGUI_DEMO_MARKER("Columns (legacy API)/Borders"); // NB: Future columns API should allow automatic horizontal borders. @@ -7772,9 +7806,9 @@ static void DemoWindowColumns() if (columns_count < 2) columns_count = 2; ImGui::SameLine(); - ImGui::Checkbox("horizontal", &h_borders); + ImGui::Checkbox(Tr("horizontal"), &h_borders); ImGui::SameLine(); - ImGui::Checkbox("vertical", &v_borders); + ImGui::Checkbox(Tr("vertical"), &v_borders); ImGui::Columns(columns_count, NULL, v_borders); for (int i = 0; i < columns_count * lines_count; i++) { @@ -7785,7 +7819,7 @@ static void DemoWindowColumns() ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x); ImGui::Text("Offset %.2f", ImGui::GetColumnOffset()); - ImGui::Text("Long text that is likely to clip"); + ImGui::Text(Tr("Long text that is likely to clip")); ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f)); ImGui::PopID(); ImGui::NextColumn(); @@ -7797,39 +7831,39 @@ static void DemoWindowColumns() } // Create multiple items in a same cell before switching to next column - if (ImGui::TreeNode("Mixed items")) + if (ImGui::TreeNode(Tr("Mixed items"))) { IMGUI_DEMO_MARKER("Columns (legacy API)/Mixed items"); ImGui::Columns(3, "mixed"); ImGui::Separator(); - ImGui::Text("Hello"); - ImGui::Button("Banana"); + ImGui::Text(Tr("Hello")); + ImGui::Button(Tr("Banana")); ImGui::NextColumn(); ImGui::Text("ImGui"); - ImGui::Button("Apple"); + ImGui::Button(Tr("Apple")); static float foo = 1.0f; ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f"); - ImGui::Text("An extra line here."); + ImGui::Text(Tr("An extra line here.")); ImGui::NextColumn(); - ImGui::Text("Sailor"); - ImGui::Button("Corniflower"); + ImGui::Text(Tr("Sailor")); + ImGui::Button(Tr("Corniflower")); static float bar = 1.0f; ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f"); ImGui::NextColumn(); - if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); - if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); - if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); + if (ImGui::CollapsingHeader(Tr("Category A"))) { ImGui::Text(Tr("Blah blah blah")); } ImGui::NextColumn(); + if (ImGui::CollapsingHeader(Tr("Category B"))) { ImGui::Text(Tr("Blah blah blah")); } ImGui::NextColumn(); + if (ImGui::CollapsingHeader(Tr("Category C"))) { ImGui::Text(Tr("Blah blah blah")); } ImGui::NextColumn(); ImGui::Columns(1); ImGui::Separator(); ImGui::TreePop(); } // Word wrapping - if (ImGui::TreeNode("Word-wrapping")) + if (ImGui::TreeNode(Tr("Word-wrapping"))) { IMGUI_DEMO_MARKER("Columns (legacy API)/Word-wrapping"); ImGui::Columns(2, "word-wrapping"); @@ -7844,7 +7878,7 @@ static void DemoWindowColumns() ImGui::TreePop(); } - if (ImGui::TreeNode("Horizontal Scrolling")) + if (ImGui::TreeNode(Tr("Horizontal Scrolling"))) { IMGUI_DEMO_MARKER("Columns (legacy API)/Horizontal Scrolling"); ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f)); @@ -7870,7 +7904,7 @@ static void DemoWindowColumns() ImGui::TreePop(); } - if (ImGui::TreeNode("Tree")) + if (ImGui::TreeNode(Tr("Tree"))) { IMGUI_DEMO_MARKER("Columns (legacy API)/Tree"); ImGui::Columns(2, "tree", true); @@ -7878,7 +7912,7 @@ static void DemoWindowColumns() { bool open1 = ImGui::TreeNode((void*)(intptr_t)x, "Node%d", x); ImGui::NextColumn(); - ImGui::Text("Node contents"); + ImGui::Text(Tr("Node contents")); ImGui::NextColumn(); if (open1) { @@ -7886,13 +7920,13 @@ static void DemoWindowColumns() { bool open2 = ImGui::TreeNode((void*)(intptr_t)y, "Node%d.%d", x, y); ImGui::NextColumn(); - ImGui::Text("Node contents"); + ImGui::Text(Tr("Node contents")); if (open2) { - ImGui::Text("Even more contents"); - if (ImGui::TreeNode("Tree in column")) + ImGui::Text(Tr("Even more contents")); + if (ImGui::TreeNode(Tr("Tree in column"))) { - ImGui::Text("The quick brown fox jumps over the lazy dog"); + ImGui::Text(Tr("The quick brown fox jumps over the lazy dog")); ImGui::TreePop(); } } @@ -7916,30 +7950,30 @@ static void DemoWindowColumns() static void DemoWindowInputs() { - if (ImGui::CollapsingHeader("Inputs & Focus")) + if (ImGui::CollapsingHeader(Tr("Inputs & Focus"))) { ImGuiIO& io = ImGui::GetIO(); // Display inputs submitted to ImGuiIO ImGui::SetNextItemOpen(true, ImGuiCond_Once); - bool inputs_opened = ImGui::TreeNode("Inputs"); + bool inputs_opened = ImGui::TreeNode(Tr("Inputs")); ImGui::SameLine(); - HelpMarker( + HelpMarker(Tr( "This is a simplified view. See more detailed input state:\n" "- in 'Tools->Metrics/Debugger->Inputs'.\n" - "- in 'Tools->Debug Log->IO'."); + "- in 'Tools->Debug Log->IO'.")); if (inputs_opened) { IMGUI_DEMO_MARKER("Inputs & Focus/Inputs"); if (ImGui::IsMousePosValid()) - ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y); + ImGui::Text(Tr("Mouse pos: (%g, %g)"), io.MousePos.x, io.MousePos.y); else - ImGui::Text("Mouse pos: "); - ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); - ImGui::Text("Mouse down:"); + ImGui::Text(Tr("Mouse pos: ")); + ImGui::Text(Tr("Mouse delta: (%g, %g)"), io.MouseDelta.x, io.MouseDelta.y); + ImGui::Text(Tr("Mouse down:")); for (int i = 0; i < IM_COUNTOF(io.MouseDown); i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } - ImGui::Text("Mouse wheel: %.1f", io.MouseWheel); - ImGui::Text("Mouse clicked count:"); + ImGui::Text(Tr("Mouse wheel: %.1f"), io.MouseWheel); + ImGui::Text(Tr("Mouse clicked count:")); for (int i = 0; i < IM_COUNTOF(io.MouseDown); i++) if (io.MouseClickedCount[i] > 0) { ImGui::SameLine(); ImGui::Text("b%d: %d", i, io.MouseClickedCount[i]); } // We iterate both legacy native range and named ImGuiKey ranges. This is a little unusual/odd but this allows @@ -7948,16 +7982,16 @@ static void DemoWindowInputs() // You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END. struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } }; ImGuiKey start_key = ImGuiKey_NamedKey_BEGIN; - ImGui::Text("Keys down:"); for (ImGuiKey key = start_key; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !ImGui::IsKeyDown(key)) continue; ImGui::SameLine(); ImGui::Text((key < ImGuiKey_NamedKey_BEGIN) ? "\"%s\"" : "\"%s\" %d", ImGui::GetKeyName(key), key); } - ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); - ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. + ImGui::Text(Tr("Keys down:")); for (ImGuiKey key = start_key; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !ImGui::IsKeyDown(key)) continue; ImGui::SameLine(); ImGui::Text((key < ImGuiKey_NamedKey_BEGIN) ? "\"%s\"" : "\"%s\" %d", ImGui::GetKeyName(key), key); } + ImGui::Text(Tr("Keys mods: %s%s%s%s"), io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); + ImGui::Text(Tr("Chars queue:")); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. ImGui::TreePop(); } // Display ImGuiIO output flags ImGui::SetNextItemOpen(true, ImGuiCond_Once); - bool outputs_opened = ImGui::TreeNode("Outputs"); + bool outputs_opened = ImGui::TreeNode(Tr("Outputs")); ImGui::SameLine(); HelpMarker( "The value of io.WantCaptureMouse and io.WantCaptureKeyboard are normally set by Dear ImGui " @@ -7977,19 +8011,19 @@ static void DemoWindowInputs() ImGui::Text("io.NavActive: %d, io.NavVisible: %d", io.NavActive, io.NavVisible); IMGUI_DEMO_MARKER("Inputs & Focus/Outputs/WantCapture override"); - if (ImGui::TreeNode("WantCapture override")) + if (ImGui::TreeNode(Tr("WantCapture override"))) { - HelpMarker( + HelpMarker(Tr( "Hovering the colored canvas will override io.WantCaptureXXX fields.\n" "Notice how normally (when set to none), the value of io.WantCaptureKeyboard would be false when hovering " - "and true when clicking."); + "and true when clicking.")); static int capture_override_mouse = -1; static int capture_override_keyboard = -1; - const char* capture_override_desc[] = { "None", "Set to false", "Set to true" }; + const char* capture_override_desc[] = { Tr("None"), Tr("Set to false"), Tr("Set to true") }; ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15); - ImGui::SliderInt("SetNextFrameWantCaptureMouse() on hover", &capture_override_mouse, -1, +1, capture_override_desc[capture_override_mouse + 1], ImGuiSliderFlags_AlwaysClamp); + ImGui::SliderInt(Tr("SetNextFrameWantCaptureMouse() on hover"), &capture_override_mouse, -1, +1, capture_override_desc[capture_override_mouse + 1], ImGuiSliderFlags_AlwaysClamp); ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15); - ImGui::SliderInt("SetNextFrameWantCaptureKeyboard() on hover", &capture_override_keyboard, -1, +1, capture_override_desc[capture_override_keyboard + 1], ImGuiSliderFlags_AlwaysClamp); + ImGui::SliderInt(Tr("SetNextFrameWantCaptureKeyboard() on hover"), &capture_override_keyboard, -1, +1, capture_override_desc[capture_override_keyboard + 1], ImGuiSliderFlags_AlwaysClamp); ImGui::ColorButton("##panel", ImVec4(0.7f, 0.1f, 0.7f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, ImVec2(128.0f, 96.0f)); // Dummy item if (ImGui::IsItemHovered() && capture_override_mouse != -1) @@ -8012,7 +8046,7 @@ static void DemoWindowInputs() // - If you call Shortcut() WITHOUT any routing option, it uses ImGuiInputFlags_RouteFocused. // TL;DR: Most uses will simply be: // - Shortcut(ImGuiMod_Ctrl | ImGuiKey_A); // Use ImGuiInputFlags_RouteFocused policy. - if (ImGui::TreeNode("Shortcuts")) + if (ImGui::TreeNode(Tr("Shortcuts"))) { IMGUI_DEMO_MARKER("Inputs & Focus/Shortcuts"); static ImGuiInputFlags route_options = ImGuiInputFlags_Repeat; @@ -8038,16 +8072,16 @@ static void DemoWindowInputs() if (route_type != ImGuiInputFlags_RouteGlobal) flags &= ~(ImGuiInputFlags_RouteOverFocused | ImGuiInputFlags_RouteOverActive | ImGuiInputFlags_RouteUnlessBgFocused); - ImGui::SeparatorText("Using SetNextItemShortcut()"); + ImGui::SeparatorText(Tr("Using SetNextItemShortcut()")); ImGui::Text("Ctrl+S"); ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_S, flags | ImGuiInputFlags_Tooltip); - ImGui::Button("Save"); + ImGui::Button(Tr("Save")); ImGui::Text("Alt+F"); ImGui::SetNextItemShortcut(ImGuiMod_Alt | ImGuiKey_F, flags | ImGuiInputFlags_Tooltip); static float f = 0.5f; - ImGui::SliderFloat("Factor", &f, 0.0f, 1.0f); + ImGui::SliderFloat(Tr("Factor"), &f, 0.0f, 1.0f); - ImGui::SeparatorText("Using Shortcut()"); + ImGui::SeparatorText(Tr("Using Shortcut()")); const float line_height = ImGui::GetTextLineHeightWithSpacing(); const ImGuiKeyChord key_chord = ImGuiMod_Ctrl | ImGuiKey_A; @@ -8057,7 +8091,7 @@ static void DemoWindowInputs() ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 0.0f, 1.0f, 0.1f)); ImGui::BeginChild("WindowA", ImVec2(-FLT_MIN, line_height * 14), true); - ImGui::Text("Press Ctrl+A and see who receives it!"); + ImGui::Text(Tr("Press Ctrl+A and see who receives it!")); ImGui::Separator(); // 1: Window polling for Ctrl+A @@ -8104,7 +8138,7 @@ static void DemoWindowInputs() } // Display mouse cursors - if (ImGui::TreeNode("Mouse Cursors")) + if (ImGui::TreeNode(Tr("Mouse Cursors"))) { IMGUI_DEMO_MARKER("Inputs & Focus/Mouse Cursors"); const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "Wait", "Progress", "NotAllowed" }; @@ -8112,12 +8146,12 @@ static void DemoWindowInputs() ImGuiMouseCursor current = ImGui::GetMouseCursor(); const char* cursor_name = (current >= ImGuiMouseCursor_Arrow) && (current < ImGuiMouseCursor_COUNT) ? mouse_cursors_names[current] : "N/A"; - ImGui::Text("Current mouse cursor = %d: %s", current, cursor_name); + ImGui::Text(Tr("Current mouse cursor = %d: %s"), current, cursor_name); ImGui::BeginDisabled(true); ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors); ImGui::EndDisabled(); - ImGui::Text("Hover to see mouse cursors:"); + ImGui::Text(Tr("Hover to see mouse cursors:")); ImGui::SameLine(); HelpMarker( "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. " "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, " @@ -8133,10 +8167,10 @@ static void DemoWindowInputs() ImGui::TreePop(); } - if (ImGui::TreeNode("Tabbing")) + if (ImGui::TreeNode(Tr("Tabbing"))) { IMGUI_DEMO_MARKER("Inputs & Focus/Tabbing"); - ImGui::Text("Use Tab/Shift+Tab to cycle through keyboard editable fields."); + ImGui::Text(Tr("Use Tab/Shift+Tab to cycle through keyboard editable fields.")); static char buf[32] = "hello"; ImGui::InputText("1", buf, IM_COUNTOF(buf)); ImGui::InputText("2", buf, IM_COUNTOF(buf)); @@ -8149,12 +8183,12 @@ static void DemoWindowInputs() ImGui::TreePop(); } - if (ImGui::TreeNode("Focus from code")) + if (ImGui::TreeNode(Tr("Focus from code"))) { IMGUI_DEMO_MARKER("Inputs & Focus/Focus from code"); - bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine(); - bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine(); - bool focus_3 = ImGui::Button("Focus on 3"); + bool focus_1 = ImGui::Button(Tr("Focus on 1")); ImGui::SameLine(); + bool focus_2 = ImGui::Button(Tr("Focus on 2")); ImGui::SameLine(); + bool focus_3 = ImGui::Button(Tr("Focus on 3")); int has_focus = 0; static char buf[128] = "click on a button to set focus"; @@ -8181,9 +8215,9 @@ static void DemoWindowInputs() // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item static float f3[3] = { 0.0f, 0.0f, 0.0f }; int focus_ahead = -1; - if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine(); - if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine(); - if (ImGui::Button("Focus on Z")) { focus_ahead = 2; } + if (ImGui::Button(Tr("Focus on X"))) { focus_ahead = 0; } ImGui::SameLine(); + if (ImGui::Button(Tr("Focus on Y"))) { focus_ahead = 1; } ImGui::SameLine(); + if (ImGui::Button(Tr("Focus on Z"))) { focus_ahead = 2; } if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead); ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f); @@ -8191,7 +8225,7 @@ static void DemoWindowInputs() ImGui::TreePop(); } - if (ImGui::TreeNode("Dragging")) + if (ImGui::TreeNode(Tr("Dragging"))) { IMGUI_DEMO_MARKER("Inputs & Focus/Dragging"); ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget."); @@ -8213,7 +8247,7 @@ static void DemoWindowInputs() ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f); ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0); ImVec2 mouse_delta = io.MouseDelta; - ImGui::Text("GetMouseDragDelta(0):"); + ImGui::Text(Tr("GetMouseDragDelta(0):")); ImGui::Text(" w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y); ImGui::Text(" w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y); ImGui::Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y); @@ -8229,7 +8263,7 @@ static void DemoWindowInputs() void ImGui::ShowAboutWindow(bool* p_open) { - if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize)) + if (!ImGui::Begin(Tr("About Dear ImGui"), p_open, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::End(); return; @@ -8256,7 +8290,7 @@ void ImGui::ShowAboutWindow(bool* p_open) ImGui::Text("If your company uses this, please consider funding the project."); static bool show_config_info = false; - ImGui::Checkbox("Config/Build Information", &show_config_info); + ImGui::Checkbox(Tr("Build Information:"), &show_config_info); if (show_config_info) { ImGuiIO& io = ImGui::GetIO(); @@ -8488,11 +8522,11 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) { // General - SeparatorText("General"); + SeparatorText(Tr("General")); if ((GetIO().BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0) { BulletText("Warning: Font scaling will NOT be smooth, because\nImGuiBackendFlags_RendererHasTextures is not set!"); - BulletText("For instructions, see:"); + BulletText(Tr("For instructions, see:")); SameLine(); TextLinkOpenURL("docs/BACKENDS.md", "https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md"); } @@ -8520,20 +8554,20 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) } // Save/Revert button - if (Button("Save Ref")) + if (Button(Tr("Save Ref"))) *ref = ref_saved_style = style; SameLine(); - if (Button("Revert Ref")) + if (Button(Tr("Revert Ref"))) style = *ref; SameLine(); HelpMarker( "Save/Revert in local non-persistent storage. Default Colors definition are not affected. " "Use \"Export\" below to save them somewhere."); - SeparatorText("Details"); + SeparatorText(Tr("Details")); if (BeginTabBar("##tabs", ImGuiTabBarFlags_None)) { - if (BeginTabItem("Sizes")) + if (BeginTabItem(Tr("Sizes"))) { SeparatorText("Main"); SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); @@ -8635,11 +8669,11 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) EndTabItem(); } - if (BeginTabItem("Colors")) + if (BeginTabItem(Tr("Colors"))) { static int output_dest = 0; static bool output_only_modified = true; - if (Button("Export")) + if (Button(Tr("Export"))) { if (output_dest == 0) LogToClipboard(); @@ -8657,15 +8691,15 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) LogFinish(); } SameLine(); SetNextItemWidth(GetFontSize() * 10); Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); - SameLine(); Checkbox("Only Modified Colors", &output_only_modified); + SameLine(); Checkbox(Tr("Only Modified Colors"), &output_only_modified); static ImGuiTextFilter filter; - filter.Draw("Filter colors", GetFontSize() * 16); + filter.Draw(Tr("Filter colors"), GetFontSize() * 16); static ImGuiColorEditFlags alpha_flags = 0; - if (RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_AlphaOpaque)) { alpha_flags = ImGuiColorEditFlags_AlphaOpaque; } SameLine(); - if (RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } SameLine(); - if (RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } SameLine(); + if (RadioButton(Tr("Opaque"), alpha_flags == ImGuiColorEditFlags_AlphaOpaque)) { alpha_flags = ImGuiColorEditFlags_AlphaOpaque; } SameLine(); + if (RadioButton(Tr("Alpha"), alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } SameLine(); + if (RadioButton(Tr("Both"), alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } SameLine(); HelpMarker( "In the color list:\n" "Left-click on color square to open color picker,\n" @@ -8692,8 +8726,8 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) // Tips: in a real user application, you may want to merge and use an icon font into the main font, // so instead of "Save"/"Revert" you'd use icons! // Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient! - SameLine(0.0f, style.ItemInnerSpacing.x); if (Button("Save")) { ref->Colors[i] = style.Colors[i]; } - SameLine(0.0f, style.ItemInnerSpacing.x); if (Button("Revert")) { style.Colors[i] = ref->Colors[i]; } + SameLine(0.0f, style.ItemInnerSpacing.x); if (Button(Tr("Save"))) { ref->Colors[i] = style.Colors[i]; } + SameLine(0.0f, style.ItemInnerSpacing.x); if (Button(Tr("Revert"))) { style.Colors[i] = ref->Colors[i]; } } SameLine(0.0f, style.ItemInnerSpacing.x); TextUnformatted(name); @@ -8705,7 +8739,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) EndTabItem(); } - if (BeginTabItem("Fonts")) + if (BeginTabItem(Tr("Fonts"))) { ImGuiIO& io = GetIO(); ImFontAtlas* atlas = io.Fonts; @@ -8733,23 +8767,23 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) EndTabItem(); } - if (BeginTabItem("Rendering")) + if (BeginTabItem(Tr("Rendering"))) { - Checkbox("Anti-aliased lines", &style.AntiAliasedLines); + Checkbox(Tr("Anti-aliased lines"), &style.AntiAliasedLines); SameLine(); HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well."); - Checkbox("Anti-aliased lines use texture", &style.AntiAliasedLinesUseTex); + Checkbox(Tr("Anti-aliased lines use texture"), &style.AntiAliasedLinesUseTex); SameLine(); HelpMarker("Faster lines using texture data. Require backend to render with bilinear filtering (not point/nearest filtering)."); - Checkbox("Anti-aliased fill", &style.AntiAliasedFill); + Checkbox(Tr("Anti-aliased fill"), &style.AntiAliasedFill); PushItemWidth(GetFontSize() * 8); - DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f"); + DragFloat(Tr("Curve Tessellation Tolerance"), &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f"); if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f; // When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles. - DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError , 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp); + DragFloat(Tr("Circle Tessellation Max Error"), &style.CircleTessellationMaxError , 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp); const bool show_samples = IsItemActive(); if (show_samples) SetNextWindowPos(GetCursorScreenPos()); @@ -8864,21 +8898,21 @@ static void ShowExampleAppMainMenuBar() { if (ImGui::BeginMainMenuBar()) { - if (ImGui::BeginMenu("File")) + if (ImGui::BeginMenu(Tr("File"))) { IMGUI_DEMO_MARKER("Menu/File"); ShowExampleMenuFile(); ImGui::EndMenu(); } - if (ImGui::BeginMenu("Edit")) + if (ImGui::BeginMenu(Tr("Edit"))) { IMGUI_DEMO_MARKER("Menu/Edit"); - if (ImGui::MenuItem("Undo", "Ctrl+Z")) {} - if (ImGui::MenuItem("Redo", "Ctrl+Y", false, false)) {} // Disabled item + if (ImGui::MenuItem(Tr("Undo"), "Ctrl+Z")) {} + if (ImGui::MenuItem(Tr("Redo"), "Ctrl+Y", false, false)) {} // Disabled item ImGui::Separator(); - if (ImGui::MenuItem("Cut", "Ctrl+X")) {} - if (ImGui::MenuItem("Copy", "Ctrl+C")) {} - if (ImGui::MenuItem("Paste", "Ctrl+V")) {} + if (ImGui::MenuItem(Tr("Cut"), "Ctrl+X")) {} + if (ImGui::MenuItem(Tr("Copy"), "Ctrl+C")) {} + if (ImGui::MenuItem(Tr("Paste"), "Ctrl+V")) {} ImGui::EndMenu(); } ImGui::EndMainMenuBar(); @@ -9055,7 +9089,7 @@ struct ExampleAppConsole ImGui::TextWrapped( "This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate " "implementation may want to store entries along with extra data such as timestamp, emitter, etc."); - ImGui::TextWrapped("Enter 'HELP' for help."); + ImGui::TextWrapped("%s", Tr("Enter 'HELP' for help.")); // TODO: display items starting from the bottom @@ -9063,9 +9097,9 @@ struct ExampleAppConsole ImGui::SameLine(); if (ImGui::SmallButton("Add Debug Error")) { AddLog("[error] something went wrong"); } ImGui::SameLine(); - if (ImGui::SmallButton("Clear")) { ClearLog(); } + if (ImGui::SmallButton(Tr("Clear"))) { ClearLog(); } ImGui::SameLine(); - bool copy_to_clipboard = ImGui::SmallButton("Copy"); + bool copy_to_clipboard = ImGui::SmallButton(Tr("Copy")); //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); } ImGui::Separator(); @@ -9073,7 +9107,7 @@ struct ExampleAppConsole // Options menu if (ImGui::BeginPopup("Options")) { - ImGui::Checkbox("Auto-scroll", &AutoScroll); + ImGui::Checkbox(Tr("Auto-scroll"), &AutoScroll); ImGui::EndPopup(); } @@ -9329,7 +9363,7 @@ struct ExampleAppConsole static void ShowExampleAppConsole(bool* p_open) { static ExampleAppConsole console; - console.Draw("Example: Console", p_open); + console.Draw(Tr("Example: Console"), p_open); } //----------------------------------------------------------------------------- @@ -9405,7 +9439,7 @@ struct ExampleAppLog // Options menu if (ImGui::BeginPopup("Options")) { - ImGui::Checkbox("Auto-scroll", &AutoScroll); + ImGui::Checkbox(Tr("Auto-scroll"), &AutoScroll); ImGui::EndPopup(); } @@ -9413,9 +9447,9 @@ struct ExampleAppLog if (ImGui::Button("Options")) ImGui::OpenPopup("Options"); ImGui::SameLine(); - bool clear = ImGui::Button("Clear"); + bool clear = ImGui::Button(Tr("Clear")); ImGui::SameLine(); - bool copy = ImGui::Button("Copy"); + bool copy = ImGui::Button(Tr("Copy")); ImGui::SameLine(); Filter.Draw("Filter", -100.0f); @@ -9494,7 +9528,7 @@ static void ShowExampleAppLog(bool* p_open) // We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window. // Most of the contents of the window will be added by the log.Draw() call. ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver); - ImGui::Begin("Example: Log", p_open); + ImGui::Begin(Tr("Example: Log"), p_open); IMGUI_DEMO_MARKER("Examples/Log"); if (ImGui::SmallButton("[Debug] Add 5 entries")) { @@ -9513,7 +9547,7 @@ static void ShowExampleAppLog(bool* p_open) ImGui::End(); // Actually call in the regular Log helper (which will Begin() into the same window as we just did) - log.Draw("Example: Log", p_open); + log.Draw(Tr("Example: Log"), p_open); } //----------------------------------------------------------------------------- @@ -9524,7 +9558,7 @@ static void ShowExampleAppLog(bool* p_open) static void ShowExampleAppLayout(bool* p_open) { ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver); - if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar)) + if (ImGui::Begin(Tr("Example: Simple layout"), p_open, ImGuiWindowFlags_MenuBar)) { IMGUI_DEMO_MARKER("Examples/Simple layout"); if (ImGui::BeginMenuBar()) @@ -9573,9 +9607,9 @@ static void ShowExampleAppLayout(bool* p_open) ImGui::EndTabBar(); } ImGui::EndChild(); - if (ImGui::Button("Revert")) {} + if (ImGui::Button(Tr("Revert"))) {} ImGui::SameLine(); - if (ImGui::Button("Save")) {} + if (ImGui::Button(Tr("Save"))) {} ImGui::EndGroup(); } } @@ -9607,7 +9641,7 @@ struct ExampleAppPropertyEditor if (ImGui::BeginChild("##tree", ImVec2(300, 0), ImGuiChildFlags_ResizeX | ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened)) { ImGui::PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true); - ImGui::Checkbox("Use Clipper", &UseClipper); + ImGui::Checkbox(Tr("Use Clipper"), &UseClipper); ImGui::SameLine(); ImGui::Text("(%d root nodes)", root_node->Childs.Size); ImGui::SetNextItemWidth(-FLT_MIN); @@ -9816,7 +9850,7 @@ struct ExampleAppPropertyEditor static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data) { ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver); - if (!ImGui::Begin("Example: Property editor", p_open)) + if (!ImGui::Begin(Tr("Example: Property editor"), p_open)) { ImGui::End(); return; @@ -9839,7 +9873,7 @@ static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo static void ShowExampleAppLongText(bool* p_open) { ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); - if (!ImGui::Begin("Example: Long text display", p_open)) + if (!ImGui::Begin(Tr("Example: Long text display"), p_open)) { ImGui::End(); return; @@ -9849,13 +9883,13 @@ static void ShowExampleAppLongText(bool* p_open) static int test_type = 0; static ImGuiTextBuffer log; static int lines = 0; - ImGui::Text("Printing unusually long amount of text."); - ImGui::Combo("Test type", &test_type, + ImGui::Text("%s", Tr("Printing unusually long amount of text.")); + ImGui::Combo(Tr("Test type"), &test_type, "Single call to TextUnformatted()\0" "Multiple calls to Text(), clipped\0" "Multiple calls to Text(), not clipped (slow)\0"); ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size()); - if (ImGui::Button("Clear")) { log.clear(); lines = 0; } + if (ImGui::Button(Tr("Clear"))) { log.clear(); lines = 0; } ImGui::SameLine(); if (ImGui::Button("Add 1000 lines")) { @@ -9901,7 +9935,7 @@ static void ShowExampleAppLongText(bool* p_open) // Demonstrate creating a window which gets auto-resized according to its content. static void ShowExampleAppAutoResize(bool* p_open) { - if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize)) + if (!ImGui::Begin(Tr("Example: Auto-resizing window"), p_open, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::End(); return; @@ -9984,7 +10018,7 @@ static void ShowExampleAppConstrainedResize(bool* p_open) if (!window_padding) ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); const ImGuiWindowFlags window_flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0; - const bool window_open = ImGui::Begin("Example: Constrained Resize", p_open, window_flags); + const bool window_open = ImGui::Begin(Tr("Example: Constrained Resize"), p_open, window_flags); if (!window_padding) ImGui::PopStyleVar(); IMGUI_DEMO_MARKER("Examples/Constrained Resizing window"); @@ -10001,15 +10035,15 @@ static void ShowExampleAppConstrainedResize(bool* p_open) } else { - ImGui::Text("(Hold Shift to display a dummy viewport)"); + ImGui::Text("%s", Tr("(Hold Shift to display a dummy viewport)")); if (ImGui::Button("Set 200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine(); if (ImGui::Button("Set 500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine(); if (ImGui::Button("Set 800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); } ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20); - ImGui::Combo("Constraint", &type, test_desc, IM_COUNTOF(test_desc)); + ImGui::Combo(Tr("Constraint"), &type, test_desc, IM_COUNTOF(test_desc)); ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20); ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100); - ImGui::Checkbox("Auto-resize", &auto_resize); + ImGui::Checkbox(Tr("Auto-resize"), &auto_resize); ImGui::Checkbox("Window padding", &window_padding); for (int i = 0; i < display_lines; i++) ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, ""); @@ -10050,15 +10084,15 @@ static void ShowExampleAppSimpleOverlay(bool* p_open) window_flags |= ImGuiWindowFlags_NoMove; } ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background - if (ImGui::Begin("Example: Simple overlay", p_open, window_flags)) + if (ImGui::Begin(Tr("Example: Simple overlay"), p_open, window_flags)) { IMGUI_DEMO_MARKER("Examples/Simple overlay"); // Scroll up to the beginning of this function to see overlay flags - ImGui::Text("Simple overlay\n" "(right-click to change position)"); + ImGui::Text("%s", Tr("Simple overlay\n(right-click to change position)")); ImGui::Separator(); if (ImGui::IsMousePosValid()) ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y); else - ImGui::Text("Mouse Position: "); + ImGui::Text("%s", Tr("Mouse Position: ")); if (ImGui::BeginPopupContextWindow()) { if (ImGui::MenuItem("Custom", NULL, location == -1)) location = -1; @@ -10090,10 +10124,10 @@ static void ShowExampleAppFullscreen(bool* p_open) ImGui::SetNextWindowPos(use_work_area ? viewport->WorkPos : viewport->Pos); ImGui::SetNextWindowSize(use_work_area ? viewport->WorkSize : viewport->Size); - if (ImGui::Begin("Example: Fullscreen window", p_open, flags)) + if (ImGui::Begin(Tr("Example: Fullscreen window"), p_open, flags)) { IMGUI_DEMO_MARKER("Examples/Fullscreen window"); - ImGui::Checkbox("Use work area instead of main area", &use_work_area); + ImGui::Checkbox(Tr("Use work area instead of main area"), &use_work_area); ImGui::SameLine(); HelpMarker("Main Area = entire viewport,\nWork Area = entire viewport minus sections used by the main menu bars, task bars etc.\n\nEnable the main-menu bar in Examples menu to see the difference."); @@ -10105,7 +10139,7 @@ static void ShowExampleAppFullscreen(bool* p_open) ImGui::CheckboxFlags("ImGuiWindowFlags_NoScrollbar", &flags, ImGuiWindowFlags_NoScrollbar); ImGui::Unindent(); - if (p_open && ImGui::Button("Close this window")) + if (p_open && ImGui::Button(Tr("Close this window"))) *p_open = false; } ImGui::End(); @@ -10145,7 +10179,7 @@ static void ShowExampleAppWindowTitles(bool*) ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 300), ImGuiCond_FirstUseEver); ImGui::Begin(buf); IMGUI_DEMO_MARKER("Examples/Manipulating window titles##3"); - ImGui::Text("This window has a changing title."); + ImGui::Text("%s", Tr("This window has a changing title.")); ImGui::End(); } @@ -10164,7 +10198,7 @@ static void PathConcaveShape(ImDrawList* draw_list, float x, float y, float sz) // Demonstrate using the low-level ImDrawList to draw custom shapes. static void ShowExampleAppCustomRendering(bool* p_open) { - if (!ImGui::Begin("Example: Custom rendering", p_open)) + if (!ImGui::Begin(Tr("Example: Custom rendering"), p_open)) { ImGui::End(); return; @@ -10178,7 +10212,7 @@ static void ShowExampleAppCustomRendering(bool* p_open) if (ImGui::BeginTabBar("##TabBar")) { - if (ImGui::BeginTabItem("Primitives")) + if (ImGui::BeginTabItem(Tr("Primitives"))) { IMGUI_DEMO_MARKER("Examples/Custom rendering/Primitives"); ImGui::PushItemWidth(-ImGui::GetFontSize() * 15); @@ -10187,7 +10221,7 @@ static void ShowExampleAppCustomRendering(bool* p_open) // Draw gradients // (note that those are currently exacerbating our sRGB/Linear issues) // Calling ImGui::GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well.. - ImGui::Text("Gradients"); + ImGui::Text("%s", Tr("Gradients")); ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight()); { ImVec2 p0 = ImGui::GetCursorScreenPos(); @@ -10207,7 +10241,7 @@ static void ShowExampleAppCustomRendering(bool* p_open) } // Draw a bunch of primitives - ImGui::Text("All primitives"); + ImGui::Text("%s", Tr("All primitives")); static float sz = 36.0f; static float thickness = 3.0f; static int ngon_sides = 6; @@ -10404,14 +10438,14 @@ static void ShowExampleAppCustomRendering(bool* p_open) ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("BG/FG draw lists")) + if (ImGui::BeginTabItem(Tr("BG/FG draw lists"))) { IMGUI_DEMO_MARKER("Examples/Custom rendering/BG & FG draw lists"); static bool draw_bg = true; static bool draw_fg = true; - ImGui::Checkbox("Draw in Background draw list", &draw_bg); + ImGui::Checkbox(Tr("Draw in Background draw list"), &draw_bg); ImGui::SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows."); - ImGui::Checkbox("Draw in Foreground draw list", &draw_fg); + ImGui::Checkbox(Tr("Draw in Foreground draw list"), &draw_fg); ImGui::SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows."); ImVec2 window_pos = ImGui::GetWindowPos(); ImVec2 window_size = ImGui::GetWindowSize(); @@ -10431,8 +10465,8 @@ static void ShowExampleAppCustomRendering(bool* p_open) IMGUI_DEMO_MARKER("Examples/Custom rendering/Draw Channels"); ImDrawList* draw_list = ImGui::GetWindowDrawList(); { - ImGui::Text("Blue shape is drawn first: appears in back"); - ImGui::Text("Red shape is drawn after: appears in front"); + ImGui::Text("%s", Tr("Blue shape is drawn first: appears in back")); + ImGui::Text("%s", Tr("Red shape is drawn after: appears in front")); ImVec2 p0 = ImGui::GetCursorScreenPos(); draw_list->AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50), IM_COL32(0, 0, 255, 255)); // Blue draw_list->AddRectFilled(ImVec2(p0.x + 25, p0.y + 25), ImVec2(p0.x + 75, p0.y + 75), IM_COL32(255, 0, 0, 255)); // Red @@ -10440,8 +10474,8 @@ static void ShowExampleAppCustomRendering(bool* p_open) } ImGui::Separator(); { - ImGui::Text("Blue shape is drawn first, into channel 1: appears in front"); - ImGui::Text("Red shape is drawn after, into channel 0: appears in back"); + ImGui::Text("%s", Tr("Blue shape is drawn first, into channel 1: appears in front")); + ImGui::Text("%s", Tr("Red shape is drawn after, into channel 0: appears in back")); ImVec2 p1 = ImGui::GetCursorScreenPos(); // Create 2 channels and draw a Blue shape THEN a Red shape. @@ -10456,7 +10490,7 @@ static void ShowExampleAppCustomRendering(bool* p_open) // This works by copying draw indices only (vertices are not copied). draw_list->ChannelsMerge(); ImGui::Dummy(ImVec2(75, 75)); - ImGui::Text("After reordering, contents of channel 0 appears below channel 1."); + ImGui::Text("%s", Tr("After reordering, contents of channel 0 appears below channel 1.")); } ImGui::EndTabItem(); } @@ -10527,7 +10561,7 @@ struct ExampleAppDocuments ImGui::PopStyleColor(); ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_R, ImGuiInputFlags_Tooltip); - if (ImGui::Button("Rename..")) + if (ImGui::Button(Tr("Rename.."))) { RenamingDoc = doc; RenamingStarted = true; @@ -10540,7 +10574,7 @@ struct ExampleAppDocuments ImGui::SameLine(); ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_S, ImGuiInputFlags_Tooltip); - if (ImGui::Button("Save")) + if (ImGui::Button(Tr("Save"))) doc->DoSave(); ImGui::SameLine(); @@ -10595,7 +10629,7 @@ void ShowExampleAppDocuments(bool* p_open) static bool opt_reorderable = true; static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_; - bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar); + bool window_contents_visible = ImGui::Begin(Tr("Example: Documents"), p_open, ImGuiWindowFlags_MenuBar); if (!window_contents_visible) { ImGui::End(); @@ -10619,7 +10653,7 @@ void ShowExampleAppDocuments(bool* p_open) doc.DoOpen(); ImGui::EndMenu(); } - if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0)) + if (ImGui::MenuItem(Tr("Close All Documents"), NULL, false, open_count > 0)) for (MyDocument& doc : app.Documents) app.CloseQueue.push_back(&doc); if (ImGui::MenuItem("Exit") && p_open) @@ -10743,7 +10777,7 @@ void ShowExampleAppDocuments(bool* p_open) ImGui::OpenPopup("Save?"); if (ImGui::BeginPopupModal("Save?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) { - ImGui::Text("Save change to the following items?"); + ImGui::Text("%s", Tr("Save change to the following items?")); float item_height = ImGui::GetTextLineHeightWithSpacing(); if (ImGui::BeginChild(ImGui::GetID("frame"), ImVec2(-FLT_MIN, 6.25f * item_height), ImGuiChildFlags_FrameStyle)) for (MyDocument* doc : app.CloseQueue) @@ -10752,7 +10786,7 @@ void ShowExampleAppDocuments(bool* p_open) ImGui::EndChild(); ImVec2 button_size(ImGui::GetFontSize() * 7.0f, 0.0f); - if (ImGui::Button("Yes", button_size)) + if (ImGui::Button(Tr("Yes"), button_size)) { for (MyDocument* doc : app.CloseQueue) { @@ -10764,7 +10798,7 @@ void ShowExampleAppDocuments(bool* p_open) ImGui::CloseCurrentPopup(); } ImGui::SameLine(); - if (ImGui::Button("No", button_size)) + if (ImGui::Button(Tr("No"), button_size)) { for (MyDocument* doc : app.CloseQueue) doc->DoForceClose(); @@ -10772,7 +10806,7 @@ void ShowExampleAppDocuments(bool* p_open) ImGui::CloseCurrentPopup(); } ImGui::SameLine(); - if (ImGui::Button("Cancel", button_size)) + if (ImGui::Button(Tr("Cancel"), button_size)) { app.CloseQueue.clear(); ImGui::CloseCurrentPopup(); @@ -10926,18 +10960,18 @@ struct ExampleAssetsBrowser { if (ImGui::BeginMenu("File")) { - if (ImGui::MenuItem("Add 10000 items")) + if (ImGui::MenuItem(Tr("Add 10000 items"))) AddItems(10000); - if (ImGui::MenuItem("Clear items")) + if (ImGui::MenuItem(Tr("Clear items"))) ClearItems(); ImGui::Separator(); if (ImGui::MenuItem("Close", NULL, false, p_open != NULL)) *p_open = false; ImGui::EndMenu(); } - if (ImGui::BeginMenu("Edit")) + if (ImGui::BeginMenu(Tr("Edit"))) { - if (ImGui::MenuItem("Delete", "Del", false, Selection.Size > 0)) + if (ImGui::MenuItem(Tr("Delete"), "Del", false, Selection.Size > 0)) RequestDelete = true; ImGui::EndMenu(); } @@ -10945,24 +10979,24 @@ struct ExampleAssetsBrowser { ImGui::PushItemWidth(ImGui::GetFontSize() * 10); - ImGui::SeparatorText("Contents"); - ImGui::Checkbox("Show Type Overlay", &ShowTypeOverlay); - ImGui::Checkbox("Allow Sorting", &AllowSorting); + ImGui::SeparatorText(Tr("Contents")); + ImGui::Checkbox(Tr("Show Type Overlay"), &ShowTypeOverlay); + ImGui::Checkbox(Tr("Allow Sorting"), &AllowSorting); - ImGui::SeparatorText("Selection Behavior"); - ImGui::Checkbox("Allow box-selection", &AllowBoxSelect); - if (ImGui::Checkbox("Allow box-selection from selected items", &AllowBoxSelectInsideSelection) && AllowBoxSelectInsideSelection) + ImGui::SeparatorText(Tr("Selection Behavior")); + ImGui::Checkbox(Tr("Allow box-selection"), &AllowBoxSelect); + if (ImGui::Checkbox(Tr("Allow box-selection from selected items"), &AllowBoxSelectInsideSelection) && AllowBoxSelectInsideSelection) AllowDragUnselected = false; - if (ImGui::Checkbox("Allow dragging unselected item", &AllowDragUnselected) && AllowDragUnselected) + if (ImGui::Checkbox(Tr("Allow dragging unselected item"), &AllowDragUnselected) && AllowDragUnselected) AllowBoxSelectInsideSelection = false; - ImGui::SeparatorText("Layout"); - ImGui::SliderFloat("Icon Size", &IconSize, 16.0f, 128.0f, "%.0f"); + ImGui::SeparatorText(Tr("Layout")); + ImGui::SliderFloat(Tr("Icon Size"), &IconSize, 16.0f, 128.0f, "%.0f"); ImGui::SameLine(); HelpMarker("Use Ctrl+Wheel to zoom"); - ImGui::SliderInt("Icon Spacing", &IconSpacing, 0, 32); - ImGui::SliderInt("Icon Hit Spacing", &IconHitSpacing, 0, 32); - ImGui::Checkbox("Stretch Spacing", &StretchSpacing); - ImGui::Checkbox("Use ScrollX", &UseScrollX); + ImGui::SliderInt(Tr("Icon Spacing"), &IconSpacing, 0, 32); + ImGui::SliderInt(Tr("Icon Hit Spacing"), &IconHitSpacing, 0, 32); + ImGui::Checkbox(Tr("Stretch Spacing"), &StretchSpacing); + ImGui::Checkbox(Tr("Use ScrollX"), &UseScrollX); ImGui::PopItemWidth(); ImGui::EndMenu(); } @@ -11105,7 +11139,7 @@ struct ExampleAssetsBrowser // (we could read from selection, but it is more correct and reusable to read from payload) const ImGuiPayload* payload = ImGui::GetDragDropPayload(); const int payload_count = (int)payload->DataSize / (int)sizeof(ImGuiID); - ImGui::Text("%d assets", payload_count); + ImGui::Text(Tr("%d assets"), payload_count); ImGui::EndDragDropSource(); } @@ -11143,9 +11177,9 @@ struct ExampleAssetsBrowser // Context menu if (ImGui::BeginPopupContextWindow()) { - ImGui::Text("Selection: %d items", Selection.Size); + ImGui::Text(Tr("Selection: %d items"), Selection.Size); ImGui::Separator(); - if (ImGui::MenuItem("Delete", "Del", false, Selection.Size > 0)) + if (ImGui::MenuItem(Tr("Delete"), "Del", false, Selection.Size > 0)) RequestDelete = true; ImGui::EndPopup(); } @@ -11197,7 +11231,7 @@ void ShowExampleAppAssetsBrowser(bool* p_open) { IMGUI_DEMO_MARKER("Examples/Assets Browser"); static ExampleAssetsBrowser assets_browser; - assets_browser.Draw("Example: Assets Browser", p_open); + assets_browser.Draw(Tr("Example: Assets Browser"), p_open); } // End of Demo code From 86e272318fa896931500cb652d70dbb03e464ef2 Mon Sep 17 00:00:00 2001 From: xuk Date: Mon, 8 Jun 2026 11:27:01 +0800 Subject: [PATCH 03/12] i18n: update Xcode project to include i18n sources and IMGUI_DEMO_ENABLE_I18N MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add imgui_i18n.cpp and locale/zh_CN.cpp to both iOS and macOS targets. Set IMGUI_DEMO_ENABLE_I18N=1 in GCC_PREPROCESSOR_DEFINITIONS for all four build configurations (iOS/macOS × Debug/Release). --- .../project.pbxproj | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj b/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj index bf3c80d6e91a..5f7c211b6737 100644 --- a/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj +++ b/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj @@ -8,6 +8,10 @@ /* Begin PBXBuildFile section */ 05318E0F274C397200A8DE2E /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05318E0E274C397200A8DE2E /* GameController.framework */; }; + A1I18N00000000000000001A /* imgui_i18n.cpp in Sources (iOS) */ = {isa = PBXBuildFile; fileRef = A1I18N00000000000000F001 /* imgui_i18n.cpp */; }; + A1I18N00000000000000001B /* imgui_i18n.cpp in Sources (macOS) */ = {isa = PBXBuildFile; fileRef = A1I18N00000000000000F001 /* imgui_i18n.cpp */; }; + A1I18N00000000000000002A /* zh_CN.cpp in Sources (iOS) */ = {isa = PBXBuildFile; fileRef = A1I18N00000000000000F002 /* zh_CN.cpp */; }; + A1I18N00000000000000002B /* zh_CN.cpp in Sources (macOS) */ = {isa = PBXBuildFile; fileRef = A1I18N00000000000000F002 /* zh_CN.cpp */; }; 07A82ED82139413D0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; }; 07A82ED92139418F0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; }; 5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5079822D257677DB0038A28D /* imgui_tables.cpp */; }; @@ -59,6 +63,8 @@ 83BBEA0220EB54E700295997 /* imgui_demo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_demo.cpp; path = ../../imgui_demo.cpp; sourceTree = ""; }; 83BBEA0320EB54E700295997 /* imgui.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui.cpp; path = ../../imgui.cpp; sourceTree = ""; }; 83BBEA0420EB54E700295997 /* imconfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imconfig.h; path = ../../imconfig.h; sourceTree = ""; }; + A1I18N00000000000000F001 /* imgui_i18n.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_i18n.cpp; path = ../../i18n/imgui_i18n.cpp; sourceTree = ""; }; + A1I18N00000000000000F002 /* zh_CN.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = zh_CN.cpp; path = ../../i18n/locale/zh_CN.cpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -162,6 +168,8 @@ 83BBEA0120EB54E700295997 /* imgui_draw.cpp */, 07A82ED62139413C0078D120 /* imgui_internal.h */, 07A82ED72139413C0078D120 /* imgui_widgets.cpp */, + A1I18N00000000000000F001 /* imgui_i18n.cpp */, + A1I18N00000000000000F002 /* zh_CN.cpp */, ); name = imgui; sourceTree = ""; @@ -273,6 +281,8 @@ 5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */, 07A82ED82139413D0078D120 /* imgui_widgets.cpp in Sources */, 8309BDA5253CCC070045E2A1 /* main.mm in Sources */, + A1I18N00000000000000001A /* imgui_i18n.cpp in Sources (iOS) */, + A1I18N00000000000000002A /* zh_CN.cpp in Sources (iOS) */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -288,6 +298,8 @@ 5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */, 07A82ED92139418F0078D120 /* imgui_widgets.cpp in Sources */, 8309BDA8253CCC080045E2A1 /* main.mm in Sources */, + A1I18N00000000000000001B /* imgui_i18n.cpp in Sources (macOS) */, + A1I18N00000000000000002B /* zh_CN.cpp in Sources (macOS) */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -409,6 +421,10 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; + GCC_PREPROCESSOR_DEFINITIONS = ( + "IMGUI_DEMO_ENABLE_I18N=1", + "$(inherited)", + ); INFOPLIST_FILE = "$(SRCROOT)/iOS/Info-iOS.plist"; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( @@ -429,6 +445,10 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; + GCC_PREPROCESSOR_DEFINITIONS = ( + "IMGUI_DEMO_ENABLE_I18N=1", + "$(inherited)", + ); INFOPLIST_FILE = "$(SRCROOT)/iOS/Info-iOS.plist"; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( @@ -452,6 +472,10 @@ COMBINE_HIDPI_IMAGES = YES; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = ""; + GCC_PREPROCESSOR_DEFINITIONS = ( + "IMGUI_DEMO_ENABLE_I18N=1", + "$(inherited)", + ); INFOPLIST_FILE = "$(SRCROOT)/macOS/Info-macOS.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -473,6 +497,10 @@ COMBINE_HIDPI_IMAGES = YES; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = ""; + GCC_PREPROCESSOR_DEFINITIONS = ( + "IMGUI_DEMO_ENABLE_I18N=1", + "$(inherited)", + ); INFOPLIST_FILE = "$(SRCROOT)/macOS/Info-macOS.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", From d497a70fcab4ca8a0a60c2eb97438b8690ea4b57 Mon Sep 17 00:00:00 2001 From: xuk Date: Mon, 8 Jun 2026 11:36:46 +0800 Subject: [PATCH 04/12] i18n: guard i18n code in main.mm with IMGUI_DEMO_ENABLE_I18N; iOS target opt-out - Wrap RebuildFonts(), g_need_font_rebuild, and font rebuild calls in #ifdef IMGUI_DEMO_ENABLE_I18N so main.mm compiles cleanly without i18n - Include imgui_i18n.h unconditionally (provides no-op Tr() stub when IMGUI_DEMO_ENABLE_I18N is not defined, enabling Tr() in the demo window) - Remove IMGUI_DEMO_ENABLE_I18N and i18n sources from iOS Xcode target (untested on iOS; macOS-only system font paths would not work on device) --- .../project.pbxproj | 16 ++-------------- examples/example_apple_metal/main.mm | 12 +++++++++++- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj b/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj index 5f7c211b6737..55a33c4eaffd 100644 --- a/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj +++ b/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj @@ -8,10 +8,8 @@ /* Begin PBXBuildFile section */ 05318E0F274C397200A8DE2E /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05318E0E274C397200A8DE2E /* GameController.framework */; }; - A1I18N00000000000000001A /* imgui_i18n.cpp in Sources (iOS) */ = {isa = PBXBuildFile; fileRef = A1I18N00000000000000F001 /* imgui_i18n.cpp */; }; - A1I18N00000000000000001B /* imgui_i18n.cpp in Sources (macOS) */ = {isa = PBXBuildFile; fileRef = A1I18N00000000000000F001 /* imgui_i18n.cpp */; }; - A1I18N00000000000000002A /* zh_CN.cpp in Sources (iOS) */ = {isa = PBXBuildFile; fileRef = A1I18N00000000000000F002 /* zh_CN.cpp */; }; - A1I18N00000000000000002B /* zh_CN.cpp in Sources (macOS) */ = {isa = PBXBuildFile; fileRef = A1I18N00000000000000F002 /* zh_CN.cpp */; }; + A1I18N00000000000000001B /* imgui_i18n.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A1I18N00000000000000F001 /* imgui_i18n.cpp */; }; + A1I18N00000000000000002B /* zh_CN.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A1I18N00000000000000F002 /* zh_CN.cpp */; }; 07A82ED82139413D0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; }; 07A82ED92139418F0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; }; 5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5079822D257677DB0038A28D /* imgui_tables.cpp */; }; @@ -281,8 +279,6 @@ 5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */, 07A82ED82139413D0078D120 /* imgui_widgets.cpp in Sources */, 8309BDA5253CCC070045E2A1 /* main.mm in Sources */, - A1I18N00000000000000001A /* imgui_i18n.cpp in Sources (iOS) */, - A1I18N00000000000000002A /* zh_CN.cpp in Sources (iOS) */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -421,10 +417,6 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; - GCC_PREPROCESSOR_DEFINITIONS = ( - "IMGUI_DEMO_ENABLE_I18N=1", - "$(inherited)", - ); INFOPLIST_FILE = "$(SRCROOT)/iOS/Info-iOS.plist"; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( @@ -445,10 +437,6 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; - GCC_PREPROCESSOR_DEFINITIONS = ( - "IMGUI_DEMO_ENABLE_I18N=1", - "$(inherited)", - ); INFOPLIST_FILE = "$(SRCROOT)/iOS/Info-iOS.plist"; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/examples/example_apple_metal/main.mm b/examples/example_apple_metal/main.mm index 01038716babe..02bcecf5499b 100644 --- a/examples/example_apple_metal/main.mm +++ b/examples/example_apple_metal/main.mm @@ -18,8 +18,12 @@ #import #include "imgui.h" +// i18n support: include unconditionally — when IMGUI_DEMO_ENABLE_I18N is not defined +// the header provides a no-op Tr(s) stub with zero overhead. #include "imgui_i18n.h" +#ifdef IMGUI_DEMO_ENABLE_I18N #include +#endif #include "imgui_impl_metal.h" #if TARGET_OS_OSX #include "imgui_impl_osx.h" @@ -40,6 +44,7 @@ @interface AppViewController () // AppViewController //----------------------------------------------------------------------------------- +#ifdef IMGUI_DEMO_ENABLE_I18N bool g_need_font_rebuild = false; static void RebuildFonts() @@ -76,6 +81,7 @@ static void RebuildFonts() } io.Fonts->Build(); } +#endif // IMGUI_DEMO_ENABLE_I18N @implementation AppViewController @@ -150,8 +156,10 @@ -(void)viewDidLoad [NSApp activateIgnoringOtherApps:YES]; #endif +#ifdef IMGUI_DEMO_ENABLE_I18N // Build initial font atlas with CJK glyphs so the Language menu renders correctly from the start. RebuildFonts(); +#endif } -(void)drawInMTKView:(MTKView*)view @@ -176,11 +184,13 @@ -(void)drawInMTKView:(MTKView*)view return; } - // 语言切换后重建字体 Atlas(必须在 NewFrame 之前,避免当帧纹理 use-after-free) +#ifdef IMGUI_DEMO_ENABLE_I18N + // Rebuild font atlas after language switch (must be before NewFrame to avoid use-after-free). if (g_need_font_rebuild) { g_need_font_rebuild = false; RebuildFonts(); } +#endif // Start the Dear ImGui frame ImGui_ImplMetal_NewFrame(renderPassDescriptor); From 0ada92b9e73a5820858e0339e5a53e60f38d93a9 Mon Sep 17 00:00:00 2001 From: xuk Date: Mon, 8 Jun 2026 11:44:26 +0800 Subject: [PATCH 05/12] i18n: replace Chinese comments in imgui_i18n.cpp with English --- i18n/imgui_i18n.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/i18n/imgui_i18n.cpp b/i18n/imgui_i18n.cpp index 653da987f4a0..abf72c81dbf7 100644 --- a/i18n/imgui_i18n.cpp +++ b/i18n/imgui_i18n.cpp @@ -5,7 +5,7 @@ namespace imgui_i18n { -// Meyers Singleton — 保证跨编译单元 static initializer 调用时已初始化(避免 SIOF) +// Meyers Singleton: guarantees initialization before first use across translation units, avoiding SIOF. static std::string& locale() { static std::string s; return s; @@ -50,8 +50,9 @@ void registerLocale( const char* loc, std::initializer_list> entries) { - // 注意:registerLocale 必须在第一次调用 translate() 之前全部完成(通常由 static initializer 保证) - // 注册完成后不可再追加,否则 unordered_map rehash 会使已返回的 c_str() 指针失效 + // All registerLocale() calls must complete before the first translate() call (normally guaranteed + // by static initializers). Do not add entries after translate() has been called: unordered_map + // rehashing would invalidate the c_str() pointers returned by translate(). auto& table = tables()[loc]; for (const auto& e : entries) table[e.first] = e.second; From 5f45f05f68ba86cb2ec95909f5a729fa6cc240f3 Mon Sep 17 00:00:00 2001 From: xuk Date: Wed, 10 Jun 2026 13:55:53 +0800 Subject: [PATCH 06/12] i18n: fix translation quality per localization standards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Do not translate 'Hello, world!' (universally recognized programming example) - Do not translate 'This is some useful text.' (standard example boilerplate) - Do not translate 'float' / 'counter = %d' (C++ type/variable labels) - Keep 'blah blah blah' as-is (intentional nonsense filler, not real content) - Keep 'dear imgui' brand name untranslated in greeting message - Fix 'Another bullet point' -> 正确翻译为项目符号而非叶节点 - Fix 'Metrics/Debugger' -> 指标/调试器 (Metrics = indicators, not performance) - Remove redundant identity entries for API function names (IsItemXxx etc.) --- examples/example_apple_metal/main.mm | 9 +++---- i18n/locale/zh_CN.cpp | 36 +++++++++------------------- 2 files changed, 16 insertions(+), 29 deletions(-) diff --git a/examples/example_apple_metal/main.mm b/examples/example_apple_metal/main.mm index 02bcecf5499b..a44a61fd482a 100644 --- a/examples/example_apple_metal/main.mm +++ b/examples/example_apple_metal/main.mm @@ -213,19 +213,20 @@ -(void)drawInMTKView:(MTKView*)view static float f = 0.0f; static int counter = 0; - ImGui::Begin(Tr("Hello, world!")); + // "Hello, world!" is the canonical ImGui getting-started window title — kept in English. + ImGui::Begin("Hello, world!"); - ImGui::Text("%s", Tr("This is some useful text.")); + ImGui::Text("This is some useful text."); // standard example text, kept in English ImGui::Checkbox(Tr("Demo Window"), &show_demo_window); ImGui::Checkbox(Tr("Another Window"), &show_another_window); - ImGui::SliderFloat(Tr("float"), &f, 0.0f, 1.0f); + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // "float" labels the C++ type, not translated ImGui::ColorEdit3(Tr("clear color"), (float*)&clear_color); if (ImGui::Button(Tr("Button"))) counter++; ImGui::SameLine(); - ImGui::Text(Tr("counter = %d"), counter); + ImGui::Text("counter = %d", counter); // variable name, not translated ImGui::Text(Tr("Application average %.3f ms/frame (%.1f FPS)"), 1000.0f / io.Framerate, io.Framerate); ImGui::End(); diff --git a/i18n/locale/zh_CN.cpp b/i18n/locale/zh_CN.cpp index af48793d0664..804d342bf859 100644 --- a/i18n/locale/zh_CN.cpp +++ b/i18n/locale/zh_CN.cpp @@ -48,7 +48,7 @@ struct ZhCNRegistrar { {"Long text display", "长文本显示"}, {"Manipulating window titles", "操控窗口标题"}, {"Tools", "工具"}, - {"Metrics/Debugger", "性能/调试器"}, + {"Metrics/Debugger", "指标/调试器"}, {"Debug Options", "调试选项"}, {"Highlight ID Conflicts", "高亮 ID 冲突"}, {"Assert on error recovery", "错误恢复时断言"}, @@ -74,7 +74,7 @@ struct ZhCNRegistrar { {"SeparatorText", "分隔文字"}, {"Dear ImGui Style Editor", "Dear ImGui 样式编辑器"}, // --- Step 1 补充(Configuration 面板) --- - {"dear imgui says hello! (%s) (%d)", "亲爱的 imgui 向你问好!(%s) (%d)"}, + {"dear imgui says hello! (%s) (%d)", "dear imgui 向你问好!(%s) (%d)"}, {"<>", "<<按空格键禁用>>"}, {"Also see Style->Rendering for rendering options.", "另见 样式->渲染 中的渲染选项。"}, {"General", "通用"}, @@ -130,7 +130,7 @@ struct ZhCNRegistrar { {"Tooltip when hovering:", "悬停提示:"}, {"Tooltip always visible:", "始终显示提示:"}, {"Hold to repeat (filtered)", "长按重复(过滤)"}, - {"Another bullet point", "另一个叶节点"}, + {"Another bullet point", "另一个项目符号"}, {"Header 1: open by default", "标题 1:默认展开"}, {"Header 2: do not show a bullet", "标题 2:无项目符号"}, {"(more empty content)", "(更多空内容)"}, @@ -186,9 +186,9 @@ struct ZhCNRegistrar { {"Only makes a difference if the popup is larger than the combo", "仅在弹窗比下拉框宽时有效"}, {"Highlight hovered item in second listbox", "在第二个列表框中高亮悬停项"}, {"Full-width:", "全宽:"}, - {"This is the Avocado tab!\nblah blah blah blah blah", "这是鳄梨标签页!\n内容内容内容内容内容"}, - {"This is the Broccoli tab!\nblah blah blah blah blah", "这是西兰花标签页!\n内容内容内容内容内容"}, - {"This is the Cucumber tab!\nblah blah blah blah blah", "这是黄瓜标签页!\n内容内容内容内容内容"}, + {"This is the Avocado tab!\nblah blah blah blah blah", "这是鳄梨标签页!\nblah blah blah blah blah"}, + {"This is the Broccoli tab!\nblah blah blah blah blah", "这是西兰花标签页!\nblah blah blah blah blah"}, + {"This is the Cucumber tab!\nblah blah blah blah blah", "这是黄瓜标签页!\nblah blah blah blah blah"}, {"Advanced & Close Button", "高级与关闭按钮"}, {"Opened:", "已打开:"}, {"This is the %s tab!", "这是 %s 标签页!"}, @@ -296,19 +296,7 @@ struct ZhCNRegistrar { {"First", "第一"}, {"Second", "第二"}, {"Third", "第三"}, - {"IsItemHovered()", "IsItemHovered()"}, - {"IsItemActive()", "IsItemActive()"}, - {"IsItemFocused()", "IsItemFocused()"}, - {"IsItemClicked()", "IsItemClicked()"}, - {"IsItemVisible()", "IsItemVisible()"}, - {"IsItemEdited()", "IsItemEdited()"}, - {"IsItemActivated()", "IsItemActivated()"}, - {"IsItemDeactivated()", "IsItemDeactivated()"}, - {"IsItemDeactivatedAfterEdit()", "IsItemDeactivatedAfterEdit()"}, - {"IsItemToggledOpen()", "IsItemToggledOpen()"}, - {"GetItemRectMin()", "GetItemRectMin()"}, - {"GetItemRectMax()", "GetItemRectMax()"}, - {"GetItemRectSize()", "GetItemRectSize()"}, + // IsItemXxx()/GetItemXxx() API names are not translated (fallback to English key). {"Mouse Cursors", "鼠标光标"}, {"Display all cursors", "显示所有光标"}, {"Hovering over them changes the mouse cursor.", "悬停改变光标样式。"}, @@ -783,15 +771,13 @@ struct ZhCNRegistrar { {"Selection: %d items", "已选:%d 个项目"}, {"Help", "帮助"}, // === main.mm window === - {"Hello, world!", "你好,世界!"}, - {"This is some useful text.", "这是一段有用的文字。"}, + // "Hello, world!" and "This is some useful text." are intentionally kept in English + // as they are universally recognized programming example strings. {"Demo Window", "演示窗口"}, {"Another Window", "另一个窗口"}, - {"float", "浮点"}, + // "float" is kept as-is: it labels a SliderFloat() demonstrating the float type. {"clear color", "背景颜色"}, - {"Button", "按钮"}, - {"counter = %d", "计数器 = %d"}, - {"Application average %.3f ms/frame (%.1f FPS)", "应用程序平均 %.3f 毫秒/帧(%.1f FPS)"}, + {"Application average %.3f ms/frame (%.1f FPS)", "平均 %.3f 毫秒/帧(%.1f FPS)"}, {"Hello from another window!", "来自另一个窗口的问候!"}, {"Close Me", "关闭"}, // === Help 折叠内容 === From c14ae88f9048ee6211aaf6704c79f49faecc98fa Mon Sep 17 00:00:00 2001 From: xuk Date: Wed, 10 Jun 2026 14:09:29 +0800 Subject: [PATCH 07/12] i18n: add Translation Guidelines section to README Document what to translate and what not to translate, with examples and quality rules (accuracy, format specifiers, redundant entries). --- i18n/README.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/i18n/README.md b/i18n/README.md index 7a729e4dd738..2d0997cac5e7 100644 --- a/i18n/README.md +++ b/i18n/README.md @@ -114,6 +114,43 @@ The pattern: --- +## Translation Guidelines + +Follow these rules when translating strings to ensure quality and consistency. + +### What to translate + +Translate user-visible UI labels: menu items, button labels, window titles, section +headers, tooltip descriptions, and status messages. + +### What NOT to translate + +| Category | Example | Reason | +|----------|---------|--------| +| Universally recognized programming examples | `"Hello, world!"` | Part of global programming culture; keeping English avoids confusion for learners following tutorials | +| Standard boilerplate example text | `"This is some useful text."` | Canonical ImGui getting-started template text | +| C++ type/variable names used as labels | `"float"`, `"counter = %d"` | Labels the underlying type or variable name, not a description | +| Intentional filler/nonsense | `"blah blah blah"` | The meaninglessness is the message; translating it to real words defeats the purpose | +| API / function names | `"IsItemHovered()"` | Must remain identical to the actual API; adding an entry that maps to itself is redundant | +| Brand / product names | `"Dear ImGui"`, `"dear imgui"` | Proper nouns; do not translate | +| `##`-suffixed ImGui IDs | `"Config##2"` | The `##` part is a disambiguation suffix handled in code, not user-visible | + +### Translation quality rules + +1. **Accuracy over literalness.** Translate meaning, not word-by-word. + Bad: `Metrics` → `性能` (performance) + Good: `Metrics` → `指标` (indicators/measurements) + +2. **Preserve format specifiers.** `%d`, `%s`, `%.3f`, `$1`, `$2` must appear unchanged in the translated string. + +3. **Preserve newlines.** `\n` positions in the translation may differ from the English, but must be present where the UI needs line breaks. + +4. **Preserve punctuation intent.** If the English ends with `:`, the translation should too (adjusted for the target language's punctuation conventions). + +5. **Redundant identity entries are noise.** If a string needs no translation (e.g. an API function name), do **not** add `{"Foo()", "Foo()"}` to the table. The fallback mechanism returns the key automatically. + +--- + ## Extracting Strings for Translation Use the helper script to generate a translation skeleton for a range of lines: From b3dc2271b350d2dfc3cbbd3072174a3a2a39cc71 Mon Sep 17 00:00:00 2001 From: xuk Date: Wed, 10 Jun 2026 14:22:09 +0800 Subject: [PATCH 08/12] i18n: convert all Chinese comments in zh_CN.cpp to English --- i18n/locale/zh_CN.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/i18n/locale/zh_CN.cpp b/i18n/locale/zh_CN.cpp index 804d342bf859..6d2235169474 100644 --- a/i18n/locale/zh_CN.cpp +++ b/i18n/locale/zh_CN.cpp @@ -1,5 +1,5 @@ // i18n/locale/zh_CN.cpp -// 中文翻译表 —— 按批次追加,static initializer 在 main() 前自动注册 +// Simplified Chinese (zh_CN) translation table. Auto-registered before main() via static initializer. #include "../imgui_i18n.h" namespace { @@ -73,7 +73,7 @@ struct ZhCNRegistrar { {"Color", "颜色"}, {"SeparatorText", "分隔文字"}, {"Dear ImGui Style Editor", "Dear ImGui 样式编辑器"}, - // --- Step 1 补充(Configuration 面板) --- + // --- Step 1 supplement: Configuration panel --- {"dear imgui says hello! (%s) (%d)", "dear imgui 向你问好!(%s) (%d)"}, {"<>", "<<按空格键禁用>>"}, {"Also see Style->Rendering for rendering options.", "另见 样式->渲染 中的渲染选项。"}, @@ -536,7 +536,7 @@ struct ZhCNRegistrar { {"Read 'Programmer Guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase.", "阅读 imgui.cpp 中的《程序员指南》了解集成方法。"}, {"Understood!", "明白了!"}, {"Oops, button is disabled!", "按钮已被禁用!"}, - // === Step 11: Tables(前半段)=== + // === Step 11: Tables (first half) === {"Borders, background", "边框与背景"}, {"Resizable, stretch", "可缩放(拉伸)"}, {"Resizable, fixed", "可缩放(固定)"}, @@ -555,7 +555,7 @@ struct ZhCNRegistrar { {"Expand all", "展开全部"}, {"Collapse all", "折叠全部"}, {"Display headers", "显示表头"}, - // === Step 11b 预留(Tables 后半段)=== + // === Step 11b: Tables (second half, part 1) === {"Headers", "表头"}, {"Row flags", "行标志"}, {"Reordering", "重排"}, @@ -585,7 +585,7 @@ struct ZhCNRegistrar { {"Vertical headers", "垂直表头"}, {"Custom headers", "自定义表头"}, {"Row background color", "行背景色"}, - // === Step 11b: Tables 后半段 === + // === Step 11b: Tables (second half, part 2) === {"Background color", "背景色"}, {"Tree view", "树形视图"}, {"Item width", "条目宽度"}, @@ -780,7 +780,7 @@ struct ZhCNRegistrar { {"Application average %.3f ms/frame (%.1f FPS)", "平均 %.3f 毫秒/帧(%.1f FPS)"}, {"Hello from another window!", "来自另一个窗口的问候!"}, {"Close Me", "关闭"}, - // === Help 折叠内容 === + // === Help collapsing section === {"ABOUT THIS DEMO:", "关于本演示:"}, {"Sections below are demonstrating many aspects of the library.", "下方各章节展示了库的众多特性。"}, {"The \"Examples\" menu above leads to more demo contents.", "上方「示例」菜单包含更多演示内容。"}, @@ -794,7 +794,7 @@ struct ZhCNRegistrar { {"Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.", "设置 'io.ConfigFlags |= NavEnableKeyboard' 以启用键盘控制。"}, {"Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.", "设置 'io.ConfigFlags |= NavEnableGamepad' 以启用手柄控制。"}, {"USER GUIDE:", "用户指南:"}, - // === Configuration HelpMarker 提示 === + // === Configuration panel HelpMarker tooltips === {"Enable keyboard controls.", "启用键盘控制。"}, {"Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.", "启用手柄控制。需要后端设置 io.BackendFlags |= ImGuiBackendFlags_HasGamepad。\n\n详情请阅读 imgui.cpp 中的说明。"}, {"Instruct dear imgui to disable mouse inputs and interactions.", "禁止 Dear ImGui 处理鼠标输入和交互。"}, From 08f82c56de65b53abf6b26c38f186eff1348b11b Mon Sep 17 00:00:00 2001 From: xuk Date: Wed, 10 Jun 2026 14:27:16 +0800 Subject: [PATCH 09/12] i18n: move i18n/ to misc/i18n/ to align with misc/ optional module convention misc/ already hosts optional supplemental modules (cpp/imgui_stdlib, freetype/, fonts/). i18n fits the same pattern: opt-in, not part of the core library. Update all include paths, Makefile, Xcode project and README accordingly. --- examples/example_apple_metal/Makefile | 6 +- .../project.pbxproj | 4 +- examples/example_apple_metal/main.mm | 2 +- imgui_demo.cpp | 2 +- misc/i18n/README.md | 206 +++++ misc/i18n/imgui_i18n.cpp | 61 ++ misc/i18n/imgui_i18n.h | 47 + misc/i18n/locale/zh_CN.cpp | 820 ++++++++++++++++++ misc/i18n/tools/extract_strings.py | 25 + 9 files changed, 1166 insertions(+), 7 deletions(-) create mode 100644 misc/i18n/README.md create mode 100644 misc/i18n/imgui_i18n.cpp create mode 100644 misc/i18n/imgui_i18n.h create mode 100644 misc/i18n/locale/zh_CN.cpp create mode 100644 misc/i18n/tools/extract_strings.py diff --git a/examples/example_apple_metal/Makefile b/examples/example_apple_metal/Makefile index 936375871850..b022cc8bba78 100644 --- a/examples/example_apple_metal/Makefile +++ b/examples/example_apple_metal/Makefile @@ -5,10 +5,10 @@ IMGUI_DIR = ../../ SOURCES = main.mm SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp SOURCES += $(IMGUI_DIR)/backends/imgui_impl_osx.mm $(IMGUI_DIR)/backends/imgui_impl_metal.mm -SOURCES += $(IMGUI_DIR)/i18n/imgui_i18n.cpp -SOURCES += $(IMGUI_DIR)/i18n/locale/zh_CN.cpp +SOURCES += $(IMGUI_DIR)/misc/i18n/imgui_i18n.cpp +SOURCES += $(IMGUI_DIR)/misc/i18n/locale/zh_CN.cpp -CXXFLAGS = -std=c++11 -ObjC++ -fobjc-arc -Wall -Wextra -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends -I$(IMGUI_DIR)/i18n -DIMGUI_DEMO_ENABLE_I18N +CXXFLAGS = -std=c++11 -ObjC++ -fobjc-arc -Wall -Wextra -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends -I$(IMGUI_DIR)/misc/i18n -DIMGUI_DEMO_ENABLE_I18N FRAMEWORKS = -framework AppKit -framework Metal -framework MetalKit -framework QuartzCore -framework GameController all: $(EXE) diff --git a/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj b/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj index 55a33c4eaffd..96399c4a43ae 100644 --- a/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj +++ b/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj @@ -61,8 +61,8 @@ 83BBEA0220EB54E700295997 /* imgui_demo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_demo.cpp; path = ../../imgui_demo.cpp; sourceTree = ""; }; 83BBEA0320EB54E700295997 /* imgui.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui.cpp; path = ../../imgui.cpp; sourceTree = ""; }; 83BBEA0420EB54E700295997 /* imconfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imconfig.h; path = ../../imconfig.h; sourceTree = ""; }; - A1I18N00000000000000F001 /* imgui_i18n.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_i18n.cpp; path = ../../i18n/imgui_i18n.cpp; sourceTree = ""; }; - A1I18N00000000000000F002 /* zh_CN.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = zh_CN.cpp; path = ../../i18n/locale/zh_CN.cpp; sourceTree = ""; }; + A1I18N00000000000000F001 /* imgui_i18n.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_i18n.cpp; path = ../../misc/i18n/imgui_i18n.cpp; sourceTree = ""; }; + A1I18N00000000000000F002 /* zh_CN.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = zh_CN.cpp; path = ../../misc/i18n/locale/zh_CN.cpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ diff --git a/examples/example_apple_metal/main.mm b/examples/example_apple_metal/main.mm index a44a61fd482a..0157dc1d45e2 100644 --- a/examples/example_apple_metal/main.mm +++ b/examples/example_apple_metal/main.mm @@ -20,7 +20,7 @@ #include "imgui.h" // i18n support: include unconditionally — when IMGUI_DEMO_ENABLE_I18N is not defined // the header provides a no-op Tr(s) stub with zero overhead. -#include "imgui_i18n.h" +#include "misc/i18n/imgui_i18n.h" #ifdef IMGUI_DEMO_ENABLE_I18N #include #endif diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 69474c0f0507..aa92115bdd2f 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -132,7 +132,7 @@ Index of this file: #include "imgui.h" // i18n support: opt-in by defining IMGUI_DEMO_ENABLE_I18N in your build. // When not defined, Tr(s) is a no-op and this header has no dependencies. -#include "i18n/imgui_i18n.h" +#include "misc/i18n/imgui_i18n.h" #ifdef IMGUI_DEMO_ENABLE_I18N #if defined(__APPLE__) extern bool g_need_font_rebuild; // defined in main.mm (Apple Metal example only) diff --git a/misc/i18n/README.md b/misc/i18n/README.md new file mode 100644 index 000000000000..b133a4e0a6d7 --- /dev/null +++ b/misc/i18n/README.md @@ -0,0 +1,206 @@ +# 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) + +```bash +# 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/.cpp` (e.g. `locale/ja_JP.cpp`). + +```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):** +```makefile +SOURCES += $(IMGUI_DIR)/misc/i18n/imgui_i18n.cpp +SOURCES += $(IMGUI_DIR)/misc/i18n/locale/ja_JP.cpp # add your new locale +CXXFLAGS += -I$(IMGUI_DIR)/i18n -DIMGUI_DEMO_ENABLE_I18N +``` + +**CMake:** +```cmake +target_sources(my_app PRIVATE + ${IMGUI_DIR}/misc/i18n/imgui_i18n.cpp + ${IMGUI_DIR}/misc/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"))`): + +```cpp +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()`. + +--- + +## Translation Guidelines + +Follow these rules when translating strings to ensure quality and consistency. + +### What to translate + +Translate user-visible UI labels: menu items, button labels, window titles, section +headers, tooltip descriptions, and status messages. + +### What NOT to translate + +| Category | Example | Reason | +|----------|---------|--------| +| Universally recognized programming examples | `"Hello, world!"` | Part of global programming culture; keeping English avoids confusion for learners following tutorials | +| Standard boilerplate example text | `"This is some useful text."` | Canonical ImGui getting-started template text | +| C++ type/variable names used as labels | `"float"`, `"counter = %d"` | Labels the underlying type or variable name, not a description | +| Intentional filler/nonsense | `"blah blah blah"` | The meaninglessness is the message; translating it to real words defeats the purpose | +| API / function names | `"IsItemHovered()"` | Must remain identical to the actual API; adding an entry that maps to itself is redundant | +| Brand / product names | `"Dear ImGui"`, `"dear imgui"` | Proper nouns; do not translate | +| `##`-suffixed ImGui IDs | `"Config##2"` | The `##` part is a disambiguation suffix handled in code, not user-visible | + +### Translation quality rules + +1. **Accuracy over literalness.** Translate meaning, not word-by-word. + Bad: `Metrics` → `性能` (performance) + Good: `Metrics` → `指标` (indicators/measurements) + +2. **Preserve format specifiers.** `%d`, `%s`, `%.3f`, `$1`, `$2` must appear unchanged in the translated string. + +3. **Preserve newlines.** `\n` positions in the translation may differ from the English, but must be present where the UI needs line breaks. + +4. **Preserve punctuation intent.** If the English ends with `:`, the translation should too (adjusted for the target language's punctuation conventions). + +5. **Redundant identity entries are noise.** If a string needs no translation (e.g. an API function name), do **not** add `{"Foo()", "Foo()"}` to the table. The fallback mechanism returns the key automatically. + +--- + +## Extracting Strings for Translation + +Use the helper script to generate a translation skeleton for a range of lines: + +```bash +cd imgui-master # or wherever imgui_demo.cpp lives +python3 misc/i18n/tools/extract_strings.py imgui_demo.cpp +``` + +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/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 + +```cpp +// 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. diff --git a/misc/i18n/imgui_i18n.cpp b/misc/i18n/imgui_i18n.cpp new file mode 100644 index 000000000000..abf72c81dbf7 --- /dev/null +++ b/misc/i18n/imgui_i18n.cpp @@ -0,0 +1,61 @@ +// i18n/imgui_i18n.cpp +#include "imgui_i18n.h" +#include +#include + +namespace imgui_i18n { + +// Meyers Singleton: guarantees initialization before first use across translation units, avoiding SIOF. +static std::string& locale() { + static std::string s; + return s; +} + +static std::unordered_map>& tables() { + static std::unordered_map> s; + return s; +} + +void setLocale(const char* loc) { + locale() = loc ? loc : ""; +} + +const char* getLocale() { + return locale().c_str(); +} + +const char* translate(const char* key) { + if (!key) return ""; + if (locale().empty()) return key; // English fast path + auto it = tables().find(locale()); + if (it == tables().end()) return key; + auto it2 = it->second.find(key); + if (it2 == it->second.end()) return key; + return it2->second.c_str(); +} + +std::string fmt(const char* key, std::initializer_list args) { + std::string result = translate(key); + int i = 1; + for (const auto& arg : args) { + std::string ph = "$" + std::to_string(i++); + size_t pos; + while ((pos = result.find(ph)) != std::string::npos) + result.replace(pos, ph.size(), arg); + } + return result; +} + +void registerLocale( + const char* loc, + std::initializer_list> entries) +{ + // All registerLocale() calls must complete before the first translate() call (normally guaranteed + // by static initializers). Do not add entries after translate() has been called: unordered_map + // rehashing would invalidate the c_str() pointers returned by translate(). + auto& table = tables()[loc]; + for (const auto& e : entries) + table[e.first] = e.second; +} + +} // namespace imgui_i18n diff --git a/misc/i18n/imgui_i18n.h b/misc/i18n/imgui_i18n.h new file mode 100644 index 000000000000..f9847b880379 --- /dev/null +++ b/misc/i18n/imgui_i18n.h @@ -0,0 +1,47 @@ +// dear imgui - i18n (internationalization) module +// Provides runtime language switching for imgui_demo.cpp. +// +// Usage: +// Define IMGUI_DEMO_ENABLE_I18N in your build system to opt in. +// Without it, Tr(s) is a no-op and other examples are unaffected. +// +// See i18n/README.md for details and how to add a new language. +#pragma once + +#ifdef IMGUI_DEMO_ENABLE_I18N + +#include +#include +#include + +// Wrap every user-visible string literal in imgui_demo.cpp with Tr(). +#define Tr(s) imgui_i18n::translate(s) +// Variant with $1/$2/... placeholder substitution. +#define TrF(s, ...) imgui_i18n::fmt(s, __VA_ARGS__) + +namespace imgui_i18n { + +// Set active locale: "" or "en" = English (default, zero-overhead fast path). +void setLocale(const char* locale); +const char* getLocale(); + +// Look up key in the active locale table; falls back to key itself if not found. +const char* translate(const char* key); + +// Replace $1, $2, ... placeholders with args (in order). +std::string fmt(const char* key, std::initializer_list args); + +// Register a translation table for a locale (called by locale/*.cpp static initializers). +void registerLocale( + const char* locale, + std::initializer_list> entries); + +} // namespace imgui_i18n + +#else // IMGUI_DEMO_ENABLE_I18N not defined + +// Stub: Tr() is a compile-time identity — zero overhead, no dependencies. +#define Tr(s) (s) +#define TrF(s, ...) (s) + +#endif // IMGUI_DEMO_ENABLE_I18N diff --git a/misc/i18n/locale/zh_CN.cpp b/misc/i18n/locale/zh_CN.cpp new file mode 100644 index 000000000000..737d75a53125 --- /dev/null +++ b/misc/i18n/locale/zh_CN.cpp @@ -0,0 +1,820 @@ +// i18n/locale/zh_CN.cpp +// Simplified Chinese (zh_CN) translation table. Auto-registered before main() via static initializer. +#include "imgui_i18n.h" + +namespace { +struct ZhCNRegistrar { + ZhCNRegistrar() { + imgui_i18n::registerLocale("zh_CN", { + // === Step 1: Demo Window + MenuBar === + {"Dear ImGui Demo", "Dear ImGui 演示"}, + {"Configuration", "配置"}, + {"Window options", "窗口选项"}, + {"No titlebar", "无标题栏"}, + {"No scrollbar", "无滚动条"}, + {"No menu", "无菜单"}, + {"No move", "禁止移动"}, + {"No resize", "禁止缩放"}, + {"No collapse", "禁止折叠"}, + {"No close", "无关闭按钮"}, + {"No nav", "无键盘/手柄导航"}, + {"No background", "无背景"}, + {"No bring to front", "不置顶"}, + {"Unsaved document", "未保存标记"}, + {"Widgets", "控件"}, + {"Layout & Scrolling", "布局与滚动"}, + {"Popups & Modal windows", "弹窗与模态框"}, + {"Tables & Columns", "表格与列"}, + {"Inputs & Focus", "输入与焦点"}, + {"Disable All", "全部禁用"}, + {"Disable (section)", "禁用(区域)"}, + {"Menu", "菜单"}, + {"Examples", "示例"}, + {"Main menu bar", "主菜单栏"}, + {"Assets Browser", "资产浏览器"}, + {"Console", "控制台"}, + {"Custom rendering", "自定义渲染"}, + {"Documents", "文档管理"}, + {"Image Viewer", "图片查看器"}, + {"Log", "日志"}, + {"Property editor", "属性编辑器"}, + {"Simple layout", "简单布局"}, + {"Simple overlay", "简单浮层"}, + {"Mini apps", "迷你应用"}, + {"Concepts", "概念演示"}, + {"Auto-resizing window", "自动调整大小的窗口"}, + {"Constrained-resizing window", "约束调整大小的窗口"}, + {"Fullscreen window", "全屏窗口"}, + {"Long text display", "长文本显示"}, + {"Manipulating window titles", "操控窗口标题"}, + {"Tools", "工具"}, + {"Metrics/Debugger", "指标/调试器"}, + {"Debug Options", "调试选项"}, + {"Highlight ID Conflicts", "高亮 ID 冲突"}, + {"Assert on error recovery", "错误恢复时断言"}, + {"(see Demo->Configuration for more)", "(详见 Demo->配置)"}, + {"Debug Log", "调试日志"}, + {"ID Stack Tool", "ID 栈工具"}, + {"Item Picker", "元素拾取器"}, + {"Style Editor", "样式编辑器"}, + {"About Dear ImGui", "关于 Dear ImGui"}, + {"Language", "语言"}, + {"File", "文件"}, + {"New", "新建"}, + {"Open", "打开"}, + {"Open Recent", "最近打开"}, + {"Save", "保存"}, + {"Save As..", "另存为.."}, + {"Export", "导出"}, + {"Quit", "退出"}, + {"Options", "选项"}, + {"Enabled", "已启用"}, + {"Size", "大小"}, + {"Color", "颜色"}, + {"SeparatorText", "分隔文字"}, + {"Dear ImGui Style Editor", "Dear ImGui 样式编辑器"}, + // --- Step 1 supplement: Configuration panel --- + {"dear imgui says hello! (%s) (%d)", "dear imgui 向你问好!(%s) (%d)"}, + {"<>", "<<按空格键禁用>>"}, + {"Also see Style->Rendering for rendering options.", "另见 样式->渲染 中的渲染选项。"}, + {"General", "通用"}, + {"Keyboard/Gamepad Navigation", "键盘/手柄导航"}, + {"Windows", "窗口"}, + {"Error Handling", "错误处理"}, + {"Debug", "调试"}, + {"Backend Flags", "后端标志"}, + {"Style, Fonts", "样式与字体"}, + {"Capture/Logging", "截图/日志"}, + {"Copy \"Hello, world!\" to clipboard", "复制 \"Hello, world!\" 到剪贴板"}, + // === Step 2: WidgetsBasic + Bullets + CollapsingHeaders === + {"Basic", "基础"}, + {"Selectable", "可选项"}, + {"Images", "图片"}, + {"Combos", "下拉框"}, + {"Drag and Drop", "拖放"}, + {"Color/Picker Widgets", "颜色/选色控件"}, + {"Multi-component Widgets", "多组件控件"}, + {"Plotting", "绘图"}, + {"Progress Bars", "进度条"}, + {"Text Input", "文本输入"}, + {"Drags and Sliders", "拖拽与滑块"}, + {"Selectables", "可选列表项"}, + {"Tree Nodes", "树节点"}, + {"Collapsing Headers", "折叠标题"}, + {"Tooltips", "提示框"}, + {"Tabs", "标签页"}, + {"Text", "文字"}, + {"List Boxes", "列表框"}, + {"Vertical Sliders", "垂直滑块"}, + {"Filtered Text Input", "过滤文本输入"}, + {"Disable Widgets", "禁用控件"}, + {"Data Types", "数据类型"}, + {"Multi-Select", "多选"}, + {"Bullet Widgets", "项目符号控件"}, + {"Bullet point 1", "项目符号 1"}, + {"Bullet point 2\nOn multiple lines", "项目符号 2\n(多行文本)"}, + {"Button", "按钮"}, + {"Click me", "点击我"}, + {"Clicked!", "已点击!"}, + {"Arrows", "箭头按钮"}, + {"Toggle disabled", "切换禁用"}, + {"Checkbox", "复选框"}, + {"RadioButton", "单选按钮"}, + {"(Disabled)", "(禁用)"}, + {"(Enabled)", "(启用)"}, + {"Hold to repeat:", "长按重复:"}, + {"Press and hold to repeat", "长按重复"}, + {"Right-click on buttons too!", "按钮也支持右键!"}, + {"Hovering over me changes the cursor to an arrow!", "悬停切换为箭头光标!"}, + {"Hovering over me changes the cursor to a hand!", "悬停切换为手形光标!"}, + {"Tooltip when hovering:", "悬停提示:"}, + {"Tooltip always visible:", "始终显示提示:"}, + {"Hold to repeat (filtered)", "长按重复(过滤)"}, + {"Another bullet point", "另一个项目符号"}, + {"Header 1: open by default", "标题 1:默认展开"}, + {"Header 2: do not show a bullet", "标题 2:无项目符号"}, + {"(more empty content)", "(更多空内容)"}, + {"(see Widgets->Selectable for more)", "(详见 控件->可选列表项)"}, + {"Thanks for clicking me!", "感谢点击!"}, + {"checkbox", "复选框"}, + {"radio a", "单选 a"}, + {"radio b", "单选 b"}, + {"radio c", "单选 c"}, + {"Click", "点击"}, + {"Tooltip", "提示"}, + {"I am a tooltip", "我是一个提示框"}, + {"label", "标签"}, + {"Value", "值"}, + {"input text", "输入文本"}, + {"input text (w/ hint)", "输入文本(带提示)"}, + {"enter text here", "在此输入"}, + {"input int", "输入整数"}, + {"input float", "输入浮点数"}, + {"input double", "输入双精度"}, + {"input scientific", "科学计数法输入"}, + {"input float3", "输入 float3"}, + {"drag int", "拖拽整数"}, + {"drag int 0..100", "拖拽整数 0..100"}, + {"drag int wrap 100..200", "拖拽整数环绕 100..200"}, + {"drag float", "拖拽浮点数"}, + {"drag small float", "拖拽小浮点数"}, + {"slider int", "滑块整数"}, + {"slider float", "滑块浮点数"}, + {"slider float (log)", "滑块浮点数(对数)"}, + {"slider angle", "滑块角度"}, + {"slider enum", "滑块枚举"}, + {"color 1", "颜色 1"}, + {"color 2", "颜色 2"}, + {"combo", "下拉框"}, + {"listbox", "列表框"}, + {"Bullets", "项目符号"}, + {"Tree node", "树节点"}, + {"Bullet point 3 (two calls)", "项目符号 3(两次调用)"}, + {"Show 2nd header", "显示第 2 个标题"}, + {"Header", "标题"}, + {"Header with a close button", "带关闭按钮的标题"}, + {"IsItemHovered: %d", "IsItemHovered: %d"}, + {"Some content %d", "部分内容 %d"}, + {"More content %d", "更多内容 %d"}, + {"Inputs", "输入"}, + {"Drags", "拖拽"}, + {"Sliders", "滑块"}, + {"Selectors/Pickers", "选择器/拾色器"}, + // === Step 3: ComboBoxes + ListBoxes + Tabs === + {"Combo", "下拉框"}, + {"One-liner variants", "单行变体"}, + {"Only makes a difference if the popup is larger than the combo", "仅在弹窗比下拉框宽时有效"}, + {"Highlight hovered item in second listbox", "在第二个列表框中高亮悬停项"}, + {"Full-width:", "全宽:"}, + {"This is the Avocado tab!\nblah blah blah blah blah", "这是鳄梨标签页!\nblah blah blah blah blah"}, + {"This is the Broccoli tab!\nblah blah blah blah blah", "这是西兰花标签页!\nblah blah blah blah blah"}, + {"This is the Cucumber tab!\nblah blah blah blah blah", "这是黄瓜标签页!\nblah blah blah blah blah"}, + {"Advanced & Close Button", "高级与关闭按钮"}, + {"Opened:", "已打开:"}, + {"This is the %s tab!", "这是 %s 标签页!"}, + {"I am an odd tab.", "我是一个奇数标签页。"}, + {"TabItemButton & Leading/Trailing flags", "标签按钮与前导/尾随标志"}, + {"Show Leading TabItemButton()", "显示前导标签按钮"}, + {"Show Trailing TabItemButton()", "显示尾随标签按钮"}, + {"Hello!", "你好!"}, + // === Step 4: DragsSliders + DataTypes + VerticalSliders === + {"Drag Int", "拖拽整数"}, + {"Drag Float", "拖拽浮点"}, + {"Drag small float", "拖拽小浮点"}, + {"Slider Int", "整数滑块"}, + {"Slider Float", "浮点滑块"}, + {"Slider angle", "角度滑块"}, + {"Reversed", "反向"}, + {"Clamp On Input", "限制输入范围"}, + {"Round to format", "按格式取整"}, + {"Logarithmic", "对数"}, + {"Whole Numbers", "整数"}, + {"Without border", "无边框"}, + {"With border", "有边框"}, + {"Input", "输入"}, + {"Sliders (DragXXX, SliderXXX)", "拖拽与滑块(DragXXX, SliderXXX)"}, + {"Drag/Slider Flags", "拖拽/滑块标志"}, + {"Underlying float value: %f", "底层浮点值:%f"}, + {"Cannot drop here!", "无法拖放到此处!"}, + {"drag me", "拖动我"}, + {"Clamp integers to 0..50", "将整数限制在 0..50"}, + {"Sliders (reverse)", "反向滑块"}, + {"Show step buttons", "显示步进按钮"}, + {"Misc", "其他"}, + {"Saturation", "饱和度"}, + {"As 0..255", "范围 0..255"}, + // === Step 5: Text + TextFilter + TextInput === + {"Text Display", "文字显示"}, + {"Colored Text", "彩色文字"}, + {"Word Wrapping", "自动换行"}, + {"UTF-8 Text", "UTF-8 文字"}, + {"Single-line text input", "单行文本输入"}, + {"Password input", "密码输入"}, + {"Multi-line text input", "多行文本输入"}, + {"Completion:", "补全:"}, + {"History:", "历史:"}, + {"Info:", "信息:"}, + {"Lock And Scroll", "锁定并滚动"}, + {"Read-only", "只读"}, + {"Resize according to text", "根据文本自动缩放"}, + {"Filtered Input", "过滤输入"}, + {"Misc inputs", "其他输入"}, + {"Upper-case input", "大写输入"}, + {"Filter with a callback", "回调过滤"}, + {"No spaces", "无空格"}, + {"Hexadecimal", "十六进制"}, + {"Scientific", "科学计数"}, + {"Custom", "自定义"}, + {"Password", "密码"}, + {"In a popup", "在弹窗中"}, + {"Pressing ENTER will submit", "按 Enter 提交"}, + {"Multiline", "多行"}, + {"Editable", "可编辑"}, + {"Font Size", "字体大小"}, + // === Step 6: Color/Pickers + Images + Plotting + ProgressBars === + {"Color widget:", "颜色控件:"}, + {"Color widget HSV with Alpha:", "HSV 带透明度:"}, + {"Color widget with Float Display:", "浮点显示颜色:"}, + {"Color button with Custom Picker Popup:", "自定义选色弹窗:"}, + {"my color", "我的颜色"}, + {"Color picker", "颜色选取器"}, + {"Set defaults in code:", "在代码中设置默认值:"}, + {"Both types:", "两种类型:"}, + {"HSV encoded colors", "HSV 编码颜色"}, + {"Color widget with InputHSV:", "InputHSV 颜色控件:"}, + {"Hover the texture for a zoomed view!", "悬停纹理查看放大视图!"}, + {"Image()/ImageWithBg() function", "Image()/ImageWithBg() 函数"}, + {"Interactive Image Viewer", "交互式图片查看器"}, + {"Textured Buttons", "纹理按钮"}, + {"And now some textured buttons..", "以下是一些纹理按钮.."}, + {"Need better plotting and graphing? Consider using ImPlot:", "需要更好的绘图?考虑使用 ImPlot:"}, + {"Animate", "动画"}, + {"Frame Times", "帧时间"}, + {"Histogram", "直方图"}, + {"Functions", "函数"}, + {"Sample count", "采样数"}, + // === Step 7: DragDrop + QueryingStatuses + DisableBlocks === + {"Disable Blocks", "禁用块"}, + {"Disable entire section above", "禁用上方全部控件"}, + {"Demonstrate using BeginDisabled()/EndDisabled() across other sections.", "演示跨区域使用 BeginDisabled()/EndDisabled()。"}, + {"Drag and drop in standard widgets", "在标准控件中拖放"}, + {"You can drag from the color squares.", "可以从颜色方块拖动。"}, + {"Drag and drop to copy/swap items", "拖放以复制/交换项目"}, + {"Copy", "复制"}, + {"Move", "移动"}, + {"Swap", "交换"}, + {"Drag to reorder items (simple)", "拖放重新排序(简单)"}, + {"Tooltip at target location", "目标位置工具提示"}, + {"Drag to re-order", "拖放以重新排序"}, + {"Hold CTRL to copy", "按住 CTRL 复制"}, + {"Querying Item Status (Edited/Active/Hovered etc.)", "查询控件状态(已编辑/激活/悬停等)"}, + {"Querying Window Status (Focused/Hovered etc.)", "查询窗口状态(聚焦/悬停等)"}, + {"Embed everything inside a child window for testing _RootWindow flag.", "将所有内容嵌入子窗口以测试 _RootWindow 标志。"}, + {"Querying Mouse Status", "查询鼠标状态"}, + {"Disabled Widgets", "禁用控件"}, + {"Disable all items", "禁用所有控件"}, + {"First", "第一"}, + {"Second", "第二"}, + {"Third", "第三"}, + // IsItemXxx()/GetItemXxx() API names are not translated (fallback to English key). + {"Mouse Cursors", "鼠标光标"}, + {"Display all cursors", "显示所有光标"}, + {"Hovering over them changes the mouse cursor.", "悬停改变光标样式。"}, + + // === Step 8: Selectables + MultiSelect + TreeNodes + Tooltips === + {"1. Direct output", "1. 直接输出"}, + {"2. Checkbox-like behavior", "2. 复选框行为"}, + {"3. Mixed usage", "3. 混合用法"}, + {"4. Full-width selectable, with a custom overlay", "4. 全宽可选项(带覆盖层)"}, + {"5. Rendering more items (150)", "5. 渲染更多项目(150 个)"}, + {"Multiple items on the same line", "同行多项目"}, + {"In Tables", "在表格中"}, + {"Grid", "网格"}, + {"Alignment", "对齐"}, + {"Selection: None", "选中:无"}, + {"(Selection: None)", "(选中:无)"}, + {"Selection State & Multi-Select", "选中状态与多选"}, + {"Single-Select", "单选"}, + {"Multi-Select (manual/simplified, without BeginMultiSelect)", "多选(手动简化版,不使用 BeginMultiSelect)"}, + {"Supported features:", "支持的功能:"}, + {"Added features:", "新增功能:"}, + {"Dynamic list with Delete key support.", "动态列表(支持 Delete 键删除)。"}, + {"Multi-Select (with clipper)", "多选(带裁剪器)"}, + {"Multi-Select (with deletion)", "多选(含删除)"}, + {"Multi-Select (dual list box)", "多选(双列表框)"}, + {"Multi-Select (in a table)", "多选(在表格中)"}, + {"Multi-Select (checkboxes)", "多选(复选框)"}, + {"In a list of checkboxes (not selectable):", "复选框列表(非 Selectable):"}, + {"Using _NoAutoSelect + _NoAutoClear flags.", "使用 _NoAutoSelect + _NoAutoClear 标志。"}, + {"Shift+Click to check multiple boxes.", "Shift+点击 勾选多个框。"}, + {"Shift+Keyboard to copy current value to other boxes.", "Shift+键盘 将当前值复制到其他框。"}, + {"Multi-Select (multiple scopes)", "多选(多作用域)"}, + {"Selection scope", "选中作用域"}, + {"Multi-Select (tiled assets browser)", "多选(平铺资产浏览器)"}, + {"(also access from 'Examples->Assets Browser' in menu)", "(也可从菜单 'Examples->Assets Browser' 进入)"}, + {"Multi-Select (trees)", "多选(树)"}, + {"Selection size: %d", "已选:%d"}, + {"Multi-Select (advanced)", "多选(高级)"}, + {"Tree nodes", "树节点项"}, + {"Enable clipper", "启用裁剪器"}, + {"Enable deletion", "启用删除"}, + {"Enable drag & drop", "启用拖放"}, + {"Show in a table", "显示在表格中"}, + {"Show color button", "显示颜色按钮"}, + {"Dragging %d objects", "正在拖动 %d 个对象"}, + {"Close", "关闭"}, + {"Wiki page:", "Wiki 页面:"}, + {"Multi-select and multiple columns", "多选与多列"}, + {"Multi-select tree", "多选树"}, + {"Multi-select table", "多选表格"}, + {"Use CTRL+Click to select multiple items.", "CTRL+点击 选择多项。"}, + {"Hold SHIFT to select a range.", "SHIFT 选择范围。"}, + {"Basic Trees", "基础树"}, + {"Hierarchy Lines", "层级连线"}, + {"Clipping Large Trees", "裁剪大型树"}, + {"Selectable Nodes", "可选节点"}, + {"Advanced", "高级"}, + {"Parent", "父节点"}, + {"Child 1", "子节点 1"}, + {"Child 2", "子节点 2"}, + {"Button for Child 1", "子节点 1 按钮"}, + {"Button for Child 2", "子节点 2 按钮"}, + {"Remaining contents", "剩余内容"}, + {"blah blah", "内容内容"}, + {"button", "按钮"}, + {"This is a drag and drop source", "这是一个拖放源"}, + {"Blah blah\nBlah Blah", "内容内容\n内容内容"}, + {"", "<节点内容>"}, + {"Align label with current X position", "与当前 X 位置对齐标签"}, + {"Make Tree Nodes as drag & drop sources", "将树节点作为拖放源"}, + {"Basic trees", "基础树"}, + {"Advanced, with Selectable nodes", "高级(带可选节点)"}, + {"Leaf node", "叶节点"}, + {"Child node 0", "子节点 0"}, + {"Child node 1", "子节点 1"}, + {"Fancy", "高级"}, + {"Curve", "曲线"}, + {"Sin(time) = %f", "Sin(时间) = %f"}, + {"Always On", "始终显示"}, + {"Off", "关闭"}, + {"Always On (Simple)", "始终显示(简单)"}, + {"Always On (Advanced)", "始终显示(高级)"}, + {"I am following you around.", "我在跟随你。"}, + {"I am a fancy tooltip", "我是一个高级提示框"}, + {"flags for a specific tooltip instance.", "针对特定提示框实例的标志。"}, + {"Manual", "手动"}, + {"I am a manually emitted tooltip.", "我是手动触发的提示框。"}, + {"DelayNone", "无延迟"}, + {"I am a tooltip with no delay.", "我是一个无延迟的提示框。"}, + {"DelayShort", "短延迟"}, + {"I am a tooltip with a short delay (%0.2f sec).", "我是一个短延迟提示框(%0.2f 秒)。"}, + {"DelayLong", "长延迟"}, + {"I am a tooltip with a long delay (%0.2f sec).", "我是一个长延迟提示框(%0.2f 秒)。"}, + {"Stationary", "静止触发"}, + {"I am a tooltip requiring mouse to be stationary before activating.", "我需要鼠标静止后才会显示。"}, + {"Disabled item", "禁用项"}, + {"I am a tooltip for a disabled item.", "我是禁用项的提示框。"}, + {"Always on", "始终显示"}, + {"Delay", "延迟"}, + {"Programmatic", "程序化"}, + {"Variable delay", "可变延迟"}, + {"Short", "短"}, + {"Long", "长"}, + {"Stationary delay", "静止延迟"}, + {"Scroll to select", "滚动选择"}, + {"Fixed", "固定"}, + {"(close)", "(关闭)"}, + {"(Closed)", "(已关闭)"}, + // === Step 9: Layout === + {"Child windows", "子窗口"}, + {"Disable Mouse Wheel", "禁用鼠标滚轮"}, + {"Disable Menu", "禁用菜单"}, + {"%04d: scrollable region", "%04d: 可滚动区域"}, + {"Manual-resize", "手动调整大小"}, + {"Auto-resize with constraints", "带约束的自动调整大小"}, + {"Lines Count", "行数"}, + {"Max Height (in Lines)", "最大高度(行数)"}, + {"Misc/Advanced", "杂项/高级"}, + {"Offset X", "X 偏移"}, + {"Override ChildBg color", "覆盖子窗口背景色"}, + {"Some test %d", "测试项 %d"}, + {"Hovered: %d", "悬浮: %d"}, + {"Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", "子窗口矩形: (%.0f,%.0f) (%.0f,%.0f)"}, + {"Widgets Width", "控件宽度"}, + {"Show indented items", "显示缩进项"}, + {"SetNextItemWidth/PushItemWidth(100)", "SetNextItemWidth/PushItemWidth(100)"}, + {"Fixed width.", "固定宽度。"}, + {"SetNextItemWidth/PushItemWidth(-100)", "SetNextItemWidth/PushItemWidth(-100)"}, + {"Align to right edge minus 100", "对齐到右边缘减 100"}, + {"SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)", "SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)"}, + {"Half of available width.\n(~ right-cursor_pos)\n(works within a column set)", "可用宽度的一半。\n(~ 右侧光标位置)\n(在列集中有效)"}, + {"SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)", "SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)"}, + {"Align to right edge minus half", "对齐到右边缘减半"}, + {"SetNextItemWidth/PushItemWidth(-FLT_MIN)", "SetNextItemWidth/PushItemWidth(-FLT_MIN)"}, + {"Align to right edge", "对齐到右边缘"}, + {"Basic Horizontal Layout", "基础水平布局"}, + {"(Use ImGui::SameLine() to keep adding items to the right of the preceding item)", "(使用 ImGui::SameLine() 在前一个控件右侧继续添加控件)"}, + {"Two items: Hello", "两个控件: Hello"}, + {"Sailor", "水手"}, + {"More spacing: Hello", "更大间距: Hello"}, + {"Normal buttons", "普通按钮"}, + {"Banana", "香蕉"}, + {"Apple", "苹果"}, + {"Corniflower", "矢车菊"}, + {"Small buttons", "小按钮"}, + {"Like this one", "像这个"}, + {"can fit within a text block.", "可以嵌入文本块中。"}, + {"Aligned", "对齐"}, + {"x=150", "x=150"}, + {"x=300", "x=300"}, + {"My", "我的"}, + {"Tailor", "裁缝"}, + {"Is", "是"}, + {"Rich", "富有的"}, + {"Lists:", "列表:"}, + {"Manual wrapping:", "手动换行:"}, + {"Groups", "分组"}, + {"Text Baseline Alignment", "文字基线对齐"}, + {"Text baseline:", "文字基线:"}, + {"Multi-line text:", "多行文本:"}, + {"Misc items:", "杂项控件:"}, + {"Item %d..", "项目 %d.."}, + {"Scrolling", "滚动"}, + {"Decoration", "装饰"}, + {"Item = %d", "项目 = %d"}, + {"Track", "跟踪"}, + {"+%.0f px", "+%.0f px"}, + {"Scroll Offset", "滚动偏移"}, + {"X/Y = %.0f px", "X/Y = %.0f px"}, + {"Scroll To Pos", "滚动到位置"}, + {"Top", "顶部"}, + {"25%", "25%"}, + {"Center", "居中"}, + {"75%", "75%"}, + {"Bottom", "底部"}, + {"Item %d", "项目 %d"}, + {"%.0f/%.0f", "%.0f/%.0f"}, + {"Left", "左"}, + {"Right", "右"}, + {"%s\n%.0f/%.0f", "%s\n%.0f/%.0f"}, + {"Lines", "行数"}, + {"Scroll from code", "代码控制滚动"}, + {"<<", "<<"}, + {">>", ">>"}, + {"Show Horizontal contents size demo window", "显示水平内容尺寸演示窗口"}, + {"Horizontal contents size demo window", "水平内容尺寸演示窗口"}, + {"Use 'Metrics->Tools->Show windows rectangles' to visualize rectangles.", "使用 'Metrics->Tools->Show windows rectangles' 可视化矩形。"}, + {"H-scrollbar", "水平滚动条"}, + {"Text wrapped", "自动换行文本"}, + {"Columns", "列"}, + {"Tab bar", "标签栏"}, + {"Child", "子窗口"}, + {"Explicit content size", "显式内容尺寸"}, + {"Scroll %.1f/%.1f %.1f/%.1f", "滚动 %.1f/%.1f %.1f/%.1f"}, + {"this is a 300-wide button", "这是一个 300 宽的按钮"}, + {"this is a tree node", "这是一个树节点"}, + {"another one of those tree node...", "另一个树节点..."}, + {"Some tree contents", "树节点内容"}, + {"CollapsingHeader", "折叠标题"}, + {"This text should automatically wrap on the edge of the work rectangle.", "这段文字应在工作区边缘自动换行。"}, + {"Tables:", "表格:"}, + {"Width %.2f", "宽度 %.2f"}, + {"Columns:", "列:"}, + {"Text Clipping", "文字裁剪"}, + {"(Click and drag to scroll)", "(点击并拖拽以滚动)"}, + {"Overlap Mode", "重叠模式"}, + {"Enable AllowOverlap", "启用重叠允许"}, + {"Button 1", "按钮 1"}, + {"Button 2", "按钮 2"}, + {"Some Selectable", "可选项"}, + // === Step 10: Popups + About + UserGuide === + {"Popups", "弹窗"}, + {"Select..", "选择.."}, + {"Right-click here", "在此右键"}, + {"right-click me!", "右键点我!"}, + {"right-click on this text", "右键点击此文字"}, + {"Modal windows", "模态框"}, + {"Delete?", "确认删除?"}, + {"This is a modal window", "这是一个模态框"}, + {"Yes", "是"}, + {"No", "否"}, + {"Stacked modals", "嵌套模态框"}, + {"Open another modal", "打开另一个模态框"}, + {"Popups in a menu", "菜单中的弹窗"}, + {"Menus", "菜单"}, + {"Context menus", "右键菜单"}, + {"Menu in a popup", "弹窗内菜单"}, + {"Popups with window restoring focus", "弹窗恢复焦点"}, + {"Open a popup!", "打开弹窗!"}, + {"Dear ImGui is an immediate mode GUI library for C++.", "Dear ImGui 是一个 C++ 即时模式 GUI 库。"}, + {"License:", "许可证:"}, + {"Build Information:", "构建信息:"}, + {"User Guide", "用户指南"}, + {"PROGRAMMER GUIDE", "程序员指南"}, + {"MOUSE & DRAG AND DROP", "鼠标与拖放"}, + {"KEYBOARD, GAMEPAD & FOCUS", "键盘、手柄与焦点"}, + {"Read 'Programmer Guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase.", "阅读 imgui.cpp 中的《程序员指南》了解集成方法。"}, + {"Understood!", "明白了!"}, + {"Oops, button is disabled!", "按钮已被禁用!"}, + // === Step 11: Tables (first half) === + {"Borders, background", "边框与背景"}, + {"Resizable, stretch", "可缩放(拉伸)"}, + {"Resizable, fixed", "可缩放(固定)"}, + {"Resizable, mixed", "可缩放(混合)"}, + {"Sizing policies", "尺寸策略"}, + {"Vertical scrolling, with clipping", "垂直滚动(带裁剪)"}, + {"Horizontal scrolling", "水平滚动"}, + {"Columns flags", "列标志"}, + {"Columns widths", "列宽"}, + {"Nested tables", "嵌套表格"}, + {"Row height", "行高"}, + {"Outer size", "外部尺寸"}, + {"Reorderable, hideable, with headers", "可重排、可隐藏(带表头)"}, + {"Padding", "内边距"}, + {"Disable tree indentation", "禁用树缩进"}, + {"Expand all", "展开全部"}, + {"Collapse all", "折叠全部"}, + {"Display headers", "显示表头"}, + // === Step 11b: Tables (second half, part 1) === + {"Headers", "表头"}, + {"Row flags", "行标志"}, + {"Reordering", "重排"}, + {"Hiding", "隐藏"}, + {"Sorting", "排序"}, + {"Column types", "列类型"}, + {"Borders", "边框"}, + {"Full headers", "完整表头"}, + {"Foot0", "底部0"}, + {"Foot1", "底部1"}, + {"Foot2", "底部2"}, + {"Seat#", "座位号"}, + {"Age", "年龄"}, + {"Average", "平均"}, + {"Sum", "总计"}, + {"First Name", "名"}, + {"Last Name", "姓"}, + {"Bream", "鲷鱼"}, + {"Haddock", "黑线鳕"}, + {"Mackerel", "鲭鱼"}, + {"Pollock", "鳕鱼"}, + {"Tilefish", "马头鱼"}, + {"Dragonfruit", "火龙果"}, + {"Eggplant", "茄子"}, + {"Fig", "无花果"}, + {"Guava", "番石榴"}, + {"Vertical headers", "垂直表头"}, + {"Custom headers", "自定义表头"}, + {"Row background color", "行背景色"}, + // === Step 11b: Tables (second half, part 2) === + {"Background color", "背景色"}, + {"Tree view", "树形视图"}, + {"Item width", "条目宽度"}, + {"Angled headers", "斜角表头"}, + {"Style settings", "样式设置"}, + {"Synced instances", "同步实例"}, + {"Legacy Columns API", "旧版 Columns API"}, + {"Mixed items", "混合条目"}, + {"Word-wrapping", "自动换行"}, + {"Horizontal Scrolling", "水平滚动"}, + {"Tree", "树形"}, + {"Name", "名称"}, + {"Type", "类型"}, + {"small", "小"}, + {"half", "半"}, + {"right-align", "右对齐"}, + {"Apricot", "杏"}, + {"Cherry", "樱桃"}, + {"One", "一"}, + {"Two", "二"}, + {"Three", "三"}, + {"ID", "ID"}, + {"Action", "操作"}, + {"Quantity", "数量"}, + {"Description", "描述"}, + {"Without border:", "无边框:"}, + {"With border:", "有边框:"}, + {"Path", "路径"}, + {"Hovered", "悬停"}, + {"horizontal", "水平"}, + {"vertical", "垂直"}, + {"Long text that is likely to clip", "很可能被截断的长文本"}, + {"Hello", "你好"}, + {"An extra line here.", "这里额外一行。"}, + {"Category A", "类别 A"}, + {"Category B", "类别 B"}, + {"Category C", "类别 C"}, + {"Blah blah blah", "巴拉巴拉巴拉"}, + {"Node contents", "节点内容"}, + {"Tree in column", "列中的树"}, + {"Even more contents", "更多内容"}, + {"The quick brown fox jumps over the lazy dog", "快速的棕色狐狸跳过了懒狗"}, + // === Step 12: Inputs + Style Editor === + {"This is a simplified view. See more detailed input state:\n- in 'Tools->Metrics/Debugger->Inputs'.\n- in 'Tools->Debug Log->IO'.", "这是简化视图。详细输入状态请查看:\n- 'Tools->Metrics/Debugger->Inputs'\n- 'Tools->Debug Log->IO'"}, + {"Mouse pos: (%g, %g)", "鼠标位置:(%g, %g)"}, + {"Mouse pos: ", "鼠标位置:<无效>"}, + {"Mouse delta: (%g, %g)", "鼠标增量:(%g, %g)"}, + {"Mouse down:", "鼠标按下:"}, + {"Mouse wheel: %.1f", "鼠标滚轮:%.1f"}, + {"Mouse clicked count:", "鼠标点击次数:"}, + {"Keys down:", "按下的键:"}, + {"Keys mods: %s%s%s%s", "修饰键:%s%s%s%s"}, + {"Chars queue:", "字符队列:"}, + {"Outputs", "输出"}, + {"WantCapture override", "捕获覆盖"}, + {"Hovering the colored canvas will override io.WantCaptureXXX fields.\nNotice how normally (when set to none), the value of io.WantCaptureKeyboard would be false when hovering and true when clicking.", "悬停在彩色画布上将覆盖 io.WantCaptureXXX 字段。\n注意通常情况下(设为 none 时),悬停时 io.WantCaptureKeyboard 为 false,点击时为 true。"}, + {"None", "无"}, + {"Set to false", "设为 false"}, + {"Set to true", "设为 true"}, + {"SetNextFrameWantCaptureMouse() on hover", "悬停时调用 SetNextFrameWantCaptureMouse()"}, + {"SetNextFrameWantCaptureKeyboard() on hover", "悬停时调用 SetNextFrameWantCaptureKeyboard()"}, + {"Shortcuts", "快捷键"}, + {"Using SetNextItemShortcut()", "使用 SetNextItemShortcut()"}, + {"Using Shortcut()", "使用 Shortcut()"}, + {"Factor", "系数"}, + {"Press Ctrl+A and see who receives it!", "按 Ctrl+A 查看谁接收到了!"}, + {"Current mouse cursor = %d: %s", "当前鼠标光标 = %d: %s"}, + {"Hover to see mouse cursors:", "悬停查看鼠标光标:"}, + {"Tabbing", "Tab 键导航"}, + {"Use Tab/Shift+Tab to cycle through keyboard editable fields.", "使用 Tab/Shift+Tab 在可编辑字段间切换。"}, + {"Focus from code", "代码设置焦点"}, + {"Focus on 1", "聚焦到 1"}, + {"Focus on 2", "聚焦到 2"}, + {"Focus on 3", "聚焦到 3"}, + {"Focus on X", "聚焦到 X"}, + {"Focus on Y", "聚焦到 Y"}, + {"Focus on Z", "聚焦到 Z"}, + {"Dragging", "拖拽"}, + {"GetMouseDragDelta(0):", "GetMouseDragDelta(0):"}, + // Style Editor + {"For instructions, see:", "使用说明请查看:"}, + {"Save Ref", "保存参考"}, + {"Revert Ref", "还原参考"}, + {"Details", "详细设置"}, + {"Sizes", "尺寸"}, + {"Colors", "颜色"}, + {"Fonts", "字体"}, + {"Rendering", "渲染"}, + {"Only Modified Colors", "仅显示修改的颜色"}, + {"Filter colors", "过滤颜色"}, + {"Opaque", "不透明"}, + {"Alpha", "Alpha"}, + {"Both", "两者"}, + {"Revert", "还原"}, + {"Anti-aliased lines", "抗锯齿线条"}, + {"Anti-aliased lines use texture", "抗锯齿线条使用纹理"}, + {"Anti-aliased fill", "抗锯齿填充"}, + {"Curve Tessellation Tolerance", "曲线细分容差"}, + {"Circle Tessellation Max Error", "圆形细分最大误差"}, + // === Step 13: Example Apps === + {"Example: Main Menu Bar", "示例:主菜单栏"}, + {"Edit", "编辑"}, + {"Undo", "撤销"}, + {"Redo", "重做"}, + {"Cut", "剪切"}, + {"Paste", "粘贴"}, + {"Example: Console", "示例:控制台"}, + {"Command:", "命令:"}, + {"Clear", "清空"}, + {"Scroll to bottom", "滚动到底部"}, + {"Auto-scroll", "自动滚动"}, + {"Enter 'HELP' for help.", "输入 'HELP' 获取帮助。"}, + {"Example: Log", "示例:日志"}, + {"Enable scrolling", "启用自动滚动"}, + {"Add Dummy Text", "添加示例文字"}, + {"Add Dummy Error", "添加示例错误"}, + {"Example: Simple Layout", "示例:简单布局"}, + {"Example: Property editor", "示例:属性编辑器"}, + {"Example: Long text display", "示例:长文本显示"}, + {"Example: Auto-resizing window", "示例:自动缩放窗口"}, + {"Example: Constrained-resizing window", "示例:约束缩放窗口"}, + {"Example: Simple overlay", "示例:简单浮层"}, + {"n/a", "不可用"}, + {"Example: Fullscreen window", "示例:全屏窗口"}, + {"Example: Manipulating window titles", "示例:操控窗口标题"}, + {"Example: Custom rendering", "示例:自定义渲染"}, + {"Example: Documents", "示例:文档管理"}, + {"(Untitled)", "(未命名)"}, + {"Erase", "擦除"}, + {"Stroke", "描边"}, + {"Primitives", "图元"}, + {"BG/FG draw lists", "前/后景绘制列表"}, + {"Mesh", "网格"}, + {"Textures", "纹理"}, + {"Example: Assets Browser", "示例:资产浏览器"}, + {"HELP", "帮助"}, + {"HISTORY", "历史"}, + {"CLEAR", "清空"}, + {"Close Me", "关闭"}, + // Additional strings from Step 13 + {"Use work area instead of main area", "使用工作区而非主区域"}, + {"Close this window", "关闭此窗口"}, + {"This window has a changing title.", "此窗口具有动态标题。"}, + {"Simple overlay\n(right-click to change position)", "简单浮层\n(右键更改位置)"}, + {"Mouse Position: ", "鼠标位置:<无效>"}, + {"(Hold Shift to display a dummy viewport)", "(按住 Shift 显示虚拟视口)"}, + {"Auto-resize", "自动缩放"}, + {"Constraint", "约束"}, + {"Use Clipper", "使用裁剪器"}, + {"Printing unusually long amount of text.", "正在打印超长文本。"}, + {"Test type", "测试类型"}, + {"Gradients", "渐变"}, + {"All primitives", "所有图元"}, + {"Draw in Background draw list", "在背景绘制列表中绘制"}, + {"Draw in Foreground draw list", "在前景绘制列表中绘制"}, + {"Blue shape is drawn first: appears in back", "蓝色形状先绘制:显示在后面"}, + {"Red shape is drawn after: appears in front", "红色形状后绘制:显示在前面"}, + {"Blue shape is drawn first, into channel 1: appears in front", "蓝色形状先绘制到通道1:显示在前面"}, + {"Red shape is drawn after, into channel 0: appears in back", "红色形状后绘制到通道0:显示在后面"}, + {"After reordering, contents of channel 0 appears below channel 1.", "重排后,通道0的内容显示在通道1下方。"}, + {"Close All Documents", "关闭所有文档"}, + {"Rename..", "重命名.."}, + {"Modify", "修改"}, + {"Save change to the following items?", "将更改保存到以下项目?"}, + {"Cancel", "取消"}, + {"Add 10000 items", "添加10000个项目"}, + {"Clear items", "清除项目"}, + {"Delete", "删除"}, + {"Contents", "内容"}, + {"Selection Behavior", "选择行为"}, + {"Layout", "布局"}, + {"Show Type Overlay", "显示类型覆盖"}, + {"Allow Sorting", "允许排序"}, + {"Allow box-selection", "允许框选"}, + {"Allow box-selection from selected items", "允许从已选项目框选"}, + {"Allow dragging unselected item", "允许拖拽未选项目"}, + {"Icon Size", "图标大小"}, + {"Icon Spacing", "图标间距"}, + {"Icon Hit Spacing", "图标命中间距"}, + {"Stretch Spacing", "拉伸间距"}, + {"Use ScrollX", "启用水平滚动"}, + {"%d assets", "%d 个资产"}, + {"Selection: %d items", "已选:%d 个项目"}, + {"Help", "帮助"}, + // === main.mm window === + // "Hello, world!" and "This is some useful text." are intentionally kept in English + // as they are universally recognized programming example strings. + {"Demo Window", "演示窗口"}, + {"Another Window", "另一个窗口"}, + // "float" is kept as-is: it labels a SliderFloat() demonstrating the float type. + {"clear color", "背景颜色"}, + {"Application average %.3f ms/frame (%.1f FPS)", "平均 %.3f 毫秒/帧(%.1f FPS)"}, + {"Hello from another window!", "来自另一个窗口的问候!"}, + {"Close Me", "关闭"}, + // === Help collapsing section === + {"ABOUT THIS DEMO:", "关于本演示:"}, + {"Sections below are demonstrating many aspects of the library.", "下方各章节展示了库的众多特性。"}, + {"The \"Examples\" menu above leads to more demo contents.", "上方「示例」菜单包含更多演示内容。"}, + {"The \"Tools\" menu above gives access to: About Box, Style Editor,\nand Metrics/Debugger (general purpose Dear ImGui debugging tool).", "上方「工具」菜单可访问:关于弹窗、样式编辑器\n以及指标/调试器(通用 Dear ImGui 调试工具)。"}, + {"Web demo (w/ source code browser): ", "在线演示(含源码浏览器):"}, + {"PROGRAMMER GUIDE:", "程序员指南:"}, + {"See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!", "参阅 imgui_demo.cpp 中的 ShowDemoWindow() 代码。← 你在这里!"}, + {"See comments in imgui.cpp.", "参阅 imgui.cpp 中的注释。"}, + {"See example applications in the examples/ folder.", "参阅 examples/ 目录下的示例程序。"}, + {"Read the FAQ at ", "阅读 FAQ:"}, + {"Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.", "设置 'io.ConfigFlags |= NavEnableKeyboard' 以启用键盘控制。"}, + {"Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.", "设置 'io.ConfigFlags |= NavEnableGamepad' 以启用手柄控制。"}, + {"USER GUIDE:", "用户指南:"}, + // === Configuration panel HelpMarker tooltips === + {"Enable keyboard controls.", "启用键盘控制。"}, + {"Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.", "启用手柄控制。需要后端设置 io.BackendFlags |= ImGuiBackendFlags_HasGamepad。\n\n详情请阅读 imgui.cpp 中的说明。"}, + {"Instruct dear imgui to disable mouse inputs and interactions.", "禁止 Dear ImGui 处理鼠标输入和交互。"}, + {"Instruct backend to not alter mouse cursor shape and visibility.", "禁止后端修改鼠标光标形状和可见性。"}, + {"Instruct dear imgui to disable keyboard inputs and interactions.", "禁止 Dear ImGui 处理键盘输入和交互。"}, + {"Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.", "启用输入队列滴流:同一帧内提交的某些事件(如按下+抬起)将分散到多帧处理,改善低帧率下的交互体验。"}, + {"Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).", "让 Dear ImGui 自行渲染鼠标光标。通过 GPU 渲染的软件光标会比硬件光标略有延迟,但与其他画面更同步。\n\n部分桌面应用会同时使用两种光标(如仅在拖拽/缩放时启用软件光标)。"}, + {"Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult", "方向键/Tab 导航会瞬移鼠标光标。在难以移动虚拟鼠标的电视/主机系统上很有用。"}, + {"Pressing Escape clears focused item.", "按 Escape 键清除焦点控件。"}, + {"Pressing Escape clears focused window.", "按 Escape 键清除焦点窗口。"}, + {"Using directional navigation key makes the cursor visible. Mouse click hides the cursor.", "使用方向导航键时显示光标,鼠标点击时隐藏光标。"}, + {"Navigation cursor is always visible.", "导航光标始终可见。"}, + {"Enable resizing of windows from their edges and from the lower-left corner.\nThis requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback.", "允许从窗口边缘和左下角调整大小。\n需要 ImGuiBackendFlags_HasMouseCursors 以获得更好的光标反馈。"}, + {"*EXPERIMENTAL* Ctrl+C copy the contents of focused window into the clipboard.\n\nExperimental because:\n- (1) has known issues with nested Begin/End pairs.\n- (2) text output quality varies.\n- (3) text output is in submission order rather than spatial order.", "*实验性* Ctrl+C 将焦点窗口内容复制到剪贴板。\n\n实验性原因:\n- (1) 嵌套 Begin/End 有已知问题。\n- (2) 文字输出质量不稳定。\n- (3) 输出按提交顺序而非空间顺序排列。"}, + {"Enable scrolling page by page when clicking outside the scrollbar grab.\nWhen disabled, always scroll to clicked location.\nWhen enabled, Shift+Click scrolls to clicked location.", "点击滚动条轨道时逐页滚动。\n禁用时:始终滚动到点击位置。\n启用时:Shift+点击滚动到点击位置。"}, + {"Enable blinking cursor (optional as some users consider it to be distracting).", "启用闪烁光标(部分用户认为会分散注意力,可选)。"}, + {"Pressing Enter will reactivate item and select all text (single-line only).", "按 Enter 键重新激活控件并全选文字(仅单行)。"}, + {"Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving).", "点击 DragXXX 控件后不移动即可切换为文本输入模式。"}, + {"Swap Cmd<>Ctrl keys, enable various MacOS style behaviors.", "交换 Cmd<>Ctrl 键,启用各种 macOS 风格行为。"}, + }); + } +} s_zh_cn; +} // namespace diff --git a/misc/i18n/tools/extract_strings.py b/misc/i18n/tools/extract_strings.py new file mode 100644 index 000000000000..d9f54b0111a7 --- /dev/null +++ b/misc/i18n/tools/extract_strings.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +""" +用法:python3 extract_strings.py imgui_demo.cpp 302 737 +输出 zh_CN.cpp 条目骨架(key=英文,value 留空供人工翻译) +""" +import sys, re + +def extract(path, start, end): + with open(path) as f: + lines = f.readlines() + chunk = ''.join(lines[start-1:end-1]) + strings = re.findall(r'"([^"\n]{2,80})"', chunk) + seen = set() + results = [] + skip = re.compile(r'^(##|###|%[0-9.]*[dfsx]$|[0-9.]+$)') + for s in strings: + if s in seen or skip.match(s): continue + seen.add(s) + results.append(s) + for s in results: + escaped = s.replace('\\', '\\\\').replace('"', '\\"') + print(f' {{"{escaped}", ""}},') + +if __name__ == '__main__': + extract(sys.argv[1], int(sys.argv[2]), int(sys.argv[3])) From e8fdf812b2470146774e54df70fd11f08c265366 Mon Sep 17 00:00:00 2001 From: xuk Date: Wed, 10 Jun 2026 14:39:43 +0800 Subject: [PATCH 10/12] i18n: translate ShowUserGuide() strings (zh_CN) Wrap all BulletText() calls in ShowUserGuide() with Tr() and add Simplified Chinese translations for all 20 user guide strings. --- imgui_demo.cpp | 54 ++++++++++++++++++-------------------- misc/i18n/locale/zh_CN.cpp | 27 +++++++++++++++++++ 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index aa92115bdd2f..5a4cd34cec75 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -8846,40 +8846,38 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) void ImGui::ShowUserGuide() { ImGuiIO& io = GetIO(); - BulletText("Double-click on title bar to collapse window."); - BulletText( - "Click and drag on lower corner or border to resize window.\n" - "(double-click to auto fit window to its contents)"); - BulletText("Ctrl+Click on a slider or drag box to input value as text."); - BulletText("Tab/Shift+Tab to cycle through keyboard editable fields."); - BulletText("Ctrl+Tab/Ctrl+Shift+Tab to focus windows."); + BulletText("%s", Tr("Double-click on title bar to collapse window.")); + BulletText("%s", Tr("Click and drag on lower corner or border to resize window.\n(double-click to auto fit window to its contents)")); + BulletText("%s", Tr("Ctrl+Click on a slider or drag box to input value as text.")); + BulletText("%s", Tr("Tab/Shift+Tab to cycle through keyboard editable fields.")); + BulletText("%s", Tr("Ctrl+Tab/Ctrl+Shift+Tab to focus windows.")); if (io.FontAllowUserScaling) - BulletText("Ctrl+Mouse Wheel to zoom window contents."); - BulletText("While inputting text:\n"); + BulletText("%s", Tr("Ctrl+Mouse Wheel to zoom window contents.")); + BulletText("%s", Tr("While inputting text:")); Indent(); - BulletText("Ctrl+Left/Right to word jump."); - BulletText("Ctrl+A or double-click to select all."); - BulletText("Ctrl+X/C/V to use clipboard cut/copy/paste."); - BulletText("Ctrl+Z to undo, Ctrl+Y/Ctrl+Shift+Z to redo."); - BulletText("Escape to revert."); + BulletText("%s", Tr("Ctrl+Left/Right to word jump.")); + BulletText("%s", Tr("Ctrl+A or double-click to select all.")); + BulletText("%s", Tr("Ctrl+X/C/V to use clipboard cut/copy/paste.")); + BulletText("%s", Tr("Ctrl+Z to undo, Ctrl+Y/Ctrl+Shift+Z to redo.")); + BulletText("%s", Tr("Escape to revert.")); Unindent(); - BulletText("With Keyboard controls enabled:"); + BulletText("%s", Tr("With Keyboard controls enabled:")); Indent(); - BulletText("Arrow keys or Home/End/PageUp/PageDown to navigate."); - BulletText("Space to activate a widget."); - BulletText("Return to input text into a widget."); - BulletText("Escape to deactivate a widget, close popup,\nexit a child window or the menu layer, clear focus."); - BulletText("Alt to jump to the menu layer of a window."); - BulletText("Menu or Shift+F10 to open a context menu."); + BulletText("%s", Tr("Arrow keys or Home/End/PageUp/PageDown to navigate.")); + BulletText("%s", Tr("Space to activate a widget.")); + BulletText("%s", Tr("Return to input text into a widget.")); + BulletText("%s", Tr("Escape to deactivate a widget, close popup,\nexit a child window or the menu layer, clear focus.")); + BulletText("%s", Tr("Alt to jump to the menu layer of a window.")); + BulletText("%s", Tr("Menu or Shift+F10 to open a context menu.")); Unindent(); - BulletText("With Gamepad controls enabled:"); + BulletText("%s", Tr("With Gamepad controls enabled:")); Indent(); - BulletText("D-Pad: Navigate / Tweak / Resize (in Windowing mode)."); - BulletText("%s Face button: Activate / Open / Toggle. Hold: activate with text input.", io.ConfigNavSwapGamepadButtons ? "East" : "South"); - BulletText("%s Face button: Cancel / Close / Exit.", io.ConfigNavSwapGamepadButtons ? "South" : "East"); - BulletText("West Face button: Toggle Menu. Hold for Windowing mode (Focus/Move/Resize windows)."); - BulletText("North Face button: Open Context Menu."); - BulletText("L1/R1: Tweak Slower/Faster, Focus Previous/Next (in Windowing Mode)."); + BulletText("%s", Tr("D-Pad: Navigate / Tweak / Resize (in Windowing mode).")); + BulletText(Tr("%s Face button: Activate / Open / Toggle. Hold: activate with text input."), io.ConfigNavSwapGamepadButtons ? "East" : "South"); + BulletText(Tr("%s Face button: Cancel / Close / Exit."), io.ConfigNavSwapGamepadButtons ? "South" : "East"); + BulletText("%s", Tr("West Face button: Toggle Menu. Hold for Windowing mode (Focus/Move/Resize windows).")); + BulletText("%s", Tr("North Face button: Open Context Menu.")); + BulletText("%s", Tr("L1/R1: Tweak Slower/Faster, Focus Previous/Next (in Windowing Mode).")); Unindent(); } diff --git a/misc/i18n/locale/zh_CN.cpp b/misc/i18n/locale/zh_CN.cpp index 737d75a53125..b79c3e65d484 100644 --- a/misc/i18n/locale/zh_CN.cpp +++ b/misc/i18n/locale/zh_CN.cpp @@ -794,6 +794,33 @@ struct ZhCNRegistrar { {"Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.", "设置 'io.ConfigFlags |= NavEnableKeyboard' 以启用键盘控制。"}, {"Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.", "设置 'io.ConfigFlags |= NavEnableGamepad' 以启用手柄控制。"}, {"USER GUIDE:", "用户指南:"}, + // === User Guide (ShowUserGuide) === + {"Double-click on title bar to collapse window.", "双击标题栏折叠窗口。"}, + {"Click and drag on lower corner or border to resize window.\n(double-click to auto fit window to its contents)", "拖拽右下角或边框调整窗口大小。\n(双击自动适应内容)"}, + {"Ctrl+Click on a slider or drag box to input value as text.", "Ctrl+点击滑块或拖拽框,可直接输入数值。"}, + {"Tab/Shift+Tab to cycle through keyboard editable fields.", "Tab/Shift+Tab 在可编辑字段间切换。"}, + {"Ctrl+Tab/Ctrl+Shift+Tab to focus windows.", "Ctrl+Tab/Ctrl+Shift+Tab 切换窗口焦点。"}, + {"Ctrl+Mouse Wheel to zoom window contents.", "Ctrl+滚轮缩放窗口内容。"}, + {"While inputting text:", "输入文字时:"}, + {"Ctrl+Left/Right to word jump.", "Ctrl+左/右方向键按单词跳转。"}, + {"Ctrl+A or double-click to select all.", "Ctrl+A 或双击全选。"}, + {"Ctrl+X/C/V to use clipboard cut/copy/paste.", "Ctrl+X/C/V 剪切/复制/粘贴。"}, + {"Ctrl+Z to undo, Ctrl+Y/Ctrl+Shift+Z to redo.", "Ctrl+Z 撤销,Ctrl+Y/Ctrl+Shift+Z 重做。"}, + {"Escape to revert.", "Escape 还原。"}, + {"With Keyboard controls enabled:", "启用键盘控制后:"}, + {"Arrow keys or Home/End/PageUp/PageDown to navigate.", "方向键或 Home/End/PageUp/PageDown 导航。"}, + {"Space to activate a widget.", "空格键激活控件。"}, + {"Return to input text into a widget.", "Enter 键向控件输入文字。"}, + {"Escape to deactivate a widget, close popup,\nexit a child window or the menu layer, clear focus.", "Escape 键取消激活控件、关闭弹窗、\n退出子窗口或菜单层、清除焦点。"}, + {"Alt to jump to the menu layer of a window.", "Alt 键跳转到窗口菜单层。"}, + {"Menu or Shift+F10 to open a context menu.", "Menu 或 Shift+F10 打开右键菜单。"}, + {"With Gamepad controls enabled:", "启用手柄控制后:"}, + {"D-Pad: Navigate / Tweak / Resize (in Windowing mode).", "方向键:导航/调整/缩放(窗口模式)。"}, + {"%s Face button: Activate / Open / Toggle. Hold: activate with text input.", "%s 键:激活/打开/切换。长按:激活并输入文字。"}, + {"%s Face button: Cancel / Close / Exit.", "%s 键:取消/关闭/退出。"}, + {"West Face button: Toggle Menu. Hold for Windowing mode (Focus/Move/Resize windows).", "West 键:切换菜单。长按进入窗口模式(聚焦/移动/缩放)。"}, + {"North Face button: Open Context Menu.", "North 键:打开右键菜单。"}, + {"L1/R1: Tweak Slower/Faster, Focus Previous/Next (in Windowing Mode).", "L1/R1:慢速/快速调整,切换焦点(窗口模式)。"}, // === Configuration panel HelpMarker tooltips === {"Enable keyboard controls.", "启用键盘控制。"}, {"Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.", "启用手柄控制。需要后端设置 io.BackendFlags |= ImGuiBackendFlags_HasGamepad。\n\n详情请阅读 imgui.cpp 中的说明。"}, From e9cd46672a75063bdc399ecb4d4e16532fc6a32a Mon Sep 17 00:00:00 2001 From: xuk Date: Wed, 10 Jun 2026 16:59:39 +0800 Subject: [PATCH 11/12] =?UTF-8?q?i18n:=20simplify=20RebuildFonts()=20?= =?UTF-8?q?=E2=80=94=20remove=20glyph=20ranges=20and=20ref=20size=20workar?= =?UTF-8?q?ound?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In v1.92+ with an updated backend, glyph ranges are handled dynamically and do not need to be specified. Remove GetGlyphRangesChineseSimplifiedCommon(), the zh_label_ranges English stub, and the explicit SizePixels on AddFontDefault() that was added to work around the ImplicitRefSize assertion. Use plain MergeMode instead. --- examples/example_apple_metal/main.mm | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/examples/example_apple_metal/main.mm b/examples/example_apple_metal/main.mm index 0157dc1d45e2..3b5c19b59705 100644 --- a/examples/example_apple_metal/main.mm +++ b/examples/example_apple_metal/main.mm @@ -51,15 +51,10 @@ static void RebuildFonts() { ImGuiIO& io = ImGui::GetIO(); io.Fonts->ClearFonts(); - // v1.92: must pass explicit SizePixels so base font is not marked ImplicitRefSize, - // otherwise MergeMode on the CJK font triggers an assertion. - ImFontConfig default_cfg; - default_cfg.SizePixels = 13.0f; - io.Fonts->AddFontDefault(&default_cfg); - - // Merge CJK font: - // zh_CN → full common range (~2500 glyphs, renders all translated text) - // English → only "中文" (2 glyphs U+4E2D,U+6587) so Language menu label renders correctly + io.Fonts->AddFontDefault(); + + // Merge a CJK font so the Language menu and translated strings render correctly. + // In v1.92+ with an updated backend, glyph ranges are handled dynamically and do not need to be specified. // Hiragino Sans GB is designed for Simplified Chinese; fall back to STHeiti. const char* font_paths[] = { "/System/Library/Fonts/Hiragino Sans GB.ttc", @@ -71,13 +66,9 @@ static void RebuildFonts() if (access(font_paths[i], R_OK) == 0) { chosen = font_paths[i]; break; } } if (chosen) { - static const ImWchar zh_label_ranges[] = { 0x4E2D, 0x4E2D, 0x6587, 0x6587, 0 }; - bool is_zh = (strcmp(imgui_i18n::getLocale(), "zh_CN") == 0); ImFontConfig cfg; - cfg.MergeMode = true; - cfg.PixelSnapH = true; - io.Fonts->AddFontFromFileTTF(chosen, 13.0f, &cfg, - is_zh ? io.Fonts->GetGlyphRangesChineseSimplifiedCommon() : zh_label_ranges); + cfg.MergeMode = true; + io.Fonts->AddFontFromFileTTF(chosen, 13.0f, &cfg); } io.Fonts->Build(); } From 552986072abeb867ea95d3694c821d0e2741521a Mon Sep 17 00:00:00 2001 From: xuk Date: Wed, 10 Jun 2026 17:55:10 +0800 Subject: [PATCH 12/12] i18n: fix ImplicitRefSize assertion by passing 0.0f size to merged CJK font AddFontDefault() uses implicit ref size. Passing an explicit size (13.0f) to AddFontFromFileTTF() in MergeMode triggers the assertion because the two fonts use different ref size conventions. Pass 0.0f instead so both fonts share the same implicit ref size and scale together with style.FontSizeBase. --- examples/example_apple_metal/main.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/example_apple_metal/main.mm b/examples/example_apple_metal/main.mm index 3b5c19b59705..63feae0bd2b1 100644 --- a/examples/example_apple_metal/main.mm +++ b/examples/example_apple_metal/main.mm @@ -68,7 +68,7 @@ static void RebuildFonts() if (chosen) { ImFontConfig cfg; cfg.MergeMode = true; - io.Fonts->AddFontFromFileTTF(chosen, 13.0f, &cfg); + io.Fonts->AddFontFromFileTTF(chosen, 0.0f, &cfg); // 0.0f = implicit ref size, matches AddFontDefault() } io.Fonts->Build(); }