Skip to content

Move the request-language GetResource overload to Web - #940

Merged
KrzysztofPajak merged 3 commits into
developfrom
refactor/business-explicity-resource
Oct 18, 2026
Merged

KrzysztofPajak merged 3 commits into
developfrom
refactor/business-explicity-resource

Conversation

@KrzysztofPajak

Copy link
Copy Markdown
Member

Part of the explicit-context work in Business (after #930, #931, #932, #936, #937, #938, #939)
Type: feature

Issue

ITranslationService.GetResource(name) reads the working language of the current request. #938 removed its last calls from src/Business, but nothing stopped new ones: the overload sat on the Business interface, and TranslationService still injected IContextAccessor only to serve it. Business code that calls it runs fine in a request and returns an empty or wrong-language text in a scheduled task, a background handler or the admin panel. #937 documented this overload as the accepted remainder of M1.

Solution

  • ITranslationService (Grand.Business.Core) keeps only GetResource(name, languageId, defaultValue, returnEmptyIfNotFound). TranslationService no longer takes IContextAccessor, so Business has no ambient read of the request left.
  • New IRequestTranslationService : ITranslationService in Grand.Web.Common.Localization adds GetResource(name) in the working language of the request. RequestTranslationService forwards everything else to the registered ITranslationService, so a replaced implementation still applies.
  • Web, the admin panels (Admin, Store, Vendor, AdminShared), LocService (Loc[...] in views) and the plugins inject IRequestTranslationService. Their GetResource(name) calls are unchanged; only the injected type changes.
  • Grand.Module.Api does not reference Grand.Web.Common. Its 17 validators read contextAccessor.WorkContext.WorkingLanguage.Id once and pass it.
  • .ai/ guides describe the new contract.

Known remainder: plugin providers (payment, shipping, tax, discount rules, widgets) resolve FriendlyName and Description() through IRequestTranslationService and are called from Business services (PaymentService, ShippingService, PricingService). This is the same behavior as before, now visible in the type. Fixing it means passing a language through IProvider and the provider contracts, which is a separate change.

Breaking changes

  • ITranslationService.GetResource(string name) is removed. Plugins call it on IRequestTranslationService (Grand.Web.Common.Localization) instead, or pass a language. A plugin built against the old interface fails with MissingMethodException until rebuilt.
  • TranslationService constructor: (IRepository<TranslationResource>, IMediator); IContextAccessor removed.
  • LocService and the Admin/Store/Vendor/AdminShared base controllers, view model services and validators take IRequestTranslationService instead of ITranslationService.
  • API module validators take IContextAccessor.

Testing

Automated: the solution builds, and dotnet test GrandNode.slnx passes. Grand.Business.Marketing.Tests failed one test in the parallel full run and passes on its own, which is the known parallel flake. New RequestTranslationServiceTests cover the request language, a request without a language (empty string), and that the explicit overload does not read the request. PluginDependencyCycleTests and the payment provider tests register IRequestTranslationService in their hand-built containers.

Manual (not run yet):

  1. Start the storefront, switch the language to a second one, and check that storefront texts, an admin page (for example Catalog → Products, then save a product to see the "updated" notification) and a store-owner page are translated.
  2. Add a product to the cart and go through checkout to the payment method step: the payment and shipping method names show in the selected language.
  3. Call the API (/api/... with a token) with an invalid product (empty name): the validation message is in the working language.

support added 2 commits October 17, 2026 20:43
ITranslationService.GetResource(name) read the working language of the
current request, so Business code could call it and silently get an empty
or wrong-language text outside a request. It is now on
IRequestTranslationService in Grand.Web.Common, which extends
ITranslationService. Business no longer sees the overload at compile time
and TranslationService no longer depends on IContextAccessor.

Web, admin panels and plugins inject IRequestTranslationService, so their
GetResource(name) calls are unchanged. The API module does not reference
Grand.Web.Common and passes the working language explicitly.
Copilot AI balanced review requested due to automatic review settings October 17, 2026 18:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

…ionService

- Add IContextAccessor.WorkingLanguageId() in the API module so validators
  no longer throw when no working language is resolved
- Move RequestTranslationService to its own file and derive it from
  TranslationService instead of forwarding every member
- Return an empty string from GetResource(name) when there is no work context
@KrzysztofPajak
KrzysztofPajak merged commit 7416ad3 into develop Oct 18, 2026
9 checks passed
@KrzysztofPajak
KrzysztofPajak deleted the refactor/business-explicity-resource branch October 18, 2026 05:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants