<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Recent changes to Translating Localizer</title><link>https://sourceforge.net/p/sucrose/wiki/Translating%2520Localizer/</link><description>Recent changes to Translating Localizer</description><atom:link href="https://sourceforge.net/p/sucrose/wiki/Translating%20Localizer/feed" rel="self"/><language>en</language><lastBuildDate>Sat, 04 Jul 2026 04:15:52 -0000</lastBuildDate><atom:link href="https://sourceforge.net/p/sucrose/wiki/Translating%20Localizer/feed" rel="self" type="application/rss+xml"/><item><title>Translating Localizer modified by Bayram Emekli</title><link>https://sourceforge.net/p/sucrose/wiki/Translating%2520Localizer/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v3
+++ v4
@@ -144,7 +144,6 @@

 - The Localizer is **interactive-only** (stdin prompts, no CLI flags). Automating it would require piping the answers.
 - The `Hash` column must stay stable — it is the cross-language join key; reindexing/checking depends on it.
 - There are **two distinct CSV schemas** (working vs POEditor); do not mix them.
-- The website's translations are a **separate surface**: the `.pages/` site uses its own i18n JSON files and is **not** produced by the Localizer. See [Localization Coverage](Localization-Coverage).

 ---

&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Bayram Emekli</dc:creator><pubDate>Sat, 04 Jul 2026 04:15:52 -0000</pubDate><guid>https://sourceforge.net4626db0377e424692fe26ad9fb53621269bfaab0</guid></item><item><title>Translating Localizer modified by Bayram Emekli</title><link>https://sourceforge.net/p/sucrose/wiki/Translating%2520Localizer/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v2
+++ v3
@@ -102,7 +102,7 @@

 ## The Hash key

-The `Hash` column is the **cross-language join key** that ties the same string together across all languages. It is computed as the **MD5** (`TextToMD5`) of `"{file-without-langcode}.{key-or-counter}"`. Because reindexing and checking (menu options 5–7) depend on the `Hash` being stable, do not hand-edit it — let the tool compute it.
+The `Hash` column is the **cross-language join key** that ties the same string together across all languages. It is computed as the **SHA256** (`TextToSHA256`) of `"{file-without-langcode}.{key-or-counter}"`. Because reindexing and checking (menu options 5–7) depend on the `Hash` being stable, do not hand-edit it — let the tool compute it.

 ---

&lt;/pre&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Bayram Emekli</dc:creator><pubDate>Sat, 04 Jul 2026 04:15:52 -0000</pubDate><guid>https://sourceforge.netd2c498e8f337338aa391805177dd3a9c01eee9fc</guid></item><item><title>Translating Localizer modified by Bayram Emekli</title><link>https://sourceforge.net/p/sucrose/wiki/Translating%2520Localizer/</link><description>&lt;div class="markdown_content"&gt;&lt;pre&gt;--- v1
+++ v2
@@ -111,11 +111,11 @@
 | Path | Contents |
 |------|----------|
 | `src/Library/Sucrose.Resources/Locales/Locale.&lt;code&gt;.xaml` | Runtime XAML resource per language. |
-| `src/Library/Sucrose.Resources/Locales/Locale.csv` | The locale registry (code → display name + version). |
+| `src/Library/Sucrose.Resources/Locales/Locale.xaml` | The runtime locale registry (code → display name + version), e.g. `Locale.EN = "English (v1.4)"`. |
 | `.localize/` (repo root) | Working/translation CSVs (`Portal.csv`, `Launcher.csv`, `Discord.csv`, and per-language `&lt;code&gt;.csv`). |
 | `.localize/POEditor/` | POEditor-format CSVs. |

-Localized XAML resources under `Sucrose.Resources/Locales/` are grouped by app area — e.g. `Locales/Portal/…` (`Portal.&lt;area/&gt;.&lt;code&gt;.xaml`, including `Portal.Enum.&lt;code&gt;.xaml`, which localizes enum display names such as `StoreServerType`, `ReportThemeType`, and `Category`), plus Launcher and Discord groups. The runtime looks strings up with segment keys via `Sucrose.Resources.Extension.Resources.GetValue("Portal","StoreCard","MenuInstall")`-style calls.
+Localized XAML resources under `Sucrose.Resources/Locales/` are grouped by app area — e.g. `Locales/Portal/…` (`Portal.&lt;area/&gt;.&lt;code&gt;.xaml`, including `Portal.Enum.&lt;code&gt;.xaml`, which localizes enum display names such as `StoreServerType` and `ReportThemeType` (the `Category` names live in a separate `Portal.Category.&lt;code&gt;.xaml` group)), plus Launcher and Discord groups. The runtime looks strings up with segment keys via `Sucrose.Resources.Extension.Resources.GetValue("Portal","StoreCard","MenuInstall")`-style calls.

 ---

&lt;/code&gt;&lt;/code&gt;&lt;/code&gt;&lt;/code&gt;&lt;/code&gt;&lt;/code&gt;&lt;/code&gt;&lt;/pre&gt;&lt;code&gt;&lt;code&gt;&lt;code&gt;
&lt;/code&gt;&lt;/code&gt;&lt;/code&gt;&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Bayram Emekli</dc:creator><pubDate>Sat, 04 Jul 2026 04:15:47 -0000</pubDate><guid>https://sourceforge.net007bd432a1648b94e4d27fbac48c9c7a10b52c01</guid></item><item><title>Translating Localizer modified by Bayram Emekli</title><link>https://sourceforge.net/p/sucrose/wiki/Translating%2520Localizer/</link><description>&lt;div class="markdown_content"&gt;&lt;h1 id="h-translating-with-the-localizer"&gt;Translating with the Localizer&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Audience: translators / contributors.&lt;/em&gt; &lt;code&gt;Sucrose.Localizer&lt;/code&gt; is a standalone console application that contributors use to translate the Sucrose app. It is &lt;strong&gt;not&lt;/strong&gt; part of the main application — it is a tooling project that converts translation data between three formats: the runtime &lt;strong&gt;XAML&lt;/strong&gt; resources, an intermediate &lt;strong&gt;CSV&lt;/strong&gt; working format, and &lt;strong&gt;POEditor CSV&lt;/strong&gt; (for the POEditor translation service). This page documents the tool's nine-option menu, the conversion pipeline, the file formats and their separator characters, and how to add a new language. For the current set of translated languages, see &lt;a href="./Localization-Coverage"&gt;Localization Coverage&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="h-contents"&gt;Contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#what-the-localizer-is"&gt;What the Localizer is&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#the-three-formats"&gt;The three formats&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#running-the-tool"&gt;Running the tool&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#the-nine-option-menu"&gt;The nine-option menu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#conversion-mechanics"&gt;Conversion mechanics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#the-hash-key"&gt;The Hash key&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#working-copies--file-locations"&gt;Working copies &amp;amp; file locations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#adding-a-new-language"&gt;Adding a new language&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#gotchas"&gt;Gotchas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#see-also"&gt;See also&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr/&gt;
&lt;h2 id="h-what-the-localizer-is"&gt;What the Localizer is&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Sucrose.Localizer&lt;/code&gt; lives in &lt;code&gt;src/Localizer/Sucrose.Localizer/&lt;/code&gt; and has its &lt;strong&gt;own solution&lt;/strong&gt;, &lt;code&gt;src/Sucrose.Localizer.slnx&lt;/code&gt; (one of the project's three solutions — see &lt;a href="./Repository-Layout"&gt;Repository Layout&lt;/a&gt;). Project facts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Targets &lt;code&gt;net10.0-windows&lt;/code&gt; but with &lt;code&gt;UseWPF=false&lt;/code&gt;; &lt;code&gt;OutputType=Exe&lt;/code&gt;; defines the &lt;code&gt;LOCALIZER&lt;/code&gt; preprocessor symbol.&lt;/li&gt;
&lt;li&gt;Package references: &lt;code&gt;Skylark&lt;/code&gt;, &lt;code&gt;Skylark.Standard&lt;/code&gt;, &lt;code&gt;CsvHelper&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Output goes to &lt;code&gt;…/Localizer/{x86|x64|ARM64}&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is purely a contributor tool: it reads and writes files on disk and is driven by an interactive numbered menu.&lt;/p&gt;
&lt;hr/&gt;
&lt;h2 id="h-the-three-formats"&gt;The three formats&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;th&gt;Where it lives&lt;/th&gt;
&lt;th&gt;Shape&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;XAML&lt;/strong&gt; (runtime)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;src/Library/Sucrose.Resources/Locales/Locale.&amp;lt;CODE&amp;gt;.xaml&lt;/code&gt; and grouped files like &lt;code&gt;Portal.&amp;lt;area&amp;gt;.&amp;lt;CODE&amp;gt;.xaml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ResourceDictionary&lt;/code&gt; of &lt;code&gt;&amp;lt;system:String x:Key="…"&amp;gt;value&amp;lt;/system:String&amp;gt;&lt;/code&gt; entries; the app loads one per language at runtime.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CSV&lt;/strong&gt; (working)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.localize/&lt;/code&gt; (repo root)&lt;/td&gt;
&lt;td&gt;Columns &lt;strong&gt;&lt;code&gt;Hash,File,Key,Value&lt;/code&gt;&lt;/strong&gt; — used for diffing/checking and as the working format.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;POEditor CSV&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.localize/POEditor/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Columns &lt;strong&gt;&lt;code&gt;Term,Translate,Context,Reference,Comment&lt;/code&gt;&lt;/strong&gt; — the import/export format for the POEditor service.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;Do not conflate the two CSV schemas: the working CSV is &lt;code&gt;Hash,File,Key,Value&lt;/code&gt;; the POEditor CSV is &lt;code&gt;Term,Translate,Context,Reference,Comment&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr/&gt;
&lt;h2 id="h-running-the-tool"&gt;Running the tool&lt;/h2&gt;
&lt;p&gt;The entry point is &lt;code&gt;App.cs&lt;/code&gt; → &lt;code&gt;Main&lt;/code&gt;, which sets the console encoding to &lt;strong&gt;UTF-8&lt;/strong&gt;, sets the culture, and calls &lt;code&gt;Helper.Program.Start()&lt;/code&gt;. &lt;code&gt;Helper/Program.cs&lt;/code&gt; presents the interactive menu. Each menu option prompts for directory paths on stdin via &lt;code&gt;Console.ReadLine&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Because the tool is &lt;strong&gt;interactive-only&lt;/strong&gt; (there are no command-line flags), running it means launching the built &lt;code&gt;Sucrose.Localizer.exe&lt;/code&gt; and answering its prompts. Build it from its own solution:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Sucrose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Localizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slnx&lt;/span&gt; &lt;span class="n"&gt;-c&lt;/span&gt; &lt;span class="n"&gt;Release&lt;/span&gt; &lt;span class="n"&gt;-p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;PlatformTarget&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="n"&gt;x64&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;hr/&gt;
&lt;h2 id="h-the-nine-option-menu"&gt;The nine-option menu&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Helper/Program.cs&lt;/code&gt; exposes nine operations:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Helper call&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Convert &lt;strong&gt;XAML → CSV&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;XamlToCsv.Convert(xamlDir, csvDir)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Extracts &lt;code&gt;system:String&lt;/code&gt; entries plus merged-dictionary blocks.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Convert &lt;strong&gt;CSV → XAML&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CsvToXaml.Convert(csvDir, xamlDir)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rebuilds the &lt;code&gt;ResourceDictionary&lt;/code&gt; XAML files.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Convert &lt;strong&gt;CSV → POEditor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CsvToPoe.Convert(csvDir, poeDir)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Convert &lt;strong&gt;POEditor → CSV&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PoeToCsv.Convert(poeDir, csvDir)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Check CSV&lt;/strong&gt; files against each other&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Against.CheckCsv(csvDir)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Row-by-row consistency across all two-letter CSVs.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Check POEditor&lt;/strong&gt; files against each other&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Against.CheckPoe(poeDir)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;CSV reindexer&lt;/strong&gt; from a reference CSV&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Against.ReindexCsv(csvDir, lang)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Re-orders all CSVs to match a reference language's line order by &lt;code&gt;Hash&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Alphabetic key indexer&lt;/strong&gt; for a CSV&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Against.AlphabeticIndexer(csvDir, lang)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sorts keys (shortest-first, then natural alpha-numeric) per file group; excludes &lt;code&gt;Base64&lt;/code&gt;/empty keys.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Create a new language&lt;/strong&gt; file from CSVs&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Creating.Create(csvDir, srcLang, outLang, outLangName)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clones a source CSV to a new language and registers it in &lt;code&gt;Locale.csv&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The typical contributor loop is: &lt;strong&gt;export&lt;/strong&gt; the current strings to POEditor (1 → 3), translate in POEditor, &lt;strong&gt;import&lt;/strong&gt; back (4 → 2), then &lt;strong&gt;check&lt;/strong&gt; consistency (5, 6) and optionally &lt;strong&gt;reindex&lt;/strong&gt; (7) before committing.&lt;/p&gt;
&lt;hr/&gt;
&lt;h2 id="h-conversion-mechanics"&gt;Conversion mechanics&lt;/h2&gt;
&lt;h3 id="h-xaml-csv-xamltocsvcs"&gt;XAML → CSV (&lt;code&gt;XamlToCsv.cs&lt;/code&gt;)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Recurses &lt;code&gt;*.xaml&lt;/code&gt;; the language code is the last dot-segment of the filename (e.g. &lt;code&gt;Portal.Enum.TR.xaml&lt;/code&gt; → &lt;code&gt;TR&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Merged-dictionary blocks (&lt;code&gt;&amp;lt;ResourceDictionary.MergedDictionaries&amp;gt;…&amp;lt;/…&amp;gt;&lt;/code&gt;) are captured whole, &lt;strong&gt;Base64-encoded&lt;/strong&gt; (&lt;code&gt;CryptologyExtension.TextToBase&lt;/code&gt;), and stored under the key &lt;code&gt;Base64&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Each &lt;code&gt;system:String&lt;/code&gt; becomes a CSV row &lt;code&gt;Hash,File,Key,Value&lt;/code&gt;; &lt;code&gt;&amp;amp;&lt;/code&gt; is escaped to &lt;code&gt;&amp;amp;amp;&lt;/code&gt;; blank separator rows preserve the XAML spacing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="h-csv-xaml-csvtoxamlcs"&gt;CSV → XAML (&lt;code&gt;CsvToXaml.cs&lt;/code&gt;)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Re-emits a &lt;code&gt;ResourceDictionary&lt;/code&gt; with &lt;code&gt;xmlns:system="clr-namespace:System;assembly=mscorlib"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Base64&lt;/code&gt; keys are decoded back to raw XAML (&lt;code&gt;BaseToText&lt;/code&gt;); empty key+value rows become blank lines.&lt;/li&gt;
&lt;li&gt;If a file has no &lt;code&gt;system:String&lt;/code&gt; entries, the header is simplified (drops the &lt;code&gt;system&lt;/code&gt; namespace, prepends a BOM).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="h-csv-poeditor-csvtopoecs"&gt;CSV → POEditor (&lt;code&gt;CsvToPoe.cs&lt;/code&gt;)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Emits &lt;code&gt;Term,Translate,Context,Reference,Comment&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Empty keys become &lt;code&gt;PASS⦙n&lt;/code&gt;; &lt;code&gt;Base64&lt;/code&gt; keys become &lt;code&gt;Base64⦙n&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Such rows get Context &lt;code&gt;Don't Touch&lt;/code&gt; and the comment "Please don't touch the translation in this line." The &lt;code&gt;Reference&lt;/code&gt; column carries the &lt;code&gt;File&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="h-poeditor-csv-poetocsvcs"&gt;POEditor → CSV (&lt;code&gt;PoeToCsv.cs&lt;/code&gt;)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Reverses the above: &lt;code&gt;PASS⦙&lt;/code&gt; terms become empty, &lt;code&gt;⦙&lt;/code&gt;-marked translations are cleared, and the &lt;code&gt;Hash&lt;/code&gt; is recomputed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Internal separator characters&lt;/strong&gt; used by the helpers: &lt;code&gt;⁞&lt;/code&gt; (entry split) and &lt;code&gt;⦙&lt;/code&gt; (special-marker split). These are literal Unicode characters baked into the file format — preserve them exactly.&lt;/p&gt;
&lt;hr/&gt;
&lt;h2 id="h-the-hash-key"&gt;The Hash key&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;Hash&lt;/code&gt; column is the &lt;strong&gt;cross-language join key&lt;/strong&gt; that ties the same string together across all languages. It is computed as the &lt;strong&gt;MD5&lt;/strong&gt; (&lt;code&gt;TextToMD5&lt;/code&gt;) of &lt;code&gt;"{file-without-langcode}.{key-or-counter}"&lt;/code&gt;. Because reindexing and checking (menu options 5–7) depend on the &lt;code&gt;Hash&lt;/code&gt; being stable, do not hand-edit it — let the tool compute it.&lt;/p&gt;
&lt;hr/&gt;
&lt;h2 id="h-working-copies-file-locations"&gt;Working copies &amp;amp; file locations&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Contents&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;src/Library/Sucrose.Resources/Locales/Locale.&amp;lt;CODE&amp;gt;.xaml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Runtime XAML resource per language.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;src/Library/Sucrose.Resources/Locales/Locale.csv&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The locale registry (code → display name + version).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.localize/&lt;/code&gt; (repo root)&lt;/td&gt;
&lt;td&gt;Working/translation CSVs (&lt;code&gt;Portal.csv&lt;/code&gt;, &lt;code&gt;Launcher.csv&lt;/code&gt;, &lt;code&gt;Discord.csv&lt;/code&gt;, and per-language &lt;code&gt;&amp;lt;CODE&amp;gt;.csv&lt;/code&gt;).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.localize/POEditor/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;POEditor-format CSVs.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Localized XAML resources under &lt;code&gt;Sucrose.Resources/Locales/&lt;/code&gt; are grouped by app area — e.g. &lt;code&gt;Locales/Portal/…&lt;/code&gt; (&lt;code&gt;Portal.&amp;lt;area&amp;gt;.&amp;lt;CODE&amp;gt;.xaml&lt;/code&gt;, including &lt;code&gt;Portal.Enum.&amp;lt;CODE&amp;gt;.xaml&lt;/code&gt;, which localizes enum display names such as &lt;code&gt;StoreServerType&lt;/code&gt;, &lt;code&gt;ReportThemeType&lt;/code&gt;, and &lt;code&gt;Category&lt;/code&gt;), plus Launcher and Discord groups. The runtime looks strings up with segment keys via &lt;code&gt;Sucrose.Resources.Extension.Resources.GetValue("Portal","StoreCard","MenuInstall")&lt;/code&gt;-style calls.&lt;/p&gt;
&lt;hr/&gt;
&lt;h2 id="h-adding-a-new-language"&gt;Adding a new language&lt;/h2&gt;
&lt;p&gt;Use &lt;strong&gt;menu option 9&lt;/strong&gt; (&lt;code&gt;Creating.Create(csvDir, srcLang, outLang, outLangName)&lt;/code&gt;):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It copies &lt;code&gt;&amp;lt;src&amp;gt;.csv&lt;/code&gt; → &lt;code&gt;&amp;lt;out&amp;gt;.csv&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It rewrites the &lt;code&gt;File&lt;/code&gt; column's language tokens (&lt;code&gt;.SRC.&lt;/code&gt; → &lt;code&gt;.OUT.&lt;/code&gt;) — including inside the Base64-encoded merged-dictionary blocks.&lt;/li&gt;
&lt;li&gt;It appends a row to &lt;code&gt;Locale.csv&lt;/code&gt; of the form:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;Locale.xaml, Locale.&amp;lt;OUT&amp;gt;, &amp;lt;Language Name&amp;gt; (v0.1)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;and re-sorts the registry by &lt;code&gt;Key&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After creating the language CSV, translate it (export to POEditor with option 3, translate, import back with option 4), then convert CSV → XAML (option 2) to produce the runtime &lt;code&gt;Locale.&amp;lt;CODE&amp;gt;.xaml&lt;/code&gt; that the app loads.&lt;/p&gt;
&lt;p&gt;The locale registry maps each code to a human display name and version, e.g. &lt;code&gt;Locale.EN = "English (v1.4)"&lt;/code&gt;. The version is a maturity indicator for the translation.&lt;/p&gt;
&lt;hr/&gt;
&lt;h2 id="h-gotchas"&gt;Gotchas&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The Localizer is &lt;strong&gt;interactive-only&lt;/strong&gt; (stdin prompts, no CLI flags). Automating it would require piping the answers.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Hash&lt;/code&gt; column must stay stable — it is the cross-language join key; reindexing/checking depends on it.&lt;/li&gt;
&lt;li&gt;There are &lt;strong&gt;two distinct CSV schemas&lt;/strong&gt; (working vs POEditor); do not mix them.&lt;/li&gt;
&lt;li&gt;The website's translations are a &lt;strong&gt;separate surface&lt;/strong&gt;: the &lt;code&gt;.pages/&lt;/code&gt; site uses its own i18n JSON files and is &lt;strong&gt;not&lt;/strong&gt; produced by the Localizer. See &lt;a href="./Localization-Coverage"&gt;Localization Coverage&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr/&gt;
&lt;h2 id="h-see-also"&gt;See also&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="./Localization-Coverage"&gt;Localization Coverage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="./Repository-Layout"&gt;Repository Layout&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/p/sucrose/wiki/Contributing/"&gt;Contributing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="./Building-From-Source"&gt;Building From Source&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="./Code-Conventions"&gt;Code Conventions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="./Create-Customization-Controls"&gt;Create — Customization Controls&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Bayram Emekli</dc:creator><pubDate>Sat, 04 Jul 2026 04:15:38 -0000</pubDate><guid>https://sourceforge.net54383a1dacd50449d96d1f6ce9ea2ecd4111d970</guid></item></channel></rss>