/// <summary> /// Convert all text items and localized strings to an easy to edit CSV format. /// </summary> public virtual string GetCSVData() { // Collect all the text items present in the scene Dictionary <string, TextItem> textItems = FindTextItems(); // Update text items with localization data from CSV file if (localizationFile != null && localizationFile.text.Length > 0) { AddCSVDataItems(textItems, localizationFile.text); } // Build CSV header row and a list of the language codes currently in use string csvHeader = "Key,Description,Standard"; var languageCodes = new List <string>(); var values = textItems.Values; foreach (var textItem in values) { foreach (string languageCode in textItem.localizedStrings.Keys) { if (!languageCodes.Contains(languageCode)) { languageCodes.Add(languageCode); csvHeader += "," + languageCode; } } } // Build the CSV file using collected text items int rowCount = 0; string csvData = csvHeader + "\n"; var keys = textItems.Keys; foreach (var stringId in keys) { TextItem textItem = textItems[stringId]; string row = CSVSupport.Escape(stringId); row += "," + CSVSupport.Escape(textItem.description); row += "," + CSVSupport.Escape(textItem.standardText); for (int i = 0; i < languageCodes.Count; i++) { var languageCode = languageCodes[i]; if (textItem.localizedStrings.ContainsKey(languageCode)) { row += "," + CSVSupport.Escape(textItem.localizedStrings[languageCode]); } else { row += ","; // Empty field } } csvData += row + "\n"; rowCount++; } notificationText = "Exported " + rowCount + " localization text items."; return(csvData); }
/// <summary> /// Scan a localization CSV file and copies the strings for the specified language code /// into the text properties of the appropriate scene objects. /// </summary> public virtual void SetActiveLanguage(string languageCode, bool forceUpdateSceneText = false) { if (!Application.isPlaying) { // This function should only ever be called when the game is playing (not in editor). return; } if (localizationFile == null) { // No localization file set return; } localizedStrings.Clear(); CsvParser csvParser = new CsvParser(); string[][] csvTable = csvParser.Parse(localizationFile.text); if (csvTable.Length <= 1) { // No data rows in file return; } // Parse header row string[] columnNames = csvTable[0]; if (columnNames.Length < 3) { // No languages defined in CSV file return; } // First assume standard text column and then look for a matching language column int languageIndex = 2; for (int i = 3; i < columnNames.Length; ++i) { if (columnNames[i] == languageCode) { languageIndex = i; break; } } if (languageIndex == 2) { // Using standard text column // Add all strings to the localized strings dict, but don't replace standard text in the scene. // This allows string substitution to work for both standard and localized text strings. for (int i = 1; i < csvTable.Length; ++i) { string[] fields = csvTable[i]; if (fields.Length < 3) { continue; } localizedStrings[fields[0]] = fields[languageIndex]; } // Early out unless we've been told to force the scene text to update. // This happens when the Set Language command is used to reset back to the standard language. if (!forceUpdateSceneText) { return; } } // Using a localized language text column // 1. Add all localized text to the localized strings dict // 2. Update all scene text properties with localized versions for (int i = 1; i < csvTable.Length; ++i) { string[] fields = csvTable[i]; if (fields.Length < languageIndex + 1) { continue; } string stringId = fields[0]; string languageEntry = CSVSupport.Unescape(fields[languageIndex]); if (languageEntry.Length > 0) { localizedStrings[stringId] = languageEntry; PopulateTextProperty(stringId, languageEntry); } } }
/// <summary> /// Adds localized strings from CSV file data to a dictionary of text items in the scene. /// </summary> protected virtual void AddCSVDataItems(Dictionary <string, TextItem> textItems, string csvData) { CsvParser csvParser = new CsvParser(); string[][] csvTable = csvParser.Parse(csvData); if (csvTable.Length <= 1) { // No data rows in file return; } // Parse header row string[] columnNames = csvTable[0]; for (int i = 1; i < csvTable.Length; ++i) { string[] fields = csvTable[i]; if (fields.Length < 3) { // No standard text or localized string fields present continue; } string stringId = fields[0]; if (!textItems.ContainsKey(stringId)) { if (stringId.StartsWith("CHARACTER.") || stringId.StartsWith("SAY.") || stringId.StartsWith("MENU.") || stringId.StartsWith("WRITE.") || stringId.StartsWith("SETTEXT.")) { // If it's a 'built-in' type this probably means that item has been deleted from its flowchart, // so there's no need to add a text item for it. continue; } // Key not found. Assume it's a custom string that we want to retain, so add a text item for it. TextItem newTextItem = new TextItem(); newTextItem.description = CSVSupport.Unescape(fields[1]); newTextItem.standardText = CSVSupport.Unescape(fields[2]); textItems[stringId] = newTextItem; } TextItem textItem = textItems[stringId]; for (int j = 3; j < fields.Length; ++j) { if (j >= columnNames.Length) { continue; } string languageCode = columnNames[j]; string languageEntry = CSVSupport.Unescape(fields[j]); if (languageEntry.Length > 0) { textItem.localizedStrings[languageCode] = languageEntry; } } } }