mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 09:48:26 -04:00
Killed history
This commit is contained in:
16
NadekoBot.Core/Services/strings/IBotStrings.cs
Normal file
16
NadekoBot.Core/Services/strings/IBotStrings.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System.Globalization;
|
||||
|
||||
namespace NadekoBot.Core.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines methods to retrieve and reload bot strings
|
||||
/// </summary>
|
||||
public interface IBotStrings
|
||||
{
|
||||
string GetText(string key, ulong? guildId = null, params object[] data);
|
||||
string GetText(string key, CultureInfo locale, params object[] data);
|
||||
void Reload();
|
||||
CommandStrings GetCommandStrings(string commandName, ulong? guildId = null);
|
||||
CommandStrings GetCommandStrings(string commandName, CultureInfo cultureInfo);
|
||||
}
|
||||
}
|
28
NadekoBot.Core/Services/strings/IBotStringsProvider.cs
Normal file
28
NadekoBot.Core/Services/strings/IBotStringsProvider.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
namespace NadekoBot.Core.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Implemented by classes which provide localized strings in their own ways
|
||||
/// </summary>
|
||||
public interface IBotStringsProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets localized string
|
||||
/// </summary>
|
||||
/// <param name="localeName">Language name</param>
|
||||
/// <param name="key">String key</param>
|
||||
/// <returns>Localized string</returns>
|
||||
string GetText(string localeName, string key);
|
||||
|
||||
/// <summary>
|
||||
/// Reloads string cache
|
||||
/// </summary>
|
||||
void Reload();
|
||||
|
||||
/// <summary>
|
||||
/// Gets command arg examples and description
|
||||
/// </summary>
|
||||
/// <param name="localeName">Language name</param>
|
||||
/// <param name="commandName">Command name</param>
|
||||
CommandStrings GetCommandStrings(string localeName, string commandName);
|
||||
}
|
||||
}
|
18
NadekoBot.Core/Services/strings/IStringsSource.cs
Normal file
18
NadekoBot.Core/Services/strings/IStringsSource.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NadekoBot.Core.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Basic interface used for classes implementing strings loading mechanism
|
||||
/// </summary>
|
||||
public interface IStringsSource
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets all response strings
|
||||
/// </summary>
|
||||
/// <returns>Dictionary(localename, Dictionary(key, response))</returns>
|
||||
Dictionary<string, Dictionary<string, string>> GetResponseStrings();
|
||||
|
||||
Dictionary<string, Dictionary<string, CommandStrings>> GetCommandStrings();
|
||||
}
|
||||
}
|
107
NadekoBot.Core/Services/strings/impl/BotStrings.cs
Normal file
107
NadekoBot.Core/Services/strings/impl/BotStrings.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Serilog;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace NadekoBot.Core.Services
|
||||
{
|
||||
public class BotStrings : IBotStrings
|
||||
{
|
||||
/// <summary>
|
||||
/// Used as failsafe in case response key doesn't exist in the selected or default language.
|
||||
/// </summary>
|
||||
private readonly CultureInfo _usCultureInfo = new CultureInfo("en-US");
|
||||
private readonly ILocalization _localization;
|
||||
private readonly IBotStringsProvider _stringsProvider;
|
||||
|
||||
public BotStrings(ILocalization loc, IBotStringsProvider stringsProvider)
|
||||
{
|
||||
_localization = loc;
|
||||
_stringsProvider = stringsProvider;
|
||||
}
|
||||
|
||||
private string GetString(string key, CultureInfo cultureInfo)
|
||||
=> _stringsProvider.GetText(cultureInfo.Name, key);
|
||||
|
||||
public string GetText(string key, ulong? guildId = null, params object[] data)
|
||||
=> GetText(key, _localization.GetCultureInfo(guildId), data);
|
||||
|
||||
public string GetText(string key, CultureInfo cultureInfo)
|
||||
{
|
||||
var text = GetString(key, cultureInfo);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
Log.Warning("'{Key}' key is missing from '{LanguageName}' response strings. You may ignore this message", key, cultureInfo.Name);
|
||||
text = GetString(key, _usCultureInfo) ?? $"Error: dkey {key} not found!";
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
return
|
||||
$"I can't tell you if the command is executed, because there was an error printing out the response." +
|
||||
$" Key '{key}' is missing from resources. You may ignore this message.";
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
public string GetText(string key, CultureInfo cultureInfo, params object[] data)
|
||||
{
|
||||
try
|
||||
{
|
||||
return string.Format(GetText(key, cultureInfo), data);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
Log.Warning(" Key '{Key}' is not properly formatted in '{LanguageName}' response strings. Please report this", key, cultureInfo.Name);
|
||||
if (cultureInfo.Name != _usCultureInfo.Name)
|
||||
return GetText(key, _usCultureInfo, data);
|
||||
return
|
||||
$"I can't tell you if the command is executed, because there was an error printing out the response.\n" +
|
||||
$"Key '{key}' is not properly formatted. Please report this.";
|
||||
}
|
||||
}
|
||||
|
||||
public CommandStrings GetCommandStrings(string commandName, ulong? guildId = null)
|
||||
=> GetCommandStrings(commandName, _localization.GetCultureInfo(guildId));
|
||||
|
||||
public CommandStrings GetCommandStrings(string commandName, CultureInfo cultureInfo)
|
||||
{
|
||||
var cmdStrings = _stringsProvider.GetCommandStrings(cultureInfo.Name, commandName);
|
||||
if (cmdStrings is null)
|
||||
{
|
||||
if (cultureInfo.Name == _usCultureInfo.Name)
|
||||
{
|
||||
Log.Warning("'{CommandName}' doesn't exist in 'en-US' command strings. Please report this",
|
||||
commandName);
|
||||
|
||||
return new CommandStrings()
|
||||
{
|
||||
Args = new[] {""},
|
||||
Desc = "?"
|
||||
};
|
||||
}
|
||||
|
||||
// Log.Warning(@"'{CommandName}' command strings don't exist in '{LanguageName}' culture.
|
||||
// This message is safe to ignore, however you can ask in Nadeko support server how you can contribute command translations",
|
||||
// commandName, cultureInfo.Name);
|
||||
|
||||
return GetCommandStrings(commandName, _usCultureInfo);
|
||||
}
|
||||
|
||||
return cmdStrings;
|
||||
}
|
||||
|
||||
public void Reload()
|
||||
{
|
||||
_stringsProvider.Reload();
|
||||
}
|
||||
}
|
||||
|
||||
public class CommandStrings
|
||||
{
|
||||
[YamlMember(Alias = "desc")]
|
||||
public string Desc { get; set; }
|
||||
[YamlMember(Alias = "args")]
|
||||
public string[] Args { get; set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NadekoBot.Core.Services
|
||||
{
|
||||
public class LocalBotStringsProvider : IBotStringsProvider
|
||||
{
|
||||
private readonly IStringsSource _source;
|
||||
private IReadOnlyDictionary<string, Dictionary<string, string>> responseStrings;
|
||||
private IReadOnlyDictionary<string, Dictionary<string, CommandStrings>> commandStrings;
|
||||
|
||||
public LocalBotStringsProvider(IStringsSource source)
|
||||
{
|
||||
_source = source;
|
||||
Reload();
|
||||
}
|
||||
|
||||
public string GetText(string localeName, string key)
|
||||
{
|
||||
if (responseStrings.TryGetValue(localeName, out var langStrings)
|
||||
&& langStrings.TryGetValue(key, out var text))
|
||||
{
|
||||
return text;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Reload()
|
||||
{
|
||||
responseStrings = _source.GetResponseStrings();
|
||||
commandStrings = _source.GetCommandStrings();
|
||||
}
|
||||
|
||||
public CommandStrings GetCommandStrings(string localeName, string commandName)
|
||||
{
|
||||
if (commandStrings.TryGetValue(localeName, out var langStrings)
|
||||
&& langStrings.TryGetValue(commandName, out var strings))
|
||||
{
|
||||
return strings;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
using Serilog;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace NadekoBot.Core.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Loads strings from the local default filepath <see cref="_responsesPath"/>
|
||||
/// </summary>
|
||||
public class LocalFileStringsSource : IStringsSource
|
||||
{
|
||||
private readonly string _responsesPath = "data/strings/responses";
|
||||
private readonly string _commandsPath = "data/strings/commands";
|
||||
|
||||
public LocalFileStringsSource(string responsesPath = "data/strings/responses",
|
||||
string commandsPath = "data/strings/commands")
|
||||
{
|
||||
_responsesPath = responsesPath;
|
||||
_commandsPath = commandsPath;
|
||||
}
|
||||
|
||||
public Dictionary<string, Dictionary<string, string>> GetResponseStrings()
|
||||
{
|
||||
var outputDict = new Dictionary<string, Dictionary<string, string>>();
|
||||
foreach (var file in Directory.GetFiles(_responsesPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
var langDict = JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(file));
|
||||
var localeName = GetLocaleName(file);
|
||||
outputDict[localeName] = langDict;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Error loading {FileName} response strings: {ErrorMessage}", file, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
return outputDict;
|
||||
}
|
||||
|
||||
public Dictionary<string, Dictionary<string, CommandStrings>> GetCommandStrings()
|
||||
{
|
||||
var deserializer = new DeserializerBuilder()
|
||||
.Build();
|
||||
|
||||
var outputDict = new Dictionary<string, Dictionary<string, CommandStrings>>();
|
||||
foreach (var file in Directory.GetFiles(_commandsPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
var text = File.ReadAllText(file);
|
||||
var langDict = deserializer.Deserialize<Dictionary<string, CommandStrings>>(text);
|
||||
var localeName = GetLocaleName(file);
|
||||
outputDict[localeName] = langDict;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Error loading {FileName} command strings: {ErrorMessage}", file, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
return outputDict;
|
||||
}
|
||||
|
||||
private static string GetLocaleName(string fileName)
|
||||
{
|
||||
fileName = Path.GetFileName(fileName);
|
||||
var dotIndex = fileName.IndexOf('.') + 1;
|
||||
var secondDotIndex = fileName.LastIndexOf('.');
|
||||
return fileName.Substring(dotIndex, secondDotIndex - dotIndex);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Extensions;
|
||||
using StackExchange.Redis;
|
||||
|
||||
namespace NadekoBot.Core.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Uses <see cref="IStringsSource"/> to load strings into redis hash (only on Shard 0)
|
||||
/// and retrieves them from redis via <see cref="GetText"/>
|
||||
/// </summary>
|
||||
public class RedisBotStringsProvider : IBotStringsProvider
|
||||
{
|
||||
private readonly ConnectionMultiplexer _redis;
|
||||
private readonly IStringsSource _source;
|
||||
private readonly IBotCredentials _creds;
|
||||
|
||||
public RedisBotStringsProvider(ConnectionMultiplexer redis, DiscordSocketClient discordClient,
|
||||
IStringsSource source, IBotCredentials creds)
|
||||
{
|
||||
_redis = redis;
|
||||
_source = source;
|
||||
_creds = creds;
|
||||
|
||||
if(discordClient.ShardId == 0)
|
||||
Reload();
|
||||
}
|
||||
|
||||
public string GetText(string localeName, string key)
|
||||
{
|
||||
var value = _redis.GetDatabase().HashGet($"{_creds.RedisKey()}:responses:{localeName}", key);
|
||||
return value;
|
||||
}
|
||||
|
||||
public CommandStrings GetCommandStrings(string localeName, string commandName)
|
||||
{
|
||||
string argsStr = _redis.GetDatabase().HashGet($"{_creds.RedisKey()}:commands:{localeName}", $"{commandName}::args");
|
||||
if (argsStr == default)
|
||||
return null;
|
||||
|
||||
var descStr = _redis.GetDatabase().HashGet($"{_creds.RedisKey()}:commands:{localeName}", $"{commandName}::desc");
|
||||
if (descStr == default)
|
||||
return null;
|
||||
|
||||
var args = Array.ConvertAll(argsStr.Split('&'), HttpUtility.UrlDecode);
|
||||
return new CommandStrings()
|
||||
{
|
||||
Args = args,
|
||||
Desc = descStr
|
||||
};
|
||||
}
|
||||
|
||||
public void Reload()
|
||||
{
|
||||
var redisDb = _redis.GetDatabase();
|
||||
foreach (var (localeName, localeStrings) in _source.GetResponseStrings())
|
||||
{
|
||||
var hashFields = localeStrings
|
||||
.Select(x => new HashEntry(x.Key, x.Value))
|
||||
.ToArray();
|
||||
|
||||
redisDb.HashSet($"{_creds.RedisKey()}:responses:{localeName}", hashFields);
|
||||
}
|
||||
|
||||
foreach (var (localeName, localeStrings) in _source.GetCommandStrings())
|
||||
{
|
||||
var hashFields = localeStrings
|
||||
.Select(x => new HashEntry($"{x.Key}::args",
|
||||
string.Join('&', Array.ConvertAll(x.Value.Args, HttpUtility.UrlEncode))))
|
||||
.Concat(localeStrings
|
||||
.Select(x => new HashEntry($"{x.Key}::desc", x.Value.Desc)))
|
||||
.ToArray();
|
||||
|
||||
redisDb.HashSet($"{_creds.RedisKey()}:commands:{localeName}", hashFields);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user