Repository navigation
Add LocalizedString.Create and LocalizedHtmlString.Create - #19933
MikeAlhayek wants to merge 3 commits into
Conversation
|
Please hold on .. we might need to discuss this with @sebastienros. If there's an option within the UI to change this, then |
a02f73d to
d8eb2e2
Compare
| { | ||
| ArgumentNullException.ThrowIfNull(value); | ||
|
|
||
| return new(value, value, isResourceNotFound: false, arguments ?? []); |
There was a problem hiding this comment.
This is weird, because the resource is not found, so the question is where the localization string should come from?
@sebastienros, how does this align with localization strings that come from PO files?!!
There was a problem hiding this comment.
If it is not found it will probably take the T["english string"] directly.
Add C# 14 static extension members that create a LocalizedString or a LocalizedHtmlString where the name is also the value. The extensions live in the same namespaces as the types so they are discoverable without an extra using directive. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
OrchardCore.Abstractions is referenced by every Orchard Core project, so the extensions can be used everywhere, including in OrchardCore.Infrastructure.Abstractions where Permission is declared. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Rename the parameter of LocalizedString.Create and LocalizedHtmlString.Create from name to value: the text is the value, and it is also used as the name. - Accept optional format arguments, like S["...", a, b] and H["...", a, b]. The name stays the unformatted text. - Explain in the docs why the value can be used as the name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
d8eb2e2 to
9e686dd
Compare
| /// <remarks> | ||
| /// The returned string is not translated. The name can be used as the key to localize the string later. | ||
| /// </remarks> | ||
| public static LocalizedString Create(string value, params object[] arguments) |
There was a problem hiding this comment.
This can't be right, the values of the arguments can only be provided on render, and the same localization string can be rendered many times with different values.
* Use immutable sources for deferred localization Supersedes #19933, #19934, #19936. Introduce OrchardCore.Localization.LocalizationSource, a sealed record pairing an untranslated value with the Type that supplies its PO context. Add IStringLocalizerFactory.Localize and IHtmlLocalizerFactory.Localize extensions that call Create(source.Type) and defer text/HTML encoding and formatting to render time. Permission.Description and DeploymentStep.Category/Title now use LocalizationSource. All 53 built-in deployment steps cache their 85 category/title sources in private static readonly fields assigned in parameterless constructors, avoiding localizer injection purely for labels. The default empty deployment category is shared as well. Context-free sources preserve legacy plain-string Permission constructors and Data Localization of dynamically generated permissions. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Add factory-based plural support for LocalizationSource Add IStringLocalizerFactory.Plural and IHtmlLocalizerFactory.Plural extensions in OrchardCore.Localization.Abstractions, taking a count, a singular LocalizationSource, the plural text, and optional format arguments. For context-bearing sources they resolve factory.Create(source.Type) and delegate to the existing IStringLocalizer.Plural/IHtmlLocalizer.Plural extensions, so culture-specific PO plural rules (including zero forms and more than two forms) select the translated form. For context-free sources they fall back to the English singular/plural rule, matching NullStringLocalizer semantics, without a reverse dependency on the higher-level OrchardCore assembly. Sources remain immutable; count is always the first format argument. Add targeted tests covering null validation, context-free fallback, context-bearing delegation, source immutability, string-vs-HTML encoding, and culture-specific zero/few/many forms using a real PortableObjectStringLocalizerFactory with a new Russian pluralization rule test helper. Update the Localize docs and revise the 4.0.0 release notes entry in place. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Add explicit LocalizationSource creation factories Use Create and Create<T> declarations for discoverable localization sources while preserving original keys, contexts, and shared instances. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Fix localization source factory analyzer violations Prefer generic factories for nonstatic contexts and retain runtime-Type and static-context coverage. Use the concrete localized HTML type in the plural test renderer. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Sébastien Ros <1165805+sebastienros@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Summary
Some APIs need a
LocalizedStringor aLocalizedHtmlString, but there is no localizer where the value is created. Today the code repeats the same text for the name and the value:This PR adds a static
Create(string value, params object[] arguments)method to both types, as C# 14 extension members, so that the text is written only once:The value is also used as the name. This works because Orchard Core uses the English text both as the default value and as the name of a localized string.
This is the first PR of a stack:
LocalizedString.CreateandLocalizedHtmlString.Create.LocalizedString.Createfor the category of every deployment step.LocalizedStringfor permission descriptions.Changes
LocalizedStringExtensionsin theMicrosoft.Extensions.Localizationnamespace, andLocalizedHtmlStringExtensionsin theMicrosoft.AspNetCore.Mvc.Localizationnamespace. Both are inOrchardCore.Abstractions/Localization/Extensions. Every Orchard Core project referencesOrchardCore.Abstractions, so the extensions can be used everywhere, including inOrchardCore.Infrastructure.Abstractions. They use the same namespaces as the types. Code that already uses the types can callLocalizedString.Create(...)with no newusingdirective.Create(value)is the same asnew LocalizedString(value, value)andnew LocalizedHtmlString(value, value). It does not translate the value, andResourceNotFoundisfalse.S["...", a, b]andH["...", a, b],Createaccepts optional format arguments. The name stays the unformatted text. For aLocalizedString, the value is formatted with the arguments. For aLocalizedHtmlString, the arguments are HTML encoded when the string is rendered. With no arguments, the text is not formatted, so"Hello {0}"does not throw.LocalizedStringExtensions.Create(...)orLocalizedHtmlStringExtensions.Create(...).reference/modules/Localize/README.md, and a 4.0.0 release notes entry.Tests
LocalizedStringExtensionsTestsandLocalizedHtmlStringExtensionsTestsinOrchardCore.Tests.dotnet test --project test/OrchardCore.Tests -c Release --filter-class "*LocalizedStringExtensionsTests" --filter-class "*LocalizedHtmlStringExtensionsTests" --filter-class "*NullStringLocalizerTests": 33 passed.Related
The PO extractor will pick up
LocalizedString.Create("...")andLocalizedHtmlString.Create("...")when the argument is literal text: OrchardCoreContrib/OrchardCoreContrib.PoExtractor#130🤖 Generated with Claude Code