Skip to content

Release v2.0.0 - #52

Merged
rent-a-developer merged 13 commits into
mainfrom
release/issue-29-v2.0.0
Oct 20, 2026
Merged

rent-a-developer merged 13 commits into
mainfrom
release/issue-29-v2.0.0

Conversation

@rent-a-developer

Copy link
Copy Markdown
Owner

Part of #29

What does this change?

ResXLocalization 2.0.0: format arguments on the binding for {l:Localize} and {l:LocalizeEnum}
(issue 11), the opt-in ICU MessageFormat package ResXLocalization.MessageFormat, typed keys for every
neutral .resx with or without a designer, and the release commit (version 2.0.0, dated changelog,
public API marked as shipped).

Issue Pull request Change
#30 #31 Every lookup goes through one replaceable message formatter; LookupFailed
#32 #33 One Get per key kind, MessageArguments, a replaceable enum key convention
#34 #43 Typed keys for every neutral .resx, with or without a designer
#35 #44 Registration of the generated resource managers
#36 #45 Format arguments on the binding: <l:Argument>
#37 #46 Format arguments for enum labels
#38 #47 A bound key for {l:Localize}
#39 #48 The opt-in package ResXLocalization.MessageFormat
#40 #49 The MessageFormat package in the consumers, the Native AOT gate and CI
#41 #50 DesignTime.Culture and a fallback for Rider's WPF previewer
#42 #51 The top-level documents and the release gates

This is a major version with breaking changes. Each one, with a before/after example, is in
Migrating to 2.0; the full list is in CHANGELOG.md under 2.0.0.

Merge with a merge commit, not a squash, so every change keeps its own commit on main.

Checklist

Always

  • pwsh -File scripts/pre-commit-gate.ps1 passes.
  • The Release build produces zero warnings.
  • pwsh -File scripts/pre-release-gate.ps1 -Version 2.0.0 passes.

Behaviour, UI packages, packaging, public API

  • New behaviour is covered by tests, in both UI test suites where it applies.
  • UI package changes are mirrored into the other package.
  • pwsh -File scripts/verify-package-aot.ps1 -Pack passes for net8.0 and net10.0, with no IL
    diagnostics and none suppressed.
  • The public API was reviewed in each feature and is marked as shipped in the release commit.
  • The XML documentation, the pages under docs/ and CHANGELOG.md are updated.

rent-a-developer and others added 12 commits October 13, 2026 03:17
Every lookup, with or without arguments, now passes its resolved value
through ILocalizer.MessageFormatter (default: StringFormatMessageFormatter).
A failed lookup raises ILocalizer.LookupFailed and returns the failure text
from ILocalizer.LookupFailureTextBuilder. RefreshTriggeringRevision changes
on every change that can change a lookup's result.

Refs #30

BREAKING CHANGE: a formatting failure no longer throws FormatException. Get
returns the failure text (by default !key!) and raises ILocalizer.LookupFailed,
and XAML renders the failure text. Get(key, args) with an empty array returns
the resource value unformatted. ILocalizer has new members (MessageFormatter,
LookupFailed, RefreshTriggeringRevision, a hidden Get overload) that custom
implementations must add. TranslationNotFound and TranslationNotFoundEventArgs
are replaced by LookupFailed and LookupFailedEventArgs, which also report
formatting failures. MissingTranslationFormat is replaced by
LookupFailureTextBuilder, a Func<LookupFailure, string> that also serves
formatting failures. See docs/guides/migration-2.0.md.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ble enum key convention (#33)

ILocalizer has three Get overloads - string, ResourceKey and Enum keys -
each with an optional MessageArguments, built with FromValues, FromTuples,
FromDictionary or FromObject. A MessageArguments is immutable and always
valid: its argument positions are 0 to Count - 1 and MessageArgument.Position
is their only source. IMessageFormatter.Format and LookupFailure.Arguments
take MessageArguments too. ILocalizer.EnumKeyBuilder replaces the fixed
enum key convention for code and XAML.

Refs #32

BREAKING CHANGE: Write Get("Key", MessageArguments.FromValues(a, b))
instead of Get("Key", a, b), Get("Key", resourceManager: rm) for a scoped
lookup and keyPrefix: for an enum prefix. A null manager means search-all
and a null key prefix the EnumKeyBuilder's default. KeyPrefix on
LocalizeEnumExtension and LocalizeEnumConverter is string? and defaults to
null. Every 1.1.0 Get signature is removed; recompile dependent assemblies.
See docs/guides/migration-2.0.md.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…designer (#43)

* feat!: generate typed keys for every neutral resx, with or without a designer

The build wiring passes MSBuild's resource name (ManifestResourceName, LogicalName,
WithCulture) to the generator through the analyzer config file, and each generated
<Name>Keys class creates its own ResourceManager from it. Also: the pre-release gate
removes cached ResXLocalization packages before the package consumers run, and the
generator project no longer lists AnalyzerReleases.*.md twice.

Refs #34

BREAKING CHANGE: generated <Name>Keys classes carry their own ResourceManager, created from the
resource name MSBuild computes, and their keys no longer use the designer's ResourceManager.
Files without a designer and dotted neutral files now produce keys classes; RXLGEN002 is
removed. Two files that produce the same keys class report RXLGEN004 instead of merging. See
docs/guides/migration-2.0.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat: name designer-less keys by CustomToolNamespace and fix WPF's temporary markup-compile pass

A .resx without a designer takes its keys-class namespace from CustomToolNamespace when it is
set. In WPF's temporary markup-compile pass the "_<random>_wpftmp" suffix is removed from our
own copies of the resource names and of CustomToolNamespace (see
build/ResXLocalization.Resx.targets). The pre-release gate also runs every package consumer on
the .NET 8 SDK, and a new consumer covers a RootNamespace derived from the project name.

Refs #34

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…sources (#44)

* feat!: register the generated resource managers and reject missing resources

BREAKING CHANGE: Localizer.RegisterResourceManager now throws ArgumentException for a plain
ResourceManager whose base name has no resources, instead of registering it and letting every
search-all lookup throw MissingManifestResourceException. Register <Name>Keys.ResourceManager.
See docs/guides/migration-2.0.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build: build the source generator in the configuration dotnet format loads

tidy-code built the generator with -c Debug, but CI sets CONFIGURATION: Release, which MSBuild reads
as the Configuration property, so dotnet format looked for the generator in bin/Release, found
nothing, and IDE0005 flagged the usings only the generated <Name>Keys classes need. Build without -c,
so the build and dotnet format resolve the same configuration.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
)

BREAKING CHANGE: the LocalizeArgs attached properties are removed from both UI packages; add
<l:Argument Value="..."/> children instead, with a constant or bound value, optionally named.
LocalizeExtension.ResourceKey is removed; Key takes a string or a ResourceKey. Arguments now
work per binding, without a target element, and without an upper limit. See
docs/guides/migration-2.0.md.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Implements the request of #11 as feature 06 of 2.0.0 (#37).

BREAKING CHANGE: {l:LocalizeEnum} takes its enum value from Value - a binding such as
Value={Binding} in item templates, or a fixed member via {x:Static} - and no longer reads the
DataContext implicitly. LocalizeEnumConverter expects RefreshTriggeringRevision as child 0 and
the enum as child 1, and forwards children from index 2 on as format arguments. See
docs/guides/migration-2.0.md.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Implements feature 07 of 2.0.0 (#38): {l:Localize {Binding Key}} and Key="{Binding Key}" take
the key from the view model, as a ResourceKey or a string. A bound value that gives no key
renders an empty string instead of throwing. Both samples show it in a new card 7.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…lural and select (#48)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…te and CI (#49)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…#50)

Implements feature 10 of 2.0.0 (#41): the attached property DesignTime.Culture, in both UI packages,
selects the language of XAML previewers and has no effect at run time. In WPF, inside a designer
that supplies the target property as a CLR property instead of a dependency property (Rider's WPF
previewer, RIDER-143207), {l:Localize} and {l:LocalizeEnum} return the lookup without arguments
instead of a binding, so localized strings render there instead of nothing. The WPF sample's view
model can be created by the designers. New guide: docs/guides/design-time.md.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…gates (#51)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- Date the changelog section 2.0.0 and add its link reference; keep an empty Unreleased section.
- Set <Version> to 2.0.0.
- Mark the public API as shipped: fold PublicAPI.Unshipped.txt into PublicAPI.Shipped.txt for Core,
  Avalonia, WPF and MessageFormat.
- Set the version placeholder of the bug report form to 2.0.0.

Part of #29
@rent-a-developer rent-a-developer added this to the v2.0.0 milestone Oct 20, 2026
@rent-a-developer rent-a-developer self-assigned this Oct 20, 2026
@rent-a-developer rent-a-developer added documentation Improvements or additions to documentation enhancement New feature or request breaking change build labels Oct 20, 2026
@rent-a-developer
rent-a-developer merged commit 80cc9a5 into main Oct 20, 2026
31 checks passed
@rent-a-developer
rent-a-developer deleted the release/issue-29-v2.0.0 branch October 20, 2026 15:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking change build documentation Improvements or additions to documentation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ResXLocalization 2.0.0: arguments on the binding, enum arguments, ICU MessageFormat and typed keys without designers

1 participant