Ejemplo n.º 1
0
 private void AddDummySuggestion()
 {
     SuggestionViewModel suggestion = new SuggestionViewModel(this);
     suggestion.IsDummy = true;
     suggestion.BaseText = Tx.T("suggestions.none");
     suggestions.Add(suggestion);
 }
Ejemplo n.º 2
0
        private void UpdateSuggestions()
        {
            Match m;

            suggestions.Clear();
            HaveSuggestions = false;

            if (string.IsNullOrEmpty(LastSelectedCulture))
            {
                AddDummySuggestion();
                return;
            }
            if (!LoadedCultureNames.Contains(LastSelectedCulture))
            {
                AddDummySuggestion();
                return;
            }
            SuggestionsCulture = CultureInfoName(new CultureInfo(LastSelectedCulture), false);
            //if (lastSelectedCulture == primaryCulture) return;

            TextKeyViewModel tk = selectedTextKeys != null && selectedTextKeys.Count > 0 ? selectedTextKeys[0] : null;
            if (tk == null || tk.CultureTextVMs.Count < 1)
            {
                AddDummySuggestion();
                return;
            }

            // The text we're finding translation suggestions for
            string refText = tk.CultureTextVMs[0].Text;
            string origRefText = refText;
            if (refText == null)
            {
                AddDummySuggestion();
                return;
            }

            //// Find the most common words to filter them out
            //Dictionary<string, int> wordCount = new Dictionary<string, int>();
            //foreach (var kvp in TextKeys)
            //{
            //    string otherBaseText = kvp.Value.CultureTextVMs[0].Text;
            //    if (string.IsNullOrEmpty(otherBaseText)) continue;

            //    // Remove all placeholders and key references
            //    string otherText = Regex.Replace(otherBaseText, @"(?<!\{)\{[^{]*?\}", "");

            //    // Extract all words
            //    m = Regex.Match(otherText, @"(\w{2,})");
            //    while (m.Success)
            //    {
            //        string lcWord = m.Groups[1].Value.ToLowerInvariant();

            //        int count;
            //        if (wordCount.TryGetValue(lcWord, out count))
            //        {
            //            wordCount[lcWord] = count + 1;
            //        }
            //        else
            //        {
            //            wordCount[lcWord] = 1;
            //        }

            //        m = m.NextMatch();
            //    }
            //}

            //HashSet<string> commonWords = new HashSet<string>();
            //if (wordCount.Count > 0)
            //{
            //    int maxCount = wordCount.Select(kvp => kvp.Value).Max();
            //    foreach (var kvp in wordCount.OrderByDescending(kvp => kvp.Value))
            //    {
            //        if (commonWords.Count < (int) (wordCount.Count * 0.05) ||
            //            kvp.Value >= (int) (maxCount * 0.8))
            //        {
            //            commonWords.Add(kvp.Key);
            //        }
            //    }
            //}

            //commonWords.Clear();
            //commonWords.Add("all");
            //commonWords.Add("also");
            //commonWords.Add("an");
            //commonWords.Add("and");
            //commonWords.Add("are");
            //commonWords.Add("as");
            //commonWords.Add("at");
            //commonWords.Add("be");
            //commonWords.Add("but");
            //commonWords.Add("by");
            //commonWords.Add("can");
            //commonWords.Add("cannot");
            //commonWords.Add("do");
            //commonWords.Add("don");
            //commonWords.Add("each");
            //commonWords.Add("for");
            //commonWords.Add("from");
            //commonWords.Add("have");
            //commonWords.Add("if");
            //commonWords.Add("in");
            //commonWords.Add("into");
            //commonWords.Add("is");
            //commonWords.Add("it");
            //commonWords.Add("its");
            //commonWords.Add("may");
            //commonWords.Add("must");
            //commonWords.Add("no");
            //commonWords.Add("not");
            //commonWords.Add("of");
            //commonWords.Add("on");
            //commonWords.Add("please");
            //commonWords.Add("that");
            //commonWords.Add("the");
            //commonWords.Add("there");
            //commonWords.Add("this");
            //commonWords.Add("those");
            //commonWords.Add("to");
            //commonWords.Add("were");
            //commonWords.Add("will");
            //commonWords.Add("with");
            //commonWords.Add("would");
            //commonWords.Add("you");
            //commonWords.Add("your");

            HashSet<string> commonWords;
            if (LastSelectedCulture.StartsWith("de"))
            {
                // GERMAN STOPWORDS
                // Zusammmengetragen von Marco Götze, Steffen Geyer
                // Last update: 2011-01-15
                // Source: http://solariz.de/649/deutsche-stopwords.htm
                // Via: http://en.wikipedia.org/wiki/Stop_words
                commonWords = new HashSet<string>(new string[]
                {
                    "ab", "aber", "abgerufen", "abgerufene", "abgerufener", "abgerufenes", "acht", "ähnlich", "alle", "allein", "allem",
                    "allen", "aller", "allerdings", "allerlei", "alles", "allgemein", "allmählich", "allzu", "als", "alsbald", "also",
                    "am", "an", "ander", "andere", "anderem", "anderen", "anderer", "andererseits", "anderes", "anderm", "andern",
                    "andernfalls", "anders", "anerkannt", "anerkannte", "anerkannter", "anerkanntes", "anfangen", "anfing", "angefangen",
                    "angesetze", "angesetzt", "angesetzten", "angesetzter", "ansetzen", "anstatt", "arbeiten", "auch", "auf", "aufgehört",
                    "aufgrund", "aufhören", "aufhörte", "aufzusuchen", "aus", "ausdrücken", "ausdrückt", "ausdrückte", "ausgenommen",
                    "außen", "ausser", "außer", "ausserdem", "außerdem", "außerhalb", "author", "autor", "bald", "bearbeite",
                    "bearbeiten", "bearbeitete", "bearbeiteten", "bedarf", "bedürfen", "bedurfte", "befragen", "befragte", "befragten",
                    "befragter", "begann", "beginnen", "begonnen", "behalten", "behielt", "bei", "beide", "beiden", "beiderlei", "beides",
                    "beim", "beinahe", "beitragen", "beitrugen", "bekannt", "bekannte", "bekannter", "bekennen", "benutzt", "bereits",
                    "berichten", "berichtet", "berichtete", "berichteten", "besonders", "besser", "bestehen", "besteht", "beträchtlich",
                    "bevor", "bezüglich", "bietet", "bin", "bis", "bis", "bisher", "bislang", "bist", "bleiben", "blieb", "bloß", "bloss",
                    "böden", "brachte", "brachten", "brauchen", "braucht", "bräuchte", "bringen", "bsp", "bzw", "ca", "da", "dabei",
                    "dadurch", "dafür", "dagegen", "daher", "dahin", "damals", "damit", "danach", "daneben", "dank", "danke", "danken",
                    "dann", "dannen", "daran", "darauf", "daraus", "darf", "darfst", "darin", "darüber", "darüberhinaus", "darum",
                    "darunter", "das", "daß", "dass", "dasselbe", "davon", "davor", "dazu", "dein", "deine", "deinem", "deinen", "deiner",
                    "deines", "dem", "demnach", "demselben", "den", "denen", "denn", "dennoch", "denselben", "der", "derart", "derartig",
                    "derem", "deren", "derer", "derjenige", "derjenigen", "derselbe", "derselben", "derzeit", "des", "deshalb",
                    "desselben", "dessen", "desto", "deswegen", "dich", "die", "diejenige", "dies", "diese", "dieselbe", "dieselben",
                    "diesem", "diesen", "dieser", "dieses", "diesseits", "dinge", "dir", "direkt", "direkte", "direkten", "direkter",
                    "doch", "doppelt", "dort", "dorther", "dorthin", "drauf", "drei", "dreißig", "drin", "dritte", "drüber", "drunter",
                    "du", "dunklen", "durch", "durchaus", "dürfen", "durfte", "dürfte", "durften", "eben", "ebenfalls", "ebenso", "ehe",
                    "eher", "eigenen", "eigenes", "eigentlich", "ein", "einbaün", "eine", "einem", "einen", "einer", "einerseits",
                    "eines", "einfach", "einführen", "einführte", "einführten", "eingesetzt", "einig", "einige", "einigem", "einigen",
                    "einiger", "einigermaßen", "einiges", "einmal", "eins", "einseitig", "einseitige", "einseitigen", "einseitiger",
                    "einst", "einstmals", "einzig", "ende", "entsprechend", "entweder", "er", "ergänze", "ergänzen", "ergänzte",
                    "ergänzten", "erhält", "erhalten", "erhielt", "erhielten", "erneut", "eröffne", "eröffnen", "eröffnet", "eröffnete",
                    "eröffnetes", "erst", "erste", "ersten", "erster", "es", "etc", "etliche", "etwa", "etwas", "euch", "euer", "eure",
                    "eurem", "euren", "eurer", "eures", "fall", "falls", "fand", "fast", "ferner", "finden", "findest", "findet",
                    "folgende", "folgenden", "folgender", "folgendes", "folglich", "fordern", "fordert", "forderte", "forderten",
                    "fortsetzen", "fortsetzt", "fortsetzte", "fortsetzten", "fragte", "frau", "frei", "freie", "freier", "freies", "fuer",
                    "fünf", "für", "gab", "gängig", "gängige", "gängigen", "gängiger", "gängiges", "ganz", "ganze", "ganzem", "ganzen",
                    "ganzer", "ganzes", "gänzlich", "gar", "gbr", "geb", "geben", "geblieben", "gebracht", "gedurft", "geehrt", "geehrte",
                    "geehrten", "geehrter", "gefallen", "gefälligst", "gefällt", "gefiel", "gegeben", "gegen", "gehabt", "gehen", "geht",
                    "gekommen", "gekonnt", "gemacht", "gemäss", "gemocht", "genommen", "genug", "gern", "gesagt", "gesehen", "gestern",
                    "gestrige", "getan", "geteilt", "geteilte", "getragen", "gewesen", "gewissermaßen", "gewollt", "geworden", "ggf",
                    "gib", "gibt", "gleich", "gleichwohl", "gleichzeitig", "glücklicherweise", "gmbh", "gratulieren", "gratuliert",
                    "gratulierte", "gute", "guten", "hab", "habe", "haben", "haette", "halb", "hallo", "hast", "hat", "hätt", "hatte",
                    "hätte", "hatten", "hätten", "hattest", "hattet", "heraus", "herein", "heute", "heutige", "hier", "hiermit",
                    "hiesige", "hin", "hinein", "hinten", "hinter", "hinterher", "hoch", "höchstens", "hundert", "ich", "igitt", "ihm",
                    "ihn", "ihnen", "ihr", "ihre", "ihrem", "ihren", "ihrer", "ihres", "im", "immer", "immerhin", "important", "in",
                    "indem", "indessen", "info", "infolge", "innen", "innerhalb", "ins", "insofern", "inzwischen", "irgend", "irgendeine",
                    "irgendwas", "irgendwen", "irgendwer", "irgendwie", "irgendwo", "ist", "ja", "jährig", "jährige", "jährigen",
                    "jähriges", "je", "jede", "jedem", "jeden", "jedenfalls", "jeder", "jederlei", "jedes", "jedoch", "jemand", "jene",
                    "jenem", "jenen", "jener", "jenes", "jenseits", "jetzt", "kam", "kann", "kannst", "kaum", "kein", "keine", "keinem",
                    "keinen", "keiner", "keinerlei", "keines", "keines", "keineswegs", "klar", "klare", "klaren", "klares", "klein",
                    "kleinen", "kleiner", "kleines", "koennen", "koennt", "koennte", "koennten", "komme", "kommen", "kommt", "konkret",
                    "konkrete", "konkreten", "konkreter", "konkretes", "könn", "können", "könnt", "konnte", "könnte", "konnten",
                    "könnten", "künftig", "lag", "lagen", "langsam", "längst", "längstens", "lassen", "laut", "lediglich", "leer",
                    "legen", "legte", "legten", "leicht", "leider", "lesen", "letze", "letzten", "letztendlich", "letztens", "letztes",
                    "letztlich", "lichten", "liegt", "liest", "links", "mache", "machen", "machst", "macht", "machte", "machten", "mag",
                    "magst", "mal", "man", "manche", "manchem", "manchen", "mancher", "mancherorts", "manches", "manchmal", "mann",
                    "margin", "mehr", "mehrere", "mein", "meine", "meinem", "meinen", "meiner", "meines", "meist", "meiste", "meisten",
                    "meta", "mich", "mindestens", "mir", "mit", "mithin", "mochte", "möchte", "möchten", "möchtest", "mögen", "möglich",
                    "mögliche", "möglichen", "möglicher", "möglicherweise", "morgen", "morgige", "muessen", "muesst", "muesste", "muss",
                    "muß", "müssen", "mußt", "musst", "müßt", "musste", "müßte", "müsste", "mussten", "müssten", "nach", "nachdem",
                    "nacher", "nachhinein", "nächste", "nacht", "nahm", "nämlich", "natürlich", "neben", "nebenan", "nehmen", "nein",
                    "neu", "neue", "neuem", "neuen", "neuer", "neues", "neun", "nicht", "nichts", "nie", "niemals", "niemand", "nimm",
                    "nimmer", "nimmt", "nirgends", "nirgendwo", "noch", "nötigenfalls", "nun", "nur", "nutzen", "nutzt", "nützt",
                    "nutzung", "ob", "oben", "oberhalb", "obgleich", "obschon", "obwohl", "oder", "oft", "ohne", "per", "pfui",
                    "plötzlich", "pro", "reagiere", "reagieren", "reagiert", "reagierte", "rechts", "regelmäßig", "rief", "rund", "sage",
                    "sagen", "sagt", "sagte", "sagten", "sagtest", "sämtliche", "sang", "sangen", "schätzen", "schätzt", "schätzte",
                    "schätzten", "schlechter", "schließlich", "schnell", "schon", "schreibe", "schreiben", "schreibens", "schreiber",
                    "schwierig", "sechs", "sect", "sehe", "sehen", "sehr", "sehrwohl", "seht", "sei", "seid", "sein", "seine", "seinem",
                    "seinen", "seiner", "seines", "seit", "seitdem", "seite", "seiten", "seither", "selber", "selbst", "senke", "senken",
                    "senkt", "senkte", "senkten", "setzen", "setzt", "setzte", "setzten", "sich", "sicher", "sicherlich", "sie", "sieben",
                    "siebte", "siehe", "sieht", "sind", "singen", "singt", "so", "sobald", "sodaß", "soeben", "sofern", "sofort", "sog",
                    "sogar", "solange", "solc hen", "solch", "solche", "solchem", "solchen", "solcher", "solches", "soll", "sollen",
                    "sollst", "sollt", "sollte", "sollten", "solltest", "somit", "sondern", "sonst", "sonstwo", "sooft", "soviel",
                    "soweit", "sowie", "sowohl", "später", "spielen", "startet", "startete", "starteten", "statt", "stattdessen", "steht",
                    "steige", "steigen", "steigt", "stets", "stieg", "stiegen", "such", "suchen", "tages", "tat", "tät", "tatsächlich",
                    "tatsächlichen", "tatsächlicher", "tatsächliches", "tausend", "teile", "teilen", "teilte", "teilten", "titel",
                    "total", "trage", "tragen", "trägt", "trotzdem", "trug", "tun", "tust", "tut", "txt", "übel", "über", "überall",
                    "überallhin", "überdies", "übermorgen", "übrig", "übrigens", "ueber", "um", "umso", "unbedingt", "und", "ungefähr",
                    "unmöglich", "unmögliche", "unmöglichen", "unmöglicher", "unnötig", "uns", "unse", "unsem", "unsen", "unser", "unser",
                    "unsere", "unserem", "unseren", "unserer", "unseres", "unserm", "unses", "unten", "unter", "unterbrach",
                    "unterbrechen", "unterhalb", "unwichtig", "usw", "vergangen", "vergangene", "vergangener", "vergangenes", "vermag",
                    "vermögen", "vermutlich", "veröffentlichen", "veröffentlicher", "veröffentlicht", "veröffentlichte",
                    "veröffentlichten", "veröffentlichtes", "verrate", "verraten", "verriet", "verrieten", "version", "versorge",
                    "versorgen", "versorgt", "versorgte", "versorgten", "versorgtes", "viel", "viele", "vielen", "vieler", "vieles",
                    "vielleicht", "vielmals", "vier", "völlig", "vollständig", "vom", "von", "vor", "voran", "vorbei", "vorgestern",
                    "vorher", "vorne", "vorüber", "wachen", "waere", "während", "während", "währenddessen", "wann", "war", "wär", "wäre",
                    "waren", "wären", "warst", "warum", "was", "weder", "weg", "wegen", "weil", "weiß", "weiter", "weitere", "weiterem",
                    "weiteren", "weiterer", "weiteres", "weiterhin", "welche", "welchem", "welchen", "welcher", "welches", "wem", "wen",
                    "wenig", "wenige", "weniger", "wenigstens", "wenn", "wenngleich", "wer", "werde", "werden", "werdet", "weshalb",
                    "wessen", "wichtig", "wie", "wieder", "wieso", "wieviel", "wiewohl", "will", "willst", "wir", "wird", "wirklich",
                    "wirst", "wo", "wodurch", "wogegen", "woher", "wohin", "wohingegen", "wohl", "wohlweislich", "wolle", "wollen",
                    "wollt", "wollte", "wollten", "wolltest", "wolltet", "womit", "woraufhin", "woraus", "worin", "wurde", "würde",
                    "wurden", "würden", "zahlreich", "zehn", "zeitweise", "ziehen", "zieht", "zog", "zogen", "zu", "zudem", "zuerst",
                    "zufolge", "zugleich", "zuletzt", "zum", "zumal", "zur", "zurück", "zusammen", "zuviel", "zwanzig", "zwar", "zwei",
                    "zwischen", "zwölf"
                });
            }
            else if (LastSelectedCulture.StartsWith("en"))
            {
                // English stop words
                // Source: http://norm.al/2009/04/14/list-of-english-stop-words/ (MySQL fulltext, from 2009-10-03)
                // Via: http://en.wikipedia.org/wiki/Stop_words
                commonWords = new HashSet<string>(new string[]
                {
                    "able", "about", "above", "according", "accordingly", "across", "actually", "after", "afterwards", "again", "against",
                    "ain", "all", "allow", "allows", "almost", "alone", "along", "already", "also", "although", "always", "am", "among",
                    "amongst", "an", "and", "another", "any", "anybody", "anyhow", "anyone", "anything", "anyway", "anyways", "anywhere",
                    "apart", "appear", "appreciate", "appropriate", "are", "aren", "around", "as", "aside", "ask", "asking", "associated",
                    "at", "available", "away", "awfully", "be", "became", "because", "become", "becomes", "becoming", "been", "before",
                    "beforehand", "behind", "being", "believe", "below", "beside", "besides", "best", "better", "between", "beyond",
                    "both", "brief", "but", "by", "mon", "came", "can", "cannot", "cause", "causes", "certain", "certainly", "changes",
                    "clearly", "co", "com", "come", "comes", "concerning", "consequently", "consider", "considering", "contain",
                    "containing", "contains", "corresponding", "could", "couldn", "course", "currently", "definitely", "described",
                    "despite", "did", "didn", "different", "do", "does", "doesn", "doing", "don", "done", "down", "downwards", "during",
                    "each", "edu", "eg", "eight", "either", "else", "elsewhere", "enough", "entirely", "especially", "et", "etc", "even",
                    "ever", "every", "everybody", "everyone", "everything", "everywhere", "ex", "exactly", "example", "except", "far",
                    "few", "fifth", "first", "five", "followed", "following", "follows", "for", "former", "formerly", "forth", "four",
                    "from", "further", "furthermore", "get", "gets", "getting", "given", "gives", "go", "goes", "going", "gone", "got",
                    "gotten", "greetings", "had", "hadn", "happens", "hardly", "has", "hasn", "have", "haven", "having", "he", "hello",
                    "help", "hence", "her", "here", "hereafter", "hereby", "herein", "hereupon", "hers", "herself", "hi", "him",
                    "himself", "his", "hither", "hopefully", "how", "howbeit", "however", "if", "ignored", "immediate", "in", "inasmuch",
                    "inc", "indeed", "indicate", "indicated", "indicates", "inner", "insofar", "instead", "into", "inward", "is", "isn",
                    "it", "its", "itself", "just", "keep", "keeps", "kept", "know", "knows", "known", "last", "lately", "later", "latter",
                    "latterly", "least", "less", "lest", "let", "like", "liked", "likely", "little", "ll", "look", "looking", "looks",
                    "ltd", "mainly", "many", "may", "maybe", "me", "mean", "meanwhile", "merely", "might", "more", "moreover", "most",
                    "mostly", "much", "must", "my", "myself", "name", "namely", "nd", "near", "nearly", "necessary", "need", "needs",
                    "neither", "never", "nevertheless", "new", "next", "nine", "no", "nobody", "non", "none", "noone", "nor", "normally",
                    "not", "nothing", "novel", "now", "nowhere", "obviously", "of", "off", "often", "oh", "ok", "okay", "old", "on",
                    "once", "one", "ones", "only", "onto", "or", "other", "others", "otherwise", "ought", "our", "ours", "ourselves",
                    "out", "outside", "over", "overall", "own", "particular", "particularly", "per", "perhaps", "placed", "please",
                    "plus", "possible", "presumably", "probably", "provides", "que", "quite", "qv", "rather", "rd", "re", "really",
                    "reasonably", "regarding", "regardless", "regards", "relatively", "respectively", "right", "said", "same", "saw",
                    "say", "saying", "says", "second", "secondly", "see", "seeing", "seem", "seemed", "seeming", "seems", "seen", "self",
                    "selves", "sensible", "sent", "serious", "seriously", "seven", "several", "shall", "she", "should", "shouldn",
                    "since", "six", "so", "some", "somebody", "somehow", "someone", "something", "sometime", "sometimes", "somewhat",
                    "somewhere", "soon", "sorry", "specified", "specify", "specifying", "still", "sub", "such", "sup", "sure", "take",
                    "taken", "tell", "tends", "th", "than", "thank", "thanks", "thanx", "that", "thats", "the", "their", "theirs", "them",
                    "themselves", "then", "thence", "there", "thereafter", "thereby", "therefore", "therein", "theres", "thereupon",
                    "these", "they", "think", "third", "this", "thorough", "thoroughly", "those", "though", "three", "through",
                    "throughout", "thru", "thus", "to", "together", "too", "took", "toward", "towards", "tried", "tries", "truly", "try",
                    "trying", "twice", "two", "un", "under", "unfortunately", "unless", "unlikely", "until", "unto", "up", "upon", "us",
                    "use", "used", "useful", "uses", "using", "usually", "value", "various", "ve", "very", "via", "viz", "vs", "want",
                    "wants", "was", "wasn", "way", "we", "welcome", "well", "went", "were", "weren", "what", "whatever", "when", "whence",
                    "whenever", "where", "whereafter", "whereas", "whereby", "wherein", "whereupon", "wherever", "whether", "which",
                    "while", "whither", "who", "whoever", "whole", "whom", "whose", "why", "will", "willing", "wish", "with", "within",
                    "without", "won", "wonder", "would", "would", "wouldn", "yes", "yet", "you", "your", "yours", "yourself",
                    "yourselves", "zero"
                });
            }
            else
            {
                commonWords = new HashSet<string>();
            }

            // Remove all placeholders and key references
            refText = Regex.Replace(refText, @"(?<!\{)\{[^{]*?\}", "");

            // Extract all words
            List<string> refWords = new List<string>();
            m = Regex.Match(refText, @"(\w{2,})");
            while (m.Success)
            {
                if (!commonWords.Contains(m.Groups[1].Value.ToLowerInvariant()))   // Skip common words
                    refWords.Add(m.Groups[1].Value);
                m = m.NextMatch();
            }

            // Find other text keys that contain these words in their primary culture text
            Dictionary<TextKeyViewModel, float> otherKeys = new Dictionary<TextKeyViewModel, float>();
            foreach (var kvp in TextKeys)
            {
                if (kvp.Value.TextKey == tk.TextKey) continue;   // Skip currently selected item
                if (kvp.Value.TextKey.StartsWith("Tx:")) continue;   // Skip system keys

                float score = 0;
                bool isExactMatch = false;
                string otherBaseText = kvp.Value.CultureTextVMs[0].Text;
                string otherTranslatedText = kvp.Value.CultureTextVMs.First(ct => ct.CultureName == LastSelectedCulture).Text;

                if (string.IsNullOrEmpty(otherBaseText)) continue;
                if (string.IsNullOrEmpty(otherTranslatedText)) continue;

                if (otherBaseText == origRefText)
                {
                    // Both keys' primary translation matches exactly
                    isExactMatch = true;
                }

                // Remove all placeholders and key references
                string otherText = Regex.Replace(otherBaseText, @"(?<!\{)\{[^{]*?\}", "");

                // Extract all words
                List<string> otherWords = new List<string>();
                m = Regex.Match(otherText, @"(\w{2,})");
                while (m.Success)
                {
                    if (!commonWords.Contains(m.Groups[1].Value.ToLowerInvariant()))   // Skip common words
                        otherWords.Add(m.Groups[1].Value);
                    m = m.NextMatch();
                }

                // Increase score by 1 for each case-insensitively matching word
                foreach (string word in refWords)
                {
                    if (otherWords.Any(w => string.Equals(w, word, StringComparison.InvariantCultureIgnoreCase)))
                        score += 1;
                }
                // Increase score by 2 for each case-sensitively matching word
                foreach (string word in refWords)
                {
                    if (otherWords.Any(w => string.Equals(w, word, StringComparison.InvariantCulture)))
                        score += 2;
                }

                // Divide by the square root of the number of relevant words. (Using the square
                // root to reduce the effect for very long texts.)
                if (otherWords.Count > 0)
                {
                    score /= (float) Math.Sqrt(otherWords.Count);
                }
                else
                {
                    // There are no significant words in the other text
                    score = 0;
                }

                if (isExactMatch)
                {
                    score = 100000;
                }

                // Accept every text key with a threshold score
                if (score >= 0.5f)
                {
                    otherKeys.Add(kvp.Value, score);
                }
            }

            // Sort all matches by their score
            foreach (var kvp in otherKeys.OrderByDescending(kvp => kvp.Value))
            {
                try
                {
                    SuggestionViewModel suggestion = new SuggestionViewModel(this);
                    suggestion.TextKey = kvp.Key.TextKey;
                    suggestion.BaseText = kvp.Key.CultureTextVMs[0].Text;
                    if (LastSelectedCulture != PrimaryCulture)
                        suggestion.TranslatedText = kvp.Key.CultureTextVMs.First(ct => ct.CultureName == LastSelectedCulture).Text;
                    suggestion.IsExactMatch = kvp.Value >= 100000;
                    suggestion.ScoreNum = kvp.Value;
                    if (suggestion.IsExactMatch)
                        suggestion.Score = Tx.T("suggestions.exact match");
                    else
                        suggestion.Score = kvp.Value.ToString("0.00");
                    suggestions.Add(suggestion);
                }
                catch
                {
                    // Something's missing (probably a LINQ-related exception), ignore that item
                }
            }

            if (suggestions.Count == 0)
            {
                AddDummySuggestion();
            }
            else
            {
                HaveSuggestions = true;
            }
        }