From 7866c8d678a9294dc82c7d6f5995a470e242ea5e Mon Sep 17 00:00:00 2001 From: Sebastian Oehm Date: Sat, 21 Feb 2026 01:23:41 +0100 Subject: [PATCH 01/19] Refactor: Add localization support and modernize codebase - Implemented localization using RESX resource files (`Resources.resx` and `Resources.de.resx`) for multi-language support (e.g., de-DE). - Removed `langVal` class and replaced hardcoded strings with resource-based localization. - Added `LanguageLoader` class to handle language and culture settings dynamically. - Migrated HTTP requests from `HttpWebRequest` to `HttpClient` for modernized and efficient networking. - Improved error handling for network and HTTP exceptions with localized messages. - Removed deprecated functions (`TranslationMaker`, `langHandler`) and unused dependencies. - Optimized code with modern C# features (e.g., `string.IsNullOrEmpty`, String-Interpolation, `using` statements). - Enhanced user interface with consistent and localized console output. - Updated project file (`Reaper.csproj`) to support resource file integration and satellite assemblies. - Improved SFTP integration with cleaner code and parameterized constructors. - Overhauled mail functionality to use localized strings and improve usability. - Ensured consistent naming conventions (e.g., `IRExcecute` -> `IRExecute`). - Removed old language files and replaced them with resource-based localization. --- AltReaper/Checks.cs | 89 ++-- AltReaper/Helper.cs | 97 ++-- AltReaper/HtmlBody.cs | 13 +- AltReaper/IO/Inputs.cs | 37 +- AltReaper/IO/LanguageLoader.cs | 33 ++ AltReaper/IO/Outputs.cs | 42 +- AltReaper/IO/TranslationMaker.cs | 163 ------- AltReaper/JsonHandling.cs | 26 -- AltReaper/Properties/Resources.Designer.cs | 490 +++++++++++++++++++++ AltReaper/Properties/Resources.de.resx | 263 +++++++++++ AltReaper/Properties/Resources.resx | 265 +++++++++++ AltReaper/Reaper.csproj | 24 + AltReaper/WetterApp.cs | 49 +-- 13 files changed, 1233 insertions(+), 358 deletions(-) create mode 100644 AltReaper/IO/LanguageLoader.cs delete mode 100644 AltReaper/IO/TranslationMaker.cs create mode 100644 AltReaper/Properties/Resources.Designer.cs create mode 100644 AltReaper/Properties/Resources.de.resx create mode 100644 AltReaper/Properties/Resources.resx diff --git a/AltReaper/Checks.cs b/AltReaper/Checks.cs index a691f5e..68241bb 100644 --- a/AltReaper/Checks.cs +++ b/AltReaper/Checks.cs @@ -1,5 +1,4 @@ -using System.Globalization; -using System.Net; +using System.Net; using System.Net.NetworkInformation; using static System.Console; @@ -10,17 +9,17 @@ internal class Checks public static bool cfgChecker(JsonHandling.config config) { bool[] bools = { - String.IsNullOrEmpty(config.apiKey), - String.IsNullOrEmpty(config.senderMail), - String.IsNullOrEmpty(config.senderMailPassword), - String.IsNullOrEmpty(config.hostDomain), - String.IsNullOrEmpty(config.portNumber), + string.IsNullOrEmpty(config.apiKey), + string.IsNullOrEmpty(config.senderMail), + string.IsNullOrEmpty(config.senderMailPassword), + string.IsNullOrEmpty(config.hostDomain), + string.IsNullOrEmpty(config.portNumber), false, - String.IsNullOrEmpty(config.bcc) + string.IsNullOrEmpty(config.bcc) }; try { - if (int.Parse(config.portNumber) < 0 && int.Parse(config.portNumber) > 65535) + if (int.Parse(config.portNumber) < 0 || int.Parse(config.portNumber) > 65535) { bools[5] = true; } } catch { return true; } @@ -38,39 +37,51 @@ public static void DeviceIsOnline() PingReply googleReply = googlePing.Send("8.8.8.8"); if (cloudflareReply.Status == IPStatus.Success | googleReply.Status == IPStatus.Success) { - WriteLine("Device is online"); + WriteLine(Properties.Resources.DeviceOnline); } else { - WriteLine(@" -Your device is not connected to the internet. -This application needs internet access. -Please connect your device to the internet to use this application."); + WriteLine(Properties.Resources.DeviceOfflineDetails); Helper.Closer(); } } public static void APIisOnline() { - //force internal output to be english - Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); - Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US"); IWebProxy defaultWebProxy = WebRequest.DefaultWebProxy; defaultWebProxy.Credentials = CredentialCache.DefaultCredentials; try { - HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://api.openweathermap.org/data/2.5/weather?q=London"); - request.Proxy = defaultWebProxy; - HttpWebResponse response = (HttpWebResponse)request.GetResponse(); - response.Close(); + var handler = new HttpClientHandler + { + Proxy = defaultWebProxy, + UseProxy = true, + DefaultProxyCredentials = CredentialCache.DefaultCredentials + }; + + using var client = new HttpClient(handler); + client.Timeout = TimeSpan.FromSeconds(10); + + HttpResponseMessage response = client.GetAsync("https://api.openweathermap.org/data/2.5/weather?q=London").GetAwaiter().GetResult(); + + // Treat HTTP 401 (Unauthorized) as online (API reachable but invalid key) + if (response.StatusCode == HttpStatusCode.Unauthorized) + { + WriteLine(Properties.Resources.ApiOnline); + return; + } + + // Any other HTTP response (including successful 200) is treated as offline for this check + WriteLine(Properties.Resources.ApiOffline); + Helper.Closer(); } - catch (WebException e) + catch (HttpRequestException e) { - if (e.Message.Equals("The remote server returned an error: (401) Unauthorized.", StringComparison.InvariantCultureIgnoreCase)) - { WriteLine("API is online"); } - else { WriteLine("API is not online. Please try again later."); Helper.Closer(); } + // network-level error (DNS, timeout, connection failure, etc.) + WriteLine(string.Format(Properties.Resources.NetworkErrorFormat, e.Message)); + Helper.Closer(); } catch (Exception e) { - WriteLine("\nThe following Exception was raised : {0}", e.Message); + WriteLine(string.Format(Properties.Resources.ExceptionRaisedFormat, e.Message)); } } } @@ -95,28 +106,28 @@ public void DisplayAvailableOptions() if (counter == Index) { prefix = ">"; - Console.BackgroundColor = ConsoleColor.White; - Console.ForegroundColor = ConsoleColor.Black; + BackgroundColor = ConsoleColor.White; + ForegroundColor = ConsoleColor.Black; } else { prefix = " "; - Console.BackgroundColor = ConsoleColor.Black; - Console.ForegroundColor = ConsoleColor.White; + BackgroundColor = ConsoleColor.Black; + ForegroundColor = ConsoleColor.White; } - Console.WriteLine($"{prefix} {currentOption}"); + WriteLine($"{prefix} {currentOption}"); } - Console.BackgroundColor = ConsoleColor.Black; - Console.ForegroundColor = ConsoleColor.Green; + BackgroundColor = ConsoleColor.Black; + ForegroundColor = ConsoleColor.Green; } - public int IRExcecute() + public int IRExecute() { ConsoleKey pressedKey; do { - Console.Clear(); + Clear(); DisplayAvailableOptions(); - ConsoleKeyInfo keyInfo = Console.ReadKey(true); + ConsoleKeyInfo keyInfo = ReadKey(true); pressedKey = keyInfo.Key; if (pressedKey == ConsoleKey.UpArrow ^ pressedKey == ConsoleKey.W) @@ -138,14 +149,14 @@ public int IRExcecute() } while (pressedKey != ConsoleKey.Enter); return Index; } - public String SRExcecute() + public string SRExecute() { ConsoleKey pressedKey; do { - Console.Clear(); + Clear(); DisplayAvailableOptions(); - ConsoleKeyInfo keyInfo = Console.ReadKey(true); + ConsoleKeyInfo keyInfo = ReadKey(true); pressedKey = keyInfo.Key; if (pressedKey == ConsoleKey.UpArrow ^ pressedKey == ConsoleKey.W) diff --git a/AltReaper/Helper.cs b/AltReaper/Helper.cs index 7a27f37..a6a7706 100644 --- a/AltReaper/Helper.cs +++ b/AltReaper/Helper.cs @@ -1,44 +1,61 @@ using Renci.SshNet; using System.Text.Json; -using System.Text.RegularExpressions; using static System.Console; +using Reaper.IO; namespace Reaper { public static class globalVars { - public static string[] fullySupportedLanguages = { "afrikaans", "albanian", "arabic", "azerbaijani", "bulgarian", "catalan", "czech", "danish", "german", "greek", "english", "basque", "persian", "farsi", "finnish", "french", "galician", "Hebrew", "hindi", "croatian", "hungarian", "indonesian", "italian", "japanese", "korean", "latvian", "lithuanian", "macedonian", "norwegian", "dutch", "polish", "portuguese", "romanian", "russian", "swedish", "slovak", "slovenian", "spanish", "serbian", "thai", "turkish", "ukrainian", "vietnamese", "chinese simplified", "chinese traditional", "zulu" }; - public static string[] supportedShortCodes = { "af", "al", "ar", "az", "bg", "ca", "cz", "da", "de", "el", "en", "eu", "fa", "fa", "fi", "fr", "gl", "he", "hi", "hr", "hu", "id", "it", "ja", "kr", "la", "lt", "mk", "no", "nl", "pl", "pt", "pt_br", "ro", "ru", "se", "sk", "sl", "sr", "th", "tr", "ua", "vi", "zh_cn", "zh_tw", "zu" }; - public static string appName = "Reaper", devName = "WetterSenseDev", versionNumber = "0.9.1"; - public static string[] devData = { appName, devName }; + // Load language lists and application metadata from resources (null-safe) + public static string[] fullySupportedLanguages = (Properties.Resources.ResourceManager.GetString("FullySupportedLanguages") ?? string.Empty) + .Split('|', StringSplitOptions.RemoveEmptyEntries); + public static string[] supportedShortCodes = (Properties.Resources.ResourceManager.GetString("SupportedShortCodes") ?? string.Empty) + .Split('|', StringSplitOptions.RemoveEmptyEntries); + public static string[] devData = { Properties.Resources.AppName, Properties.Resources.DevName }; public static string baseLoc = $"{Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)}\\Reaper"; - public static string tree = $"{baseLoc}\\langFiles\\", cfgLoc = $"{baseLoc}\\config.json"; + public static string cfgLoc = $"{baseLoc}\\config.json"; + + // App visible languages and mapping to OpenWeatherMap API codes / culture names. + // Keep small for now: English and German only. + public static string[] appLanguages = { "English", "German" }; + public static Dictionary appToApiCode = new() + { + { "English", "en" }, + { "German", "de" } + }; + // Map app language display -> culture name used for ResourceManager lookups (use BCP-47 style) + public static Dictionary appToCulture = new() + { + { "English", "en" }, + { "German", "de" } + }; } internal class Helper { - public static void MailOption(JsonHandling.langVal langValue, JsonHandling.config config, String[] content) + public static void MailOption(JsonHandling.config config, String[] content) { - string[] mailOptions = { langValue.yes, langValue.no }; - Menu mailMenu = new Menu(langValue.mailWanted, mailOptions); + string[] mailOptions = { Properties.Resources.YesOption, Properties.Resources.NoOption }; + Menu mailMenu = new(Properties.Resources.mailWanted, mailOptions); - if (mailMenu.IRExcecute() == 0) + if (mailMenu.IRExecute() == 0) { bool partSuccess = false; while (!partSuccess) { if (Checks.cfgChecker(config)) { - Inputs.configGen(langValue, config); + Inputs.configGen(config); config = JsonSerializer.Deserialize(File.ReadAllText(globalVars.cfgLoc)); } - Write($"\n{langValue.mailAddressQuery}\n>"); + Write($"\n{Properties.Resources.mailAddressQuery}\n>"); CursorVisible = true; ForegroundColor = ConsoleColor.White; ForegroundColor = ConsoleColor.Green; CursorVisible = false; - if (Outputs.MailOutput(ReadLine(), langValue.yourWeatherInfo, content, langValue, config)) + if (Outputs.MailOutput(ReadLine(), Properties.Resources.yourWeatherInfo, content, config)) { - Closer(config, langValue); + Closer(config); } else { throw new Exception(); } partSuccess = true; @@ -61,7 +78,7 @@ public static string PasswordMaker() { if (password.Length > 0) { - password = password.Remove(password.Length - 1); + password = password[..^1]; Write("\b \b"); } } @@ -78,64 +95,46 @@ public static string PasswordMaker() } public static void SuperUserMode(String superUserPwd, String appName, string directoryLoc) { - SftpClient sftp = new SftpClient("ssh.strato.de", $"sftp_{appName}@wettersense.de", superUserPwd); + SftpClient sftp = new("ssh.strato.de", 22, $"sftp_{appName}@wettersense.de", superUserPwd); sftp.Connect(); Stream configLoc = File.Create($"{directoryLoc}\\config.json"); sftp.DownloadFile(@"/config.json", configLoc); configLoc.Close(); - System.Collections.IEnumerator enumerator = sftp.ListDirectory("/langFiles/", null).GetEnumerator(); - List files = new List(); - while (enumerator.MoveNext()) - { - Renci.SshNet.Sftp.SftpFile sftpFile = (Renci.SshNet.Sftp.SftpFile)enumerator.Current; - string name = sftpFile.Name; - files.Add(name); - } - - Regex myRegex = new Regex(@"^[a-z]+Text\.json$"); - List downloadList = files.Where(f => myRegex.IsMatch(f)).ToList(); - foreach (string str in downloadList) - { - Stream langFileLoc = File.Create($"{directoryLoc}\\langFiles\\{str}"); - sftp.DownloadFile($"/langFiles/{str}", langFileLoc); - langFileLoc.Close(); - } sftp.Disconnect(); } public static void Closer() { Uninstaller(); - WriteLine($"\nThank you for using {globalVars.devData[0]}!"); - WriteLine("Weather data powered by openweathermap.org"); - WriteLine($"{globalVars.devData[0]} by {globalVars.devData[1]}"); - WriteLine("Press any key to exit."); + WriteLine(string.Format(Properties.Resources.ThankYouFormat, globalVars.devData[0])); + WriteLine(Properties.Resources.WeatherPoweredBy); + WriteLine(string.Format(Properties.Resources.BylineFormat, globalVars.devData[0], globalVars.devData[1])); + WriteLine(Properties.Resources.PressAnyKeyExit); ReadKey(true); Environment.Exit(0); } - public static void Closer(JsonHandling.config config, JsonHandling.langVal langValue) + public static void Closer(JsonHandling.config config) { - WriteLine($"{langValue.mailSuccessMessage}"); + WriteLine($"{Properties.Resources.mailSuccessMessage}"); Uninstaller(); - WriteLine($"\nThank you for using {globalVars.devData[0]}!"); - WriteLine("Weather data powered by openweathermap.org"); - WriteLine($"Mail powered by htmlemail.io & {config.senderMail.Split('@')[1]}"); - WriteLine($"{globalVars.devData[0]} by {globalVars.devData[1]}"); - WriteLine("Press any key to exit."); + WriteLine(string.Format(Properties.Resources.ThankYouFormat, globalVars.devData[0])); + WriteLine(Properties.Resources.WeatherPoweredBy); + WriteLine(string.Format(Properties.Resources.MailPoweredByFormat, config.senderMail.Split('@')[1])); + WriteLine(string.Format(Properties.Resources.BylineFormat, globalVars.devData[0], globalVars.devData[1])); + WriteLine(Properties.Resources.PressAnyKeyExit); ReadKey(true); Environment.Exit(0); } public static void Uninstaller() { - string baseLoc = $"{Environment.GetEnvironmentVariable("USERPROFILE")}\\Desktop\\Reaper"; - string uninstallPrompt = $"\nDo you want to unistall {globalVars.devData[0]}?"; - string[] uninstallOptions = { "yes", "no" }; + string uninstallPrompt = string.Format(Properties.Resources.UninstallPromptFormat, globalVars.devData[0]); + string[] uninstallOptions = { Properties.Resources.YesOption, Properties.Resources.NoOption }; Menu uninstallMenu = new(uninstallPrompt, uninstallOptions); - int uninstallChoice = uninstallMenu.IRExcecute(); + int uninstallChoice = uninstallMenu.IRExecute(); if (uninstallChoice == 0) { - Directory.Delete(baseLoc, true); + Directory.Delete(globalVars.baseLoc, true); } } } diff --git a/AltReaper/HtmlBody.cs b/AltReaper/HtmlBody.cs index 99aaf26..a40d798 100644 --- a/AltReaper/HtmlBody.cs +++ b/AltReaper/HtmlBody.cs @@ -1,17 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection.Metadata; -using System.Text; -using System.Threading.Tasks; -using static Reaper.JsonHandling; -using System.Xml.Linq; - -namespace Reaper +namespace Reaper { internal class HtmlBody { - public static string getBody(string[] content, string easterEgg, string name, config config) + public static string getBody(string[] content, string easterEgg, string name, JsonHandling.config config) { string htmlBody = $"\r\n" + diff --git a/AltReaper/IO/Inputs.cs b/AltReaper/IO/Inputs.cs index 94a6ec3..5e64477 100644 --- a/AltReaper/IO/Inputs.cs +++ b/AltReaper/IO/Inputs.cs @@ -12,20 +12,16 @@ * port * bcc */ -namespace Reaper +namespace Reaper.IO { internal class Inputs { - public static String configReader() + public static string configReader() { return File.ReadAllText(globalVars.cfgLoc); } - public static String langHandler(String langPreferenceLong) - { - //importing selected language file - return File.ReadAllText($"{globalVars.tree}{langPreferenceLong}Text.json"); - } - public static async Task APICall(String city, String langPreferenceShort, String unitPreference, String APIKey) + + public static async Task APICall(string city, string langPreferenceShort, string unitPreference, string APIKey) { //Use default system proxy settings IWebProxy defaultWebProxy = WebRequest.DefaultWebProxy; @@ -42,7 +38,7 @@ public static String langHandler(String langPreferenceLong) return await client.GetFromJsonAsync($"weather?q={city}&lang={langPreferenceShort}&units={unitPreference}&appid={APIKey}"); } - public static bool configGen(JsonHandling.langVal langValue, JsonHandling.config config) + public static bool configGen(JsonHandling.config config) { //checks if config file exists and if all lines have information if (File.Exists(globalVars.cfgLoc) && Checks.cfgChecker(config) == false) { return true; } @@ -63,7 +59,7 @@ public static bool configGen(JsonHandling.langVal langValue, JsonHandling.config ForegroundColor = ConsoleColor.White; string portNumber = ReadLine(); ForegroundColor = ConsoleColor.Green; - Write($"\nEnter the mail address of the BCC archive mail or type \"{langValue.no}\" (without quotes) \n>"); + Write($"\nEnter the mail address of the BCC archive mail or type \"{Properties.Resources.NoOption}\" (without quotes) \n>"); ForegroundColor = ConsoleColor.White; string BCC = ReadLine(); CursorVisible = false; @@ -80,12 +76,12 @@ public static bool configGen(JsonHandling.langVal langValue, JsonHandling.config File.WriteAllText(globalVars.cfgLoc, JsonSerializer.Serialize(json)); return true; } - public static string UnitPreference(JsonHandling.langVal langValue) + public static string UnitPreference() { //gets unit preference - string[] unitOptions = { langValue.metric, langValue.imperial }; - Menu unitMenu = new(langValue.unitQuery, unitOptions); - return unitMenu.IRExcecute() == 0 ? "metric" : "imperial"; + string[] unitOptions = { Properties.Resources.metric, Properties.Resources.imperial }; + Menu unitMenu = new(Properties.Resources.unitQuery, unitOptions); + return unitMenu.IRExecute() == 0 ? "metric" : "imperial"; } public static void ConfigGetter() { @@ -108,20 +104,17 @@ public static void ConfigGetter() File.WriteAllText(globalVars.cfgLoc, JsonSerializer.Serialize(tmp)); } } - public static String langPreference() + public static string langPreference() { List availableLanguages = new(); - foreach (string l in globalVars.fullySupportedLanguages) + foreach (string l in globalVars.appLanguages) { - if (File.Exists($"{globalVars.tree}{l}Text.json")) - { - availableLanguages.Add($"{char.ToUpper(l[0]) + l.Substring(1)}"); - } + availableLanguages.Add(l); } - Menu languageMenu = new Menu("Please select your desired language or \"new\" to implement a new language", availableLanguages.ToArray()); + Menu languageMenu = new(Properties.Resources.SelectPreferredLanguage, availableLanguages.ToArray()); string spacer = "-------------------------"; - string selectedLanguage = languageMenu.SRExcecute(); + string selectedLanguage = languageMenu.SRExecute(); WriteLine($"\n{spacer}\n"); WriteLine($"using {selectedLanguage}"); WriteLine($"\n{spacer}"); diff --git a/AltReaper/IO/LanguageLoader.cs b/AltReaper/IO/LanguageLoader.cs new file mode 100644 index 0000000..2d8aaa7 --- /dev/null +++ b/AltReaper/IO/LanguageLoader.cs @@ -0,0 +1,33 @@ +using System.Globalization; + +namespace Reaper.IO +{ + internal static class LanguageLoader + { + // Load language values from RESX resources for a given selected language display name + public static (string apiCode, CultureInfo culture) Load(string selectedLanguageDisplay) + { + // Normalize selected display name + string selectedDisplay = string.IsNullOrEmpty(selectedLanguageDisplay) ? "English" : selectedLanguageDisplay; + + // Determine culture name and API code using app-level mappings + string cultureName = "en"; + if (Reaper.globalVars.appToCulture != null && Reaper.globalVars.appToCulture.ContainsKey(selectedDisplay)) + { + cultureName = Reaper.globalVars.appToCulture[selectedDisplay]; + } + + string apiCode = "en"; + if (Reaper.globalVars.appToApiCode != null && Reaper.globalVars.appToApiCode.ContainsKey(selectedDisplay)) + { + apiCode = Reaper.globalVars.appToApiCode[selectedDisplay]; + } + + CultureInfo culture = CultureInfo.InvariantCulture; + try { if (!string.IsNullOrEmpty(cultureName)) culture = new CultureInfo(cultureName); } + catch { culture = CultureInfo.InvariantCulture; } + + return (apiCode, culture); + } + } +} diff --git a/AltReaper/IO/Outputs.cs b/AltReaper/IO/Outputs.cs index ca5c191..aa55c60 100644 --- a/AltReaper/IO/Outputs.cs +++ b/AltReaper/IO/Outputs.cs @@ -1,16 +1,13 @@ -using System.Globalization; -using System.Net; +using System.Net; using System.Net.Mail; using static System.Console; -namespace Reaper +namespace Reaper.IO { internal class Outputs { - public static String[] WeatherOutput(WeatherResponse.root weatherData, String unitPreference, JsonHandling.langVal langValue) + public static string[] WeatherOutput(WeatherResponse.root weatherData, string unitPreference) { - Thread.CurrentThread.CurrentCulture = new CultureInfo("de-DE"); - Thread.CurrentThread.CurrentUICulture = new CultureInfo("de-DE"); //time & timezones, units char unitSymbol; DateTime localSystemTime = DateTime.Now; @@ -21,31 +18,31 @@ public static String[] WeatherOutput(WeatherResponse.root weatherData, String un unitSymbol = unitPreference == "metric" ? 'c' : 'f'; //main output - List content = new(); + List content = new(); string spacer = "\n-------------------------------------\n"; content.Add(spacer); - content.Add($"{langValue.theWeatherIn}: {weatherData.name}, {weatherData.sys.country}"); - content.Add($"{langValue.localSystemTime}: {localSystemTime}"); - content.Add($"{langValue.timeAtDestination}: : {locTime} {timezoneUTC} "); - content.Add($"{langValue.temp}: {weatherData.main.temp:0.#}°{unitSymbol}"); - content.Add($"{langValue.lowestTemp}: {weatherData.main.temp_min:0.#}°{unitSymbol}"); - content.Add($"{langValue.highestTemp}: {weatherData.main.temp_max:0.#}°{unitSymbol}"); - content.Add($"{langValue.description}: {weatherData.weather[0].description}"); + content.Add($"{Properties.Resources.theWeatherIn}: {weatherData.name}, {weatherData.sys.country}"); + content.Add($"{Properties.Resources.localSystemTime}: {localSystemTime}"); + content.Add($"{Properties.Resources.timeAtDestination}: : {locTime} {timezoneUTC} "); + content.Add($"{Properties.Resources.temp}: {weatherData.main.temp:0.#}°{unitSymbol}"); + content.Add($"{Properties.Resources.lowestTemp}: {weatherData.main.temp_min:0.#}°{unitSymbol}"); + content.Add($"{Properties.Resources.highestTemp}: {weatherData.main.temp_max:0.#}°{unitSymbol}"); + content.Add($"{Properties.Resources.description}: {weatherData.weather[0].description}"); content.Add(spacer); string[] cArray = content.ToArray(); - WriteLine(String.Join("\r\n", cArray)); - WriteLine(langValue.pressEnterContinue); + WriteLine(string.Join("\r\n", cArray)); + WriteLine(Properties.Resources.pressEnterContinue); while (ReadKey(true).Key != ConsoleKey.Enter) { continue; } return cArray; } - public static bool MailOutput(String recipient, String subjectLine, String[] content, JsonHandling.langVal langValue, JsonHandling.config config) + public static bool MailOutput(string recipient, string subjectLine, string[] content, JsonHandling.config config) { //Set salutation - Write($"\n{langValue.nameOr}\n>"); + Write($"\n{Properties.Resources.nameOr}\n>"); CursorVisible = true; ForegroundColor = ConsoleColor.White; - string name = ReadLine(); - if (name == langValue.no) { name = ""; } + string? name = ReadLine(); + if (name == Properties.Resources.NoOption || string.IsNullOrEmpty(name) || string.IsNullOrWhiteSpace(name)) { name = ""; } ForegroundColor = ConsoleColor.Green; CursorVisible = false; //Set smtp config @@ -70,14 +67,13 @@ public static bool MailOutput(String recipient, String subjectLine, String[] con mailMessage.To.Add(recipient); //Set bcc for analysation/archivating usage - if (config.bcc == langValue.no) { } + if (config.bcc == Properties.Resources.NoOption) { } else { mailMessage.Bcc.Add(config.bcc); } //sending try { smtpClient.Send(mailMessage); } - catch + catch (Exception mail) { - Exception mail = new Exception(); WriteLine(mail.Message); return false; } diff --git a/AltReaper/IO/TranslationMaker.cs b/AltReaper/IO/TranslationMaker.cs deleted file mode 100644 index 76a0d66..0000000 --- a/AltReaper/IO/TranslationMaker.cs +++ /dev/null @@ -1,163 +0,0 @@ -using System.Text.Json; -using static System.Console; - -namespace Reaper -{ - internal class TranslationMaker - { - public static bool newFileMaker(string langName) - { - string currentUserDesktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\Desktop\\Reaper\\langFiles\\"; - string futureFilePath = currentUserDesktopPath + langName.ToLower() + "Text.json"; - - bool langCreated = false; - if (langName.ToLower() == "default" | String.IsNullOrEmpty(langName) | langName.ToLower() == "english") { return false; } //ensures only files with names that arent defaultText or Text are created - //Creates file if not existant or user confirms that they want to - if (File.Exists(futureFilePath)) - { - Write("\nThere is already a File for the language you selected. If you want to overwrite it, type \"I know what I am doing!\" (without quotes)\n>"); - if (ReadLine() == "I know what I am doing!") { } else { return false; } - } - - //checks if language is fully supported - string shortLanguage = null; - if (globalVars.fullySupportedLanguages.Contains(langName, StringComparer.OrdinalIgnoreCase)) - { - int index = Array.FindIndex(globalVars.fullySupportedLanguages, x => x.ToLower() == langName.ToLower()); - shortLanguage = globalVars.supportedShortCodes[index]; - } - else { WriteLine("Language not fully supported. Some output may be in English"); shortLanguage = "en"; } - - //Instructions & translation items - WriteLine("Follow the instructions! \nOnly translate what is inside quotes! \nDo not put your translation in quotes unless told! \nPress Enter after translation to proceed"); - Write("\nTranslate \"Enter the name of the unit system you want to use\"\n>"); - string unitQuery = ReadLine(); - Write("\nTranslate the word \"metric\" (the measurement/unit system)\n>"); - string metric = ReadLine().ToLower(); - Write("\nTranslate the word \"imperial\" (the mesarement/unit system)\n>"); - string imperial = ReadLine().ToLower(); - Write("\nTranslate \"Enter the name of the city which you want weather data of.\"\n>"); - string nameOfCity = ReadLine(); - Write("\nTranslate \"Invalid input.\"\n>"); - string invalidInput = ReadLine(); - Write("\nTranslate \"\"Press Enter to continue.\n>"); - string pressEnterContinue = ReadLine(); - Write("\nTranslate \"Error found.\"\n>"); - string errorMessage = ReadLine(); - Write("\nTranslate \"The weather in\" (like in )\n>"); - string theWeatherIn = ReadLine(); - Write("\nTranslate the word \"temperature\"\n>"); - string temp = ReadLine(); - Write("\nTranslate \"lowest Temperature\"\n>"); - string lowestTemp = ReadLine(); - Write("\nTranslate \"highest temperature\"\n>"); - string highestTemp = ReadLine(); - Write("\nTranslate the word \"description\"\n>"); - string description = ReadLine(); - Write("\nTranslate \"local system time\"\n>"); - string localSystemTime = ReadLine(); - Write("\nTranslate \"time at destination\"\n>"); - string timeAtDestination = ReadLine(); - Write("\nTranslate \"your weather info\"(formal your)\n>"); - string yourWeatherInfo = ReadLine(); - Write("\nTranslate the word \"yes\"\n>"); - string yes = ReadLine().ToLower(); - Write("\nTranslate the word \"no\"\n>"); - string no = ReadLine().ToLower(); - Write("\nDo you want this as a mail?\n>"); - string mailWanted = ReadLine(); - Write("\nEnter your mail address\n>"); - string mailAddressQuery = ReadLine(); - string nameOr = ""; - while ((nameOr.Contains('"') && nameOr.Contains('(') && nameOr.Contains(')')) == false) - { - WriteLine("Translate everything inside the next message, including \" \\ and messages inside brackets"); - Write("\nEnter your name or type \"no\" to not be addressed (without quotes)\n>"); - nameOr = ReadLine(); - } - Write("\nMail sent successfully\n>"); - string mailSuccessMessage = ReadLine(); - - var langVal = new JsonHandling.langVal - { - shortLanguage = shortLanguage, - unitQuery = unitQuery, - metric = metric, - imperial = imperial, - nameOfCity = nameOfCity, - invalidInput = invalidInput, - pressEnterContinue = pressEnterContinue, - errorMessage = errorMessage, - theWeatherIn = theWeatherIn, - temp = temp, - lowestTemp = lowestTemp, - highestTemp = highestTemp, - description = description, - localSystemTime = localSystemTime, - timeAtDestination = timeAtDestination, - yourWeatherInfo = yourWeatherInfo, - yes = yes, - no = no, - mailWanted = mailWanted, - mailAddressQuery = mailAddressQuery, - nameOr = nameOr, - mailSuccessMessage = mailSuccessMessage, - }; - - WriteLine("Writing to file"); - File.WriteAllText(futureFilePath, JsonSerializer.Serialize(langVal)); - Clear(); - - if (File.Exists(futureFilePath)) - { - langCreated = true; - WriteLine($"{char.ToUpper(langName[0]) + langName.Substring(1)} language file successfully created."); - } - return langCreated; - } - - public static bool defaultFileMaker() - { - string langName = "english"; - bool langCreated = false; - - string currentUserDesktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\Desktop\\Reaper\\langFiles\\"; - string futureFilePath = currentUserDesktopPath + langName.ToLower() + "Text.json"; - - var langVal = new JsonHandling.langVal - { - shortLanguage = "en", - unitQuery = "Enter the name of the unit system you want to use", - metric = "metric", - imperial = "imperial", - errorMessage = "Error found.", - no = "no", - nameOfCity = "Enter the name of the city which you want weather data of.", - invalidInput = "Invalid input.", - pressEnterContinue = "Press Enter to continue.", - theWeatherIn = "The weather in", - temp = "temperature", - lowestTemp = "lowest temperature", - highestTemp = "highest temperature", - description = "description", - yes = "yes", - timeAtDestination = "time at destination", - yourWeatherInfo = "your weather info", - mailWanted = "Do you want this as a mail?", - mailAddressQuery = "Enter your mail address", - nameOr = "Enter your name or type \"no\" to not be addressed (without quotes)", - mailSuccessMessage = "Mail sent successfully", - localSystemTime = "local system time" - }; - File.WriteAllText(futureFilePath, JsonSerializer.Serialize(langVal)); - - if (File.Exists(futureFilePath)) - { - langCreated = true; - WriteLine($"{char.ToUpper(langName[0]) + langName.Substring(1)} language file successfully created."); - Clear(); - } - return langCreated; - } - } -} \ No newline at end of file diff --git a/AltReaper/JsonHandling.cs b/AltReaper/JsonHandling.cs index a4ab92b..462c080 100644 --- a/AltReaper/JsonHandling.cs +++ b/AltReaper/JsonHandling.cs @@ -13,32 +13,6 @@ public class config public string portNumber { get; set; } public string bcc { get; set; } } - public class langVal - { - public string shortLanguage { get; set; } - public string unitQuery { get; set; } - public string metric { get; set; } - public string imperial { get; set; } - public string nameOfCity { get; set; } - public string invalidInput { get; set; } - public string pressEnterContinue { get; set; } - public string errorMessage { get; set; } - public string theWeatherIn { get; set; } - public string temp { get; set; } - public string lowestTemp { get; set; } - public string highestTemp { get; set; } - public string description { get; set; } - public string localSystemTime { get; set; } - public string timeAtDestination { get; set; } - public string yourWeatherInfo { get; set; } - public string yes { get; set; } - public string no { get; set; } - public string mailWanted { get; set; } - public string mailAddressQuery { get; set; } - public string nameOr { get; set; } - public string mailSuccessMessage { get; set; } - } - } public static class WeatherResponse { diff --git a/AltReaper/Properties/Resources.Designer.cs b/AltReaper/Properties/Resources.Designer.cs new file mode 100644 index 0000000..87591e7 --- /dev/null +++ b/AltReaper/Properties/Resources.Designer.cs @@ -0,0 +1,490 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.42000 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +namespace Reaper.Properties { + using System; + + + /// + /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// + // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert + // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert. + // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen + // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Reaper.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle + /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die API is not online. Please try again later. ähnelt. + /// + public static string ApiOffline { + get { + return ResourceManager.GetString("ApiOffline", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die API is online ähnelt. + /// + public static string ApiOnline { + get { + return ResourceManager.GetString("ApiOnline", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Reaper ähnelt. + /// + public static string AppName { + get { + return ResourceManager.GetString("AppName", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die {0} v{1} ähnelt. + /// + public static string AppTitleFormat { + get { + return ResourceManager.GetString("AppTitleFormat", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die {0} by {1} ähnelt. + /// + public static string BylineFormat { + get { + return ResourceManager.GetString("BylineFormat", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Close {0} with error: {1} ähnelt. + /// + public static string CloseAppErrorFormat { + get { + return ResourceManager.GetString("CloseAppErrorFormat", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Closed {0}. ähnelt. + /// + public static string CloseAppFormat { + get { + return ResourceManager.GetString("CloseAppFormat", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Continuing in standard mode ähnelt. + /// + public static string ContinuingStandardMode { + get { + return ResourceManager.GetString("ContinuingStandardMode", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die description ähnelt. + /// + public static string description { + get { + return ResourceManager.GetString("description", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die + ///Your device is not connected to the internet. + ///This application needs internet access. + ///Please connect your device to the internet to use this application. ähnelt. + /// + public static string DeviceOfflineDetails { + get { + return ResourceManager.GetString("DeviceOfflineDetails", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Device is online ähnelt. + /// + public static string DeviceOnline { + get { + return ResourceManager.GetString("DeviceOnline", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die WetterSenseDev ähnelt. + /// + public static string DevName { + get { + return ResourceManager.GetString("DevName", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Error found. ähnelt. + /// + public static string errorMessage { + get { + return ResourceManager.GetString("errorMessage", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Error. Retype password ähnelt. + /// + public static string ErrorRetypePassword { + get { + return ResourceManager.GetString("ErrorRetypePassword", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die + ///The following Exception was raised : {0} ähnelt. + /// + public static string ExceptionRaisedFormat { + get { + return ResourceManager.GetString("ExceptionRaisedFormat", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die afrikaans|albanian|arabic|azerbaijani|bulgarian|catalan|czech|danish|german|greek|english|basque|persian|farsi|finnish|french|galician|Hebrew|hindi|croatian|hungarian|indonesian|italian|japanese|korean|latvian|lithuanian|macedonian|norwegian|dutch|polish|portuguese|romanian|russian|swedish|slovak|slovenian|spanish|serbian|thai|turkish|ukrainian|vietnamese|chinese simplified|chinese traditional|zulu ähnelt. + /// + public static string FullySupportedLanguages { + get { + return ResourceManager.GetString("FullySupportedLanguages", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die highest temperature ähnelt. + /// + public static string highestTemp { + get { + return ResourceManager.GetString("highestTemp", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die imperial ähnelt. + /// + public static string imperial { + get { + return ResourceManager.GetString("imperial", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Invalid input. ähnelt. + /// + public static string invalidInput { + get { + return ResourceManager.GetString("invalidInput", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die local system time ähnelt. + /// + public static string localSystemTime { + get { + return ResourceManager.GetString("localSystemTime", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die lowest temperature ähnelt. + /// + public static string lowestTemp { + get { + return ResourceManager.GetString("lowestTemp", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Enter your mail address ähnelt. + /// + public static string mailAddressQuery { + get { + return ResourceManager.GetString("mailAddressQuery", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Mail powered by htmlemail.io & {0} ähnelt. + /// + public static string MailPoweredByFormat { + get { + return ResourceManager.GetString("MailPoweredByFormat", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Mail sent successfully ähnelt. + /// + public static string mailSuccessMessage { + get { + return ResourceManager.GetString("mailSuccessMessage", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Do you want this as a mail? ähnelt. + /// + public static string mailWanted { + get { + return ResourceManager.GetString("mailWanted", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die metric ähnelt. + /// + public static string metric { + get { + return ResourceManager.GetString("metric", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Enter the name of the city which you want weather data of. ähnelt. + /// + public static string nameOfCity { + get { + return ResourceManager.GetString("nameOfCity", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Enter your name or type "no" to not be addressed (without quotes) ähnelt. + /// + public static string nameOr { + get { + return ResourceManager.GetString("nameOr", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Network error contacting API: {0} ähnelt. + /// + public static string NetworkErrorFormat { + get { + return ResourceManager.GetString("NetworkErrorFormat", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die no ähnelt. + /// + public static string NoOption { + get { + return ResourceManager.GetString("NoOption", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Press any key to exit. ähnelt. + /// + public static string PressAnyKeyExit { + get { + return ResourceManager.GetString("PressAnyKeyExit", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Press Enter to continue. ähnelt. + /// + public static string pressEnterContinue { + get { + return ResourceManager.GetString("pressEnterContinue", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Select your preferred language ähnelt. + /// + public static string SelectPreferredLanguage { + get { + return ResourceManager.GetString("SelectPreferredLanguage", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Enter the superuser password. Password won't be shown, type each char individually, backspace to correct, enter to continue ähnelt. + /// + public static string SuperUserPasswordPrompt { + get { + return ResourceManager.GetString("SuperUserPasswordPrompt", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Do you want to enter superuser mode? ähnelt. + /// + public static string SuperUserQuestion { + get { + return ResourceManager.GetString("SuperUserQuestion", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die af|al|ar|az|bg|ca|cz|da|de|el|en|eu|fa|fa|fi|fr|gl|he|hi|hr|hu|id|it|ja|kr|la|lt|mk|no|nl|pl|pt|pt_br|ro|ru|se|sk|sl|sr|th|tr|ua|vi|zh_cn|zh_tw|zu ähnelt. + /// + public static string SupportedShortCodes { + get { + return ResourceManager.GetString("SupportedShortCodes", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die temperature ähnelt. + /// + public static string temp { + get { + return ResourceManager.GetString("temp", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Thank you for using {0}! ähnelt. + /// + public static string ThankYouFormat { + get { + return ResourceManager.GetString("ThankYouFormat", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die The weather in ähnelt. + /// + public static string theWeatherIn { + get { + return ResourceManager.GetString("theWeatherIn", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die time at destination ähnelt. + /// + public static string timeAtDestination { + get { + return ResourceManager.GetString("timeAtDestination", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Uninstall of {0} failed with error: {1} ähnelt. + /// + public static string UninstallErrorFormat { + get { + return ResourceManager.GetString("UninstallErrorFormat", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Do you want to unistall {0}? ähnelt. + /// + public static string UninstallPromptFormat { + get { + return ResourceManager.GetString("UninstallPromptFormat", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Enter the name of the unit system you want to use ähnelt. + /// + public static string unitQuery { + get { + return ResourceManager.GetString("unitQuery", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die 0.9.1 ähnelt. + /// + public static string VersionNumber { + get { + return ResourceManager.GetString("VersionNumber", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Weather data powered by openweathermap.org ähnelt. + /// + public static string WeatherPoweredBy { + get { + return ResourceManager.GetString("WeatherPoweredBy", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die yes ähnelt. + /// + public static string YesOption { + get { + return ResourceManager.GetString("YesOption", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die your weather info ähnelt. + /// + public static string yourWeatherInfo { + get { + return ResourceManager.GetString("yourWeatherInfo", resourceCulture); + } + } + } +} diff --git a/AltReaper/Properties/Resources.de.resx b/AltReaper/Properties/Resources.de.resx new file mode 100644 index 0000000..7fa06d0 --- /dev/null +++ b/AltReaper/Properties/Resources.de.resx @@ -0,0 +1,263 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Gerät ist online + + + Ihr Gerät ist nicht mit dem Internet verbunden. +Diese Anwendung benötigt Internetzugang. +Bitte verbinden Sie Ihr Gerät mit dem Internet, um diese Anwendung zu benutzen. + + + API ist online + + + API ist nicht online. Bitte versuchen Sie es später erneut. + + + Netzwerkfehler beim Kontaktieren der API: {0} + + + Die folgende Ausnahme wurde ausgelöst : {0} + + + {0} v{1} + + + Möchten Sie in den Superuser-Modus wechseln? + + + ja + + + nein + + + Geben Sie das Superuser-Passwort ein. Das Passwort wird nicht angezeigt, geben Sie jedes Zeichen einzeln ein, Rücktaste zum Korrigieren, Enter zum Fortfahren + + + Fehler. Passwort erneut eingeben + + + Wird im Standardmodus fortgesetzt + + + afrikaans|albanian|arabic|azerbaijani|bulgarian|catalan|czech|danish|german|greek|english|basque|persian|farsi|finnish|french|galician|Hebrew|hindi|croatian|hungarian|indonesian|italian|japanese|korean|latvian|lithuanian|macedonian|norwegian|dutch|polish|portuguese|romanian|russian|swedish|slovak|slovenian|spanish|serbian|thai|turkish|ukrainian|vietnamese|chinese simplified|chinese traditional|zulu + + + af|al|ar|az|bg|ca|cz|da|de|el|en|eu|fa|fa|fi|fr|gl|he|hi|hr|hu|id|it|ja|kr|la|lt|mk|no|nl|pl|pt|pt_br|ro|ru|se|sk|sl|sr|th|tr|ua|vi|zh_cn|zh_tw|zu + + + Reaper + + + WetterSenseDev + + + 0.9.1 + + + Danke für die Nutzung von {0}! + + + Wetterdaten von openweathermap.org + + + {0} von {1} + + + Beliebige Taste zum Verlassen drücken. + + + Mail von htmlemail.io & {0} + + + {0} deinstallieren? + + + Geschlossen: {0}. + + + Schließen von {0} mit Fehler: {1} + + + Deinstallation von {0} schlug fehl. Fehler: {1} + + + Geben Sie den Namen des Einheitensystems ein, das Sie verwenden möchten + + + metrisch + + + Imperial + + + Geben Sie den Namen der Stadt ein, für die Sie Wetterdaten wünschen. + + + Ungültige Eingabe. + + + Drücken Sie die Eingabetaste, um fortzufahren. + + + Fehler aufgetreten. + + + Das Wetter in + + + Temperatur + + + niedrigste Temperatur + + + höchste Temperatur + + + Beschreibung + + + lokale Systemzeit + + + Zeit am Zielort + + + Ihre Wetterinformationen + + + Möchten Sie dies per E-Mail erhalten? + + + Geben Sie Ihre E-Mail-Adresse ein + + + Geben Sie Ihren Namen ein oder geben Sie "nein" ein, um nicht angesprochen zu werden (ohne Anführungszeichen) + + + E-Mail erfolgreich gesendet + + + Bevorzugte Sprache auswählen + + \ No newline at end of file diff --git a/AltReaper/Properties/Resources.resx b/AltReaper/Properties/Resources.resx new file mode 100644 index 0000000..989aba3 --- /dev/null +++ b/AltReaper/Properties/Resources.resx @@ -0,0 +1,265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Device is online + + + +Your device is not connected to the internet. +This application needs internet access. +Please connect your device to the internet to use this application. + + + API is online + + + API is not online. Please try again later. + + + Network error contacting API: {0} + + + +The following Exception was raised : {0} + + + {0} v{1} + + + Do you want to enter superuser mode? + + + yes + + + no + + + Enter the superuser password. Password won't be shown, type each char individually, backspace to correct, enter to continue + + + Error. Retype password + + + Continuing in standard mode + + + afrikaans|albanian|arabic|azerbaijani|bulgarian|catalan|czech|danish|german|greek|english|basque|persian|farsi|finnish|french|galician|Hebrew|hindi|croatian|hungarian|indonesian|italian|japanese|korean|latvian|lithuanian|macedonian|norwegian|dutch|polish|portuguese|romanian|russian|swedish|slovak|slovenian|spanish|serbian|thai|turkish|ukrainian|vietnamese|chinese simplified|chinese traditional|zulu + + + af|al|ar|az|bg|ca|cz|da|de|el|en|eu|fa|fa|fi|fr|gl|he|hi|hr|hu|id|it|ja|kr|la|lt|mk|no|nl|pl|pt|pt_br|ro|ru|se|sk|sl|sr|th|tr|ua|vi|zh_cn|zh_tw|zu + + + Reaper + + + WetterSenseDev + + + 0.9.1 + + + Thank you for using {0}! + + + Weather data powered by openweathermap.org + + + {0} by {1} + + + Press any key to exit. + + + Mail powered by htmlemail.io & {0} + + + Do you want to unistall {0}? + + + Closed {0}. + + + Close {0} with error: {1} + + + Uninstall of {0} failed with error: {1} + + + Enter the name of the unit system you want to use + + + metric + + + imperial + + + Enter the name of the city which you want weather data of. + + + Invalid input. + + + Press Enter to continue. + + + Error found. + + + The weather in + + + temperature + + + lowest temperature + + + highest temperature + + + description + + + local system time + + + time at destination + + + your weather info + + + Do you want this as a mail? + + + Enter your mail address + + + Enter your name or type "no" to not be addressed (without quotes) + + + Mail sent successfully + + + Select your preferred language + + \ No newline at end of file diff --git a/AltReaper/Reaper.csproj b/AltReaper/Reaper.csproj index d1c785d..f753279 100644 --- a/AltReaper/Reaper.csproj +++ b/AltReaper/Reaper.csproj @@ -11,4 +11,28 @@ + + + True + True + Resources.resx + + + + + + + PublicResXFileCodeGenerator + Resources.Designer.cs + + + + + Resources.resx + true + + + + + diff --git a/AltReaper/WetterApp.cs b/AltReaper/WetterApp.cs index 5dea5a8..96f198f 100644 --- a/AltReaper/WetterApp.cs +++ b/AltReaper/WetterApp.cs @@ -1,4 +1,6 @@ -using System.Text.Json; +using Reaper.IO; +using System.Globalization; +using System.Text.Json; using static Reaper.JsonHandling; using static Reaper.WeatherResponse; using static System.Console; @@ -9,8 +11,8 @@ public static class Program { public static void Main(String[] args) { - - Title = $"{globalVars.appName} v{globalVars.versionNumber}"; + + Title = string.Format(Properties.Resources.AppTitleFormat, Properties.Resources.AppName, Properties.Resources.VersionNumber); ForegroundColor = ConsoleColor.Green; OutputEncoding = System.Text.Encoding.UTF8; CursorVisible = false; @@ -19,51 +21,48 @@ public static void Main(String[] args) Checks.DeviceIsOnline(); Checks.APIisOnline(); - - if (!Directory.Exists(globalVars.tree)) { Directory.CreateDirectory(globalVars.tree); } - - string[] superUserOptions = { "yes", "no" }; - Menu superUser = new("Do you want to enter superuser mode?", superUserOptions); + string[] superUserOptions = { Properties.Resources.YesOption, Properties.Resources.NoOption }; + Menu superUser = new(Properties.Resources.SuperUserQuestion, superUserOptions); - if (superUser.IRExcecute() == 0) + if (superUser.IRExecute() == 0) { - Write("\nEnter the superuser password. Password won't be shown, type each char individually, backspace to correct, enter to continue\n>"); + Write("\n" + Properties.Resources.SuperUserPasswordPrompt + "\n>"); while (true) { try { - Helper.SuperUserMode(Helper.PasswordMaker(), globalVars.appName, globalVars.baseLoc); + Helper.SuperUserMode(Helper.PasswordMaker(), Properties.Resources.AppName, globalVars.baseLoc); break; } - catch { Write("\nError. Retype password\n>"); continue; } + catch { Write("\n" + Properties.Resources.ErrorRetypePassword + "\n>"); continue; } } } - else { Write("Continuing in standard mode"); } - TranslationMaker.defaultFileMaker(); - + else { Write(Properties.Resources.ContinuingStandardMode); } string chosenLanguage = Inputs.langPreference(); - langVal langValue = JsonSerializer.Deserialize(Inputs.langHandler(chosenLanguage)); + // Load language values from RESX via LanguageLoader + (string apiCode, CultureInfo culture) = LanguageLoader.Load(chosenLanguage); + Thread.CurrentThread.CurrentUICulture = culture; + Thread.CurrentThread.CurrentCulture = culture; Inputs.ConfigGetter(); config config = JsonSerializer.Deserialize(File.ReadAllText(globalVars.cfgLoc)); - string unitPreference = Inputs.UnitPreference(langValue); - - string city = null; + string unitPreference = Inputs.UnitPreference(); int check = 0; CursorVisible = true; + string? city; while (true) { - Write($"\n{langValue.nameOfCity}\n>"); + Write($"\n{Properties.Resources.nameOfCity}\n>"); ForegroundColor = ConsoleColor.White; city = ReadLine(); - if (!String.IsNullOrEmpty(city)) { break; } + if (!string.IsNullOrEmpty(city)) { break; } if (check >= 1) { ForegroundColor = ConsoleColor.Green; - WriteLine(langValue.invalidInput); + WriteLine(Properties.Resources.invalidInput); continue; } check++; @@ -71,11 +70,11 @@ public static void Main(String[] args) ForegroundColor = ConsoleColor.Green; CursorVisible = false; - root weatherData = Inputs.APICall(city, langValue.shortLanguage, unitPreference, config.apiKey).Result; + root weatherData = Inputs.APICall(city, apiCode, unitPreference, config.apiKey).Result; - var content = Outputs.WeatherOutput(weatherData, unitPreference, langValue); + var content = Outputs.WeatherOutput(weatherData, unitPreference); - Helper.MailOption(langValue, config, content); + Helper.MailOption(config, content); } } } \ No newline at end of file From 582f09c348c86f22c3ac94cd7d6cea6efbc0f39e Mon Sep 17 00:00:00 2001 From: Sebastian Oehm Date: Sat, 21 Feb 2026 01:29:08 +0100 Subject: [PATCH 02/19] Remove redundant configReader method Remove redundant comment --- AltReaper/IO/Inputs.cs | 5 ----- AltReaper/WetterApp.cs | 1 - 2 files changed, 6 deletions(-) diff --git a/AltReaper/IO/Inputs.cs b/AltReaper/IO/Inputs.cs index 5e64477..474ab32 100644 --- a/AltReaper/IO/Inputs.cs +++ b/AltReaper/IO/Inputs.cs @@ -16,11 +16,6 @@ namespace Reaper.IO { internal class Inputs { - public static string configReader() - { - return File.ReadAllText(globalVars.cfgLoc); - } - public static async Task APICall(string city, string langPreferenceShort, string unitPreference, string APIKey) { //Use default system proxy settings diff --git a/AltReaper/WetterApp.cs b/AltReaper/WetterApp.cs index 96f198f..2314c27 100644 --- a/AltReaper/WetterApp.cs +++ b/AltReaper/WetterApp.cs @@ -40,7 +40,6 @@ public static void Main(String[] args) else { Write(Properties.Resources.ContinuingStandardMode); } string chosenLanguage = Inputs.langPreference(); - // Load language values from RESX via LanguageLoader (string apiCode, CultureInfo culture) = LanguageLoader.Load(chosenLanguage); Thread.CurrentThread.CurrentUICulture = culture; Thread.CurrentThread.CurrentCulture = culture; From bb728bfa615ee43d9dc81dcbfd690fc2c3c6c5ab Mon Sep 17 00:00:00 2001 From: Sebastian Oehm Date: Sat, 21 Feb 2026 01:33:21 +0100 Subject: [PATCH 03/19] Move easterEgg string to globalVars --- AltReaper/Helper.cs | 2 +- AltReaper/IO/Outputs.cs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/AltReaper/Helper.cs b/AltReaper/Helper.cs index a6a7706..4b5b043 100644 --- a/AltReaper/Helper.cs +++ b/AltReaper/Helper.cs @@ -15,7 +15,7 @@ public static class globalVars public static string[] devData = { Properties.Resources.AppName, Properties.Resources.DevName }; public static string baseLoc = $"{Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)}\\Reaper"; public static string cfgLoc = $"{baseLoc}\\config.json"; - + public static string easterEgg = "https://bit.ly/3Gpgiyh"; // App visible languages and mapping to OpenWeatherMap API codes / culture names. // Keep small for now: English and German only. public static string[] appLanguages = { "English", "German" }; diff --git a/AltReaper/IO/Outputs.cs b/AltReaper/IO/Outputs.cs index aa55c60..e73a7c6 100644 --- a/AltReaper/IO/Outputs.cs +++ b/AltReaper/IO/Outputs.cs @@ -53,14 +53,13 @@ public static bool MailOutput(string recipient, string subjectLine, string[] con }; //Set smtp content - string easterEgg = "https://bit.ly/3Gpgiyh"; var mailMessage = new MailMessage() { From = new MailAddress(config.senderMail), Priority = MailPriority.Low, Subject = subjectLine, IsBodyHtml = true, - Body = HtmlBody.getBody(content,easterEgg,name,config) + Body = HtmlBody.getBody(content,globalVars.easterEgg,name,config) }; //Set recipient From 8cdd440d5861c13e32e5861cef71dd8a3312c685 Mon Sep 17 00:00:00 2001 From: Sebastian Oehm Date: Sat, 21 Feb 2026 01:33:54 +0100 Subject: [PATCH 04/19] Add nullforgiving operator to config --- AltReaper/WetterApp.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AltReaper/WetterApp.cs b/AltReaper/WetterApp.cs index 2314c27..ec2166f 100644 --- a/AltReaper/WetterApp.cs +++ b/AltReaper/WetterApp.cs @@ -69,7 +69,7 @@ public static void Main(String[] args) ForegroundColor = ConsoleColor.Green; CursorVisible = false; - root weatherData = Inputs.APICall(city, apiCode, unitPreference, config.apiKey).Result; + root weatherData = Inputs.APICall(city, apiCode, unitPreference, config!.apiKey).Result; var content = Outputs.WeatherOutput(weatherData, unitPreference); From 10cab5efe55080bc081f85d046074c6bee0b2570 Mon Sep 17 00:00:00 2001 From: Sebastian Oehm Date: Sat, 21 Feb 2026 01:34:38 +0100 Subject: [PATCH 05/19] fix formatting --- AltReaper/IO/Outputs.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AltReaper/IO/Outputs.cs b/AltReaper/IO/Outputs.cs index e73a7c6..54a2ba8 100644 --- a/AltReaper/IO/Outputs.cs +++ b/AltReaper/IO/Outputs.cs @@ -59,7 +59,7 @@ public static bool MailOutput(string recipient, string subjectLine, string[] con Priority = MailPriority.Low, Subject = subjectLine, IsBodyHtml = true, - Body = HtmlBody.getBody(content,globalVars.easterEgg,name,config) + Body = HtmlBody.getBody(content, globalVars.easterEgg, name, config) }; //Set recipient From efb61f57af1bfc6349a05c516b2d0ffc80899776 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 30 Sep 2026 11:06:49 +0000 Subject: [PATCH 06/19] Bump SSH.NET from 2020.0.2 to 2026.0.0 --- updated-dependencies: - dependency-name: SSH.NET dependency-version: 2026.0.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- AltReaper/Reaper.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AltReaper/Reaper.csproj b/AltReaper/Reaper.csproj index f753279..e50b062 100644 --- a/AltReaper/Reaper.csproj +++ b/AltReaper/Reaper.csproj @@ -8,7 +8,7 @@ - + From 0619018a183ff108b26afb678b551240c8b0a8e7 Mon Sep 17 00:00:00 2001 From: Sebastian Oehm Date: Sat, 3 Oct 2026 21:48:27 +0200 Subject: [PATCH 07/19] Replace localized BCC "no" marker with yes/no menu An empty bcc now means no BCC mail. The old marker was the localized "no"/"nein", so a config written in one language crashed Bcc.Add when used in the other. Legacy "no"/"nein" values are still accepted. --- AltReaper/Checks.cs | 3 +-- AltReaper/IO/Inputs.cs | 15 ++++++++++++--- AltReaper/IO/Outputs.cs | 5 ++++- AltReaper/Properties/Resources.Designer.cs | 9 +++++++++ AltReaper/Properties/Resources.de.resx | 3 +++ AltReaper/Properties/Resources.resx | 3 +++ 6 files changed, 32 insertions(+), 6 deletions(-) diff --git a/AltReaper/Checks.cs b/AltReaper/Checks.cs index 68241bb..4c7d0eb 100644 --- a/AltReaper/Checks.cs +++ b/AltReaper/Checks.cs @@ -14,8 +14,7 @@ public static bool cfgChecker(JsonHandling.config config) string.IsNullOrEmpty(config.senderMailPassword), string.IsNullOrEmpty(config.hostDomain), string.IsNullOrEmpty(config.portNumber), - false, - string.IsNullOrEmpty(config.bcc) + false }; try { diff --git a/AltReaper/IO/Inputs.cs b/AltReaper/IO/Inputs.cs index 474ab32..27fee2b 100644 --- a/AltReaper/IO/Inputs.cs +++ b/AltReaper/IO/Inputs.cs @@ -54,9 +54,18 @@ public static bool configGen(JsonHandling.config config) ForegroundColor = ConsoleColor.White; string portNumber = ReadLine(); ForegroundColor = ConsoleColor.Green; - Write($"\nEnter the mail address of the BCC archive mail or type \"{Properties.Resources.NoOption}\" (without quotes) \n>"); - ForegroundColor = ConsoleColor.White; - string BCC = ReadLine(); + //empty bcc means no BCC mail + string BCC = ""; + string[] bccOptions = { Properties.Resources.YesOption, Properties.Resources.NoOption }; + Menu bccMenu = new(Properties.Resources.bccWanted, bccOptions); + if (bccMenu.IRExecute() == 0) + { + Write("\nEnter the mail address of the BCC archive mail\n>"); + CursorVisible = true; + ForegroundColor = ConsoleColor.White; + BCC = ReadLine(); + ForegroundColor = ConsoleColor.Green; + } CursorVisible = false; var json = new JsonHandling.config diff --git a/AltReaper/IO/Outputs.cs b/AltReaper/IO/Outputs.cs index 54a2ba8..5c9343c 100644 --- a/AltReaper/IO/Outputs.cs +++ b/AltReaper/IO/Outputs.cs @@ -66,7 +66,10 @@ public static bool MailOutput(string recipient, string subjectLine, string[] con mailMessage.To.Add(recipient); //Set bcc for analysation/archivating usage - if (config.bcc == Properties.Resources.NoOption) { } + //empty bcc means no BCC mail. Older configs stored the localized "no" instead, so accept that of every app language + bool noBcc = string.IsNullOrWhiteSpace(config.bcc) || globalVars.appToCulture.Values.Any(c => + config.bcc == Properties.Resources.ResourceManager.GetString(nameof(Properties.Resources.NoOption), new System.Globalization.CultureInfo(c))); + if (noBcc) { } else { mailMessage.Bcc.Add(config.bcc); } //sending diff --git a/AltReaper/Properties/Resources.Designer.cs b/AltReaper/Properties/Resources.Designer.cs index 87591e7..30824c9 100644 --- a/AltReaper/Properties/Resources.Designer.cs +++ b/AltReaper/Properties/Resources.Designer.cs @@ -280,6 +280,15 @@ public static string mailSuccessMessage { } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Do you want to send a BCC archive mail? ähnelt. + /// + public static string bccWanted { + get { + return ResourceManager.GetString("bccWanted", resourceCulture); + } + } + /// /// Sucht eine lokalisierte Zeichenfolge, die Do you want this as a mail? ähnelt. /// diff --git a/AltReaper/Properties/Resources.de.resx b/AltReaper/Properties/Resources.de.resx index 7fa06d0..9ec12db 100644 --- a/AltReaper/Properties/Resources.de.resx +++ b/AltReaper/Properties/Resources.de.resx @@ -245,6 +245,9 @@ Bitte verbinden Sie Ihr Gerät mit dem Internet, um diese Anwendung zu benutzen. Ihre Wetterinformationen + + Möchten Sie eine BCC-Archiv-E-Mail senden? + Möchten Sie dies per E-Mail erhalten? diff --git a/AltReaper/Properties/Resources.resx b/AltReaper/Properties/Resources.resx index 989aba3..6dab90c 100644 --- a/AltReaper/Properties/Resources.resx +++ b/AltReaper/Properties/Resources.resx @@ -247,6 +247,9 @@ The following Exception was raised : {0} your weather info + + Do you want to send a BCC archive mail? + Do you want this as a mail? From 3c3e83086eafca08b1b2ae37e975c585125a21dd Mon Sep 17 00:00:00 2001 From: Sebastian Oehm Date: Sat, 3 Oct 2026 21:54:11 +0200 Subject: [PATCH 08/19] Remove unused language list resources --- AltReaper/Helper.cs | 6 +----- AltReaper/Properties/Resources.Designer.cs | 19 ------------------- AltReaper/Properties/Resources.de.resx | 6 ------ AltReaper/Properties/Resources.resx | 6 ------ 4 files changed, 1 insertion(+), 36 deletions(-) diff --git a/AltReaper/Helper.cs b/AltReaper/Helper.cs index 4b5b043..544ce22 100644 --- a/AltReaper/Helper.cs +++ b/AltReaper/Helper.cs @@ -7,11 +7,7 @@ namespace Reaper { public static class globalVars { - // Load language lists and application metadata from resources (null-safe) - public static string[] fullySupportedLanguages = (Properties.Resources.ResourceManager.GetString("FullySupportedLanguages") ?? string.Empty) - .Split('|', StringSplitOptions.RemoveEmptyEntries); - public static string[] supportedShortCodes = (Properties.Resources.ResourceManager.GetString("SupportedShortCodes") ?? string.Empty) - .Split('|', StringSplitOptions.RemoveEmptyEntries); + // Load application metadata from resources public static string[] devData = { Properties.Resources.AppName, Properties.Resources.DevName }; public static string baseLoc = $"{Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)}\\Reaper"; public static string cfgLoc = $"{baseLoc}\\config.json"; diff --git a/AltReaper/Properties/Resources.Designer.cs b/AltReaper/Properties/Resources.Designer.cs index 30824c9..47d394d 100644 --- a/AltReaper/Properties/Resources.Designer.cs +++ b/AltReaper/Properties/Resources.Designer.cs @@ -199,15 +199,6 @@ public static string ExceptionRaisedFormat { } } - /// - /// Sucht eine lokalisierte Zeichenfolge, die afrikaans|albanian|arabic|azerbaijani|bulgarian|catalan|czech|danish|german|greek|english|basque|persian|farsi|finnish|french|galician|Hebrew|hindi|croatian|hungarian|indonesian|italian|japanese|korean|latvian|lithuanian|macedonian|norwegian|dutch|polish|portuguese|romanian|russian|swedish|slovak|slovenian|spanish|serbian|thai|turkish|ukrainian|vietnamese|chinese simplified|chinese traditional|zulu ähnelt. - /// - public static string FullySupportedLanguages { - get { - return ResourceManager.GetString("FullySupportedLanguages", resourceCulture); - } - } - /// /// Sucht eine lokalisierte Zeichenfolge, die highest temperature ähnelt. /// @@ -388,16 +379,6 @@ public static string SuperUserQuestion { } } - /// - /// Sucht eine lokalisierte Zeichenfolge, die af|al|ar|az|bg|ca|cz|da|de|el|en|eu|fa|fa|fi|fr|gl|he|hi|hr|hu|id|it|ja|kr|la|lt|mk|no|nl|pl|pt|pt_br|ro|ru|se|sk|sl|sr|th|tr|ua|vi|zh_cn|zh_tw|zu ähnelt. - /// - public static string SupportedShortCodes { - get { - return ResourceManager.GetString("SupportedShortCodes", resourceCulture); - } - } - - /// /// Sucht eine lokalisierte Zeichenfolge, die temperature ähnelt. /// public static string temp { diff --git a/AltReaper/Properties/Resources.de.resx b/AltReaper/Properties/Resources.de.resx index 9ec12db..c772e8d 100644 --- a/AltReaper/Properties/Resources.de.resx +++ b/AltReaper/Properties/Resources.de.resx @@ -158,12 +158,6 @@ Bitte verbinden Sie Ihr Gerät mit dem Internet, um diese Anwendung zu benutzen. Wird im Standardmodus fortgesetzt - - afrikaans|albanian|arabic|azerbaijani|bulgarian|catalan|czech|danish|german|greek|english|basque|persian|farsi|finnish|french|galician|Hebrew|hindi|croatian|hungarian|indonesian|italian|japanese|korean|latvian|lithuanian|macedonian|norwegian|dutch|polish|portuguese|romanian|russian|swedish|slovak|slovenian|spanish|serbian|thai|turkish|ukrainian|vietnamese|chinese simplified|chinese traditional|zulu - - - af|al|ar|az|bg|ca|cz|da|de|el|en|eu|fa|fa|fi|fr|gl|he|hi|hr|hu|id|it|ja|kr|la|lt|mk|no|nl|pl|pt|pt_br|ro|ru|se|sk|sl|sr|th|tr|ua|vi|zh_cn|zh_tw|zu - Reaper diff --git a/AltReaper/Properties/Resources.resx b/AltReaper/Properties/Resources.resx index 6dab90c..1bc2cdc 100644 --- a/AltReaper/Properties/Resources.resx +++ b/AltReaper/Properties/Resources.resx @@ -160,12 +160,6 @@ The following Exception was raised : {0} Continuing in standard mode - - afrikaans|albanian|arabic|azerbaijani|bulgarian|catalan|czech|danish|german|greek|english|basque|persian|farsi|finnish|french|galician|Hebrew|hindi|croatian|hungarian|indonesian|italian|japanese|korean|latvian|lithuanian|macedonian|norwegian|dutch|polish|portuguese|romanian|russian|swedish|slovak|slovenian|spanish|serbian|thai|turkish|ukrainian|vietnamese|chinese simplified|chinese traditional|zulu - - - af|al|ar|az|bg|ca|cz|da|de|el|en|eu|fa|fa|fi|fr|gl|he|hi|hr|hu|id|it|ja|kr|la|lt|mk|no|nl|pl|pt|pt_br|ro|ru|se|sk|sl|sr|th|tr|ua|vi|zh_cn|zh_tw|zu - Reaper From 7639d565f22f02b0695277c032d865ae4a36d1e0 Mon Sep 17 00:00:00 2001 From: Sebastian Oehm Date: Sat, 3 Oct 2026 22:02:35 +0200 Subject: [PATCH 09/19] Fix IDE1006 naming violations in types, methods and properties Properties keep their JSON keys through JsonPropertyName. --- AltReaper/Checks.cs | 14 ++--- AltReaper/Helper.cs | 26 ++++----- AltReaper/HtmlBody.cs | 4 +- AltReaper/IO/Inputs.cs | 54 +++++++++---------- AltReaper/IO/LanguageLoader.cs | 8 +-- AltReaper/IO/Outputs.cs | 30 +++++------ AltReaper/JsonHandling.cs | 96 ++++++++++++++++++++++------------ AltReaper/WetterApp.cs | 8 +-- 8 files changed, 134 insertions(+), 106 deletions(-) diff --git a/AltReaper/Checks.cs b/AltReaper/Checks.cs index 4c7d0eb..f5e1e96 100644 --- a/AltReaper/Checks.cs +++ b/AltReaper/Checks.cs @@ -6,19 +6,19 @@ namespace Reaper { internal class Checks { - public static bool cfgChecker(JsonHandling.config config) + public static bool CfgChecker(JsonHandling.Config config) { bool[] bools = { - string.IsNullOrEmpty(config.apiKey), - string.IsNullOrEmpty(config.senderMail), - string.IsNullOrEmpty(config.senderMailPassword), - string.IsNullOrEmpty(config.hostDomain), - string.IsNullOrEmpty(config.portNumber), + string.IsNullOrEmpty(config.ApiKey), + string.IsNullOrEmpty(config.SenderMail), + string.IsNullOrEmpty(config.SenderMailPassword), + string.IsNullOrEmpty(config.HostDomain), + string.IsNullOrEmpty(config.PortNumber), false }; try { - if (int.Parse(config.portNumber) < 0 || int.Parse(config.portNumber) > 65535) + if (int.Parse(config.PortNumber) < 0 || int.Parse(config.PortNumber) > 65535) { bools[5] = true; } } catch { return true; } diff --git a/AltReaper/Helper.cs b/AltReaper/Helper.cs index 544ce22..13f5c26 100644 --- a/AltReaper/Helper.cs +++ b/AltReaper/Helper.cs @@ -5,7 +5,7 @@ namespace Reaper { - public static class globalVars + public static class GlobalVars { // Load application metadata from resources public static string[] devData = { Properties.Resources.AppName, Properties.Resources.DevName }; @@ -29,7 +29,7 @@ public static class globalVars } internal class Helper { - public static void MailOption(JsonHandling.config config, String[] content) + public static void MailOption(JsonHandling.Config config, String[] content) { string[] mailOptions = { Properties.Resources.YesOption, Properties.Resources.NoOption }; Menu mailMenu = new(Properties.Resources.mailWanted, mailOptions); @@ -39,10 +39,10 @@ public static void MailOption(JsonHandling.config config, String[] content) bool partSuccess = false; while (!partSuccess) { - if (Checks.cfgChecker(config)) + if (Checks.CfgChecker(config)) { - Inputs.configGen(config); - config = JsonSerializer.Deserialize(File.ReadAllText(globalVars.cfgLoc)); + Inputs.ConfigGen(config); + config = JsonSerializer.Deserialize(File.ReadAllText(GlobalVars.cfgLoc)); } Write($"\n{Properties.Resources.mailAddressQuery}\n>"); CursorVisible = true; @@ -103,34 +103,34 @@ public static void SuperUserMode(String superUserPwd, String appName, string dir public static void Closer() { Uninstaller(); - WriteLine(string.Format(Properties.Resources.ThankYouFormat, globalVars.devData[0])); + WriteLine(string.Format(Properties.Resources.ThankYouFormat, GlobalVars.devData[0])); WriteLine(Properties.Resources.WeatherPoweredBy); - WriteLine(string.Format(Properties.Resources.BylineFormat, globalVars.devData[0], globalVars.devData[1])); + WriteLine(string.Format(Properties.Resources.BylineFormat, GlobalVars.devData[0], GlobalVars.devData[1])); WriteLine(Properties.Resources.PressAnyKeyExit); ReadKey(true); Environment.Exit(0); } - public static void Closer(JsonHandling.config config) + public static void Closer(JsonHandling.Config config) { WriteLine($"{Properties.Resources.mailSuccessMessage}"); Uninstaller(); - WriteLine(string.Format(Properties.Resources.ThankYouFormat, globalVars.devData[0])); + WriteLine(string.Format(Properties.Resources.ThankYouFormat, GlobalVars.devData[0])); WriteLine(Properties.Resources.WeatherPoweredBy); - WriteLine(string.Format(Properties.Resources.MailPoweredByFormat, config.senderMail.Split('@')[1])); - WriteLine(string.Format(Properties.Resources.BylineFormat, globalVars.devData[0], globalVars.devData[1])); + WriteLine(string.Format(Properties.Resources.MailPoweredByFormat, config.SenderMail.Split('@')[1])); + WriteLine(string.Format(Properties.Resources.BylineFormat, GlobalVars.devData[0], GlobalVars.devData[1])); WriteLine(Properties.Resources.PressAnyKeyExit); ReadKey(true); Environment.Exit(0); } public static void Uninstaller() { - string uninstallPrompt = string.Format(Properties.Resources.UninstallPromptFormat, globalVars.devData[0]); + string uninstallPrompt = string.Format(Properties.Resources.UninstallPromptFormat, GlobalVars.devData[0]); string[] uninstallOptions = { Properties.Resources.YesOption, Properties.Resources.NoOption }; Menu uninstallMenu = new(uninstallPrompt, uninstallOptions); int uninstallChoice = uninstallMenu.IRExecute(); if (uninstallChoice == 0) { - Directory.Delete(globalVars.baseLoc, true); + Directory.Delete(GlobalVars.baseLoc, true); } } } diff --git a/AltReaper/HtmlBody.cs b/AltReaper/HtmlBody.cs index a40d798..396cacf 100644 --- a/AltReaper/HtmlBody.cs +++ b/AltReaper/HtmlBody.cs @@ -2,7 +2,7 @@ { internal class HtmlBody { - public static string getBody(string[] content, string easterEgg, string name, JsonHandling.config config) + public static string GetBody(string[] content, string easterEgg, string name, JsonHandling.Config config) { string htmlBody = $"\r\n" + @@ -19,7 +19,7 @@ public static string getBody(string[] content, string easterEgg, string name, Js $"\r\n\r\n\r\n\r\n" + $"
\r\n\r\n\r\n\r\n \r\n \r\n " + - $"\r\n \r\n
\r\n" + $"
Don't like these emails? Unsubscribe.\r\n
\r\n Powered by htmlemail & {config.senderMail.Split('@')[1].Split('.')[0]}.\r\n
\r\n " + + $"\r\n Powered by htmlemail & {config.SenderMail.Split('@')[1].Split('.')[0]}.\r\n \r\n \r\n \r\n " + $"
\r\n \r\n\r\n\r\n" + $"\r\n  \r\n\r\n\r\n" + $"\r\n" + diff --git a/AltReaper/IO/Inputs.cs b/AltReaper/IO/Inputs.cs index 27fee2b..79cd9d6 100644 --- a/AltReaper/IO/Inputs.cs +++ b/AltReaper/IO/Inputs.cs @@ -16,7 +16,7 @@ namespace Reaper.IO { internal class Inputs { - public static async Task APICall(string city, string langPreferenceShort, string unitPreference, string APIKey) + public static async Task APICall(string city, string langPreferenceShort, string unitPreference, string APIKey) { //Use default system proxy settings IWebProxy defaultWebProxy = WebRequest.DefaultWebProxy; @@ -30,15 +30,15 @@ internal class Inputs BaseAddress = new Uri("https://api.openweathermap.org/data/2.5/"), }; - return await client.GetFromJsonAsync($"weather?q={city}&lang={langPreferenceShort}&units={unitPreference}&appid={APIKey}"); + return await client.GetFromJsonAsync($"weather?q={city}&lang={langPreferenceShort}&units={unitPreference}&appid={APIKey}"); } - public static bool configGen(JsonHandling.config config) + public static bool ConfigGen(JsonHandling.Config config) { //checks if config file exists and if all lines have information - if (File.Exists(globalVars.cfgLoc) && Checks.cfgChecker(config) == false) { return true; } + if (File.Exists(GlobalVars.cfgLoc) && Checks.CfgChecker(config) == false) { return true; } - string apiKey = config.apiKey; + string apiKey = config.ApiKey; Write("\nEnter the mail address which you want use to send mails\n>"); CursorVisible = true; ForegroundColor = ConsoleColor.White; @@ -68,16 +68,16 @@ public static bool configGen(JsonHandling.config config) } CursorVisible = false; - var json = new JsonHandling.config + var json = new JsonHandling.Config { - apiKey = apiKey, - senderMail = senderMail, - senderMailPassword = senderMailPassword, - hostDomain = hostDomain, - portNumber = portNumber, - bcc = BCC + ApiKey = apiKey, + SenderMail = senderMail, + SenderMailPassword = senderMailPassword, + HostDomain = hostDomain, + PortNumber = portNumber, + Bcc = BCC }; - File.WriteAllText(globalVars.cfgLoc, JsonSerializer.Serialize(json)); + File.WriteAllText(GlobalVars.cfgLoc, JsonSerializer.Serialize(json)); return true; } public static string UnitPreference() @@ -89,29 +89,29 @@ public static string UnitPreference() } public static void ConfigGetter() { - JsonHandling.config test = null; - try { test = JsonSerializer.Deserialize(File.ReadAllText(globalVars.cfgLoc)); } - catch { File.Delete(globalVars.cfgLoc); } - if (!File.Exists(globalVars.cfgLoc)) + JsonHandling.Config test = null; + try { test = JsonSerializer.Deserialize(File.ReadAllText(GlobalVars.cfgLoc)); } + catch { File.Delete(GlobalVars.cfgLoc); } + if (!File.Exists(GlobalVars.cfgLoc)) { Write("\nEnter your APIKey\n>"); string apiKey = ReadLine(); - var tmp = new JsonHandling.config + var tmp = new JsonHandling.Config { - apiKey = apiKey, - senderMail = "", - senderMailPassword = "", - hostDomain = "", - portNumber = "", - bcc = "" + ApiKey = apiKey, + SenderMail = "", + SenderMailPassword = "", + HostDomain = "", + PortNumber = "", + Bcc = "" }; - File.WriteAllText(globalVars.cfgLoc, JsonSerializer.Serialize(tmp)); + File.WriteAllText(GlobalVars.cfgLoc, JsonSerializer.Serialize(tmp)); } } - public static string langPreference() + public static string LangPreference() { List availableLanguages = new(); - foreach (string l in globalVars.appLanguages) + foreach (string l in GlobalVars.appLanguages) { availableLanguages.Add(l); } diff --git a/AltReaper/IO/LanguageLoader.cs b/AltReaper/IO/LanguageLoader.cs index 2d8aaa7..4338c00 100644 --- a/AltReaper/IO/LanguageLoader.cs +++ b/AltReaper/IO/LanguageLoader.cs @@ -12,15 +12,15 @@ public static (string apiCode, CultureInfo culture) Load(string selectedLanguage // Determine culture name and API code using app-level mappings string cultureName = "en"; - if (Reaper.globalVars.appToCulture != null && Reaper.globalVars.appToCulture.ContainsKey(selectedDisplay)) + if (Reaper.GlobalVars.appToCulture != null && Reaper.GlobalVars.appToCulture.ContainsKey(selectedDisplay)) { - cultureName = Reaper.globalVars.appToCulture[selectedDisplay]; + cultureName = Reaper.GlobalVars.appToCulture[selectedDisplay]; } string apiCode = "en"; - if (Reaper.globalVars.appToApiCode != null && Reaper.globalVars.appToApiCode.ContainsKey(selectedDisplay)) + if (Reaper.GlobalVars.appToApiCode != null && Reaper.GlobalVars.appToApiCode.ContainsKey(selectedDisplay)) { - apiCode = Reaper.globalVars.appToApiCode[selectedDisplay]; + apiCode = Reaper.GlobalVars.appToApiCode[selectedDisplay]; } CultureInfo culture = CultureInfo.InvariantCulture; diff --git a/AltReaper/IO/Outputs.cs b/AltReaper/IO/Outputs.cs index 5c9343c..b96d2de 100644 --- a/AltReaper/IO/Outputs.cs +++ b/AltReaper/IO/Outputs.cs @@ -6,12 +6,12 @@ namespace Reaper.IO { internal class Outputs { - public static string[] WeatherOutput(WeatherResponse.root weatherData, string unitPreference) + public static string[] WeatherOutput(WeatherResponse.Root weatherData, string unitPreference) { //time & timezones, units char unitSymbol; DateTime localSystemTime = DateTime.Now; - int timeZoneShiftFromUTC = weatherData.timezone / 3600; + int timeZoneShiftFromUTC = weatherData.Timezone / 3600; string timezoneUTC; DateTime locTime = DateTime.UtcNow.AddHours(timeZoneShiftFromUTC); timezoneUTC = timeZoneShiftFromUTC >= 0 ? $"UTC+{timeZoneShiftFromUTC}" : $"UTC{timeZoneShiftFromUTC}" ; @@ -21,13 +21,13 @@ public static string[] WeatherOutput(WeatherResponse.root weatherData, string un List content = new(); string spacer = "\n-------------------------------------\n"; content.Add(spacer); - content.Add($"{Properties.Resources.theWeatherIn}: {weatherData.name}, {weatherData.sys.country}"); + content.Add($"{Properties.Resources.theWeatherIn}: {weatherData.Name}, {weatherData.Sys.Country}"); content.Add($"{Properties.Resources.localSystemTime}: {localSystemTime}"); content.Add($"{Properties.Resources.timeAtDestination}: : {locTime} {timezoneUTC} "); - content.Add($"{Properties.Resources.temp}: {weatherData.main.temp:0.#}°{unitSymbol}"); - content.Add($"{Properties.Resources.lowestTemp}: {weatherData.main.temp_min:0.#}°{unitSymbol}"); - content.Add($"{Properties.Resources.highestTemp}: {weatherData.main.temp_max:0.#}°{unitSymbol}"); - content.Add($"{Properties.Resources.description}: {weatherData.weather[0].description}"); + content.Add($"{Properties.Resources.temp}: {weatherData.Main.Temp:0.#}°{unitSymbol}"); + content.Add($"{Properties.Resources.lowestTemp}: {weatherData.Main.TempMin:0.#}°{unitSymbol}"); + content.Add($"{Properties.Resources.highestTemp}: {weatherData.Main.TempMax:0.#}°{unitSymbol}"); + content.Add($"{Properties.Resources.description}: {weatherData.Weather[0].Description}"); content.Add(spacer); string[] cArray = content.ToArray(); WriteLine(string.Join("\r\n", cArray)); @@ -35,7 +35,7 @@ public static string[] WeatherOutput(WeatherResponse.root weatherData, string un while (ReadKey(true).Key != ConsoleKey.Enter) { continue; } return cArray; } - public static bool MailOutput(string recipient, string subjectLine, string[] content, JsonHandling.config config) + public static bool MailOutput(string recipient, string subjectLine, string[] content, JsonHandling.Config config) { //Set salutation Write($"\n{Properties.Resources.nameOr}\n>"); @@ -46,20 +46,20 @@ public static bool MailOutput(string recipient, string subjectLine, string[] con ForegroundColor = ConsoleColor.Green; CursorVisible = false; //Set smtp config - var smtpClient = new SmtpClient(config.hostDomain, int.Parse(config.portNumber)) + var smtpClient = new SmtpClient(config.HostDomain, int.Parse(config.PortNumber)) { - Credentials = new NetworkCredential(config.senderMail, config.senderMailPassword), + Credentials = new NetworkCredential(config.SenderMail, config.SenderMailPassword), EnableSsl = true, }; //Set smtp content var mailMessage = new MailMessage() { - From = new MailAddress(config.senderMail), + From = new MailAddress(config.SenderMail), Priority = MailPriority.Low, Subject = subjectLine, IsBodyHtml = true, - Body = HtmlBody.getBody(content, globalVars.easterEgg, name, config) + Body = HtmlBody.GetBody(content, GlobalVars.easterEgg, name, config) }; //Set recipient @@ -67,10 +67,10 @@ public static bool MailOutput(string recipient, string subjectLine, string[] con //Set bcc for analysation/archivating usage //empty bcc means no BCC mail. Older configs stored the localized "no" instead, so accept that of every app language - bool noBcc = string.IsNullOrWhiteSpace(config.bcc) || globalVars.appToCulture.Values.Any(c => - config.bcc == Properties.Resources.ResourceManager.GetString(nameof(Properties.Resources.NoOption), new System.Globalization.CultureInfo(c))); + bool noBcc = string.IsNullOrWhiteSpace(config.Bcc) || GlobalVars.appToCulture.Values.Any(c => + config.Bcc == Properties.Resources.ResourceManager.GetString(nameof(Properties.Resources.NoOption), new System.Globalization.CultureInfo(c))); if (noBcc) { } - else { mailMessage.Bcc.Add(config.bcc); } + else { mailMessage.Bcc.Add(config.Bcc); } //sending try { smtpClient.Send(mailMessage); } diff --git a/AltReaper/JsonHandling.cs b/AltReaper/JsonHandling.cs index 462c080..3b19d0f 100644 --- a/AltReaper/JsonHandling.cs +++ b/AltReaper/JsonHandling.cs @@ -1,57 +1,85 @@ - +using System.Text.Json.Serialization; + namespace Reaper { internal static class JsonHandling { - public class config + public class Config { - public string apiKey { get; set; } - public string senderMail { get; set; } + [JsonPropertyName("apiKey")] + public string ApiKey { get; set; } + [JsonPropertyName("senderMail")] + public string SenderMail { get; set; } - public string senderMailPassword { get; set; } - public string hostDomain { get; set; } - public string portNumber { get; set; } - public string bcc { get; set; } + [JsonPropertyName("senderMailPassword")] + public string SenderMailPassword { get; set; } + [JsonPropertyName("hostDomain")] + public string HostDomain { get; set; } + [JsonPropertyName("portNumber")] + public string PortNumber { get; set; } + [JsonPropertyName("bcc")] + public string Bcc { get; set; } } } public static class WeatherResponse { - public class weather + public class Weather { - public string description { get; set; } - public string main { get; set; } - public string icon { get; set; } + [JsonPropertyName("description")] + public string Description { get; set; } + [JsonPropertyName("main")] + public string Main { get; set; } + [JsonPropertyName("icon")] + public string Icon { get; set; } } - public class main + public class Main { - public double temp { get; set; } - public double temp_min { get; set; } - public double temp_max { get; set; } - public double feels_like { get; set; } - public int pressure { get; set; } - public int humidity { get; set; } + [JsonPropertyName("temp")] + public double Temp { get; set; } + [JsonPropertyName("temp_min")] + public double TempMin { get; set; } + [JsonPropertyName("temp_max")] + public double TempMax { get; set; } + [JsonPropertyName("feels_like")] + public double FeelsLike { get; set; } + [JsonPropertyName("pressure")] + public int Pressure { get; set; } + [JsonPropertyName("humidity")] + public int Humidity { get; set; } } - public class sys + public class Sys { - public long sunrise { get; set; } - public long sunset { get; set; } - public string country { get; set; } + [JsonPropertyName("sunrise")] + public long Sunrise { get; set; } + [JsonPropertyName("sunset")] + public long Sunset { get; set; } + [JsonPropertyName("country")] + public string Country { get; set; } } - public class wind + public class Wind { - public double speed { get; set; } - public int deg { get; set; } + [JsonPropertyName("speed")] + public double Speed { get; set; } + [JsonPropertyName("deg")] + public int Deg { get; set; } } - public class root + public class Root { - public List weather { get; set; } - public main main { get; set; } - public sys sys { get; set; } - public wind wind { get; set; } - public long dt { get; set; } - public int timezone { get; set; } - public string name { get; set; } + [JsonPropertyName("weather")] + public List Weather { get; set; } + [JsonPropertyName("main")] + public Main Main { get; set; } + [JsonPropertyName("sys")] + public Sys Sys { get; set; } + [JsonPropertyName("wind")] + public Wind Wind { get; set; } + [JsonPropertyName("dt")] + public long Dt { get; set; } + [JsonPropertyName("timezone")] + public int Timezone { get; set; } + [JsonPropertyName("name")] + public string Name { get; set; } } } } \ No newline at end of file diff --git a/AltReaper/WetterApp.cs b/AltReaper/WetterApp.cs index ec2166f..2636aea 100644 --- a/AltReaper/WetterApp.cs +++ b/AltReaper/WetterApp.cs @@ -31,7 +31,7 @@ public static void Main(String[] args) { try { - Helper.SuperUserMode(Helper.PasswordMaker(), Properties.Resources.AppName, globalVars.baseLoc); + Helper.SuperUserMode(Helper.PasswordMaker(), Properties.Resources.AppName, GlobalVars.baseLoc); break; } catch { Write("\n" + Properties.Resources.ErrorRetypePassword + "\n>"); continue; } @@ -39,13 +39,13 @@ public static void Main(String[] args) } else { Write(Properties.Resources.ContinuingStandardMode); } - string chosenLanguage = Inputs.langPreference(); + string chosenLanguage = Inputs.LangPreference(); (string apiCode, CultureInfo culture) = LanguageLoader.Load(chosenLanguage); Thread.CurrentThread.CurrentUICulture = culture; Thread.CurrentThread.CurrentCulture = culture; Inputs.ConfigGetter(); - config config = JsonSerializer.Deserialize(File.ReadAllText(globalVars.cfgLoc)); + Config config = JsonSerializer.Deserialize(File.ReadAllText(GlobalVars.cfgLoc)); string unitPreference = Inputs.UnitPreference(); @@ -69,7 +69,7 @@ public static void Main(String[] args) ForegroundColor = ConsoleColor.Green; CursorVisible = false; - root weatherData = Inputs.APICall(city, apiCode, unitPreference, config!.apiKey).Result; + Root weatherData = Inputs.APICall(city, apiCode, unitPreference, config!.ApiKey).Result; var content = Outputs.WeatherOutput(weatherData, unitPreference); From 0e57bd18c5da89333937688d49b74ca85ab88d65 Mon Sep 17 00:00:00 2001 From: Sebastian Oehm Date: Sat, 3 Oct 2026 22:14:30 +0200 Subject: [PATCH 10/19] Fix remaining IDE0044, IDE0059 and IDE0060 violations Use the proxy handler in APICall instead of leaving it unused. --- AltReaper/Checks.cs | 4 ++-- AltReaper/IO/Inputs.cs | 8 +++++--- AltReaper/WetterApp.cs | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/AltReaper/Checks.cs b/AltReaper/Checks.cs index f5e1e96..f9ba983 100644 --- a/AltReaper/Checks.cs +++ b/AltReaper/Checks.cs @@ -87,8 +87,8 @@ public static void APIisOnline() class Menu { private int Index; - private string[] Options; - private string InputPrompt; + private readonly string[] Options; + private readonly string InputPrompt; public Menu(string inputPrompt, string[] options) { InputPrompt = inputPrompt; diff --git a/AltReaper/IO/Inputs.cs b/AltReaper/IO/Inputs.cs index 79cd9d6..c641113 100644 --- a/AltReaper/IO/Inputs.cs +++ b/AltReaper/IO/Inputs.cs @@ -25,7 +25,7 @@ internal class Inputs { Proxy = defaultWebProxy, }; - HttpClient client = new() + HttpClient client = new(handler) { BaseAddress = new Uri("https://api.openweathermap.org/data/2.5/"), }; @@ -89,8 +89,10 @@ public static string UnitPreference() } public static void ConfigGetter() { - JsonHandling.Config test = null; - try { test = JsonSerializer.Deserialize(File.ReadAllText(GlobalVars.cfgLoc)); } + try + { + _ = JsonSerializer.Deserialize(File.ReadAllText(GlobalVars.cfgLoc)); + } catch { File.Delete(GlobalVars.cfgLoc); } if (!File.Exists(GlobalVars.cfgLoc)) { diff --git a/AltReaper/WetterApp.cs b/AltReaper/WetterApp.cs index 2636aea..32403c7 100644 --- a/AltReaper/WetterApp.cs +++ b/AltReaper/WetterApp.cs @@ -9,7 +9,7 @@ namespace Reaper { public static class Program { - public static void Main(String[] args) + public static void Main() { Title = string.Format(Properties.Resources.AppTitleFormat, Properties.Resources.AppName, Properties.Resources.VersionNumber); From 93babd5ffd7f9ca5dabbdd991ace92ac3deaa7e6 Mon Sep 17 00:00:00 2001 From: Sebastian Oehm Date: Sat, 3 Oct 2026 22:16:33 +0200 Subject: [PATCH 11/19] Make GlobalVars fields readonly to fix CA2211 --- AltReaper/Helper.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/AltReaper/Helper.cs b/AltReaper/Helper.cs index 13f5c26..b224adb 100644 --- a/AltReaper/Helper.cs +++ b/AltReaper/Helper.cs @@ -8,20 +8,20 @@ namespace Reaper public static class GlobalVars { // Load application metadata from resources - public static string[] devData = { Properties.Resources.AppName, Properties.Resources.DevName }; - public static string baseLoc = $"{Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)}\\Reaper"; - public static string cfgLoc = $"{baseLoc}\\config.json"; - public static string easterEgg = "https://bit.ly/3Gpgiyh"; + public static readonly string[] devData = { Properties.Resources.AppName, Properties.Resources.DevName }; + public static readonly string baseLoc = $"{Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)}\\Reaper"; + public static readonly string cfgLoc = $"{baseLoc}\\config.json"; + public static readonly string easterEgg = "https://bit.ly/3Gpgiyh"; // App visible languages and mapping to OpenWeatherMap API codes / culture names. // Keep small for now: English and German only. - public static string[] appLanguages = { "English", "German" }; - public static Dictionary appToApiCode = new() + public static readonly string[] appLanguages = { "English", "German" }; + public static readonly Dictionary appToApiCode = new() { { "English", "en" }, { "German", "de" } }; // Map app language display -> culture name used for ResourceManager lookups (use BCP-47 style) - public static Dictionary appToCulture = new() + public static readonly Dictionary appToCulture = new() { { "English", "en" }, { "German", "de" } From 179c6c7c5b9be56bd7e730b5609e155ede794d8d Mon Sep 17 00:00:00 2001 From: Sebastian Oehm Date: Sat, 3 Oct 2026 22:18:19 +0200 Subject: [PATCH 12/19] Bump target framework from net6.0 to net8.0 --- AltReaper/Reaper.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AltReaper/Reaper.csproj b/AltReaper/Reaper.csproj index e50b062..fc318ce 100644 --- a/AltReaper/Reaper.csproj +++ b/AltReaper/Reaper.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net8.0 enable enable From 996a678f4b2e3c105c23926bd77634c0c00eed51 Mon Sep 17 00:00:00 2001 From: Sebastian Oehm Date: Sat, 3 Oct 2026 22:19:59 +0200 Subject: [PATCH 13/19] Use TryGetValue in LanguageLoader to fix CA1854 --- AltReaper/IO/LanguageLoader.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/AltReaper/IO/LanguageLoader.cs b/AltReaper/IO/LanguageLoader.cs index 4338c00..81cacb9 100644 --- a/AltReaper/IO/LanguageLoader.cs +++ b/AltReaper/IO/LanguageLoader.cs @@ -11,16 +11,14 @@ public static (string apiCode, CultureInfo culture) Load(string selectedLanguage string selectedDisplay = string.IsNullOrEmpty(selectedLanguageDisplay) ? "English" : selectedLanguageDisplay; // Determine culture name and API code using app-level mappings - string cultureName = "en"; - if (Reaper.GlobalVars.appToCulture != null && Reaper.GlobalVars.appToCulture.ContainsKey(selectedDisplay)) + if (!Reaper.GlobalVars.appToCulture.TryGetValue(selectedDisplay, out string? cultureName)) { - cultureName = Reaper.GlobalVars.appToCulture[selectedDisplay]; + cultureName = "en"; } - string apiCode = "en"; - if (Reaper.GlobalVars.appToApiCode != null && Reaper.GlobalVars.appToApiCode.ContainsKey(selectedDisplay)) + if (!Reaper.GlobalVars.appToApiCode.TryGetValue(selectedDisplay, out string? apiCode)) { - apiCode = Reaper.GlobalVars.appToApiCode[selectedDisplay]; + apiCode = "en"; } CultureInfo culture = CultureInfo.InvariantCulture; From 6b7fad020f96e3afea1cc02c117c47886916dadd Mon Sep 17 00:00:00 2001 From: Sebastian Oehm Date: Sat, 3 Oct 2026 22:22:58 +0200 Subject: [PATCH 14/19] Apply collection expressions and primary constructor suggestions Fixes IDE0028, IDE0290, IDE0300 and IDE0305. --- AltReaper/Checks.cs | 19 +++++++------------ AltReaper/Helper.cs | 8 ++++---- AltReaper/IO/Inputs.cs | 12 ++++-------- AltReaper/IO/Outputs.cs | 4 ++-- AltReaper/WetterApp.cs | 2 +- 5 files changed, 18 insertions(+), 27 deletions(-) diff --git a/AltReaper/Checks.cs b/AltReaper/Checks.cs index f9ba983..17fee45 100644 --- a/AltReaper/Checks.cs +++ b/AltReaper/Checks.cs @@ -8,14 +8,14 @@ internal class Checks { public static bool CfgChecker(JsonHandling.Config config) { - bool[] bools = { + bool[] bools = [ string.IsNullOrEmpty(config.ApiKey), string.IsNullOrEmpty(config.SenderMail), string.IsNullOrEmpty(config.SenderMailPassword), string.IsNullOrEmpty(config.HostDomain), string.IsNullOrEmpty(config.PortNumber), false - }; + ]; try { if (int.Parse(config.PortNumber) < 0 || int.Parse(config.PortNumber) > 65535) @@ -84,17 +84,12 @@ public static void APIisOnline() } } } - class Menu + class Menu(string inputPrompt, string[] options) { - private int Index; - private readonly string[] Options; - private readonly string InputPrompt; - public Menu(string inputPrompt, string[] options) - { - InputPrompt = inputPrompt; - Options = options; - Index = 0; - } + private int Index = 0; + private readonly string[] Options = options; + private readonly string InputPrompt = inputPrompt; + public void DisplayAvailableOptions() { Console.WriteLine(InputPrompt); diff --git a/AltReaper/Helper.cs b/AltReaper/Helper.cs index b224adb..ce9e7c0 100644 --- a/AltReaper/Helper.cs +++ b/AltReaper/Helper.cs @@ -8,13 +8,13 @@ namespace Reaper public static class GlobalVars { // Load application metadata from resources - public static readonly string[] devData = { Properties.Resources.AppName, Properties.Resources.DevName }; + public static readonly string[] devData = [Properties.Resources.AppName, Properties.Resources.DevName]; public static readonly string baseLoc = $"{Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)}\\Reaper"; public static readonly string cfgLoc = $"{baseLoc}\\config.json"; public static readonly string easterEgg = "https://bit.ly/3Gpgiyh"; // App visible languages and mapping to OpenWeatherMap API codes / culture names. // Keep small for now: English and German only. - public static readonly string[] appLanguages = { "English", "German" }; + public static readonly string[] appLanguages = ["English", "German"]; public static readonly Dictionary appToApiCode = new() { { "English", "en" }, @@ -31,7 +31,7 @@ internal class Helper { public static void MailOption(JsonHandling.Config config, String[] content) { - string[] mailOptions = { Properties.Resources.YesOption, Properties.Resources.NoOption }; + string[] mailOptions = [Properties.Resources.YesOption, Properties.Resources.NoOption]; Menu mailMenu = new(Properties.Resources.mailWanted, mailOptions); if (mailMenu.IRExecute() == 0) @@ -125,7 +125,7 @@ public static void Closer(JsonHandling.Config config) public static void Uninstaller() { string uninstallPrompt = string.Format(Properties.Resources.UninstallPromptFormat, GlobalVars.devData[0]); - string[] uninstallOptions = { Properties.Resources.YesOption, Properties.Resources.NoOption }; + string[] uninstallOptions = [Properties.Resources.YesOption, Properties.Resources.NoOption]; Menu uninstallMenu = new(uninstallPrompt, uninstallOptions); int uninstallChoice = uninstallMenu.IRExecute(); if (uninstallChoice == 0) diff --git a/AltReaper/IO/Inputs.cs b/AltReaper/IO/Inputs.cs index c641113..c970a76 100644 --- a/AltReaper/IO/Inputs.cs +++ b/AltReaper/IO/Inputs.cs @@ -56,7 +56,7 @@ public static bool ConfigGen(JsonHandling.Config config) ForegroundColor = ConsoleColor.Green; //empty bcc means no BCC mail string BCC = ""; - string[] bccOptions = { Properties.Resources.YesOption, Properties.Resources.NoOption }; + string[] bccOptions = [Properties.Resources.YesOption, Properties.Resources.NoOption]; Menu bccMenu = new(Properties.Resources.bccWanted, bccOptions); if (bccMenu.IRExecute() == 0) { @@ -83,7 +83,7 @@ public static bool ConfigGen(JsonHandling.Config config) public static string UnitPreference() { //gets unit preference - string[] unitOptions = { Properties.Resources.metric, Properties.Resources.imperial }; + string[] unitOptions = [Properties.Resources.metric, Properties.Resources.imperial]; Menu unitMenu = new(Properties.Resources.unitQuery, unitOptions); return unitMenu.IRExecute() == 0 ? "metric" : "imperial"; } @@ -112,13 +112,9 @@ public static void ConfigGetter() } public static string LangPreference() { - List availableLanguages = new(); - foreach (string l in GlobalVars.appLanguages) - { - availableLanguages.Add(l); - } + List availableLanguages = [.. GlobalVars.appLanguages]; - Menu languageMenu = new(Properties.Resources.SelectPreferredLanguage, availableLanguages.ToArray()); + Menu languageMenu = new(Properties.Resources.SelectPreferredLanguage, [.. availableLanguages]); string spacer = "-------------------------"; string selectedLanguage = languageMenu.SRExecute(); WriteLine($"\n{spacer}\n"); diff --git a/AltReaper/IO/Outputs.cs b/AltReaper/IO/Outputs.cs index b96d2de..6623fdc 100644 --- a/AltReaper/IO/Outputs.cs +++ b/AltReaper/IO/Outputs.cs @@ -18,7 +18,7 @@ public static string[] WeatherOutput(WeatherResponse.Root weatherData, string un unitSymbol = unitPreference == "metric" ? 'c' : 'f'; //main output - List content = new(); + List content = []; string spacer = "\n-------------------------------------\n"; content.Add(spacer); content.Add($"{Properties.Resources.theWeatherIn}: {weatherData.Name}, {weatherData.Sys.Country}"); @@ -29,7 +29,7 @@ public static string[] WeatherOutput(WeatherResponse.Root weatherData, string un content.Add($"{Properties.Resources.highestTemp}: {weatherData.Main.TempMax:0.#}°{unitSymbol}"); content.Add($"{Properties.Resources.description}: {weatherData.Weather[0].Description}"); content.Add(spacer); - string[] cArray = content.ToArray(); + string[] cArray = [.. content]; WriteLine(string.Join("\r\n", cArray)); WriteLine(Properties.Resources.pressEnterContinue); while (ReadKey(true).Key != ConsoleKey.Enter) { continue; } diff --git a/AltReaper/WetterApp.cs b/AltReaper/WetterApp.cs index 32403c7..06d994e 100644 --- a/AltReaper/WetterApp.cs +++ b/AltReaper/WetterApp.cs @@ -21,7 +21,7 @@ public static void Main() Checks.DeviceIsOnline(); Checks.APIisOnline(); - string[] superUserOptions = { Properties.Resources.YesOption, Properties.Resources.NoOption }; + string[] superUserOptions = [Properties.Resources.YesOption, Properties.Resources.NoOption]; Menu superUser = new(Properties.Resources.SuperUserQuestion, superUserOptions); if (superUser.IRExecute() == 0) From e1544d6c0d12014f6c987076fb650b54fbe72802 Mon Sep 17 00:00:00 2001 From: Sebastian Oehm Date: Sat, 3 Oct 2026 22:30:42 +0200 Subject: [PATCH 15/19] Treat HttpClient timeout as offline in APIisOnline A timeout throws TaskCanceledException, which the HttpRequestException catch missed, so the app continued with the API unreachable. --- AltReaper/Checks.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AltReaper/Checks.cs b/AltReaper/Checks.cs index 17fee45..7e420fc 100644 --- a/AltReaper/Checks.cs +++ b/AltReaper/Checks.cs @@ -72,9 +72,9 @@ public static void APIisOnline() WriteLine(Properties.Resources.ApiOffline); Helper.Closer(); } - catch (HttpRequestException e) + catch (Exception e) when (e is HttpRequestException or TaskCanceledException) { - // network-level error (DNS, timeout, connection failure, etc.) + // network-level error (DNS, connection failure) or HttpClient.Timeout, which surfaces as TaskCanceledException WriteLine(string.Format(Properties.Resources.NetworkErrorFormat, e.Message)); Helper.Closer(); } From 9743703c87265bef9fbd4da0340922d5de0813fd Mon Sep 17 00:00:00 2001 From: Sebastian Oehm Date: Sat, 3 Oct 2026 22:30:43 +0200 Subject: [PATCH 16/19] Create the Reaper base directory on startup Nothing created it after the langFiles directory handling was removed, so the first config write failed. --- AltReaper/WetterApp.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AltReaper/WetterApp.cs b/AltReaper/WetterApp.cs index 06d994e..627ffbe 100644 --- a/AltReaper/WetterApp.cs +++ b/AltReaper/WetterApp.cs @@ -21,6 +21,8 @@ public static void Main() Checks.DeviceIsOnline(); Checks.APIisOnline(); + Directory.CreateDirectory(GlobalVars.baseLoc); + string[] superUserOptions = [Properties.Resources.YesOption, Properties.Resources.NoOption]; Menu superUser = new(Properties.Resources.SuperUserQuestion, superUserOptions); From c20cf0c1fbfe8771d8855bd69c03af8c89f1d3fe Mon Sep 17 00:00:00 2001 From: Sebastian Oehm Date: Sat, 3 Oct 2026 22:32:34 +0200 Subject: [PATCH 17/19] Bump target framework from net8.0 to net10.0 --- AltReaper/Reaper.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AltReaper/Reaper.csproj b/AltReaper/Reaper.csproj index fc318ce..2a56ed6 100644 --- a/AltReaper/Reaper.csproj +++ b/AltReaper/Reaper.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net10.0 enable enable From de83b01e30b5ebec562548b619d019d0fe0f7d17 Mon Sep 17 00:00:00 2001 From: Sebastian Oehm Date: Sat, 3 Oct 2026 22:37:53 +0200 Subject: [PATCH 18/19] Fix nullable reference warnings Initialize model properties, default ReadLine results to empty strings, guard the default proxy and throw on an empty weather response. --- AltReaper/Checks.cs | 4 ++-- AltReaper/Helper.cs | 4 ++-- AltReaper/IO/Inputs.cs | 17 +++++++++-------- AltReaper/JsonHandling.cs | 30 +++++++++++++++--------------- AltReaper/WetterApp.cs | 4 ++-- 5 files changed, 30 insertions(+), 29 deletions(-) diff --git a/AltReaper/Checks.cs b/AltReaper/Checks.cs index 7e420fc..525f353 100644 --- a/AltReaper/Checks.cs +++ b/AltReaper/Checks.cs @@ -45,8 +45,8 @@ public static void DeviceIsOnline() } public static void APIisOnline() { - IWebProxy defaultWebProxy = WebRequest.DefaultWebProxy; - defaultWebProxy.Credentials = CredentialCache.DefaultCredentials; + IWebProxy? defaultWebProxy = WebRequest.DefaultWebProxy; + defaultWebProxy?.Credentials = CredentialCache.DefaultCredentials; try { var handler = new HttpClientHandler diff --git a/AltReaper/Helper.cs b/AltReaper/Helper.cs index ce9e7c0..79216c4 100644 --- a/AltReaper/Helper.cs +++ b/AltReaper/Helper.cs @@ -42,14 +42,14 @@ public static void MailOption(JsonHandling.Config config, String[] content) if (Checks.CfgChecker(config)) { Inputs.ConfigGen(config); - config = JsonSerializer.Deserialize(File.ReadAllText(GlobalVars.cfgLoc)); + config = JsonSerializer.Deserialize(File.ReadAllText(GlobalVars.cfgLoc))!; } Write($"\n{Properties.Resources.mailAddressQuery}\n>"); CursorVisible = true; ForegroundColor = ConsoleColor.White; ForegroundColor = ConsoleColor.Green; CursorVisible = false; - if (Outputs.MailOutput(ReadLine(), Properties.Resources.yourWeatherInfo, content, config)) + if (Outputs.MailOutput(ReadLine() ?? "", Properties.Resources.yourWeatherInfo, content, config)) { Closer(config); } diff --git a/AltReaper/IO/Inputs.cs b/AltReaper/IO/Inputs.cs index c970a76..5d4ad1b 100644 --- a/AltReaper/IO/Inputs.cs +++ b/AltReaper/IO/Inputs.cs @@ -19,8 +19,8 @@ internal class Inputs public static async Task APICall(string city, string langPreferenceShort, string unitPreference, string APIKey) { //Use default system proxy settings - IWebProxy defaultWebProxy = WebRequest.DefaultWebProxy; - defaultWebProxy.Credentials = CredentialCache.DefaultCredentials; + IWebProxy? defaultWebProxy = WebRequest.DefaultWebProxy; + defaultWebProxy?.Credentials = CredentialCache.DefaultCredentials; HttpClientHandler handler = new() { Proxy = defaultWebProxy, @@ -30,7 +30,8 @@ internal class Inputs BaseAddress = new Uri("https://api.openweathermap.org/data/2.5/"), }; - return await client.GetFromJsonAsync($"weather?q={city}&lang={langPreferenceShort}&units={unitPreference}&appid={APIKey}"); + return await client.GetFromJsonAsync($"weather?q={city}&lang={langPreferenceShort}&units={unitPreference}&appid={APIKey}") + ?? throw new InvalidOperationException("The weather API returned an empty response."); } public static bool ConfigGen(JsonHandling.Config config) @@ -42,17 +43,17 @@ public static bool ConfigGen(JsonHandling.Config config) Write("\nEnter the mail address which you want use to send mails\n>"); CursorVisible = true; ForegroundColor = ConsoleColor.White; - string senderMail = ReadLine(); + string senderMail = ReadLine() ?? ""; ForegroundColor = ConsoleColor.Green; Write("\nEnter the password for the mail (won't be shown) letter by letter, then press enter\n>"); string senderMailPassword = Helper.PasswordMaker(); Write("\nEnter the smtp host domain\"\n>"); ForegroundColor = ConsoleColor.White; - string hostDomain = ReadLine(); + string hostDomain = ReadLine() ?? ""; ForegroundColor = ConsoleColor.Green; Write("\nEnter the smtp port Number\n>"); ForegroundColor = ConsoleColor.White; - string portNumber = ReadLine(); + string portNumber = ReadLine() ?? ""; ForegroundColor = ConsoleColor.Green; //empty bcc means no BCC mail string BCC = ""; @@ -63,7 +64,7 @@ public static bool ConfigGen(JsonHandling.Config config) Write("\nEnter the mail address of the BCC archive mail\n>"); CursorVisible = true; ForegroundColor = ConsoleColor.White; - BCC = ReadLine(); + BCC = ReadLine() ?? ""; ForegroundColor = ConsoleColor.Green; } CursorVisible = false; @@ -97,7 +98,7 @@ public static void ConfigGetter() if (!File.Exists(GlobalVars.cfgLoc)) { Write("\nEnter your APIKey\n>"); - string apiKey = ReadLine(); + string apiKey = ReadLine() ?? ""; var tmp = new JsonHandling.Config { ApiKey = apiKey, diff --git a/AltReaper/JsonHandling.cs b/AltReaper/JsonHandling.cs index 3b19d0f..8a1ca56 100644 --- a/AltReaper/JsonHandling.cs +++ b/AltReaper/JsonHandling.cs @@ -7,18 +7,18 @@ internal static class JsonHandling public class Config { [JsonPropertyName("apiKey")] - public string ApiKey { get; set; } + public string ApiKey { get; set; } = string.Empty; [JsonPropertyName("senderMail")] - public string SenderMail { get; set; } + public string SenderMail { get; set; } = string.Empty; [JsonPropertyName("senderMailPassword")] - public string SenderMailPassword { get; set; } + public string SenderMailPassword { get; set; } = string.Empty; [JsonPropertyName("hostDomain")] - public string HostDomain { get; set; } + public string HostDomain { get; set; } = string.Empty; [JsonPropertyName("portNumber")] - public string PortNumber { get; set; } + public string PortNumber { get; set; } = string.Empty; [JsonPropertyName("bcc")] - public string Bcc { get; set; } + public string Bcc { get; set; } = string.Empty; } } public static class WeatherResponse @@ -26,11 +26,11 @@ public static class WeatherResponse public class Weather { [JsonPropertyName("description")] - public string Description { get; set; } + public string Description { get; set; } = string.Empty; [JsonPropertyName("main")] - public string Main { get; set; } + public string Main { get; set; } = string.Empty; [JsonPropertyName("icon")] - public string Icon { get; set; } + public string Icon { get; set; } = string.Empty; } public class Main { @@ -54,7 +54,7 @@ public class Sys [JsonPropertyName("sunset")] public long Sunset { get; set; } [JsonPropertyName("country")] - public string Country { get; set; } + public string Country { get; set; } = string.Empty; } public class Wind { @@ -67,19 +67,19 @@ public class Wind public class Root { [JsonPropertyName("weather")] - public List Weather { get; set; } + public List Weather { get; set; } = []; [JsonPropertyName("main")] - public Main Main { get; set; } + public Main Main { get; set; } = new(); [JsonPropertyName("sys")] - public Sys Sys { get; set; } + public Sys Sys { get; set; } = new(); [JsonPropertyName("wind")] - public Wind Wind { get; set; } + public Wind Wind { get; set; } = new(); [JsonPropertyName("dt")] public long Dt { get; set; } [JsonPropertyName("timezone")] public int Timezone { get; set; } [JsonPropertyName("name")] - public string Name { get; set; } + public string Name { get; set; } = string.Empty; } } } \ No newline at end of file diff --git a/AltReaper/WetterApp.cs b/AltReaper/WetterApp.cs index 627ffbe..9dc45f4 100644 --- a/AltReaper/WetterApp.cs +++ b/AltReaper/WetterApp.cs @@ -47,7 +47,7 @@ public static void Main() Thread.CurrentThread.CurrentCulture = culture; Inputs.ConfigGetter(); - Config config = JsonSerializer.Deserialize(File.ReadAllText(GlobalVars.cfgLoc)); + Config config = JsonSerializer.Deserialize(File.ReadAllText(GlobalVars.cfgLoc))!; string unitPreference = Inputs.UnitPreference(); @@ -71,7 +71,7 @@ public static void Main() ForegroundColor = ConsoleColor.Green; CursorVisible = false; - Root weatherData = Inputs.APICall(city, apiCode, unitPreference, config!.ApiKey).Result; + Root weatherData = Inputs.APICall(city, apiCode, unitPreference, config.ApiKey).Result; var content = Outputs.WeatherOutput(weatherData, unitPreference); From 9df86842ebca29c2d1104412d47a33b151e8eff7 Mon Sep 17 00:00:00 2001 From: Sebastian Oehm Date: Sat, 3 Oct 2026 22:37:53 +0200 Subject: [PATCH 19/19] Match leading whitespace of German resource entries DeviceOfflineDetails and ExceptionRaisedFormat lacked the leading line break of the neutral resources. --- AltReaper/Properties/Resources.de.resx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/AltReaper/Properties/Resources.de.resx b/AltReaper/Properties/Resources.de.resx index c772e8d..d1ee718 100644 --- a/AltReaper/Properties/Resources.de.resx +++ b/AltReaper/Properties/Resources.de.resx @@ -121,7 +121,8 @@ Gerät ist online - Ihr Gerät ist nicht mit dem Internet verbunden. + +Ihr Gerät ist nicht mit dem Internet verbunden. Diese Anwendung benötigt Internetzugang. Bitte verbinden Sie Ihr Gerät mit dem Internet, um diese Anwendung zu benutzen. @@ -135,7 +136,8 @@ Bitte verbinden Sie Ihr Gerät mit dem Internet, um diese Anwendung zu benutzen. Netzwerkfehler beim Kontaktieren der API: {0} - Die folgende Ausnahme wurde ausgelöst : {0} + +Die folgende Ausnahme wurde ausgelöst : {0} {0} v{1}