2026-05-25 06:38:16 +02:00
|
|
|
using System.Text.Json;
|
|
|
|
|
|
|
|
|
|
namespace AuthorBuddy.Web.Services;
|
|
|
|
|
|
|
|
|
|
public class LocalizationService : ILocalizationService
|
|
|
|
|
{
|
|
|
|
|
private readonly ISettingsService _settingsService;
|
|
|
|
|
private Dictionary<string, string> _translations = new();
|
|
|
|
|
private string _language = "de";
|
|
|
|
|
|
|
|
|
|
public string CurrentLanguage => _language;
|
|
|
|
|
|
|
|
|
|
public LocalizationService(ISettingsService settingsService)
|
|
|
|
|
{
|
|
|
|
|
_settingsService = settingsService;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task InitAsync()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
_language = await _settingsService.GetLanguageAsync() ?? "de";
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
_language = "de";
|
|
|
|
|
}
|
|
|
|
|
await LoadLanguageInternalAsync(_language);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string Get(string key)
|
|
|
|
|
{
|
|
|
|
|
if (_translations.TryGetValue(key, out var value))
|
|
|
|
|
return value;
|
|
|
|
|
return Fallback(key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string this[string key] => Get(key);
|
|
|
|
|
|
|
|
|
|
public async Task SetLanguageAsync(string language)
|
|
|
|
|
{
|
|
|
|
|
_language = language;
|
|
|
|
|
await LoadLanguageInternalAsync(language);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task LoadLanguageInternalAsync(string language)
|
|
|
|
|
{
|
|
|
|
|
var searched = new List<string>();
|
|
|
|
|
|
|
|
|
|
var paths = new[]
|
|
|
|
|
{
|
|
|
|
|
Path.Combine(AppContext.BaseDirectory, "Resources", $"{language}.json"),
|
|
|
|
|
Path.Combine(Directory.GetCurrentDirectory(), "Resources", $"{language}.json"),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
searched.AddRange(paths);
|
|
|
|
|
|
|
|
|
|
foreach (var path in paths)
|
|
|
|
|
{
|
|
|
|
|
if (File.Exists(path))
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var json = await File.ReadAllTextAsync(path);
|
|
|
|
|
var dict = JsonSerializer.Deserialize<Dictionary<string, string>>(json);
|
|
|
|
|
if (dict != null && dict.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
_translations = dict;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
// try next path
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_translations = new();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string Fallback(string key)
|
|
|
|
|
{
|
|
|
|
|
return key switch
|
|
|
|
|
{
|
|
|
|
|
"common.status.ready" => "Bereit",
|
|
|
|
|
"common.cancel" => "Abbrechen",
|
|
|
|
|
"common.error" => "Fehler:",
|
|
|
|
|
"common.copy" => "Kopieren",
|
|
|
|
|
"common.status.error" => "Fehler",
|
|
|
|
|
"page.title.login" => "Anmelden - Author Buddy",
|
|
|
|
|
"page.title.register" => "Registrieren - Author Buddy",
|
|
|
|
|
"page.title.setup2fa" => "2FA einrichten - Author Buddy",
|
|
|
|
|
"page.title.settings" => "Einstellungen",
|
|
|
|
|
"page.title.editor" => "Editor - Author Buddy",
|
|
|
|
|
"page.title.assistant" => "Assistent - Author Buddy",
|
|
|
|
|
"page.title.models" => "Modelle - Author Buddy",
|
|
|
|
|
"page.title.home" => "Dashboard - Author Buddy",
|
|
|
|
|
"page.title.error" => "Fehler",
|
|
|
|
|
"page.title.not_found" => "Seite nicht gefunden",
|
|
|
|
|
"login.heading" => "Anmelden",
|
|
|
|
|
"login.label.username" => "Benutzername",
|
|
|
|
|
"login.label.password" => "Passwort",
|
|
|
|
|
"login.button.submit" => "Anmelden",
|
|
|
|
|
"login.link.register" => "Registrieren",
|
|
|
|
|
"login.2fa.instruction" => "Gib deinen 2FA-Code ein:",
|
|
|
|
|
"login.2fa.label.code" => "2FA-Code",
|
|
|
|
|
"login.2fa.button.verify" => "Bestätigen",
|
|
|
|
|
"login.error.empty_fields" => "Bitte Benutzername und Passwort eingeben.",
|
|
|
|
|
"login.error.invalid_credentials" => "Ungültige Anmeldedaten.",
|
|
|
|
|
"login.2fa.error.invalid_code" => "Der 2FA-Code muss 6-stellig sein.",
|
|
|
|
|
"login.2fa.error.code_failed" => "Ungültiger 2FA-Code.",
|
|
|
|
|
"nav.user.logged_in_as" => "Angemeldet als",
|
|
|
|
|
"nav.user.manage_2fa" => "2FA verwalten",
|
|
|
|
|
"nav.user.logout" => "Abmelden",
|
2026-05-31 19:31:27 +02:00
|
|
|
"assistant.exposee.context" => "Berücksichtige folgendes Exposé der Geschichte:",
|
2026-05-25 06:38:16 +02:00
|
|
|
_ => key,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|