Example #1
0
 /// <summary>
 /// Helper for converting the C printf-style %0, %1 ... style identifiers in a formatted nugget msgid string
 /// to the .NET-style format items: {0}, {1} ...
 /// </summary>
 /// <remarks>
 /// A formatted msgid may be in the form:
 /// <para>
 /// Enter between %1 and %0 characters
 /// </para>
 /// <para>
 /// For which we return:
 /// </para>
 /// <para>
 /// Enter between {1} and {0} characters
 /// </para>
 /// </remarks>
 public static string ConvertIdentifiersInMsgId(string msgid)
 {
     // Convert %n style identifiers to {n} style.
     return(m_regexPrintfIdentifiers.Replace(msgid, delegate(Match match)
     {
         string s = match.Groups[1].Value;
         double id;
         if (ParseHelpers.TryParseDecimal(s, 1, s.Length - 1 + 1, out id))
         {
             s = string.Format("{{{0}}}", id);
         }
         return s;
     }));
 }
Example #2
0
        // Static helpers
        /// <summary>
        /// Parses an HTTP Accept-Language or Content-Language header value, returning
        /// a representative ordered array of LanguageItem instances, sorted in order of
        /// language preference.
        /// E.g. "de;q=0.5, en;q=1, fr-FR;q=0,ga;q=0.5".
        /// Notably, is able to re-order elements based on quality.
        /// </summary>
        /// <remarks>
        /// The first element position in the returned array is reserved for an item that
        /// describes the Principal Application Language (PAL) for the request. If/when the PAL
        /// is not set, that element will be a null item (LanguageItem.LanguageTag == null).
        ///
        /// This method is designed to be as efficient as possible, typically requiring
        /// only a single heap alloc, for the returned array object itself.
        /// </remarks>
        /// <param name="headerval">
        /// HTTP Accept-Language header value.
        /// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html.
        /// May be null or empty string for zero languages.
        /// </param>
        /// <param name="pal">
        /// Optional language to store at the first element position in the array, which is reserved
        /// for the Principal Application Language (PAL). Any such LanguageItem stored that has a quality
        /// value of 2 (LanguageItem.PalQualitySetting). Null if no such language to be stored there and the
        /// item to be set as null (LanguageItem.LanguageTag == null).
        /// </param>
        /// <returns>
        /// Array of languages items (with possibly null LanguageTag members) sorted in order or language preference.
        /// </returns>
        public static       LanguageItem[] ParseHttpLanguageHeader(string headerval, ILanguageTag pal = null)
        {
            // This method is designed to be as efficient as possible (avoiding string allocations where possible).
            //
            int begin, end, pos1;
            int len     = headerval != null ? headerval.Length : 0;
            int ordinal = 0;
            // Init array with enough elements for each language entry in the header.
            var LanguageItems = new LanguageItem[(len > 0 ? headerval.CountOfChar(',') + 1 : 0) + 1];

            // First element position is reserved for any PAL.
            LanguageItems[ordinal] = new LanguageItem(pal, PalQualitySetting, ordinal);
            ++ordinal;
            // For each language component of the header (delimited by comma)
            for (begin = 0; begin < len; begin = end + 1)
            {
                end = headerval.IndexOf(',', begin);
                if (-1 == end)
                {
                    end = len;
                }
                float qvalue = 1;
                pos1 = headerval.IndexOf(';', begin);
                if (-1 != pos1 &&
                    pos1 < end)
                {
                    // pos1 -> ";q=n"
                    if (pos1 - begin < 2 || // room for valid langtag
                        pos1 + 3 >= headerval.Length ||
                        headerval[pos1 + 1] != 'q' ||
                        headerval[pos1 + 2] != '=')
                    {
                        continue;
                    }
                    if (!ParseHelpers.TryParseDecimal(headerval, pos1 + 3, -1, out qvalue))
                    {
                        continue;
                    }
                    if (qvalue < 0f || qvalue > 1.0f)
                    {
                        continue;
                    }
                }
                else
                {
                    pos1 = end;
                }
                // Skip over any whitespace. We expect this to make the following Trim redundant,
                // thus saving on an alloc.
                while (headerval[begin] == ' ')
                {
                    ++begin;
                }
                // Extract language subtag e.g. "fr-FR".
                // NB: we expect this to be efficient and not allocate a new string as
                // a string matching the trimmed value is most likely already Intern (held by
                // the LanguageTag cache as a key value). Only first time here for a particular
                // value will a new string possibly be allocated.
                string langtag = headerval.Substring(begin, pos1 - begin).Trim();
                // Wrap langtag.
                LanguageTag lt = i18n.LanguageTag.GetCachedInstance(langtag);
                if (lt == null || !lt.Language.IsSet())
                {
                    continue;
                }
                // Ignore the langtag if already added.
                //if (pal.IsValid() && pal.Equals(lt)) {
                //    continue; }
                // NB: the above check disabled as it can cause the first lang in the header,
                // where it matches the PAL intially, to be lost if/when the PAL is later changed
                // to something else.
                // Store a new representative item.
                // NB: LanguageItem is a value type so no alloc done here.
                LanguageItems[ordinal] = new LanguageItem(lt, qvalue, ordinal);
                ++ordinal;
            }
            // Truncate any extra elements from end of array.
            if (ordinal != LanguageItems.Length)
            {
                LanguageItems = LanguageItems.Where(x => x.LanguageTag.IsValid()).ToArray();
            }
            // If there was no PAL, and the header value was invalid then we will have no language items, so add the default
            if (LanguageItems.Length == 0)
            {
                LanguageItems = new LanguageItem[] { new LanguageItem(LocalizedApplication.Current.DefaultLanguageTag, PalQualitySetting, 0) }
            }
            ;
            // Rearrange items into order of precedence. This is facilitated by LanguageItem's
            // impl. of IComparable.
            Array.Sort(LanguageItems);
            // Done.
            return(LanguageItems);
        }
    }