Repository navigation
feat(l10n): localize grid-style editor errors by type - #173
Merged
Merged
Conversation
The in-app grid-style editor was the last unlocalized operator surface.
Its ErrorMessage was built by joining raw .Message strings, bypassing
ReasonLocalizer entirely, so a load/validate/save failure rendered
English regardless of UI culture. The editor opens after startup, when
the culture is established, so there is no reason to leave any of it
English.
Type all eight grid-style error producers and route the three ErrorMessage
join sites through ReasonLocalizer.Localize:
- GridStyleValidator: config-missing, section-missing (unifying the
'colors' and generic cases), orientation-invalid, key-missing,
invalid-hex-color.
- GridStyleLoader: config-not-found, and load-failed as a Rule-B envelope.
- GridStyleWriter: save-failed as a Rule-B envelope.
Each gets a ReasonLocalizer arm, en/ru resx, and a coverage sample; the
join sites localize by type and fall through to .Message for anything not
yet typed. English base messages stay byte-identical except the two Rule-B
headlines, which drop the ": {ex.Message}" tail.
The orientation error carries its two expected values as properties because
GridOrientationValues is internal to Core and invisible to the UI localizer.
The dropped exception detail is preserved on CausedBy and logged at both
consumers of the shared loader: the editor view model (LogWarning) and the
startup path in Program.cs (Log.Error) -- without the startup sink a
malformed grid_style.yaml at launch would lose its parse detail entirely.
ReportSaveException drops its raw tail to the already-localized
Resources.SaveFailed; the exceptions reaching it are pre-write pipeline
throws, not file-write failures, so naming a file would mislead.
After this the operator-facing error surfaces are fully typed. The startup
config load (before the culture exists) and the two PLC malformed-wire
diagnostic edges remain English by design. Issue #118 (the editor's
structural refactor) is independent and unaffected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The in-app grid-style editor (
GridStyleEditorViewModel) was the last unlocalized operator surface in the error-localization roadmap. ItsErrorMessagewas built by joining raw.Messagestrings, bypassingReasonLocalizerentirely —ReasonLocalizerwasn't referenced inStyleEditor/at all. So a load / validate / save failure rendered English regardless of UI culture. The editor opens after startup (culture established), so there's no reason to leave any of it English — leaving loader errors English while validator errors were Russian would show one panel in mixed languages depending on whether the file was missing or a color was malformed.What changed
Type all 8 grid-style error producers and route the three
ErrorMessagejoin sites throughReasonLocalizer.Localize:GridStyleValidatorcolors+ generic), orientation-invalid, key-missing, invalid-hex-colorGridStyleLoaderGridStyleWriterEach gets a
ReasonLocalizerarm, en/ru resx + Designer, and a coverage sample. The join sites localize by type and fall through to.Messagefor anything not yet typed. English base messages stay byte-identical except the two Rule-B headlines, which drop the: {ex.Message}tail.Two design points worth calling out:
GridOrientationValuesisinternalto Core and invisible to the UI localizer, so the arm can't reference it.CausedBy(ex)and is logged at both consumers of the shared loader: the editor view model (LogWarning) and the startup path inProgram.cs(Log.Error). Without the startup sink, a malformedgrid_style.yamlat launch would lose its parse detail entirely.ReportSaveExceptiondrops its raw tail to the already-localizedResources.SaveFailed— the exceptions reaching it are pre-write pipeline throws, not file-write failures, so naming a file would mislead.Scope: pure localization. Issue #118 (the editor's structural refactor — declarative 60-field map, async
Save,HexColor.Parseremoval) is independent and untouched; only the three join sites move. After this, the operator-facing error surfaces are fully typed — the startup config load (before culture exists) and the two PLC malformed-wire diagnostic edges remain English by design.Verification
dotnet build SemiStep.slnx— 0 warnings;dotnet test— 1685 passed, 0 failed;dotnet formatclean.ReasonLocalizerTestspins each of the 8 types' ru render + the enLocalize == .Messagepins;CoreErrorLocalizationCoverageTestsauto-enrolls the 8 public errors;ResourceSyncTestsenforces en/ru/Designer key + placeholder parity.GridStyleEditorViewModelTests.LoadAsync_MalformedHexColoroverlays a corrupted color on the shipped config and assertsErrorMessageis the exact Russian hex sentence (a regression to raw.Messagefails it). Two log-sink tests assert theCausedByexception reaches the log — removing the sink call fails them.GridStyleEditorFacadeTestsassertGridStyleLoadFailedError/GridStyleSaveFailedErrorretain their exception on the nested.Reasons.Path→FilePathrename.Per-task commits before collapse
🤖 Generated with Claude Code