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

Feature/gb 163 location multi language #79

Open
wants to merge 31 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
b7ad2d6
add culture pipeline behaviour to easily fetch the current user's cul…
Joren-vanGoethem Feb 18, 2025
8665d9b
add new behaviour to pipeline
Joren-vanGoethem Feb 18, 2025
e3faad5
add some new items to translation infra as support for new behaviour
Joren-vanGoethem Feb 18, 2025
015164f
use page endpoints as first test for i18n support
Joren-vanGoethem Feb 18, 2025
1cc5ffb
some cleanup in response object
Joren-vanGoethem Feb 18, 2025
102993d
add translation key
Joren-vanGoethem Feb 18, 2025
2ac3e32
update page config
Joren-vanGoethem Feb 18, 2025
59a42e1
update page with new translated data
Joren-vanGoethem Feb 18, 2025
c598986
remove the need for passing language keys, always use current culture…
Joren-vanGoethem Feb 18, 2025
ddf4abb
update dbcontext and entity config for json mapping
Joren-vanGoethem Feb 18, 2025
11a86e0
update controller and response
Joren-vanGoethem Feb 18, 2025
ea3ec39
automatic keycloak policy mapping
Joren-vanGoethem Feb 18, 2025
932118c
remove the need to pass language key, fetch from CultureInfo
Joren-vanGoethem Feb 18, 2025
9ee2fb4
add new translation for when a translation is not found
Joren-vanGoethem Feb 18, 2025
186caa1
add migration
Joren-vanGoethem Feb 18, 2025
f5f374f
update frontend to refetch all data when switching languages and move…
Joren-vanGoethem Feb 18, 2025
24db7f5
work in progress multi language event importer
Joren-vanGoethem Feb 18, 2025
2395664
add translations to event data and make importer import all languages
Joren-vanGoethem Feb 20, 2025
97055e2
update backend for translations on locations
Joren-vanGoethem Feb 22, 2025
cbfba7b
fix filtering on events
Joren-vanGoethem Feb 22, 2025
19959bb
add todo
Joren-vanGoethem Feb 22, 2025
ee9cc2a
Merge branch 'dev' into feature/GB-163-location-multi-language
Joren-vanGoethem Feb 22, 2025
412b55c
fix filtering
Joren-vanGoethem Feb 24, 2025
54973d0
fix date filter logic
Joren-vanGoethem Feb 24, 2025
4567a1a
update date filter
Joren-vanGoethem Feb 24, 2025
2efc587
new code, more linq, less custom sql
Joren-vanGoethem Feb 24, 2025
a8d37e2
fix import, update seems buggy
Joren-vanGoethem Feb 26, 2025
d39d413
add todo
Joren-vanGoethem Feb 26, 2025
a84fe86
update migrations
Joren-vanGoethem Feb 26, 2025
5972507
Merge branch 'dev' into feature/GB-163-location-multi-language
Joren-vanGoethem Feb 26, 2025
2acbe2c
push fix
Joren-vanGoethem Feb 26, 2025
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -515,3 +515,5 @@ build/

# IDE
frontend/.env

.qodo
11 changes: 7 additions & 4 deletions Api/Controllers/Events/CreateEvent/CreateEventHandler.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using System.Globalization;
using Api.Infrastructure.Extensions;
using Domain;
using Domain.Category.repository;
using Domain.Coordinates;
using Domain.Events;
using Domain.Events.repository;
using Domain.Locations;
using Domain.Locations.repository;
using Domain.Urls;
using Shared.Api;
Expand All @@ -17,12 +17,15 @@ public class CreateEventHandler : ApiRequestHandler<CreateEventQuery, CreateEven
private readonly IEventRepository _eventRepository;
private readonly ILocationRepository _locationRepository;
private readonly ICategoryRepository _categoryRepository;
private readonly CultureInfo _culture;

public CreateEventHandler(IEventRepository eventRepository, ILocationRepository locationRepository, ICategoryRepository categoryRepository)
public CreateEventHandler(IEventRepository eventRepository, ILocationRepository locationRepository,
ICategoryRepository categoryRepository)
{
_eventRepository = eventRepository;
_locationRepository = locationRepository;
_categoryRepository = categoryRepository;
_culture = CultureInfo.CurrentCulture;
}

public override async Task<CreateEventResponse> Handle(CreateEventQuery request, CancellationToken cancellationToken)
Expand All @@ -38,8 +41,8 @@ public override async Task<CreateEventResponse> Handle(CreateEventQuery request,
throw new ProblemDetailsException(TranslationKeys.LocationNotFound);
var categories = _categoryRepository.GetByIds(request.CategoryIds).ToList();

var (eventResult, @event) = Event.Create(request.EventId, request.TerminId, request.Title, request.Description, request.StartDate, request.EndDate,
location, coords, urls, categories);
var (eventResult, @event) = Event.Create(request.EventId, request.TerminId, request.Title, request.Description,
request.StartDate, request.EndDate, location, coords, urls, categories, _culture);
eventResult.ThrowIfFailure();

await _eventRepository.SaveAsync(@event);
Expand Down
10 changes: 7 additions & 3 deletions Api/Controllers/Events/GetAllEvents/GetAllEventsHandler.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
using System.Globalization;
using Api.Controllers.Events.Shared;
using Api.Shared;
using Domain.Events.repository;
using Shared.Api;
using Api.Shared;

namespace Api.Controllers.Events.GetAllEvents;

public class GetAllEventsHandler : ApiPagedRequestHandler<GetAllEventsQuery, GetAllEventsResponse, EventResponse>
{
private readonly IEventRepository _eventRepository;
private readonly CultureInfo _culture;

public GetAllEventsHandler(IEventRepository eventRepository)
{
_eventRepository = eventRepository;
_culture = CultureInfo.CurrentCulture;
}

public override async Task<GetAllEventsResponse> Handle(GetAllEventsQuery request, CancellationToken
cancellationToken)
{

var filter = new EventFilterCriteria
{
TitleQuery = request.TitleSearch,
Expand All @@ -28,15 +32,15 @@ public override async Task<GetAllEventsResponse> Handle(GetAllEventsQuery reques
SortDirection = request.SortDirection?.MapToDomain(),
};

var pagedResult = await _eventRepository.GetAllEventsPaged(request, filter);
var pagedResult = await _eventRepository.GetAllEventsPaged(request, filter, _culture);

return new GetAllEventsResponse
{
PageNumber = pagedResult.PageNumber,
PageSize = pagedResult.PageSize,
TotalCount = pagedResult.TotalCount,
PageCount = pagedResult.PageCount,
Results = pagedResult.Results.Select(EventResponse.Map)
Results = pagedResult.Results.Select(e => EventResponse.Map(e, _culture))
};
}
}
16 changes: 12 additions & 4 deletions Api/Controllers/Events/Shared/EventResponse.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
using System.Globalization;
using Api.Controllers.Categories.Shared;
using Api.Controllers.Locations.Shared;
using Api.Infrastructure.Translations;
using Domain;
using Domain.Coordinates;
using Domain.Events;
using Domain.Urls;
using Shared.Api;

namespace Api.Controllers.Events.Shared;

Expand All @@ -20,18 +24,22 @@ public struct EventResponse
public required IEnumerable<UrlResponse> Urls { get; set; }
public required IEnumerable<CategoryResponse> Categories { get; set; }

public static EventResponse Map(Event @event)
public static EventResponse Map(Event @event, CultureInfo cultureInfo)
{
var i18NData = @event.Translations.GetTranslation(cultureInfo);
if (i18NData is null)
throw new ProblemDetailsException(TranslationKeys.NoValidTranslationsFound);

return new EventResponse()
{
Id = @event.Id,
EventId = @event.EventId,
TerminId = @event.TerminId,
Title = @event.Title,
Description = @event.Description,
Title = i18NData.Title,
Description = i18NData.Description,
StartDate = @event.StartDate,
EndDate = @event.EndDate,
Location = LocationResponse.Map(@event.Location),
Location = LocationResponse.Map(@event.Location, cultureInfo),
Coordinates = @event.Coordinates is not null ? CoordinatesResponse.Map(@event.Coordinates) : null,
Urls = @event.Urls.Select(UrlResponse.Map),
Categories = @event.Categories.Select(CategoryResponse.Map)
Expand Down
13 changes: 10 additions & 3 deletions Api/Controllers/Events/UpdateEvent/UpdateEventHandler.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using Api.Infrastructure.Extensions;
using Api.Infrastructure.Translations;
using Domain;
using Domain.Category.repository;
using Domain.Coordinates;
using Domain.Events;
using Domain.Events.repository;
using Domain.Locations.repository;
using Domain.Urls;
Expand All @@ -15,13 +17,15 @@ public class UpdateEventHandler : ApiRequestHandler<UpdateEventQuery, UpdateEven
private readonly IEventRepository _eventRepository;
private readonly ILocationRepository _locationRepository;
private readonly ICategoryRepository _categoryRepository;
private readonly ICultureProvider _cultureProvider;

public UpdateEventHandler(IEventRepository eventRepository, ICategoryRepository categoryRepository,
ILocationRepository locationRepository)
ILocationRepository locationRepository, ICultureProvider cultureProvider)
{
_eventRepository = eventRepository;
_categoryRepository = categoryRepository;
_locationRepository = locationRepository;
_cultureProvider = cultureProvider;
}

public override async Task<UpdateEventResponse> Handle(UpdateEventQuery request, CancellationToken cancellationToken)
Expand All @@ -44,8 +48,11 @@ public override async Task<UpdateEventResponse> Handle(UpdateEventQuery request,
if (categories is null)
throw new ProblemDetailsException(TranslationKeys.CategoryNotFound);

var updateResult = eventToUpdate.Update(request.Title, request.Description, request.StartDate, request.EndDate, coords, location,
categories, urls);
var (i18NResult, i18NData) = EventI18NData.Create(request.Title, request.Description);
i18NResult.ThrowIfFailure();

var updateResult = eventToUpdate.Update(i18NData, request.StartDate, request.EndDate, coords, location, categories,
urls, _cultureProvider.GetCulture());

updateResult.ThrowIfFailure();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Globalization;
using Api.Controllers.Locations.Shared;
using Domain.Locations.repository;
using Shared.Api;
Expand All @@ -7,10 +8,12 @@ namespace Api.Controllers.Locations.GetAllLocations;
public class GetAllLocationsHandler : ApiRequestHandler<GetAllLocationsQuery, GetAllLocationsResponse>
{
private readonly ILocationRepository _locationRepository;
private readonly CultureInfo _culture;

public GetAllLocationsHandler(ILocationRepository locationRepository)
{
_locationRepository = locationRepository;
_culture = CultureInfo.CurrentCulture;
}

public override async Task<GetAllLocationsResponse> Handle(GetAllLocationsQuery request, CancellationToken
Expand All @@ -20,7 +23,7 @@ public override async Task<GetAllLocationsResponse> Handle(GetAllLocationsQuery

return new GetAllLocationsResponse()
{
Locations = locations.Select(LocationResponse.Map).ToList()
Locations = locations.Select(l => LocationResponse.Map(l, _culture)).ToList()
};
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Globalization;
using Api.Infrastructure.Extensions;
using Domain.Locations;
using Domain.Locations.repository;
Expand All @@ -8,21 +9,23 @@ namespace Api.Controllers.Locations.GetOrCreatelocation;
public class GetOrCreateLocationHandler : ApiRequestHandler<GetOrCreateLocationQuery, GetOrCreateLocationResponse>
{
private readonly ILocationRepository _locationRepository;
private readonly CultureInfo _culture;

public GetOrCreateLocationHandler(ILocationRepository locationRepository)
{
_locationRepository = locationRepository;
_culture = CultureInfo.CurrentCulture;
}

public override Task<GetOrCreateLocationResponse> Handle(GetOrCreateLocationQuery request,
public override async Task<GetOrCreateLocationResponse> Handle(GetOrCreateLocationQuery request,
CancellationToken cancellationToken)
{
Guid locationId;
var (locationResult, tempLocation) = Location.Create(request.Name, request.City, request.Street, request.TelephoneNumber, request
.Fax, request.Email, request.Website, request.Zip);
.Fax, request.Email, request.Website, request.Zip, _culture);
locationResult.ThrowIfFailure();

var foundLocation = _locationRepository.Find(tempLocation);
var foundLocation = await _locationRepository.FindByName(request.Name, _culture);
if (foundLocation is null)
{
_locationRepository.Save(tempLocation);
Expand All @@ -33,9 +36,9 @@ public override Task<GetOrCreateLocationResponse> Handle(GetOrCreateLocationQuer
locationId = foundLocation.Id;
}

return Task.FromResult(new GetOrCreateLocationResponse()
return new GetOrCreateLocationResponse()
{
LocationId = locationId,
});
};
}
}
12 changes: 10 additions & 2 deletions Api/Controllers/Locations/Shared/LocationResponse.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
using System.Globalization;
using Api.Infrastructure.Translations;
using Domain;
using Domain.Locations;
using Shared.Api;

namespace Api.Controllers.Locations.Shared;

Expand All @@ -8,12 +12,16 @@ public struct LocationResponse
public required string Name { get; set; }
public string? City { get; set; }

public static LocationResponse Map(Location location)
public static LocationResponse Map(Location location, CultureInfo cultureInfo)
{
var i18NData = location.Translations.GetTranslation(cultureInfo);
if (i18NData is null)
throw new ProblemDetailsException(TranslationKeys.NoValidTranslationsFound);

return new LocationResponse
{
Id = location.Id,
Name = location.Name,
Name = i18NData.Name,
City = location.City
};
}
Expand Down
5 changes: 4 additions & 1 deletion Api/Controllers/Pages/GetAllPages/GetAllPagesHandler.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Globalization;
using Api.Controllers.Pages.Shared;
using Domain.Pages.repository;
using Shared.Api;
Expand All @@ -7,10 +8,12 @@ namespace Api.Controllers.Pages.GetAllPages;
public class GetAllPagesHandler : ApiRequestHandler<GetAllPagesQuery, GetAllPagesResponse>
{
private readonly IPageRepository _pageRepository;
private readonly CultureInfo _culture;

public GetAllPagesHandler(IPageRepository pageRepository)
{
_pageRepository = pageRepository;
_culture = CultureInfo.CurrentCulture;
}

public override async Task<GetAllPagesResponse> Handle(GetAllPagesQuery request, CancellationToken
Expand All @@ -20,7 +23,7 @@ public override async Task<GetAllPagesResponse> Handle(GetAllPagesQuery request,

return new GetAllPagesResponse
{
Pages = pages.Select(PageResponse.Map).ToList()
Pages = pages.Select(p => PageResponse.Map(p, _culture)).ToList()
};
}
}
5 changes: 4 additions & 1 deletion Api/Controllers/Pages/GetPage/GetPageHandler.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Globalization;
using Api.Controllers.Pages.Shared;
using Domain;
using Domain.Pages.repository;
Expand All @@ -8,10 +9,12 @@ namespace Api.Controllers.Pages.GetPage;
public class GetPageHandler : ApiRequestHandler<GetPageQuery, PageResponse>
{
private readonly IPageRepository _pageRepository;
private readonly CultureInfo _culture;

public GetPageHandler(IPageRepository pageRepository)
{
_pageRepository = pageRepository;
_culture = CultureInfo.CurrentCulture;
}

public override async Task<PageResponse> Handle(GetPageQuery request, CancellationToken
Expand All @@ -22,6 +25,6 @@ public override async Task<PageResponse> Handle(GetPageQuery request, Cancellati
if (page is null)
throw new ProblemDetailsException(TranslationKeys.PageNotFound);

return PageResponse.Map(page);
return PageResponse.Map(page, _culture);
}
}
5 changes: 3 additions & 2 deletions Api/Controllers/Pages/Shared/PageResponse.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Globalization;
using Api.Infrastructure.Translations;
using Domain;
using Domain.Pages;
Expand All @@ -11,9 +12,9 @@ public struct PageResponse
public required string Title { get; set; }
public required string Description { get; set; }

public static PageResponse Map(Page page)
public static PageResponse Map(Page page, CultureInfo cultureInfo)
{
var i18NData = page.Translations.GetTranslation();
var i18NData = page.Translations.GetTranslation(cultureInfo);
if (i18NData is null)
throw new ProblemDetailsException(TranslationKeys.NoValidTranslationsFound);

Expand Down
7 changes: 5 additions & 2 deletions Api/Controllers/Pages/UpdatePage/UpdatePageHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ namespace Api.Controllers.Pages.UpdatePage;
public class UpdatePageHandler : ApiRequestHandler<UpdatePageQuery, UpdatePageResponse>
{
private readonly IPageRepository _pageRepository;
private readonly CultureInfo _culture;

public UpdatePageHandler(IPageRepository pageRepository)
{
_pageRepository = pageRepository;
_culture = CultureInfo.CurrentCulture;

}

public override async Task<UpdatePageResponse> Handle(UpdatePageQuery request, CancellationToken cancellationToken)
Expand All @@ -23,14 +26,14 @@ public override async Task<UpdatePageResponse> Handle(UpdatePageQuery request, C
var (pageResult, newPage) = Page.Create(request.Id);
pageResult.ThrowIfFailure();

var updateTranslation = newPage.UpdateTranslation(CultureInfo.CurrentCulture.TwoLetterISOLanguageName, request.Title, request.Description);
var updateTranslation = newPage.UpdateTranslation(request.Title, request.Description, _culture);
updateTranslation.ThrowIfFailure();

await _pageRepository.SaveAsync(newPage);
}
else
{
page.UpdateTranslation(CultureInfo.CurrentCulture.TwoLetterISOLanguageName, request.Title, request.Description);
page.UpdateTranslation(request.Title, request.Description, _culture);
}

return new UpdatePageResponse();
Expand Down
16 changes: 16 additions & 0 deletions Api/Infrastructure/Translations/CultureProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.Globalization;

namespace Api.Infrastructure.Translations;

public interface ICultureProvider
{
CultureInfo GetCulture();
}

public class CultureProvider : ICultureProvider
{
public CultureInfo GetCulture()
{
return CultureInfo.CurrentCulture;
}
}
Loading
Loading