Add translation support to website, read user's language from settings

This commit is contained in:
jvyden 2022-04-14 16:24:17 -04:00
commit 3e18d79fa5
No known key found for this signature in database
GPG key ID: 18BCF2BE0262B278
8 changed files with 103 additions and 33 deletions

View file

@ -15,15 +15,12 @@ public static class LocalizationManager
Console.WriteLine($"Attempting to load '{key}' for '{language}'");
#endif
string resourceBasename;
if (language == defaultLang)
{
resourceBasename = $"{namespaceStr}.{translationArea.ToString()}";
}
else
{
resourceBasename = $"{namespaceStr}.{translationArea.ToString()}.lang-{language}";
}
string resourceBasename = $"{namespaceStr}.{translationArea.ToString()}";
// We don't have an en-US .resx, so if we aren't using en-US then we need to add the appropriate language.
// Otherwise, keep it to the normal .resx file
// e.g. BaseLayout.resx as opposed to BaseLayout.lang-da-DK.resx.
if (language != defaultLang) resourceBasename += $".lang-{language}";
ResourceManager resourceManager = new(resourceBasename, Assembly.GetExecutingAssembly());
@ -39,12 +36,12 @@ public static class LocalizationManager
return localizedString;
}
public static IEnumerable<string> GetAvailableLanguages(TranslationAreas translationArea)
// This is a bit scuffed, but it will work for what I need it to do.
public static IEnumerable<string> GetAvailableLanguages()
{
string area = translationArea.ToString();
string area = TranslationAreas.BaseLayout.ToString();
// scuffed but it will work for now
List<string> langs = Assembly.GetExecutingAssembly()
List<string> languages = Assembly.GetExecutingAssembly()
.GetManifestResourceNames()
.Where(r => r.StartsWith($"{namespaceStr}.{area}"))
.Select(r => r.Substring(r.IndexOf(area), r.Length - r.IndexOf(area)).Substring(area.Length + 1))
@ -53,8 +50,8 @@ public static class LocalizationManager
.Where(r => r != "resources")
.ToList();
langs.Add(defaultLang);
languages.Add(defaultLang);
return langs;
return languages;
}
}

View file

@ -14,7 +14,7 @@ public static class Program
Console.Write('\n');
foreach (string language in LocalizationManager.GetAvailableLanguages(TranslationAreas.BaseLayout))
foreach (string language in LocalizationManager.GetAvailableLanguages())
{
Console.WriteLine(LocalizationManager.GetLocalizedString(TranslationAreas.BaseLayout, language, "header_home"));
}

View file

@ -0,0 +1,11 @@
namespace LBPUnion.ProjectLighthouse.Localization.StringLists;
public static class BaseLayoutStrings
{
public static readonly TranslatableString HeaderHome = create("header_home");
public static readonly TranslatableString HeaderUsers = create("header_users");
public static readonly TranslatableString HeaderPhotos = create("header_photos");
public static readonly TranslatableString HeaderSlots = create("header_slots");
private static TranslatableString create(string key) => new(TranslationAreas.BaseLayout, key);
}

View file

@ -0,0 +1,21 @@
namespace LBPUnion.ProjectLighthouse.Localization;
public class TranslatableString
{
public TranslatableString(TranslationAreas area, string key)
{
this.Key = key;
this.Area = area;
}
public string Key { get; init; }
public TranslationAreas Area { get; init; }
public string Translate(string language) => LocalizationManager.GetLocalizedString(this.Area, language, this.Key);
[Obsolete("Do not translate by using ToString. Use TranslatableString.Translate().", true)]
public override string ToString() => "NOT TRANSLATED CORRECTLY!";
[Obsolete("Do not translate by using ToString. Use TranslatableString.Translate().", true)]
public static implicit operator string(TranslatableString _) => "NOT TRANSLATED CORRECTLY!";
}

View file

@ -1,5 +1,6 @@
@using LBPUnion.ProjectLighthouse.Helpers
@using LBPUnion.ProjectLighthouse.Helpers.Extensions
@using LBPUnion.ProjectLighthouse.Localization
@using LBPUnion.ProjectLighthouse.Types
@using LBPUnion.ProjectLighthouse.Types.Settings
@model LBPUnion.ProjectLighthouse.Pages.Layouts.BaseLayout
@ -7,21 +8,21 @@
@{
if (Model!.User == null)
{
Model.NavigationItemsRight.Add(new PageNavigationItem("Login / Register", "/login", "sign in"));
Model.NavigationItemsRight.Add(new PageNavigationItem(new TranslatableString(TranslationAreas.BaseLayout, "Login / Register"), "/login", "sign in"));
}
else
{
if (ServerSettings.Instance.UseExternalAuth)
{
Model.NavigationItems.Add(new PageNavigationItem("Authentication", "/authentication", "key"));
Model.NavigationItems.Add(new PageNavigationItem(new TranslatableString(TranslationAreas.BaseLayout, "Authentication"), "/authentication", "key"));
}
Model.NavigationItemsRight.Add(new PageNavigationItem("Profile", "/user/" + Model.User.UserId, "user alternate"));
Model.NavigationItemsRight.Add(new PageNavigationItem(new TranslatableString(TranslationAreas.BaseLayout, "Profile"), "/user/" + Model.User.UserId, "user alternate"));
@if (Model.User.IsAdmin)
{
Model.NavigationItemsRight.Add(new PageNavigationItem("Admin Panel", "/admin", "cogs"));
Model.NavigationItemsRight.Add(new PageNavigationItem(new TranslatableString(TranslationAreas.BaseLayout, "Admin Panel"), "/admin", "cogs"));
}
Model.NavigationItemsRight.Add(new PageNavigationItem("Log out", "/logout", "user alternate slash")); // should always be last
Model.NavigationItemsRight.Add(new PageNavigationItem(new TranslatableString(TranslationAreas.BaseLayout, "Log out"), "/logout", "user alternate slash")); // should always be last
}
Model.IsMobile = Model.Request.IsMobile();
@ -93,7 +94,7 @@
@if (!Model.IsMobile)
{
@navigationItem.Name
@Model.Translate(navigationItem.Name)
}
</a>
}
@ -108,7 +109,7 @@
@if (!Model.IsMobile)
{
@navigationItem.Name
@Model.Translate(navigationItem.Name)
}
</a>
}

View file

@ -1,22 +1,19 @@
#nullable enable
using System;
using System.Collections.Generic;
using LBPUnion.ProjectLighthouse.Localization;
using LBPUnion.ProjectLighthouse.Localization.StringLists;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace LBPUnion.ProjectLighthouse.Pages.Layouts;
public class BaseLayout : PageModel
{
public readonly Database Database;
public readonly List<PageNavigationItem> NavigationItems = new()
{
new PageNavigationItem("Home", "/", "home"),
new PageNavigationItem("Users", "/users/0", "user friends"),
new PageNavigationItem("Photos", "/photos/0", "camera"),
new PageNavigationItem("Levels", "/slots/0", "certificate"),
};
public readonly List<PageNavigationItem> NavigationItems = new();
public readonly List<PageNavigationItem> NavigationItemsRight = new();
public string Description = string.Empty;
@ -31,6 +28,11 @@ public class BaseLayout : PageModel
public BaseLayout(Database database)
{
this.Database = database;
this.NavigationItems.Add(new PageNavigationItem(BaseLayoutStrings.HeaderHome, "/", "home"));
this.NavigationItems.Add(new PageNavigationItem(BaseLayoutStrings.HeaderUsers, "/users/0", "user friends"));
this.NavigationItems.Add(new PageNavigationItem(BaseLayoutStrings.HeaderPhotos, "/photos/0", "camera"));
this.NavigationItems.Add(new PageNavigationItem(BaseLayoutStrings.HeaderSlots, "/slots/0", "certificate"));
}
public new User? User {
@ -41,4 +43,20 @@ public class BaseLayout : PageModel
}
set => this.user = value;
}
public string Translate(TranslatableString translatableString)
{
string lang;
IRequestCultureFeature? requestCulture = Request.HttpContext.Features.Get<IRequestCultureFeature>();
if (requestCulture == null) lang = "en-UD"; // TODO: change to en-US when i can verify this is working
else
{
lang = requestCulture.RequestCulture.UICulture.Name;
}
Console.WriteLine(lang);
return translatableString.Translate(lang);
}
}

View file

@ -1,9 +1,13 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using Kettu;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Localization;
using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types;
@ -12,6 +16,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Localization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
@ -85,6 +90,19 @@ public class Startup
}
);
services.Configure<RequestLocalizationOptions>
(
config =>
{
List<CultureInfo> languages = LocalizationManager.GetAvailableLanguages().Select(l => new CultureInfo(l)).ToList();
config.DefaultRequestCulture = new RequestCulture(new CultureInfo("en-US"));
config.SupportedCultures = languages;
config.SupportedUICultures = languages;
}
);
#if DEBUG
services.AddSingleton<IHostLifetime, DebugWarmupLifetime>();
#else
@ -123,6 +141,8 @@ public class Startup
}
);
app.UseRequestLocalization();
// Logs every request and the response to it
// Example: "200, 13ms: GET /LITTLEBIGPLANETPS3_XML/news"
// Example: "404, 127ms: GET /asdasd?query=osucookiezi727ppbluezenithtopplayhdhr"

View file

@ -1,16 +1,18 @@
using LBPUnion.ProjectLighthouse.Localization;
#nullable enable
namespace LBPUnion.ProjectLighthouse.Types;
public class PageNavigationItem
{
public PageNavigationItem(string name, string url, string? icon = null)
public PageNavigationItem(TranslatableString name, string url, string? icon = null)
{
this.Name = name;
this.Url = url;
this.Icon = icon;
}
public string Name { get; set; }
public TranslatableString Name { get; set; }
public string Url { get; set; }
public string? Icon { get; set; }
}