Пример #1
0
        /// <summary>
        /// Get a display name for a transliterator. This reimplements the logic from the C++
        /// Transliterator::getDisplayName method, since the ICU C API doesn't expose a
        /// utrans_getDisplayName() call. (Unfortunately).
        /// Note that if no text is found for the given locale, ICU will (by default) fallback to
        /// the root locale. However, the root locale's strings for transliterator display names
        /// are ugly and not suitable for displaying to the user. Therefore, if we have to
        /// fallback, we fallback to the "en" locale instead of the root locale.
        /// </summary>
        /// <param name="transId">The translator's system ID in ICU.</param>
        /// <param name="localeName">The ICU name of the locale in which to calculate the display
        /// name.</param>
        /// <returns>A name suitable for displaying to the user in the given locale, or in English
        /// if no translated text is present in the given locale.</returns>
        public static string GetDisplayName(string transId, string localeName)
        {
            const string translitDisplayNameRBKeyPrefix = "%Translit%%";           // See RB_DISPLAY_NAME_PREFIX in translit.cpp in ICU source code
            const string scriptDisplayNameRBKeyPrefix   = "%Translit%";            // See RB_SCRIPT_DISPLAY_NAME_PREFIX in translit.cpp in ICU source code
            const string translitResourceBundleName     = "ICUDATA-translit";
            const string translitDisplayNamePatternKey  = "TransliteratorNamePattern";

            ParseTransliteratorID(transId, out var source, out var target, out var variant);
            if (target.Length < 1)
            {
                return(transId);                 // Malformed ID? Give up
            }
            using (var bundle = new ResourceBundle(translitResourceBundleName, localeName))
                using (var bundleFallback = new ResourceBundle(translitResourceBundleName, "en"))
                {
                    var pattern = bundle.GetStringByKey(translitDisplayNamePatternKey);
                    // If we don't find a MessageFormat pattern in our locale, try the English fallback
                    if (string.IsNullOrEmpty(pattern))
                    {
                        pattern = bundleFallback.GetStringByKey(translitDisplayNamePatternKey);
                    }
                    // Still can't find a pattern? Then we won't be able to format the ID, so just return it
                    if (string.IsNullOrEmpty(pattern))
                    {
                        return(transId);
                    }

                    // First check if there is a specific localized name for this transliterator, and if so, just return it.
                    // Note that we need to check whether the string we got still starts with the "%Translit%%" prefix, because
                    // if so, it means that we got a value from the root locale's bundle, which isn't actually localized.
                    var translitLocalizedName = bundle.GetStringByKey(translitDisplayNameRBKeyPrefix + transId);

                    if (!string.IsNullOrEmpty(translitLocalizedName) && !translitLocalizedName.StartsWith(translitDisplayNameRBKeyPrefix))
                    {
                        return(translitLocalizedName);
                    }

                    // There was no specific localized name for this transliterator (which will be true of most cases). Build one.

                    // Try getting localized display names for the source and target, if possible.
                    var localizedSource = bundle.GetStringByKey(scriptDisplayNameRBKeyPrefix + source);
                    if (string.IsNullOrEmpty(localizedSource))
                    {
                        localizedSource = source;                 // Can't localize
                    }
                    else
                    {
                        // As with the transliterator name, we need to check that the string we got didn't come from the root bundle
                        // (which just returns a string that still contains the ugly %Translit% prefix). If it did, fall back to English.
                        if (localizedSource.StartsWith(scriptDisplayNameRBKeyPrefix))
                        {
                            localizedSource = bundleFallback.GetStringByKey(scriptDisplayNameRBKeyPrefix + source);
                        }
                        if (string.IsNullOrEmpty(localizedSource) || localizedSource.StartsWith(scriptDisplayNameRBKeyPrefix))
                        {
                            localizedSource = source;
                        }
                    }

                    // Same thing for target
                    var localizedTarget = bundle.GetStringByKey(scriptDisplayNameRBKeyPrefix + target);

                    if (string.IsNullOrEmpty(localizedTarget))
                    {
                        localizedTarget = target;                 // Can't localize
                    }
                    else
                    {
                        if (localizedTarget.StartsWith(scriptDisplayNameRBKeyPrefix))
                        {
                            localizedTarget = bundleFallback.GetStringByKey(scriptDisplayNameRBKeyPrefix + target);
                        }
                        if (string.IsNullOrEmpty(localizedTarget) || localizedTarget.StartsWith(scriptDisplayNameRBKeyPrefix))
                        {
                            localizedTarget = target;
                        }
                    }

                    var displayName = MessageFormatter.Format(pattern, localeName, out var status,
                                                              2.0, localizedSource, localizedTarget);
                    if (status.IsSuccess())
                    {
                        return(displayName + variant); // Variant is either empty string or starts with "/"
                    }
                    return(transId);                   // If formatting fails, the transliterator's ID is still our final fallback
                }
        }