/// <summary> /// Looks up in the passed collection of supported AppLanguages the language that is best matched /// to this langtag. I.e. the written AppLanguage that a user understanding this langtag /// will most-likely understand. /// </summary> /// <returns>Selected CultureInfoEx instance from the AppLanguages collection or null if there was no match.</returns> public int Match(LanguageTag[] AppLanguages, MatchGrade matchGrade = MatchGrade.LanguageMatch) { int matchScore = 0; foreach (LanguageTag langtag in AppLanguages) { int score = Match(langtag, matchGrade); if (score > matchScore) { matchScore = score; if (matchScore == 100) // Can't beat an exact match. { break; } } } return(matchScore); }
// Operations /// <summary> /// Performs 'language matching' between lang described by this (A) /// and language decibed by i_rhs (B). Essentially, returns an assessment of /// how well a speaker of A will understand B. /// The key points are as follows: /// · The Script is almost as relevant as the language itself; that is, if /// you speak a language but do not understand the script, you cannot /// read that language. Thus a mismatch in Script should score low. /// · The Region is less relevant than Script to understanding of language. /// The one exception to this is where the Region has traditionally been /// used to also indicate the Script. E.g. /// zh-CH -> Chinese (Simplified) i.e. zh-Hans /// zh-TW -> Chinese (Traditional) i.e. zh-Hant /// In these cases we normalize all legacy langtags to their new values /// before matching. E.g. zh-CH is normalized to zh-Hans. /// «LX113» /// </summary> /// <param name="i_rhs"></param> /// <returns> /// Returns a score on to what extent the two languages match. The value ranges from /// 100 (exact match) down to 0 (fundamental language tag mismatch), with values /// in between which may be used to compare quality of a match, larger the value /// meaning better quality. /// </returns> /// <remarks> /// Matching values: /// RHS /// this lang lang+script lang+region lang+script+region /// ---------------------------------------------------------------------------------- /// lang | A D C D /// lang+script | D A D B /// lang+region | C D A D /// lang+script+region | D B D A /// /// NB: For the purposes of the logic above, lang incorporates Language + PrivateUse subtags. /// /// A. Exact match (100) /// All three subtags match. /// B. Unbalanced Region Mismatch (99) [zh, zh-HK] [zh-Hans, zh-Hans-HK] /// Language and Script match; /// one side has Region set while the other doesn't. /// Here there is the possibility that due to defaults Region matches. /// C. Balanced Region Mismatch (98) [zh-IK, zh-HK] [zh-Hans-IK, zh-Hans-HK] /// Language and Script match; /// both sides have Region set but to different values. /// Here there is NO possibility that Region matches. /// D. Unbalanced Script Mismatch (97) [zh-HK, zh-Hant-HK] /// Language matches, Region may match; /// one side has Script set while the other doesn't. /// Here there is the possibility that due to defaults Script matches. /// E. Balanced Script Mismatch (96) /// Language matches, Region may match; /// both sides have Script set but to different values. /// Here there is NO possibility that Script matches. /// F. Language Mismatch (0) /// Language doesn't match. /// </remarks> /// <seealso href="http://msdn.microsoft.com/en-us/library/windows/apps/jj673578.aspx"/> public int Match(LanguageTag i_rhs, MatchGrade matchGrade = MatchGrade.LanguageMatch) { if (i_rhs == null) { throw new ArgumentNullException("i_rhs"); } // Either langtag being null fails the match. if (!Language.IsSet() || !i_rhs.Language.IsSet()) { return(0); } // Init. bool[] L = { 0 == string.Compare(Language, i_rhs.Language, true), Language.IsSet(), i_rhs.Language.IsSet() }; bool[] S = { 0 == string.Compare(Script, i_rhs.Script, true), Script.IsSet(), i_rhs.Script.IsSet() }; bool[] R = { 0 == string.Compare(Region, i_rhs.Region, true), Region.IsSet(), i_rhs.Region.IsSet() }; bool[] P = { 0 == string.Compare(PrivateUse, i_rhs.PrivateUse, true), PrivateUse.IsSet(), i_rhs.PrivateUse.IsSet() }; // Language incorporates Language + PrivateUse subtags for our logic here. L[0] = L[0] && P[0]; L[1] = L[1] || P[1]; L[2] = L[2] || P[2]; // Logic. int score = 100; // F. if (!L[0]) { return(0); } // A. if (S[0] && R[0] && P[0]) { return(score); } --score; if (matchGrade != MatchGrade.ExactMatch) { // B. if (S[0] && !R[0] && R[1] != R[2]) { return(score); } --score; if (matchGrade != MatchGrade.DefaultRegion) { // C. if (S[0] && !R[0] && R[1] == R[2]) { return(score); } --score; if (matchGrade != MatchGrade.ScriptMatch) { // D. if (!S[0] && S[1] != S[2]) { return(score); } --score; // E. if (!S[0] && S[1] == S[2]) { return(score); } } //--score; //DebugHelpers.WriteLine("LanguageTag.Match -- fallen through: {0}, {1}", ToString(), i_rhs.ToString()); //Debug.Assert(false); } } // F. return(0); }