aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/Localization
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations/Localization')
-rw-r--r--Emby.Server.Implementations/Localization/Core/af.json8
-rw-r--r--Emby.Server.Implementations/Localization/Core/de.json40
-rw-r--r--Emby.Server.Implementations/Localization/Core/ms.json34
-rw-r--r--Emby.Server.Implementations/Localization/Core/te.json10
-rw-r--r--Emby.Server.Implementations/Localization/LocalizationManager.cs199
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/0-prefer.csv11
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/0-prefer.json34
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/au.csv17
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/au.json69
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/be.csv11
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/be.json55
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/br.csv14
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/br.json55
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/ca.csv18
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/ca.json90
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/cl.json41
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/co.csv7
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/co.json55
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/de.csv17
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/de.json41
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/dk.csv7
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/dk.json48
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/es.csv25
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/es.json90
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/fi.csv10
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/fi.json41
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/fr.csv13
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/fr.json69
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/gb.csv23
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/gb.json97
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/ie.csv10
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/ie.json55
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/jp.csv11
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/jp.json62
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/kz.csv6
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/kz.json41
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/mx.csv6
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/mx.json41
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/nl.csv8
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/nl.json55
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/no.csv10
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/no.json69
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/nz.csv16
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/nz.json69
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/pl.json41
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/ro.csv6
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/ro.json48
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/ru.csv6
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/ru.json48
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/se.csv10
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/se.json55
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/sk.csv6
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/sk.json41
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/uk.csv22
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/uk.json97
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/us.csv52
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/us.json83
57 files changed, 1752 insertions, 471 deletions
diff --git a/Emby.Server.Implementations/Localization/Core/af.json b/Emby.Server.Implementations/Localization/Core/af.json
index e89ede10b..1dce58923 100644
--- a/Emby.Server.Implementations/Localization/Core/af.json
+++ b/Emby.Server.Implementations/Localization/Core/af.json
@@ -129,5 +129,11 @@
"TaskAudioNormalizationDescription": "Skandeer lêers vir oudio-normaliseringsdata.",
"TaskAudioNormalization": "Odio Normalisering",
"TaskCleanCollectionsAndPlaylists": "Maak versamelings en snitlyste skoon",
- "TaskCleanCollectionsAndPlaylistsDescription": "Verwyder items uit versamelings en snitlyste wat nie meer bestaan nie."
+ "TaskCleanCollectionsAndPlaylistsDescription": "Verwyder items uit versamelings en snitlyste wat nie meer bestaan nie.",
+ "TaskDownloadMissingLyrics": "Laai tekorte lirieke af",
+ "TaskDownloadMissingLyricsDescription": "Laai lirieke af vir liedjies",
+ "TaskExtractMediaSegments": "Media Segment Skandeer",
+ "TaskExtractMediaSegmentsDescription": "Onttrek of verkry mediasegmente van MediaSegment-geaktiveerde inproppe.",
+ "TaskMoveTrickplayImages": "Migreer Trickplay Beeldligging",
+ "TaskMoveTrickplayImagesDescription": "Skuif ontstaande trickplay lêers volgens die biblioteekinstellings."
}
diff --git a/Emby.Server.Implementations/Localization/Core/de.json b/Emby.Server.Implementations/Localization/Core/de.json
index c38af5bf4..f5ae43bb5 100644
--- a/Emby.Server.Implementations/Localization/Core/de.json
+++ b/Emby.Server.Implementations/Localization/Core/de.json
@@ -43,7 +43,7 @@
"NameInstallFailed": "Installation von {0} fehlgeschlagen",
"NameSeasonNumber": "Staffel {0}",
"NameSeasonUnknown": "Staffel unbekannt",
- "NewVersionIsAvailable": "Eine neue Version von Jellyfin-Server steht zum Download bereit.",
+ "NewVersionIsAvailable": "Eine neue Jellyfin-Serverversion steht zum Download bereit.",
"NotificationOptionApplicationUpdateAvailable": "Anwendungsaktualisierung verfügbar",
"NotificationOptionApplicationUpdateInstalled": "Anwendungsaktualisierung installiert",
"NotificationOptionAudioPlayback": "Audiowiedergabe gestartet",
@@ -72,12 +72,12 @@
"ServerNameNeedsToBeRestarted": "{0} muss neu gestartet werden",
"Shows": "Serien",
"Songs": "Lieder",
- "StartupEmbyServerIsLoading": "Jellyfin-Server startet, bitte versuche es gleich noch einmal.",
+ "StartupEmbyServerIsLoading": "Jellyfin-Server lädt. Bitte versuche es gleich noch einmal.",
"SubtitleDownloadFailureForItem": "Download der Untertitel fehlgeschlagen für {0}",
"SubtitleDownloadFailureFromForItem": "Untertitel von {0} für {1} konnten nicht heruntergeladen werden",
"Sync": "Synchronisation",
"System": "System",
- "TvShows": "TV-Sendungen",
+ "TvShows": "TV-Serien",
"User": "Benutzer",
"UserCreatedWithName": "Benutzer {0} wurde erstellt",
"UserDeletedWithName": "Benutzer {0} wurde gelöscht",
@@ -92,30 +92,30 @@
"ValueHasBeenAddedToLibrary": "{0} wurde deiner Bibliothek hinzugefügt",
"ValueSpecialEpisodeName": "Extra - {0}",
"VersionNumber": "Version {0}",
- "TaskDownloadMissingSubtitlesDescription": "Suche im Internet basierend auf den Metadaten-Einstellungen nach fehlenden Untertiteln.",
- "TaskDownloadMissingSubtitles": "Lade fehlende Untertitel herunter",
- "TaskRefreshChannelsDescription": "Aktualisiere Internet-Kanal-Informationen.",
- "TaskRefreshChannels": "Aktualisiere Kanäle",
- "TaskCleanTranscodeDescription": "Löscht Transkodierdateien, die älter als einen Tag sind.",
- "TaskCleanTranscode": "Räume Transkodierungs-Verzeichnis auf",
+ "TaskDownloadMissingSubtitlesDescription": "Sucht im Internet basierend auf den Metadaten-Einstellungen nach fehlenden Untertiteln.",
+ "TaskDownloadMissingSubtitles": "Fehlende Untertitel herunterladen",
+ "TaskRefreshChannelsDescription": "Aktualisiert Internet-Kanal-Informationen.",
+ "TaskRefreshChannels": "Kanäle aktualisieren",
+ "TaskCleanTranscodeDescription": "Löscht Transkodierungsdateien, die älter als einen Tag sind.",
+ "TaskCleanTranscode": "Transkodierungs-Verzeichnis aufräumen",
"TaskUpdatePluginsDescription": "Lädt Updates für Plugins herunter, welche für automatische Updates konfiguriert sind und installiert diese.",
- "TaskUpdatePlugins": "Aktualisiere Plugins",
+ "TaskUpdatePlugins": "Plugins aktualisieren",
"TaskRefreshPeopleDescription": "Aktualisiert Metadaten für Schauspieler und Regisseure in deinen Bibliotheken.",
- "TaskRefreshPeople": "Aktualisiere Personen",
+ "TaskRefreshPeople": "Personen aktualisieren",
"TaskCleanLogsDescription": "Lösche Log-Dateien, die älter als {0} Tage sind.",
- "TaskCleanLogs": "Räumt Log-Verzeichnis auf",
- "TaskRefreshLibraryDescription": "Scannt alle Bibliotheken nach neu hinzugefügten Dateien und aktualisiere Metadaten.",
- "TaskRefreshLibrary": "Scanne Medien-Bibliothek",
+ "TaskCleanLogs": "Log-Verzeichnis aufräumen",
+ "TaskRefreshLibraryDescription": "Durchsucht alle Bibliotheken nach neu hinzugefügten Dateien und aktualisiert Metadaten.",
+ "TaskRefreshLibrary": "Medien-Bibliothek scannen",
"TaskRefreshChapterImagesDescription": "Erstellt Vorschaubilder für Videos, die Kapitel besitzen.",
- "TaskRefreshChapterImages": "Extrahiere Kapitel-Bilder",
- "TaskCleanCacheDescription": "Löscht nicht mehr benötigte Zwischenspeicherdateien.",
- "TaskCleanCache": "Leere Zwischenspeicher",
+ "TaskRefreshChapterImages": "Kapitel-Bilder extrahieren",
+ "TaskCleanCacheDescription": "Löscht vom System nicht mehr benötigte Zwischenspeicherdateien.",
+ "TaskCleanCache": "Zwischenspeicher-Verzeichnis aufräumen",
"TasksChannelsCategory": "Internet-Kanäle",
"TasksApplicationCategory": "Anwendung",
"TasksLibraryCategory": "Bibliothek",
"TasksMaintenanceCategory": "Wartung",
"TaskCleanActivityLogDescription": "Löscht Aktivitätsprotokolleinträge, die älter als das konfigurierte Alter sind.",
- "TaskCleanActivityLog": "Aktivitätsprotokoll aufräumen",
+ "TaskCleanActivityLog": "Aktivitätsprotokolle aufräumen",
"Undefined": "Undefiniert",
"Forced": "Erzwungen",
"Default": "Standard",
@@ -128,12 +128,12 @@
"TaskRefreshTrickplayImages": "Trickplay-Bilder generieren",
"TaskRefreshTrickplayImagesDescription": "Erstellt ein Trickplay-Vorschauen für Videos in aktivierten Bibliotheken.",
"TaskCleanCollectionsAndPlaylists": "Sammlungen und Playlisten aufräumen",
- "TaskCleanCollectionsAndPlaylistsDescription": "Lösche nicht mehr vorhandene Einträge aus den Sammlungen und Playlisten.",
+ "TaskCleanCollectionsAndPlaylistsDescription": "Löscht nicht mehr vorhandene Einträge aus den Sammlungen und Playlisten.",
"TaskAudioNormalization": "Audio Normalisierung",
"TaskAudioNormalizationDescription": "Durchsucht Dateien nach Audionormalisierungsdaten.",
"TaskDownloadMissingLyricsDescription": "Lädt Songtexte herunter",
"TaskDownloadMissingLyrics": "Fehlende Songtexte herunterladen",
- "TaskExtractMediaSegments": "Scanne Mediensegmente",
+ "TaskExtractMediaSegments": "Mediensegmente scannen",
"TaskExtractMediaSegmentsDescription": "Extrahiert oder empfängt Mediensegmente von Plugins die Mediensegmente nutzen.",
"TaskMoveTrickplayImages": "Verzeichnis für Trickplay-Bilder migrieren",
"TaskMoveTrickplayImagesDescription": "Trickplay-Bilder werden entsprechend der Bibliothekseinstellungen verschoben."
diff --git a/Emby.Server.Implementations/Localization/Core/ms.json b/Emby.Server.Implementations/Localization/Core/ms.json
index c64bcda04..a3fc7881e 100644
--- a/Emby.Server.Implementations/Localization/Core/ms.json
+++ b/Emby.Server.Implementations/Localization/Core/ms.json
@@ -9,14 +9,14 @@
"Channels": "Saluran",
"ChapterNameValue": "Bab {0}",
"Collections": "Koleksi",
- "DeviceOfflineWithName": "{0} telah diputuskan sambungan",
+ "DeviceOfflineWithName": "{0} telah dinyahsambung",
"DeviceOnlineWithName": "{0} telah disambung",
- "FailedLoginAttemptWithUserName": "Percubaan log masuk daripada {0} gagal",
+ "FailedLoginAttemptWithUserName": "Percubaan gagal log masuk daripada {0}",
"Favorites": "Kegemaran",
- "Folders": "Fail-fail",
+ "Folders": "Folder-folder",
"Genres": "Genre-genre",
- "HeaderAlbumArtists": "Album Artis-artis",
- "HeaderContinueWatching": "Terus Menonton",
+ "HeaderAlbumArtists": "Album artis-artis",
+ "HeaderContinueWatching": "Teruskan Menonton",
"HeaderFavoriteAlbums": "Album-album Kegemaran",
"HeaderFavoriteArtists": "Artis-artis Kegemaran",
"HeaderFavoriteEpisodes": "Episod-episod Kegemaran",
@@ -25,26 +25,26 @@
"HeaderLiveTV": "TV Siaran Langsung",
"HeaderNextUp": "Seterusnya",
"HeaderRecordingGroups": "Kumpulan-kumpulan Rakaman",
- "HomeVideos": "Video Personal",
- "Inherit": "Mewarisi",
- "ItemAddedWithName": "{0} telah ditambahkan ke dalam pustaka",
+ "HomeVideos": "Video Peribadi",
+ "Inherit": "Warisi",
+ "ItemAddedWithName": "{0} telah ditambah ke dalam pustaka",
"ItemRemovedWithName": "{0} telah dibuang daripada pustaka",
"LabelIpAddressValue": "Alamat IP: {0}",
"LabelRunningTimeValue": "Masa berjalan: {0}",
- "Latest": "Terbaru",
- "MessageApplicationUpdated": "Jellyfin Server telah dikemas kini",
- "MessageApplicationUpdatedTo": "Jellyfin Server telah dikemas kini ke {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Konfigurasi pelayan di bahagian {0} telah dikemas kini",
+ "Latest": "Terbaharu",
+ "MessageApplicationUpdated": "Pelayan Jellyfin telah dikemas kini",
+ "MessageApplicationUpdatedTo": "Pelayan Jellyfin telah dikemas kini ke {0}",
+ "MessageNamedServerConfigurationUpdatedWithValue": "Konfigurasi pelayan bahagian {0} telah dikemas kini",
"MessageServerConfigurationUpdated": "Konfigurasi pelayan telah dikemas kini",
"MixedContent": "Kandungan campuran",
"Movies": "Filem-filem",
"Music": "Muzik",
"MusicVideos": "Video Muzik",
"NameInstallFailed": "{0} pemasangan gagal",
- "NameSeasonNumber": "Musim {0}",
+ "NameSeasonNumber": "Musim ke-{0}",
"NameSeasonUnknown": "Musim Tidak Diketahui",
- "NewVersionIsAvailable": "Versi terbaru Jellyfin Server bersedia untuk dimuat turunkan.",
- "NotificationOptionApplicationUpdateAvailable": "Kemas kini aplikasi telah sedia",
+ "NewVersionIsAvailable": "Versi terbaharu Pelayan Jellyfin telah tersedia untuk dimuat turun.",
+ "NotificationOptionApplicationUpdateAvailable": "Kemas kini aplikasi telah tersedia",
"NotificationOptionApplicationUpdateInstalled": "Kemas kini aplikasi telah dipasang",
"NotificationOptionAudioPlayback": "Ulangmain audio bermula",
"NotificationOptionAudioPlaybackStopped": "Ulangmain audio dihentikan",
@@ -98,8 +98,8 @@
"TasksLibraryCategory": "Perpustakaan",
"TasksMaintenanceCategory": "Penyelenggaraan",
"Undefined": "Tidak ditentukan",
- "Forced": "Paksa",
- "Default": "Asal",
+ "Forced": "Dipaksa",
+ "Default": "Lalai",
"TaskCleanCache": "Bersihkan Direktori Cache",
"TaskCleanActivityLogDescription": "Padamkan entri log aktiviti yang lebih tua daripada usia yang dikonfigurasi.",
"TaskRefreshPeople": "Segarkan Orang",
diff --git a/Emby.Server.Implementations/Localization/Core/te.json b/Emby.Server.Implementations/Localization/Core/te.json
index 7d4422d62..1fa2a3cc5 100644
--- a/Emby.Server.Implementations/Localization/Core/te.json
+++ b/Emby.Server.Implementations/Localization/Core/te.json
@@ -51,5 +51,13 @@
"Latest": "తాజా",
"NameInstallFailed": "{0} ఇన్‌స్టాలేషన్ విఫలమైంది",
"NameSeasonUnknown": "భాగం తెలియదు",
- "NotificationOptionApplicationUpdateAvailable": "అప్లికేషన్ అప్‌డేట్ అందుబాటులో ఉంది"
+ "NotificationOptionApplicationUpdateAvailable": "అప్లికేషన్ అప్‌డేట్ అందుబాటులో ఉంది",
+ "NameSeasonNumber": "సీజన్ {0}",
+ "NotificationOptionAudioPlaybackStopped": "ఆడియో ఆడటం ఆగిపోయింది",
+ "NotificationOptionNewLibraryContent": "కొత్త కంటెంట్ జోడించబడింది",
+ "MixedContent": "వివిధ రకాల కంటెంట్",
+ "NotificationOptionAudioPlayback": "ఆడియో ప్లే కావడం మొదలైంది",
+ "NotificationOptionCameraImageUploaded": "కెమెరా చిత్రాన్ని అప్లోడ్ చేశారు",
+ "NotificationOptionInstallationFailed": "ఇన్స్టాలేషన్ విఫలమైంది",
+ "NotificationOptionServerRestartRequired": "సర్వర్ రీస్టార్ట్ అవసరం"
}
diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs
index 754a01329..17db7ad4c 100644
--- a/Emby.Server.Implementations/Localization/LocalizationManager.cs
+++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs
@@ -1,7 +1,8 @@
using System;
using System.Collections.Concurrent;
+using System.Collections.Frozen;
using System.Collections.Generic;
-using System.Globalization;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -26,20 +27,20 @@ namespace Emby.Server.Implementations.Localization
private const string CulturesPath = "Emby.Server.Implementations.Localization.iso6392.txt";
private const string CountriesPath = "Emby.Server.Implementations.Localization.countries.json";
private static readonly Assembly _assembly = typeof(LocalizationManager).Assembly;
- private static readonly string[] _unratedValues = { "n/a", "unrated", "not rated", "nr" };
+ private static readonly string[] _unratedValues = ["n/a", "unrated", "not rated", "nr"];
private readonly IServerConfigurationManager _configurationManager;
private readonly ILogger<LocalizationManager> _logger;
- private readonly Dictionary<string, Dictionary<string, ParentalRating>> _allParentalRatings =
- new Dictionary<string, Dictionary<string, ParentalRating>>(StringComparer.OrdinalIgnoreCase);
+ private readonly Dictionary<string, Dictionary<string, ParentalRatingScore?>> _allParentalRatings = new(StringComparer.OrdinalIgnoreCase);
- private readonly ConcurrentDictionary<string, Dictionary<string, string>> _dictionaries =
- new ConcurrentDictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);
+ private readonly ConcurrentDictionary<string, Dictionary<string, string>> _dictionaries = new(StringComparer.OrdinalIgnoreCase);
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
- private List<CultureDto> _cultures = new List<CultureDto>();
+ private List<CultureDto> _cultures = [];
+
+ private FrozenDictionary<string, string> _iso6392BtoT = null!;
/// <summary>
/// Initializes a new instance of the <see cref="LocalizationManager" /> class.
@@ -68,35 +69,26 @@ namespace Emby.Server.Implementations.Localization
continue;
}
- string countryCode = resource.Substring(RatingsPath.Length, 2);
- var dict = new Dictionary<string, ParentalRating>(StringComparer.OrdinalIgnoreCase);
-
- var stream = _assembly.GetManifestResourceStream(resource);
- await using (stream!.ConfigureAwait(false)) // shouldn't be null here, we just got the resource path from Assembly.GetManifestResourceNames()
+ using var stream = _assembly.GetManifestResourceStream(resource);
+ if (stream is not null)
{
- using var reader = new StreamReader(stream!);
- await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false))
+ var ratingSystem = await JsonSerializer.DeserializeAsync<ParentalRatingSystem>(stream, _jsonOptions).ConfigureAwait(false)
+ ?? throw new InvalidOperationException($"Invalid resource path: '{CountriesPath}'");
+
+ var dict = new Dictionary<string, ParentalRatingScore?>();
+ if (ratingSystem.Ratings is not null)
{
- if (string.IsNullOrWhiteSpace(line))
+ foreach (var ratingEntry in ratingSystem.Ratings)
{
- continue;
+ foreach (var ratingString in ratingEntry.RatingStrings)
+ {
+ dict[ratingString] = ratingEntry.RatingScore;
+ }
}
- string[] parts = line.Split(',');
- if (parts.Length == 2
- && int.TryParse(parts[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
- {
- var name = parts[0];
- dict.Add(name, new ParentalRating(name, value));
- }
- else
- {
- _logger.LogWarning("Malformed line in ratings file for country {CountryCode}", countryCode);
- }
+ _allParentalRatings[ratingSystem.CountryCode] = dict;
}
}
-
- _allParentalRatings[countryCode] = dict;
}
await LoadCultures().ConfigureAwait(false);
@@ -111,22 +103,30 @@ namespace Emby.Server.Implementations.Localization
private async Task LoadCultures()
{
- List<CultureDto> list = new List<CultureDto>();
+ List<CultureDto> list = [];
+ Dictionary<string, string> iso6392BtoTdict = new Dictionary<string, string>();
- await using var stream = _assembly.GetManifestResourceStream(CulturesPath)
- ?? throw new InvalidOperationException($"Invalid resource path: '{CulturesPath}'");
- using var reader = new StreamReader(stream);
- await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false))
+ using var stream = _assembly.GetManifestResourceStream(CulturesPath);
+ if (stream is null)
{
- if (string.IsNullOrWhiteSpace(line))
+ throw new InvalidOperationException($"Invalid resource path: '{CulturesPath}'");
+ }
+ else
+ {
+ using var reader = new StreamReader(stream);
+ await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false))
{
- continue;
- }
+ if (string.IsNullOrWhiteSpace(line))
+ {
+ continue;
+ }
- var parts = line.Split('|');
+ var parts = line.Split('|');
+ if (parts.Length != 5)
+ {
+ throw new InvalidDataException($"Invalid culture data found at: '{line}'");
+ }
- if (parts.Length == 5)
- {
string name = parts[3];
if (string.IsNullOrWhiteSpace(name))
{
@@ -139,21 +139,26 @@ namespace Emby.Server.Implementations.Localization
continue;
}
- string[] threeletterNames;
+ string[] threeLetterNames;
if (string.IsNullOrWhiteSpace(parts[1]))
{
- threeletterNames = new[] { parts[0] };
+ threeLetterNames = [parts[0]];
}
else
{
- threeletterNames = new[] { parts[0], parts[1] };
+ threeLetterNames = [parts[0], parts[1]];
+
+ // In cases where there are two TLN the first one is ISO 639-2/T and the second one is ISO 639-2/B
+ // We need ISO 639-2/T for the .NET cultures so we cultivate a dictionary for the translation B->T
+ iso6392BtoTdict.TryAdd(parts[1], parts[0]);
}
- list.Add(new CultureDto(name, name, twoCharName, threeletterNames));
+ list.Add(new CultureDto(name, name, twoCharName, threeLetterNames));
}
- }
- _cultures = list;
+ _cultures = list;
+ _iso6392BtoT = iso6392BtoTdict.ToFrozenDictionary(StringComparer.OrdinalIgnoreCase);
+ }
}
/// <inheritdoc />
@@ -176,82 +181,80 @@ namespace Emby.Server.Implementations.Localization
}
/// <inheritdoc />
- public IEnumerable<CountryInfo> GetCountries()
+ public IReadOnlyList<CountryInfo> GetCountries()
{
- using StreamReader reader = new StreamReader(
- _assembly.GetManifestResourceStream(CountriesPath) ?? throw new InvalidOperationException($"Invalid resource path: '{CountriesPath}'"));
- return JsonSerializer.Deserialize<IEnumerable<CountryInfo>>(reader.ReadToEnd(), _jsonOptions)
- ?? throw new InvalidOperationException($"Resource contains invalid data: '{CountriesPath}'");
+ using var stream = _assembly.GetManifestResourceStream(CountriesPath) ?? throw new InvalidOperationException($"Invalid resource path: '{CountriesPath}'");
+
+ return JsonSerializer.Deserialize<IReadOnlyList<CountryInfo>>(stream, _jsonOptions) ?? [];
}
/// <inheritdoc />
- public IEnumerable<ParentalRating> GetParentalRatings()
+ public IReadOnlyList<ParentalRating> GetParentalRatings()
{
// Use server default language for ratings
// Fall back to empty list if there are no parental ratings for that language
- var ratings = GetParentalRatingsDictionary()?.Values.ToList()
- ?? new List<ParentalRating>();
+ var ratings = GetParentalRatingsDictionary()?.Select(x => new ParentalRating(x.Key, x.Value)).ToList() ?? [];
// Add common ratings to ensure them being available for selection
// Based on the US rating system due to it being the main source of rating in the metadata providers
// Unrated
- if (!ratings.Any(x => x.Value is null))
+ if (!ratings.Any(x => x is null))
{
- ratings.Add(new ParentalRating("Unrated", null));
+ ratings.Add(new("Unrated", null));
}
// Minimum rating possible
- if (ratings.All(x => x.Value != 0))
+ if (ratings.All(x => x.RatingScore?.Score != 0))
{
- ratings.Add(new ParentalRating("Approved", 0));
+ ratings.Add(new("Approved", new(0, null)));
}
// Matches PG (this has different age restrictions depending on country)
- if (ratings.All(x => x.Value != 10))
+ if (ratings.All(x => x.RatingScore?.Score != 10))
{
- ratings.Add(new ParentalRating("10", 10));
+ ratings.Add(new("10", new(10, null)));
}
// Matches PG-13
- if (ratings.All(x => x.Value != 13))
+ if (ratings.All(x => x.RatingScore?.Score != 13))
{
- ratings.Add(new ParentalRating("13", 13));
+ ratings.Add(new("13", new(13, null)));
}
// Matches TV-14
- if (ratings.All(x => x.Value != 14))
+ if (ratings.All(x => x.RatingScore?.Score != 14))
{
- ratings.Add(new ParentalRating("14", 14));
+ ratings.Add(new("14", new(14, null)));
}
// Catchall if max rating of country is less than 21
// Using 21 instead of 18 to be sure to allow access to all rated content except adult and banned
- if (!ratings.Any(x => x.Value >= 21))
+ if (!ratings.Any(x => x.RatingScore?.Score >= 21))
{
- ratings.Add(new ParentalRating("21", 21));
+ ratings.Add(new ParentalRating("21", new(21, null)));
}
// A lot of countries don't explicitly have a separate rating for adult content
- if (ratings.All(x => x.Value != 1000))
+ if (ratings.All(x => x.RatingScore?.Score != 1000))
{
- ratings.Add(new ParentalRating("XXX", 1000));
+ ratings.Add(new ParentalRating("XXX", new(1000, null)));
}
// A lot of countries don't explicitly have a separate rating for banned content
- if (ratings.All(x => x.Value != 1001))
+ if (ratings.All(x => x.RatingScore?.Score != 1001))
{
- ratings.Add(new ParentalRating("Banned", 1001));
+ ratings.Add(new ParentalRating("Banned", new(1001, null)));
}
- return ratings.OrderBy(r => r.Value);
+ return [.. ratings.OrderBy(r => r.RatingScore?.Score).ThenBy(r => r.RatingScore?.SubScore)];
}
/// <summary>
/// Gets the parental ratings dictionary.
/// </summary>
/// <param name="countryCode">The optional two letter ISO language string.</param>
- /// <returns><see cref="Dictionary{String, ParentalRating}" />.</returns>
- private Dictionary<string, ParentalRating>? GetParentalRatingsDictionary(string? countryCode = null)
+ /// <returns><see cref="Dictionary{String, ParentalRatingScore}" />.</returns>
+ private Dictionary<string, ParentalRatingScore?>? GetParentalRatingsDictionary(string? countryCode = null)
{
// Fallback to server default if no country code is specified.
if (string.IsNullOrEmpty(countryCode))
@@ -268,7 +271,7 @@ namespace Emby.Server.Implementations.Localization
}
/// <inheritdoc />
- public int? GetRatingLevel(string rating, string? countryCode = null)
+ public ParentalRatingScore? GetRatingScore(string rating, string? countryCode = null)
{
ArgumentException.ThrowIfNullOrEmpty(rating);
@@ -278,11 +281,11 @@ namespace Emby.Server.Implementations.Localization
return null;
}
- // Convert integers directly
+ // Convert ints directly
// This may override some of the locale specific age ratings (but those always map to the same age)
if (int.TryParse(rating, out var ratingAge))
{
- return ratingAge;
+ return new(ratingAge, null);
}
// Fairly common for some users to have "Rated R" in their rating field
@@ -295,9 +298,9 @@ namespace Emby.Server.Implementations.Localization
if (!string.IsNullOrEmpty(countryCode))
{
var ratingsDictionary = GetParentalRatingsDictionary(countryCode);
- if (ratingsDictionary is not null && ratingsDictionary.TryGetValue(rating, out ParentalRating? value))
+ if (ratingsDictionary is not null && ratingsDictionary.TryGetValue(rating, out ParentalRatingScore? value))
{
- return value.Value;
+ return value;
}
}
else
@@ -305,9 +308,9 @@ namespace Emby.Server.Implementations.Localization
// Fall back to server default language for ratings check
// If it has no ratings, use the US ratings
var ratingsDictionary = GetParentalRatingsDictionary() ?? GetParentalRatingsDictionary("us");
- if (ratingsDictionary is not null && ratingsDictionary.TryGetValue(rating, out ParentalRating? value))
+ if (ratingsDictionary is not null && ratingsDictionary.TryGetValue(rating, out ParentalRatingScore? value))
{
- return value.Value;
+ return value;
}
}
@@ -316,7 +319,7 @@ namespace Emby.Server.Implementations.Localization
{
if (dictionary.TryGetValue(rating, out var value))
{
- return value.Value;
+ return value;
}
}
@@ -326,7 +329,7 @@ namespace Emby.Server.Implementations.Localization
var ratingLevelRightPart = rating.AsSpan().RightPart(':');
if (ratingLevelRightPart.Length != 0)
{
- return GetRatingLevel(ratingLevelRightPart.ToString());
+ return GetRatingScore(ratingLevelRightPart.ToString());
}
}
@@ -342,7 +345,7 @@ namespace Emby.Server.Implementations.Localization
if (ratingLevelRightPart.Length != 0)
{
// Check rating system of culture
- return GetRatingLevel(ratingLevelRightPart.ToString(), culture?.TwoLetterISOLanguageName);
+ return GetRatingScore(ratingLevelRightPart.ToString(), culture?.TwoLetterISOLanguageName);
}
}
@@ -406,7 +409,7 @@ namespace Emby.Server.Implementations.Localization
private async Task CopyInto(IDictionary<string, string> dictionary, string resourcePath)
{
- await using var stream = _assembly.GetManifestResourceStream(resourcePath);
+ using var stream = _assembly.GetManifestResourceStream(resourcePath);
// If a Culture doesn't have a translation the stream will be null and it defaults to en-us further up the chain
if (stream is null)
{
@@ -414,12 +417,7 @@ namespace Emby.Server.Implementations.Localization
return;
}
- var dict = await JsonSerializer.DeserializeAsync<Dictionary<string, string>>(stream, _jsonOptions).ConfigureAwait(false);
- if (dict is null)
- {
- throw new InvalidOperationException($"Resource contains invalid data: '{stream}'");
- }
-
+ var dict = await JsonSerializer.DeserializeAsync<Dictionary<string, string>>(stream, _jsonOptions).ConfigureAwait(false) ?? throw new InvalidOperationException($"Resource contains invalid data: '{stream}'");
foreach (var key in dict.Keys)
{
dictionary[key] = dict[key];
@@ -517,5 +515,26 @@ namespace Emby.Server.Implementations.Localization
yield return new LocalizationOption("漢語 (繁體字)", "zh-TW");
yield return new LocalizationOption("廣東話 (香港)", "zh-HK");
}
+
+ /// <inheritdoc />
+ public bool TryGetISO6392TFromB(string isoB, [NotNullWhen(true)] out string? isoT)
+ {
+ // Unlikely case the dictionary is not (yet) initialized properly
+ if (_iso6392BtoT == null)
+ {
+ isoT = null;
+ return false;
+ }
+
+ var result = _iso6392BtoT.TryGetValue(isoB, out isoT) && !string.IsNullOrEmpty(isoT);
+
+ // Ensure the ISO code being null if the result is false
+ if (!result)
+ {
+ isoT = null;
+ }
+
+ return result;
+ }
}
}
diff --git a/Emby.Server.Implementations/Localization/Ratings/0-prefer.csv b/Emby.Server.Implementations/Localization/Ratings/0-prefer.csv
deleted file mode 100644
index 36886ba76..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/0-prefer.csv
+++ /dev/null
@@ -1,11 +0,0 @@
-E,0
-EC,0
-T,7
-M,18
-AO,18
-UR,18
-RP,18
-X,1000
-XX,1000
-XXX,1000
-XXXX,1000
diff --git a/Emby.Server.Implementations/Localization/Ratings/0-prefer.json b/Emby.Server.Implementations/Localization/Ratings/0-prefer.json
new file mode 100644
index 000000000..b39015161
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/0-prefer.json
@@ -0,0 +1,34 @@
+{
+ "countryCode": "0-prefer",
+ "supportsSubScores": false,
+ "ratings": [
+ {
+ "ratingStrings": ["E", "EC"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["T"],
+ "ratingScore": {
+ "score": 7,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["M", "AO", "UR", "RP"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["X", "XX", "XXX", "XXXX"],
+ "ratingScore": {
+ "score": 1000,
+ "subScore": null
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/au.csv b/Emby.Server.Implementations/Localization/Ratings/au.csv
deleted file mode 100644
index 6e12759a4..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/au.csv
+++ /dev/null
@@ -1,17 +0,0 @@
-Exempt,0
-G,0
-7+,7
-PG,15
-M,15
-MA,15
-MA15+,15
-MA 15+,15
-16+,16
-R,18
-R18+,18
-R 18+,18
-18+,18
-X18+,1000
-X 18+,1000
-X,1000
-RC,1001
diff --git a/Emby.Server.Implementations/Localization/Ratings/au.json b/Emby.Server.Implementations/Localization/Ratings/au.json
new file mode 100644
index 000000000..a563df899
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/au.json
@@ -0,0 +1,69 @@
+{
+ "countryCode": "au",
+ "supportsSubScores": true,
+ "ratings": [
+ {
+ "ratingStrings": ["Exempt", "G"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["7+"],
+ "ratingScore": {
+ "score": 7,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["PG"],
+ "ratingScore": {
+ "score": 15,
+ "subScore": 1
+ }
+ },
+ {
+ "ratingStrings": ["M"],
+ "ratingScore": {
+ "score": 15,
+ "subScore": 2
+ }
+ },
+ {
+ "ratingStrings": ["MA", "MA 15+", "MA15+"],
+ "ratingScore": {
+ "score": 15,
+ "subScore": 3
+ }
+ },
+ {
+ "ratingStrings": ["16+"],
+ "ratingScore": {
+ "score": 16,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["18+", "R", "R18+", "R 18+"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": 1
+ }
+ },
+ {
+ "ratingStrings": ["X", "X18", "X 18"],
+ "ratingScore": {
+ "score": 1000,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["RC"],
+ "ratingScore": {
+ "score": 1001,
+ "subScore": 0
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/be.csv b/Emby.Server.Implementations/Localization/Ratings/be.csv
deleted file mode 100644
index d171a7132..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/be.csv
+++ /dev/null
@@ -1,11 +0,0 @@
-AL,0
-KT,0
-TOUS,0
-MG6,6
-6,6
-9,9
-KNT,12
-12,12
-14,14
-16,16
-18,18
diff --git a/Emby.Server.Implementations/Localization/Ratings/be.json b/Emby.Server.Implementations/Localization/Ratings/be.json
new file mode 100644
index 000000000..18ea2c260
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/be.json
@@ -0,0 +1,55 @@
+{
+ "countryCode": "be",
+ "supportsSubScores": false,
+ "ratings": [
+ {
+ "ratingStrings": ["AL", "KT", "TOUS"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["6", "MG6"],
+ "ratingScore": {
+ "score": 6,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["9"],
+ "ratingScore": {
+ "score": 9,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["12", "KNT"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["14"],
+ "ratingScore": {
+ "score": 14,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["16"],
+ "ratingScore": {
+ "score": 16,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["18"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": null
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/br.csv b/Emby.Server.Implementations/Localization/Ratings/br.csv
deleted file mode 100644
index f6053c88c..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/br.csv
+++ /dev/null
@@ -1,14 +0,0 @@
-Livre,0
-L,0
-AL,0
-ER,10
-10,10
-A10,10
-12,12
-A12,12
-14,14
-A14,14
-16,16
-A16,16
-18,18
-A18,18
diff --git a/Emby.Server.Implementations/Localization/Ratings/br.json b/Emby.Server.Implementations/Localization/Ratings/br.json
new file mode 100644
index 000000000..f455b6643
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/br.json
@@ -0,0 +1,55 @@
+{
+ "countryCode": "br",
+ "supportsSubScores": false,
+ "ratings": [
+ {
+ "ratingStrings": ["L", "AL", "Livre"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["9"],
+ "ratingScore": {
+ "score": 9,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["10", "A10", "ER"],
+ "ratingScore": {
+ "score": 10,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["12", "A12"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["14", "A14"],
+ "ratingScore": {
+ "score": 14,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["16", "A16"],
+ "ratingScore": {
+ "score": 16,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["18", "A18"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": null
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/ca.csv b/Emby.Server.Implementations/Localization/Ratings/ca.csv
deleted file mode 100644
index 41dbda134..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/ca.csv
+++ /dev/null
@@ -1,18 +0,0 @@
-E,0
-G,0
-TV-Y,0
-TV-G,0
-TV-Y7,7
-TV-Y7-FV,7
-PG,9
-TV-PG,9
-TV-14,14
-14A,14
-16+,16
-NC-17,17
-R,18
-TV-MA,18
-18A,18
-18+,18
-A,1000
-Prohibited,1001
diff --git a/Emby.Server.Implementations/Localization/Ratings/ca.json b/Emby.Server.Implementations/Localization/Ratings/ca.json
new file mode 100644
index 000000000..fa43a8f2b
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/ca.json
@@ -0,0 +1,90 @@
+{
+ "countryCode": "ca",
+ "supportsSubScores": true,
+ "ratings": [
+ {
+ "ratingStrings": ["E", "G", "TV-Y", "TV-G"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["TV-Y7"],
+ "ratingScore": {
+ "score": 7,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["TV-Y7-FV"],
+ "ratingScore": {
+ "score": 7,
+ "subScore": 1
+ }
+ },
+ {
+ "ratingStrings": ["PG", "TV-PG"],
+ "ratingScore": {
+ "score": 9,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["14A"],
+ "ratingScore": {
+ "score": 14,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["TV-14"],
+ "ratingScore": {
+ "score": 14,
+ "subScore": 1
+ }
+ },
+ {
+ "ratingStrings": ["16+"],
+ "ratingScore": {
+ "score": 16,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["NC-17"],
+ "ratingScore": {
+ "score": 17,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["18A"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["18+", "TV-MA", "R"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": 1
+ }
+ },
+ {
+ "ratingStrings": ["A"],
+ "ratingScore": {
+ "score": 1000,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["Prohibited"],
+ "ratingScore": {
+ "score": 1001,
+ "subScore": 0
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/cl.json b/Emby.Server.Implementations/Localization/Ratings/cl.json
new file mode 100644
index 000000000..086619471
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/cl.json
@@ -0,0 +1,41 @@
+{
+ "countryCode": "cl",
+ "supportsSubScores": false,
+ "ratings": [
+ {
+ "ratingStrings": ["TE"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["6"],
+ "ratingScore": {
+ "score": 6,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["TE+7"],
+ "ratingScore": {
+ "score": 7,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["14"],
+ "ratingScore": {
+ "score": 14,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["18", "18V", "18S"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": null
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/co.csv b/Emby.Server.Implementations/Localization/Ratings/co.csv
deleted file mode 100644
index e1e96c590..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/co.csv
+++ /dev/null
@@ -1,7 +0,0 @@
-T,0
-7,7
-12,12
-15,15
-18,18
-X,1000
-Prohibited,1001
diff --git a/Emby.Server.Implementations/Localization/Ratings/co.json b/Emby.Server.Implementations/Localization/Ratings/co.json
new file mode 100644
index 000000000..4eff6dcc5
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/co.json
@@ -0,0 +1,55 @@
+{
+ "countryCode": "co",
+ "supportsSubScores": false,
+ "ratings": [
+ {
+ "ratingStrings": ["T"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["7"],
+ "ratingScore": {
+ "score": 7,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["12"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["15"],
+ "ratingScore": {
+ "score": 15,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["18"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["X"],
+ "ratingScore": {
+ "score": 1000,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["Prohibited"],
+ "ratingScore": {
+ "score": 1001,
+ "subScore": null
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/de.csv b/Emby.Server.Implementations/Localization/Ratings/de.csv
deleted file mode 100644
index f6181575e..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/de.csv
+++ /dev/null
@@ -1,17 +0,0 @@
-Educational,0
-Infoprogramm,0
-FSK-0,0
-FSK 0,0
-0,0
-FSK-6,6
-FSK 6,6
-6,6
-FSK-12,12
-FSK 12,12
-12,12
-FSK-16,16
-FSK 16,16
-16,16
-FSK-18,18
-FSK 18,18
-18,18
diff --git a/Emby.Server.Implementations/Localization/Ratings/de.json b/Emby.Server.Implementations/Localization/Ratings/de.json
new file mode 100644
index 000000000..30c34b230
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/de.json
@@ -0,0 +1,41 @@
+{
+ "countryCode": "de",
+ "supportsSubScores": false,
+ "ratings": [
+ {
+ "ratingStrings": ["0", "FSK 0", "FSK-0", "Educational", "Infoprogramm"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["6", "FSK 6", "FSK-6"],
+ "ratingScore": {
+ "score": 6,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["12", "FSK 12", "FSK-12"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["16", "FSK 16", "FSK-16"],
+ "ratingScore": {
+ "score": 16,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["18", "FSK 18", "FSK-18"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": null
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/dk.csv b/Emby.Server.Implementations/Localization/Ratings/dk.csv
deleted file mode 100644
index 4ef63b2ea..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/dk.csv
+++ /dev/null
@@ -1,7 +0,0 @@
-F,0
-A,0
-7,7
-11,11
-12,12
-15,15
-16,16
diff --git a/Emby.Server.Implementations/Localization/Ratings/dk.json b/Emby.Server.Implementations/Localization/Ratings/dk.json
new file mode 100644
index 000000000..9fcd6d44f
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/dk.json
@@ -0,0 +1,48 @@
+{
+ "countryCode": "dk",
+ "supportsSubScores": false,
+ "ratings": [
+ {
+ "ratingStrings": ["F", "A"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["7"],
+ "ratingScore": {
+ "score": 7,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["11"],
+ "ratingScore": {
+ "score": 11,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["12"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["15"],
+ "ratingScore": {
+ "score": 15,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["16"],
+ "ratingScore": {
+ "score": 16,
+ "subScore": null
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/es.csv b/Emby.Server.Implementations/Localization/Ratings/es.csv
deleted file mode 100644
index ee5866090..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/es.csv
+++ /dev/null
@@ -1,25 +0,0 @@
-A,0
-A/fig,0
-A/i,0
-A/i/fig,0
-APTA,0
-ERI,0
-TP,0
-0+,0
-6+,6
-7/fig,7
-7/i,7
-7/i/fig,7
-7,7
-9+,9
-10,10
-12,12
-12/fig,12
-13,13
-14,14
-16,16
-16/fig,16
-18,18
-18/fig,18
-X,1000
-Banned,1001
diff --git a/Emby.Server.Implementations/Localization/Ratings/es.json b/Emby.Server.Implementations/Localization/Ratings/es.json
new file mode 100644
index 000000000..c19629939
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/es.json
@@ -0,0 +1,90 @@
+{
+ "countryCode": "es",
+ "supportsSubScores": false,
+ "ratings": [
+ {
+ "ratingStrings": ["0+", "A", "A/i", "A/fig", "A/i/fig", "APTA", "ERI", "TP"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["6+"],
+ "ratingScore": {
+ "score": 6,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["7", "7/i", "7/fig", "7/i/fig"],
+ "ratingScore": {
+ "score": 11,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["9+"],
+ "ratingScore": {
+ "score": 9,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["10"],
+ "ratingScore": {
+ "score": 10,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["12", "12/fig"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["13"],
+ "ratingScore": {
+ "score": 13,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["14"],
+ "ratingScore": {
+ "score": 14,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["16", "16/fig"],
+ "ratingScore": {
+ "score": 16,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["18", "18/fig"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["X"],
+ "ratingScore": {
+ "score": 1000,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["Banned"],
+ "ratingScore": {
+ "score": 1001,
+ "subScore": null
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/fi.csv b/Emby.Server.Implementations/Localization/Ratings/fi.csv
deleted file mode 100644
index 7ff92f259..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/fi.csv
+++ /dev/null
@@ -1,10 +0,0 @@
-S,0
-T,0
-K7,7
-7,7
-K12,12
-12,12
-K16,16
-16,16
-K18,18
-18,18
diff --git a/Emby.Server.Implementations/Localization/Ratings/fi.json b/Emby.Server.Implementations/Localization/Ratings/fi.json
new file mode 100644
index 000000000..3152317b5
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/fi.json
@@ -0,0 +1,41 @@
+{
+ "countryCode": "fi",
+ "supportsSubScores": false,
+ "ratings": [
+ {
+ "ratingStrings": ["S", "T"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["7", "K7"],
+ "ratingScore": {
+ "score": 7,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["12", "K12"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["16", "K16"],
+ "ratingScore": {
+ "score": 16,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["18", "K18"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": null
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/fr.csv b/Emby.Server.Implementations/Localization/Ratings/fr.csv
deleted file mode 100644
index 139ea376b..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/fr.csv
+++ /dev/null
@@ -1,13 +0,0 @@
-Public Averti,0
-Tous Publics,0
-TP,0
-U,0
-0+,0
-6+,6
-9+,9
-10,10
-12,12
-14+,14
-16,16
-18,18
-X,1000
diff --git a/Emby.Server.Implementations/Localization/Ratings/fr.json b/Emby.Server.Implementations/Localization/Ratings/fr.json
new file mode 100644
index 000000000..e8bafd6b8
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/fr.json
@@ -0,0 +1,69 @@
+{
+ "countryCode": "fr",
+ "supportsSubScores": false,
+ "ratings": [
+ {
+ "ratingStrings": ["0+", "Public Averti", "Tous Publics", "TP", "U"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["6+"],
+ "ratingScore": {
+ "score": 6,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["9+"],
+ "ratingScore": {
+ "score": 9,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["10"],
+ "ratingScore": {
+ "score": 10,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["12"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["14+"],
+ "ratingScore": {
+ "score": 14,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["16"],
+ "ratingScore": {
+ "score": 16,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["18"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["X"],
+ "ratingScore": {
+ "score": 1000,
+ "subScore": null
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/gb.csv b/Emby.Server.Implementations/Localization/Ratings/gb.csv
deleted file mode 100644
index 858b9a32d..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/gb.csv
+++ /dev/null
@@ -1,23 +0,0 @@
-All,0
-E,0
-G,0
-U,0
-0+,0
-6+,6
-7+,7
-PG,8
-9,9
-12,12
-12+,12
-12A,12
-12PG,12
-Teen,13
-13+,13
-14+,14
-15,15
-16,16
-Caution,18
-18,18
-Mature,1000
-Adult,1000
-R18,1000
diff --git a/Emby.Server.Implementations/Localization/Ratings/gb.json b/Emby.Server.Implementations/Localization/Ratings/gb.json
new file mode 100644
index 000000000..7fc88272c
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/gb.json
@@ -0,0 +1,97 @@
+{
+ "countryCode": "gb",
+ "supportsSubScores": true,
+ "ratings": [
+ {
+ "ratingStrings": ["0+", "All", "E", "G", "U"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["6+"],
+ "ratingScore": {
+ "score": 6,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["7+"],
+ "ratingScore": {
+ "score": 7,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["PG"],
+ "ratingScore": {
+ "score": 8,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["9"],
+ "ratingScore": {
+ "score": 9,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["12A", "12PG"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["12", "12+"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": 1
+ }
+ },
+ {
+ "ratingStrings": ["13+", "Teen"],
+ "ratingScore": {
+ "score": 13,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["14+"],
+ "ratingScore": {
+ "score": 14,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["15"],
+ "ratingScore": {
+ "score": 15,
+ "subScore": 3
+ }
+ },
+ {
+ "ratingStrings": ["16"],
+ "ratingScore": {
+ "score": 16,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["18", "Caution"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": 1
+ }
+ },
+ {
+ "ratingStrings": ["Mature", "Adult", "R18"],
+ "ratingScore": {
+ "score": 1000,
+ "subScore": 0
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/ie.csv b/Emby.Server.Implementations/Localization/Ratings/ie.csv
deleted file mode 100644
index d3c634fc9..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/ie.csv
+++ /dev/null
@@ -1,10 +0,0 @@
-G,4
-PG,12
-12,12
-12A,12
-12PG,12
-15,15
-15PG,15
-15A,15
-16,16
-18,18
diff --git a/Emby.Server.Implementations/Localization/Ratings/ie.json b/Emby.Server.Implementations/Localization/Ratings/ie.json
new file mode 100644
index 000000000..f6cc56ed6
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/ie.json
@@ -0,0 +1,55 @@
+{
+ "countryCode": "ie",
+ "supportsSubScores": true,
+ "ratings": [
+ {
+ "ratingStrings": ["G"],
+ "ratingScore": {
+ "score": 4,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["12A", "12PG", "PG"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["12"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": 1
+ }
+ },
+ {
+ "ratingStrings": ["15A", "15PG"],
+ "ratingScore": {
+ "score": 15,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["15"],
+ "ratingScore": {
+ "score": 15,
+ "subScore": 3
+ }
+ },
+ {
+ "ratingStrings": ["16"],
+ "ratingScore": {
+ "score": 16,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["18"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": 1
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/jp.csv b/Emby.Server.Implementations/Localization/Ratings/jp.csv
deleted file mode 100644
index bfb5fdaae..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/jp.csv
+++ /dev/null
@@ -1,11 +0,0 @@
-A,0
-G,0
-B,12
-PG12,12
-C,15
-15+,15
-R15+,15
-16+,16
-D,17
-Z,18
-18+,18
diff --git a/Emby.Server.Implementations/Localization/Ratings/jp.json b/Emby.Server.Implementations/Localization/Ratings/jp.json
new file mode 100644
index 000000000..efff9e92c
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/jp.json
@@ -0,0 +1,62 @@
+{
+ "countryCode": "jp",
+ "supportsSubScores": true,
+ "ratings": [
+ {
+ "ratingStrings": ["A", "G"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["PG12"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["B"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": 1
+ }
+ },
+ {
+ "ratingStrings": ["15A", "15PG"],
+ "ratingScore": {
+ "score": 15,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["C", "15+", "R15+"],
+ "ratingScore": {
+ "score": 15,
+ "subScore": 1
+ }
+ },
+ {
+ "ratingStrings": ["16+"],
+ "ratingScore": {
+ "score": 16,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["D"],
+ "ratingScore": {
+ "score": 17,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["18+", "Z"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": null
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/kz.csv b/Emby.Server.Implementations/Localization/Ratings/kz.csv
deleted file mode 100644
index e26b32b67..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/kz.csv
+++ /dev/null
@@ -1,6 +0,0 @@
-K,0
-БА,12
-Б14,14
-E16,16
-E18,18
-HA,18
diff --git a/Emby.Server.Implementations/Localization/Ratings/kz.json b/Emby.Server.Implementations/Localization/Ratings/kz.json
new file mode 100644
index 000000000..0f8f0c68e
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/kz.json
@@ -0,0 +1,41 @@
+{
+ "countryCode": "kz",
+ "supportsSubScores": false,
+ "ratings": [
+ {
+ "ratingStrings": ["K"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["БА"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["Б14"],
+ "ratingScore": {
+ "score": 14,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["E16"],
+ "ratingScore": {
+ "score": 16,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["E18", "HA"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": null
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/mx.csv b/Emby.Server.Implementations/Localization/Ratings/mx.csv
deleted file mode 100644
index 305912f23..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/mx.csv
+++ /dev/null
@@ -1,6 +0,0 @@
-A,0
-AA,0
-B,12
-B-15,15
-C,18
-D,1000
diff --git a/Emby.Server.Implementations/Localization/Ratings/mx.json b/Emby.Server.Implementations/Localization/Ratings/mx.json
new file mode 100644
index 000000000..9dc3b89bd
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/mx.json
@@ -0,0 +1,41 @@
+{
+ "countryCode": "mx",
+ "supportsSubScores": false,
+ "ratings": [
+ {
+ "ratingStrings": ["A", "AA"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["B"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["B-15"],
+ "ratingScore": {
+ "score": 15,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["C"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["D"],
+ "ratingScore": {
+ "score": 1000,
+ "subScore": null
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/nl.csv b/Emby.Server.Implementations/Localization/Ratings/nl.csv
deleted file mode 100644
index 44f372b2d..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/nl.csv
+++ /dev/null
@@ -1,8 +0,0 @@
-AL,0
-MG6,6
-6,6
-9,9
-12,12
-14,14
-16,16
-18,18
diff --git a/Emby.Server.Implementations/Localization/Ratings/nl.json b/Emby.Server.Implementations/Localization/Ratings/nl.json
new file mode 100644
index 000000000..2e43eb83a
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/nl.json
@@ -0,0 +1,55 @@
+{
+ "countryCode": "nl",
+ "supportsSubScores": false,
+ "ratings": [
+ {
+ "ratingStrings": ["AL"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["6", "MG6"],
+ "ratingScore": {
+ "score": 6,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["9"],
+ "ratingScore": {
+ "score": 9,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["12"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["14"],
+ "ratingScore": {
+ "score": 14,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["16"],
+ "ratingScore": {
+ "score": 16,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["18"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": null
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/no.csv b/Emby.Server.Implementations/Localization/Ratings/no.csv
deleted file mode 100644
index 6856a2dbb..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/no.csv
+++ /dev/null
@@ -1,10 +0,0 @@
-A,0
-6,6
-7,7
-9,9
-11,11
-12,12
-15,15
-18,18
-C,18
-Not approved,1001
diff --git a/Emby.Server.Implementations/Localization/Ratings/no.json b/Emby.Server.Implementations/Localization/Ratings/no.json
new file mode 100644
index 000000000..a5e952316
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/no.json
@@ -0,0 +1,69 @@
+{
+ "countryCode": "no",
+ "supportsSubScores": false,
+ "ratings": [
+ {
+ "ratingStrings": ["A"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["6"],
+ "ratingScore": {
+ "score": 6,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["7"],
+ "ratingScore": {
+ "score": 7,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["9"],
+ "ratingScore": {
+ "score": 9,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["11"],
+ "ratingScore": {
+ "score": 11,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["12"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["15"],
+ "ratingScore": {
+ "score": 15,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["18"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["Not approved"],
+ "ratingScore": {
+ "score": 1001,
+ "subScore": null
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/nz.csv b/Emby.Server.Implementations/Localization/Ratings/nz.csv
deleted file mode 100644
index 633da78fe..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/nz.csv
+++ /dev/null
@@ -1,16 +0,0 @@
-Exempt,0
-G,0
-GY,13
-PG,13
-R13,13
-RP13,13
-R15,15
-M,16
-R16,16
-RP16,16
-GA,18
-R18,18
-RP18,18
-MA,1000
-R,1001
-Objectionable,1001
diff --git a/Emby.Server.Implementations/Localization/Ratings/nz.json b/Emby.Server.Implementations/Localization/Ratings/nz.json
new file mode 100644
index 000000000..3c1332271
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/nz.json
@@ -0,0 +1,69 @@
+{
+ "countryCode": "nz",
+ "supportsSubScores": true,
+ "ratings": [
+ {
+ "ratingStrings": ["Exempt", "G"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["RP13", "PG"],
+ "ratingScore": {
+ "score": 13,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["GY", "R13"],
+ "ratingScore": {
+ "score": 13,
+ "subScore": 1
+ }
+ },
+ {
+ "ratingStrings": ["RP16", "M"],
+ "ratingScore": {
+ "score": 16,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["R16"],
+ "ratingScore": {
+ "score": 16,
+ "subScore": 1
+ }
+ },
+ {
+ "ratingStrings": ["RP18"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["R18", "GA"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": 1
+ }
+ },
+ {
+ "ratingStrings": ["MA"],
+ "ratingScore": {
+ "score": 1000,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["Objectionable", "R"],
+ "ratingScore": {
+ "score": 1001,
+ "subScore": 0
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/pl.json b/Emby.Server.Implementations/Localization/Ratings/pl.json
new file mode 100644
index 000000000..c3001ffb3
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/pl.json
@@ -0,0 +1,41 @@
+{
+ "countryCode": "pl",
+ "supportsSubScores": false,
+ "ratings": [
+ {
+ "ratingStrings": ["b.o.", "AL"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["7", "od 7 lat"],
+ "ratingScore": {
+ "score": 7,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["12", "od 12 lat"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["16", "od 16 lat"],
+ "ratingScore": {
+ "score": 16,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["18", "od 18 lat", "R"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": null
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/ro.csv b/Emby.Server.Implementations/Localization/Ratings/ro.csv
deleted file mode 100644
index 44c23e248..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/ro.csv
+++ /dev/null
@@ -1,6 +0,0 @@
-AG,0
-AP-12,12
-N-15,15
-IM-18,18
-IM-18-XXX,1000
-IC,1001
diff --git a/Emby.Server.Implementations/Localization/Ratings/ro.json b/Emby.Server.Implementations/Localization/Ratings/ro.json
new file mode 100644
index 000000000..9cf735a54
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/ro.json
@@ -0,0 +1,48 @@
+{
+ "countryCode": "ro",
+ "supportsSubScores": false,
+ "ratings": [
+ {
+ "ratingStrings": ["AG"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["AP-12"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["N-15"],
+ "ratingScore": {
+ "score": 15,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["IM-18"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["IM-18-XXX"],
+ "ratingScore": {
+ "score": 1000,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["IC"],
+ "ratingScore": {
+ "score": 1001,
+ "subScore": null
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/ru.csv b/Emby.Server.Implementations/Localization/Ratings/ru.csv
deleted file mode 100644
index 8b264070b..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/ru.csv
+++ /dev/null
@@ -1,6 +0,0 @@
-0+,0
-6+,6
-12+,12
-16+,16
-18+,18
-Refused classification,1001
diff --git a/Emby.Server.Implementations/Localization/Ratings/ru.json b/Emby.Server.Implementations/Localization/Ratings/ru.json
new file mode 100644
index 000000000..d1b8b13aa
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/ru.json
@@ -0,0 +1,48 @@
+{
+ "countryCode": "ru",
+ "supportsSubScores": false,
+ "ratings": [
+ {
+ "ratingStrings": ["0+"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["6+"],
+ "ratingScore": {
+ "score": 6,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["12+"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["16+"],
+ "ratingScore": {
+ "score": 16,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["18+"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["Refused classification"],
+ "ratingScore": {
+ "score": 1001,
+ "subScore": null
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/se.csv b/Emby.Server.Implementations/Localization/Ratings/se.csv
deleted file mode 100644
index e129c3561..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/se.csv
+++ /dev/null
@@ -1,10 +0,0 @@
-Alla,0
-Barntillåten,0
-Btl,0
-0+,0
-7,7
-9+,9
-10+,10
-11,11
-14,14
-15,15
diff --git a/Emby.Server.Implementations/Localization/Ratings/se.json b/Emby.Server.Implementations/Localization/Ratings/se.json
new file mode 100644
index 000000000..70084995d
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/se.json
@@ -0,0 +1,55 @@
+{
+ "countryCode": "se",
+ "supportsSubScores": false,
+ "ratings": [
+ {
+ "ratingStrings": ["0+", "Alla", "Barntillåten", "Btl"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["7"],
+ "ratingScore": {
+ "score": 7,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["9+"],
+ "ratingScore": {
+ "score": 9,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["10+"],
+ "ratingScore": {
+ "score": 10,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["11"],
+ "ratingScore": {
+ "score": 11,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["14"],
+ "ratingScore": {
+ "score": 14,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["15"],
+ "ratingScore": {
+ "score": 15,
+ "subScore": null
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/sk.csv b/Emby.Server.Implementations/Localization/Ratings/sk.csv
deleted file mode 100644
index dbafd8efa..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/sk.csv
+++ /dev/null
@@ -1,6 +0,0 @@
-NR,0
-U,0
-7,7
-12,12
-15,15
-18,18
diff --git a/Emby.Server.Implementations/Localization/Ratings/sk.json b/Emby.Server.Implementations/Localization/Ratings/sk.json
new file mode 100644
index 000000000..5ec6111ec
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/sk.json
@@ -0,0 +1,41 @@
+{
+ "countryCode": "sk",
+ "supportsSubScores": false,
+ "ratings": [
+ {
+ "ratingStrings": ["U", "NR"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["7"],
+ "ratingScore": {
+ "score": 7,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["12"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["15"],
+ "ratingScore": {
+ "score": 15,
+ "subScore": null
+ }
+ },
+ {
+ "ratingStrings": ["18"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": null
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/uk.csv b/Emby.Server.Implementations/Localization/Ratings/uk.csv
deleted file mode 100644
index 75b1c2058..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/uk.csv
+++ /dev/null
@@ -1,22 +0,0 @@
-All,0
-E,0
-G,0
-U,0
-0+,0
-6+,6
-7+,7
-PG,8
-9+,9
-12,12
-12+,12
-12A,12
-Teen,13
-13+,13
-14+,14
-15,15
-16,16
-Caution,18
-18,18
-Mature,1000
-Adult,1000
-R18,1000
diff --git a/Emby.Server.Implementations/Localization/Ratings/uk.json b/Emby.Server.Implementations/Localization/Ratings/uk.json
new file mode 100644
index 000000000..7fc88272c
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/uk.json
@@ -0,0 +1,97 @@
+{
+ "countryCode": "gb",
+ "supportsSubScores": true,
+ "ratings": [
+ {
+ "ratingStrings": ["0+", "All", "E", "G", "U"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["6+"],
+ "ratingScore": {
+ "score": 6,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["7+"],
+ "ratingScore": {
+ "score": 7,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["PG"],
+ "ratingScore": {
+ "score": 8,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["9"],
+ "ratingScore": {
+ "score": 9,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["12A", "12PG"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["12", "12+"],
+ "ratingScore": {
+ "score": 12,
+ "subScore": 1
+ }
+ },
+ {
+ "ratingStrings": ["13+", "Teen"],
+ "ratingScore": {
+ "score": 13,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["14+"],
+ "ratingScore": {
+ "score": 14,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["15"],
+ "ratingScore": {
+ "score": 15,
+ "subScore": 3
+ }
+ },
+ {
+ "ratingStrings": ["16"],
+ "ratingScore": {
+ "score": 16,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["18", "Caution"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": 1
+ }
+ },
+ {
+ "ratingStrings": ["Mature", "Adult", "R18"],
+ "ratingScore": {
+ "score": 1000,
+ "subScore": 0
+ }
+ }
+ ]
+}
diff --git a/Emby.Server.Implementations/Localization/Ratings/us.csv b/Emby.Server.Implementations/Localization/Ratings/us.csv
deleted file mode 100644
index 9aa5c00eb..000000000
--- a/Emby.Server.Implementations/Localization/Ratings/us.csv
+++ /dev/null
@@ -1,52 +0,0 @@
-Approved,0
-G,0
-TV-G,0
-TV-Y,0
-TV-Y7,7
-TV-Y7-FV,7
-PG,10
-TV-PG,10
-TV-PG-D,10
-TV-PG-L,10
-TV-PG-S,10
-TV-PG-V,10
-TV-PG-DL,10
-TV-PG-DS,10
-TV-PG-DV,10
-TV-PG-LS,10
-TV-PG-LV,10
-TV-PG-SV,10
-TV-PG-DLS,10
-TV-PG-DLV,10
-TV-PG-DSV,10
-TV-PG-LSV,10
-TV-PG-DLSV,10
-PG-13,13
-TV-14,14
-TV-14-D,14
-TV-14-L,14
-TV-14-S,14
-TV-14-V,14
-TV-14-DL,14
-TV-14-DS,14
-TV-14-DV,14
-TV-14-LS,14
-TV-14-LV,14
-TV-14-SV,14
-TV-14-DLS,14
-TV-14-DLV,14
-TV-14-DSV,14
-TV-14-LSV,14
-TV-14-DLSV,14
-NC-17,17
-R,17
-TV-MA,17
-TV-MA-L,17
-TV-MA-S,17
-TV-MA-V,17
-TV-MA-LS,17
-TV-MA-LV,17
-TV-MA-SV,17
-TV-MA-LSV,17
-TV-X,18
-TV-AO,18
diff --git a/Emby.Server.Implementations/Localization/Ratings/us.json b/Emby.Server.Implementations/Localization/Ratings/us.json
new file mode 100644
index 000000000..08a637312
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Ratings/us.json
@@ -0,0 +1,83 @@
+{
+ "countryCode": "us",
+ "supportsSubScores": true,
+ "ratings": [
+ {
+ "ratingStrings": ["Approved", "G", "TV-G", "TV-Y"],
+ "ratingScore": {
+ "score": 0,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["TV-Y7"],
+ "ratingScore": {
+ "score": 7,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["TV-Y7-FV"],
+ "ratingScore": {
+ "score": 7,
+ "subScore": 1
+ }
+ },
+ {
+ "ratingStrings": ["PG", "TV-PG"],
+ "ratingScore": {
+ "score": 10,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["TV-PG-D", "TV-PG-L", "TV-PG-S", "TV-PG-V", "TV-PG-DL", "TV-PG-DS", "TV-PG-DV", "TV-PG-LS", "TV-PG-LV", "TV-PG-SV", "TV-PG-DLS", "TV-PG-DLV", "TV-PG-DSV", "TV-PG-LSV", "TV-PG-DLSV"],
+ "ratingScore": {
+ "score": 10,
+ "subScore": 1
+ }
+ },
+ {
+ "ratingStrings": ["PG-13"],
+ "ratingScore": {
+ "score": 13,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["TV-14"],
+ "ratingScore": {
+ "score": 14,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["TV-14-D", "TV-14-L", "TV-14-S", "TV-14-V", "TV-14-DL", "TV-14-DS", "TV-14-DV", "TV-14-LS", "TV-14-LV", "TV-14-SV", "TV-14-DLS", "TV-14-DLV", "TV-14-DSV", "TV-14-LSV", "TV-14-DLSV"],
+ "ratingScore": {
+ "score": 14,
+ "subScore": 1
+ }
+ },
+ {
+ "ratingStrings": ["R"],
+ "ratingScore": {
+ "score": 17,
+ "subScore": 0
+ }
+ },
+ {
+ "ratingStrings": ["NC-17", "TV-MA", "TV-MA-L", "TV-MA-S", "TV-MA-V", "TV-MA-LS", "TV-MA-LV", "TV-MA-SV", "TV-MA-LSV"],
+ "ratingScore": {
+ "score": 17,
+ "subScore": 1
+ }
+ },
+ {
+ "ratingStrings": ["TV-X", "TV-AO"],
+ "ratingScore": {
+ "score": 18,
+ "subScore": 0
+ }
+ }
+ ]
+}