diff --git a/api/src/Kurs.Platform.DbMigrator/Seeds/HostData.json b/api/src/Kurs.Platform.DbMigrator/Seeds/HostData.json index d1c04f12..b8799d14 100644 --- a/api/src/Kurs.Platform.DbMigrator/Seeds/HostData.json +++ b/api/src/Kurs.Platform.DbMigrator/Seeds/HostData.json @@ -9,9 +9,9 @@ "code": "Abp.Localization.DefaultLanguage", "nameKey": "Abp.Localization.DefaultLanguage", "descriptionKey": "Abp.Localization.DefaultLanguage.Description", - "defaultValue": "en", + "defaultValue": "tr", "isVisibleToClients": false, - "providers": ["G", "D"], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "App.SiteManagement", @@ -40,12 +40,12 @@ "order": 1 }, { - "code": "Abp.Localization.Timezone", - "nameKey": "Abp.Localization.Timezone", - "descriptionKey": "Abp.Localization.Timezone.Description", - "defaultValue": "UTC", + "code": "Abp.Timing.TimeZone", + "nameKey": "Abp.Timing.TimeZone", + "descriptionKey": "Abp.Timing.TimeZone.Description", + "defaultValue": "Turkey Standard Time", "isVisibleToClients": false, - "providers": ["G", "D"], + "providers": ["T", "G", "D"], "isInherited": false, "isEncrypted": false, "mainGroupKey": "App.SiteManagement", @@ -3607,6 +3607,12 @@ "en": "Timezone", "tr": "Saat Dilimi" }, + { + "resourceName": "Platform", + "key": "Abp.Timing.TimeZone", + "en": "Timezone", + "tr": "Saat Dilimi" + }, { "resourceName": "Platform", "key": "Abp.Localization.Timezone.Description", @@ -5813,13 +5819,13 @@ "resourceName": "Platform", "key": "ListForms.ListFormEdit.EditingForm", "en": "Form", - "tr": "Dışarıdan Tıklandığında Gizle" + "tr": "Form" }, { "resourceName": "Platform", "key": "ListForms.ListFormEdit.EditingFormFormFields", "en": "Editing Form Fields", - "tr": "Form" + "tr": "Düzenleme Form Alanları" }, { "resourceName": "Platform", diff --git a/api/src/Kurs.Platform.DbMigrator/Seeds/ListFormsSeeder.cs b/api/src/Kurs.Platform.DbMigrator/Seeds/ListFormsSeeder.cs index e2b5a076..5dc049fb 100644 --- a/api/src/Kurs.Platform.DbMigrator/Seeds/ListFormsSeeder.cs +++ b/api/src/Kurs.Platform.DbMigrator/Seeds/ListFormsSeeder.cs @@ -39113,7 +39113,7 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency RoleId = null, UserId = null, CultureName = LanguageCodes.En, - SourceDbType = DbType.Date, + SourceDbType = DbType.DateTime, FieldName = "StartDate", Width = 100, ListOrderNo = 5, @@ -39147,7 +39147,7 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency RoleId = null, UserId = null, CultureName = LanguageCodes.En, - SourceDbType = DbType.Date, + SourceDbType = DbType.DateTime, FieldName = "EndDate", Width = 100, ListOrderNo = 6, diff --git a/api/src/Kurs.Platform.Domain.Shared/PlatformConsts.cs b/api/src/Kurs.Platform.Domain.Shared/PlatformConsts.cs index 5001f833..0cf5a6ea 100644 --- a/api/src/Kurs.Platform.Domain.Shared/PlatformConsts.cs +++ b/api/src/Kurs.Platform.Domain.Shared/PlatformConsts.cs @@ -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 NumberStandartFormat = "{ \"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 diff --git a/api/src/Kurs.Platform.Domain/PlatformDomainModule.cs b/api/src/Kurs.Platform.Domain/PlatformDomainModule.cs index c3bab8c1..5f4f77e1 100644 --- a/api/src/Kurs.Platform.Domain/PlatformDomainModule.cs +++ b/api/src/Kurs.Platform.Domain/PlatformDomainModule.cs @@ -51,9 +51,9 @@ public class PlatformDomainModule : AbpModule //context.Services.Replace(ServiceDescriptor.Singleton()); #endif - Configure(options => - { - options.Kind = DateTimeKind.Utc; - }); + // Configure(options => + // { + // options.Kind = DateTimeKind.Utc; + // }); } } diff --git a/api/src/Kurs.Platform.HttpApi.Host/PlatformHttpApiHostModule.cs b/api/src/Kurs.Platform.HttpApi.Host/PlatformHttpApiHostModule.cs index f43e3fdd..9cad72ab 100644 --- a/api/src/Kurs.Platform.HttpApi.Host/PlatformHttpApiHostModule.cs +++ b/api/src/Kurs.Platform.HttpApi.Host/PlatformHttpApiHostModule.cs @@ -12,6 +12,7 @@ using Kurs.Platform.Classrooms; using Kurs.Platform.EntityFrameworkCore; using Kurs.Platform.Extensions; using Kurs.Platform.Identity; +using Kurs.Platform.Localization; using Kurs.Settings; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Cors; @@ -47,6 +48,7 @@ using Volo.Abp.Identity; using Volo.Abp.Modularity; using Volo.Abp.Security.Claims; using Volo.Abp.Swashbuckle; +using Volo.Abp.Timing; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.VirtualFileSystem; using static Kurs.Platform.PlatformConsts; @@ -101,6 +103,11 @@ public class PlatformHttpApiHostModule : AbpModule { var configuration = context.Services.GetConfiguration(); + //Tenant bazında lokalizasyon ayarları için + //TenantLocalization Middleware kaydı + context.Services.AddTransient(); + context.Services.AddTransient(); + ConfigureAuthentication(context); ConfigureBundles(); ConfigureUrls(configuration); @@ -391,6 +398,7 @@ public class PlatformHttpApiHostModule : AbpModule if (PlatformConsts.IsMultiTenant) { app.UseMultiTenancy(); + app.UseMiddleware(); } app.UseUnitOfWork(); diff --git a/api/src/Kurs.Platform.HttpApi.Host/TenantLocalizationInitializer.cs b/api/src/Kurs.Platform.HttpApi.Host/TenantLocalizationInitializer.cs new file mode 100644 index 00000000..25b7113d --- /dev/null +++ b/api/src/Kurs.Platform.HttpApi.Host/TenantLocalizationInitializer.cs @@ -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 _clockOptions; + + public TenantLocalizationInitializer( + ISettingProvider settingProvider, + ICurrentTenant currentTenant, + IOptions 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; + } + } + } +} diff --git a/api/src/Kurs.Platform.HttpApi.Host/TenantLocalizationMiddleware.cs b/api/src/Kurs.Platform.HttpApi.Host/TenantLocalizationMiddleware.cs new file mode 100644 index 00000000..611bc0d1 --- /dev/null +++ b/api/src/Kurs.Platform.HttpApi.Host/TenantLocalizationMiddleware.cs @@ -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); + } +} diff --git a/ui/src/shared/useListFormColumns.ts b/ui/src/shared/useListFormColumns.ts index 1778c3b5..2d209956 100644 --- a/ui/src/shared/useListFormColumns.ts +++ b/ui/src/shared/useListFormColumns.ts @@ -55,7 +55,7 @@ const cellTemplateMultiValue = ( > ${v} - ` + `, ) .join('') @@ -64,7 +64,6 @@ const cellTemplateMultiValue = ( } } - function calculateFilterExpressionMultiValue( this: DataGridTypes.Column, filterValue: any, @@ -392,7 +391,24 @@ const useListFormColumns = ({ column.alignment = colData.alignment 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 column.fixed = colData.columnCustomizationDto?.fixed diff --git a/ui/src/utils/hooks/useLocale.ts b/ui/src/utils/hooks/useLocale.ts index abcea2d3..a6a1f0c8 100644 --- a/ui/src/utils/hooks/useLocale.ts +++ b/ui/src/utils/hooks/useLocale.ts @@ -1,22 +1,43 @@ import { useEffect } from 'react' 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 { dateLocales } from '@/constants/dateLocales.constant' +dayjs.extend(utc) +dayjs.extend(timezone) + function useLocale() { const cultureName = useStoreState((state) => state.locale.currentLang) const languageList = useStoreState((state) => state.abpConfig.config?.localization.languages) + const abpConfig = useStoreState((state) => state.abpConfig.config) const twoLetterISOLanguageName = languageList?.find( (lang) => lang.cultureName === cultureName, )?.twoLetterISOLanguageName + const timeZone = abpConfig?.timing?.timeZone?.iana?.timeZoneName ?? 'UTC' + useEffect(() => { if (cultureName && twoLetterISOLanguageName && dateLocales[twoLetterISOLanguageName]) { dateLocales[twoLetterISOLanguageName]().then(() => { 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 }