# Localization Guide This document explains how to add, modify, and translate user-visible strings in ClaudeForge. --- ## Table of Contents 1. [How it works](#how-it-works) 2. [Adding or changing a string](#adding-or-changing-a-string) 3. [Key naming conventions](#key-naming-conventions) 4. [Using strings in AXAML](#using-strings-in-axaml) 5. [Using strings in C# code](#using-strings-in-c-code) 6. [Adding a new language](#adding-a-new-language) 7. [Culture resolution at startup](#culture-resolution-at-startup) 8. [Regenerating Strings.Designer.cs](#regenerating-stringsdesignercs) 9. [Trimming and single-file builds](#trimming-and-single-file-builds) --- ## How it works All user-visible strings live in a single `.resx` file: ``` src/ClaudeForge/Localization/ ├── Strings.resx ← master English strings (edit this) ├── Strings.Designer.cs ← auto-generated strongly-typed wrapper (commit this) └── Strings.zh-Hans.resx ← example translation file (create per language) ``` The `Strings.resx` file is an embedded resource compiled into the assembly. The .NET `ResourceManager` resolves the correct satellite assembly at runtime based on `CultureInfo.CurrentUICulture`. If no satellite assembly matches the current culture, it falls back to the base English strings. `Strings.Designer.cs` is generated from `Strings.resx` by `ResXFileCodeGenerator`. It exposes every key as a `public static string` property so that typos in key names are caught at compile time rather than at runtime. --- ## Adding or changing a string ### Step 1 — Edit `Strings.resx` Open `src/ClaudeForge/Localization/Strings.resx` and add a `` element inside the `` block. Place it in the section that matches the view or feature it belongs to (sections are marked with `` comments). ```xml Save Profile Save the current settings to this profile ``` Always include `xml:space="preserve"` — it prevents XML parsers from collapsing whitespace inside the value. ### Step 2 — Regenerate `Strings.Designer.cs` In **Visual Studio**: save `Strings.resx` — the `ResXFileCodeGenerator` runs automatically and updates `Strings.Designer.cs`. From the **command line** (no Visual Studio required): ```bash dotnet tool install -g dotnet-resx # one-time install if not present # Alternatively: just add the properties manually (see below) ``` If you prefer to skip the generator entirely, you can add the property manually to `Strings.Designer.cs` following the same pattern used for every other key: ```csharp /// Save Profile public static string ButtonSaveProfile => G("ButtonSaveProfile"); /// Save the current settings to this profile public static string TipButtonSaveProfile => G("TipButtonSaveProfile"); ``` ### Step 3 — Use the string See [Using strings in AXAML](#using-strings-in-axaml) and [Using strings in C# code](#using-strings-in-c-code) below. ### Step 4 — Translate (optional) If a translation file exists for a language (e.g., `Strings.zh-Hans.resx`), add the same key with the translated value there too. --- ## Key naming conventions Keys use a **prefix that describes the UI role** followed by a `PascalCase` description. This keeps the file scannable and makes the intent of each string obvious at a glance. | Prefix | UI role | Example | |--------|---------|---------| | `Button` | Button label | `ButtonSave`, `ButtonOpenProject` | | `Label` | Static label next to a control | `LabelEditingProfile`, `LabelModel` | | `Tip` | Tooltip text | `TipButtonSave`, `TipLabelModel` | | `AutoName` | `AutomationProperties.Name` (screen readers) | `AutoNameButtonSave` | | `AutoHelp` | `AutomationProperties.HelpText` | `AutoHelpSearchBox` | | `Text` | Longer prose, descriptions, warning banners | `TextInstallBannerDesc` | | `Heading` | Section or page heading | `HeadingProfiles` | | `Tab` | Tab strip label | `TabBackup`, `TabSettings` | | `Watermark` | Placeholder text in a text input | `WatermarkSearch` | | `Badge` | Small badge / chip label | `BadgeLabelCli`, `BadgeLabelDesktop` | | `Header` | Column or table header | `HeaderProfileName`, `HeaderCreated` | | `Menu` | Context-menu or menu-bar item | `MenuOpenFileLocation` | | `Dialog` | Dialog title or prompt | `DialogTitleNewProfile` | | `Msg` | Error or informational message (may contain `{0}` placeholders) | `MsgReservedProfileName` | | `Status` | Status-bar message | `StatusReady`, `StatusSaving` | | `Progress` | In-progress indicator text | `ProgressPreparing` | | `StringFormat` | A format string used with `string.Format()` | `StringFormatCliActive` (`"CLI: {0}"`) | | `Section` | Collapsible section title | `SectionClaudeAnthropicNode` | | `Checkbox` | CheckBox content label | `CheckboxShowDialog` | **Tips:** - For a button that also has a tooltip, create both `ButtonXxx` and `TipButtonXxx`. - For a button that is referenced by a screen reader, also create `AutoNameButtonXxx`. - For messages with runtime values, use `{0}`, `{1}`, etc. and call `string.Format()` in code rather than building the string in the resx value. - Emoji are fine in button/label strings (e.g., `💾 Save`) but avoid them in tooltips and accessibility strings where they may be read aloud literally. --- ## Using strings in AXAML ### Namespace declaration Every AXAML file that uses localized strings must declare the `loc` namespace. Add it to the root element alongside the other `xmlns` declarations: ```xml ``` For `UserControl` files the declaration is identical — just on `` instead. ### Binding pattern Use `{x:Static loc:Strings.KeyName}` wherever a string value is needed: ```xml