-
Notifications
You must be signed in to change notification settings - Fork 0
Localization
Harpyx keeps user-facing UI text in ASP.NET Core resource files. Razor markup should describe structure and behavior; copy belongs in .resx files organized by area and page.
The WebApp uses the standard ASP.NET Core localization stack:
AddLocalization(options => options.ResourcesPath = "Resources")-
AddViewLocalization()for Razor Page and view text -
AddDataAnnotationsLocalization()for validation and model metadata
The service registration lives in src/Harpyx.WebApp/Extensions/WebApplicationBuilderExtensions.cs.
Every Razor Page receives two localizers from src/Harpyx.WebApp/Pages/_ViewImports.cshtml:
@inject IViewLocalizer Localizer
@inject IStringLocalizer<Harpyx.WebApp.Shared.SharedResource> SharedLocalizerUse Localizer for text owned by the current page:
@{
ViewData["Title"] = Localizer["PageTitle"].Value;
}
<button class="btn btn-primary">@Localizer["SaveButton"]</button>Use SharedLocalizer for text intentionally reused across multiple pages, layouts, or partials:
var brandHero = new BrandHeroViewModel(
SharedLocalizer["BrandHeroTitle"].Value,
SharedLocalizer["BrandHeroSubtitle"].Value);This mirrors common ASP.NET Core guidance: page-local strings stay close to the page resource, while cross-page vocabulary goes through a shared marker resource.
Resource files mirror the Razor UI surface. The folder name should explain the owning area, and the file name should match the page or shared concept.
src/Harpyx.WebApp/
Resources/
Pages/
Index.resx
Welcome.resx
Profile/
Index.resx
Areas/
Admin/
Pages/
Llm/
Index.resx
Shared/
SharedResource.resx
Examples:
| UI file | Resource file |
|---|---|
Pages/Index.cshtml |
Resources/Pages/Index.resx |
Pages/Welcome.cshtml |
Resources/Pages/Welcome.resx |
Pages/Profile/Index.cshtml |
Resources/Pages/Profile/Index.resx |
Areas/Admin/Pages/Llm/Index.cshtml |
Resources/Areas/Admin/Pages/Llm/Index.resx |
| shared brand/layout copy | Resources/Shared/SharedResource.resx |
The shared resource uses a marker class at src/Harpyx.WebApp/Localization/Shared/SharedResource.cs. The class intentionally has no behavior; it gives IStringLocalizer<T> a stable resource anchor.
Resource keys are semantic identifiers, not the English text itself.
Use PascalCase keys:
PageTitle
SaveButton
DeleteConfirmationTitle
DeleteConfirmationMessage
BrandHeroTitle
BrandHeroSubtitle
Avoid full-sentence keys:
Save changes
Are you sure you want to delete this project?
Welcome to Harpyx!
Semantic keys are more stable when copy changes, easier to search, and friendlier to IDE completion and refactoring.
Put a string in the page resource when it belongs to one page:
@Localizer["GoToProjects"]Put a string in SharedResource.resx when it is deliberately shared:
@SharedLocalizer["BrandHeroTitle"]Do not move text into SharedResource.resx just because two pages happen to use the same English words. Shared resources should represent shared product language, shared layout copy, or reusable components.
When adding a Razor Page:
- Create the page resource file under
Resources/PagesorResources/Areas, mirroring the Razor path. - Add semantic PascalCase keys for every user-facing string.
- Reference page-owned strings with
Localizer["KeyName"]. - Reference global/shared copy with
SharedLocalizer["KeyName"]. - Keep HTML, tag helpers, route names, CSS classes, and icon names out of resource files unless they are true user-facing content.
For example, a new page at Pages/Projects/Create.cshtml should use:
Resources/Pages/Projects/Create.resx
and the Razor markup should read:
<h1>@Localizer["PageTitle"]</h1>
<button type="submit" class="btn btn-primary">@Localizer["CreateProjectButton"]</button>Validation messages and model metadata also use ASP.NET Core localization through AddDataAnnotationsLocalization().
Use explicit resource-backed messages for user-facing validation text. Prefer stable semantic keys when the same validation message appears in multiple places, and keep field-specific copy in the resource owned by that UI/model area.