Esempio n. 1
0
        /// <summary>
        /// Remove special private use subtag sequence identified by "lvariant"
        /// and return the rest. Only used by LocaleExtensions.
        /// </summary>
        internal static string RemovePrivateuseVariant(string privuseVal)
        {
            StringTokenEnumerator itr = new StringTokenEnumerator(privuseVal, LanguageTag.Separator);

            // Note: privateuse value "abc-lvariant" is unchanged
            // because no subtags after "lvariant".

            int  prefixStart   = -1;
            bool sawPrivuseVar = false;

            while (itr.MoveNext())
            {
                if (prefixStart != -1)
                {
                    // Note: privateuse value "abc-lvariant" is unchanged
                    // because no subtags after "lvariant".
                    sawPrivuseVar = true;
                    break;
                }
                if (AsciiUtil.CaseIgnoreMatch(itr.Current, LanguageTag.PrivateUse_Variant_Prefix))
                {
                    prefixStart = itr.CurrentStart;
                }
            }
            if (!sawPrivuseVar)
            {
                return(privuseVal);
            }

            Debug.Assert(prefixStart == 0 || prefixStart > 1);
            return((prefixStart == 0) ? null : privuseVal.Substring(0, prefixStart - 1)); // ICU4N: Checked 2nd parameter
        }
Esempio n. 2
0
        private bool ParseVariants(StringTokenEnumerator itr, ParseStatus sts)
        {
            if (itr.IsDone || sts.IsError)
            {
                return(false);
            }

            bool found = false;

            while (!itr.IsDone)
            {
                string s = itr.Current;
                if (!IsVariant(s))
                {
                    break;
                }
                found = true;
                if (!_variants.Any())
                {
                    _variants = new List <string>(3);
                }
                _variants.Add(s);
                sts.ParseLength = itr.CurrentEnd;
                itr.MoveNext();
            }

            return(found);
        }
Esempio n. 3
0
        private bool ParseExtlangs(StringTokenEnumerator itr, ParseStatus sts)
        {
            if (itr.IsDone || sts.IsError)
            {
                return(false);
            }

            bool found = false;

            while (!itr.IsDone)
            {
                string s = itr.Current;
                if (!IsExtlang(s))
                {
                    break;
                }
                found = true;
                if (!_extlangs.Any())
                {
                    _extlangs = new List <string>(3);
                }
                _extlangs.Add(s);
                sts.ParseLength = itr.CurrentEnd;
                itr.MoveNext();

                if (_extlangs.Count == 3)
                {
                    // Maximum 3 extlangs
                    break;
                }
            }

            return(found);
        }
Esempio n. 4
0
        private bool ParseExtensions(StringTokenEnumerator itr, ParseStatus sts)
        {
            if (itr.IsDone || sts.IsError)
            {
                return(false);
            }

            bool found = false;

            while (!itr.IsDone)
            {
                string s = itr.Current;
                if (IsExtensionSingleton(s))
                {
                    int           start     = itr.CurrentStart;
                    string        singleton = s;
                    StringBuilder sb        = new StringBuilder(singleton);

                    itr.MoveNext();
                    while (!itr.IsDone)
                    {
                        s = itr.Current;
                        if (IsExtensionSubtag(s))
                        {
                            sb.Append(SEP).Append(s);
                            sts.ParseLength = itr.CurrentEnd;
                        }
                        else
                        {
                            break;
                        }
                        itr.MoveNext();
                    }

                    if (sts.ParseLength <= start)
                    {
                        sts.ErrorIndex   = start;
                        sts.ErrorMessage = "Incomplete extension '" + singleton + "'";
                        break;
                    }

                    if (_extensions.Count == 0)
                    {
                        _extensions = new List <String>(4);
                    }
                    _extensions.Add(sb.ToString());
                    found = true;
                }
                else
                {
                    break;
                }
            }
            return(found);
        }
Esempio n. 5
0
        /// <summary>
        /// Check if the given variant subtags separated by the given
        /// separator(s) are valid.
        /// </summary>
        private int CheckVariants(string variants, string sep)
        {
            StringTokenEnumerator itr = new StringTokenEnumerator(variants, sep);

            while (itr.MoveNext())
            {
                string s = itr.Current;
                if (!LanguageTag.IsVariant(s))
                {
                    return(itr.CurrentStart);
                }
            }
            return(-1);
        }
Esempio n. 6
0
        private bool ParsePrivateuse(StringTokenEnumerator itr, ParseStatus sts)
        {
            if (itr.IsDone || sts.IsError)
            {
                return(false);
            }

            bool found = false;

            string s = itr.Current;

            if (IsPrivateusePrefix(s))
            {
                int           start = itr.CurrentStart;
                StringBuilder sb    = new StringBuilder(s);

                itr.MoveNext();
                while (!itr.IsDone)
                {
                    s = itr.Current;
                    if (!IsPrivateuseSubtag(s))
                    {
                        break;
                    }
                    sb.Append(SEP).Append(s);
                    sts.ParseLength = itr.CurrentEnd;

                    itr.MoveNext();
                }

                if (sts.ParseLength <= start)
                {
                    // need at least 1 private subtag
                    sts.ErrorIndex   = start;
                    sts.ErrorMessage = "Incomplete privateuse";
                }
                else
                {
                    _privateuse = sb.ToString();
                    found       = true;
                }
            }

            return(found);
        }
Esempio n. 7
0
        public BaseLocale GetBaseLocale()
        {
            string language = _language;
            string script   = _script;
            string region   = _region;
            string variant  = _variant;

            // Special private use subtag sequence identified by "lvariant" will be
            // interpreted as Java variant.
            if (_extensions != null)
            {
                string privuse;
                if (_extensions.TryGetValue(PRIVUSE_KEY, out privuse) && privuse != null)
                {
                    StringTokenEnumerator itr = new StringTokenEnumerator(privuse, LanguageTag.Separator);
                    bool sawPrefix            = false;
                    int  privVarStart         = -1;
                    while (itr.MoveNext())
                    {
                        if (sawPrefix)
                        {
                            privVarStart = itr.CurrentStart;
                            break;
                        }
                        if (AsciiUtil.CaseIgnoreMatch(itr.Current, LanguageTag.PrivateUse_Variant_Prefix))
                        {
                            sawPrefix = true;
                        }
                    }
                    if (privVarStart != -1)
                    {
                        StringBuilder sb = new StringBuilder(variant);
                        if (sb.Length != 0)
                        {
                            sb.Append(BaseLocale.Separator);
                        }
                        sb.Append(privuse.Substring(privVarStart).Replace(LanguageTag.Separator, BaseLocale.Separator));
                        variant = sb.ToString();
                    }
                }
            }

            return(BaseLocale.GetInstance(language, script, region, variant));
        }
Esempio n. 8
0
        public InternalLocaleBuilder SetUnicodeLocaleKeyword(string key, string type)
        {
            if (!UnicodeLocaleExtension.IsKey(key))
            {
                throw new FormatException("Ill-formed Unicode locale keyword key: " + key);
            }

            CaseInsensitiveString cikey = new CaseInsensitiveString(key);

            if (type == null)
            {
                if (_ukeywords != null)
                {
                    // null type is used for remove the key
                    _ukeywords.Remove(cikey);
                }
            }
            else
            {
                if (type.Length != 0)
                {
                    // normalize separator to "-"
                    string tp = type.Replace(BaseLocale.Separator, LanguageTag.Separator);
                    // validate
                    StringTokenEnumerator itr = new StringTokenEnumerator(tp, LanguageTag.Separator);
                    while (itr.MoveNext())
                    {
                        string s = itr.Current;
                        if (!UnicodeLocaleExtension.IsTypeSubtag(s))
                        {
                            throw new FormatException("Ill-formed Unicode locale keyword type: " + type /*, itr.CurrentStart*/);
                        }
                    }
                }
                if (_ukeywords == null)
                {
                    _ukeywords = new Dictionary <CaseInsensitiveString, string>(4);
                }
                _ukeywords[cikey] = type;
            }
            return(this);
        }
Esempio n. 9
0
        private bool ParseRegion(StringTokenEnumerator itr, ParseStatus sts)
        {
            if (itr.IsDone || sts.IsError)
            {
                return(false);
            }

            bool found = false;

            string s = itr.Current;

            if (IsRegion(s))
            {
                found           = true;
                _region         = s;
                sts.ParseLength = itr.CurrentEnd;
                itr.MoveNext();
            }

            return(found);
        }
Esempio n. 10
0
        /// <summary>
        /// Private methods parsing Unicode Locale Extension subtags.
        /// Duplicated attributes/keywords will be ignored.
        /// The input must be a valid extension subtags (excluding singleton).
        /// </summary>
        private void SetUnicodeLocaleExtension(string subtags)
        {
            // wipe out existing attributes/keywords
            if (_uattributes != null)
            {
                _uattributes.Clear();
            }
            if (_ukeywords != null)
            {
                _ukeywords.Clear();
            }

            StringTokenEnumerator itr = new StringTokenEnumerator(subtags, LanguageTag.Separator);

            // parse attributes
            while (itr.MoveNext())
            {
                if (!UnicodeLocaleExtension.IsAttribute(itr.Current))
                {
                    break;
                }
                if (_uattributes == null)
                {
                    _uattributes = new HashSet <CaseInsensitiveString>(/*4*/);
                }
                _uattributes.Add(new CaseInsensitiveString(itr.Current));
            }

            // parse keywords
            CaseInsensitiveString key = null;
            string type;
            int    typeStart = -1;
            int    typeEnd   = -1;

            while (!itr.IsDone)
            {
                if (key != null)
                {
                    if (UnicodeLocaleExtension.IsKey(itr.Current))
                    {
                        // next keyword - emit previous one
                        Debug.Assert(typeStart == -1 || typeEnd != -1);
                        type = (typeStart == -1) ? "" : subtags.Substring(typeStart, typeEnd - typeStart); // ICU4N: Corrected 2nd parameter
                        if (_ukeywords == null)
                        {
                            _ukeywords = new Dictionary <CaseInsensitiveString, string>(4);
                        }
                        _ukeywords[key] = type;

                        // reset keyword info
                        CaseInsensitiveString tmpKey = new CaseInsensitiveString(itr.Current);
                        key       = _ukeywords.ContainsKey(tmpKey) ? null : tmpKey;
                        typeStart = typeEnd = -1;
                    }
                    else
                    {
                        if (typeStart == -1)
                        {
                            typeStart = itr.CurrentStart;
                        }
                        typeEnd = itr.CurrentEnd;
                    }
                }
                else if (UnicodeLocaleExtension.IsKey(itr.Current))
                {
                    // 1. first keyword or
                    // 2. next keyword, but previous one was duplicate
                    key = new CaseInsensitiveString(itr.Current);
                    if (_ukeywords != null && _ukeywords.ContainsKey(key))
                    {
                        // duplicate
                        key = null;
                    }
                }

                if (!itr.HasNext)
                {
                    if (key != null)
                    {
                        // last keyword
                        Debug.Assert(typeStart == -1 || typeEnd != -1);
                        type = (typeStart == -1) ? "" : subtags.Substring(typeStart, typeEnd - typeStart); // ICU4N: Corrected 2nd parameter
                        if (_ukeywords == null)
                        {
                            _ukeywords = new Dictionary <CaseInsensitiveString, string>(4);
                        }
                        _ukeywords[key] = type;
                    }
                    break;
                }

                itr.MoveNext();
            }
        }
Esempio n. 11
0
        /// <summary>
        /// Set extension/private subtags in a single string representation
        /// </summary>
        public InternalLocaleBuilder SetExtensions(string subtags)
        {
            if (subtags == null || subtags.Length == 0)
            {
                ClearExtensions();
                return(this);
            }
            subtags = subtags.Replace(BaseLocale.Separator, LanguageTag.Separator);
            StringTokenEnumerator itr = new StringTokenEnumerator(subtags, LanguageTag.Separator);

            List <string> extensions = null;
            string        privateuse = null;

            int parsed = 0;
            int start;

            // Move to first element
            itr.MoveNext();

            // Make a list of extension subtags
            while (!itr.IsDone)
            {
                string s = itr.Current;
                if (LanguageTag.IsExtensionSingleton(s))
                {
                    start = itr.CurrentStart;
                    string        singleton = s;
                    StringBuilder sb        = new StringBuilder(singleton);

                    itr.MoveNext();
                    while (!itr.IsDone)
                    {
                        s = itr.Current;
                        if (LanguageTag.IsExtensionSubtag(s))
                        {
                            sb.Append(LanguageTag.Separator).Append(s);
                            parsed = itr.CurrentEnd;
                        }
                        else
                        {
                            break;
                        }
                        itr.MoveNext();
                    }

                    if (parsed < start)
                    {
                        throw new FormatException("Incomplete extension '" + singleton + "'" /*, start*/);
                    }

                    if (extensions == null)
                    {
                        extensions = new List <string>(4);
                    }
                    extensions.Add(sb.ToString());
                }
                else
                {
                    break;
                }
            }
            if (!itr.IsDone)
            {
                string s = itr.Current;
                if (LanguageTag.IsPrivateusePrefix(s))
                {
                    start = itr.CurrentStart;
                    StringBuilder sb = new StringBuilder(s);

                    itr.MoveNext();
                    while (!itr.IsDone)
                    {
                        s = itr.Current;
                        if (!LanguageTag.IsPrivateuseSubtag(s))
                        {
                            break;
                        }
                        sb.Append(LanguageTag.Separator).Append(s);
                        parsed = itr.CurrentEnd;

                        itr.MoveNext();
                    }
                    if (parsed <= start)
                    {
                        throw new FormatException("Incomplete privateuse:" + subtags.Substring(start) /*, start*/);
                    }
                    else
                    {
                        privateuse = sb.ToString();
                    }
                }
            }

            if (!itr.IsDone)
            {
                throw new FormatException("Ill-formed extension subtags:" + subtags.Substring(itr.CurrentStart) /*, itr.CurrentStart*/);
            }

            return(SetExtensions(extensions, privateuse));
        }
Esempio n. 12
0
        public InternalLocaleBuilder SetExtension(char singleton, string value)
        {
            // validate key
            bool isBcpPrivateuse = LanguageTag.IsPrivateusePrefixChar(singleton);

            if (!isBcpPrivateuse && !LanguageTag.IsExtensionSingletonChar(singleton))
            {
                throw new FormatException("Ill-formed extension key: " + singleton);
            }

            bool remove             = (value == null || value.Length == 0);
            CaseInsensitiveChar key = new CaseInsensitiveChar(singleton);

            if (remove)
            {
                if (UnicodeLocaleExtension.IsSingletonChar(key.Value))
                {
                    // clear entire Unicode locale extension
                    if (_uattributes != null)
                    {
                        _uattributes.Clear();
                    }
                    if (_ukeywords != null)
                    {
                        _ukeywords.Clear();
                    }
                }
                else
                {
                    if (_extensions != null && _extensions.ContainsKey(key))
                    {
                        _extensions.Remove(key);
                    }
                }
            }
            else
            {
                // validate value
                string val = value.Replace(BaseLocale.Separator, LanguageTag.Separator);
                StringTokenEnumerator itr = new StringTokenEnumerator(val, LanguageTag.Separator);
                while (itr.MoveNext())
                {
                    string s = itr.Current;
                    bool   validSubtag;
                    if (isBcpPrivateuse)
                    {
                        validSubtag = LanguageTag.IsPrivateuseSubtag(s);
                    }
                    else
                    {
                        validSubtag = LanguageTag.IsExtensionSubtag(s);
                    }
                    if (!validSubtag)
                    {
                        throw new FormatException("Ill-formed extension value: " + s /*, itr.CurrentStart*/);
                    }
                }

                if (UnicodeLocaleExtension.IsSingletonChar(key.Value))
                {
                    SetUnicodeLocaleExtension(val);
                }
                else
                {
                    if (_extensions == null)
                    {
                        _extensions = new Dictionary <CaseInsensitiveChar, string>(4);
                    }
                    _extensions[key] = val;
                }
            }
            return(this);
        }
Esempio n. 13
0
        public static LanguageTag ParseLocale(BaseLocale baseLocale, LocaleExtensions localeExtensions)
        {
            LanguageTag tag = new LanguageTag();

            string language = baseLocale.GetLanguage();
            string script   = baseLocale.GetScript();
            string region   = baseLocale.GetRegion();
            string variant  = baseLocale.GetVariant();

            bool hasSubtag = false;

            string privuseVar = null;   // store ill-formed variant subtags

            if (language.Length > 0 && IsLanguage(language))
            {
                // Convert a deprecated language code used by Java to
                // a new code
                if (language.Equals("iw"))
                {
                    language = "he";
                }
                else if (language.Equals("ji"))
                {
                    language = "yi";
                }
                else if (language.Equals("in"))
                {
                    language = "id";
                }
                tag._language = language;
            }

            if (script.Length > 0 && IsScript(script))
            {
                tag._script = CanonicalizeScript(script);
                hasSubtag   = true;
            }

            if (region.Length > 0 && IsRegion(region))
            {
                tag._region = CanonicalizeRegion(region);
                hasSubtag   = true;
            }

            // ICU4N TODO: Remove ?
            if (JDKIMPL)
            {
                // Special handling for no_NO_NY - use nn_NO for language tag
                if (tag._language.Equals("no") && tag._region.Equals("NO") && variant.Equals("NY")) // ICU4N TODO: Fix this handling for .NET (no-NO is not reliable across platforms)
                {
                    tag._language = "nn";
                    variant       = "";
                }
            }

            if (variant.Length > 0)
            {
                List <string>         variants = null;
                StringTokenEnumerator varitr   = new StringTokenEnumerator(variant, BaseLocale.SEP);
                while (varitr.MoveNext())
                {
                    string var = varitr.Current;
                    if (!IsVariant(var))
                    {
                        break;
                    }
                    if (variants == null)
                    {
                        variants = new List <string>();
                    }
                    if (JDKIMPL)
                    {
                        variants.Add(var);  // Do not canonicalize!
                    }
                    else
                    {
                        variants.Add(CanonicalizeVariant(var));
                    }
                }
                if (variants != null)
                {
                    tag._variants = variants;
                    hasSubtag     = true;
                }
                if (!varitr.IsDone)
                {
                    // ill-formed variant subtags
                    StringBuilder buf = new StringBuilder();
                    while (!varitr.IsDone)
                    {
                        string prvv = varitr.Current;
                        if (!IsPrivateuseSubtag(prvv))
                        {
                            // cannot use private use subtag - truncated
                            break;
                        }
                        if (buf.Length > 0)
                        {
                            buf.Append(SEP);
                        }
                        if (!JDKIMPL)
                        {
                            prvv = AsciiUtil.ToLowerString(prvv);
                        }
                        buf.Append(prvv);
                        varitr.MoveNext();
                    }
                    if (buf.Length > 0)
                    {
                        privuseVar = buf.ToString();
                    }
                }
            }

            List <string> extensions = null;
            string        privateuse = null;

            var locextKeys = localeExtensions.Keys;

            foreach (char locextKey in locextKeys)
            {
                Extension ext = localeExtensions.GetExtension(locextKey);
                if (IsPrivateusePrefixChar(locextKey))
                {
                    privateuse = ext.Value;
                }
                else
                {
                    if (extensions == null)
                    {
                        extensions = new List <string>();
                    }
                    extensions.Add(locextKey.ToString() + SEP + ext.Value);
                }
            }

            if (extensions != null)
            {
                tag._extensions = extensions;
                hasSubtag       = true;
            }

            // append ill-formed variant subtags to private use
            if (privuseVar != null)
            {
                if (privateuse == null)
                {
                    privateuse = PRIVUSE_VARIANT_PREFIX + SEP + privuseVar;
                }
                else
                {
                    privateuse = privateuse + SEP + PRIVUSE_VARIANT_PREFIX + SEP + privuseVar.Replace(BaseLocale.SEP, SEP);
                }
            }

            if (privateuse != null)
            {
                tag._privateuse = privateuse;
            }

            if (tag._language.Length == 0 && (hasSubtag || privateuse == null))
            {
                // use lang "und" when 1) no language is available AND
                // 2) any of other subtags other than private use are available or
                // no private use tag is available
                tag._language = UNDETERMINED;
            }

            return(tag);
        }
Esempio n. 14
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);
        }