mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-01-23 23:20:51 +01:00
Fix zh-CN subtitle language display
The DisplayTitle property was using .NET's CultureInfo.GetCultures(NeutralCultures) to resolve language display names. Since zh-CN is a specific culture (not neutral), it would fall back to the base 'zh' code, resulting in generic 'Chinese' instead of 'Chinese (Simplified)'. This change adds a LocalizedLanguage property to MediaStream that gets populated via LocalizationManager.FindLanguageInfo() when streams are retrieved from the database. This leverages Jellyfin's existing iso6392.txt mappings which correctly map zh-CN to 'Chinese (Simplified)'. The same pattern is already used for other localized strings like LocalizedDefault and LocalizedExternal.
This commit is contained in:
parent
706a8d2850
commit
9039077286
3 changed files with 55 additions and 46 deletions
|
|
@ -158,6 +158,12 @@ public class MediaStreamRepository : IMediaStreamRepository
|
||||||
dto.LocalizedDefault = _localization.GetLocalizedString("Default");
|
dto.LocalizedDefault = _localization.GetLocalizedString("Default");
|
||||||
dto.LocalizedExternal = _localization.GetLocalizedString("External");
|
dto.LocalizedExternal = _localization.GetLocalizedString("External");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(dto.Language))
|
||||||
|
{
|
||||||
|
var culture = _localization.FindLanguageInfo(dto.Language);
|
||||||
|
dto.LocalizedLanguage = culture?.DisplayName;
|
||||||
|
}
|
||||||
|
|
||||||
if (dto.Type is MediaStreamType.Subtitle)
|
if (dto.Type is MediaStreamType.Subtitle)
|
||||||
{
|
{
|
||||||
dto.LocalizedUndefined = _localization.GetLocalizedString("Undefined");
|
dto.LocalizedUndefined = _localization.GetLocalizedString("Undefined");
|
||||||
|
|
|
||||||
|
|
@ -260,6 +260,8 @@ namespace MediaBrowser.Model.Entities
|
||||||
|
|
||||||
public string LocalizedHearingImpaired { get; set; }
|
public string LocalizedHearingImpaired { get; set; }
|
||||||
|
|
||||||
|
public string LocalizedLanguage { get; set; }
|
||||||
|
|
||||||
public string DisplayTitle
|
public string DisplayTitle
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -273,29 +275,8 @@ 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).
|
// 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))
|
if (!string.IsNullOrEmpty(Language) && !_specialCodes.Contains(Language, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
// Get full language string i.e. eng -> English, zh-Hans -> Chinese (Simplified).
|
// Use pre-resolved localized language name, falling back to raw language code.
|
||||||
var cultures = CultureInfo.GetCultures(CultureTypes.NeutralCultures);
|
attributes.Add(StringHelper.FirstToUpper(LocalizedLanguage ?? Language));
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Profile) && !string.Equals(Profile, "lc", StringComparison.OrdinalIgnoreCase))
|
if (!string.IsNullOrEmpty(Profile) && !string.Equals(Profile, "lc", StringComparison.OrdinalIgnoreCase))
|
||||||
|
|
@ -393,29 +374,8 @@ namespace MediaBrowser.Model.Entities
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Language))
|
if (!string.IsNullOrEmpty(Language))
|
||||||
{
|
{
|
||||||
// Get full language string i.e. eng -> English, zh-Hans -> Chinese (Simplified).
|
// Use pre-resolved localized language name, falling back to raw language code.
|
||||||
var cultures = CultureInfo.GetCultures(CultureTypes.NeutralCultures);
|
attributes.Add(StringHelper.FirstToUpper(LocalizedLanguage ?? Language));
|
||||||
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
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,49 @@ namespace Jellyfin.Model.Tests.Entities
|
||||||
IsExternal = true
|
IsExternal = true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Test LocalizedLanguage is used when set (fixes zh-CN display issue #15935)
|
||||||
|
data.Add(
|
||||||
|
"Chinese (Simplified) - SRT",
|
||||||
|
new MediaStream
|
||||||
|
{
|
||||||
|
Type = MediaStreamType.Subtitle,
|
||||||
|
Title = null,
|
||||||
|
Language = "zh-CN",
|
||||||
|
LocalizedLanguage = "Chinese (Simplified)",
|
||||||
|
IsForced = false,
|
||||||
|
IsDefault = false,
|
||||||
|
Codec = "SRT"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test LocalizedLanguage for audio streams
|
||||||
|
data.Add(
|
||||||
|
"Japanese - AAC - Stereo",
|
||||||
|
new MediaStream
|
||||||
|
{
|
||||||
|
Type = MediaStreamType.Audio,
|
||||||
|
Title = null,
|
||||||
|
Language = "jpn",
|
||||||
|
LocalizedLanguage = "Japanese",
|
||||||
|
IsForced = false,
|
||||||
|
IsDefault = false,
|
||||||
|
Codec = "AAC",
|
||||||
|
ChannelLayout = "stereo"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test fallback to Language when LocalizedLanguage is null
|
||||||
|
data.Add(
|
||||||
|
"Eng - ASS",
|
||||||
|
new MediaStream
|
||||||
|
{
|
||||||
|
Type = MediaStreamType.Subtitle,
|
||||||
|
Title = null,
|
||||||
|
Language = "eng",
|
||||||
|
LocalizedLanguage = null,
|
||||||
|
IsForced = false,
|
||||||
|
IsDefault = false,
|
||||||
|
Codec = "ASS"
|
||||||
|
});
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue