예제 #1
0
        /// <summary>
        /// Creates or updates collection
        /// </summary>
        /// <param name="collectionName"></param>
        /// <param name="categoryName"></param>
        public void SetCollection(string collectionName, string categoryName)
        {
            lock (Lock)
            {
                // Get the localization collection. If it does not exist, create it first
                var localizationCategory = LocalizationCategories.FirstOrDefault(x => x.Name.ToLower() == categoryName.ToLower());
                if (localizationCategory == null)
                {
                    localizationCategory = new LocalizationCategory
                    {
                        Name = categoryName
                    };
                    Provider.InsertOrUpdateLocalizationCategory(localizationCategory);
                    LocalizationCategories = Provider.LoadLocalizationCategories();
                    localizationCategory   = LocalizationCategories.FirstOrDefault(x => x.Name.ToLower() == categoryName.ToLower());
                }

                if (localizationCategory == null)
                {
                    return;
                }

                var collection = LocalizationCollections.FirstOrDefault(x => x.Name.ToLower() == collectionName.ToLower())
                                 ?? new LocalizationCollection
                {
                    LocalizationCategoryId = localizationCategory.Id
                };
                collection.Name = collectionName;
                Provider.InsertOrUpdateLocalizationCollection(collection);
                LocalizationCollections = Provider.LoadLocalizationCollections();
            }
        }
        private bool CanSaveLocalization()
        {
            if (!LocalizationCategories.Any())
            {
                return(false);
            }
            int numChecked = 0;

            if (ShowGerman)
            {
                numChecked++;
            }
            if (ShowRussian)
            {
                numChecked++;
            }
            if (ShowPolish)
            {
                numChecked++;
            }
            if (ShowFrench)
            {
                numChecked++;
            }
            if (ShowSpanish)
            {
                numChecked++;
            }
            if (numChecked == 1)
            {
                return(true);
            }
            return(false);
        }
예제 #3
0
        private void LoadLocalization()
        {
            OpenFileDialog openFileDialog = new OpenFileDialog()
            {
                Title  = "Select [lang].xaml file",
                Filter = "Xaml files|*.xaml"
            };

            if (openFileDialog.ShowDialog() == true)
            {
                var fname    = openFileDialog.FileName;
                var basename = Path.GetFileNameWithoutExtension(fname);
                if (!LocalizedString.Languages.Contains(basename, StringComparer.InvariantCultureIgnoreCase))
                {
                    MessageBox.Show("Filename must be XXX.xaml, with XXX being your language code. The file selected does not match a supported language.");
                    return;
                }

                //Wipe existing strings for that lang
                foreach (var cat in LocalizationCategories)
                {
                    foreach (var ls in cat.LocalizedStringsForSection)
                    {
                        switch (basename)
                        {
                        case "rus":
                            ls.RUS = null;
                            break;

                        case "deu":
                            ls.DEU = null;
                            break;

                        case "pol":
                            ls.POL = null;
                            break;

                        case "fra":
                            ls.FRA = null;
                            break;

                        case "esn":
                            ls.ESN = null;
                            break;

                        case "bra":
                            ls.BRA = null;
                            break;
                        }
                    }
                }

                //Load lang from file
                var dict = new Dictionary <string, string>();
                dict[basename] = File.ReadAllText(fname);
                parseLocalizations(LocalizationCategories.ToList(), dict);
                MessageBox.Show("Loaded localization for " + basename + ".");
            }
        }
 public void OnSelectedBranchChanged()
 {
     if (oldBranch != null)
     {
         if (SelectedBranch != null)
         {
             LoadLocalizations(SelectedBranch);
             oldBranch = SelectedBranch;
         }
         else
         {
             LocalizationCategories.ClearEx();
             LocalizedTips.ClearEx();
             dynamicHelpLocalizations.Clear();
         }
     }
 }
예제 #5
0
        /// <summary>
        /// Creates or updates collection
        /// </summary>
        /// <param name="collecitonName"></param>
        /// <param name="categoryId"></param>
        public void SetCollection(string collecitonName, int categoryId)
        {
            lock (Lock)
            {
                var localizationCategory = LocalizationCategories.FirstOrDefault(x => x.Id == categoryId);
                if (localizationCategory == null)
                {
                    return;
                }

                Provider.InsertOrUpdateLocalizationCollection(new LocalizationCollection
                {
                    LocalizationCategoryId = localizationCategory.Id,
                    Name = collecitonName
                });
                LocalizationCollections = Provider.LoadLocalizationCollections();
            }
        }
예제 #6
0
 /// <summary>
 /// Returns all localization categories
 /// </summary>
 /// <returns></returns>
 public List <LocalizationCategory> GetAllCategories()
 {
     return(LocalizationCategories.ToList());
 }
예제 #7
0
 /// <summary>
 /// Returns localization category
 /// </summary>
 /// <param name="category"></param>
 /// <returns></returns>
 public LocalizationCategory GetCategory(string category)
 {
     return(LocalizationCategories.FirstOrDefault(x => x.Name.ToLower() == category.ToLower()));
 }
예제 #8
0
        /// <summary>
        /// Sets new translation for the provided key and language (or current culture language if not provided)
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="collection"></param>
        /// <param name="category"></param>
        /// <param name="culture"></param>
        public void Set(string key, string value, string collection, string category, CultureInfo culture = null)
        {
            lock (Lock)
            {
                // Get the localization key Id. If it does not exist, create it first
                var localizationKey = LocalizationKeys.FirstOrDefault(x => x.Name.ToLower() == key.ToLower());
                if (localizationKey == null)
                {
                    localizationKey = new LocalizationKey {
                        Name = key
                    };
                    Provider.InsertLocalizationKey(localizationKey);
                    LocalizationKeys = Provider.LoadLocalizationKeys();
                    localizationKey  = LocalizationKeys.FirstOrDefault(x => x.Name.ToLower() == key.ToLower());
                }
                if (localizationKey == null)
                {
                    return;
                }

                // Get the localization language. If it does not exist, create it first
                var langName             = GetLanguageNameFromCulture(culture).ToLower();
                var langDisplayName      = GetLanguageDisplayNameFromCulture(culture);
                var localizationLanguage = LocalizationLanguages.FirstOrDefault(x => x.Name.ToLower() == GetLanguageNameFromCulture(culture).ToLower());
                if (localizationLanguage == null)
                {
                    localizationLanguage = new LocalizationLanguage
                    {
                        Name  = langName,
                        Value = langDisplayName
                    };
                    Provider.InsertLocalizationLanguage(localizationLanguage);
                    LocalizationLanguages = Provider.LoadLocalizationLanguages();
                    localizationLanguage  = LocalizationLanguages.FirstOrDefault(x => x.Name.ToLower() == GetLanguageNameFromCulture(culture).ToLower());
                }
                if (localizationLanguage == null)
                {
                    return;
                }

                // Get the localization collection. If it does not exist, create it first
                var localizationCategory = LocalizationCategories.FirstOrDefault(x => x.Name.ToLower() == category.ToLower());
                if (localizationCategory == null)
                {
                    localizationCategory = new LocalizationCategory
                    {
                        Name = category
                    };
                    Provider.InsertOrUpdateLocalizationCategory(localizationCategory);
                    LocalizationCategories = Provider.LoadLocalizationCategories();
                    localizationCategory   = LocalizationCategories.FirstOrDefault(x => x.Name.ToLower() == category.ToLower());
                }
                if (localizationCategory == null)
                {
                    return;
                }

                // Get the localization collection. If it does not exist, create it first
                var localizationCollection = LocalizationCollections.FirstOrDefault(x =>
                                                                                    x.Name.ToLower() == collection.ToLower() &&
                                                                                    x.LocalizationCategoryId == localizationCategory.Id);

                if (localizationCollection == null)
                {
                    localizationCollection = new LocalizationCollection
                    {
                        Name = collection,
                        LocalizationCategoryId = localizationCategory.Id
                    };
                    Provider.InsertOrUpdateLocalizationCollection(localizationCollection);
                    LocalizationCollections = Provider.LoadLocalizationCollections();
                    localizationCollection  = LocalizationCollections.FirstOrDefault(x =>
                                                                                     x.Name.ToLower() == collection.ToLower() &&
                                                                                     x.LocalizationCategoryId == localizationCategory.Id);
                }
                if (localizationCollection == null)
                {
                    return;
                }
                localizationCollection.LocalizationCategory   = localizationCategory;
                localizationCollection.LocalizationCategoryId = localizationCategory.Id;

                // Don't check the collection since only one combination of key and language is allowed across collections
                var entry = LocalizationEntries.FirstOrDefault(x => x.LocalizationKeyId == localizationKey.Id &&
                                                               x.LocalizationLanguageId == localizationLanguage.Id);

                if (entry == null)
                {
                    // Create
                    entry = new LocalizationEntry
                    {
                        Value = value,
                        LocalizationCollectionId = localizationCollection.Id,
                        LocalizationKeyId        = localizationKey.Id,
                        LocalizationLanguageId   = localizationLanguage.Id,
                        CreatedOn = DateTime.UtcNow,
                        UpdatedOn = DateTime.UtcNow
                    };
                    Provider.InsertLocalizationEntry(entry);
                    LocalizationEntries = Provider.LoadLocalizationEntries();
                }
            }
        }
        private void Find_Clicked(object sender, RoutedEventArgs e)
        {
            int indexOfCurrentCategory = SelectedCategory != null?LocalizationCategories.IndexOf(SelectedCategory) : 0;

            Debug.WriteLine("Current cat index: " + indexOfCurrentCategory);

            int    numCategories = LocalizationCategories.Count(); //might need to +1 this
            string searchTerm    = SearchText.ToLower();

            if (string.IsNullOrEmpty(searchTerm))
            {
                return;
            }
            LocalizedString      itemToHighlight = null;
            LocalizationCategory catToHighlight  = null;

            for (int i = 0; i < numCategories; i++)
            {
                bool found = false;
                LocalizationCategory cat = LocalizationCategories[(i + indexOfCurrentCategory) % LocalizationCategories.Count()];
                int startSearchIndex     = 0;
                int numToSearch          = cat.LocalizedStringsForSection.Count();
                if (i == 0 && cat == SelectedCategory && SelectedDataGridItem != null)
                {
                    startSearchIndex = cat.LocalizedStringsForSection.IndexOf(SelectedDataGridItem) + 1;
                    numToSearch     -= startSearchIndex;
                }
                Debug.WriteLine(cat.CategoryName);
                for (int j = 0; j < numToSearch; j++)
                {
                    var ls = cat.LocalizedStringsForSection[(j + startSearchIndex) % cat.LocalizedStringsForSection.Count];

                    //Key
                    if (ls.key.Contains(searchTerm, StringComparison.InvariantCultureIgnoreCase))
                    {
                        //found
                        found           = true;
                        itemToHighlight = ls;
                        catToHighlight  = cat;
                        break;
                    }

                    //English
                    if (ls.INT.Contains(searchTerm, StringComparison.InvariantCultureIgnoreCase))
                    {
                        //found
                        found           = true;
                        itemToHighlight = ls;
                        catToHighlight  = cat;
                        break;
                    }

                    //German
                    if (ShowGerman && ls.DEU != null && ls.DEU.Contains(searchTerm, StringComparison.InvariantCultureIgnoreCase))
                    {
                        //found
                        found           = true;
                        itemToHighlight = ls;
                        catToHighlight  = cat;
                        break;
                    }

                    //Russian
                    if (ShowRussian && ls.RUS != null && ls.RUS.Contains(searchTerm, StringComparison.InvariantCultureIgnoreCase))
                    {
                        //found
                        found           = true;
                        itemToHighlight = ls;
                        catToHighlight  = cat;
                        break;
                    }

                    //Polish
                    if (ShowPolish && ls.POL != null && ls.POL.Contains(searchTerm, StringComparison.InvariantCultureIgnoreCase))
                    {
                        //found
                        found           = true;
                        itemToHighlight = ls;
                        catToHighlight  = cat;
                        break;
                    }

                    //French
                    if (ShowFrench && ls.FRA != null && ls.FRA.Contains(searchTerm, StringComparison.InvariantCultureIgnoreCase))
                    {
                        //found
                        found           = true;
                        itemToHighlight = ls;
                        catToHighlight  = cat;
                        break;
                    }

                    //Spanish
                    if (ShowSpanish && ls.ESN != null && ls.ESN.Contains(searchTerm, StringComparison.InvariantCultureIgnoreCase))
                    {
                        //found
                        found           = true;
                        itemToHighlight = ls;
                        catToHighlight  = cat;
                        break;
                    }
                }
                if (found)
                {
                    break;
                }
            }

            if (itemToHighlight == null)
            {
                SystemSounds.Beep.Play();
            }
            else
            {
                SelectedCategory     = catToHighlight;
                SelectedDataGridItem = itemToHighlight;
                DataGridTable.ScrollIntoView(SelectedDataGridItem);
            }
        }
        private void LoadLocalizations(string branch = null)
        {
            BackgroundWorker bw = new BackgroundWorker();

            bw.DoWork += (x, y) =>
            {
                if (!LocalizationBranches.Any())
                {
                    var ghclient = new GitHubClient(new ProductHeaderValue(@"ME3TweaksModManager"));
                    try
                    {
                        var branches    = ghclient.Repository.Branch.GetAll("ME3Tweaks", "ME3TweaksModManager").Result;
                        var locbranches = branches.Where(x => x.Name.Contains("master") || x.Name.Contains("-localization"));
                        System.Windows.Application.Current.Dispatcher.Invoke(delegate { LocalizationBranches.ReplaceAll(locbranches.Select(x => x.Name)); });
                    }
                    catch (Exception e)
                    {
                        System.Windows.Application.Current.Dispatcher.Invoke(delegate { MessageBox.Show("Error getting list of localization branches: " + e.Message); });
                        return;
                    }
                }

                if (LocalizationBranches.Any())
                {
                    if (branch == null)
                    {
                        branch         = LocalizationBranches.First();
                        SelectedBranch = branch;
                        oldBranch      = branch;
                    }
                }
                else
                {
                    System.Windows.Application.Current.Dispatcher.Invoke(delegate { MessageBox.Show("Could not find any branches on ME3TweaksModManager repo containing name 'localization'"); });
                    return;
                }

                var       dictionaries = new Dictionary <string, string>();
                string    endpoint     = $"https://raw.githubusercontent.com/ME3Tweaks/ME3TweaksModManager/{branch}/MassEffectModManagerCore/modmanager/localizations/"; //make dynamic, maybe with octokit.
                WebClient client       = new WebClient();
                foreach (var lang in LocalizedString.Languages)
                {
                    var url  = endpoint + lang + ".xaml";
                    var dict = client.DownloadStringAwareOfEncoding(url);
                    dictionaries[lang] = dict;
                }

                //Parse INT.
                int currentLine          = 3; //Skip header.
                LocalizationCategory cat = null;
                int numBlankLines        = 0;
                List <LocalizationCategory> categories = new List <LocalizationCategory>();
                var intLines = Regex.Split(dictionaries["int"], "\r\n|\r|\n");
                for (int i = 3; i < intLines.Length - 2; i++)
                {
                    var line = intLines[i].Trim();
                    if (string.IsNullOrWhiteSpace(line))
                    {
                        numBlankLines++;
                        continue;
                    }

                    if (line.StartsWith("<!--") && line.EndsWith("-->"))
                    {
                        //Comment - parse
                        line = line.Substring(4);
                        line = line.Substring(0, line.Length - 3);
                        line = line.Trim();
                        if (numBlankLines > 0 || cat == null)
                        {
                            //New category?
                            if (cat != null)
                            {
                                categories.Add(cat);
                            }

                            cat = new LocalizationCategory()
                            {
                                CategoryName = line
                            };
                        }

                        //notes for previous item?
                        var prevItem = cat.LocalizedStringsForSection.LastOrDefault();
                        if (prevItem != null)
                        {
                            prevItem.notes = line;
                        }
                        //Debug.WriteLine(line);

                        //New Category
                        //line = line.
                        continue;
                    }

                    numBlankLines = 0;
                    var             lineInfo = extractInfo(line);
                    LocalizedString ls       = new LocalizedString()
                    {
                        key = lineInfo.key,
                        preservewhitespace = lineInfo.preserveWhitespace,
                        INT = lineInfo.text
                    };
                    if (lineInfo.key == null)
                    {
                        Debugger.Break();
                    }
                    if (ls.INT == null)
                    {
                        Debugger.Break();
                    }
                    cat.LocalizedStringsForSection.Add(ls);
                }

                if (cat != null)
                {
                    categories.Add(cat);
                }

                parseLocalizations(categories, dictionaries);
                y.Result = categories;

                //TIPS SERVICE
                string tipsEndpoint = "https://me3tweaks.com/modmanager/services/tipsservice";
                string contents;
                using var wc = new System.Net.WebClient();
                var tipsJson = wc.DownloadString(tipsEndpoint);
                var jsonObj  = JsonConvert.DeserializeObject <Dictionary <string, List <string> > >(tipsJson);
                var langs    = LocalizedString.Languages.Where(x => x != "int");
                var locTips  = new List <LocalizedString>();
                for (int i = 0; i < jsonObj["int"].Count; i++)
                {
                    LocalizedString ls = new LocalizedString()
                    {
                        INT = jsonObj["int"][i]
                    };
                    foreach (var lang in langs)
                    {
                        if (jsonObj[lang].Count <= i)
                        {
                            continue;                           //skip
                        }
                        switch (lang)
                        {
                        case "rus":
                            ls.RUS = jsonObj["rus"][i];
                            break;

                        case "deu":
                            ls.DEU = jsonObj["deu"][i];
                            break;

                        case "pol":
                            ls.POL = jsonObj["pol"][i];
                            break;

                        case "fra":
                            ls.FRA = jsonObj["fra"][i];
                            break;

                        case "esn":
                            ls.ESN = jsonObj["esn"][i];
                            break;
                        }
                    }
                    locTips.Add(ls);
                }
                System.Windows.Application.Current.Dispatcher.Invoke(delegate
                {
                    LocalizedTips.ReplaceAll(locTips);
                });

                //DYNAMIC HELP
                endpoint = $"https://raw.githubusercontent.com/ME3Tweaks/ME3TweaksModManager/{branch}/MassEffectModManagerCore/staticfiles/dynamichelp/latesthelp-localized.xml";
                var       dynamicHelpXml = wc.DownloadString(endpoint);
                XDocument doc            = XDocument.Parse(dynamicHelpXml);
                var       intxml         = doc.XPathSelectElement("/localizations/helpmenu[@lang='int']");
                dynamicHelpLocalizations["int"] = intxml.ToString();

                Debug.WriteLine(doc.ToString());
                foreach (var lang in langs)
                {
                    var langxml = doc.XPathSelectElement($"/localizations/helpmenu[@lang='{lang}']");
                    if (langxml != null)
                    {
                        dynamicHelpLocalizations[lang] = langxml.ToString();
                    }
                }

                /*
                 * var langs = LocalizedString.Languages.Where(x => x != "int");
                 * var locTips = new List<LocalizedString>();
                 * for (int i = 0; i < jsonObj["int"].Count; i++)
                 * {
                 *  LocalizedString ls = new LocalizedString()
                 *  {
                 *      INT = jsonObj["int"][i]
                 *  };
                 *  foreach (var lang in langs)
                 *  {
                 *      if (jsonObj[lang].Count <= i) continue; //skip
                 *      switch (lang)
                 *      {
                 *          case "rus":
                 *              ls.RUS = jsonObj["rus"][i];
                 *              break;
                 *          case "deu":
                 *              ls.DEU = jsonObj["deu"][i];
                 *              break;
                 *          case "pol":
                 *              ls.POL = jsonObj["pol"][i];
                 *              break;
                 *          case "fra":
                 *              ls.FRA = jsonObj["fra"][i];
                 *              break;
                 *          case "esn":
                 *              ls.ESN = jsonObj["esn"][i];
                 *              break;
                 *      }
                 *  }
                 *  locTips.Add(ls);
                 * }
                 */
                System.Windows.Application.Current.Dispatcher.Invoke(delegate
                {
                    intViewer.Text = intxml.ToString();
                    LocalizedTips.ReplaceAll(locTips);
                });
            };
            bw.RunWorkerCompleted += (a, b) =>
            {
                if (b.Error == null && b.Result is List <LocalizationCategory> categories)
                {
                    LocalizationCategories.ReplaceAll(categories);
                }
            };
            bw.RunWorkerAsync();
        }
예제 #11
0
        private void LoadLocalizations(string branch = null)
        {
            BackgroundWorker bw = new BackgroundWorker();

            bw.DoWork += (x, y) =>
            {
                if (!LocalizationBranches.Any())
                {
                    PleaseWaitString = "Fetching remote localization branches";
                    var ghclient = new GitHubClient(new ProductHeaderValue(@"ME3TweaksModManager"));
                    try
                    {
                        var branches    = ghclient.Repository.Branch.GetAll("ME3Tweaks", "ME3TweaksModManager").Result;
                        var locbranches = branches.Where(x => /*x.Name.Contains("master") ||*/ x.Name.Contains("-localization"));
                        System.Windows.Application.Current.Dispatcher.Invoke(delegate { LocalizationBranches.ReplaceAll(locbranches.Select(x => x.Name).OrderByDescending(x => x)); });
                    }
                    catch (Exception e)
                    {
                        System.Windows.Application.Current.Dispatcher.Invoke(delegate { MessageBox.Show("Error getting list of localization branches: " + e.Message); });
                        return;
                    }
                }

                string oldBuildBranch = null;
                if (LocalizationBranches.Any())
                {
                    if (branch == null)
                    {
                        branch         = LocalizationBranches.First();
                        SelectedBranch = branch;
                        oldBranch      = branch;
                        if (LocalizationBranches.Count() > 1)
                        {
                            oldBuildBranch = LocalizationBranches[1];
                        }
                    }
                }
                else
                {
                    System.Windows.Application.Current.Dispatcher.Invoke(delegate { MessageBox.Show("Could not find any branches on ME3TweaksModManager repo containing name 'localization'"); });
                    return;
                }

                var       dictionaries = new Dictionary <string, string>();
                string    endpoint     = $"https://raw.githubusercontent.com/ME3Tweaks/ME3TweaksModManager/{branch}/MassEffectModManagerCore/modmanager/localizations/"; //make dynamic, maybe with octokit.
                WebClient client       = new WebClient();
                foreach (var lang in LocalizedString.Languages)
                {
                    PleaseWaitString = $"Fetching {branch} {lang}";

                    var url  = endpoint + lang + ".xaml";
                    var dict = client.DownloadStringAwareOfEncoding(url);
                    dictionaries[lang] = dict;
                }

                if (oldBuildBranch != null)
                {
                    PleaseWaitString = $"Fetching {oldBuildBranch} int";

                    endpoint = $"https://raw.githubusercontent.com/ME3Tweaks/ME3TweaksModManager/{oldBuildBranch}/MassEffectModManagerCore/modmanager/localizations/"; //make dynamic, maybe with octokit.
                    var url  = endpoint + "int.xaml";
                    var dict = client.DownloadStringAwareOfEncoding(url);
                    dictionaries["int-prev"] = dict;
                }

                PleaseWaitString = $"Parsing main strings";

                Dictionary <string, string> oldStuff = new Dictionary <string, string>();
                if (dictionaries.TryGetValue("int-prev", out var oldStrXml))
                {
                    XDocument  oldBuildDoc = XDocument.Parse(oldStrXml);
                    XNamespace system      = "clr-namespace:System;assembly=System.Runtime";
                    XNamespace xk          = "http://schemas.microsoft.com/winfx/2006/xaml";
                    var        lstrings    = oldBuildDoc.Root.Descendants(system + "String").ToList();
                    foreach (var lstring in lstrings)
                    {
                        oldStuff[lstring.Attribute(xk + "Key").Value] = lstring.Value;
                    }
                }


                //Parse INT.
                int currentLine          = 3; //Skip header.
                LocalizationCategory cat = null;
                int numBlankLines        = 0;
                List <LocalizationCategory> categories = new List <LocalizationCategory>();
                var intLines = Regex.Split(dictionaries["int"], "\r\n|\r|\n");
                for (int i = 3; i < intLines.Length - 2; i++)
                {
                    var line = intLines[i].Trim();
                    if (string.IsNullOrWhiteSpace(line))
                    {
                        numBlankLines++;
                        continue;
                    }

                    if (line.StartsWith("<!--") && line.EndsWith("-->"))
                    {
                        //Comment - parse
                        line = line.Substring(4);
                        line = line.Substring(0, line.Length - 3);
                        line = line.Trim();
                        if (numBlankLines > 0 || cat == null)
                        {
                            //New category?
                            if (cat != null)
                            {
                                categories.Add(cat);
                            }

                            cat = new LocalizationCategory()
                            {
                                CategoryName = line
                            };
                        }

                        //notes for previous item?
                        var prevItem = cat.LocalizedStringsForSection.LastOrDefault();
                        if (prevItem != null)
                        {
                            prevItem.notes = line;
                        }
                        //Debug.WriteLine(line);

                        //New Category
                        //line = line.
                        continue;
                    }

                    numBlankLines = 0;
                    var             lineInfo = extractInfo(line);
                    LocalizedString ls       = new LocalizedString()
                    {
                        key = lineInfo.key,
                        preservewhitespace = lineInfo.preserveWhitespace,
                        INT = lineInfo.text
                    };

                    if (oldStuff.TryGetValue(lineInfo.key, out var oldString))
                    {
                        var       oldValue = new XText(oldString).ToString();
                        var       newValue = new XText(lineInfo.text).ToString();
                        XDocument newV     = XDocument.Parse("<text>" + lineInfo.text + "</text>");
                        if (oldString != newV.Root.Value)
                        {
                            if (ls.key == "string_modEndorsed")
                            {
                                Debugger.Break();
                            }
                            Debug.WriteLine("Changed: " + ls.key);
                            Debug.WriteLine("  OLD: " + oldString);
                            Debug.WriteLine("  NEW: " + lineInfo.text);
                            ls.ChangedFromPrevious = true;
                        }
                    }
                    else if (oldStuff.Any())
                    {
                        Debug.WriteLine("New: " + ls.key);
                        ls.ChangedFromPrevious = true;
                    }

                    if (lineInfo.key == null)
                    {
                        Debugger.Break();
                    }
                    if (ls.INT == null)
                    {
                        Debugger.Break();
                    }
                    cat.LocalizedStringsForSection.Add(ls);
                }

                if (cat != null)
                {
                    categories.Add(cat);
                }

                parseLocalizations(categories, dictionaries);
                y.Result = categories;

                //TIPS SERVICE
                PleaseWaitString = $"Fetching Tips Service";

                string tipsEndpoint = "https://me3tweaks.com/modmanager/services/tipsservice";
                string contents;
                var    wc       = new System.Net.WebClient();
                var    tipsJson = wc.DownloadString(tipsEndpoint);
                var    jsonObj  = JsonConvert.DeserializeObject <Dictionary <string, List <string> > >(tipsJson);
                var    langs    = LocalizedString.Languages.Where(x => x != "int");
                var    locTips  = new List <LocalizedString>();
                for (int i = 0; i < jsonObj["int"].Count; i++)
                {
                    LocalizedString ls = new LocalizedString()
                    {
                        INT = jsonObj["int"][i]
                    };
                    foreach (var lang in langs)
                    {
                        if (jsonObj[lang].Count <= i)
                        {
                            continue;                           //skip
                        }
                        switch (lang)
                        {
                        case "rus":
                            ls.RUS = jsonObj["rus"][i];
                            break;

                        case "deu":
                            ls.DEU = jsonObj["deu"][i];
                            break;

                        case "pol":
                            ls.POL = jsonObj["pol"][i];
                            break;

                        case "fra":
                            ls.FRA = jsonObj["fra"][i];
                            break;

                        case "esn":
                            ls.ESN = jsonObj["esn"][i];
                            break;

                        case "bra":
                            ls.BRA = jsonObj["bra"][i];
                            break;
                        }
                    }
                    locTips.Add(ls);
                }
                System.Windows.Application.Current.Dispatcher.Invoke(delegate
                {
                    LocalizedTips.ReplaceAll(locTips);
                });

                //DYNAMIC HELP
                PleaseWaitString = $"Fetching Dynamic Help";

                endpoint = $"https://raw.githubusercontent.com/ME3Tweaks/ME3TweaksModManager/{branch}/MassEffectModManagerCore/staticfiles/dynamichelp/latesthelp-localized.xml";
                var       dynamicHelpXml = wc.DownloadString(endpoint);
                XDocument doc            = XDocument.Parse(dynamicHelpXml);
                var       intxml         = doc.XPathSelectElement("/localizations/helpmenu[@lang='int']");
                dynamicHelpLocalizations["int"] = intxml.ToString();

                //Debug.WriteLine(doc.ToString());
                foreach (var lang in langs)
                {
                    var langxml = doc.XPathSelectElement($"/localizations/helpmenu[@lang='{lang}']");
                    if (langxml != null)
                    {
                        dynamicHelpLocalizations[lang] = langxml.ToString();
                    }
                }

                // TUTORIAL SERVICE
                PleaseWaitString = $"Fetching Tutorial Service";

                string tutorialEndpoint = "https://me3tweaks.com/modmanager/services/tutorialservice";
                wc.Dispose();
                wc = new System.Net.WebClient();
                var tutorialJson = wc.DownloadString(tutorialEndpoint);
                var TSjsonObj    = JsonConvert.DeserializeObject <List <Dictionary <string, string> > >(tutorialJson);
                langs = LocalizedString.Languages.Where(x => x != "int");
                var locTutorial = new List <LocalizedString>();
                for (int i = 0; i < TSjsonObj.Count; i++)
                {
                    LocalizedString ls = new LocalizedString()
                    {
                        INT = TSjsonObj[i]["lang_int"]
                    };
                    foreach (var lang in langs)
                    {
                        switch (lang)
                        {
                        case "rus":
                            ls.RUS = TSjsonObj[i]["lang_rus"];
                            break;

                        case "deu":
                            ls.DEU = TSjsonObj[i]["lang_deu"];
                            break;

                        case "pol":
                            ls.POL = TSjsonObj[i]["lang_pol"];
                            break;

                        case "fra":
                            ls.FRA = TSjsonObj[i]["lang_fra"];
                            break;

                        case "esn":
                            ls.ESN = TSjsonObj[i]["lang_esn"];
                            break;

                        case "bra":
                            ls.BRA = TSjsonObj[i]["lang_bra"];
                            break;
                        }
                    }
                    locTutorial.Add(ls);
                }

                PleaseWaitString = "";

                System.Windows.Application.Current.Dispatcher.Invoke(delegate
                {
                    LocalizedTutorialService.ReplaceAll(locTutorial);
                    intViewer.Text = intxml.ToString();
                });
            };
            bw.RunWorkerCompleted += (a, b) =>
            {
                if (b.Error == null && b.Result is List <LocalizationCategory> categories)
                {
                    LoadingVisibility = Visibility.Collapsed;
                    LocalizationCategories.ReplaceAll(categories);
                }
            };
            bw.RunWorkerAsync();
        }