Tenant bazında Localization düzenlemesi

This commit is contained in:
Sedat Öztürk 2025-10-25 00:53:53 +03:00
parent 768dfdfd16
commit bab93daf10
9 changed files with 150 additions and 19 deletions

View file

@ -9,9 +9,9 @@
"code": "Abp.Localization.DefaultLanguage", "code": "Abp.Localization.DefaultLanguage",
"nameKey": "Abp.Localization.DefaultLanguage", "nameKey": "Abp.Localization.DefaultLanguage",
"descriptionKey": "Abp.Localization.DefaultLanguage.Description", "descriptionKey": "Abp.Localization.DefaultLanguage.Description",
"defaultValue": "en", "defaultValue": "tr",
"isVisibleToClients": false, "isVisibleToClients": false,
"providers": ["G", "D"], "providers": ["T", "G", "D"],
"isInherited": false, "isInherited": false,
"isEncrypted": false, "isEncrypted": false,
"mainGroupKey": "App.SiteManagement", "mainGroupKey": "App.SiteManagement",
@ -40,12 +40,12 @@
"order": 1 "order": 1
}, },
{ {
"code": "Abp.Localization.Timezone", "code": "Abp.Timing.TimeZone",
"nameKey": "Abp.Localization.Timezone", "nameKey": "Abp.Timing.TimeZone",
"descriptionKey": "Abp.Localization.Timezone.Description", "descriptionKey": "Abp.Timing.TimeZone.Description",
"defaultValue": "UTC", "defaultValue": "Turkey Standard Time",
"isVisibleToClients": false, "isVisibleToClients": false,
"providers": ["G", "D"], "providers": ["T", "G", "D"],
"isInherited": false, "isInherited": false,
"isEncrypted": false, "isEncrypted": false,
"mainGroupKey": "App.SiteManagement", "mainGroupKey": "App.SiteManagement",
@ -3607,6 +3607,12 @@
"en": "Timezone", "en": "Timezone",
"tr": "Saat Dilimi" "tr": "Saat Dilimi"
}, },
{
"resourceName": "Platform",
"key": "Abp.Timing.TimeZone",
"en": "Timezone",
"tr": "Saat Dilimi"
},
{ {
"resourceName": "Platform", "resourceName": "Platform",
"key": "Abp.Localization.Timezone.Description", "key": "Abp.Localization.Timezone.Description",
@ -5813,13 +5819,13 @@
"resourceName": "Platform", "resourceName": "Platform",
"key": "ListForms.ListFormEdit.EditingForm", "key": "ListForms.ListFormEdit.EditingForm",
"en": "Form", "en": "Form",
"tr": "Dışarıdan Tıklandığında Gizle" "tr": "Form"
}, },
{ {
"resourceName": "Platform", "resourceName": "Platform",
"key": "ListForms.ListFormEdit.EditingFormFormFields", "key": "ListForms.ListFormEdit.EditingFormFormFields",
"en": "Editing Form Fields", "en": "Editing Form Fields",
"tr": "Form" "tr": "Düzenleme Form Alanları"
}, },
{ {
"resourceName": "Platform", "resourceName": "Platform",

View file

@ -39113,7 +39113,7 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
RoleId = null, RoleId = null,
UserId = null, UserId = null,
CultureName = LanguageCodes.En, CultureName = LanguageCodes.En,
SourceDbType = DbType.Date, SourceDbType = DbType.DateTime,
FieldName = "StartDate", FieldName = "StartDate",
Width = 100, Width = 100,
ListOrderNo = 5, ListOrderNo = 5,
@ -39147,7 +39147,7 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
RoleId = null, RoleId = null,
UserId = null, UserId = null,
CultureName = LanguageCodes.En, CultureName = LanguageCodes.En,
SourceDbType = DbType.Date, SourceDbType = DbType.DateTime,
FieldName = "EndDate", FieldName = "EndDate",
Width = 100, Width = 100,
ListOrderNo = 6, ListOrderNo = 6,

View file

@ -26,6 +26,8 @@ public static class PlatformConsts
public static string TimeSpanOptions = "{\"type\":\"time\",\"pickerType\":\"list\",\"displayFormat\":\"HH:mm\",\"dateSerializationFormat\":\"yyyy-MM-ddTHH:mm:ss\",\"interval\":30,\"width\":\"100%\"}"; public static string TimeSpanOptions = "{\"type\":\"time\",\"pickerType\":\"list\",\"displayFormat\":\"HH:mm\",\"dateSerializationFormat\":\"yyyy-MM-ddTHH:mm:ss\",\"interval\":30,\"width\":\"100%\"}";
public static string NumberStandartFormat = "{ \"format\": \",##0.###\" }"; public static string NumberStandartFormat = "{ \"format\": \",##0.###\" }";
public static string NumberPercentFormat = "{ \"format\": \"#0.##'%'\" }"; public static string NumberPercentFormat = "{ \"format\": \"#0.##'%'\" }";
public static string DateFormat = "{ \"format\": \"dd/MM/yyyy\", \"displayFormat\" : \"dd/MM/yyyy\" }";
public static string DateTimeFormat = "{ \"format\": \"dd/MM/yyyy HH:mm\", \"displayFormat\" : \"dd/MM/yyyy HH:mm\" }";
} }
public static class EditorScriptValues public static class EditorScriptValues

View file

@ -51,9 +51,9 @@ public class PlatformDomainModule : AbpModule
//context.Services.Replace(ServiceDescriptor.Singleton<IEmailSender, NullEmailSender>()); //context.Services.Replace(ServiceDescriptor.Singleton<IEmailSender, NullEmailSender>());
#endif #endif
Configure<AbpClockOptions>(options => // Configure<AbpClockOptions>(options =>
{ // {
options.Kind = DateTimeKind.Utc; // options.Kind = DateTimeKind.Utc;
}); // });
} }
} }

View file

@ -12,6 +12,7 @@ using Kurs.Platform.Classrooms;
using Kurs.Platform.EntityFrameworkCore; using Kurs.Platform.EntityFrameworkCore;
using Kurs.Platform.Extensions; using Kurs.Platform.Extensions;
using Kurs.Platform.Identity; using Kurs.Platform.Identity;
using Kurs.Platform.Localization;
using Kurs.Settings; using Kurs.Settings;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Cors;
@ -47,6 +48,7 @@ using Volo.Abp.Identity;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.Security.Claims; using Volo.Abp.Security.Claims;
using Volo.Abp.Swashbuckle; using Volo.Abp.Swashbuckle;
using Volo.Abp.Timing;
using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.UI.Navigation.Urls;
using Volo.Abp.VirtualFileSystem; using Volo.Abp.VirtualFileSystem;
using static Kurs.Platform.PlatformConsts; using static Kurs.Platform.PlatformConsts;
@ -101,6 +103,11 @@ public class PlatformHttpApiHostModule : AbpModule
{ {
var configuration = context.Services.GetConfiguration(); var configuration = context.Services.GetConfiguration();
//Tenant bazında lokalizasyon ayarları için
//TenantLocalization Middleware kaydı
context.Services.AddTransient<TenantLocalizationMiddleware>();
context.Services.AddTransient<TenantLocalizationInitializer>();
ConfigureAuthentication(context); ConfigureAuthentication(context);
ConfigureBundles(); ConfigureBundles();
ConfigureUrls(configuration); ConfigureUrls(configuration);
@ -391,6 +398,7 @@ public class PlatformHttpApiHostModule : AbpModule
if (PlatformConsts.IsMultiTenant) if (PlatformConsts.IsMultiTenant)
{ {
app.UseMultiTenancy(); app.UseMultiTenancy();
app.UseMiddleware<TenantLocalizationMiddleware>();
} }
app.UseUnitOfWork(); app.UseUnitOfWork();

View file

@ -0,0 +1,59 @@
using System;
using System.Globalization;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
using Volo.Abp.Timing;
using Volo.Abp.MultiTenancy;
using Microsoft.Extensions.Options;
namespace Kurs.Platform.Localization
{
public class TenantLocalizationInitializer : ITransientDependency
{
private readonly ISettingProvider _settingProvider;
private readonly ICurrentTenant _currentTenant;
private readonly IOptions<AbpClockOptions> _clockOptions;
public TenantLocalizationInitializer(
ISettingProvider settingProvider,
ICurrentTenant currentTenant,
IOptions<AbpClockOptions> clockOptions)
{
_settingProvider = settingProvider;
_currentTenant = currentTenant;
_clockOptions = clockOptions;
}
public async Task ApplyTenantSettingsAsync()
{
// Dil ayarı
var lang = await _settingProvider.GetOrNullAsync("Abp.Localization.DefaultLanguage") ?? "en";
try
{
var culture = new CultureInfo(lang);
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
}
catch
{
CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture;
}
// Saat tipi (UTC / Local)
var timeZoneId = await _settingProvider.GetOrNullAsync("Abp.Timing.TimeZone") ?? "UTC";
try
{
var tz = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
_clockOptions.Value.Kind = tz.Id.Contains("UTC", StringComparison.OrdinalIgnoreCase)
? DateTimeKind.Utc
: DateTimeKind.Local;
}
catch
{
_clockOptions.Value.Kind = DateTimeKind.Utc;
}
}
}
}

View file

@ -0,0 +1,19 @@
using System.Threading.Tasks;
using Kurs.Platform.Localization;
using Microsoft.AspNetCore.Http;
public class TenantLocalizationMiddleware : IMiddleware
{
private readonly TenantLocalizationInitializer _initializer;
public TenantLocalizationMiddleware(TenantLocalizationInitializer initializer)
{
_initializer = initializer;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
await _initializer.ApplyTenantSettingsAsync();
await next(context);
}
}

View file

@ -55,7 +55,7 @@ const cellTemplateMultiValue = (
> >
${v} ${v}
</div> </div>
` `,
) )
.join('') .join('')
@ -64,7 +64,6 @@ const cellTemplateMultiValue = (
} }
} }
function calculateFilterExpressionMultiValue( function calculateFilterExpressionMultiValue(
this: DataGridTypes.Column, this: DataGridTypes.Column,
filterValue: any, filterValue: any,
@ -392,7 +391,24 @@ const useListFormColumns = ({
column.alignment = colData.alignment column.alignment = colData.alignment
column.format = colData.format column.format = colData.format
column.editorOptions = { ...(colData.editorOptions as IFormatProps) }
let editorOptions: any = {}
if (colData.editorOptions) {
try {
editorOptions =
typeof colData.editorOptions === 'string'
? JSON.parse(colData.editorOptions)
: colData.editorOptions
} catch {
editorOptions = {}
}
}
column.editorOptions = { ...editorOptions }
if (column.editorOptions.displayFormat) {
column.format = column.editorOptions.displayFormat
}
// columnCustomizationDto // columnCustomizationDto
column.fixed = colData.columnCustomizationDto?.fixed column.fixed = colData.columnCustomizationDto?.fixed

View file

@ -1,22 +1,43 @@
import { useEffect } from 'react' import { useEffect } from 'react'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc'
import timezone from 'dayjs/plugin/timezone'
import { locale as dxLocale } from 'devextreme/localization'
import config from 'devextreme/core/config'
import { useStoreState } from '@/store' import { useStoreState } from '@/store'
import { dateLocales } from '@/constants/dateLocales.constant' import { dateLocales } from '@/constants/dateLocales.constant'
dayjs.extend(utc)
dayjs.extend(timezone)
function useLocale() { function useLocale() {
const cultureName = useStoreState((state) => state.locale.currentLang) const cultureName = useStoreState((state) => state.locale.currentLang)
const languageList = useStoreState((state) => state.abpConfig.config?.localization.languages) const languageList = useStoreState((state) => state.abpConfig.config?.localization.languages)
const abpConfig = useStoreState((state) => state.abpConfig.config)
const twoLetterISOLanguageName = languageList?.find( const twoLetterISOLanguageName = languageList?.find(
(lang) => lang.cultureName === cultureName, (lang) => lang.cultureName === cultureName,
)?.twoLetterISOLanguageName )?.twoLetterISOLanguageName
const timeZone = abpConfig?.timing?.timeZone?.iana?.timeZoneName ?? 'UTC'
useEffect(() => { useEffect(() => {
if (cultureName && twoLetterISOLanguageName && dateLocales[twoLetterISOLanguageName]) { if (cultureName && twoLetterISOLanguageName && dateLocales[twoLetterISOLanguageName]) {
dateLocales[twoLetterISOLanguageName]().then(() => { dateLocales[twoLetterISOLanguageName]().then(() => {
dayjs.locale(cultureName) dayjs.locale(cultureName)
dayjs.tz.setDefault(timeZone)
// ✅ DevExtreme locale ayarı
dxLocale(cultureName)
// ✅ Para birimi
config({
defaultCurrency: cultureName.startsWith('tr') ? 'TRY' : 'USD',
})
// console.info(`🌍 Locale: ${cultureName}, TZ: ${timeZone}`)
}) })
} }
}, [cultureName, twoLetterISOLanguageName]) }, [cultureName, twoLetterISOLanguageName, timeZone])
return cultureName return cultureName
} }