Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blazor localizations with resx files #1081

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 26 additions & 26 deletions src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -16,61 +16,61 @@
<PackageVersion Include="Finbuckle.MultiTenant" Version="9.0.0" />
<PackageVersion Include="Finbuckle.MultiTenant.AspNetCore" Version="9.0.0" />
<PackageVersion Include="Finbuckle.MultiTenant.EntityFrameworkCore" Version="9.0.0" />
<PackageVersion Include="Hangfire" Version="1.8.15" />
<PackageVersion Include="Hangfire" Version="1.8.17" />
<PackageVersion Include="Hangfire.MemoryStorage" Version="1.8.1.1" />
<PackageVersion Include="Hangfire.PostgreSql" Version="1.20.10" />
<PackageVersion Include="MailKit" Version="4.8.0" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.0" />
<PackageVersion Include="MailKit" Version="4.9.0" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.1" />
<PackageVersion Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="9.0.1" />
<PackageVersion Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.11.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="9.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.1" />
<PackageVersion Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="9.0.1" />
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="9.0.1" />
<PackageVersion Include="Microsoft.NET.Build.Containers" Version="8.0.100" />
<PackageVersion Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
<PackageVersion Include="MimeKit" Version="4.8.0" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.1" />
<PackageVersion Include="OpenTelemetry.Exporter.Console" Version="1.10.0" />
<PackageVersion Include="MimeKit" Version="4.9.0" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.3" />
<PackageVersion Include="OpenTelemetry.Exporter.Console" Version="1.11.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.EntityFrameworkCore" Version="1.0.0-beta.12" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Process" Version="0.5.0-beta.6" />
<PackageVersion Include="Serilog.Expressions" Version="5.0.0" />
<PackageVersion Include="Serilog.Sinks.OpenTelemetry" Version="4.1.1" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="7.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.0" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="7.2.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.1" />
<PackageVersion Include="Swashbuckle.AspNetCore.ReDoc" Version="6.5.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Common" Version="4.11.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.11.0" />
</ItemGroup>
<ItemGroup>
<PackageVersion Include="Mapster" Version="7.4.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="9.0.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.0.1" />
</ItemGroup>
<ItemGroup>
<PackageVersion Include="SonarAnalyzer.CSharp" Version="9.32.0.97167" />
<PackageVersion Include="SonarAnalyzer.CSharp" Version="10.5.0.109200" />
</ItemGroup>
<ItemGroup>
<PackageVersion Include="MediatR" Version="12.4.1" />
<PackageVersion Include="FluentValidation.DependencyInjectionExtensions" Version="11.11.0" />
<PackageVersion Include="Carter" Version="9.0.0" />
</ItemGroup>
<ItemGroup>
<PackageVersion Include="Serilog" Version="4.1.0" />
<PackageVersion Include="Serilog.AspNetCore" Version="8.0.3" />
<PackageVersion Include="Serilog" Version="4.2.0" />
<PackageVersion Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageVersion Include="Serilog.Enrichers.CorrelationId" Version="3.0.1" />
<PackageVersion Include="Serilog.Enrichers.Environment" Version="3.0.1" />
<PackageVersion Include="Serilog.Enrichers.Span" Version="3.1.0" />
<PackageVersion Include="Serilog.Exceptions" Version="8.4.0" />
<PackageVersion Include="Serilog.Extensions.Hosting" Version="8.0.0" />
<PackageVersion Include="Serilog.Extensions.Hosting" Version="9.0.0" />
<PackageVersion Include="Serilog.Sinks.Elasticsearch" Version="10.0.0" />
<PackageVersion Include="Serilog.Formatting.Elasticsearch" Version="10.0.0" />
<PackageVersion Include="Serilog.Sinks.Async" Version="2.1.0" />
<PackageVersion Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageVersion Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageVersion Include="Serilog.Sinks.Seq" Version="8.0.0" />
<PackageVersion Include="Serilog.Sinks.Seq" Version="9.0.0" />
<PackageVersion Include="Serilog.Sinks.SpectreConsole" Version="0.3.3" />
<PackageVersion Include="SerilogAnalyzer" Version="0.15.0" />
<PackageVersion Include="SerilogTimings" Version="3.1.0" />
Expand All @@ -80,13 +80,13 @@
<ItemGroup Label="Aspire">
<PackageVersion Include="Aspire.Hosting.AppHost" Version="9.0.0" />
<PackageVersion Include="Aspire.AppHost.Sdk" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="9.1.0" />
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="9.0.0" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.10.0" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.11.0" />
<PackageVersion Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.9.0-beta.2" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.10.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.9.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.9.0" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.11.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.10.1" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="1.10.0" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.10.0" />
</ItemGroup>
</Project>
7 changes: 7 additions & 0 deletions src/Shared/Constants/LanguageCode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace FSH.Starter.Shared.Constants;

public class LanguageCode
{
public string DisplayName { get; set; }

Check warning on line 5 in src/Shared/Constants/LanguageCode.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'DisplayName' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

Check warning on line 5 in src/Shared/Constants/LanguageCode.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'DisplayName' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
public string Code { get; set; }

Check warning on line 6 in src/Shared/Constants/LanguageCode.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Code' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

Check warning on line 6 in src/Shared/Constants/LanguageCode.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Code' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
}
17 changes: 17 additions & 0 deletions src/Shared/Constants/LocalizationConstants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace FSH.Starter.Shared.Constants;

public static class LocalizationConstants
{
public static readonly LanguageCode[] SupportedLanguages = {
new LanguageCode
{
Code = "en-US",
DisplayName= "English"
},
new LanguageCode
{
Code = "af-ZA",
DisplayName = "Afrikaans"
}
};
}
3 changes: 2 additions & 1 deletion src/api/framework/Core/Persistence/DatabaseOptions.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using System.ComponentModel.DataAnnotations;

namespace FSH.Framework.Core.Persistence;

public class DatabaseOptions : IValidatableObject
{
public string Provider { get; set; } = "postgresql";
public string Provider { get; set; } = "mssql";
public string ConnectionString { get; set; } = string.Empty;

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
Expand Down
4 changes: 4 additions & 0 deletions src/api/framework/Infrastructure/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ public static WebApplicationBuilder ConfigureFshFramework(this WebApplicationBui
builder.AddServiceDefaults();
builder.ConfigureSerilog();
builder.ConfigureDatabase();
builder.Services.AddLocalization(options =>
{
options.ResourcesPath = "Resources";
});
builder.Services.ConfigureMultitenancy();
builder.Services.ConfigureIdentity();
builder.Services.AddCorsPolicy(builder.Configuration);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public CatalogDbContext(IMultiTenantContextAccessor<FshTenantInfo> multiTenantCo
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
ArgumentNullException.ThrowIfNull(modelBuilder);
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(typeof(CatalogDbContext).Assembly);
modelBuilder.HasDefaultSchema(SchemaNames.Catalog);
}
Expand Down
1 change: 1 addition & 0 deletions src/api/modules/Todo/Persistence/TodoDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public TodoDbContext(IMultiTenantContextAccessor<FshTenantInfo> multiTenantConte
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
ArgumentNullException.ThrowIfNull(modelBuilder);
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(typeof(TodoDbContext).Assembly);
modelBuilder.HasDefaultSchema(SchemaNames.Todo);
}
Expand Down
4 changes: 2 additions & 2 deletions src/api/server/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"DatabaseOptions": {
"Provider": "postgresql",
"ConnectionString": "Server=192.168.1.110;Database=fullstackherodb;User Id=postgres;Password=password"
"Provider": "mssql",
"ConnectionString": "Data Source=KALLIENTB;Integrated Security=True;User ID=Kallientb\\Kallie;Database=RUMAS_ROOT;TrustServerCertificate=True;"
},
"OriginOptions": {
"OriginUrl": "https://localhost:7000"
Expand Down
2 changes: 2 additions & 0 deletions src/apps/blazor/client/Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
<RootNamespace>FSH.Starter.Blazor.Client</RootNamespace>
<AssemblyName>FSH.Starter.Blazor.Client</AssemblyName>
<ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Mapster" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" PrivateAssets="all" />
<PackageReference Include="MudBlazor" />
</ItemGroup>

<ItemGroup>
Expand Down
3 changes: 2 additions & 1 deletion src/apps/blazor/client/Components/Common/TablePager.razor
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
<MudTablePager RowsPerPageString="RowsPerPageString" InfoFormat="InfoFormat" />
@inject Microsoft.Extensions.Localization.IStringLocalizer<TablePager> _localizer
<MudTablePager RowsPerPageString="@_localizer["RowsPerPageString"]" InfoFormat="@_localizer["InfoFormat"]" />
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
<MudDialog>
@inject Microsoft.Extensions.Localization.IStringLocalizer<DeleteConfirmation> _localizer
<MudDialog>
<TitleContent>
<MudText Typo="Typo.h6">
<MudIcon Icon="@Icons.Material.Filled.Delete" Class="mr-3 mb-n1" />
Delete Confirmation
@_localizer["Delete Confirmation"]
</MudText>
</TitleContent>
<DialogContent>
<MudText>@ContentText</MudText>
</DialogContent>
<DialogActions>
<MudButton DropShadow=false StartIcon="@Icons.Material.Filled.Cancel" OnClick="Cancel">Cancel</MudButton>
<MudButton DropShadow=false StartIcon="@Icons.Material.Filled.Delete" Color="Color.Error" Variant="Variant.Filled" OnClick="Submit">Confirm</MudButton>
<MudButton DropShadow=false StartIcon="@Icons.Material.Filled.Cancel" OnClick="Cancel">@_localizer["Cancel"]</MudButton>
<MudButton DropShadow=false StartIcon="@Icons.Material.Filled.Delete" Color="Color.Error" Variant="Variant.Filled" OnClick="Submit">@_localizer["Confirm"]</MudButton>
</DialogActions>
</MudDialog>

Expand Down
6 changes: 3 additions & 3 deletions src/apps/blazor/client/Components/Dialogs/Logout.razor
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
@namespace FSH.Starter.Blazor.Client.Components.Dialogs

@inject Microsoft.Extensions.Localization.IStringLocalizer<Logout> _localizer

@inject IAuthenticationService AuthService

<MudDialog Class="py-4 px-4">
<TitleContent>
<MudText Typo="Typo.h6">
<MudIcon Icon="@Icons.Material.Filled.Logout" Class="mr-3 mb-n1" />
Logout Confirmation
@_localizer["Logout Confirmation"]
</MudText>
</TitleContent>
<DialogContent>
<MudText>@ContentText</MudText>
</DialogContent>
<DialogActions>
<MudButton DropShadow=false StartIcon="@Icons.Material.Filled.Cancel" Variant="Variant.Filled" OnClick="Cancel">Cancel</MudButton>
<MudButton DropShadow=false StartIcon="@Icons.Material.Filled.Cancel" Variant="Variant.Filled" OnClick="Cancel">@_localizer["Cancel"]</MudButton>
<MudButton DropShadow=false StartIcon="@Icons.Material.Filled.Logout" Color="@Color" Variant="Variant.Filled" OnClick="Submit">@ButtonText</MudButton>
</DialogActions>
</MudDialog>
Expand Down
10 changes: 5 additions & 5 deletions src/apps/blazor/client/Components/EntityTable/AddEditModal.razor
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@typeparam TRequest
@inject Microsoft.Extensions.Localization.IStringLocalizer<Modals> _localizer
@typeparam TRequest

<EditForm Model="@RequestModel" OnValidSubmit="SaveAsync">
<MudDialog>
Expand Down Expand Up @@ -29,21 +30,20 @@

<DialogActions>
<MudButton DropShadow="false" Variant="Variant.Filled" StartIcon="@Icons.Material.Filled.Cancel" OnClick="MudDialog.Cancel">
Cancel
@_localizer["Cancel"]
</MudButton>
@if (IsCreate)
{
<MudButton DropShadow="false" Variant="Variant.Filled" StartIcon="@Icons.Material.Filled.Save" ButtonType="ButtonType.Submit" Color="Color.Success">
Save
@_localizer["Save"]
</MudButton>
}
else
{
<MudButton DropShadow="false" Variant="Variant.Filled" StartIcon="@Icons.Material.Filled.Update" ButtonType="ButtonType.Submit" Color="Color.Secondary">
Update
@_localizer["Update"]
</MudButton>
}
</DialogActions>

</MudDialog>
</EditForm>
27 changes: 10 additions & 17 deletions src/apps/blazor/client/Components/EntityTable/EntityTable.razor
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
@typeparam TEntity
@inject Microsoft.Extensions.Localization.IStringLocalizer<Modals> _localizer
@typeparam TEntity
@typeparam TId
@typeparam TRequest

@inject IJSRuntime JS

<style>
.mud-table-container {
overflow: auto;
Expand All @@ -12,12 +11,11 @@

<ErrorBoundary>
<ChildContent>

@if (_canSearch && (Context.AdvancedSearchEnabled || AdvancedSearchContent is not null))
{
<MudExpansionPanel @bind-bind-Expanded="_advancedSearchExpanded"
Style="padding:10px!important; margin-bottom:10px!important;border-radius: var(--mud-default-borderradius) !important;"
Class="mud-table mud-table-outlined" Text="Advanced Search" Expanded=false>
Class="mud-table mud-table-outlined" Text="@_localizer["Advanced Search"]" Expanded=false>
<MudTextField @bind-Value="SearchString" Immediate="true"
Placeholder="@($"Search for {Context.EntityNamePlural}")" Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium"
Expand All @@ -35,23 +33,21 @@
</div>
} *@
@AdvancedSearchContent

</MudExpansionPanel>
}

<FshTable @ref="_table" Outlined ServerData="@ServerReloadFunc" Items="@_entityList" Filter="LocalSearch"
Loading="@Loading" LoadingProgressColor="@Color.Secondary" ChildRowContent="@ChildRowContent">

<ToolBarContent>
<div class="justify-center mud-text-align-center">
@if (_canCreate)
{
<MudButton Variant="Variant.Filled" Color="Color.Primary" DropShadow="false"
OnClick="(() => InvokeModal())" StartIcon="@Icons.Material.Filled.Add"
IconColor="Color.Surface" Class="mr-4">Create</MudButton>
IconColor="Color.Surface" Class="mr-4">@_localizer["Create"]</MudButton>
}
<MudButton Variant="Variant.Filled" OnClick="ReloadDataAsync" DropShadow="false"
StartIcon="@Icons.Material.Filled.Refresh" IconColor="Color.Surface" Color="Color.Secondary">Reload</MudButton>
StartIcon="@Icons.Material.Filled.Refresh" IconColor="Color.Surface" Color="Color.Secondary">@_localizer["Reload"]</MudButton>
</div>
<MudSpacer />
@if (_canSearch && !_advancedSearchExpanded)
Expand Down Expand Up @@ -81,7 +77,7 @@
</MudTh>
}
}
<MudTh Style="text-align:right">Actions</MudTh>
<MudTh Style="text-align:right">@_localizer["Actions"]</MudTh>
</HeaderContent>

<RowTemplate>
Expand Down Expand Up @@ -109,16 +105,16 @@
}
else if (HasActions)
{
<MudMenu Label="Actions" Variant="Variant.Filled" DropShadow=false
<MudMenu Label="@_localizer["Actions"]" Variant="Variant.Filled" DropShadow=false
EndIcon="@Icons.Material.Filled.KeyboardArrowDown" IconColor="Color.Secondary" direction="Direction.Left"
offsetX="true">
@if (CanUpdateEntity(context))
{
<MudMenuItem @onclick="@(() => InvokeModal(context))">Edit</MudMenuItem>
<MudMenuItem @onclick="@(() => InvokeModal(context))">@_localizer["Edit"]</MudMenuItem>
}
@if (CanDeleteEntity(context))
{
<MudMenuItem Style="color:red!important" @onclick="@(() => Delete(context))">Delete</MudMenuItem>
<MudMenuItem Style="color:red!important" @onclick="@(() => Delete(context))">@_localizer["Delete"]</MudMenuItem>
}
@if (ExtraActions is not null)
{
Expand All @@ -131,18 +127,15 @@
<MudButton Variant="Variant.Filled" DropShadow="false"
StartIcon="@Icons.Material.Filled.DoNotTouch" IconColor="Color.Secondary" Size="Size.Small"
Color="Color.Surface">
No Allowed Actions
@_localizer["No Allowed Actions"]
</MudButton>
}
</MudTd>
</RowTemplate>

<PagerContent>
<TablePager />
</PagerContent>

</FshTable>

</ChildContent>
<ErrorContent>
<FshCustomError />
Expand Down
Loading
Loading