예제 #1
0
        /// <summary>
        /// BNF in RFC5464
        /// </summary>
        /// <remarks>
        /// Language-Tag  = langtag             ; normal language tags
        ///               / privateuse          ; private use tag
        ///               / grandfathered       ; grandfathered tags
        ///
        ///
        /// langtag       = language
        ///                 ["-" script]
        ///                 ["-" region]
        ///                 *("-" variant)
        ///                 *("-" extension)
        ///                 ["-" privateuse]
        ///
        /// language      = 2*3ALPHA            ; shortest ISO 639 code
        ///                 ["-" extlang]       ; sometimes followed by
        ///                                     ; extended language subtags
        ///               / 4ALPHA              ; or reserved for future use
        ///               / 5*8ALPHA            ; or registered language subtag
        ///
        /// extlang       = 3ALPHA              ; selected ISO 639 codes
        ///                 *2("-" 3ALPHA)      ; permanently reserved
        ///
        /// script        = 4ALPHA              ; ISO 15924 code
        ///
        /// region        = 2ALPHA              ; ISO 3166-1 code
        ///               / 3DIGIT              ; UN M.49 code
        ///
        /// variant       = 5*8alphanum         ; registered variants
        ///               / (DIGIT 3alphanum)
        ///
        /// extension     = singleton 1*("-" (2*8alphanum))
        ///
        ///                                     ; Single alphanumerics
        ///                                     ; "x" reserved for private use
        /// singleton     = DIGIT               ; 0 - 9
        ///               / %x41-57             ; A - W
        ///               / %x59-5A             ; Y - Z
        ///               / %x61-77             ; a - w
        ///               / %x79-7A             ; y - z
        ///
        /// privateuse    = "x" 1*("-" (1*8alphanum))
        /// </remarks>
        public static LanguageTag Parse(string languageTag, ParseStatus sts)
        {
            if (sts == null)
            {
                sts = new ParseStatus();
            }
            else
            {
                sts.Reset();
            }

            StringTokenEnumerator itr;
            bool isGrandfathered = false;

            // Check if the tag is grandfathered
            string[] gfmap;
            if (GRANDFATHERED.TryGetValue(new AsciiUtil.CaseInsensitiveKey(languageTag), out gfmap) && gfmap != null)
            {
                // use preferred mapping
                itr             = new StringTokenEnumerator(gfmap[1], SEP);
                isGrandfathered = true;
            }
            else
            {
                itr = new StringTokenEnumerator(languageTag, SEP);
            }

            // ICU4N: Move to the first element
            itr.MoveNext();
            LanguageTag tag = new LanguageTag();

            // langtag must start with either language or privateuse
            if (tag.ParseLanguage(itr, sts))
            {
                tag.ParseExtlangs(itr, sts);
                tag.ParseScript(itr, sts);
                tag.ParseRegion(itr, sts);
                tag.ParseVariants(itr, sts);
                tag.ParseExtensions(itr, sts);
            }
            tag.ParsePrivateuse(itr, sts);

            if (isGrandfathered)
            {
                // Grandfathered tag is replaced with a well-formed tag above.
                // However, the parsed length must be the original tag length.
                Debug.Assert(itr.IsDone);
                Debug.Assert(!sts.IsError);
                sts.ParseLength = languageTag.Length;
            }
            else if (!itr.IsDone && !sts.IsError)
            {
                string s = itr.Current;
                sts.ErrorIndex = itr.CurrentStart;
                if (s.Length == 0)
                {
                    sts.ErrorMessage = "Empty subtag";
                }
                else
                {
                    sts.ErrorMessage = "Invalid subtag: " + s;
                }
            }

            return(tag);
        }