| title | Translation and Localization |
|---|---|
| layout | default |
Grex uses Windows .resw resource catalogs under Strings/<culture>/Resources.resw.
The repository currently contains:
- one source catalog:
Strings/en-US/Resources.resw; - 107 non-English catalogs;
- 476 English resource entries at the time of this documentation audit.
Non-English catalogs are not complete. Do not describe every listed locale as fully translated. Run the status script for current counts.
LocalizationService:
- loads strings for the selected culture;
- falls back to
en-USwhen possible; - returns the resource key when lookup fails;
- formats parameterized strings;
- updates thread culture;
- raises
PropertyChangedwhen culture changes; - caps cached resource contexts at 20.
The Settings language list is built from culture directories that contain Resources.resw. If packaged resource files cannot be enumerated, the UI uses a fallback culture list.
Views refresh dynamic text after a culture change. LocalizedToolTipRegistry refreshes registered tooltips. Some WinUI resource behavior may still require an application restart.
Use x:Uid when WinUI can populate a static property:
<Button x:Name="SearchButton"
x:Uid="SearchButton" />The resource key includes the property:
<data name="SearchButton.Content" xml:space="preserve">
<value>Search</value>
<comment>status:complete</comment>
</data>Use the localization service for runtime strings:
var text = LocalizationService.Instance.GetLocalizedString("SearchErrorTitle");
var formatted = LocalizationService.Instance.GetLocalizedString(
"FoundMatchesStatus",
matchCount,
fileCount,
elapsed);Do not hard-code user-facing English in C# or XAML fallback paths unless an existing compatibility pattern requires it.
Regex Builder strings follow this same system. See Regex Builder Localization for its resource families and focused validation steps.
Every <data> entry should have one status comment.
| Comment | Meaning |
|---|---|
status:complete |
Reviewed translation |
status:incomplete |
English placeholder or unreviewed translation |
status:error:<details> |
Automatic translation failed |
status:error:permanent |
Do not retry automatically |
English entries use status:complete.
Example:
<data name="NewFeatureButton.Content" xml:space="preserve">
<value>New feature</value>
<comment>status:incomplete</comment>
</data>English is the source of truth.
-
Add the key and English text to
Strings/en-US/Resources.reswwithstatus:complete. -
From the repository root, propagate the same key:
python Scripts/add_localization_entry.py "NewFeatureButton.Content" "New feature"
-
The script skips the existing English key and adds an English placeholder with
status:incompleteto other catalogs. -
Translate and review the affected non-English entries.
-
Run script tests and the Windows .NET tests.
The add script:
- discovers
Strings/*/Resources.resw; - does not overwrite an existing key;
- escapes XML through
xml.etree.ElementTree; - reports added and skipped catalogs.
Use the removal script rather than hand-editing 108 files:
python Scripts/remove_localization_entry.py "OldFeatureButton.Content"Then search for remaining code/XAML references:
rg -n "OldFeatureButton" Controls ViewModels Services MainWindow.xaml MainWindow.xaml.csReview the diff before committing.
When changing an English message:
- update
en-US; - identify every catalog containing the key;
- preserve placeholders and XML whitespace;
- mark stale non-English values
status:incomplete; - translate and review;
- run the status report.
Do not silently leave a previously translated value attached to changed English semantics.
Preserve:
- format placeholders such as
{0},{1}, and{2}; - literal command names, flags, paths, and file extensions;
- keyboard names;
- XML escaping;
- leading/trailing whitespace when meaningful;
- punctuation required by the UI;
- accelerator or glyph text used by controls.
Do not translate:
Grex;- API model ids;
- command names such as
grep,docker,wsl, andgrex-cli; - CLI options such as
--gitignore; - technical units such as KB, MB, and GB;
- file or resource keys.
Keep translations concise enough for the existing control. Test long strings and right-to-left scripts in the running app.
Scripts/translate_remaining_entries.py can process incomplete entries with the optional googletrans package:
python -m pip install googletrans==4.0.0rc1
python Scripts/translate_remaining_entries.pyWithout googletrans, the script identifies work but cannot translate it.
The script:
- compares non-English values with English;
- skips complete and permanent-error entries;
- maps Windows culture codes to provider language codes;
- marks successful values complete;
- records transient or permanent errors;
- avoids overwriting values already different from English.
Machine translation is a draft, not approval. Review terminology, placeholders, directionality, truncation, and feature context before changing a status to complete.
The translation provider is external. Do not place secrets or private product text in resource values submitted to it.
Run:
python Scripts/generate_translation_status.pyThe report:
- parses the English key set;
- counts complete, incomplete, and error entries per locale;
- summarizes locale status;
- lists locales nearest completion;
- lists translation errors.
This output is authoritative. Counts in prose can become stale.
Standard library:
python Scripts/test_add_localization_entry.py
python Scripts/test_remove_localization_entry.pyWith pytest:
python -m pytest Scripts/test_add_localization_entry.py Scripts/test_remove_localization_entry.pyOn Windows, run localization-focused .NET tests:
dotnet test Tests/Grex.Tests.csproj -p:Platform=x64 -p:WindowsAppSdkBootstrapInitialize=false --filter "FullyQualifiedName~Localization"
dotnet test Tests/Grex.Tests.csproj -p:Platform=x64 -p:WindowsAppSdkBootstrapInitialize=false --filter "FullyQualifiedName~RegexBuilderLanguage"
dotnet test IntegrationTests/Grex.IntegrationTests.csproj -p:Platform=x64 -p:WindowsAppSdkBootstrapInitialize=false --filter "FullyQualifiedName~AiSearchLocalization"Then manually verify:
- Settings language list;
- Search, Regex Builder, Settings, About, and Credits;
- tooltips;
- dialogs and notifications;
- result/status pluralization;
- restart persistence;
- fallback for an intentionally missing key.
All .resw files are CRLF. Python's XML writer emits platform-native newlines, so running mutation scripts on Linux or macOS can turn every line into LF.
Before editing on any platform:
git config core.autocrlf false
git ls-files --eol Strings/en-US/Resources.reswExpected index form:
i/crlf
After running a script:
git diff --stat -- Strings
git ls-files --eol Strings/en-US/Resources.reswOn Linux or macOS, convert changed .resw files back to CRLF before committing. Avoid a repository-wide line-ending diff.
- Choose a valid Windows culture code, such as
xx-YY. - Copy the English catalog to
Strings/xx-YY/Resources.resw. - Keep the same key set and XML structure.
- Set non-English entries to
status:incomplete. - Translate and review.
- Run the status report.
- Build on Windows so PRI resource generation validates the culture.
- Verify the language appears in Settings and survives restart.
Grex.csproj includes Strings\**\Resources.resw as PRI resources, so no per-language project entry is normally needed.
- Every English key exists once.
- Every changed key exists in every catalog.
- Format placeholders match English.
- No user-facing text was added outside localization.
- Status comments match review state.
.reswfiles remain CRLF.- Script and .NET localization tests pass.
- Dynamic language switching was checked.
- Machine-translated text received human review.