using System; using System.Text; using System.Text.RegularExpressions; using System.Collections.Generic; using System.Globalization; using System.IO; namespace MinecraftClient { /// /// Allows to localize MinecraftClient in different languages /// /// /// By ORelio (c) 2015-2018 - CDDL 1.0 /// public static class Translations { private static Dictionary translations; private static string translationFilePath = "lang" + Path.DirectorySeparatorChar + "mcc"; private static string defaultTranslation = "en.ini"; private static Regex translationKeyRegex = new Regex(@"\(\[(.*?)\]\)", RegexOptions.Compiled); // Extract string inside ([ ]) /// /// Return a tranlation for the requested text. Support string formatting /// /// text identifier /// returns translation for this identifier public static string Get(string msgName, params object[] args) { if (translations.ContainsKey(msgName)) { if (args.Length > 0) { return string.Format(translations[msgName], args); } else return translations[msgName]; } return msgName.ToUpper(); } /// /// Return a tranlation for the requested text. Support string formatting. If not found, return the original text /// /// text identifier /// /// Translated text or original text if not found /// Useful when not sure msgName is a translation mapping key or a normal text public static string TryGet(string msgName, params object[] args) { if (translations.ContainsKey(msgName)) return Get(msgName, args); else return msgName; } /// /// Replace the translation key inside a sentence to translated text. Wrap the key in ([translation.key]) /// /// /// e.g. I only want to replace ([this]) /// would only translate "this" without touching other words. /// /// Sentence for replace /// /// Translated sentence public static string Replace(string msg, params object[] args) { string translated = translationKeyRegex.Replace(msg, new MatchEvaluator(ReplaceKey)); if (args.Length > 0) return string.Format(translated, args); else return translated; } private static string ReplaceKey(Match m) { return Get(m.Groups[1].Value); } /// /// Initialize translations depending on system language. /// English is the default for all unknown system languages. /// static Translations() { translations = new Dictionary(); LoadDefaultTranslationsFile(); } /// /// Load default translation file (English) /// /// /// This will be loaded during program start up. /// private static void LoadDefaultTranslationsFile() { string[] engLang = DefaultConfigResource.TranslationEnglish.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); // use embedded translations ParseTranslationContent(engLang); } /// /// Load translation file depends on system language or by giving a file path. Default to English if translation file does not exist /// public static void LoadExternalTranslationFile(string language) { /* * External translation files * These files are loaded from the installation directory as: * Lang/abc.ini, e.g. Lang/eng.ini which is the default language file * Useful for adding new translations of fixing typos without recompiling */ // Try to convert Minecraft language file name to two letters language name if (language == "zh_cn") language = "zh-CHS"; else if (language == "zh_tw") language = "zh-CHT"; else language = language.Split('_')[0]; string systemLanguage = string.IsNullOrEmpty(CultureInfo.CurrentCulture.Parent.Name) // Parent.Name might be empty ? CultureInfo.CurrentCulture.Name : CultureInfo.CurrentCulture.Parent.Name; string langDir = AppDomain.CurrentDomain.BaseDirectory + Path.DirectorySeparatorChar + translationFilePath + Path.DirectorySeparatorChar; string langFileSystemLanguage = langDir + systemLanguage + ".ini"; string langFileConfigLanguage = langDir + language + ".ini"; if (File.Exists(langFileConfigLanguage)) {// Language set in ini config ParseTranslationContent(File.ReadAllLines(langFileConfigLanguage)); return; } else { if (Settings.DebugMessages) ConsoleIO.WriteLogLine("[Translations] No translation file found for " + language + ". (Looked '" + langFileConfigLanguage + "'"); } if (File.Exists(langFileSystemLanguage)) {// Fallback to system language ParseTranslationContent(File.ReadAllLines(langFileSystemLanguage)); return; } else { if (Settings.DebugMessages) ConsoleIO.WriteLogLine("[Translations] No translation file found for system language (" + systemLanguage + "). (Looked '" + langFileSystemLanguage + "'"); } } /// /// Parse the given array to translation map /// /// Content of the translation file (in ini format) private static void ParseTranslationContent(string[] content) { foreach (string lineRaw in content) { string line = lineRaw.Trim(); if (line.Length <= 0) continue; if (line.StartsWith("#")) // ignore comment line started with # continue; if (line[0] == '[' && line[line.Length - 1] == ']') // ignore section continue; string translationName = line.Split('=')[0]; if (line.Length > (translationName.Length + 1)) { string translationValue = line.Substring(translationName.Length + 1).Replace("\\n", "\n"); translations[translationName] = translationValue; } } } /// /// Write the default translation file (English) to the disk. /// private static void WriteDefaultTranslation() { string defaultPath = AppDomain.CurrentDomain.BaseDirectory + Path.DirectorySeparatorChar + translationFilePath + Path.DirectorySeparatorChar + defaultTranslation; if (!Directory.Exists(translationFilePath)) { Directory.CreateDirectory(translationFilePath); } File.WriteAllText(defaultPath, DefaultConfigResource.TranslationEnglish, Encoding.UTF8); } #region Console writing method wrapper /// /// Translate the key and write the result to the standard output, without newline character /// /// Translation key public static void Write(string key) { ConsoleIO.Write(Get(key)); } /// /// Translate the key and write a Minecraft-Like formatted string to the standard output, using §c color codes /// See minecraft.gamepedia.com/Classic_server_protocol#Color_Codes for more info /// /// Translation key /// If false, space are printed instead of newlines /// /// If false, no timestamp is prepended. /// If true, "hh-mm-ss" timestamp will be prepended. /// If unspecified, value is retrieved from EnableTimestamps. /// public static void WriteLineFormatted(string key, bool acceptnewlines = true, bool? displayTimestamp = null) { ConsoleIO.WriteLineFormatted(Get(key), acceptnewlines, displayTimestamp); } /// /// Translate the key, format the result and write it to the standard output with a trailing newline. Support string formatting /// /// Translation key /// public static void WriteLine(string key, params object[] args) { if (args.Length > 0) ConsoleIO.WriteLine(string.Format(Get(key), args)); else ConsoleIO.WriteLine(Get(key)); } /// /// Translate the key and write the result with a prefixed log line. Prefix is set in LogPrefix. /// /// Translation key /// Allow line breaks public static void WriteLogLine(string key, bool acceptnewlines = true) { ConsoleIO.WriteLogLine(Get(key), acceptnewlines); } #endregion } }