/// <summary> /// Loads languages from XML files. /// </summary> private void LoadLanguages() { // Clear existing dictionary. languages.Clear(); // Get the current assembly path and append our locale directory name. string assemblyPath = ModUtils.GetAssemblyPath(); if (!assemblyPath.IsNullOrWhiteSpace()) { string localePath = Path.Combine(assemblyPath, "Translations"); // Ensure that the directory exists before proceeding. if (Directory.Exists(localePath)) { // Load each file in directory and attempt to deserialise as a translation file. string[] translationFiles = Directory.GetFiles(localePath); foreach (string translationFile in translationFiles) { using (StreamReader reader = new StreamReader(translationFile)) { XmlSerializer xmlSerializer = new XmlSerializer(typeof(Language)); if (xmlSerializer.Deserialize(reader) is Language translation) { // Got one! add it to the list, if we don't already have a copy. if (!languages.ContainsKey(translation.uniqueName)) { languages.Add(translation.uniqueName, translation); } else { Logging.Error("duplicate translation for ", translation.uniqueName); } } else { Logging.Error("couldn't deserialize translation file '", translationFile); } } } } else { Logging.Error("translations directory not found"); } } else { Logging.Error("assembly path was empty"); } }
/// <summary> /// Loads languages from CSV files. /// </summary> private void LoadLanguages() { // Clear existing dictionary. languages.Clear(); // Get the current assembly path and append our locale directory name. string assemblyPath = ModUtils.GetAssemblyPath(); if (!assemblyPath.IsNullOrWhiteSpace()) { string localePath = Path.Combine(assemblyPath, "Translations"); // Ensure that the directory exists before proceeding. if (Directory.Exists(localePath)) { // Load each file in directory and attempt to deserialise as a translation file. string[] translationFiles = Directory.GetFiles(localePath); foreach (string translationFile in translationFiles) { // Skip anything that's not marked as a .csv file. if (!translationFile.EndsWith(".csv")) { continue; } // Read file. FileStream fileStream = new FileStream(translationFile, FileMode.Open, FileAccess.Read); using (StreamReader reader = new StreamReader(fileStream)) { // Create new language instance for this file. Language thisLanguage = new Language(); string key = null; bool quoting = false; // Iterate through each line of file. string line = reader.ReadLine(); while (line != null) { // Are we parsing quoted lines? if (quoting) { // Parsing a quoted line - make sure we have a valid current key. if (!key.IsNullOrWhiteSpace()) { // Yes - if the line ends with a quote, trim the quote and add to existing dictionary entry and stop quoting. if (line.EndsWith("\"")) { quoting = false; thisLanguage.translationDictionary[key] += line.Substring(0, line.Length - 1); } else { // Line doesn't end with a quote - add line to existing dictionary entry and keep going. thisLanguage.translationDictionary[key] += line + Environment.NewLine; } } } else { // Not parsing quoted line - look for comma separator on this line. int commaPos = line.IndexOf(","); if (commaPos > 0) { // Comma found - split line into key and value, delimited by first comma. key = line.Substring(0, commaPos); string value = line.Substring(commaPos + 1); // Don't do anything if either key or value is invalid. if (!key.IsNullOrWhiteSpace() && !value.IsNullOrWhiteSpace()) { // Trim quotes off keys. if (key.StartsWith("\"")) { // Starts with quotation mark - if it also ends in a quotation mark, strip both quotation marks. if (key.EndsWith("\"")) { key = key.Substring(1, key.Length - 2); } else { // Doesn't end in a quotation mark, so just strip leading quotation mark. key = key.Substring(1); } } // Does this value start with a quotation mark? if (value.StartsWith("\"")) { // Starts with quotation mark - if it also ends in a quotation mark, strip both quotation marks. if (value.EndsWith("\"")) { value = value.Substring(1, value.Length - 2); } else { // Doesn't end in a quotation mark, so we've (presumably) got a multi-line quoted entry // Flag quoting mode and set initial value to start of quoted string (less leading quotation mark), plus trailing newline. quoting = true; value = value.Substring(1) + Environment.NewLine; } } // Check for reserved keywords. if (key.Equals(Language.CodeKey)) { // Language code. thisLanguage.uniqueName = value; } else if (key.Equals(Language.NameKey)) { // Language readable name. thisLanguage.readableName = value; } else { // Try to add key/value pair to translation dictionary. if (!thisLanguage.translationDictionary.ContainsKey(key)) { thisLanguage.translationDictionary.Add(key, value); } else { Logging.Error("duplicate translation key ", key, " in file ", translationFile); } } } } else { // No comma delimiter found - append to previous line (if last-used key is valid). if (!key.IsNullOrWhiteSpace()) { thisLanguage.translationDictionary[key] += line; } } } // Read next line. line = reader.ReadLine(); } // Did we get a valid dictionary from this? if (thisLanguage.uniqueName != null && thisLanguage.readableName != null && thisLanguage.translationDictionary.Count > 0) { // Yes - add to languages dictionary. if (!languages.ContainsKey(thisLanguage.uniqueName)) { languages.Add(thisLanguage.uniqueName, thisLanguage); } else { Logging.Error("duplicate translation file for language ", thisLanguage.uniqueName); } } else { Logging.Error("file ", translationFile, " did not produce a valid translation dictionary"); } } } } else { Logging.Error("translations directory not found"); } } else { Logging.Error("assembly path was empty"); } }
/// <summary> /// Opens the named resource file for reading. /// </summary> /// <param name="fileName">File to open</param> /// <returns>Read-only file stream</returns> private static Stream OpenResourceFile(string fileName) { string path = Path.Combine(ModUtils.GetAssemblyPath(), "Resources"); return(File.OpenRead(Path.Combine(path, fileName))); }