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

View file

@ -14,7 +14,7 @@ public static class Program
Console.Write('\n'); 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")); 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
@using LBPUnion.ProjectLighthouse.Helpers.Extensions @using LBPUnion.ProjectLighthouse.Helpers.Extensions
@using LBPUnion.ProjectLighthouse.Localization
@using LBPUnion.ProjectLighthouse.Types @using LBPUnion.ProjectLighthouse.Types
@using LBPUnion.ProjectLighthouse.Types.Settings @using LBPUnion.ProjectLighthouse.Types.Settings
@model LBPUnion.ProjectLighthouse.Pages.Layouts.BaseLayout @model LBPUnion.ProjectLighthouse.Pages.Layouts.BaseLayout
@ -7,21 +8,21 @@
@{ @{
if (Model!.User == null) 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 else
{ {
if (ServerSettings.Instance.UseExternalAuth) 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) @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(); Model.IsMobile = Model.Request.IsMobile();
@ -93,7 +94,7 @@
@if (!Model.IsMobile) @if (!Model.IsMobile)
{ {
@navigationItem.Name @Model.Translate(navigationItem.Name)
} }
</a> </a>
} }
@ -108,7 +109,7 @@
@if (!Model.IsMobile) @if (!Model.IsMobile)
{ {
@navigationItem.Name @Model.Translate(navigationItem.Name)
} }
</a> </a>
} }

View file

@ -1,22 +1,19 @@
#nullable enable #nullable enable
using System;
using System.Collections.Generic; using System.Collections.Generic;
using LBPUnion.ProjectLighthouse.Localization;
using LBPUnion.ProjectLighthouse.Localization.StringLists;
using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.RazorPages;
namespace LBPUnion.ProjectLighthouse.Pages.Layouts; namespace LBPUnion.ProjectLighthouse.Pages.Layouts;
public class BaseLayout : PageModel public class BaseLayout : PageModel
{ {
public readonly Database Database; public readonly Database Database;
public readonly List<PageNavigationItem> NavigationItems = new() 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> NavigationItemsRight = new(); public readonly List<PageNavigationItem> NavigationItemsRight = new();
public string Description = string.Empty; public string Description = string.Empty;
@ -31,6 +28,11 @@ public class BaseLayout : PageModel
public BaseLayout(Database database) public BaseLayout(Database database)
{ {
this.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 { public new User? User {
@ -41,4 +43,20 @@ public class BaseLayout : PageModel
} }
set => this.user = value; 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;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization;
using System.IO; using System.IO;
using System.Linq;
using System.Reflection; using System.Reflection;
using Kettu; using Kettu;
using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Localization;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Serialization; using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types;
@ -12,6 +16,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Localization;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; 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 #if DEBUG
services.AddSingleton<IHostLifetime, DebugWarmupLifetime>(); services.AddSingleton<IHostLifetime, DebugWarmupLifetime>();
#else #else
@ -123,6 +141,8 @@ public class Startup
} }
); );
app.UseRequestLocalization();
// Logs every request and the response to it // Logs every request and the response to it
// Example: "200, 13ms: GET /LITTLEBIGPLANETPS3_XML/news" // Example: "200, 13ms: GET /LITTLEBIGPLANETPS3_XML/news"
// Example: "404, 127ms: GET /asdasd?query=osucookiezi727ppbluezenithtopplayhdhr" // Example: "404, 127ms: GET /asdasd?query=osucookiezi727ppbluezenithtopplayhdhr"

View file

@ -1,16 +1,18 @@
using LBPUnion.ProjectLighthouse.Localization;
#nullable enable #nullable enable
namespace LBPUnion.ProjectLighthouse.Types; namespace LBPUnion.ProjectLighthouse.Types;
public class PageNavigationItem 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.Name = name;
this.Url = url; this.Url = url;
this.Icon = icon; this.Icon = icon;
} }
public string Name { get; set; } public TranslatableString Name { get; set; }
public string Url { get; set; } public string Url { get; set; }
public string? Icon { get; set; } public string? Icon { get; set; }
} }