浏览代码

Further refinement of BCP 47 language labeling support

dyphire 5 天之前
父节点
当前提交
2007815fa6

+ 6 - 2
Emby.Naming/ExternalFiles/ExternalPathParser.cs

@@ -97,14 +97,18 @@ namespace Emby.Naming.ExternalFiles
 
                     if (culture is not null && pathInfo.Language is null)
                     {
-                        pathInfo.Language = culture.ThreeLetterISOLanguageName;
+                        pathInfo.Language = culture.Name.Contains('-', StringComparison.OrdinalIgnoreCase)
+                                          ? culture.Name
+                                          : culture.ThreeLetterISOLanguageName;
                         extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
                     }
                     else if (culture is not null && pathInfo.Language == "hin")
                     {
                         // Hindi language code "hi" collides with a hearing impaired flag - use as Hindi only if no other language is set
                         pathInfo.IsHearingImpaired = true;
-                        pathInfo.Language = culture.ThreeLetterISOLanguageName;
+                        pathInfo.Language = culture.Name.Contains('-', StringComparison.OrdinalIgnoreCase)
+                                          ? culture.Name
+                                          : culture.ThreeLetterISOLanguageName;
                         extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
                     }
                     else if (_namingOptions.MediaHearingImpairedFlags.Any(s => currentSliceWithoutSeparator.Equals(s, StringComparison.OrdinalIgnoreCase)))

+ 1 - 1
Emby.Server.Implementations/Library/MediaSourceManager.cs

@@ -379,7 +379,7 @@ namespace Emby.Server.Implementations.Library
             var culture = _localizationManager.FindLanguageInfo(language);
             if (culture is not null)
             {
-                return culture.ThreeLetterISOLanguageNames;
+                return culture.Name.Contains('-', StringComparison.OrdinalIgnoreCase) ? [culture.Name] : culture.ThreeLetterISOLanguageNames;
             }
 
             return [language];

+ 7 - 2
Emby.Server.Implementations/Localization/LocalizationManager.cs

@@ -128,7 +128,8 @@ namespace Emby.Server.Implementations.Localization
                     }
 
                     string name = parts[3];
-                    if (string.IsNullOrWhiteSpace(name))
+                    string displayname = parts[3];
+                    if (string.IsNullOrWhiteSpace(displayname))
                     {
                         continue;
                     }
@@ -138,6 +139,10 @@ namespace Emby.Server.Implementations.Localization
                     {
                         continue;
                     }
+                    else if (twoCharName.Contains('-', StringComparison.OrdinalIgnoreCase))
+                    {
+                        name = twoCharName;
+                    }
 
                     string[] threeLetterNames;
                     if (string.IsNullOrWhiteSpace(parts[1]))
@@ -153,7 +158,7 @@ namespace Emby.Server.Implementations.Localization
                         iso6392BtoTdict.TryAdd(parts[1], parts[0]);
                     }
 
-                    list.Add(new CultureDto(name, name, twoCharName, threeLetterNames));
+                    list.Add(new CultureDto(name, displayname, twoCharName, threeLetterNames));
                 }
 
                 _cultures = list;

+ 11 - 9
Emby.Server.Implementations/Localization/iso6392.txt

@@ -311,8 +311,8 @@ nia|||Nias|nias
 nic|||Niger-Kordofanian languages|nigéro-kordofaniennes, langues
 niu|||Niuean|niué
 nld|dut|nl|Dutch; Flemish|néerlandais; flamand
-nno||nn|Norwegian Nynorsk; Nynorsk, Norwegian|norvégien nynorsk; nynorsk, norvégien
-nob||nb|Bokmål, Norwegian; Norwegian Bokmål|norvégien bokmål
+nno||nn|Norwegian (Nynorsk)|norvégien (nynorsk)
+nob||nb|Norwegian (Bokmal)|norvégien (bokmål)
 nog|||Nogai|nogaï; nogay
 non|||Norse, Old|norrois, vieux
 nor||no|Norwegian|norvégien
@@ -391,10 +391,10 @@ slv||sl|Slovenian|slovène
 sma|||Southern Sami|sami du Sud
 sme||se|Northern Sami|sami du Nord
 smi|||Sami languages|sames, langues
-smj|||Lule Sami|sami de Lule
-smn|||Inari Sami|sami d'Inari
+smj|||Sami (Lule)|sami de Lule
+smn|||Sami (Inari)|sami d'Inari
 smo||sm|Samoan|samoan
-sms|||Skolt Sami|sami skolt
+sms|||Sami (Skolt)|sami skolt
 sna||sn|Shona|shona
 snd||sd|Sindhi|sindhi
 snk|||Soninke|soninké
@@ -483,10 +483,12 @@ zen|||Zenaga|zenaga
 zgh|||Standard Moroccan Tamazight|amazighe standard marocain
 zha||za|Zhuang; Chuang|zhuang; chuang
 zho|chi|zh|Chinese|chinois
-zho|chi|ze|Chinese; Bilingual|chinois
-zho|chi|zh-cn|Chinese; Simplified|chinois
-zho|chi|zh-tw|Chinese; Traditional|chinois
-zho|chi|zh-hk|Chinese; Hong Kong|chinois
+zho|chi|ze|Chinese (Bilingual)|chinois
+zho|chi|zh-cn|Chinese (Simplified)|chinois
+zho|chi|zh-hans|Chinese (Simplified)|chinois
+zho|chi|zh-tw|Chinese (Traditional)|chinois
+zho|chi|zh-hant|Chinese (Traditional)|chinois
+zho|chi|zh-hk|Chinese (Hong Kong)|chinois
 znd|||Zande languages|zandé, langues
 zul||zu|Zulu|zoulou
 zun|||Zuni|zuni

+ 4 - 1
Jellyfin.Api/Controllers/ItemUpdateController.cs

@@ -158,7 +158,10 @@ public class ItemUpdateController : BaseJellyfinApiController
             ParentalRatingOptions = _localizationManager.GetParentalRatings().ToList(),
             ExternalIdInfos = _providerManager.GetExternalIdInfos(item).ToArray(),
             Countries = _localizationManager.GetCountries().ToArray(),
-            Cultures = _localizationManager.GetCultures().ToArray()
+            Cultures = _localizationManager.GetCultures()
+                .DistinctBy(c => c.DisplayName, StringComparer.OrdinalIgnoreCase)
+                .OrderBy(c => c.DisplayName)
+                .ToArray()
         };
 
         if (!item.IsVirtualItem

+ 10 - 1
Jellyfin.Api/Controllers/LocalizationController.cs

@@ -1,4 +1,6 @@
+using System;
 using System.Collections.Generic;
+using System.Linq;
 using MediaBrowser.Common.Api;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Globalization;
@@ -34,7 +36,14 @@ public class LocalizationController : BaseJellyfinApiController
     [ProducesResponseType(StatusCodes.Status200OK)]
     public ActionResult<IEnumerable<CultureDto>> GetCultures()
     {
-        return Ok(_localization.GetCultures());
+        var allCultures = _localization.GetCultures();
+
+        var distinctCultures = allCultures
+            .DistinctBy(c => c.DisplayName, StringComparer.OrdinalIgnoreCase)
+            .OrderBy(c => c.DisplayName)
+            .AsEnumerable();
+
+        return Ok(distinctCultures);
     }
 
     /// <summary>

+ 44 - 10
MediaBrowser.Model/Entities/MediaStream.cs

@@ -273,11 +273,28 @@ namespace MediaBrowser.Model.Entities
                         // Do not display the language code in display titles if unset or set to a special code. Show it in all other cases (possibly expanded).
                         if (!string.IsNullOrEmpty(Language) && !_specialCodes.Contains(Language, StringComparison.OrdinalIgnoreCase))
                         {
-                            // Get full language string i.e. eng -> English.
-                            string fullLanguage = CultureInfo
-                                .GetCultures(CultureTypes.NeutralCultures)
-                                .FirstOrDefault(r => r.ThreeLetterISOLanguageName.Equals(Language, StringComparison.OrdinalIgnoreCase))
-                                ?.DisplayName;
+                            // Get full language string i.e. eng -> English, zh-Hans -> Chinese (Simplified).
+                            var cultures = CultureInfo.GetCultures(CultureTypes.NeutralCultures);
+                            CultureInfo match = null;
+                            if (Language.Contains('-', StringComparison.OrdinalIgnoreCase))
+                            {
+                                match = cultures.FirstOrDefault(r =>
+                                    r.Name.Equals(Language, StringComparison.OrdinalIgnoreCase));
+
+                                if (match is null)
+                                {
+                                    string baseLang = Language.AsSpan().LeftPart('-').ToString();
+                                    match = cultures.FirstOrDefault(r =>
+                                        r.TwoLetterISOLanguageName.Equals(baseLang, StringComparison.OrdinalIgnoreCase));
+                                }
+                            }
+                            else
+                            {
+                                match = cultures.FirstOrDefault(r =>
+                                    r.ThreeLetterISOLanguageName.Equals(Language, StringComparison.OrdinalIgnoreCase));
+                            }
+
+                            string fullLanguage = match?.DisplayName;
                             attributes.Add(StringHelper.FirstToUpper(fullLanguage ?? Language));
                         }
 
@@ -376,11 +393,28 @@ namespace MediaBrowser.Model.Entities
 
                         if (!string.IsNullOrEmpty(Language))
                         {
-                            // Get full language string i.e. eng -> English.
-                            string fullLanguage = CultureInfo
-                                .GetCultures(CultureTypes.NeutralCultures)
-                                .FirstOrDefault(r => r.ThreeLetterISOLanguageName.Equals(Language, StringComparison.OrdinalIgnoreCase))
-                                ?.DisplayName;
+                            // Get full language string i.e. eng -> English, zh-Hans -> Chinese (Simplified).
+                            var cultures = CultureInfo.GetCultures(CultureTypes.NeutralCultures);
+                            CultureInfo match = null;
+                            if (Language.Contains('-', StringComparison.OrdinalIgnoreCase))
+                            {
+                                match = cultures.FirstOrDefault(r =>
+                                    r.Name.Equals(Language, StringComparison.OrdinalIgnoreCase));
+
+                                if (match is null)
+                                {
+                                    string baseLang = Language.AsSpan().LeftPart('-').ToString();
+                                    match = cultures.FirstOrDefault(r =>
+                                        r.TwoLetterISOLanguageName.Equals(baseLang, StringComparison.OrdinalIgnoreCase));
+                                }
+                            }
+                            else
+                            {
+                                match = cultures.FirstOrDefault(r =>
+                                    r.ThreeLetterISOLanguageName.Equals(Language, StringComparison.OrdinalIgnoreCase));
+                            }
+
+                            string fullLanguage = match?.DisplayName;
                             attributes.Add(StringHelper.FirstToUpper(fullLanguage ?? Language));
                         }
                         else

+ 1 - 1
tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs

@@ -41,7 +41,7 @@ namespace Jellyfin.Server.Implementations.Tests.Localization
             await localizationManager.LoadAll();
             var cultures = localizationManager.GetCultures().ToList();
 
-            Assert.Equal(191, cultures.Count);
+            Assert.Equal(194, cultures.Count);
 
             var germany = cultures.FirstOrDefault(x => x.TwoLetterISOLanguageName.Equals("de", StringComparison.Ordinal));
             Assert.NotNull(germany);