using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.IO; using System.Text.RegularExpressions; using System.Resources; using System.Collections; using System.ComponentModel.Design; namespace EduNetworkBuilder { public partial class TranslationWindow : Form { Network myNet = null; string[,] LanguageChoices = NB.LanguageChoices; string FormChosenDir = ""; List TranslationResxFiles = new List(); List FormData = new List(); string EnglishTargetFile = "edustrings.resx"; bool ChangedFormData = false; bool ChangedPuzzleData = false; ToolTip myTooltip = new ToolTip(); public TranslationWindow(Network ToEdit) { InitializeComponent(); this.KeyPreview = true; myNet = ToEdit; LocalSetup(); } void LocalSetup() { FillTranslationFormData(); myTooltip.AutoPopDelay = 5000; myTooltip.InitialDelay = 1000; myTooltip.ReshowDelay = 500; cb1Language.Items.Clear(); cb2Language.Items.Clear(); cbFormLang1Choice.Items.Clear(); cbFormLang2Choice.Items.Clear(); cbFormHighPriority.CheckedChanged += PopulateFormTranslationItems; cbFormShowTranslated.CheckedChanged += PopulateFormTranslationItems; cbFormFilter.Items.Clear(); foreach(TranslationFormData TFD in FormData) { cbFormFilter.Items.Add(TFD.Prefix); } panelTranslateFormItems.Enabled = false; NBSettings mySettings = NB.GetSettings(); //See if the file we are editing has the right folder. If so, we do not need to choose one FormChosenDir = mySettings.FormLastTransDir; if (!TryToChooseFormDir(FormChosenDir)) TryToChooseFormDir(Path.GetDirectoryName(myNet.NetworkFilename)); for (int i = 0; i < LanguageChoices.GetLength(0); i++) { cb1Language.Items.Add(LanguageChoices[i, 0]); cb2Language.Items.Add(LanguageChoices[i, 0]); cbFormLang1Choice.Items.Add(LanguageChoices[i, 0]); cbFormLang2Choice.Items.Add(LanguageChoices[i, 0]); if (mySettings.LastTrans1Lang == LanguageChoices[i, 1]) { cb1Language.SelectedItem = LanguageChoices[i, 0]; cbFormLang1Choice.SelectedItem = LanguageChoices[i, 0]; } if (mySettings.LastTrans2Lang == LanguageChoices[i, 1]) { cb2Language.SelectedItem = LanguageChoices[i, 0]; cbFormLang2Choice.SelectedItem = LanguageChoices[i, 0]; } } if (cb1Language.SelectedIndex == -1) cb1Language.SelectedIndex = 0; if (cb2Language.SelectedIndex == -1) cb2Language.SelectedIndex = 0; Icon = Properties.Resources.NBIco; lblStatus.Text = ""; LanguagifyComponents(); cbFormFilter.Text = "Any"; } private void LanguagifyComponents() { Text = NB.Translate("TW_Translate"); btnSave.Text = NB.Translate("_Save"); btnClose.Text = NB.Translate("_Done"); tpMessageTitle.Text = NB.Translate("TW_Message"); tpFormStuff.Text = NB.Translate("TW_Form"); } private void FillTranslationFormData() { FormData.Clear(); FormData.Add(new TranslationFormData("TW_", "Translation Window. The Window where translation into another language is done.", 1)); FormData.Add(new TranslationFormData("_", "Phrases which are used on multiple windows", 10)); FormData.Add(new TranslationFormData("Any", "Not Filtered by form", 0)); FormData.Add(new TranslationFormData("DC_", "Device Config Window. This is where you configure the switch, firewall, PC, etc.", 10)); FormData.Add(new TranslationFormData("H_", "The Help system.", 1)); FormData.Add(new TranslationFormData("IPAE_", "IP Address Editor. This is the IP Address Edit Window where you set the IP, subnet, gateway, etc", 9)); FormData.Add(new TranslationFormData("LBW_", "ListBox Window. This is mainly the list of puzzles.", 8)); FormData.Add(new TranslationFormData("LE_", "LinkEditor. This is where you define a network link between two devices", 6)); FormData.Add(new TranslationFormData("N_", "Network. The Network is basically the collection of devices, links, tests and the like. Most of the things translated are status or error messages.", 4)); FormData.Add(new TranslationFormData("NB_", "NetworkBuilder Window. This is the main window and the menus on that window.", 10)); FormData.Add(new TranslationFormData("NC_", "NetworkCard. The card itself mainly just generates error messages.", 4)); FormData.Add(new TranslationFormData("NCE_", "Network Card Editor. The window where you define the network card (VPN, Wireless card, etc)", 7)); FormData.Add(new TranslationFormData("ND_", "Network Device. The device is what generates most of the main error messages.", 8)); FormData.Add(new TranslationFormData("NI_", "Network Interface. This generates some error messages (VLAN, etc)", 3)); FormData.Add(new TranslationFormData("NL_", "Network Link. Generates some error messages when packets are corrupt.", 7)); FormData.Add(new TranslationFormData("NT_", "Network Test. These are the things that make the puzzles puzzling.", 10)); FormData.Add(new TranslationFormData("NTE_", "Network Test Editor. This is the window where you edit the network tests.", 2)); FormData.Add(new TranslationFormData("OW_", "Options Window. Where the puzzle options are configured. Teachers use this, but most students would not", 3)); FormData.Add(new TranslationFormData("Options_", "A few options which are used both on the options window, but also on the main window", 9)); FormData.Add(new TranslationFormData("P_", "Packet. The error messages that the packet itself generates.", 7)); FormData.Add(new TranslationFormData("PC_", "Person Class. When working with students and faculty.", 2)); FormData.Add(new TranslationFormData("PM_", "Packet Messages. The system for dealing with packet messages", 4)); FormData.Add(new TranslationFormData("PPF_", "Person Profile Form. When dealing with faculty / students.", 1)); FormData.Add(new TranslationFormData("RPC_", "Random Puzzle Chooser. The form for generating a random puzzle", 5)); FormData.Add(new TranslationFormData("RTFW_", "RichText Window. A multipurpose window. Used for displaying help or the puzzle description.", 7)); FormData.Sort((a, b) => a.Prefix.CompareTo(b.Prefix) ); } private void ClosingStuff() { NBSettings mySettings = NB.GetSettings(); for (int i = 0; i < LanguageChoices.GetLength(0); i++) { if (cb1Language.Text == LanguageChoices[i, 0]) { mySettings.LastTrans1Lang = LanguageChoices[i, 1]; } if (cb2Language.Text == LanguageChoices[i, 0]) { mySettings.LastTrans2Lang = LanguageChoices[i, 1]; } mySettings.FormLastTransDir = FormChosenDir; } mySettings.Save(); } string CodeFromLang(string language) { for (int i = 0; i < LanguageChoices.GetLength(0); i++) { if (language == LanguageChoices[i, 0]) return LanguageChoices[i, 1]; } return ""; } string LangFromCode(string Code) { for (int i = 0; i < LanguageChoices.GetLength(0); i++) { if (Code == LanguageChoices[i, 1]) return LanguageChoices[i, 0]; } return ""; } private void btnClose_Click(object sender, EventArgs e) { Close(); } private void Save() { if (ChangedPuzzleData && File.Exists(myNet.NetworkFilename)) { myNet.Save(); //Console.WriteLine("Saved"); lblStatus.Text = NB.Translate("_Saved"); } if(ChangedFormData) { foreach (TranslationResxFile one in TranslationResxFiles) one.Save(); ChangedFormData = false; lblStatus.Text = NB.Translate("_Saved"); } } private void TranslationWindow_KeyDown(object sender, KeyEventArgs e) { if(e.Modifiers == Keys.Control && e.KeyCode == Keys.S) { //ctrl-s was pressed Save(); } } private void TranslationWindow_FormClosing(object sender, FormClosingEventArgs e) { if(ChangedFormData || ChangedPuzzleData) { DialogResult answer = MessageBox.Show("Save?", "Save?", MessageBoxButtons.YesNoCancel); if(answer == DialogResult.Cancel) { e.Cancel = true; return; } if (answer == DialogResult.Yes) Save(); } ClosingStuff(); } private void cb1Language_SelectedIndexChanged(object sender, EventArgs e) { string What = CodeFromLang(cb1Language.Text); if (What != "") { tb1Message.Text = myNet.NetMessage.GetText(What); tb1Title.Text = myNet.NetTitle.GetText(What); tb1URL.Text = myNet.NetURL.GetText(What); } } private void cb2Language_SelectedIndexChanged(object sender, EventArgs e) { string What = CodeFromLang(cb2Language.Text); if (What != "") { tb2Message.Text = myNet.NetMessage.GetText(What); tb2Title.Text = myNet.NetTitle.GetText(What); tb2URL.Text = myNet.NetURL.GetText(What); } } void RefreshContents() { cb1Language_SelectedIndexChanged(null, EventArgs.Empty); cb2Language_SelectedIndexChanged(null, EventArgs.Empty); lblStatus.Text = ""; } private void tb1Message_Leave(object sender, EventArgs e) { string What = CodeFromLang(cb1Language.Text); if (What != "") { if (tb1Message.Text != myNet.NetMessage.GetText(What)) { ChangedPuzzleData = true; myNet.NetMessage.ChangeText(What, tb1Message.Text); } } RefreshContents(); } private void tb2Message_Leave(object sender, EventArgs e) { string What = CodeFromLang(cb2Language.Text); if (What != "") { if (tb2Message.Text != myNet.NetMessage.GetText(What)) { ChangedPuzzleData = true; myNet.NetMessage.ChangeText(What, tb2Message.Text); } } RefreshContents(); } private void btnSave_Click(object sender, EventArgs e) { Save(); } private void tb1Title_Leave(object sender, EventArgs e) { string What = CodeFromLang(cb1Language.Text); if (What != "") { myNet.NetTitle.ChangeText(What, tb1Title.Text); } RefreshContents(); } private void tb2Title_Leave(object sender, EventArgs e) { string What = CodeFromLang(cb2Language.Text); if (What != "") { myNet.NetTitle.ChangeText(What, tb2Title.Text); } RefreshContents(); } private void tb1URL_Leave(object sender, EventArgs e) { string What = CodeFromLang(cb1Language.Text); if (What != "") { myNet.NetURL.ChangeText(What, tb1URL.Text); } RefreshContents(); } private void tb2URL_Leave(object sender, EventArgs e) { string What = CodeFromLang(cb2Language.Text); if (What != "") { myNet.NetURL.ChangeText(What, tb2URL.Text); } RefreshContents(); } #region Form Translation Stuff //**********************************************************************// //******************* Form Translation Things **************************// //**********************************************************************// bool TryToChooseFormDir(string Choice) { if (Choice == null || Choice == "") return false; //We want to have a file named edustrings.resx there //There may be other files: edustrings.fr.resx //If these exist, we are OK. Otherwise, see if there is a "languages" dir and try that if it does exist string toCheck = Path.GetFileName(Choice).ToLower(); if (File.Exists(Choice)) if (toCheck == EnglishTargetFile) { FormChosenDir = Path.GetDirectoryName(Choice); LoadResxFiles(); panelTranslateFormItems.Enabled = true; lblFormDir.Text = "Dir: " + FormChosenDir; lblFormDir.AutoSize = true; lblFormDir.MaximumSize = new Size(250, 200); return true; } if(Directory.Exists(Choice)) { //It is a directory. See if it has the correct file in it. if (TryToChooseFormDir(Path.Combine(Choice, EnglishTargetFile))) { return true; //It was successful } //If we get here, it did not have the file. See if there is a "languages" directory if (TryToChooseFormDir(Path.Combine(Choice, "languages", EnglishTargetFile))) { return true; //It was successful } } return false; } void LoadResxFiles() { if (!Directory.Exists(FormChosenDir)) return; var resxFiles = Directory.EnumerateFiles(FormChosenDir, "*.resx", SearchOption.AllDirectories); TranslationResxFiles.Clear(); foreach (string currentFile in resxFiles) { TranslationResxFile TRF = new TranslationResxFile(currentFile); TranslationResxFiles.Add(TRF); } //Add any resx files that do not exist, but should for( int i=0; i< LanguageChoices.GetLength(0); i++) { TranslationResxFile one = FileFromLangCode(LanguageChoices[i, 1]); if(one == null) { //We need to make an empty resx file one = new TranslationResxFile(); one.language = LanguageChoices[i, 1]; string filename = "edustrings."+ LanguageChoices[i, 1] + ".resx"; one.filename = filename; TranslationResxFiles.Add(one); } } //Populate any missing entries. TranslationResxFile EN = FileFromLangCode("en"); if(EN != null) //Being null had better not happen... But just in case. { TranslationItem tempTI = null; foreach(TranslationResxFile TRF in TranslationResxFiles) { if (TRF.language == EN.language) continue; //skip eng since that is the master //Make sure each language has each item that the Eng version has foreach(TranslationItem TI in EN.Items) { tempTI = ItemFromKey(TRF, TI.Key); if(tempTI == null) //It does not exist in this language. Add it { tempTI = new TranslationItem(TI); tempTI.translated = false; //Make sure it is set to false. TRF.Items.Add(tempTI); ChangedFormData = true; //We have changed something. We want to be able to save it } } } } //Populate the fields from our new data PopulateFormTranslationItems(); } void PopulateFormTranslationItems(object sender, EventArgs e) { PopulateFormTranslationItems(); } private void PopulateFormTranslationItems() { cbFormItemChoice.Items.Clear(); TranslationResxFile en = FileFromLangCode("en"); List Priorities = new List() { }; foreach(TranslationFormData TFD in FormData) { if (TFD.Importance > 5) Priorities.Add(TFD.Prefix); } if(en != null) { foreach(TranslationItem TI in en.Items) { bool AddTranslated = false; bool AddHigh = false; if (cbFormFilter.Text != "Any") { if (!TI.Key.StartsWith(cbFormFilter.Text)) continue;//Skip it if it does not match the filter. } if (!TI.translated || cbFormShowTranslated.Checked) AddTranslated = true; if (cbFormHighPriority.Checked) { foreach(string one in Priorities) { if(TI.Key.StartsWith(one)) { AddHigh = true; break; } } } else AddHigh = true; if(AddTranslated && AddHigh) cbFormItemChoice.Items.Add(TI.Key); } } if(cbFormItemChoice.SelectedIndex <0) { if (cbFormItemChoice.Items.Count > 0) cbFormItemChoice.SelectedIndex = 1; } else { cbFormItemChoice.Text = ""; } } private TranslationResxFile FileFromLangCode(string code) { foreach (TranslationResxFile one in TranslationResxFiles) if (one.language == code) return one; return null; } private TranslationItem ItemFromKey(TranslationResxFile File, string Key) { if (File == null) return null; foreach(TranslationItem TI in File.Items) { if (TI.Key == Key) return TI; } return null; } private TranslationItem GetEditedTranslationItem() { string code = CodeFromLang(cbFormLang2Choice.Text); TranslationResxFile TRf = FileFromLangCode(code); TranslationItem TI = ItemFromKey(TRf, cbFormItemChoice.Text); return TI; } private void btnChooseDir_Click(object sender, EventArgs e) { string startingDir = FormChosenDir; if (FormChosenDir == "" && File.Exists(myNet.NetworkFilename)) startingDir = Path.GetDirectoryName(myNet.NetworkFilename); //Prompt for a directory. OpenFileDialog ofd = NB.SelectDirectoryDialog("Directory with language files", startingDir); if(ofd.FileName != "") { //try to see if the chosen filename has appropriate files. We need the English, at least if(!TryToChooseFormDir(Path.GetDirectoryName(ofd.FileName))) { MessageBox.Show("Invalid Directory."); } } } private void cbFormItemChoice_SelectedIndexChanged(object sender, EventArgs e) { string code = CodeFromLang(cbFormLang1Choice.Text); TranslationResxFile TRf = FileFromLangCode(code); TranslationItem TI = ItemFromKey(TRf, cbFormItemChoice.Text); if(TRf != null && TI != null) { tbFormItem1.Text = TI.Value; } code = CodeFromLang(cbFormLang2Choice.Text); TRf = FileFromLangCode(code); TI = ItemFromKey(TRf, cbFormItemChoice.Text); if (TRf != null && TI != null) { tbFormItem2.Text = TI.Value; cbFormItemTranslated.Checked = TI.translated; } } private void cbFormItemTranslated_CheckedChanged(object sender, EventArgs e) { TranslationItem TI = GetEditedTranslationItem(); if(TI != null) { TI.translated = cbFormItemTranslated.Checked; ChangedFormData = true; } } private void tbFormItem2_Leave(object sender, EventArgs e) { //If the text no longer matches, we want to update it. TranslationItem TI = GetEditedTranslationItem(); if (TI != null) { //only make a note if it has changed if (TI.Value != tbFormItem2.Text) { TI.Value = tbFormItem2.Text; ChangedFormData = true; } } } private void cbFormFilter_SelectedIndexChanged(object sender, EventArgs e) { //We want to filter the form based on what we have here. PopulateFormTranslationItems(); string tooltip = ""; foreach(TranslationFormData one in FormData) { if(one.Prefix == cbFormFilter.Text) { tooltip = one.Description; break; } } myTooltip.SetToolTip(cbFormFilter,tooltip); } } #endregion #region TranslationClasses public class TranslationItem { public string Key = ""; public string Value = ""; public string Comment = ""; public bool translated = false; public TranslationItem() { } public TranslationItem(TranslationItem Source) { Key = Source.Key; Value = Source.Value; Comment = Source.Comment; translated = Source.translated; } } public class TranslationResxFile { public string filename; public List Items = new List(); public string language = ""; string beginning = "translated: "; public TranslationResxFile() { } public TranslationResxFile(string File) { filename = File; Load(); string fn = Path.GetFileName(File); if (fn == "edustrings.resx") { language = "en"; } else language = fn.Substring(11, 2); } void Load() { if(! File.Exists(filename)) { //The file does not exist yet. Nothing to load. Exit gracefully return; } Items.Clear(); ResXResourceReader InResx = new ResXResourceReader(filename); InResx.UseResXDataNodes = true; System.Reflection.Assembly currentAssembly = System.Reflection.Assembly.GetExecutingAssembly(); foreach (DictionaryEntry d in InResx) { ResXDataNode rdn = (ResXDataNode)d.Value; TranslationItem TI = new TranslationItem(); TI.Comment = rdn.Comment; if (TI.Comment.StartsWith(beginning)) { //trim off the beginning "translated" tag TI.Comment = rdn.Comment.Substring(0, beginning.Length - 1); TI.translated = true; } TI.Key = rdn.Name; TI.Value = (string)rdn.GetValue(new System.Reflection.AssemblyName[] { currentAssembly.GetName() }); Items.Add(TI); } Items.Sort((a,b) => a.Key.CompareTo(b.Key)); InResx.Close(); } public void Save() { string tmpfile = Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename) + "-tmp" + Path.GetExtension(filename)); ResXResourceWriter WriteResx = new ResXResourceWriter(tmpfile); foreach (TranslationItem d in Items) { ResXDataNode rdn = new ResXDataNode(d.Key, d.Value); if (d.translated) rdn.Comment = beginning + d.Comment; else rdn.Comment = d.Comment; WriteResx.AddResource(rdn); //Console.WriteLine("Adding " + toWrite.Name); } WriteResx.Generate(); WriteResx.Close(); //If we have an error, we should have exited and gone to "catch." //Proceed to put the new file if(File.Exists(filename)) File.Delete(filename); File.Move(tmpfile, filename); } } public class TranslationFormData { public string Prefix; public string Description; public int Importance; //10 is most important, 0 is least important public TranslationFormData(string prefix, string description, int importance) { Prefix = prefix; Description = description; Importance = importance; } } #endregion }