/*
         * Serialization:
         */

        public void Save(string fileName, string version)
        {
            string newFileName = fileName;
            string newFilePath = Path.Combine(Localization.LanguageFolder, newFileName);

            // Create document and root:
            XDocument xmlDoc  = new XDocument();
            XElement  xmlRoot = new XElement("Language");

            xmlRoot.Add(new XAttribute("name", this.Name));
            xmlRoot.Add(new XAttribute("iso", this.ISO));
            if (this.ISO != "en-US" && this.Author.Length > 0)
            {
                xmlRoot.Add(new XAttribute("author", this.Author));
            }

            if (this.ISO == "en-US")
            {
                xmlDoc.AddFirst(
                    new XComment("\n" +
                                 "     This file is auto-generated on program start.\n" +
                                 "     Therefore any changes made to this file will be overwritten.\n" +
                                 "     You can use this as a template for your own translation, though.\n" +
                                 "\n" +
                                 "     If you need help with translating, you can find a guide here:\n" +
                                 "     https://github.com/FelisDiligens/Fallout76-QuickConfiguration/wiki/Translations\n"));
            }
            else
            {
                xmlDoc.AddFirst(
                    new XComment("\n" +
                                 "     This is a template that contains some of the already translated elements.\n" +
                                 "     You can rename it from \"*.template.xml\" to \"*.xml\" and translate the added elements.\n" +
                                 "\n" +
                                 "     If you need help with translating, you can find a guide here:\n" +
                                 "     https://github.com/FelisDiligens/Fallout76-QuickConfiguration/wiki/Translations\n"));
            }

            xmlRoot.Add(new XAttribute("version", version));
            xmlDoc.Add(xmlRoot);

            // Serialize external stuff:
            // TODO: Find a way to remove the references, plz:
            XElement xmlStrings      = Localization.SerializeStrings();
            XElement xmlDropDowns    = DropDown.SerializeAll();
            XElement xmlMsgBoxes     = MsgBox.SerializeAll();
            XElement xmlDescriptions = LinkedTweaks.SerializeTweakDescriptionList();
            string   separator       = "".PadLeft(150, '*');

            xmlStrings.AddFirst(new XComment($"\n        Strings\n        {separator}\n        Basically little text snippets that can be used everywhere.\n    "));
            xmlDropDowns.AddFirst(new XComment($"\n        Dropdowns\n        {separator}\n        Make sure that the amount of options stays the same.\n    "));
            xmlMsgBoxes.AddFirst(new XComment($"\n        Message boxes\n        {separator}\n        The {"{0}"} is a placeholder, btw.\n    "));
            xmlDescriptions.AddFirst(new XComment($"\n        Descriptions\n        {separator}\n        These are the descriptions of almost all tweaks.\n        They appear in tool tips, when the user hovers over a tweak with the mouse cursor.\n    "));
            xmlRoot.Add(xmlStrings);
            xmlRoot.Add(xmlDropDowns);
            xmlRoot.Add(xmlMsgBoxes);
            xmlRoot.Add(xmlDescriptions);

            ignoreTooltipsOfTheseControls = LinkedTweaks.GetListOfLinkedControlNames();

            // Serialize all control elements:
            foreach (LocalizedForm form in Localization.LocalizedForms)
            {
                XElement xmlForm = new XElement(form.Form.Name, new XAttribute("title", form.Form.Text));
                xmlForm.AddFirst(new XComment($"\n        {form.Form.Name}\n        {separator}\n        {form.Form.Text}\n    "));
                SerializeControls(xmlForm, form.Form, form.ToolTip);
                foreach (Control control in form.SpecialControls)
                {
                    SerializeControl(xmlForm, control, form.ToolTip);
                }
                xmlRoot.Add(xmlForm);
            }

            // Save it:
            Directory.CreateDirectory(Localization.LanguageFolder);
            xmlDoc.Save(newFilePath);
        }
        /*
         * Deserialization:
         */

        public void Apply()
        {
            try
            {
                // Read *.xml file:
                XDocument xmlDoc  = XDocument.Load(this.filePath);
                XElement  xmlRoot = xmlDoc.Element("Language");

                ignoreTooltipsOfTheseControls = LinkedTweaks.GetListOfLinkedControlNames();

                // Translate each form individually:
                foreach (LocalizedForm form in Localization.LocalizedForms)
                {
                    XElement xmlForm = xmlRoot.Element(form.Form.Name);

                    // Ignore non-existing forms
                    if (xmlForm == null)
                    {
                        continue; // throw new InvalidXmlException($"Couldn't find <{form.Form.Name}>");
                    }
                    // Set title, if it exists:
                    if (xmlForm.Attribute("title") != null)
                    {
                        form.Form.Text = xmlForm.Attribute("title").Value;
                    }

                    // Forms:
                    DeserializeDictionaries(xmlForm); // TODO: xmlRoot replaced with xmlForm. Good idea?
                    DeserializeControls(xmlForm, form.Form, form.ToolTip);
                    foreach (Control subControl in form.SpecialControls)
                    {
                        DeserializeControl(xmlForm, subControl, form.ToolTip);
                    }

                    // Message boxes:
                    XElement xmlMsgBox = xmlRoot.Element("Messageboxes");
                    if (xmlMsgBox != null)
                    {
                        MsgBox.Deserialize(xmlMsgBox);
                    }

                    // Strings:
                    XElement xmlStrings = xmlRoot.Element("Strings");
                    if (xmlStrings != null)
                    {
                        Localization.DeserializeStrings(xmlStrings);
                    }

                    // TODO: Generalize this. No outside references, plz:

                    // TODO: Doesn't make sense to deserialize them multiple times:

                    // Drop downs:
                    XElement xmlDropDowns = xmlRoot.Element("Dropdowns");
                    if (xmlDropDowns != null)
                    {
                        DropDown.DeserializeAll(xmlDropDowns);
                    }

                    // Tweak descriptions:
                    XElement xmlTweakDescriptions = xmlRoot.Element("TweakDescriptions");
                    if (xmlTweakDescriptions != null)
                    {
                        LinkedTweaks.DeserializeTweakDescriptionList(xmlTweakDescriptions);
                    }
                    if (form.ToolTip != null)
                    {
                        LinkedTweaks.SetToolTips(); // TODO: No need to call it per form anymore
                    }
                }

                // Call event handler:
                if (LanguageChanged != null)
                {
                    TranslationEventArgs e = new TranslationEventArgs();
                    e.HasAuthor = this.Author != "";
                    //e.ActiveTranslation = this;
                    LanguageChanged(this, e);
                }
            }
            catch (Exception exc)
            {
                MsgBox.Show("Loading translation failed", $"The translation '{Path.GetFileNameWithoutExtension(filePath)}' couldn't be loaded.\n{exc.GetType()}: {exc.Message}", MessageBoxIcon.Error);
            }
        }